99 *
1010 *
1111 * IDENTIFICATION
12- * $Header: /cvsroot/pgsql/src/backend/optimizer/path/indxpath.c,v 1.78 2000/01/26 05:56:34 momjian Exp $
12+ * $Header: /cvsroot/pgsql/src/backend/optimizer/path/indxpath.c,v 1.79 2000/02/05 18:26:09 tgl Exp $
1313 *
1414 *-------------------------------------------------------------------------
1515 */
@@ -51,15 +51,12 @@ typedef enum {
5151}Prefix_Status ;
5252
5353static void match_index_orclauses (RelOptInfo * rel ,IndexOptInfo * index ,
54- int indexkey ,Oid opclass ,
5554List * restrictinfo_list );
5655static List * match_index_orclause (RelOptInfo * rel ,IndexOptInfo * index ,
57- int indexkey ,Oid opclass ,
5856List * or_clauses ,
5957List * other_matching_indices );
6058static bool match_or_subclause_to_indexkey (RelOptInfo * rel ,
6159IndexOptInfo * index ,
62- int indexkey ,Oid opclass ,
6360Expr * clause );
6461static List * group_clauses_by_indexkey (RelOptInfo * rel ,IndexOptInfo * index ,
6562int * indexkeys ,Oid * classes ,
@@ -174,20 +171,11 @@ create_index_paths(Query *root,
174171 * so we can't build a path for an 'or' clause until all indexes have
175172 * been matched against it.)
176173 *
177- * We currently only look to match the first key of each index against
178- * 'or' subclauses. There are cases where a later key of a multi-key
179- * index could be used (if other top-level clauses match earlier keys
180- * of the index), but our poor brains are hurting already...
181- *
182174 * We don't even think about special handling of 'or' clauses that
183175 * involve more than one relation (ie, are join clauses).
184176 * Can we do anything useful with those?
185177 */
186- match_index_orclauses (rel ,
187- index ,
188- index -> indexkeys [0 ],
189- index -> classlist [0 ],
190- restrictinfo_list );
178+ match_index_orclauses (rel ,index ,restrictinfo_list );
191179
192180/*
193181 * 2. If the keys of this index match any of the available non-'or'
@@ -267,15 +255,11 @@ create_index_paths(Query *root,
267255 *
268256 * 'rel' is the node of the relation on which the index is defined.
269257 * 'index' is the index node.
270- * 'indexkey' is the (single) key of the index that we will consider.
271- * 'class' is the class of the operator corresponding to 'indexkey'.
272258 * 'restrictinfo_list' is the list of available restriction clauses.
273259 */
274260static void
275261match_index_orclauses (RelOptInfo * rel ,
276262IndexOptInfo * index ,
277- int indexkey ,
278- Oid opclass ,
279263List * restrictinfo_list )
280264{
281265List * i ;
@@ -292,7 +276,6 @@ match_index_orclauses(RelOptInfo *rel,
292276 */
293277restrictinfo -> subclauseindices =
294278match_index_orclause (rel ,index ,
295- indexkey ,opclass ,
296279restrictinfo -> clause -> args ,
297280restrictinfo -> subclauseindices );
298281}
@@ -305,9 +288,12 @@ match_index_orclauses(RelOptInfo *rel,
305288 *
306289 * A match means that:
307290 * (1) the operator within the subclause can be used with the
308- * index's specified operator class, and
291+ * index's specified operator class, and
309292 * (2) one operand of the subclause matches the index key.
310293 *
294+ * If a subclause is an 'and' clause, then it matches if any of its
295+ * subclauses is an opclause that matches.
296+ *
311297 * 'or_clauses' is the list of subclauses within the 'or' clause
312298 * 'other_matching_indices' is the list of information on other indices
313299 *that have already been matched to subclauses within this
@@ -323,8 +309,6 @@ match_index_orclauses(RelOptInfo *rel,
323309static List *
324310match_index_orclause (RelOptInfo * rel ,
325311IndexOptInfo * index ,
326- int indexkey ,
327- Oid opclass ,
328312List * or_clauses ,
329313List * other_matching_indices )
330314{
@@ -350,8 +334,7 @@ match_index_orclause(RelOptInfo *rel,
350334{
351335Expr * clause = lfirst (clist );
352336
353- if (match_or_subclause_to_indexkey (rel ,index ,indexkey ,opclass ,
354- clause ))
337+ if (match_or_subclause_to_indexkey (rel ,index ,clause ))
355338{
356339/* OK to add this index to sublist for this subclause */
357340lfirst (matching_indices )= lcons (index ,
@@ -368,33 +351,84 @@ match_index_orclause(RelOptInfo *rel,
368351 * See if a subclause of an OR clause matches an index.
369352 *
370353 * We accept the subclause if it is an operator clause that matches the
371- * index, or if it is an AND clause all of whose members are operators
372- * that match the index. (XXX Would accepting a single match be useful?)
354+ * index, or if it is an AND clause any of whose members is an opclause
355+ * that matches the index.
356+ *
357+ * We currently only look to match the first key of an index against
358+ * 'or' subclauses. There are cases where a later key of a multi-key
359+ * index could be used (if other top-level clauses match earlier keys
360+ * of the index), but our poor brains are hurting already...
373361 */
374362static bool
375363match_or_subclause_to_indexkey (RelOptInfo * rel ,
376364IndexOptInfo * index ,
377- int indexkey ,
378- Oid opclass ,
379365Expr * clause )
380366{
367+ int indexkey = index -> indexkeys [0 ];
368+ Oid opclass = index -> classlist [0 ];
369+
381370if (and_clause ((Node * )clause ))
382371{
383372List * item ;
384373
385374foreach (item ,clause -> args )
386375{
387- if (! match_clause_to_indexkey (rel ,index ,indexkey ,opclass ,
388- lfirst (item ), false))
389- return false ;
376+ if (match_clause_to_indexkey (rel ,index ,indexkey ,opclass ,
377+ lfirst (item ), false))
378+ return true ;
390379}
391- return true ;
380+ return false ;
392381}
393382else
394383return match_clause_to_indexkey (rel ,index ,indexkey ,opclass ,
395384clause , false);
396385}
397386
387+ /*
388+ * Given an OR subclause that has previously been determined to match
389+ * the specified index, extract a list of specific opclauses that can be
390+ * used as indexquals.
391+ *
392+ * In the simplest case this just means making a one-element list of the
393+ * given opclause. However, if the OR subclause is an AND, we have to
394+ * scan it to find the opclause(s) that match the index. (There should
395+ * be at least one, if match_or_subclause_to_indexkey succeeded, but there
396+ * could be more.) Also, we apply expand_indexqual_conditions() to convert
397+ * any special matching opclauses to indexable operators.
398+ *
399+ * The passed-in clause is not changed.
400+ */
401+ List *
402+ extract_or_indexqual_conditions (RelOptInfo * rel ,
403+ IndexOptInfo * index ,
404+ Expr * orsubclause )
405+ {
406+ List * quals = NIL ;
407+ int indexkey = index -> indexkeys [0 ];
408+ Oid opclass = index -> classlist [0 ];
409+
410+ if (and_clause ((Node * )orsubclause ))
411+ {
412+ List * item ;
413+
414+ foreach (item ,orsubclause -> args )
415+ {
416+ if (match_clause_to_indexkey (rel ,index ,indexkey ,opclass ,
417+ lfirst (item ), false))
418+ quals = lappend (quals ,lfirst (item ));
419+ }
420+ if (quals == NIL )
421+ elog (ERROR ,"extract_or_indexqual_conditions: no matching clause" );
422+ }
423+ else
424+ {
425+ /* we assume the caller passed a valid indexable qual */
426+ quals = lcons (orsubclause ,NIL );
427+ }
428+
429+ return expand_indexqual_conditions (quals );
430+ }
431+
398432
399433/****************************************************************************
400434 *---- ROUTINES TO CHECK RESTRICTIONS ----
@@ -614,8 +648,8 @@ group_clauses_by_ikey_for_joins(RelOptInfo *rel,
614648 *
615649 * Returns true if the clause can be used with this index key.
616650 *
617- * NOTE: returns false if clause is an OR or AND clause;to the extent
618- *we cope with those at all, it is done by higher-level routines.
651+ * NOTE: returns false if clause is an OR or AND clause;it is the
652+ *responsibility of higher-level routines to cope with those .
619653 */
620654static bool
621655match_clause_to_indexkey (RelOptInfo * rel ,