aboutsummaryrefslogtreecommitdiff
path: root/src/backend/optimizer/util/restrictinfo.c
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2003-06-15 22:51:45 +0000
committerTom Lane <tgl@sss.pgh.pa.us>2003-06-15 22:51:45 +0000
commitcb02610e503957d7ed9b4375537fb6275c16f1fa (patch)
tree540391048748403dc597c35b4cb662d2d4cc3494 /src/backend/optimizer/util/restrictinfo.c
parent3fb6f1347ffbfcbba48b37ea35925f6b19821bf6 (diff)
downloadpostgresql-cb02610e503957d7ed9b4375537fb6275c16f1fa.tar.gz
postgresql-cb02610e503957d7ed9b4375537fb6275c16f1fa.zip
Adjust nestloop-with-inner-indexscan plan generation so that we catch
some cases of redundant clauses that were formerly not caught. We have to special-case this because the clauses involved never get attached to the same join restrictlist and so the existing logic does not notice that they are redundant.
Diffstat (limited to 'src/backend/optimizer/util/restrictinfo.c')
-rw-r--r--src/backend/optimizer/util/restrictinfo.c170
1 files changed, 118 insertions, 52 deletions
diff --git a/src/backend/optimizer/util/restrictinfo.c b/src/backend/optimizer/util/restrictinfo.c
index bdcc338d609..334fc5784cf 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.16 2003/01/24 03:58:43 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/optimizer/util/restrictinfo.c,v 1.17 2003/06/15 22:51:45 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -20,6 +20,12 @@
#include "optimizer/var.h"
+static bool join_clause_is_redundant(Query *root,
+ RestrictInfo *rinfo,
+ List *reference_list,
+ JoinType jointype);
+
+
/*
* restriction_is_or_clause
*
@@ -94,6 +100,76 @@ get_actual_join_clauses(List *restrictinfo_list,
* discussion). We detect that case and omit the redundant clause from the
* result list.
*
+ * The result is a fresh List, but it points to the same member nodes
+ * as were in the input.
+ */
+List *
+remove_redundant_join_clauses(Query *root, List *restrictinfo_list,
+ JoinType jointype)
+{
+ List *result = NIL;
+ List *item;
+
+ foreach(item, restrictinfo_list)
+ {
+ RestrictInfo *rinfo = (RestrictInfo *) lfirst(item);
+
+ /* drop it if redundant with any prior clause */
+ if (join_clause_is_redundant(root, rinfo, result, jointype))
+ continue;
+
+ /* otherwise, add it to result list */
+ result = lappend(result, rinfo);
+ }
+
+ return result;
+}
+
+/*
+ * select_nonredundant_join_clauses
+ *
+ * Given a list of RestrictInfo clauses that are to be applied in a join,
+ * select the ones that are not redundant with any clause in the
+ * reference_list.
+ *
+ * This is similar to remove_redundant_join_clauses, but we are looking for
+ * redundancies with a separate list of clauses (i.e., clauses that have
+ * already been applied below the join itself).
+ *
+ * Note that we assume the given restrictinfo_list has already been checked
+ * for local redundancies, so we don't check again.
+ */
+List *
+select_nonredundant_join_clauses(Query *root,
+ List *restrictinfo_list,
+ List *reference_list,
+ JoinType jointype)
+{
+ List *result = NIL;
+ List *item;
+
+ foreach(item, restrictinfo_list)
+ {
+ RestrictInfo *rinfo = (RestrictInfo *) lfirst(item);
+
+ /* drop it if redundant with any reference clause */
+ if (join_clause_is_redundant(root, rinfo, reference_list, jointype))
+ continue;
+
+ /* otherwise, add it to result list */
+ result = lappend(result, rinfo);
+ }
+
+ return result;
+}
+
+/*
+ * join_clause_is_redundant
+ * Returns true if rinfo is redundant with any clause in reference_list.
+ *
+ * This is the guts of both remove_redundant_join_clauses and
+ * select_nonredundant_join_clauses. See the docs above for motivation.
+ *
* We can detect redundant mergejoinable clauses very cheaply by using their
* left and right pathkeys, which uniquely identify the sets of equijoined
* variables in question. All the members of a pathkey set that are in the
@@ -113,69 +189,59 @@ get_actual_join_clauses(List *restrictinfo_list,
* except one is pushed down into an outer join and the other isn't,
* then they're not really redundant, because one constrains the
* joined rows after addition of null fill rows, and the other doesn't.
- *
- * The result is a fresh List, but it points to the same member nodes
- * as were in the input.
*/
-List *
-remove_redundant_join_clauses(Query *root, List *restrictinfo_list,
- JoinType jointype)
+static bool
+join_clause_is_redundant(Query *root,
+ RestrictInfo *rinfo,
+ List *reference_list,
+ JoinType jointype)
{
- List *result = NIL;
- List *item;
+ /* always consider exact duplicates redundant */
+ /* XXX would it be sufficient to use ptrMember here? */
+ if (member(rinfo, reference_list))
+ return true;
- foreach(item, restrictinfo_list)
+ /* check for redundant merge clauses */
+ if (rinfo->mergejoinoperator != InvalidOid)
{
- RestrictInfo *rinfo = (RestrictInfo *) lfirst(item);
+ bool redundant = false;
+ List *refitem;
- /* always eliminate duplicates */
- if (member(rinfo, result))
- continue;
+ cache_mergeclause_pathkeys(root, rinfo);
- /* check for redundant merge clauses */
- if (rinfo->mergejoinoperator != InvalidOid)
+ /* do the cheap tests first */
+ foreach(refitem, reference_list)
{
- bool redundant = false;
- List *olditem;
+ RestrictInfo *refrinfo = (RestrictInfo *) lfirst(refitem);
- cache_mergeclause_pathkeys(root, rinfo);
-
- /* do the cheap tests first */
- foreach(olditem, result)
+ if (refrinfo->mergejoinoperator != InvalidOid &&
+ rinfo->left_pathkey == refrinfo->left_pathkey &&
+ rinfo->right_pathkey == refrinfo->right_pathkey &&
+ (rinfo->ispusheddown == refrinfo->ispusheddown ||
+ !IS_OUTER_JOIN(jointype)))
{
- RestrictInfo *oldrinfo = (RestrictInfo *) lfirst(olditem);
-
- if (oldrinfo->mergejoinoperator != InvalidOid &&
- rinfo->left_pathkey == oldrinfo->left_pathkey &&
- rinfo->right_pathkey == oldrinfo->right_pathkey &&
- (rinfo->ispusheddown == oldrinfo->ispusheddown ||
- !IS_OUTER_JOIN(jointype)))
- {
- redundant = true;
- break;
- }
- }
-
- if (redundant)
- {
- /*
- * 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 */
+ redundant = true;
+ break;
}
}
- /* otherwise, add it to result list */
- result = lappend(result, rinfo);
+ if (redundant)
+ {
+ /*
+ * 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)
+ return true; /* var = var, so redundant */
+ if (contain_var_clause(get_leftop(rinfo->clause)) &&
+ contain_var_clause(get_rightop(rinfo->clause)))
+ return true; /* var = var, so redundant */
+ /* else var = const, not redundant */
+ }
}
- return result;
+ /* otherwise, not redundant */
+ return false;
}