summaryrefslogtreecommitdiff
path: root/src/backend/executor/nodeIndexscan.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/executor/nodeIndexscan.c')
-rw-r--r--src/backend/executor/nodeIndexscan.c1050
1 files changed, 0 insertions, 1050 deletions
diff --git a/src/backend/executor/nodeIndexscan.c b/src/backend/executor/nodeIndexscan.c
deleted file mode 100644
index d33147793f8..00000000000
--- a/src/backend/executor/nodeIndexscan.c
+++ /dev/null
@@ -1,1050 +0,0 @@
-/*-------------------------------------------------------------------------
- *
- * nodeIndexscan.c
- * Routines to support indexes and indexed scans of relations
- *
- * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
- * Portions Copyright (c) 1994, Regents of the University of California
- *
- *
- * IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/executor/nodeIndexscan.c,v 1.69 2002/06/20 20:29:28 momjian Exp $
- *
- *-------------------------------------------------------------------------
- */
-/*
- * INTERFACE ROUTINES
- * ExecIndexScan scans a relation using indices
- * ExecIndexNext using index to retrieve next tuple
- * ExecInitIndexScan creates and initializes state info.
- * ExecIndexReScan rescans the indexed relation.
- * ExecEndIndexScan releases all storage.
- * ExecIndexMarkPos marks scan position.
- * ExecIndexRestrPos restores scan position.
- */
-#include "postgres.h"
-
-#include "access/genam.h"
-#include "access/heapam.h"
-#include "executor/execdebug.h"
-#include "executor/nodeIndexscan.h"
-#include "nodes/nodeFuncs.h"
-#include "optimizer/clauses.h"
-#include "parser/parsetree.h"
-
-/* ----------------
- * Misc stuff to move to executor.h soon -cim 6/5/90
- * ----------------
- */
-#define NO_OP 0
-#define LEFT_OP 1
-#define RIGHT_OP 2
-
-static TupleTableSlot *IndexNext(IndexScan *node);
-
-/* ----------------------------------------------------------------
- * IndexNext
- *
- * Retrieve a tuple from the IndexScan node's currentRelation
- * using the indices in the IndexScanState information.
- *
- * note: the old code mentions 'Primary indices'. to my knowledge
- * we only support a single secondary index. -cim 9/11/89
- *
- * old comments:
- * retrieve a tuple from relation using the indices given.
- * The indices are used in the order they appear in 'indices'.
- * The indices may be primary or secondary indices:
- * * primary index -- scan the relation 'relID' using keys supplied.
- * * secondary index -- scan the index relation to get the 'tid' for
- * a tuple in the relation 'relID'.
- * If the current index(pointed by 'indexPtr') fails to return a
- * tuple, the next index in the indices is used.
- *
- * bug fix so that it should retrieve on a null scan key.
- * ----------------------------------------------------------------
- */
-static TupleTableSlot *
-IndexNext(IndexScan *node)
-{
- EState *estate;
- CommonScanState *scanstate;
- IndexScanState *indexstate;
- ExprContext *econtext;
- ScanDirection direction;
- IndexScanDescPtr scanDescs;
- IndexScanDesc scandesc;
- HeapTuple tuple;
- TupleTableSlot *slot;
- int numIndices;
- bool bBackward;
- int indexNumber;
-
- /*
- * extract necessary information from index scan node
- */
- estate = node->scan.plan.state;
- direction = estate->es_direction;
- if (ScanDirectionIsBackward(node->indxorderdir))
- {
- if (ScanDirectionIsForward(direction))
- direction = BackwardScanDirection;
- else if (ScanDirectionIsBackward(direction))
- direction = ForwardScanDirection;
- }
- scanstate = node->scan.scanstate;
- indexstate = node->indxstate;
- scanDescs = indexstate->iss_ScanDescs;
- numIndices = indexstate->iss_NumIndices;
- econtext = scanstate->cstate.cs_ExprContext;
- slot = scanstate->css_ScanTupleSlot;
-
- /*
- * Check if we are evaluating PlanQual for tuple of this relation.
- * Additional checking is not good, but no other way for now. We could
- * introduce new nodes for this case and handle IndexScan --> NewNode
- * switching in Init/ReScan plan...
- */
- if (estate->es_evTuple != NULL &&
- estate->es_evTuple[node->scan.scanrelid - 1] != NULL)
- {
- List *qual;
-
- ExecClearTuple(slot);
- if (estate->es_evTupleNull[node->scan.scanrelid - 1])
- return slot; /* return empty slot */
-
- ExecStoreTuple(estate->es_evTuple[node->scan.scanrelid - 1],
- slot, InvalidBuffer, false);
-
- /* Does the tuple meet any of the OR'd indxqual conditions? */
- econtext->ecxt_scantuple = slot;
-
- ResetExprContext(econtext);
-
- foreach(qual, node->indxqualorig)
- {
- if (ExecQual((List *) lfirst(qual), econtext, false))
- break;
- }
- if (qual == NIL) /* would not be returned by indices */
- slot->val = NULL;
-
- /* Flag for the next call that no more tuples */
- estate->es_evTupleNull[node->scan.scanrelid - 1] = true;
-
- return slot;
- }
-
- /*
- * 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.
- */
- bBackward = ScanDirectionIsBackward(direction);
- if (bBackward)
- {
- indexNumber = numIndices - indexstate->iss_IndexPtr - 1;
- if (indexNumber < 0)
- {
- indexNumber = 0;
- indexstate->iss_IndexPtr = numIndices - 1;
- }
- }
- else
- {
- if ((indexNumber = indexstate->iss_IndexPtr) < 0)
- {
- indexNumber = 0;
- indexstate->iss_IndexPtr = 0;
- }
- }
- while (indexNumber < numIndices)
- {
- scandesc = scanDescs[indexstate->iss_IndexPtr];
- while ((tuple = index_getnext(scandesc, direction)) != NULL)
- {
- /*
- * store the scanned tuple in the scan tuple slot of the
- * scan state. Note: we pass 'false' because tuples
- * returned by amgetnext are pointers onto disk pages and
- * must not be pfree()'d.
- */
- ExecStoreTuple(tuple, /* tuple to store */
- slot, /* slot to store in */
- scandesc->xs_cbuf, /* buffer containing tuple */
- false); /* don't pfree */
-
- /*
- * We must check to see if the current tuple was already
- * matched by an earlier index, so we don't double-report
- * it. We do this by passing the tuple through ExecQual
- * and checking for failure with all previous
- * qualifications.
- */
- if (indexstate->iss_IndexPtr > 0)
- {
- bool prev_matches = false;
- int prev_index;
- List *qual;
-
- econtext->ecxt_scantuple = slot;
- ResetExprContext(econtext);
- qual = node->indxqualorig;
- for (prev_index = 0;
- prev_index < indexstate->iss_IndexPtr;
- prev_index++)
- {
- if (ExecQual((List *) lfirst(qual), econtext, false))
- {
- prev_matches = true;
- break;
- }
- qual = lnext(qual);
- }
- if (prev_matches)
- {
- /* Duplicate, so drop it and loop back for another */
- ExecClearTuple(slot);
- continue;
- }
- }
-
- return slot; /* OK to return tuple */
- }
-
- if (indexNumber < numIndices)
- {
- indexNumber++;
- if (bBackward)
- indexstate->iss_IndexPtr--;
- else
- indexstate->iss_IndexPtr++;
- }
- }
-
- /*
- * if we get here it means the index scan failed so we are at the end
- * of the scan..
- */
- return ExecClearTuple(slot);
-}
-
-/* ----------------------------------------------------------------
- * ExecIndexScan(node)
- *
- * old comments:
- * Scans the relation using primary or secondary indices and returns
- * the next qualifying tuple in the direction specified.
- * It calls ExecScan() and passes it the access methods which returns
- * the next tuple using the indices.
- *
- * Conditions:
- * -- the "cursor" maintained by the AMI is positioned at the tuple
- * returned previously.
- *
- * Initial States:
- * -- the relation indicated is opened for scanning so that the
- * "cursor" is positioned before the first qualifying tuple.
- * -- all index realtions are opened for scanning.
- * -- indexPtr points to the first index.
- * -- state variable ruleFlag = nil.
- * ----------------------------------------------------------------
- */
-TupleTableSlot *
-ExecIndexScan(IndexScan *node)
-{
- IndexScanState *indexstate = node->indxstate;
-
- /*
- * If we have runtime keys and they've not already been set up, do it
- * now.
- */
- if (indexstate->iss_RuntimeKeyInfo && !indexstate->iss_RuntimeKeysReady)
- ExecReScan((Plan *) node, NULL, NULL);
-
- /*
- * use IndexNext as access method
- */
- return ExecScan(&node->scan, (ExecScanAccessMtd) IndexNext);
-}
-
-/* ----------------------------------------------------------------
- * ExecIndexReScan(node)
- *
- * Recalculates the value of the scan keys whose value depends on
- * information known at runtime and rescans the indexed relation.
- * Updating the scan key was formerly done separately in
- * ExecUpdateIndexScanKeys. Integrating it into ReScan makes
- * rescans of indices and relations/general streams more uniform.
- *
- * ----------------------------------------------------------------
- */
-void
-ExecIndexReScan(IndexScan *node, ExprContext *exprCtxt, Plan *parent)
-{
- EState *estate;
- IndexScanState *indexstate;
- ExprContext *econtext;
- int numIndices;
- IndexScanDescPtr scanDescs;
- ScanKey *scanKeys;
- int **runtimeKeyInfo;
- int *numScanKeys;
- int i;
- int j;
-
- estate = node->scan.plan.state;
- indexstate = node->indxstate;
- econtext = indexstate->iss_RuntimeContext; /* context for runtime
- * keys */
- numIndices = indexstate->iss_NumIndices;
- scanDescs = indexstate->iss_ScanDescs;
- scanKeys = indexstate->iss_ScanKeys;
- runtimeKeyInfo = indexstate->iss_RuntimeKeyInfo;
- numScanKeys = indexstate->iss_NumScanKeys;
-
- if (econtext)
- {
- /*
- * If we are being passed an outer tuple, save it for runtime key
- * calc. We also need to link it into the "regular" per-tuple
- * econtext, so it can be used during indexqualorig evaluations.
- */
- if (exprCtxt != NULL)
- {
- ExprContext *stdecontext;
-
- econtext->ecxt_outertuple = exprCtxt->ecxt_outertuple;
- stdecontext = node->scan.scanstate->cstate.cs_ExprContext;
- stdecontext->ecxt_outertuple = exprCtxt->ecxt_outertuple;
- }
-
- /*
- * Reset the runtime-key context so we don't leak memory as each
- * outer tuple is scanned. Note this assumes that we will
- * recalculate *all* runtime keys on each call.
- */
- ResetExprContext(econtext);
- }
-
- /*
- * If we are doing runtime key calculations (ie, the index keys depend
- * on data from an outer scan), compute the new key values
- */
- if (runtimeKeyInfo)
- {
- List *indxqual;
-
- indxqual = node->indxqual;
- for (i = 0; i < numIndices; i++)
- {
- List *qual = lfirst(indxqual);
- int n_keys;
- ScanKey scan_keys;
- int *run_keys;
- List *listscan;
-
- indxqual = lnext(indxqual);
- n_keys = numScanKeys[i];
- scan_keys = scanKeys[i];
- run_keys = runtimeKeyInfo[i];
-
- listscan = qual;
- for (j = 0; j < n_keys; j++)
- {
- Expr *clause = lfirst(listscan);
-
- listscan = lnext(listscan);
-
- /*
- * 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.
- *
- * Note: the result of the eval could be a pass-by-ref value
- * that's stored in the outer scan's tuple, not in
- * econtext->ecxt_per_tuple_memory. We assume that the
- * outer tuple will stay put throughout our scan. If this
- * is wrong, we could copy the result into our context
- * explicitly, but I think that's not necessary...
- */
- if (run_keys[j] != NO_OP)
- {
- Node *scanexpr;
- Datum scanvalue;
- bool isNull;
-
- scanexpr = (run_keys[j] == RIGHT_OP) ?
- (Node *) get_rightop(clause) :
- (Node *) get_leftop(clause);
-
- scanvalue = ExecEvalExprSwitchContext(scanexpr,
- econtext,
- &isNull,
- NULL);
- scan_keys[j].sk_argument = scanvalue;
- if (isNull)
- scan_keys[j].sk_flags |= SK_ISNULL;
- else
- scan_keys[j].sk_flags &= ~SK_ISNULL;
- }
- }
- }
-
- indexstate->iss_RuntimeKeysReady = true;
- }
-
- /* If this is re-scanning of PlanQual ... */
- if (estate->es_evTuple != NULL &&
- estate->es_evTuple[node->scan.scanrelid - 1] != NULL)
- {
- estate->es_evTupleNull[node->scan.scanrelid - 1] = false;
- return;
- }
-
- /* reset index scans */
- if (ScanDirectionIsBackward(node->indxorderdir))
- indexstate->iss_IndexPtr = numIndices;
- else
- indexstate->iss_IndexPtr = -1;
-
- for (i = 0; i < numIndices; i++)
- {
- IndexScanDesc scan = scanDescs[i];
- ScanKey skey = scanKeys[i];
-
- index_rescan(scan, skey);
- }
-}
-
-/* ----------------------------------------------------------------
- * ExecEndIndexScan
- *
- * old comments
- * Releases any storage allocated through C routines.
- * Returns nothing.
- * ----------------------------------------------------------------
- */
-void
-ExecEndIndexScan(IndexScan *node)
-{
- CommonScanState *scanstate;
- IndexScanState *indexstate;
- int **runtimeKeyInfo;
- ScanKey *scanKeys;
- List *indxqual;
- int *numScanKeys;
- int numIndices;
- Relation relation;
- RelationPtr indexRelationDescs;
- IndexScanDescPtr indexScanDescs;
- int i;
-
- scanstate = node->scan.scanstate;
- indexstate = node->indxstate;
- indxqual = node->indxqual;
- runtimeKeyInfo = indexstate->iss_RuntimeKeyInfo;
-
- /*
- * extract information from the node
- */
- numIndices = indexstate->iss_NumIndices;
- scanKeys = indexstate->iss_ScanKeys;
- numScanKeys = indexstate->iss_NumScanKeys;
- indexRelationDescs = indexstate->iss_RelationDescs;
- indexScanDescs = indexstate->iss_ScanDescs;
- relation = scanstate->css_currentRelation;
-
- /*
- * Free the projection info and the scan attribute info
- *
- * Note: we don't ExecFreeResultType(scanstate) because the rule manager
- * depends on the tupType returned by ExecMain(). So for now, this is
- * freed at end-transaction time. -cim 6/2/91
- */
- ExecFreeProjectionInfo(&scanstate->cstate);
- ExecFreeExprContext(&scanstate->cstate);
- if (indexstate->iss_RuntimeContext)
- FreeExprContext(indexstate->iss_RuntimeContext);
-
- /*
- * close the index relations
- */
- for (i = 0; i < numIndices; i++)
- {
- if (indexScanDescs[i] != NULL)
- index_endscan(indexScanDescs[i]);
-
- if (indexRelationDescs[i] != NULL)
- index_close(indexRelationDescs[i]);
- }
-
- /*
- * close the heap relation.
- *
- * Currently, we do not release the AccessShareLock acquired by
- * ExecInitIndexScan. This lock should be held till end of transaction.
- * (There is a faction that considers this too much locking, however.)
- */
- heap_close(relation, NoLock);
-
- /*
- * free the scan keys used in scanning the indices
- */
- for (i = 0; i < numIndices; i++)
- {
- if (scanKeys[i] != NULL)
- pfree(scanKeys[i]);
- }
- pfree(scanKeys);
- pfree(numScanKeys);
-
- if (runtimeKeyInfo)
- {
- for (i = 0; i < numIndices; i++)
- {
- if (runtimeKeyInfo[i] != NULL)
- pfree(runtimeKeyInfo[i]);
- }
- pfree(runtimeKeyInfo);
- }
-
- /*
- * clear out tuple table slots
- */
- ExecClearTuple(scanstate->cstate.cs_ResultTupleSlot);
- ExecClearTuple(scanstate->css_ScanTupleSlot);
-}
-
-/* ----------------------------------------------------------------
- * ExecIndexMarkPos
- *
- * old comments
- * Marks scan position by marking the current index.
- * Returns nothing.
- * ----------------------------------------------------------------
- */
-void
-ExecIndexMarkPos(IndexScan *node)
-{
- IndexScanState *indexstate;
- IndexScanDescPtr indexScanDescs;
- IndexScanDesc scanDesc;
- int indexPtr;
-
- indexstate = node->indxstate;
- indexPtr = indexstate->iss_MarkIndexPtr = indexstate->iss_IndexPtr;
- indexScanDescs = indexstate->iss_ScanDescs;
- scanDesc = indexScanDescs[indexPtr];
-
-#ifdef NOT_USED
- IndexScanMarkPosition(scanDesc);
-#endif
- index_markpos(scanDesc);
-}
-
-/* ----------------------------------------------------------------
- * ExecIndexRestrPos
- *
- * old comments
- * Restores scan position by restoring the current index.
- * Returns nothing.
- *
- * XXX Assumes previously marked scan position belongs to current index
- * ----------------------------------------------------------------
- */
-void
-ExecIndexRestrPos(IndexScan *node)
-{
- IndexScanState *indexstate;
- IndexScanDescPtr indexScanDescs;
- IndexScanDesc scanDesc;
- int indexPtr;
-
- indexstate = node->indxstate;
- indexPtr = indexstate->iss_IndexPtr = indexstate->iss_MarkIndexPtr;
- indexScanDescs = indexstate->iss_ScanDescs;
- scanDesc = indexScanDescs[indexPtr];
-
-#ifdef NOT_USED
- IndexScanRestorePosition(scanDesc);
-#endif
- index_restrpos(scanDesc);
-}
-
-/* ----------------------------------------------------------------
- * ExecInitIndexScan
- *
- * Initializes the index scan's state information, creates
- * scan keys, and opens the base and index relations.
- *
- * Note: index scans have 2 sets of state information because
- * we have to keep track of the base relation and the
- * index relations.
- *
- * old comments
- * Creates the run-time state information for the node and
- * sets the relation id to contain relevant descriptors.
- *
- * Parameters:
- * node: IndexNode node produced by the planner.
- * estate: the execution state initialized in InitPlan.
- * ----------------------------------------------------------------
- */
-bool
-ExecInitIndexScan(IndexScan *node, EState *estate, Plan *parent)
-{
- IndexScanState *indexstate;
- CommonScanState *scanstate;
- List *indxqual;
- List *indxid;
- List *listscan;
- int i;
- int numIndices;
- int indexPtr;
- ScanKey *scanKeys;
- int *numScanKeys;
- RelationPtr indexDescs;
- IndexScanDescPtr scanDescs;
- int **runtimeKeyInfo;
- bool have_runtime_keys;
- RangeTblEntry *rtentry;
- Index relid;
- Oid reloid;
- Relation currentRelation;
-
- /*
- * assign execution state to node
- */
- node->scan.plan.state = estate;
-
- /*
- * Part 1) initialize scan state
- *
- * create new CommonScanState for node
- */
- scanstate = makeNode(CommonScanState);
- node->scan.scanstate = scanstate;
-
- /*
- * Miscellaneous initialization
- *
- * create expression context for node
- */
- ExecAssignExprContext(estate, &scanstate->cstate);
-
-#define INDEXSCAN_NSLOTS 2
-
- /*
- * tuple table initialization
- */
- ExecInitResultTupleSlot(estate, &scanstate->cstate);
- ExecInitScanTupleSlot(estate, scanstate);
-
- /*
- * initialize projection info. result type comes from scan desc
- * below..
- */
- ExecAssignProjectionInfo((Plan *) node, &scanstate->cstate);
-
- /*
- * Part 2) initialize index scan state
- *
- * create new IndexScanState for node
- */
- indexstate = makeNode(IndexScanState);
- indexstate->iss_NumIndices = 0;
- indexstate->iss_IndexPtr = -1;
- indexstate->iss_ScanKeys = NULL;
- indexstate->iss_NumScanKeys = NULL;
- indexstate->iss_RuntimeKeyInfo = NULL;
- indexstate->iss_RuntimeContext = NULL;
- indexstate->iss_RuntimeKeysReady = false;
- indexstate->iss_RelationDescs = NULL;
- indexstate->iss_ScanDescs = NULL;
-
- node->indxstate = indexstate;
-
- /*
- * get the index node information
- */
- indxid = node->indxid;
- numIndices = length(indxid);
- indexPtr = -1;
-
- CXT1_printf("ExecInitIndexScan: context is %d\n", CurrentMemoryContext);
-
- /*
- * scanKeys is used to keep track of the ScanKey's. This is needed
- * because a single scan may use several indices and each index has
- * its own ScanKey.
- */
- numScanKeys = (int *) palloc(numIndices * sizeof(int));
- scanKeys = (ScanKey *) palloc(numIndices * sizeof(ScanKey));
- indexDescs = (RelationPtr) palloc(numIndices * sizeof(Relation));
- scanDescs = (IndexScanDescPtr) palloc(numIndices * sizeof(IndexScanDesc));
-
- /*
- * initialize space for runtime key info (may not be needed)
- */
- have_runtime_keys = false;
- runtimeKeyInfo = (int **) palloc(numIndices * sizeof(int *));
-
- /*
- * build the index scan keys from the index qualification
- */
- indxqual = node->indxqual;
- for (i = 0; i < numIndices; i++)
- {
- int j;
- List *qual;
- int n_keys;
- ScanKey scan_keys;
- int *run_keys;
-
- qual = lfirst(indxqual);
- indxqual = lnext(indxqual);
- n_keys = length(qual);
- scan_keys = (n_keys <= 0) ? (ScanKey) NULL :
- (ScanKey) palloc(n_keys * sizeof(ScanKeyData));
- run_keys = (n_keys <= 0) ? (int *) NULL :
- (int *) palloc(n_keys * sizeof(int));
-
- 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++)
- {
- Expr *clause; /* one clause of index qual */
- Oper *op; /* operator used in clause */
- Node *leftop; /* expr on lhs of operator */
- Node *rightop; /* expr on rhs ... */
- bits16 flags = 0;
-
- int scanvar; /* which var identifies varattno */
- AttrNumber varattno = 0; /* att number used in scan */
- Oid opid; /* operator id used in scan */
- Datum scanvalue = 0; /* value used in scan (if const) */
-
- /*
- * extract clause information from the qualification
- */
- clause = lfirst(listscan);
- listscan = lnext(listscan);
-
- op = (Oper *) clause->oper;
- if (!IsA(clause, Expr) ||!IsA(op, Oper))
- elog(ERROR, "ExecInitIndexScan: indxqual not an opclause!");
-
- opid = op->opid;
-
- /*
- * 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.
- *
- * 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 then set the
- * appropriate flag in run_keys to LEFT_OP or RIGHT_OP. The
- * corresponding scan keys 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] = NO_OP;
-
- /*
- * determine information in leftop
- */
- leftop = (Node *) get_leftop(clause);
-
- if (leftop && IsA(leftop, RelabelType))
- leftop = ((RelabelType *) leftop)->arg;
-
- 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 if (IsA(leftop, Param))
- {
- bool isnull;
-
- /*
- * if the leftop is a Param node then it means it
- * identifies the value to place in our scan key.
- */
-
- /* Life was so easy before ... subselects */
- if (((Param *) leftop)->paramkind == PARAM_EXEC)
- {
- /* treat Param as runtime key */
- have_runtime_keys = true;
- run_keys[j] = LEFT_OP;
- }
- else
- {
- /* treat Param like a constant */
- scanvalue = ExecEvalParam((Param *) leftop,
- scanstate->cstate.cs_ExprContext,
- &isnull);
- if (isnull)
- 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] = LEFT_OP;
- }
-
- /*
- * now determine information in rightop
- */
- rightop = (Node *) get_rightop(clause);
-
- 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, "ExecInitIndexScan: %s",
- "both left and right op's 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 the rightop is a const node then it means it
- * identifies the value to place in our scan key.
- */
- scanvalue = ((Const *) rightop)->constvalue;
- if (((Const *) rightop)->constisnull)
- flags |= SK_ISNULL;
- }
- else if (IsA(rightop, Param))
- {
- bool isnull;
-
- /*
- * if the rightop is a Param node then it means it
- * identifies the value to place in our scan key.
- */
-
- /* Life was so easy before ... subselects */
- if (((Param *) rightop)->paramkind == PARAM_EXEC)
- {
- /* treat Param as runtime key */
- have_runtime_keys = true;
- run_keys[j] = RIGHT_OP;
- }
- else
- {
- /* treat Param like a constant */
- scanvalue = ExecEvalParam((Param *) rightop,
- scanstate->cstate.cs_ExprContext,
- &isnull);
- if (isnull)
- flags |= SK_ISNULL;
- }
- }
- else
- {
- /*
- * otherwise, the rightop contains an expression evaluable
- * at runtime to figure out the value to place in our scan
- * key.
- */
- have_runtime_keys = true;
- run_keys[j] = RIGHT_OP;
- }
-
- /*
- * now check that at least one op tells us the scan
- * attribute...
- */
- if (scanvar == NO_OP)
- elog(ERROR, "ExecInitIndexScan: %s",
- "neither leftop nor rightop refer to scan relation");
-
- /*
- * initialize the scan key's fields appropriately
- */
- ScanKeyEntryInitialize(&scan_keys[j],
- flags,
- varattno, /* attribute number to
- * scan */
- (RegProcedure) opid, /* reg proc to use */
- scanvalue); /* constant */
- }
-
- /*
- * store the key information into our arrays.
- */
- numScanKeys[i] = n_keys;
- scanKeys[i] = scan_keys;
- runtimeKeyInfo[i] = run_keys;
- }
-
- indexstate->iss_NumIndices = numIndices;
- if (ScanDirectionIsBackward(node->indxorderdir))
- indexPtr = numIndices;
- indexstate->iss_IndexPtr = indexPtr;
- indexstate->iss_ScanKeys = scanKeys;
- indexstate->iss_NumScanKeys = numScanKeys;
-
- /*
- * If all of our keys have the form (op var 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
- * needs to be evaluated at runtime. -cim 10/24/89
- *
- * If we do have runtime keys, we need an ExprContext to evaluate them;
- * the node's standard context won't do because we want to reset that
- * context for every tuple. So, build another context just like the
- * other one... -tgl 7/11/00
- */
- if (have_runtime_keys)
- {
- ExprContext *stdecontext = scanstate->cstate.cs_ExprContext;
-
- ExecAssignExprContext(estate, &scanstate->cstate);
- indexstate->iss_RuntimeKeyInfo = runtimeKeyInfo;
- indexstate->iss_RuntimeContext = scanstate->cstate.cs_ExprContext;
- scanstate->cstate.cs_ExprContext = stdecontext;
- }
- else
- {
- indexstate->iss_RuntimeKeyInfo = NULL;
- indexstate->iss_RuntimeContext = NULL;
- /* Get rid of the speculatively-allocated flag arrays, too */
- for (i = 0; i < numIndices; i++)
- {
- if (runtimeKeyInfo[i] != NULL)
- pfree(runtimeKeyInfo[i]);
- }
- pfree(runtimeKeyInfo);
- }
-
- /*
- * open the base relation and acquire AccessShareLock on it.
- */
- relid = node->scan.scanrelid;
- rtentry = rt_fetch(relid, estate->es_range_table);
- reloid = rtentry->relid;
-
- currentRelation = heap_open(reloid, AccessShareLock);
-
- if (!RelationGetForm(currentRelation)->relhasindex)
- elog(ERROR, "indexes of the relation %u was inactivated", reloid);
-
- scanstate->css_currentRelation = currentRelation;
- scanstate->css_currentScanDesc = NULL; /* no heap scan here */
-
- /*
- * get the scan type from the relation descriptor.
- */
- ExecAssignScanType(scanstate, RelationGetDescr(currentRelation), false);
- ExecAssignResultTypeFromTL((Plan *) node, &scanstate->cstate);
-
- /*
- * open the index relations and initialize relation and scan
- * descriptors. Note we acquire no locks here; the index machinery
- * 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 = (Oid) lfirsti(listscan);
-
- indexDescs[i] = index_open(indexOid);
- scanDescs[i] = index_beginscan(currentRelation,
- indexDescs[i],
- estate->es_snapshot,
- numScanKeys[i],
- scanKeys[i]);
- listscan = lnext(listscan);
- }
-
- indexstate->iss_RelationDescs = indexDescs;
- indexstate->iss_ScanDescs = scanDescs;
-
- /*
- * all done.
- */
- return TRUE;
-}
-
-int
-ExecCountSlotsIndexScan(IndexScan *node)
-{
- return ExecCountSlotsNode(outerPlan((Plan *) node)) +
- ExecCountSlotsNode(innerPlan((Plan *) node)) + INDEXSCAN_NSLOTS;
-}