aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorBruce Momjian <bruce@momjian.us>1998-08-01 22:12:13 +0000
committerBruce Momjian <bruce@momjian.us>1998-08-01 22:12:13 +0000
commit0a2e5cdfc90ff60d8995409a8640a4d6f16a343d (patch)
treeea60044a4f68934a0c2b75ad3e32fd010517d418 /src
parent0668aa88179cce20362bad88c9f0be0a461bb699 (diff)
downloadpostgresql-0a2e5cdfc90ff60d8995409a8640a4d6f16a343d.tar.gz
postgresql-0a2e5cdfc90ff60d8995409a8640a4d6f16a343d.zip
Allow index use with OR clauses.
Diffstat (limited to 'src')
-rw-r--r--src/backend/executor/execQual.c4
-rw-r--r--src/backend/executor/nodeIndexscan.c225
-rw-r--r--src/backend/nodes/copyfuncs.c12
-rw-r--r--src/backend/nodes/equalfuncs.c18
-rw-r--r--src/backend/nodes/outfuncs.c6
-rw-r--r--src/backend/nodes/readfuncs.c8
-rw-r--r--src/backend/optimizer/path/clausesel.c17
-rw-r--r--src/backend/optimizer/path/indxpath.c219
-rw-r--r--src/backend/optimizer/path/orindxpath.c94
9 files changed, 287 insertions, 316 deletions
diff --git a/src/backend/executor/execQual.c b/src/backend/executor/execQual.c
index 31e2791eabe..55a16f53b2f 100644
--- a/src/backend/executor/execQual.c
+++ b/src/backend/executor/execQual.c
@@ -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;
diff --git a/src/backend/executor/nodeIndexscan.c b/src/backend/executor/nodeIndexscan.c
index 51308d41014..0f9be0a129d 100644
--- a/src/backend/executor/nodeIndexscan.c
+++ b/src/backend/executor/nodeIndexscan.c
@@ -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;
}
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index 518b6f553da..fbaa1298c36 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -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);
diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c
index 3c6bbe4d306..675cb856bc6 100644
--- a/src/backend/nodes/equalfuncs.c
+++ b/src/backend/nodes/equalfuncs.c
@@ -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;
diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c
index aaa726740ff..693039405ab 100644
--- a/src/backend/nodes/outfuncs.c
+++ b/src/backend/nodes/outfuncs.c
@@ -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);
diff --git a/src/backend/nodes/readfuncs.c b/src/backend/nodes/readfuncs.c
index 39201e2613e..61032aaaa50 100644
--- a/src/backend/nodes/readfuncs.c
+++ b/src/backend/nodes/readfuncs.c
@@ -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))
diff --git a/src/backend/optimizer/path/clausesel.c b/src/backend/optimizer/path/clausesel.c
index c372b6ce644..5f495d92a7f 100644
--- a/src/backend/optimizer/path/clausesel.c
+++ b/src/backend/optimizer/path/clausesel.c
@@ -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))
{
diff --git a/src/backend/optimizer/path/indxpath.c b/src/backend/optimizer/path/indxpath.c
index 3722688a21b..b557d9d59b3 100644
--- a/src/backend/optimizer/path/indxpath.c
+++ b/src/backend/optimizer/path/indxpath.c
@@ -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
-}
diff --git a/src/backend/optimizer/path/orindxpath.c b/src/backend/optimizer/path/orindxpath.c
index c697078e1b2..7f220fc54ba 100644
--- a/src/backend/optimizer/path/orindxpath.c
+++ b/src/backend/optimizer/path/orindxpath.c
@@ -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;
}