88 *
99 *
1010 * IDENTIFICATION
11- * $Header: /cvsroot/pgsql/src/backend/optimizer/path/indxpath.c,v 1.63 1999/07/24 23:21:09 tgl Exp $
11+ * $Header: /cvsroot/pgsql/src/backend/optimizer/path/indxpath.c,v 1.64 1999/07/25 17:53:27 tgl Exp $
1212 *
1313 *-------------------------------------------------------------------------
1414 */
@@ -55,10 +55,11 @@ static bool one_pred_test(Expr *predicate, List *restrictinfo_list);
5555static bool one_pred_clause_expr_test (Expr * predicate ,Node * clause );
5656static bool one_pred_clause_test (Expr * predicate ,Node * clause );
5757static bool clause_pred_clause_test (Expr * predicate ,Node * clause );
58- static List * indexable_joinclauses (RelOptInfo * rel ,RelOptInfo * index ,
59- List * joininfo_list ,List * restrictinfo_list );
60- static List * index_innerjoin (Query * root ,RelOptInfo * rel ,
61- List * clausegroup_list ,RelOptInfo * index );
58+ static void indexable_joinclauses (RelOptInfo * rel ,RelOptInfo * index ,
59+ List * joininfo_list ,List * restrictinfo_list ,
60+ List * * clausegroups ,List * * outerrelids );
61+ static List * index_innerjoin (Query * root ,RelOptInfo * rel ,RelOptInfo * index ,
62+ List * clausegroup_list ,List * outerrelids_list );
6263static List * create_index_path_group (Query * root ,RelOptInfo * rel ,RelOptInfo * index ,
6364List * clausegroup_list ,bool join );
6465static bool match_index_to_operand (int indexkey ,Expr * operand ,
@@ -99,6 +100,7 @@ create_index_paths(Query *root,
99100RelOptInfo * index = (RelOptInfo * )lfirst (ilist );
100101List * scanclausegroups ;
101102List * joinclausegroups ;
103+ List * joinouterrelids ;
102104
103105/*
104106 * If this is a partial index, we can only use it if it passes
@@ -161,9 +163,10 @@ create_index_paths(Query *root,
161163 * mergejoin, or if the index can possibly be used for scanning
162164 * the inner relation of a nestloop join.
163165 */
164- joinclausegroups = indexable_joinclauses (rel ,index ,
165- joininfo_list ,
166- restrictinfo_list );
166+ indexable_joinclauses (rel ,index ,
167+ joininfo_list ,restrictinfo_list ,
168+ & joinclausegroups ,
169+ & joinouterrelids );
167170
168171if (joinclausegroups != NIL )
169172{
@@ -174,9 +177,9 @@ create_index_paths(Query *root,
174177joinclausegroups ,
175178 true));
176179rel -> innerjoin = nconc (rel -> innerjoin ,
177- index_innerjoin (root ,rel ,
180+ index_innerjoin (root ,rel ,index ,
178181joinclausegroups ,
179- index ));
182+ joinouterrelids ));
180183}
181184}
182185
@@ -326,19 +329,23 @@ match_index_orclause(RelOptInfo *rel,
326329 * 'index' is a index on 'rel'.
327330 * 'indexkeys' are the index keys to be matched.
328331 * 'classes' are the classes of the index operators on those keys.
329- * 'clauses ' is the list of available restriction clauses for 'rel'.
332+ * 'restrictinfo_list ' is the list of available restriction clauses for 'rel'.
330333 *
331334 * Returns NIL if no clauses can be used with this index.
332335 * Otherwise, a list containing a single sublist is returned (indicating
333336 * to create_index_path_group() that a single IndexPath should be created).
334- * The sublist is ordered by index key, and contains sublists of clauses
335- * that can be used with that index key.
337+ * The sublist contains the RestrictInfo nodes for all clauses that can be
338+ * used with this index.
339+ *
340+ * The sublist is ordered by index key (but as far as I can tell, this is
341+ * an implementation artifact of this routine, and is not depended on by
342+ * any user of the returned list --- tgl 7/99).
336343 *
337344 * Note that in a multi-key index, we stop if we find a key that cannot be
338345 * used with any clause. For example, given an index on (A,B,C), we might
339- * return ((( C1 C2) ( C3 C4) )) if we find that clauses C1 and C2 use column A,
346+ * return ((C1 C2 C3 C4)) if we find that clauses C1 and C2 use column A,
340347 * clauses C3 and C4 use column B, and no clauses use column C. But if no
341- * clauses match B we will return ((( C1 C2) )), whether or not there are
348+ * clauses match B we will return ((C1 C2)), whether or not there are
342349 * clauses matching column C, because the executor couldn't use them anyway.
343350 */
344351static List *
@@ -1108,21 +1115,35 @@ clause_pred_clause_test(Expr *predicate, Node *clause)
11081115 * Finds all groups of join clauses from among 'joininfo_list' that can
11091116 * be used in conjunction with 'index'.
11101117 *
1111- * The first clause in the group is marked as having the other relation
1112- * in the join clause as its outer join relation.
1118+ * Each clause group comes from a single joininfo node plus the current
1119+ * rel's restrictinfo list. Therefore, every clause in the group references
1120+ * the current rel plus the same set of other rels (except for the restrict
1121+ * clauses, which only reference the current rel). Therefore, this set
1122+ * of clauses could be used as an indexqual if the relation is scanned
1123+ * as the inner side of a nestloop join when the outer side contains
1124+ * (at least) all those "other rels".
11131125 *
1114- * Returns a list of these clause groups.
1126+ * XXX Actually, given that we are considering a join that requires an
1127+ * outer rel set (A,B,C), we should use all qual clauses that reference
1128+ * any subset of these rels, not just the full set or none. This is
1129+ * doable with a doubly nested loop over joininfo_list; is it worth it?
11151130 *
1116- * Added: restrictinfo_list - list of restriction RestrictInfos. It's to
1117- *support multi-column indices in joins and for cases
1118- *when a key is in both join & restriction clauses. - vadim 03/18/97
1131+ * Returns two parallel lists of the same length: the clause groups,
1132+ * and the required outer rel set for each one.
11191133 *
1134+ * 'rel' is the relation for which 'index' is defined
1135+ * 'joininfo_list' is the list of JoinInfo nodes for 'rel'
1136+ * 'restrictinfo_list' is the list of restriction clauses for 'rel'
1137+ * '*clausegroups' receives a list of clause sublists
1138+ * '*outerrelids' receives a list of relid lists
11201139 */
1121- static List *
1140+ static void
11221141indexable_joinclauses (RelOptInfo * rel ,RelOptInfo * index ,
1123- List * joininfo_list ,List * restrictinfo_list )
1142+ List * joininfo_list ,List * restrictinfo_list ,
1143+ List * * clausegroups ,List * * outerrelids )
11241144{
11251145List * cg_list = NIL ;
1146+ List * relid_list = NIL ;
11261147List * i ;
11271148
11281149foreach (i ,joininfo_list )
@@ -1139,15 +1160,32 @@ indexable_joinclauses(RelOptInfo *rel, RelOptInfo *index,
11391160joininfo -> jinfo_restrictinfo ,
11401161restrictinfo_list );
11411162
1163+ /*----------
1164+ * This code knows that group_clauses_by_ikey_for_joins() returns
1165+ * either NIL or a list containing a single sublist of clauses.
1166+ * The line
1167+ *cg_list = nconc(cg_list, clausegroups);
1168+ * is better read as
1169+ *cg_list = lappend(cg_list, lfirst(clausegroups));
1170+ * That is, we are appending the only sublist returned by
1171+ * group_clauses_by_ikey_for_joins() to the list of clause sublists
1172+ * that this routine will return. By using nconc() we recycle
1173+ * a cons cell that would be wasted ... whoever wrote this code
1174+ * was too clever by half...
1175+ *----------
1176+ */
11421177if (clausegroups != NIL )
11431178{
1144- List * clauses = lfirst (clausegroups );
1145-
1146- ((RestrictInfo * )lfirst (clauses ))-> restrictinfojoinid = joininfo -> unjoined_relids ;
11471179cg_list = nconc (cg_list ,clausegroups );
1180+ relid_list = lappend (relid_list ,joininfo -> unjoined_relids );
11481181}
11491182}
1150- return cg_list ;
1183+
1184+ /* Make sure above clever code didn't screw up */
1185+ Assert (length (cg_list )== length (relid_list ));
1186+
1187+ * clausegroups = cg_list ;
1188+ * outerrelids = relid_list ;
11511189}
11521190
11531191/****************************************************************************
@@ -1159,15 +1197,17 @@ indexable_joinclauses(RelOptInfo *rel, RelOptInfo *index,
11591197 * Creates index path nodes corresponding to paths to be used as inner
11601198 * relations in nestloop joins.
11611199 *
1162- * 'clausegroup-list' is a list of list of restrictinfo nodes which can use
1200+ * 'rel' is the relation for which 'index' is defined
1201+ * 'clausegroup_list' is a list of lists of restrictinfo nodes which can use
11631202 * 'index' on their inner relation.
1203+ * 'outerrelids_list' is a list of the required outer rels for each group
1204+ * of join clauses.
11641205 *
11651206 * Returns a list of index pathnodes.
1166- *
11671207 */
11681208static List *
1169- index_innerjoin (Query * root ,RelOptInfo * rel ,List * clausegroup_list ,
1170- RelOptInfo * index )
1209+ index_innerjoin (Query * root ,RelOptInfo * rel ,RelOptInfo * index ,
1210+ List * clausegroup_list , List * outerrelids_list )
11711211{
11721212List * path_list = NIL ;
11731213List * i ;
@@ -1211,7 +1251,8 @@ index_innerjoin(Query *root, RelOptInfo *rel, List *clausegroup_list,
12111251pathnode -> indexkeys = index -> indexkeys ;
12121252pathnode -> indexqual = lcons (get_actual_clauses (clausegroup ),NIL );
12131253
1214- pathnode -> path .joinid = ((RestrictInfo * )lfirst (clausegroup ))-> restrictinfojoinid ;
1254+ /* joinid saves the rels needed on the outer side of the join */
1255+ pathnode -> path .joinid = lfirst (outerrelids_list );
12151256
12161257pathnode -> path .path_cost = cost_index ((Oid )lfirsti (index -> relids ),
12171258 (int )temp_pages ,
@@ -1235,6 +1276,7 @@ index_innerjoin(Query *root, RelOptInfo *rel, List *clausegroup_list,
12351276((Path * )pathnode )-> path_cost += xfunc_get_path_cost ((Path * )pathnode );
12361277#endif
12371278path_list = lappend (path_list ,pathnode );
1279+ outerrelids_list = lnext (outerrelids_list );
12381280}
12391281return path_list ;
12401282}
@@ -1245,7 +1287,7 @@ index_innerjoin(Query *root, RelOptInfo *rel, List *clausegroup_list,
12451287 * (restriction or join) that can be used in conjunction with an index.
12461288 *
12471289 * 'rel' is the relation for which 'index' is defined
1248- * 'clausegroup-list ' is the list of clause groups (lists of restrictinfo
1290+ * 'clausegroup_list ' is the list of clause groups (lists of restrictinfo
12491291 *nodes) grouped by mergejoinorder
12501292 * 'join' is a flag indicating whether or not the clauses are join
12511293 *clauses