Remove 'restrictinfojoinid' field from RestrictInfo nodes.
authorTom Lane
Sun, 25 Jul 1999 17:53:27 +0000 (17:53 +0000)
committerTom Lane
Sun, 25 Jul 1999 17:53:27 +0000 (17:53 +0000)
The only place it was being used was as temporary storage in indxpath.c,
and the logic was wrong: the same restrictinfo node could get chosen to
carry the info for two different joins.  Right fix is to return a second
list of unjoined-relids parallel to the list of clause groups.

src/backend/nodes/copyfuncs.c
src/backend/nodes/freefuncs.c
src/backend/optimizer/path/indxpath.c
src/include/nodes/relation.h

index ba412332058f79af0ae60ce02ff5d4b578eb4076..ca17faf8a5f71b14fe4571059c4a6d5996bf6e5f 100644 (file)
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.87 1999/07/24 23:21:06 tgl Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.88 1999/07/25 17:53:27 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -1321,7 +1321,6 @@ _copyRestrictInfo(RestrictInfo *from)
    Node_Copy(from, newnode, indexids);
    Node_Copy(from, newnode, mergejoinorder);
    newnode->hashjoinoperator = from->hashjoinoperator;
-   newnode->restrictinfojoinid = listCopy(from->restrictinfojoinid);
 
    return newnode;
 }
index 066f7704e0844d9979bf3986040106a6f4bab248..8bedf17fdb971187f065518a78aab0d566521eff 100644 (file)
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/nodes/Attic/freefuncs.c,v 1.22 1999/07/17 20:17:06 momjian Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/nodes/Attic/freefuncs.c,v 1.23 1999/07/25 17:53:27 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -929,7 +929,6 @@ _freeRestrictInfo(RestrictInfo *node)
    freeObject(node->clause);
    freeObject(node->indexids);
    freeObject(node->mergejoinorder);
-   freeList(node->restrictinfojoinid);
 
    pfree(node);
 }
index d2da20a5b347a20e8c06d952a651a04a7fe0e781..62996ee7d4c0aa6fc8a15c708157bb4bbf53803c 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/optimizer/path/indxpath.c,v 1.63 1999/07/24 23:21:09 tgl Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/optimizer/path/indxpath.c,v 1.64 1999/07/25 17:53:27 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -55,10 +55,11 @@ static bool one_pred_test(Expr *predicate, List *restrictinfo_list);
 static bool one_pred_clause_expr_test(Expr *predicate, Node *clause);
 static bool one_pred_clause_test(Expr *predicate, Node *clause);
 static bool clause_pred_clause_test(Expr *predicate, Node *clause);
-static List *indexable_joinclauses(RelOptInfo *rel, RelOptInfo *index,
-                     List *joininfo_list, List *restrictinfo_list);
-static List *index_innerjoin(Query *root, RelOptInfo *rel,
-               List *clausegroup_list, RelOptInfo *index);
+static void indexable_joinclauses(RelOptInfo *rel, RelOptInfo *index,
+                                 List *joininfo_list, List *restrictinfo_list,
+                                 List **clausegroups, List **outerrelids);
+static List *index_innerjoin(Query *root, RelOptInfo *rel, RelOptInfo *index,
+                            List *clausegroup_list, List *outerrelids_list);
 static List *create_index_path_group(Query *root, RelOptInfo *rel, RelOptInfo *index,
                        List *clausegroup_list, bool join);
 static bool match_index_to_operand(int indexkey, Expr *operand,
@@ -99,6 +100,7 @@ create_index_paths(Query *root,
        RelOptInfo *index = (RelOptInfo *) lfirst(ilist);
        List       *scanclausegroups;
        List       *joinclausegroups;
+       List       *joinouterrelids;
 
        /*
         * If this is a partial index, we can only use it if it passes
@@ -161,9 +163,10 @@ create_index_paths(Query *root,
         * mergejoin, or if the index can possibly be used for scanning
         * the inner relation of a nestloop join.
         */
-       joinclausegroups = indexable_joinclauses(rel, index,
-                                                joininfo_list,
-                                                restrictinfo_list);
+       indexable_joinclauses(rel, index,
+                             joininfo_list, restrictinfo_list,
+                             &joinclausegroups,
+                             &joinouterrelids);
 
        if (joinclausegroups != NIL)
        {
@@ -174,9 +177,9 @@ create_index_paths(Query *root,
                                                   joinclausegroups,
                                                   true));
            rel->innerjoin = nconc(rel->innerjoin,
-                                  index_innerjoin(root, rel,
+                                  index_innerjoin(root, rel, index,
                                                   joinclausegroups,
-                                                  index));
+                                                  joinouterrelids));
        }
    }
 
