1 /*-------------------------------------------------------------------------
4 * Routines to support indexes and indexed scans of relations
6 * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
7 * Portions Copyright (c) 1994, Regents of the University of California
11 * $Header: /cvsroot/pgsql/src/backend/executor/nodeIndexscan.c,v 1.49 2000/04/12 17:15:09 momjian Exp $
13 *-------------------------------------------------------------------------
17 * ExecInsertIndexTuples inserts tuples into indices on result relation
19 * ExecIndexScan scans a relation using indices
20 * ExecIndexNext using index to retrieve next tuple
21 * ExecInitIndexScan creates and initializes state info.
22 * ExecIndexReScan rescans the indexed relation.
23 * ExecEndIndexScan releases all storage.
24 * ExecIndexMarkPos marks scan position.
25 * ExecIndexRestrPos restores scan position.
28 * the code supporting ExecInsertIndexTuples should be
29 * collected and merged with the genam stuff.
36 #include "access/genam.h"
37 #include "access/heapam.h"
38 #include "executor/execdebug.h"
39 #include "executor/executor.h"
40 #include "executor/nodeIndexscan.h"
41 #include "nodes/nodeFuncs.h"
42 #include "optimizer/clauses.h"
43 #include "parser/parsetree.h"
46 * Misc stuff to move to executor.h soon -cim 6/5/90
53 static TupleTableSlot *IndexNext(IndexScan *node);
55 /* ----------------------------------------------------------------
58 * Retrieve a tuple from the IndexScan node's currentRelation
59 * using the indices in the IndexScanState information.
61 * note: the old code mentions 'Primary indices'. to my knowledge
62 * we only support a single secondary index. -cim 9/11/89
65 * retrieve a tuple from relation using the indices given.
66 * The indices are used in the order they appear in 'indices'.
67 * The indices may be primary or secondary indices:
68 * * primary index -- scan the relation 'relID' using keys supplied.
69 * * secondary index -- scan the index relation to get the 'tid' for
70 * a tuple in the relation 'relID'.
71 * If the current index(pointed by 'indexPtr') fails to return a
72 * tuple, the next index in the indices is used.
74 * bug fix so that it should retrieve on a null scan key.
75 * ----------------------------------------------------------------
77 static TupleTableSlot *
78 IndexNext(IndexScan *node)
81 CommonScanState *scanstate;
82 IndexScanState *indexstate;
83 ScanDirection direction;
85 IndexScanDescPtr scanDescs;
86 IndexScanDesc scandesc;
87 Relation heapRelation;
88 RetrieveIndexResult result;
91 Buffer buffer = InvalidBuffer;
98 * extract necessary information from index scan node
101 estate = node->scan.plan.state;
102 direction = estate->es_direction;
103 if (ScanDirectionIsBackward(node->indxorderdir))
105 if (ScanDirectionIsForward(direction))
106 direction = BackwardScanDirection;
107 else if (ScanDirectionIsBackward(direction))
108 direction = ForwardScanDirection;
110 snapshot = estate->es_snapshot;
111 scanstate = node->scan.scanstate;
112 indexstate = node->indxstate;
113 scanDescs = indexstate->iss_ScanDescs;
114 heapRelation = scanstate->css_currentRelation;
115 numIndices = indexstate->iss_NumIndices;
116 slot = scanstate->css_ScanTupleSlot;
119 * Check if we are evaluating PlanQual for tuple of this relation.
120 * Additional checking is not good, but no other way for now. We could
121 * introduce new nodes for this case and handle IndexScan --> NewNode
122 * switching in Init/ReScan plan...
124 if (estate->es_evTuple != NULL &&
125 estate->es_evTuple[node->scan.scanrelid - 1] != NULL)
129 ExecClearTuple(slot);
130 if (estate->es_evTupleNull[node->scan.scanrelid - 1])
131 return slot; /* return empty slot */
133 /* probably ought to use ExecStoreTuple here... */
134 slot->val = estate->es_evTuple[node->scan.scanrelid - 1];
135 slot->ttc_shouldFree = false;
137 scanstate->cstate.cs_ExprContext->ecxt_scantuple = slot;
139 /* Does the tuple meet any of the OR'd indxqual conditions? */
140 foreach(qual, node->indxqualorig)
142 if (ExecQual((List *) lfirst(qual),
143 scanstate->cstate.cs_ExprContext,
147 if (qual == NIL) /* would not be returned by indices */
150 /* Flag for the next call that no more tuples */
151 estate->es_evTupleNull[node->scan.scanrelid - 1] = true;
156 tuple = &(indexstate->iss_htup);
159 * ok, now that we have what we need, fetch an index tuple.
160 * if scanning this index succeeded then return the
161 * appropriate heap tuple.. else return NULL.
164 bBackward = ScanDirectionIsBackward(direction);
167 indexNumber = numIndices - indexstate->iss_IndexPtr - 1;
171 indexstate->iss_IndexPtr = numIndices - 1;
176 if ((indexNumber = indexstate->iss_IndexPtr) < 0)
179 indexstate->iss_IndexPtr = 0;
182 while (indexNumber < numIndices)
184 scandesc = scanDescs[indexstate->iss_IndexPtr];
185 while ((result = index_getnext(scandesc, direction)) != NULL)
187 tuple->t_self = result->heap_iptr;
188 heap_fetch(heapRelation, snapshot, tuple, &buffer);
191 if (tuple->t_data != NULL)
193 bool prev_matches = false;
198 * store the scanned tuple in the scan tuple slot of the
199 * scan state. Eventually we will only do this and not
200 * return a tuple. Note: we pass 'false' because tuples
201 * returned by amgetnext are pointers onto disk pages and
202 * must not be pfree()'d.
204 ExecStoreTuple(tuple, /* tuple to store */
205 slot, /* slot to store in */
206 buffer, /* buffer associated with tuple */
207 false); /* don't pfree */
210 * At this point we have an extra pin on the buffer,
211 * because ExecStoreTuple incremented the pin count. Drop
214 ReleaseBuffer(buffer);
217 * We must check to see if the current tuple was already
218 * matched by an earlier index, so we don't double-report
219 * it. We do this by passing the tuple through ExecQual
220 * and checking for failure with all previous
223 scanstate->cstate.cs_ExprContext->ecxt_scantuple = slot;
224 qual = node->indxqualorig;
225 for (prev_index = 0; prev_index < indexstate->iss_IndexPtr;
228 if (ExecQual((List *) lfirst(qual),
229 scanstate->cstate.cs_ExprContext,
238 return slot;/* OK to return tuple */
239 /* Duplicate tuple, so drop it and loop back for another */
240 ExecClearTuple(slot);
243 if (indexNumber < numIndices)
247 indexstate->iss_IndexPtr--;
249 indexstate->iss_IndexPtr++;
253 * if we get here it means the index scan failed so we
254 * are at the end of the scan..
257 return ExecClearTuple(slot);
260 /* ----------------------------------------------------------------
261 * ExecIndexScan(node)
264 * Scans the relation using primary or secondary indices and returns
265 * the next qualifying tuple in the direction specified.
266 * It calls ExecScan() and passes it the access methods which returns
267 * the next tuple using the indices.
270 * -- the "cursor" maintained by the AMI is positioned at the tuple
271 * returned previously.
274 * -- the relation indicated is opened for scanning so that the
275 * "cursor" is positioned before the first qualifying tuple.
276 * -- all index realtions are opened for scanning.
277 * -- indexPtr points to the first index.
278 * -- state variable ruleFlag = nil.
279 * ----------------------------------------------------------------
282 ExecIndexScan(IndexScan *node)
285 * use IndexNext as access method
288 return ExecScan(&node->scan, IndexNext);
291 /* ----------------------------------------------------------------
292 * ExecIndexReScan(node)
294 * Recalculates the value of the scan keys whose value depends on
295 * information known at runtime and rescans the indexed relation.
296 * Updating the scan key was formerly done separately in
297 * ExecUpdateIndexScanKeys. Integrating it into ReScan
298 * makes rescans of indices and
299 * relations/general streams more uniform.
301 * ----------------------------------------------------------------
304 ExecIndexReScan(IndexScan *node, ExprContext *exprCtxt, Plan *parent)
307 IndexScanState *indexstate;
308 ScanDirection direction;
309 IndexScanDescPtr scanDescs;
316 Pointer *runtimeKeyInfo;
330 indexstate = node->indxstate;
331 estate = node->scan.plan.state;
332 direction = estate->es_direction;
333 numIndices = indexstate->iss_NumIndices;
334 scanDescs = indexstate->iss_ScanDescs;
335 scanKeys = indexstate->iss_ScanKeys;
336 runtimeKeyInfo = (Pointer *) indexstate->iss_RuntimeKeyInfo;
337 numScanKeys = indexstate->iss_NumScanKeys;
338 indexstate->iss_IndexPtr = -1;
339 if (ScanDirectionIsBackward(node->indxorderdir))
340 indexstate->iss_IndexPtr = numIndices;
342 /* If we are being passed an outer tuple, save it for runtime key calc */
343 if (exprCtxt != NULL)
344 node->scan.scanstate->cstate.cs_ExprContext->ecxt_outertuple =
345 exprCtxt->ecxt_outertuple;
347 /* If this is re-scanning of PlanQual ... */
348 if (estate->es_evTuple != NULL &&
349 estate->es_evTuple[node->scan.scanrelid - 1] != NULL)
351 estate->es_evTupleNull[node->scan.scanrelid - 1] = false;
356 * get the index qualifications and recalculate the appropriate values
358 indxqual = node->indxqual;
359 for (i = 0; i < numIndices; i++)
361 qual = lfirst(indxqual);
362 indxqual = lnext(indxqual);
363 n_keys = numScanKeys[i];
364 scan_keys = (ScanKey) scanKeys[i];
368 run_keys = (int *) runtimeKeyInfo[i];
369 for (j = 0; j < n_keys; j++)
373 * If we have a run-time key, then extract the run-time
374 * expression and evaluate it with respect to the current
375 * outer tuple. We then stick the result into the scan
378 if (run_keys[j] != NO_OP)
380 clause = nth(j, qual);
381 scanexpr = (run_keys[j] == RIGHT_OP) ?
382 (Node *) get_rightop(clause) :
383 (Node *) get_leftop(clause);
386 * pass in isDone but ignore it. We don't iterate in
390 ExecEvalExpr(scanexpr,
391 node->scan.scanstate->cstate.cs_ExprContext,
393 scan_keys[j].sk_argument = scanvalue;
395 scan_keys[j].sk_flags |= SK_ISNULL;
397 scan_keys[j].sk_flags &= ~SK_ISNULL;
403 index_rescan(scan, direction, skey);
406 * perhaps return something meaningful
412 /* ----------------------------------------------------------------
416 * Releases any storage allocated through C routines.
418 * ----------------------------------------------------------------
421 ExecEndIndexScan(IndexScan *node)
423 CommonScanState *scanstate;
424 IndexScanState *indexstate;
425 Pointer *runtimeKeyInfo;
432 scanstate = node->scan.scanstate;
433 indexstate = node->indxstate;
434 indxqual = node->indxqual;
435 runtimeKeyInfo = (Pointer *) indexstate->iss_RuntimeKeyInfo;
438 * extract information from the node
441 numIndices = indexstate->iss_NumIndices;
442 scanKeys = indexstate->iss_ScanKeys;
443 numScanKeys = indexstate->iss_NumScanKeys;
446 * Free the projection info and the scan attribute info
448 * Note: we don't ExecFreeResultType(scanstate)
449 * because the rule manager depends on the tupType
450 * returned by ExecMain(). So for now, this
451 * is freed at end-transaction time. -cim 6/2/91
454 ExecFreeProjectionInfo(&scanstate->cstate);
457 * close the heap and index relations
460 ExecCloseR((Plan *) node);
463 * free the scan keys used in scanning the indices
466 for (i = 0; i < numIndices; i++)
468 if (scanKeys[i] != NULL)
476 for (i = 0; i < numIndices; i++)
481 qual = nth(i, indxqual);
482 n_keys = length(qual);
484 pfree(runtimeKeyInfo[i]);
486 pfree(runtimeKeyInfo);
490 * clear out tuple table slots
493 ExecClearTuple(scanstate->cstate.cs_ResultTupleSlot);
494 ExecClearTuple(scanstate->css_ScanTupleSlot);
495 /* ExecClearTuple(scanstate->css_RawTupleSlot); */
498 /* ----------------------------------------------------------------
502 * Marks scan position by marking the current index.
504 * ----------------------------------------------------------------
507 ExecIndexMarkPos(IndexScan *node)
509 IndexScanState *indexstate;
510 IndexScanDescPtr indexScanDescs;
511 IndexScanDesc scanDesc;
514 indexstate = node->indxstate;
515 indexPtr = indexstate->iss_MarkIndexPtr = indexstate->iss_IndexPtr;
516 indexScanDescs = indexstate->iss_ScanDescs;
517 scanDesc = indexScanDescs[indexPtr];
520 IndexScanMarkPosition(scanDesc);
522 index_markpos(scanDesc);
525 /* ----------------------------------------------------------------
529 * Restores scan position by restoring the current index.
532 * XXX Assumes previously marked scan position belongs to current index
533 * ----------------------------------------------------------------
536 ExecIndexRestrPos(IndexScan *node)
538 IndexScanState *indexstate;
539 IndexScanDescPtr indexScanDescs;
540 IndexScanDesc scanDesc;
543 indexstate = node->indxstate;
544 indexPtr = indexstate->iss_IndexPtr = indexstate->iss_MarkIndexPtr;
545 indexScanDescs = indexstate->iss_ScanDescs;
546 scanDesc = indexScanDescs[indexPtr];
549 IndexScanRestorePosition(scanDesc);
551 index_restrpos(scanDesc);
554 /* ----------------------------------------------------------------
557 * Initializes the index scan's state information, creates
558 * scan keys, and opens the base and index relations.
560 * Note: index scans have 2 sets of state information because
561 * we have to keep track of the base relation and the
565 * Creates the run-time state information for the node and
566 * sets the relation id to contain relevant decriptors.
569 * node: IndexNode node produced by the planner.
570 * estate: the execution state initialized in InitPlan.
571 * ----------------------------------------------------------------
574 ExecInitIndexScan(IndexScan *node, EState *estate, Plan *parent)
576 IndexScanState *indexstate;
577 CommonScanState *scanstate;
585 RelationPtr relationDescs;
586 IndexScanDescPtr scanDescs;
587 Pointer *runtimeKeyInfo;
588 bool have_runtime_keys;
590 RangeTblEntry *rtentry;
594 Relation currentRelation;
595 HeapScanDesc currentScanDesc;
596 ScanDirection direction;
599 List *execParam = NULL;
602 * assign execution state to node
605 node->scan.plan.state = estate;
607 /* --------------------------------
608 * Part 1) initialize scan state
610 * create new CommonScanState for node
611 * --------------------------------
613 scanstate = makeNode(CommonScanState);
615 scanstate->ss_ProcOuterFlag = false;
616 scanstate->ss_OldRelId = 0;
619 node->scan.scanstate = scanstate;
622 * assign node's base_id .. we don't use AssignNodeBaseid() because
623 * the increment is done later on after we assign the index scan's
624 * scanstate. see below.
627 baseid = estate->es_BaseId;
628 /* scanstate->csstate.cstate.bnode.base_id = baseid; */
629 scanstate->cstate.cs_base_id = baseid;
632 * create expression context for node
635 ExecAssignExprContext(estate, &scanstate->cstate);
637 #define INDEXSCAN_NSLOTS 3
639 * tuple table initialization
642 ExecInitResultTupleSlot(estate, &scanstate->cstate);
643 ExecInitScanTupleSlot(estate, scanstate);
644 /* ExecInitRawTupleSlot(estate, scanstate); */
647 * initialize projection info. result type comes from scan desc
651 ExecAssignProjectionInfo((Plan *) node, &scanstate->cstate);
653 /* --------------------------------
654 * Part 2) initialize index scan state
656 * create new IndexScanState for node
657 * --------------------------------
659 indexstate = makeNode(IndexScanState);
660 indexstate->iss_NumIndices = 0;
661 indexstate->iss_IndexPtr = -1;
662 indexstate->iss_ScanKeys = NULL;
663 indexstate->iss_NumScanKeys = NULL;
664 indexstate->iss_RuntimeKeyInfo = NULL;
665 indexstate->iss_RelationDescs = NULL;
666 indexstate->iss_ScanDescs = NULL;
668 node->indxstate = indexstate;
671 * assign base id to index scan state also
674 indexstate->cstate.cs_base_id = baseid;
676 estate->es_BaseId = baseid;
679 * get the index node information
682 indxid = node->indxid;
683 numIndices = length(indxid);
686 CXT1_printf("ExecInitIndexScan: context is %d\n", CurrentMemoryContext);
689 * scanKeys is used to keep track of the ScanKey's. This is needed
690 * because a single scan may use several indices and each index has
694 numScanKeys = (int *) palloc(numIndices * sizeof(int));
695 scanKeys = (ScanKey *) palloc(numIndices * sizeof(ScanKey));
696 relationDescs = (RelationPtr) palloc(numIndices * sizeof(Relation));
697 scanDescs = (IndexScanDescPtr) palloc(numIndices * sizeof(IndexScanDesc));
700 * initialize runtime key info.
703 have_runtime_keys = false;
704 runtimeKeyInfo = (Pointer *)
705 palloc(numIndices * sizeof(Pointer));
708 * build the index scan keys from the index qualification
711 indxqual = node->indxqual;
712 for (i = 0; i < numIndices; i++)
720 qual = lfirst(indxqual);
721 indxqual = lnext(indxqual);
722 n_keys = length(qual);
723 scan_keys = (n_keys <= 0) ? NULL :
724 (ScanKey) palloc(n_keys * sizeof(ScanKeyData));
725 run_keys = (n_keys <= 0) ? NULL :
726 (int *) palloc(n_keys * sizeof(int));
728 CXT1_printf("ExecInitIndexScan: context is %d\n", CurrentMemoryContext);
731 * for each opclause in the given qual,
732 * convert each qual's opclause into a single scan key
735 for (j = 0; j < n_keys; j++)
737 Expr *clause; /* one part of index qual */
738 Oper *op; /* operator used in scan.. */
739 Node *leftop; /* expr on lhs of operator */
740 Node *rightop;/* expr on rhs ... */
743 int scanvar;/* which var identifies varattno */
744 AttrNumber varattno = 0; /* att number used in scan */
745 Oid opid; /* operator id used in scan */
746 Datum scanvalue = 0; /* value used in scan (if const) */
749 * extract clause information from the qualification
752 clause = nth(j, qual);
754 op = (Oper *) clause->oper;
755 if (!IsA(clause, Expr) ||!IsA(op, Oper))
756 elog(ERROR, "ExecInitIndexScan: indxqual not an opclause!");
761 * Here we figure out the contents of the index qual.
762 * The usual case is (var op const) or (const op var)
763 * which means we form a scan key for the attribute
764 * listed in the var node and use the value of the const.
766 * If we don't have a const node, then it means that
767 * one of the var nodes refers to the "scan" tuple and
768 * is used to determine which attribute to scan, and the
769 * other expression is used to calculate the value used in
770 * scanning the index.
772 * This means our index scan's scan key is a function of
773 * information obtained during the execution of the plan
774 * in which case we need to recalculate the index scan key
777 * Hence, we set have_runtime_keys to true and then set
778 * the appropriate flag in run_keys to LEFT_OP or RIGHT_OP.
779 * The corresponding scan keys are recomputed at run time.
781 * XXX Although this code *thinks* it can handle an indexqual
782 * with the indexkey on either side, in fact it cannot.
783 * Indexscans only work with quals that have the indexkey on
784 * the left (the planner/optimizer makes sure it never passes
785 * anything else). The reason: the scankey machinery has no
786 * provision for distinguishing which side of the operator is
787 * the indexed attribute and which is the compared-to constant.
788 * It just assumes that the attribute is on the left :-(
790 * I am leaving this code able to support both ways, even though
791 * half of it is dead code, on the off chance that someone will
792 * fix the scankey machinery someday --- tgl 8/11/99.
799 * determine information in leftop
802 leftop = (Node *) get_leftop(clause);
804 Assert(leftop != NULL);
806 if (IsA(leftop, Var) &&var_is_rel((Var *) leftop))
809 * if the leftop is a "rel-var", then it means
810 * that it is a var node which tells us which
811 * attribute to use for our scan key.
814 varattno = ((Var *) leftop)->varattno;
817 else if (is_funcclause(leftop) &&
818 var_is_rel(lfirst(((Expr *) leftop)->args)))
821 * if the leftop is a func node then it means
822 * it identifies the value to place in our scan key.
823 * Since functional indices have only one attribute
824 * the attno must always be set to 1.
830 else if (IsA(leftop, Const))
833 * if the leftop is a const node then it means
834 * it identifies the value to place in our scan key.
838 scanvalue = ((Const *) leftop)->constvalue;
840 else if (IsA(leftop, Param))
845 * if the leftop is a Param node then it means
846 * it identifies the value to place in our scan key.
850 /* Life was so easy before ... subselects */
851 if (((Param *) leftop)->paramkind == PARAM_EXEC)
853 have_runtime_keys = true;
854 run_keys[j] = LEFT_OP;
855 execParam = lappendi(execParam, ((Param *) leftop)->paramid);
859 scanvalue = ExecEvalParam((Param *) leftop,
860 scanstate->cstate.cs_ExprContext,
871 * otherwise, the leftop contains information usable
872 * at runtime to figure out the value to place in our
876 have_runtime_keys = true;
877 run_keys[j] = LEFT_OP;
878 scanvalue = Int32GetDatum((int32) true);
882 * now determine information in rightop
885 rightop = (Node *) get_rightop(clause);
887 Assert(rightop != NULL);
889 if (IsA(rightop, Var) &&var_is_rel((Var *) rightop))
892 * here we make sure only one op identifies the
896 if (scanvar == LEFT_OP)
897 elog(ERROR, "ExecInitIndexScan: %s",
898 "both left and right op's are rel-vars");
901 * if the rightop is a "rel-var", then it means
902 * that it is a var node which tells us which
903 * attribute to use for our scan key.
906 varattno = ((Var *) rightop)->varattno;
909 else if (is_funcclause(rightop) &&
910 var_is_rel(lfirst(((Expr *) rightop)->args)))
913 * if the rightop is a func node then it means
914 * it identifies the value to place in our scan key.
915 * Since functional indices have only one attribute
916 * the attno must always be set to 1.
919 if (scanvar == LEFT_OP)
920 elog(ERROR, "ExecInitIndexScan: %s",
921 "both left and right ops are rel-vars");
926 else if (IsA(rightop, Const))
929 * if the rightop is a const node then it means
930 * it identifies the value to place in our scan key.
934 scanvalue = ((Const *) rightop)->constvalue;
936 else if (IsA(rightop, Param))
941 * if the rightop is a Param node then it means
942 * it identifies the value to place in our scan key.
946 /* Life was so easy before ... subselects */
947 if (((Param *) rightop)->paramkind == PARAM_EXEC)
949 have_runtime_keys = true;
950 run_keys[j] = RIGHT_OP;
951 execParam = lappendi(execParam, ((Param *) rightop)->paramid);
955 scanvalue = ExecEvalParam((Param *) rightop,
956 scanstate->cstate.cs_ExprContext,
967 * otherwise, the rightop contains information usable
968 * at runtime to figure out the value to place in our
972 have_runtime_keys = true;
973 run_keys[j] = RIGHT_OP;
974 scanvalue = Int32GetDatum((int32) true);
978 * now check that at least one op tells us the scan
982 if (scanvar == NO_OP)
983 elog(ERROR, "ExecInitIndexScan: %s",
984 "neither leftop nor rightop refer to scan relation");
987 * initialize the scan key's fields appropriately
990 ScanKeyEntryInitialize(&scan_keys[j],
992 varattno, /* attribute number to
994 (RegProcedure) opid, /* reg proc to use */
995 (Datum) scanvalue); /* constant */
999 * store the key information into our array.
1002 numScanKeys[i] = n_keys;
1003 scanKeys[i] = scan_keys;
1004 runtimeKeyInfo[i] = (Pointer) run_keys;
1007 indexstate->iss_NumIndices = numIndices;
1008 if (ScanDirectionIsBackward(node->indxorderdir))
1009 indexPtr = numIndices;
1010 indexstate->iss_IndexPtr = indexPtr;
1011 indexstate->iss_ScanKeys = scanKeys;
1012 indexstate->iss_NumScanKeys = numScanKeys;
1015 * If all of our keys have the form (op var const) , then we have no
1016 * runtime keys so we store NULL in the runtime key info.
1017 * Otherwise runtime key info contains an array of pointers
1018 * (one for each index) to arrays of flags (one for each key)
1019 * which indicate that the qual needs to be evaluated at runtime.
1023 if (have_runtime_keys)
1024 indexstate->iss_RuntimeKeyInfo = (Pointer) runtimeKeyInfo;
1026 indexstate->iss_RuntimeKeyInfo = NULL;
1029 * get the range table and direction information
1030 * from the execution state (these are needed to
1031 * open the relations).
1034 rangeTable = estate->es_range_table;
1035 direction = estate->es_direction;
1038 * open the base relation
1041 relid = node->scan.scanrelid;
1042 rtentry = rt_fetch(relid, rangeTable);
1043 reloid = rtentry->relid;
1045 ExecOpenScanR(reloid, /* relation */
1047 (ScanKey) NULL, /* scan key */
1049 direction, /* scan direction */
1050 estate->es_snapshot, /* */
1051 ¤tRelation, /* return: rel desc */
1052 (Pointer *) ¤tScanDesc); /* return: scan desc */
1054 if (!RelationGetForm(currentRelation)->relhasindex)
1055 elog(ERROR, "indexes of the relation %u was inactivated", reloid);
1056 scanstate->css_currentRelation = currentRelation;
1057 scanstate->css_currentScanDesc = currentScanDesc;
1061 * get the scan type from the relation descriptor.
1064 ExecAssignScanType(scanstate, RelationGetDescr(currentRelation));
1065 ExecAssignResultTypeFromTL((Plan *) node, &scanstate->cstate);
1068 * index scans don't have subtrees..
1071 /* scanstate->ss_ProcOuterFlag = false; */
1074 * open the index relations and initialize
1075 * relation and scan descriptors.
1078 for (i = 0; i < numIndices; i++)
1080 Oid indexOid = (Oid) nthi(i, indxid);
1084 ExecOpenScanR(indexOid, /* relation */
1085 numScanKeys[i], /* nkeys */
1086 scanKeys[i], /* scan key */
1087 true, /* is index */
1088 direction, /* scan direction */
1089 estate->es_snapshot,
1090 &(relationDescs[i]), /* return: rel desc */
1091 (Pointer *) &(scanDescs[i]));
1092 /* return: scan desc */
1096 indexstate->iss_RelationDescs = relationDescs;
1097 indexstate->iss_ScanDescs = scanDescs;
1099 indexstate->cstate.cs_TupFromTlist = false;
1102 * if there are some PARAM_EXEC in skankeys then force index rescan on
1105 ((Plan *) node)->chgParam = execParam;
1115 ExecCountSlotsIndexScan(IndexScan *node)
1117 return ExecCountSlotsNode(outerPlan((Plan *) node)) +
1118 ExecCountSlotsNode(innerPlan((Plan *) node)) + INDEXSCAN_NSLOTS;