]> granicus.if.org Git - postgresql/commitdiff
Allow index use with OR clauses.
authorBruce Momjian <bruce@momjian.us>
Sat, 1 Aug 1998 22:12:13 +0000 (22:12 +0000)
committerBruce Momjian <bruce@momjian.us>
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;
 }