@@ -326,19 +329,23 @@ match_index_orclause(RelOptInfo *rel,
  * 'index' is a index on 'rel'.
  * 'indexkeys' are the index keys to be matched.
  * 'classes' are the classes of the index operators on those keys.
- * 'clauses' is the list of available restriction clauses for 'rel'.
+ * 'restrictinfo_list' is the list of available restriction clauses for 'rel'.
  *
  * Returns NIL if no clauses can be used with this index.
  * Otherwise, a list containing a single sublist is returned (indicating
  * to create_index_path_group() that a single IndexPath should be created).
- * The sublist is ordered by index key, and contains sublists of clauses
- * that can be used with that index key.
+ * The sublist contains the RestrictInfo nodes for all clauses that can be
+ * used with this index.
+ *
+ * The sublist is ordered by index key (but as far as I can tell, this is
+ * an implementation artifact of this routine, and is not depended on by
+ * any user of the returned list --- tgl 7/99).
  *
  * Note that in a multi-key index, we stop if we find a key that cannot be
  * used with any clause.  For example, given an index on (A,B,C), we might
- * return (((C1 C2) (C3 C4))) if we find that clauses C1 and C2 use column A,
+ * return ((C1 C2 C3 C4)) if we find that clauses C1 and C2 use column A,
  * clauses C3 and C4 use column B, and no clauses use column C.  But if no
- * clauses match B we will return (((C1 C2))), whether or not there are
+ * clauses match B we will return ((C1 C2)), whether or not there are
  * clauses matching column C, because the executor couldn't use them anyway.
  */
 static List *
@@ -1108,21 +1115,35 @@ clause_pred_clause_test(Expr *predicate, Node *clause)
  *   Finds all groups of join clauses from among 'joininfo_list' that can
  *   be used in conjunction with 'index'.
  *
- *   The first clause in the group is marked as having the other relation
- *   in the join clause as its outer join relation.
+ *   Each clause group comes from a single joininfo node plus the current
+ *   rel's restrictinfo list.  Therefore, every clause in the group references
+ *   the current rel plus the same set of other rels (except for the restrict
+ *   clauses, which only reference the current rel).  Therefore, this set
+ *    of clauses could be used as an indexqual if the relation is scanned
+ *   as the inner side of a nestloop join when the outer side contains
+ *   (at least) all those "other rels".
  *
- * Returns a list of these clause groups.
+ *   XXX Actually, given that we are considering a join that requires an
+ *   outer rel set (A,B,C), we should use all qual clauses that reference
+ *   any subset of these rels, not just the full set or none.  This is
+ *   doable with a doubly nested loop over joininfo_list; is it worth it?
  *
- *   Added: restrictinfo_list - list of restriction RestrictInfos. It's to
- *     support multi-column indices in joins and for cases
- *     when a key is in both join & restriction clauses. - vadim 03/18/97
+ * Returns two parallel lists of the same length: the clause groups,
+ * and the required outer rel set for each one.
  *
+ * 'rel' is the relation for which 'index' is defined
+ * 'joininfo_list' is the list of JoinInfo nodes for 'rel'
+ * 'restrictinfo_list' is the list of restriction clauses for 'rel'
+ * '*clausegroups' receives a list of clause sublists
+ * '*outerrelids' receives a list of relid lists
  */
-static List *
+static void
 indexable_joinclauses(RelOptInfo *rel, RelOptInfo *index,
-                     List *joininfo_list, List *restrictinfo_list)
+                     List *joininfo_list, List *restrictinfo_list,
+                     List **clausegroups, List **outerrelids)
 {
    List       *cg_list = NIL;
+   List       *relid_list = NIL;
    List       *i;
 
    foreach(i, joininfo_list)
@@ -1139,15 +1160,32 @@ indexable_joinclauses(RelOptInfo *rel, RelOptInfo *index,
                                            joininfo->jinfo_restrictinfo,
                                                       restrictinfo_list);
 
+       /*----------
+        * This code knows that group_clauses_by_ikey_for_joins() returns
+        * either NIL or a list containing a single sublist of clauses.  
+        * The line
+        *      cg_list = nconc(cg_list, clausegroups);
+        * is better read as
+        *      cg_list = lappend(cg_list, lfirst(clausegroups));
+        * That is, we are appending the only sublist returned by
+        * group_clauses_by_ikey_for_joins() to the list of clause sublists
+        * that this routine will return.  By using nconc() we recycle
+        * a cons cell that would be wasted ... whoever wrote this code
+        * was too clever by half...
+        *----------
+        */
        if (clausegroups != NIL)
        {
-           List       *clauses = lfirst(clausegroups);
-
-           ((RestrictInfo *) lfirst(clauses))->restrictinfojoinid = joininfo->unjoined_relids;
            cg_list = nconc(cg_list, clausegroups);
+           relid_list = lappend(relid_list, joininfo->unjoined_relids);
        }
    }
