Allow index use with OR clauses.
This commit is contained in:
parent
0668aa8817
commit
0a2e5cdfc9
@ -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;
|
||||||
|
@ -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;
|
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
|
@ -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;
|
||||||
|
@ -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);
|
||||||
|
@ -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))
|
||||||
|
@ -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))
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@ -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
|
|
||||||
}
|
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user