aboutsummaryrefslogtreecommitdiff
path: root/src/backend/optimizer/util
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/optimizer/util')
-rw-r--r--src/backend/optimizer/util/joininfo.c110
-rw-r--r--src/backend/optimizer/util/relnode.c13
-rw-r--r--src/backend/optimizer/util/restrictinfo.c28
3 files changed, 143 insertions, 8 deletions
diff --git a/src/backend/optimizer/util/joininfo.c b/src/backend/optimizer/util/joininfo.c
index c202615b1f5..79a9f7a3bac 100644
--- a/src/backend/optimizer/util/joininfo.c
+++ b/src/backend/optimizer/util/joininfo.c
@@ -8,13 +8,14 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/optimizer/util/joininfo.c,v 1.32 2003/01/20 18:54:56 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/optimizer/util/joininfo.c,v 1.33 2003/01/24 03:58:43 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
#include "optimizer/joininfo.h"
+#include "optimizer/pathnode.h"
/*
@@ -63,3 +64,110 @@ make_joininfo_node(RelOptInfo *this_rel, Relids join_relids)
}
return joininfo;
}
+
+
+/*
+ * add_join_clause_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
+ * (there must be more than one)
+ */
+void
+add_join_clause_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);
+ /*
+ * Can't freeList(unjoined_relids) because new joininfo node may
+ * link to it. We could avoid leaking memory by doing listCopy()
+ * in make_joininfo_node, but for now speed seems better.
+ */
+ }
+}
+
+/*
+ * remove_join_clause_from_rels
+ * Delete 'restrictinfo' from all the joininfo lists it is in
+ *
+ * This reverses the effect of add_join_clause_to_rels. It's used when we
+ * discover that a join clause is redundant.
+ *
+ * 'restrictinfo' describes the join clause
+ * 'join_relids' is the list of relations participating in the join clause
+ * (there must be more than one)
+ */
+void
+remove_join_clause_from_rels(Query *root,
+ RestrictInfo *restrictinfo,
+ Relids join_relids)
+{
+ List *join_relid;
+
+ /* For every relid, find the joininfo */
+ 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 the joininfo node for this combination of rels; it should
+ * exist already, if add_join_clause_to_rels was called.
+ */
+ joininfo = find_joininfo_node(find_base_rel(root, cur_relid),
+ unjoined_relids);
+ Assert(joininfo);
+ /*
+ * Remove the restrictinfo from the list. Pointer comparison
+ * is sufficient.
+ */
+ Assert(ptrMember(restrictinfo, joininfo->jinfo_restrictinfo));
+ joininfo->jinfo_restrictinfo = lremove(restrictinfo,
+ joininfo->jinfo_restrictinfo);
+ freeList(unjoined_relids);
+ }
+}
diff --git a/src/backend/optimizer/util/relnode.c b/src/backend/optimizer/util/relnode.c
index 144fac75501..06a73bf4e9e 100644
--- a/src/backend/optimizer/util/relnode.c
+++ b/src/backend/optimizer/util/relnode.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/optimizer/util/relnode.c,v 1.44 2003/01/20 18:54:56 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/optimizer/util/relnode.c,v 1.45 2003/01/24 03:58:43 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -549,14 +549,19 @@ subbuild_joinrel_joinlist(RelOptInfo *joinrel,
/*
* These clauses are still join clauses at this level, so find
* or make the appropriate JoinInfo item for the joinrel, and
- * add the clauses to it (eliminating duplicates).
+ * add the clauses to it, eliminating duplicates. (Since
+ * RestrictInfo nodes are normally multiply-linked rather than
+ * copied, pointer equality should be a sufficient test. If
+ * two equal() nodes should happen to sneak in, no great harm
+ * is done --- they'll be detected by redundant-clause testing
+ * when they reach a restriction list.)
*/
JoinInfo *new_joininfo;
new_joininfo = make_joininfo_node(joinrel, new_unjoined_relids);
new_joininfo->jinfo_restrictinfo =
- set_union(new_joininfo->jinfo_restrictinfo,
- joininfo->jinfo_restrictinfo);
+ set_ptrUnion(new_joininfo->jinfo_restrictinfo,
+ joininfo->jinfo_restrictinfo);
}
}
}
diff --git a/src/backend/optimizer/util/restrictinfo.c b/src/backend/optimizer/util/restrictinfo.c
index bc1fcc36464..bdcc338d609 100644
--- a/src/backend/optimizer/util/restrictinfo.c
+++ b/src/backend/optimizer/util/restrictinfo.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/optimizer/util/restrictinfo.c,v 1.15 2002/11/24 21:52:14 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/optimizer/util/restrictinfo.c,v 1.16 2003/01/24 03:58:43 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -17,6 +17,7 @@
#include "optimizer/clauses.h"
#include "optimizer/paths.h"
#include "optimizer/restrictinfo.h"
+#include "optimizer/var.h"
/*
@@ -101,6 +102,13 @@ get_actual_join_clauses(List *restrictinfo_list,
* equality between any set member on the left and any member on the right;
* by transitivity, all the rest are then equal.
*
+ * However, clauses that are of the form "var expr = const expr" cannot be
+ * eliminated as redundant. This is because when there are const expressions
+ * in a pathkey set, generate_implied_equalities() suppresses "var = var"
+ * clauses in favor of "var = const" clauses. We cannot afford to drop any
+ * of the latter, even though they might seem redundant by the pathkey
+ * membership test.
+ *
* Weird special case: if we have two clauses that seem redundant
* except one is pushed down into an outer join and the other isn't,
* then they're not really redundant, because one constrains the
@@ -120,7 +128,7 @@ remove_redundant_join_clauses(Query *root, List *restrictinfo_list,
{
RestrictInfo *rinfo = (RestrictInfo *) lfirst(item);
- /* eliminate duplicates */
+ /* always eliminate duplicates */
if (member(rinfo, result))
continue;
@@ -132,6 +140,7 @@ remove_redundant_join_clauses(Query *root, List *restrictinfo_list,
cache_mergeclause_pathkeys(root, rinfo);
+ /* do the cheap tests first */
foreach(olditem, result)
{
RestrictInfo *oldrinfo = (RestrictInfo *) lfirst(olditem);
@@ -148,7 +157,20 @@ remove_redundant_join_clauses(Query *root, List *restrictinfo_list,
}
if (redundant)
- continue;
+ {
+ /*
+ * It looks redundant, now check for "var = const" case.
+ * If left_relids/right_relids are set, then there are
+ * definitely vars on both sides; else we must check the
+ * hard way.
+ */
+ if (rinfo->left_relids)
+ continue; /* var = var, so redundant */
+ if (contain_var_clause(get_leftop(rinfo->clause)) &&
+ contain_var_clause(get_rightop(rinfo->clause)))
+ continue; /* var = var, so redundant */
+ /* else var = const, not redundant */
+ }
}
/* otherwise, add it to result list */