Allow index use with OR clauses.

This commit is contained in:
Bruce Momjian 1998-08-01 22:12:13 +00:00
parent 0668aa8817
commit 0a2e5cdfc9
9 changed files with 289 additions and 318 deletions

View File

@ -7,7 +7,7 @@
* *
* *
* IDENTIFICATION * 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) foreach(clause, qual)
{ {
result = ExecQualClause((Node *) lfirst(clause), econtext); result = ExecQualClause((Node *) lfirst(clause), econtext);
if (result == true) if (result == true)
break; break;

View File

@ -7,7 +7,7 @@
* *
* *
* IDENTIFICATION * 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; IndexScanState *indexstate;
ScanDirection direction; ScanDirection direction;
Snapshot snapshot; Snapshot snapshot;
int indexPtr;
IndexScanDescPtr scanDescs; IndexScanDescPtr scanDescs;
IndexScanDesc scandesc; IndexScanDesc scandesc;
Relation heapRelation; Relation heapRelation;
@ -95,6 +94,7 @@ IndexNext(IndexScan *node)
HeapTuple tuple; HeapTuple tuple;
TupleTableSlot *slot; TupleTableSlot *slot;
Buffer buffer = InvalidBuffer; Buffer buffer = InvalidBuffer;
int numIndices;
/* ---------------- /* ----------------
* extract necessary information from index scan node * extract necessary information from index scan node
@ -105,23 +105,20 @@ IndexNext(IndexScan *node)
snapshot = estate->es_snapshot; snapshot = estate->es_snapshot;
scanstate = node->scan.scanstate; scanstate = node->scan.scanstate;
indexstate = node->indxstate; indexstate = node->indxstate;
indexPtr = indexstate->iss_IndexPtr;
scanDescs = indexstate->iss_ScanDescs; scanDescs = indexstate->iss_ScanDescs;
scandesc = scanDescs[indexPtr];
heapRelation = scanstate->css_currentRelation; heapRelation = scanstate->css_currentRelation;
numIndices = indexstate->iss_NumIndices;
slot = scanstate->css_ScanTupleSlot; slot = scanstate->css_ScanTupleSlot;
/* ---------------- /* ----------------
* ok, now that we have what we need, fetch an index tuple. * ok, now that we have what we need, fetch an index tuple.
* ----------------
*/
/* ----------------
* if scanning this index succeeded then return the * if scanning this index succeeded then return the
* appropriate heap tuple.. else return NULL. * appropriate heap tuple.. else return NULL.
* ---------------- * ----------------
*/ */
while (indexstate->iss_IndexPtr < numIndices)
{
scandesc = scanDescs[indexstate->iss_IndexPtr];
while ((result = index_getnext(scandesc, direction)) != NULL) while ((result = index_getnext(scandesc, direction)) != NULL)
{ {
tuple = heap_fetch(heapRelation, snapshot, tuple = heap_fetch(heapRelation, snapshot,
@ -131,6 +128,9 @@ IndexNext(IndexScan *node)
if (tuple != NULL) if (tuple != NULL)
{ {
bool prev_matches = false;
int prev_index;
/* ---------------- /* ----------------
* store the scanned tuple in the scan tuple slot of * store the scanned tuple in the scan tuple slot of
* the scan state. Eventually we will only do this and not * the scan state. Eventually we will only do this and not
@ -144,15 +144,27 @@ IndexNext(IndexScan *node)
buffer, /* buffer associated with tuple */ buffer, /* buffer associated with tuple */
false); /* don't pfree */ false); /* don't pfree */
return slot; for (prev_index = 0; prev_index < indexstate->iss_IndexPtr;
} prev_index++)
else
{ {
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)) if (BufferIsValid(buffer))
ReleaseBuffer(buffer); ReleaseBuffer(buffer);
} }
if (indexstate->iss_IndexPtr < numIndices)
indexstate->iss_IndexPtr++;
} }
/* ---------------- /* ----------------
* if we get here it means the index scan failed so we * if we get here it means the index scan failed so we
* are at the end of the scan.. * are at the end of the scan..
@ -218,7 +230,6 @@ ExecIndexReScan(IndexScan *node, ExprContext *exprCtxt, Plan *parent)
int i; int i;
Pointer *runtimeKeyInfo; Pointer *runtimeKeyInfo;
int indexPtr;
int *numScanKeys; int *numScanKeys;
List *indxqual; List *indxqual;
List *qual; List *qual;
@ -238,31 +249,34 @@ ExecIndexReScan(IndexScan *node, ExprContext *exprCtxt, Plan *parent)
numIndices = indexstate->iss_NumIndices; numIndices = indexstate->iss_NumIndices;
scanDescs = indexstate->iss_ScanDescs; scanDescs = indexstate->iss_ScanDescs;
scanKeys = indexstate->iss_ScanKeys; scanKeys = indexstate->iss_ScanKeys;
runtimeKeyInfo = (Pointer *) indexstate->iss_RuntimeKeyInfo; runtimeKeyInfo = (Pointer *) indexstate->iss_RuntimeKeyInfo;
if (runtimeKeyInfo != NULL)
{
/*
* get the index qualifications and recalculate the appropriate
* values
*/
indexPtr = indexstate->iss_IndexPtr;
indxqual = node->indxqual; indxqual = node->indxqual;
qual = nth(indexPtr, indxqual);
numScanKeys = indexstate->iss_NumScanKeys; numScanKeys = indexstate->iss_NumScanKeys;
n_keys = numScanKeys[indexPtr]; indexstate->iss_IndexPtr = 0;
run_keys = (int *) runtimeKeyInfo[indexPtr];
scan_keys = (ScanKey) scanKeys[indexPtr];
/* it's possible in subselects */ /* it's possible in subselects */
if (exprCtxt == NULL) if (exprCtxt == NULL)
exprCtxt = node->scan.scanstate->cstate.cs_ExprContext; exprCtxt = node->scan.scanstate->cstate.cs_ExprContext;
if (exprCtxt != NULL)
node->scan.scanstate->cstate.cs_ExprContext->ecxt_outertuple =
exprCtxt->ecxt_outertuple;
/*
* get the index qualifications and recalculate the appropriate
* values
*/
for (i = 0; i < numIndices; i++)
{
if (runtimeKeyInfo && runtimeKeyInfo[i] != NULL)
{
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++) for (j = 0; j < n_keys; j++)
{ {
/* /*
* If we have a run-time key, then extract the run-time * If we have a run-time key, then extract the run-time
* expression and evaluate it with respect to the current * expression and evaluate it with respect to the current
@ -287,16 +301,6 @@ ExecIndexReScan(IndexScan *node, ExprContext *exprCtxt, Plan *parent)
scan_keys[j].sk_flags &= ~SK_ISNULL; scan_keys[j].sk_flags &= ~SK_ISNULL;
} }
} }
}
/*
* 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]; sdesc = scanDescs[i];
skey = scanKeys[i]; skey = scanKeys[i];
index_rescan(sdesc, direction, skey); index_rescan(sdesc, direction, skey);
@ -322,12 +326,15 @@ ExecEndIndexScan(IndexScan *node)
{ {
CommonScanState *scanstate; CommonScanState *scanstate;
IndexScanState *indexstate; IndexScanState *indexstate;
Pointer *runtimeKeyInfo;
ScanKey *scanKeys; ScanKey *scanKeys;
int *numScanKeys;
int numIndices; int numIndices;
int i; int i;
scanstate = node->scan.scanstate; scanstate = node->scan.scanstate;
indexstate = node->indxstate; indexstate = node->indxstate;
runtimeKeyInfo = (Pointer *) indexstate->iss_RuntimeKeyInfo;
/* ---------------- /* ----------------
* extract information from the node * extract information from the node
@ -335,6 +342,7 @@ ExecEndIndexScan(IndexScan *node)
*/ */
numIndices = indexstate->iss_NumIndices; numIndices = indexstate->iss_NumIndices;
scanKeys = indexstate->iss_ScanKeys; scanKeys = indexstate->iss_ScanKeys;
numScanKeys = indexstate->iss_NumScanKeys;
/* ---------------- /* ----------------
* Free the projection info and the scan attribute info * Free the projection info and the scan attribute info
@ -362,6 +370,23 @@ ExecEndIndexScan(IndexScan *node)
if (scanKeys[i] != NULL) if (scanKeys[i] != NULL)
pfree(scanKeys[i]); 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 * clear out tuple table slots
@ -886,20 +911,7 @@ ExecInitIndexScan(IndexScan *node, EState *estate, Plan *parent)
if (have_runtime_keys) if (have_runtime_keys)
indexstate->iss_RuntimeKeyInfo = (Pointer) runtimeKeyInfo; indexstate->iss_RuntimeKeyInfo = (Pointer) runtimeKeyInfo;
else else
{
indexstate->iss_RuntimeKeyInfo = NULL; 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 * get the range table and direction information
@ -991,6 +1003,5 @@ int
ExecCountSlotsIndexScan(IndexScan *node) ExecCountSlotsIndexScan(IndexScan *node)
{ {
return ExecCountSlotsNode(outerPlan((Plan *) node)) + return ExecCountSlotsNode(outerPlan((Plan *) node)) +
ExecCountSlotsNode(innerPlan((Plan *) node)) + ExecCountSlotsNode(innerPlan((Plan *) node)) + INDEXSCAN_NSLOTS;
INDEXSCAN_NSLOTS;
} }

View File

@ -7,7 +7,7 @@
* *
* *
* IDENTIFICATION * 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!!! ** planner/path/xfunc.c accordingly!!!
** -- JMH, 8/2/93 ** -- JMH, 8/2/93
*/ */
static RelOptInfo * static RelOptInfo *
_copyRel(RelOptInfo *from) _copyRelOptInfo(RelOptInfo *from)
{ {
RelOptInfo *newnode = makeNode(RelOptInfo); RelOptInfo *newnode = makeNode(RelOptInfo);
int i, int i,
@ -1735,7 +1735,7 @@ copyObject(void *from)
* RELATION NODES * RELATION NODES
*/ */
case T_RelOptInfo: case T_RelOptInfo:
retval = _copyRel(from); retval = _copyRelOptInfo(from);
break; break;
case T_Path: case T_Path:
retval = _copyPath(from); retval = _copyPath(from);

View File

@ -7,7 +7,7 @@
* *
* *
* IDENTIFICATION * 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))); (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 static bool
_equalJoinMethod(JoinMethod *a, JoinMethod *b) _equalJoinMethod(JoinMethod *a, JoinMethod *b)
{ {
@ -663,6 +676,9 @@ equal(void *a, void *b)
case T_CInfo: case T_CInfo:
retval = _equalCInfo(a, b); retval = _equalCInfo(a, b);
break; break;
case T_RelOptInfo:
retval = _equalRelOptInfo(a, b);
break;
case T_JoinMethod: case T_JoinMethod:
retval = _equalJoinMethod(a, b); retval = _equalJoinMethod(a, b);
break; break;

View File

@ -7,7 +7,7 @@
* *
* *
* IDENTIFICATION * 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 * NOTES
* Every (plan) node in POSTGRES has an associated "out" routine which * Every (plan) node in POSTGRES has an associated "out" routine which
@ -990,7 +990,7 @@ _outEState(StringInfo str, EState *node)
* Stuff from relation.h * Stuff from relation.h
*/ */
static void static void
_outRel(StringInfo str, RelOptInfo *node) _outRelOptInfo(StringInfo str, RelOptInfo *node)
{ {
char buf[500]; char buf[500];
@ -1788,7 +1788,7 @@ _outNode(StringInfo str, void *obj)
_outEState(str, obj); _outEState(str, obj);
break; break;
case T_RelOptInfo: case T_RelOptInfo:
_outRel(str, obj); _outRelOptInfo(str, obj);
break; break;
case T_TargetEntry: case T_TargetEntry:
_outTargetEntry(str, obj); _outTargetEntry(str, obj);

View File

@ -7,7 +7,7 @@
* *
* *
* IDENTIFICATION * 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 * NOTES
* Most of the read functions for plan nodes are tested. (In fact, they * Most of the read functions for plan nodes are tested. (In fact, they
@ -1218,11 +1218,11 @@ _readEState()
*/ */
/* ---------------- /* ----------------
* _readRel * _readRelOptInfo
* ---------------- * ----------------
*/ */
static RelOptInfo * static RelOptInfo *
_readRel() _readRelOptInfo()
{ {
RelOptInfo *local_node; RelOptInfo *local_node;
char *token; char *token;
@ -1991,7 +1991,7 @@ parsePlanString(void)
else if (!strncmp(token, "ESTATE", length)) else if (!strncmp(token, "ESTATE", length))
return_value = _readEState(); return_value = _readEState();
else if (!strncmp(token, "RELOPTINFO", length)) else if (!strncmp(token, "RELOPTINFO", length))
return_value = _readRel(); return_value = _readRelOptInfo();
else if (!strncmp(token, "TARGETENTRY", length)) else if (!strncmp(token, "TARGETENTRY", length))
return_value = _readTargetEntry(); return_value = _readTargetEntry();
else if (!strncmp(token, "RTE", length)) else if (!strncmp(token, "RTE", length))

View File

@ -7,7 +7,7 @@
* *
* *
* IDENTIFICATION * 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 Cost
compute_clause_selec(Query *root, Node *clause, List *or_selectivities) compute_clause_selec(Query *root, Node *clause, List *or_selectivities)
{ {
if (!is_opclause(clause)) if (is_opclause (clause))
{ return compute_selec(root, lcons(clause,NIL), or_selectivities);
/*
* 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);
}
else if (not_clause(clause)) else if (not_clause(clause))
{ {

View File

@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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 "access/nbtree.h"
#include "catalog/catname.h" #include "catalog/catname.h"
#include "catalog/pg_amop.h" #include "catalog/pg_amop.h"
#include "catalog/pg_type.h"
#include "executor/executor.h" #include "executor/executor.h"
#include "fmgr.h" #include "fmgr.h"
#include "nodes/makefuncs.h" #include "nodes/makefuncs.h"
@ -77,10 +78,7 @@ create_index_paths(Query *root, RelOptInfo *rel, RelOptInfo *index,
List *clausegroup_list, bool join); List *clausegroup_list, bool join);
static List *add_index_paths(List *indexpaths, List *new_indexpaths); static List *add_index_paths(List *indexpaths, List *new_indexpaths);
static bool function_index_operand(Expr *funcOpnd, RelOptInfo *rel, RelOptInfo *index); 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-- * find-index-paths--
@ -121,35 +119,25 @@ find_index_paths(Query *root,
List *joinclausegroups = NIL; List *joinclausegroups = NIL;
List *joinpaths = NIL; List *joinpaths = NIL;
List *retval = NIL; List *retval = NIL;
List *ilist;
if (indices == NIL) foreach(ilist, indices)
return (NULL); {
index = (RelOptInfo *) lfirst(ilist);
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 this is a partial index, return if it fails the predicate test */
if (index->indpred != NIL) if (index->indpred != NIL)
if (!pred_test(index->indpred, clauseinfo_list, joininfo_list)) if (!pred_test(index->indpred, clauseinfo_list, joininfo_list))
return retval; continue;
/* /*
* 1. If this index has only one key, try matching it against * 1. Try matching the index against subclauses of an 'or' clause.
* subclauses of an 'or' clause. The fields of the clauseinfo nodes * The fields of the clauseinfo nodes are marked with lists of the
* are marked with lists of the matching indices no path are actually * matching indices. No path are actually created. We currently
* created. * 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
* XXX NOTE: Currently btrees dos not support indices with > 1 key, so * second key.
* the following test will always be true for now but we have decided
* not to support index-scans on disjunction . -- lp
*/ */
if (SingleAttributeIndex(index))
{
match_index_orclauses(rel, match_index_orclauses(rel,
index, index,
index->indexkeys[0], index->indexkeys[0],
@ -205,6 +193,7 @@ find_index_paths(Query *root,
retval = add_index_paths(joinpaths, retval); retval = add_index_paths(joinpaths, retval);
if (scanpaths != NULL) if (scanpaths != NULL)
retval = add_index_paths(scanpaths, retval); retval = add_index_paths(scanpaths, retval);
}
return retval; return retval;
@ -297,7 +286,7 @@ match_index_to_operand(int indexkey,
* (1) the operator within the subclause can be used with one * (1) the operator within the subclause can be used with one
* of the index's operator classes, and * of the index's operator classes, and
* (2) there is a usable key that matches the variable within a * (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 * 'or-clauses' are the remaining subclauses within the 'or' clause
* 'other-matching-indices' is the list of information on other indices * '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 *matched_indices = other_matching_indices;
List *index_list = NIL; List *index_list = NIL;
List *clist; List *clist;
List *ind;
if (!matched_indices) foreach(clist, or_clauses)
matched_indices = lcons(NIL, NIL);
for (clist = or_clauses, ind = matched_indices;
clist;
clist = lnext(clist), ind = lnext(ind))
{ {
clause = lfirst(clist); clause = lfirst(clist);
if (is_opclause(clause) && if (is_opclause(clause) &&
op_class(((Oper *) ((Expr *) clause)->oper)->opno, op_class(((Oper *) ((Expr *) clause)->oper)->opno,
xclass, index->relam) && xclass, index->relam) &&
match_index_to_operand(indexkey, ((match_index_to_operand(indexkey,
(Expr *) get_leftop((Expr *) clause), (Expr *) get_leftop((Expr *) clause),
rel, rel,
index) && index) &&
IsA(get_rightop((Expr *) clause), Const)) IsA(get_rightop((Expr *) clause), Const)) ||
(match_index_to_operand(indexkey,
(Expr *) get_leftop((Expr *) clause),
rel,
index) &&
IsA(get_rightop((Expr *) clause), Const))))
{ {
matched_indices = lcons(index, matched_indices); 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); return (index_list);
@ -1061,7 +1051,7 @@ clause_pred_clause_test(Expr *predicate, Node *clause)
*/ */
test_oper = makeOper(test_op, /* opno */ test_oper = makeOper(test_op, /* opno */
InvalidOid, /* opid */ InvalidOid, /* opid */
BOOL_TYPEID, /* opresulttype */ BOOLOID, /* opresulttype */
0, /* opsize */ 0, /* opsize */
NULL); /* op_fcache */ NULL); /* op_fcache */
replace_opid(test_oper); replace_opid(test_oper);
@ -1176,7 +1166,8 @@ extract_restrict_clauses(List *clausegroup)
* *
*/ */
static List * 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 *clausegroup = NIL;
List *cg_list = NIL; List *cg_list = NIL;
@ -1366,29 +1357,3 @@ function_index_operand(Expr *funcOpnd, RelOptInfo *rel, RelOptInfo *index)
return true; 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
}

View File

@ -7,7 +7,7 @@
* *
* *
* IDENTIFICATION * 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) RelOptInfo *rel, List *clauses)
{ {
List *t_list = NIL; 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, * 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; index_list = clausenode->indexids;
foreach(temp, index_list) foreach(temp, index_list)
{ {
if (!temp) if (!lfirst(temp))
{
index_flag = false; index_flag = false;
break;
}
} }
if (index_flag) if (index_flag)
{ /* used to be a lisp every function */ { /* used to be a lisp every function */
@ -100,8 +104,7 @@ create_or_index_paths(Query *root,
pathnode->path.pathtype = T_IndexScan; pathnode->path.pathtype = T_IndexScan;
pathnode->path.parent = rel; pathnode->path.parent = rel;
pathnode->indexqual = pathnode->indexqual = lcons(clausenode, NIL);
lcons(clausenode, NIL);
pathnode->indexid = indexids; pathnode->indexid = indexids;
pathnode->path.path_cost = cost; pathnode->path.path_cost = cost;
@ -110,9 +113,8 @@ create_or_index_paths(Query *root,
* processing -- JMH, 7/7/92 * processing -- JMH, 7/7/92
*/ */
pathnode->path.locclauseinfo = pathnode->path.locclauseinfo =
set_difference(clauses, set_difference(copyObject((Node *)rel->clauseinfo),
copyObject((Node *) lcons(clausenode,NIL));
rel->clauseinfo));
#if 0 /* fix xfunc */ #if 0 /* fix xfunc */
/* add in cost for expensive functions! -- JMH, 7/7/92 */ /* add in cost for expensive functions! -- JMH, 7/7/92 */
@ -123,12 +125,8 @@ create_or_index_paths(Query *root,
} }
#endif #endif
clausenode->selectivity = (Cost) floatVal(selecs); clausenode->selectivity = (Cost) floatVal(selecs);
t_list = t_list = lappend(t_list, pathnode);
lcons(pathnode,
create_or_index_paths(root, rel, lnext(clauses)));
} }
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 */ Cost *cost, /* return value */
List **selecs) /* return value */ List **selecs) /* return value */
{ {
if (subclauses == NIL) List *slist;
{
*indexids = nreverse(examined_indexids); foreach (slist, subclauses)
*cost = subcost;
*selecs = nreverse(selectivities);
}
else
{ {
int best_indexid; int best_indexid;
Cost best_cost; Cost best_cost;
Cost best_selec; 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); &best_indexid, &best_cost, &best_selec);
best_or_subclause_indices(root, examined_indexids = lappendi(examined_indexids, best_indexid);
rel, subcost += best_cost;
lnext(subclauses), selectivities = lappend(selectivities, makeFloat(best_selec));
lnext(indices),
lconsi(best_indexid, examined_indexids), indices = lnext(indices);
subcost + best_cost,
lcons(makeFloat(best_selec), selectivities),
indexids,
cost,
selecs);
} }
*indexids = examined_indexids;
*cost = subcost;
*selecs = selectivities;
return; return;
} }
@ -219,20 +213,21 @@ best_or_subclause_index(Query *root,
Cost *retCost, /* return value */ Cost *retCost, /* return value */
Cost *retSelec) /* 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; Datum value;
int flag = 0; int flag = 0;
Cost subcost; Cost subcost;
RelOptInfo *index = (RelOptInfo *) lfirst(indices);
AttrNumber attno = (get_leftop(subclause))->varattno; AttrNumber attno = (get_leftop(subclause))->varattno;
Oid opno = ((Oper *) subclause->oper)->opno; Oid opno = ((Oper *) subclause->oper)->opno;
bool constant_on_right = non_null((Expr *) get_rightop(subclause)); bool constant_on_right = non_null((Expr *) get_rightop(subclause));
float npages, float npages,
selec; selec;
int subclause_indexid;
Cost subclause_cost;
Cost subclause_selec;
if (constant_on_right) if (constant_on_right)
value = ((Const *) get_rightop(subclause))->constvalue; value = ((Const *) get_rightop(subclause))->constvalue;
@ -242,6 +237,7 @@ best_or_subclause_index(Query *root,
flag = (_SELEC_IS_CONSTANT_ || _SELEC_CONSTANT_RIGHT_); flag = (_SELEC_IS_CONSTANT_ || _SELEC_CONSTANT_RIGHT_);
else else
flag = _SELEC_CONSTANT_RIGHT_; flag = _SELEC_CONSTANT_RIGHT_;
index_selectivity(lfirsti(index->relids), index_selectivity(lfirsti(index->relids),
index->classlist, index->classlist,
lconsi(opno, NIL), lconsi(opno, NIL),
@ -262,26 +258,22 @@ best_or_subclause_index(Query *root,
index->pages, index->pages,
index->tuples, index->tuples,
false); 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); *retIndexid = lfirsti(index->relids);
*retCost = subcost; *retCost = subcost;
*retSelec = selec; *retSelec = selec;
first_run = false;
} }
else }
/* we didn't get any indexes, so zero return values */
if (first_run)
{ {
*retIndexid = 0; *retIndexid = 0;
*retCost = 0.0; *retCost = 0.0;
*retSelec = 0.0; *retSelec = 0.0;
} }
}
return; return;
} }