diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 2003-11-09 21:30:38 +0000 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 2003-11-09 21:30:38 +0000 |
commit | c1d62bfd00f4d1ea0647e12947ca1de9fea39b33 (patch) | |
tree | 1afdccb5267627182cab94b347730657107ad6eb /src/backend/executor/nodeIndexscan.c | |
parent | 723825afebb6de7212fa18882bcc78212d5c1743 (diff) | |
download | postgresql-c1d62bfd00f4d1ea0647e12947ca1de9fea39b33.tar.gz postgresql-c1d62bfd00f4d1ea0647e12947ca1de9fea39b33.zip |
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.
Diffstat (limited to 'src/backend/executor/nodeIndexscan.c')
-rw-r--r-- | src/backend/executor/nodeIndexscan.c | 164 |
1 files changed, 47 insertions, 117 deletions
diff --git a/src/backend/executor/nodeIndexscan.c b/src/backend/executor/nodeIndexscan.c index 6ab2f0a47bd..54114ad9245 100644 --- a/src/backend/executor/nodeIndexscan.c +++ b/src/backend/executor/nodeIndexscan.c @@ -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,24 +821,20 @@ 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 */ ScanKeyEntryInitialize(&scan_keys[j], 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; |