-   return cg_list;
+
+   /* Make sure above clever code didn't screw up */
+   Assert(length(cg_list) == length(relid_list));
+
+   *clausegroups = cg_list;
+   *outerrelids = relid_list;
 }
 
 /****************************************************************************
@@ -1159,15 +1197,17 @@ indexable_joinclauses(RelOptInfo *rel, RelOptInfo *index,
  *   Creates index path nodes corresponding to paths to be used as inner
  *   relations in nestloop joins.
  *
- * 'clausegroup-list' is a list of list of restrictinfo nodes which can use
+ * 'rel' is the relation for which 'index' is defined
+ * 'clausegroup_list' is a list of lists of restrictinfo nodes which can use
  * 'index' on their inner relation.
+ * 'outerrelids_list' is a list of the required outer rels for each group
+ * of join clauses.
  *
  * Returns a list of index pathnodes.
- *
  */
 static List *
-index_innerjoin(Query *root, RelOptInfo *rel, List *clausegroup_list,
-               RelOptInfo *index)
+index_innerjoin(Query *root, RelOptInfo *rel, RelOptInfo *index,
+               List *clausegroup_list, List *outerrelids_list)
 {
    List       *path_list = NIL;
    List       *i;
@@ -1211,7 +1251,8 @@ index_innerjoin(Query *root, RelOptInfo *rel, List *clausegroup_list,
        pathnode->indexkeys = index->indexkeys;
        pathnode->indexqual = lcons(get_actual_clauses(clausegroup), NIL);
 
-       pathnode->path.joinid = ((RestrictInfo *) lfirst(clausegroup))->restrictinfojoinid;
+       /* joinid saves the rels needed on the outer side of the join */
+       pathnode->path.joinid = lfirst(outerrelids_list);
 
        pathnode->path.path_cost = cost_index((Oid) lfirsti(index->relids),
                                              (int) temp_pages,
@@ -1235,6 +1276,7 @@ index_innerjoin(Query *root, RelOptInfo *rel, List *clausegroup_list,
            ((Path *) pathnode)->path_cost += xfunc_get_path_cost((Path *) pathnode);
 #endif
        path_list = lappend(path_list, pathnode);
+       outerrelids_list = lnext(outerrelids_list);
    }
    return path_list;
 }
@@ -1245,7 +1287,7 @@ index_innerjoin(Query *root, RelOptInfo *rel, List *clausegroup_list,
  *   (restriction or join) that can be used in conjunction with an index.
  *
  * 'rel' is the relation for which 'index' is defined
- * 'clausegroup-list' is the list of clause groups (lists of restrictinfo
+ * 'clausegroup_list' is the list of clause groups (lists of restrictinfo
  *             nodes) grouped by mergejoinorder
  * 'join' is a flag indicating whether or not the clauses are join
  *             clauses
index 416cdb0c55b2e80e07edef4eab05f1fdf7196aaa..0402fb8fb9ee1314cc7d46f81fea01aac1cfab43 100644 (file)
@@ -6,7 +6,7 @@
  *
  * Copyright (c) 1994, Regents of the University of California
  *
- * $Id: relation.h,v 1.35 1999/07/24 23:21:04 tgl Exp $
+ * $Id: relation.h,v 1.36 1999/07/25 17:53:26 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -242,7 +242,6 @@ typedef struct RestrictInfo
 
    /* hashjoin only */
    Oid         hashjoinoperator;
-   Relids      restrictinfojoinid;
 } RestrictInfo;
 
 typedef struct JoinMethod