Allow index use with OR clauses.
authorBruce Momjian
Sat, 1 Aug 1998 22:12:13 +0000 (22:12 +0000)
committerBruce Momjian
Sat, 1 Aug 1998 22:12:13 +0000 (22:12 +0000)
src/backend/executor/execQual.c
src/backend/executor/nodeIndexscan.c
src/backend/nodes/copyfuncs.c
src/backend/nodes/equalfuncs.c
src/backend/nodes/outfuncs.c
src/backend/nodes/readfuncs.c
src/backend/optimizer/path/clausesel.c
src/backend/optimizer/path/indxpath.c
src/backend/optimizer/path/orindxpath.c

index 31e2791eabebfbe7bc7e333921c6e0f51a1d019b..55a16f53b2f3c4e16f8b066f2042663b4bf214a1 100644 (file)
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/executor/execQual.c,v 1.33 1998/06/15 19:28:19 momjian Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/executor/execQual.c,v 1.34 1998/08/01 22:12:02 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -1349,8 +1349,6 @@ ExecQual(List *qual, ExprContext *econtext)
 
    foreach(clause, qual)
    {
-    
-     
        result = ExecQualClause((Node *) lfirst(clause), econtext);
        if (result == true)
            break;
index 51308d4101409e7114b93887e3e8d7c078ecc418..0f9be0a129d85097b1a451b78c4cc25927c0c7c5 100644 (file)
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/executor/nodeIndexscan.c,v 1.19 1998/07/27 19:37:57 vadim Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/executor/nodeIndexscan.c,v 1.20 1998/08/01 22:12:04 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -87,7 +87,6 @@ IndexNext(IndexScan *node)
    IndexScanState *indexstate;
    ScanDirection   direction;
    Snapshot        snapshot;
-   int         indexPtr;
    IndexScanDescPtr scanDescs;
    IndexScanDesc scandesc;
    Relation    heapRelation;
@@ -95,7 +94,8 @@ IndexNext(IndexScan *node)
    HeapTuple   tuple;
    TupleTableSlot *slot;
    Buffer      buffer = InvalidBuffer;
-
+   int         numIndices;
+   
    /* ----------------
     *  extract necessary information from index scan node
     * ----------------
@@ -105,54 +105,66 @@ IndexNext(IndexScan *node)
    snapshot = estate->es_snapshot;
    scanstate = node->scan.scanstate;
    indexstate = node->indxstate;
-   indexPtr = indexstate->iss_IndexPtr;
    scanDescs = indexstate->iss_ScanDescs;
-   scandesc = scanDescs[indexPtr];
    heapRelation = scanstate->css_currentRelation;
-
+   numIndices = indexstate->iss_NumIndices;
    slot = scanstate->css_ScanTupleSlot;
 
    /* ----------------
     *  ok, now that we have what we need, fetch an index tuple.
-    * ----------------
-    */
-
-   /* ----------------
     *  if scanning this index succeeded then return the
     *  appropriate heap tuple.. else return NULL.
     * ----------------
     */
-   while ((result = index_getnext(scandesc, direction)) != NULL)
+   while (indexstate->iss_IndexPtr < numIndices)
    {
-       tuple = heap_fetch(heapRelation, snapshot, 
-                           &result->heap_iptr, &buffer);
-       /* be tidy */
-       pfree(result);
-
-       if (tuple != NULL)
-       {
-           /* ----------------
-            *  store the scanned tuple in the scan tuple slot of
-            *  the scan state.  Eventually we will only do this and not
-            *  return a tuple.  Note: we pass 'false' because tuples
-            *  returned by amgetnext are pointers onto disk pages and
-            *  were not created with palloc() and so should not be pfree()'d.
-            * ----------------
-            */
-           ExecStoreTuple(tuple,       /* tuple to store */
-                           slot,       /* slot to store in */
-                           buffer,     /* buffer associated with tuple  */
-                           false);     /* don't pfree */
-   
-           return slot;
-       }
-       else
+       scandesc = scanDescs[indexstate->iss_IndexPtr];
+       while ((result = index_getnext(scandesc, direction)) != NULL)
        {
+           tuple = heap_fetch(heapRelation, snapshot,
+                               &result->heap_iptr, &buffer);
+           /* be tidy */
+           pfree(result);
+
+           if (tuple != NULL)
+           {
+               bool        prev_matches = false;
+               int         prev_index;
+
+               /* ----------------
+                *  store the scanned tuple in the scan tuple slot of
+                *  the scan state.  Eventually we will only do this and not
+                *  return a tuple.  Note: we pass 'false' because tuples
+                *  returned by amgetnext are pointers onto disk pages and
+                *  were not created with palloc() and so should not be pfree()'d.
+                * ----------------
+                */
+               ExecStoreTuple(tuple,       /* tuple to store */
+                               slot,       /* slot to store in */
+                               buffer,     /* buffer associated with tuple  */
+                               false);     /* don't pfree */
+               for (prev_index = 0; prev_index < indexstate->iss_IndexPtr;
+                                                               prev_index++)
+               {
+                   if (ExecQual(nth(prev_index, node->indxqual),
+                       scanstate->cstate.cs_ExprContext))
+                   {
+                       prev_matches = true;
+                       break;
+                   }
+               }
+               if (!prev_matches)
+                   return slot;
+               else
+                   ExecClearTuple(slot);
+           }
            if (BufferIsValid(buffer))
                ReleaseBuffer(buffer);
        }
+       if (indexstate->iss_IndexPtr < numIndices)
+           indexstate->iss_IndexPtr++;
    }
-
    /* ----------------
     *  if we get here it means the index scan failed so we
     *  are at the end of the scan..
@@ -218,7 +230,6 @@ ExecIndexReScan(IndexScan *node, ExprContext *exprCtxt, Plan *parent)
    int         i;
 
    Pointer    *runtimeKeyInfo;
-   int         indexPtr;
    int        *numScanKeys;
    List       *indxqual;
    List       *qual;
@@ -238,69 +249,62 @@ ExecIndexReScan(IndexScan *node, ExprContext *exprCtxt, Plan *parent)
    numIndices = indexstate->iss_NumIndices;
    scanDescs = indexstate->iss_ScanDescs;
    scanKeys = indexstate->iss_ScanKeys;
-
    runtimeKeyInfo = (Pointer *) indexstate->iss_RuntimeKeyInfo;
+   indxqual = node->indxqual;
+   numScanKeys = indexstate->iss_NumScanKeys;
+   indexstate->iss_IndexPtr = 0;
+   
+   /* it's possible in subselects */
+   if (exprCtxt == NULL)
+       exprCtxt = node->scan.scanstate->cstate.cs_ExprContext;
 
-   if (runtimeKeyInfo != NULL)
-   {
-
-       /*
-        * get the index qualifications and recalculate the appropriate
-        * values
-        */
-       indexPtr = indexstate->iss_IndexPtr;
-       indxqual = node->indxqual;
-       qual = nth(indexPtr, indxqual);
-       numScanKeys = indexstate->iss_NumScanKeys;
-       n_keys = numScanKeys[indexPtr];
-       run_keys = (int *) runtimeKeyInfo[indexPtr];
-       scan_keys = (ScanKey) scanKeys[indexPtr];
+   if (exprCtxt != NULL)
+       node->scan.scanstate->cstate.cs_ExprContext->ecxt_outertuple =
+           exprCtxt->ecxt_outertuple;
        
-       /* it's possible in subselects */
-       if (exprCtxt == NULL)
-           exprCtxt = node->scan.scanstate->cstate.cs_ExprContext;
-       
-       for (j = 0; j < n_keys; j++)
+   /*
+    * get the index qualifications and recalculate the appropriate
+    * values
+    */
+   for (i = 0; i < numIndices; i++)
+   {
+       if (runtimeKeyInfo && runtimeKeyInfo[i] != NULL)
        {
-
-           /*
-            * If we have a run-time key, then extract the run-time
-            * expression and evaluate it with respect to the current
-            * outer tuple.  We then stick the result into the scan key.
-            */
-           if (run_keys[j] != NO_OP)
+           qual = nth(i, indxqual);
+           n_keys = numScanKeys[i];
+           run_keys = (int *) runtimeKeyInfo[i];
+           scan_keys = (ScanKey) scanKeys[i];
+       
+           for (j = 0; j < n_keys; j++)
            {
-               clause = nth(j, qual);
-               scanexpr = (run_keys[j] == RIGHT_OP) ?
-                   (Node *) get_rightop(clause) : (Node *) get_leftop(clause);
-
                /*
-                * pass in isDone but ignore it.  We don't iterate in
-                * quals
+                * If we have a run-time key, then extract the run-time
+                * expression and evaluate it with respect to the current
+                * outer tuple.  We then stick the result into the scan key.
                 */
-               scanvalue = (Datum)
-                   ExecEvalExpr(scanexpr, exprCtxt, &isNull, &isDone);
-               scan_keys[j].sk_argument = scanvalue;
-               if (isNull)
-                   scan_keys[j].sk_flags |= SK_ISNULL;
-               else
-                   scan_keys[j].sk_flags &= ~SK_ISNULL;
+               if (run_keys[j] != NO_OP)
+               {
+                   clause = nth(j, qual);
+                   scanexpr = (run_keys[j] == RIGHT_OP) ?
+                       (Node *) get_rightop(clause) : (Node *) get_leftop(clause);
+   
+                   /*
+                    * pass in isDone but ignore it.  We don't iterate in
+                    * quals
+                    */
+                   scanvalue = (Datum)
+                       ExecEvalExpr(scanexpr, exprCtxt, &isNull, &isDone);
+                   scan_keys[j].sk_argument = scanvalue;
+                   if (isNull)
+                       scan_keys[j].sk_flags |= SK_ISNULL;
+                   else
+                       scan_keys[j].sk_flags &= ~SK_ISNULL;
+               }
            }
+           sdesc = scanDescs[i];
+           skey = scanKeys[i];
+           index_rescan(sdesc, direction, skey);
        }
-   }
-
-   /*
-    * rescans all indices
-    *
-    * note: AMrescan assumes only one scan key.  This may have to change if
-    * we ever decide to support multiple keys.
-    */
-   for (i = 0; i < numIndices; i++)
-   {
-       sdesc = scanDescs[i];
-       skey = scanKeys[i];
-       index_rescan(sdesc, direction, skey);
-   }
 
    /* ----------------
     *  perhaps return something meaningful
@@ -322,19 +326,23 @@ ExecEndIndexScan(IndexScan *node)
 {
    CommonScanState *scanstate;
    IndexScanState *indexstate;
+   Pointer    *runtimeKeyInfo;
    ScanKey    *scanKeys;
+   int        *numScanKeys;
    int         numIndices;
    int         i;
 
    scanstate = node->scan.scanstate;
    indexstate = node->indxstate;
-
+   runtimeKeyInfo = (Pointer *) indexstate->iss_RuntimeKeyInfo;
+   
    /* ----------------
     *  extract information from the node
     * ----------------
     */
    numIndices = indexstate->iss_NumIndices;
    scanKeys = indexstate->iss_ScanKeys;
+   numScanKeys = indexstate->iss_NumScanKeys;
 
    /* ----------------
     *  Free the projection info and the scan attribute info
@@ -362,7 +370,24 @@ ExecEndIndexScan(IndexScan *node)
        if (scanKeys[i] != NULL)
            pfree(scanKeys[i]);
    }
+   pfree(scanKeys);
+   pfree(numScanKeys);
+
+   if (runtimeKeyInfo)
+   {   
+       for (i = 0; i < numIndices; i++)
+       {
+           List       *qual;
+           int         n_keys;
 
+           qual = nth(i, indxqual);
+           n_keys = length(qual);
+           if (n_keys > 0)
+               pfree(runtimeKeyInfo[i]);
+       }
+       pfree(runtimeKeyInfo);
+   }
+   
    /* ----------------
     *  clear out tuple table slots
     * ----------------
@@ -430,7 +455,7 @@ ExecIndexRestrPos(IndexScan *node)
 
 /* ----------------------------------------------------------------
  *     ExecInitIndexScan
- *
 *
  *     Initializes the index scan's state information, creates
  *     scan keys, and opens the base and index relations.
  *
@@ -886,20 +911,7 @@ ExecInitIndexScan(IndexScan *node, EState *estate, Plan *parent)
    if (have_runtime_keys)
        indexstate->iss_RuntimeKeyInfo = (Pointer) runtimeKeyInfo;
    else
-   {
        indexstate->iss_RuntimeKeyInfo = NULL;
-       for (i = 0; i < numIndices; i++)
-       {
-           List       *qual;
-           int         n_keys;
-
-           qual = nth(i, indxqual);
-           n_keys = length(qual);
-           if (n_keys > 0)
-               pfree(runtimeKeyInfo[i]);
-       }
-       pfree(runtimeKeyInfo);
-   }
 
    /* ----------------
     *  get the range table and direction information
@@ -991,6 +1003,5 @@ int
 ExecCountSlotsIndexScan(IndexScan *node)
 {
    return ExecCountSlotsNode(outerPlan((Plan *) node)) +
-   ExecCountSlotsNode(innerPlan((Plan *) node)) +
-   INDEXSCAN_NSLOTS;
+          ExecCountSlotsNode(innerPlan((Plan *) node)) + INDEXSCAN_NSLOTS;
 }
index 518b6f553da12d7de6f3ef91ef017047c36dcbeb..fbaa1298c3661aed8b99c7cea9f8c3e672369cb3 100644 (file)
@@ -1,4 +1,4 @@
-/*-------------------------------------------------------------------------
+ /*-------------------------------------------------------------------------
  *
  * copyfuncs.c--
  *   Copy functions for Postgres tree nodes.
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.44 1998/07/18 04:22:25 momjian Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.45 1998/08/01 22:12:05 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -990,16 +990,16 @@ _copyArrayRef(ArrayRef *from)
  */
 
 /* ----------------
- *     _copyRel
+ *     _copyRelOptInfo
  * ----------------
  */
 /*
- ** when you change this, also make sure to fix up xfunc_copyRel in
+ ** when you change this, also make sure to fix up xfunc_copyRelOptInfo in
  ** planner/path/xfunc.c accordingly!!!
  **            -- JMH, 8/2/93
  */
 static RelOptInfo *
-_copyRel(RelOptInfo *from)
+_copyRelOptInfo(RelOptInfo *from)
 {
    RelOptInfo         *newnode = makeNode(RelOptInfo);
    int         i,
@@ -1735,7 +1735,7 @@ copyObject(void *from)
             * RELATION NODES
             */
        case T_RelOptInfo:
-           retval = _copyRel(from);
+           retval = _copyRelOptInfo(from);
            break;
        case T_Path:
            retval = _copyPath(from);
index 3c6bbe4d306e33743443991ea0b424f26b1757c3..675cb856bc6adf4ba0ee447d2287bbb00cac8ecb 100644 (file)
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.16 1998/02/26 04:32:07 momjian Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.17 1998/08/01 22:12:07 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -302,6 +302,19 @@ _equalCInfo(CInfo *a, CInfo *b)
                  (b->indexids)));
 }
 
