1
0
mirror of https://github.com/postgres/postgres.git synced 2025-07-05 07:21:24 +03:00

Add operator strategy and comparison-value datatype fields to ScanKey.

Remove the 'strategy map' code, which was a large amount of mechanism
that no longer had any use except reverse-mapping from procedure OID to
strategy number.  Passing the strategy number to the index AM in the
first place is simpler and faster.
This is a preliminary step in planned support for cross-datatype index
operations.  I'm committing it now since the ScanKeyEntryInitialize()
API change touches quite a lot of files, and I want to commit those
changes before the tree drifts under me.
This commit is contained in:
Tom Lane
2003-11-09 21:30:38 +00:00
parent 723825afeb
commit c1d62bfd00
72 changed files with 950 additions and 2147 deletions

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/executor/nodeIndexscan.c,v 1.84 2003/09/24 18:54:01 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/executor/nodeIndexscan.c,v 1.85 2003/11/09 21:30:36 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -31,13 +31,10 @@
#include "miscadmin.h"
#include "nodes/nodeFuncs.h"
#include "optimizer/clauses.h"
#include "parser/parse_expr.h"
#include "parser/parsetree.h"
#define NO_OP 0
#define LEFT_OP 1
#define RIGHT_OP 2
/*
* In a multiple-index plan, we must take care to return any given tuple
* only once, even if it matches conditions of several index scans. Our
@ -617,8 +614,8 @@ ExecInitIndexScan(IndexScan *node, EState *estate)
{
IndexScanState *indexstate;
List *indxqual;
List *indxstrategy;
List *indxid;
List *listscan;
int i;
int numIndices;
int indexPtr;
@ -713,46 +710,49 @@ ExecInitIndexScan(IndexScan *node, EState *estate)
* build the index scan keys from the index qualification
*/
indxqual = node->indxqual;
indxstrategy = node->indxstrategy;
for (i = 0; i < numIndices; i++)
{
int j;
List *qual;
List *quals;
List *strategies;
int n_keys;
ScanKey scan_keys;
ExprState **run_keys;
int j;
qual = lfirst(indxqual);
quals = lfirst(indxqual);
indxqual = lnext(indxqual);
n_keys = length(qual);
strategies = lfirst(indxstrategy);
indxstrategy = lnext(indxstrategy);
n_keys = length(quals);
scan_keys = (n_keys <= 0) ? (ScanKey) NULL :
(ScanKey) palloc(n_keys * sizeof(ScanKeyData));
run_keys = (n_keys <= 0) ? (ExprState **) NULL :
(ExprState **) palloc(n_keys * sizeof(ExprState *));
CXT1_printf("ExecInitIndexScan: context is %d\n", CurrentMemoryContext);
/*
* for each opclause in the given qual, convert each qual's
* opclause into a single scan key
*/
listscan = qual;
for (j = 0; j < n_keys; j++)
{
OpExpr *clause; /* one clause of index qual */
Expr *leftop; /* expr on lhs of operator */
Expr *rightop; /* expr on rhs ... */
bits16 flags = 0;
int scanvar; /* which var identifies varattno */
AttrNumber varattno = 0; /* att number used in scan */
Oid opfuncid; /* operator id used in scan */
Datum scanvalue = 0; /* value used in scan (if const) */
OpExpr *clause; /* one clause of index qual */
Expr *leftop; /* expr on lhs of operator */
Expr *rightop; /* expr on rhs ... */
int flags = 0;
AttrNumber varattno; /* att number used in scan */
StrategyNumber strategy; /* op's strategy number */
RegProcedure opfuncid; /* operator proc id used in scan */
Datum scanvalue; /* value used in scan (if const) */
Oid rhstype; /* datatype of comparison value */
/*
* extract clause information from the qualification
*/
clause = (OpExpr *) lfirst(listscan);
listscan = lnext(listscan);
clause = (OpExpr *) lfirst(quals);
quals = lnext(quals);
strategy = lfirsti(strategies);
strategies = lnext(strategies);
if (!IsA(clause, OpExpr))
elog(ERROR, "indxqual is not an OpExpr");
@ -761,40 +761,17 @@ ExecInitIndexScan(IndexScan *node, EState *estate)
/*
* Here we figure out the contents of the index qual. The
* usual case is (var op const) or (const op var) which means
* we form a scan key for the attribute listed in the var node
* and use the value of the const.
* usual case is (var op const) which means we form a scan key
* for the attribute listed in the var node and use the value of
* the const as comparison data.
*
* If we don't have a const node, then it means that one of the
* var nodes refers to the "scan" tuple and is used to
* determine which attribute to scan, and the other expression
* is used to calculate the value used in scanning the index.
*
* This means our index scan's scan key is a function of
* information obtained during the execution of the plan in
* which case we need to recalculate the index scan key at run
* time.
*
* Hence, we set have_runtime_keys to true and place the
* appropriate subexpression in run_keys. The corresponding
* If we don't have a const node, it means our scan key is a
* function of information obtained during the execution of the
* plan, in which case we need to recalculate the index scan key
* at run time. Hence, we set have_runtime_keys to true and place
* the appropriate subexpression in run_keys. The corresponding
* scan key values are recomputed at run time.
*
* XXX Although this code *thinks* it can handle an indexqual
* with the indexkey on either side, in fact it cannot.
* Indexscans only work with quals that have the indexkey on
* the left (the planner/optimizer makes sure it never passes
* anything else). The reason: the scankey machinery has no
* provision for distinguishing which side of the operator is
* the indexed attribute and which is the compared-to
* constant. It just assumes that the attribute is on the left
* :-(
*
* I am leaving this code able to support both ways, even though
* half of it is dead code, on the off chance that someone
* will fix the scankey machinery someday --- tgl 8/11/99.
*/
scanvar = NO_OP;
run_keys[j] = NULL;
/*
@ -807,67 +784,25 @@ ExecInitIndexScan(IndexScan *node, EState *estate)
Assert(leftop != NULL);
if (IsA(leftop, Var) &&
var_is_rel((Var *) leftop))
{
/*
* if the leftop is a "rel-var", then it means that it is
* a var node which tells us which attribute to use for
* our scan key.
*/
varattno = ((Var *) leftop)->varattno;
scanvar = LEFT_OP;
}
else if (IsA(leftop, Const))
{
/*
* if the leftop is a const node then it means it
* identifies the value to place in our scan key.
*/
scanvalue = ((Const *) leftop)->constvalue;
if (((Const *) leftop)->constisnull)
flags |= SK_ISNULL;
}
else
{
/*
* otherwise, the leftop contains an expression evaluable
* at runtime to figure out the value to place in our scan
* key.
*/
have_runtime_keys = true;
run_keys[j] = ExecInitExpr(leftop, (PlanState *) indexstate);
}
if (!(IsA(leftop, Var) &&
var_is_rel((Var *) leftop)))
elog(ERROR, "indxqual doesn't have key on left side");
varattno = ((Var *) leftop)->varattno;
/*
* now determine information in rightop
*/
rightop = (Expr *) get_rightop((Expr *) clause);
rhstype = exprType((Node *) rightop);
if (rightop && IsA(rightop, RelabelType))
rightop = ((RelabelType *) rightop)->arg;
Assert(rightop != NULL);
if (IsA(rightop, Var) &&
var_is_rel((Var *) rightop))
{
/*
* here we make sure only one op identifies the
* scan-attribute...
*/
if (scanvar == LEFT_OP)
elog(ERROR, "both left and right operands are rel-vars");
/*
* if the rightop is a "rel-var", then it means that it is
* a var node which tells us which attribute to use for
* our scan key.
*/
varattno = ((Var *) rightop)->varattno;
scanvar = RIGHT_OP;
}
else if (IsA(rightop, Const))
if (IsA(rightop, Const))
{
/*
* if the rightop is a const node then it means it
@ -886,15 +821,9 @@ ExecInitIndexScan(IndexScan *node, EState *estate)
*/
have_runtime_keys = true;
run_keys[j] = ExecInitExpr(rightop, (PlanState *) indexstate);
scanvalue = (Datum) 0;
}
/*
* now check that at least one op tells us the scan
* attribute...
*/
if (scanvar == NO_OP)
elog(ERROR, "neither left nor right operand refer to scan relation");
/*
* initialize the scan key's fields appropriately
*/
@ -902,8 +831,10 @@ ExecInitIndexScan(IndexScan *node, EState *estate)
flags,
varattno, /* attribute number to
* scan */
strategy, /* op's strategy */
opfuncid, /* reg proc to use */
scanvalue); /* constant */
scanvalue, /* constant */
rhstype); /* constant's type */
}
/*
@ -922,7 +853,7 @@ ExecInitIndexScan(IndexScan *node, EState *estate)
indexstate->iss_NumScanKeys = numScanKeys;
/*
* If all of our keys have the form (op var const) , then we have no
* If all of our keys have the form (var op const), then we have no
* runtime keys so we store NULL in the runtime key info. Otherwise
* runtime key info contains an array of pointers (one for each index)
* to arrays of flags (one for each key) which indicate that the qual
@ -978,10 +909,9 @@ ExecInitIndexScan(IndexScan *node, EState *estate)
* does its own locks and unlocks. (We rely on having AccessShareLock
* on the parent table to ensure the index won't go away!)
*/
listscan = indxid;
for (i = 0; i < numIndices; i++)
{
Oid indexOid = lfirsto(listscan);
Oid indexOid = lfirsto(indxid);
indexDescs[i] = index_open(indexOid);
scanDescs[i] = index_beginscan(currentRelation,
@ -989,7 +919,7 @@ ExecInitIndexScan(IndexScan *node, EState *estate)
estate->es_snapshot,
numScanKeys[i],
scanKeys[i]);
listscan = lnext(listscan);
indxid = lnext(indxid);
}
indexstate->iss_RelationDescs = indexDescs;