+/*
+ * RelOptInfo is a subclass of Node.
+ */
+static bool
+_equalRelOptInfo(RelOptInfo *a, RelOptInfo *b)
+{
+   Assert(IsA(a, RelOptInfo));
+   Assert(IsA(b, RelOptInfo));
+
+   return (equal((a->relids),
+                 (b->relids)));
+}
+
 static bool
 _equalJoinMethod(JoinMethod *a, JoinMethod *b)
 {
@@ -663,6 +676,9 @@ equal(void *a, void *b)
        case T_CInfo:
            retval = _equalCInfo(a, b);
            break;
+       case T_RelOptInfo:
+           retval = _equalRelOptInfo(a, b);
+           break;
        case T_JoinMethod:
            retval = _equalJoinMethod(a, b);
            break;
index aaa726740ff1302823c3cfb23df731b4edea8d66..693039405abe9a94275f099dc925a158389f341f 100644 (file)
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/nodes/outfuncs.c,v 1.41 1998/07/18 04:22:26 momjian Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/nodes/outfuncs.c,v 1.42 1998/08/01 22:12:08 momjian Exp $
  *
  * NOTES
  *   Every (plan) node in POSTGRES has an associated "out" routine which
@@ -990,7 +990,7 @@ _outEState(StringInfo str, EState *node)
  * Stuff from relation.h
  */
 static void
-_outRel(StringInfo str, RelOptInfo *node)
+_outRelOptInfo(StringInfo str, RelOptInfo *node)
 {
    char        buf[500];
 
@@ -1788,7 +1788,7 @@ _outNode(StringInfo str, void *obj)
                _outEState(str, obj);
                break;
            case T_RelOptInfo:
-               _outRel(str, obj);
+               _outRelOptInfo(str, obj);
                break;
            case T_TargetEntry:
                _outTargetEntry(str, obj);
index 39201e2613e1f767c947fb6035c9e282eee78750..61032aaaa502b59795a096eb929f5b5f5dd9459e 100644 (file)
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/nodes/readfuncs.c,v 1.33 1998/07/18 04:22:26 momjian Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/nodes/readfuncs.c,v 1.34 1998/08/01 22:12:09 momjian Exp $
  *
  * NOTES
  *   Most of the read functions for plan nodes are tested. (In fact, they
@@ -1218,11 +1218,11 @@ _readEState()
  */
 
 /* ----------------
- *     _readRel
+ *     _readRelOptInfo
  * ----------------
  */
 static RelOptInfo *
-_readRel()
+_readRelOptInfo()
 {
    RelOptInfo         *local_node;
    char       *token;
@@ -1991,7 +1991,7 @@ parsePlanString(void)
    else if (!strncmp(token, "ESTATE", length))
        return_value = _readEState();
    else if (!strncmp(token, "RELOPTINFO", length))
-       return_value = _readRel();
+       return_value = _readRelOptInfo();
    else if (!strncmp(token, "TARGETENTRY", length))
        return_value = _readTargetEntry();
    else if (!strncmp(token, "RTE", length))
index c372b6ce64447a9bb142fd42008976e9921b9001..5f495d92a7ffd2d2486154514ad6242dd7ae1939 100644 (file)
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/optimizer/path/clausesel.c,v 1.9 1998/07/18 04:22:30 momjian Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/optimizer/path/clausesel.c,v 1.10 1998/08/01 22:12:11 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -159,19 +159,8 @@ set_rest_selec(Query *root, List *clauseinfo_list)
 Cost
 compute_clause_selec(Query *root, Node *clause, List *or_selectivities)
 {
-   if (!is_opclause(clause))
-   {
-
-       /*
-        * if it's not an operator clause, then it is a boolean clause
-        * -jolly
-        */
-
-       /*
-        * Boolean variables get a selectivity of 1/2.
-        */
-       return (0.1);
-   }
+    if (is_opclause (clause))
+       return compute_selec(root, lcons(clause,NIL), or_selectivities);
    else if (not_clause(clause))
    {
 
index 3722688a21b4aa908fbb7a78edde5a2de53c16c0..b557d9d59b34d2a7b3bdbbd8ce4fdcde0b7f8739 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/optimizer/path/indxpath.c,v 1.19 1998/07/31 15:10:40 vadim Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/optimizer/path/indxpath.c,v 1.20 1998/08/01 22:12:12 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -21,6 +21,7 @@
 #include "access/nbtree.h"
 #include "catalog/catname.h"
 #include "catalog/pg_amop.h"
+#include "catalog/pg_type.h"
 #include "executor/executor.h"
 #include "fmgr.h"
 #include "nodes/makefuncs.h"
@@ -77,10 +78,7 @@ create_index_paths(Query *root, RelOptInfo *rel, RelOptInfo *index,
                   List *clausegroup_list, bool join);
 static List *add_index_paths(List *indexpaths, List *new_indexpaths);
 static bool function_index_operand(Expr *funcOpnd, RelOptInfo *rel, RelOptInfo *index);
-static bool SingleAttributeIndex(RelOptInfo *index);
 
-/* If Spyros can use a constant PRS2_BOOL_TYPEID, I can use this */
-#define BOOL_TYPEID ((Oid) 16)
 
 /*
  * find-index-paths--
@@ -121,91 +119,82 @@ find_index_paths(Query *root,
    List       *joinclausegroups = NIL;
    List       *joinpaths = NIL;
    List       *retval = NIL;
-
-   if (indices == NIL)
-       return (NULL);
-
-   index = (RelOptInfo *) lfirst(indices);
-
-   retval = find_index_paths(root,
-                             rel,
-                             lnext(indices),
-                             clauseinfo_list,
-                             joininfo_list);
-
-   /* If this is a partial index, return if it fails the predicate test */
-   if (index->indpred != NIL)
-       if (!pred_test(index->indpred, clauseinfo_list, joininfo_list))
-           return retval;
-
-   /*
-    * 1. If this index has only one key, try matching it against
-    * subclauses of an 'or' clause.  The fields of the clauseinfo nodes
-    * are marked with lists of the matching indices no path are actually
-    * created.
-    *
-    * XXX NOTE:  Currently btrees dos not support indices with > 1 key, so
-    * the following test will always be true for now but we have decided
-    * not to support index-scans on disjunction . -- lp
-    */
-   if (SingleAttributeIndex(index))
+   List       *ilist;
+   
+   foreach(ilist, indices)
    {
+       index = (RelOptInfo *) lfirst(ilist);
+   
+       /* If this is a partial index, return if it fails the predicate test */
+       if (index->indpred != NIL)
+           if (!pred_test(index->indpred, clauseinfo_list, joininfo_list))
+               continue;
+   
+       /*
+        * 1. Try matching the index against subclauses of an 'or' clause.
+        * The fields of the clauseinfo nodes are marked with lists of the
+        * matching indices.  No path are actually created.  We currently
+        * only look to match the first key.  We don't find multi-key index
+        * cases where an AND matches the first key, and the OR matches the
+        * second key.
+        */
        match_index_orclauses(rel,
-                             index,
-                             index->indexkeys[0],
-                             index->classlist[0],
-                             clauseinfo_list);
-   }
-
-   /*
-    * 2. If the keys of this index match any of the available restriction
-    * clauses, then create pathnodes corresponding to each group of
-    * usable clauses.
-    */
-   scanclausegroups = group_clauses_by_indexkey(rel,
-                                                index,
-                                                index->indexkeys,
-                                                index->classlist,
-                                                clauseinfo_list);
-
-   scanpaths = NIL;
-   if (scanclausegroups != NIL)
-       scanpaths = create_index_paths(root,
-                                      rel,
-                                      index,
-                                      scanclausegroups,
-                                      false);
-
-   /*
-    * 3. If this index can be used with any join clause, then create
-    * pathnodes for each group of usable clauses.  An index can be used
-    * with a join clause if its ordering is useful for a 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, clauseinfo_list);
-   joinpaths = NIL;
-
-   if (joinclausegroups != NIL)
-   {
-       List       *new_join_paths = create_index_paths(root, rel,
-                                                       index,
-                                                       joinclausegroups,
-                                                       true);
-       List       *innerjoin_paths = index_innerjoin(root, rel, joinclausegroups, index);
-
-       rel->innerjoin = nconc(rel->innerjoin, innerjoin_paths);
-       joinpaths = new_join_paths;
+                                 index,
+                                 index->indexkeys[0],
+                                 index->classlist[0],
+                                 clauseinfo_list);
+       }
+   
+       /*
+        * 2. If the keys of this index match any of the available restriction
+        * clauses, then create pathnodes corresponding to each group of
+        * usable clauses.
+        */
+       scanclausegroups = group_clauses_by_indexkey(rel,
+                                                    index,
+                                                    index->indexkeys,
+                                                    index->classlist,
+                                                    clauseinfo_list);
+   
+       scanpaths = NIL;
+       if (scanclausegroups != NIL)
+           scanpaths = create_index_paths(root,
+                                          rel,
+                                          index,
+                                          scanclausegroups,
+                                          false);
+   
+       /*
+        * 3. If this index can be used with any join clause, then create
+        * pathnodes for each group of usable clauses.  An index can be used
+        * with a join clause if its ordering is useful for a 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, clauseinfo_list);
+       joinpaths = NIL;
+   
+       if (joinclausegroups != NIL)
+       {
+           List       *new_join_paths = create_index_paths(root, rel,
+                                                           index,
+                                                           joinclausegroups,
+                                                           true);
+           List       *innerjoin_paths = index_innerjoin(root, rel, joinclausegroups, index);
+   
+           rel->innerjoin = nconc(rel->innerjoin, innerjoin_paths);
+           joinpaths = new_join_paths;
+       }
+   
+       /*
+        * Some sanity checks to make sure that the indexpath is valid.
+        */
+       if (joinpaths != NULL)
+           retval = add_index_paths(joinpaths, retval);
+       if (scanpaths != NULL)
+           retval = add_index_paths(scanpaths, retval);
    }
-
-   /*
-    * Some sanity checks to make sure that the indexpath is valid.
-    */
-   if (joinpaths != NULL)
-       retval = add_index_paths(joinpaths, retval);
-   if (scanpaths != NULL)
-       retval = add_index_paths(scanpaths, retval);
-
+   
    return retval;
 
 }
@@ -297,7 +286,7 @@ match_index_to_operand(int indexkey,
  *   (1) the operator within the subclause can be used with one
  *             of the index's operator classes, and
  *   (2) there is a usable key that matches the variable within a
- *             sargable clause.
+ *             searchable clause.
  *
  * 'or-clauses' are the remaining subclauses within the 'or' clause
  * 'other-matching-indices' is the list of information on other indices
@@ -322,30 +311,31 @@ match_index_orclause(RelOptInfo *rel,
    List       *matched_indices = other_matching_indices;
    List       *index_list = NIL;
    List       *clist;
-   List       *ind;
-
-   if (!matched_indices)
-       matched_indices = lcons(NIL, NIL);
 
-   for (clist = or_clauses, ind = matched_indices;
-        clist;
-        clist = lnext(clist), ind = lnext(ind))
+   foreach(clist, or_clauses)
    {
        clause = lfirst(clist);
        if (is_opclause(clause) &&
            op_class(((Oper *) ((Expr *) clause)->oper)->opno,
                     xclass, index->relam) &&
-           match_index_to_operand(indexkey,
+           ((match_index_to_operand(indexkey,
+                                  (Expr *) get_leftop((Expr *) clause),
+                                  rel,
+                                  index) &&
+             IsA(get_rightop((Expr *) clause), Const)) ||
+            (match_index_to_operand(indexkey,
                                   (Expr *) get_leftop((Expr *) clause),
                                   rel,
                                   index) &&
-           IsA(get_rightop((Expr *) clause), Const))
+            IsA(get_rightop((Expr *) clause), Const))))
        {
-
            matched_indices = lcons(index, matched_indices);
-           index_list = lappend(index_list,
-                                matched_indices);
        }
+       index_list = lappend(index_list, matched_indices);
+
+       /* for the first index, we are creating the indexids list */
+       if (matched_indices)
+           matched_indices = lnext(matched_indices);
    }
    return (index_list);
 
@@ -1061,7 +1051,7 @@ clause_pred_clause_test(Expr *predicate, Node *clause)
     */
    test_oper = makeOper(test_op,       /* opno */
                         InvalidOid,    /* opid */
-                        BOOL_TYPEID,   /* opresulttype */
+                        BOOLOID,   /* opresulttype */
                         0,     /* opsize */
                         NULL); /* op_fcache */
    replace_opid(test_oper);
@@ -1176,7 +1166,8 @@ extract_restrict_clauses(List *clausegroup)
  *
  */
 static List *
-index_innerjoin(Query *root, RelOptInfo *rel, List *clausegroup_list, RelOptInfo *index)
+index_innerjoin(Query *root, RelOptInfo *rel, List *clausegroup_list,
+               RelOptInfo *index)
 {
    List       *clausegroup = NIL;
    List       *cg_list = NIL;
@@ -1366,29 +1357,3 @@ function_index_operand(Expr *funcOpnd, RelOptInfo *rel, RelOptInfo *index)
 
    return true;
 }
-
-static bool
-SingleAttributeIndex(RelOptInfo *index)
-{
-
-   /*
-    * return false for now as I don't know if we support index scans on
-    * disjunction and the code doesn't work
-    */
-   return (false);
-
-#if 0
-
-   /*
-    * Non-functional indices.
-    */
-   if (index->indproc == InvalidOid)
-       return (index->indexkeys[0] != 0 &&
-               index->indexkeys[1] == 0);
-
-   /*
-    * We have a functional index which is a single attr index
-    */
-   return true;
-#endif
-}
index c697078e1b20986f417959d85d057ee7749b217e..7f220fc54bae2af6b1805a2b4fe8791e833705de 100644 (file)
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/optimizer/path/orindxpath.c,v 1.7 1998/07/18 04:22:33 momjian Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/optimizer/path/orindxpath.c,v 1.8 1998/08/01 22:12:13 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -55,10 +55,11 @@ create_or_index_paths(Query *root,
                      RelOptInfo *rel, List *clauses)
 {
    List       *t_list = NIL;
+   List       *clist;
 
-   if (clauses != NIL)
+   foreach(clist, clauses)
    {
-       CInfo      *clausenode = (CInfo *) (lfirst(clauses));
+       CInfo      *clausenode = (CInfo *) (lfirst(clist));
 
        /*
         * Check to see if this clause is an 'or' clause, and, if so,
@@ -77,8 +78,11 @@ create_or_index_paths(Query *root,
            index_list = clausenode->indexids;
            foreach(temp, index_list)
            {
-               if (!temp)
+               if (!lfirst(temp))
+               {
                    index_flag = false;
+                   break;
+               }
            }
            if (index_flag)
            {                   /* used to be a lisp every function */
@@ -100,8 +104,7 @@ create_or_index_paths(Query *root,
 
                pathnode->path.pathtype = T_IndexScan;
                pathnode->path.parent = rel;
-               pathnode->indexqual =
-                   lcons(clausenode, NIL);
+               pathnode->indexqual = lcons(clausenode, NIL);
                pathnode->indexid = indexids;
                pathnode->path.path_cost = cost;
 
@@ -110,9 +113,8 @@ create_or_index_paths(Query *root,
                 * processing    -- JMH, 7/7/92
                 */
                pathnode->path.locclauseinfo =
-                   set_difference(clauses,
-                                  copyObject((Node *)
-                                             rel->clauseinfo));
+                   set_difference(copyObject((Node *)rel->clauseinfo),
+                                  lcons(clausenode,NIL));
 
 #if 0                          /* fix xfunc */
                /* add in cost for expensive functions!  -- JMH, 7/7/92 */
@@ -123,12 +125,8 @@ create_or_index_paths(Query *root,
                }
 #endif
                clausenode->selectivity = (Cost) floatVal(selecs);
-               t_list =
-                   lcons(pathnode,
-                      create_or_index_paths(root, rel, lnext(clauses)));
+               t_list = lappend(t_list, pathnode);
            }
-           else
-               t_list = create_or_index_paths(root, rel, lnext(clauses));
        }
    }
 
@@ -167,32 +165,28 @@ best_or_subclause_indices(Query *root,
                          Cost *cost,   /* return value */
                          List **selecs)        /* return value */
 {
-   if (subclauses == NIL)
-   {
-       *indexids = nreverse(examined_indexids);
-       *cost = subcost;
-       *selecs = nreverse(selectivities);
-   }
-   else
+   List *slist;
+   
+   foreach (slist, subclauses)
    {
        int         best_indexid;
        Cost        best_cost;
        Cost        best_selec;
 
-       best_or_subclause_index(root, rel, lfirst(subclauses), lfirst(indices),
+       best_or_subclause_index(root, rel, lfirst(slist), lfirst(indices),
                                &best_indexid, &best_cost, &best_selec);
+                               
+       examined_indexids = lappendi(examined_indexids, best_indexid);
+       subcost += best_cost;
+       selectivities = lappend(selectivities, makeFloat(best_selec));
 
-       best_or_subclause_indices(root,
-                                 rel,
-                                 lnext(subclauses),
-                                 lnext(indices),
-                                 lconsi(best_indexid, examined_indexids),
-                                 subcost + best_cost,
-                            lcons(makeFloat(best_selec), selectivities),
-                                 indexids,
-                                 cost,
-                                 selecs);
+       indices = lnext(indices);
    }
+
+   *indexids = examined_indexids;
+   *cost = subcost;
+   *selecs = selectivities;
+
    return;
 }
 
@@ -219,20 +213,21 @@ best_or_subclause_index(Query *root,
                        Cost *retCost,  /* return value */
                        Cost *retSelec) /* return value */
 {
-   if (indices != NIL)
+   List *ilist;
+   bool first_run = true;
+   
+   foreach (ilist, indices)
    {
+       RelOptInfo         *index = (RelOptInfo *) lfirst(ilist);
+       
        Datum       value;
        int         flag = 0;
        Cost        subcost;
-       RelOptInfo         *index = (RelOptInfo *) lfirst(indices);
        AttrNumber  attno = (get_leftop(subclause))->varattno;
        Oid         opno = ((Oper *) subclause->oper)->opno;
        bool        constant_on_right = non_null((Expr *) get_rightop(subclause));
        float       npages,
                    selec;
-       int         subclause_indexid;
-       Cost        subclause_cost;
-       Cost        subclause_selec;
 
        if (constant_on_right)
            value = ((Const *) get_rightop(subclause))->constvalue;
@@ -242,6 +237,7 @@ best_or_subclause_index(Query *root,
            flag = (_SELEC_IS_CONSTANT_ || _SELEC_CONSTANT_RIGHT_);
        else
            flag = _SELEC_CONSTANT_RIGHT_;
+
        index_selectivity(lfirsti(index->relids),
                          index->classlist,
                          lconsi(opno, NIL),
@@ -262,26 +258,22 @@ best_or_subclause_index(Query *root,
                             index->pages,
                             index->tuples,
                             false);
-       best_or_subclause_index(root,
-                               rel,
-                               subclause,
-                               lnext(indices),
-                               &subclause_indexid,
-                               &subclause_cost,
-                               &subclause_selec);
 
-       if (subclause_indexid == 0 || subcost < subclause_cost)
+       if (first_run || subcost < *retCost)
        {
            *retIndexid = lfirsti(index->relids);
            *retCost = subcost;
            *retSelec = selec;
+           first_run = false;
        }
-       else
-       {
-           *retIndexid = 0;
-           *retCost = 0.0;
-           *retSelec = 0.0;
-       }
+   }
+
+   /* we didn't get any indexes, so zero return values */
+   if (first_run)
+   {
+       *retIndexid = 0;
+       *retCost = 0.0;
+       *retSelec = 0.0;
    }
    return;
 }