1 /*-------------------------------------------------------------------------
4 * Routines to support indexes and indexed scans of relations
6 * Copyright (c) 1994, Regents of the University of California
10 * $Header: /cvsroot/pgsql/src/backend/executor/nodeIndexscan.c,v 1.22 1998/08/03 19:41:29 momjian Exp $
12 *-------------------------------------------------------------------------
16 * ExecInsertIndexTuples inserts tuples into indices on result relation
18 * ExecIndexScan scans a relation using indices
19 * ExecIndexNext using index to retrieve next tuple
20 * ExecInitIndexScan creates and initializes state info.
21 * ExecIndexReScan rescans the indexed relation.
22 * ExecEndIndexScan releases all storage.
23 * ExecIndexMarkPos marks scan position.
24 * ExecIndexRestrPos restores scan position.
27 * the code supporting ExecInsertIndexTuples should be
28 * collected and merged with the genam stuff.
33 #include "executor/executor.h"
34 #include "executor/execdebug.h"
35 #include "executor/nodeIndexscan.h"
37 #include "optimizer/clauses.h" /* for get_op, get_leftop, get_rightop */
38 #include "parser/parsetree.h" /* for rt_fetch() */
40 #include "access/skey.h"
41 #include "access/heapam.h"
42 #include "access/genam.h"
43 #include "utils/palloc.h"
44 #include "utils/mcxt.h"
45 #include "catalog/index.h"
46 #include "storage/bufmgr.h"
47 #include "storage/lmgr.h"
48 #include "nodes/nodeFuncs.h"
51 * Misc stuff to move to executor.h soon -cim 6/5/90
58 static TupleTableSlot *IndexNext(IndexScan *node);
60 /* ----------------------------------------------------------------
63 * Retrieve a tuple from the IndexScan node's currentRelation
64 * using the indices in the IndexScanState information.
66 * note: the old code mentions 'Primary indices'. to my knowledge
67 * we only support a single secondary index. -cim 9/11/89
70 * retrieve a tuple from relation using the indices given.
71 * The indices are used in the order they appear in 'indices'.
72 * The indices may be primary or secondary indices:
73 * * primary index -- scan the relation 'relID' using keys supplied.
74 * * secondary index -- scan the index relation to get the 'tid' for
75 * a tuple in the relation 'relID'.
76 * If the current index(pointed by 'indexPtr') fails to return a
77 * tuple, the next index in the indices is used.
79 * bug fix so that it should retrieve on a null scan key.
80 * ----------------------------------------------------------------
82 static TupleTableSlot *
83 IndexNext(IndexScan *node)
86 CommonScanState *scanstate;
87 IndexScanState *indexstate;
88 ScanDirection direction;
90 IndexScanDescPtr scanDescs;
91 IndexScanDesc scandesc;
92 Relation heapRelation;
93 RetrieveIndexResult result;
96 Buffer buffer = InvalidBuffer;
100 * extract necessary information from index scan node
103 estate = node->scan.plan.state;
104 direction = estate->es_direction;
105 snapshot = estate->es_snapshot;
106 scanstate = node->scan.scanstate;
107 indexstate = node->indxstate;
108 scanDescs = indexstate->iss_ScanDescs;
109 heapRelation = scanstate->css_currentRelation;
110 numIndices = indexstate->iss_NumIndices;
111 slot = scanstate->css_ScanTupleSlot;
114 * ok, now that we have what we need, fetch an index tuple.
115 * if scanning this index succeeded then return the
116 * appropriate heap tuple.. else return NULL.
119 while (indexstate->iss_IndexPtr < numIndices)
121 scandesc = scanDescs[indexstate->iss_IndexPtr];
122 while ((result = index_getnext(scandesc, direction)) != NULL)
124 tuple = heap_fetch(heapRelation, snapshot,
125 &result->heap_iptr, &buffer);
131 bool prev_matches = false;
135 * store the scanned tuple in the scan tuple slot of
136 * the scan state. Eventually we will only do this and not
137 * return a tuple. Note: we pass 'false' because tuples
138 * returned by amgetnext are pointers onto disk pages and
139 * were not created with palloc() and so should not be pfree()'d.
142 ExecStoreTuple(tuple, /* tuple to store */
143 slot, /* slot to store in */
144 buffer, /* buffer associated with tuple */
145 false); /* don't pfree */
147 for (prev_index = 0; prev_index < indexstate->iss_IndexPtr;
150 if (ExecQual(nth(prev_index, node->indxqual),
151 scanstate->cstate.cs_ExprContext))
160 ExecClearTuple(slot);
162 if (BufferIsValid(buffer))
163 ReleaseBuffer(buffer);
165 if (indexstate->iss_IndexPtr < numIndices)
166 indexstate->iss_IndexPtr++;
169 * if we get here it means the index scan failed so we
170 * are at the end of the scan..
173 return ExecClearTuple(slot);
176 /* ----------------------------------------------------------------
177 * ExecIndexScan(node)
180 * Scans the relation using primary or secondary indices and returns
181 * the next qualifying tuple in the direction specified.
182 * It calls ExecScan() and passes it the access methods which returns
183 * the next tuple using the indices.
186 * -- the "cursor" maintained by the AMI is positioned at the tuple
187 * returned previously.
190 * -- the relation indicated is opened for scanning so that the
191 * "cursor" is positioned before the first qualifying tuple.
192 * -- all index realtions are opened for scanning.
193 * -- indexPtr points to the first index.
194 * -- state variable ruleFlag = nil.
195 * ----------------------------------------------------------------
198 ExecIndexScan(IndexScan *node)
201 * use IndexNext as access method
204 return ExecScan(&node->scan, IndexNext);
207 /* ----------------------------------------------------------------
208 * ExecIndexReScan(node)
210 * Recalculates the value of the scan keys whose value depends on
211 * information known at runtime and rescans the indexed relation.
212 * Updating the scan key was formerly done separately in
213 * ExecUpdateIndexScanKeys. Integrating it into ReScan
214 * makes rescans of indices and
215 * relations/general streams more uniform.
217 * ----------------------------------------------------------------
220 ExecIndexReScan(IndexScan *node, ExprContext *exprCtxt, Plan *parent)
223 IndexScanState *indexstate;
224 ScanDirection direction;
225 IndexScanDescPtr scanDescs;
232 Pointer *runtimeKeyInfo;
246 indexstate = node->indxstate;
247 estate = node->scan.plan.state;
248 direction = estate->es_direction;
249 numIndices = indexstate->iss_NumIndices;
250 scanDescs = indexstate->iss_ScanDescs;
251 scanKeys = indexstate->iss_ScanKeys;
252 runtimeKeyInfo = (Pointer *) indexstate->iss_RuntimeKeyInfo;
253 indxqual = node->indxqual;
254 numScanKeys = indexstate->iss_NumScanKeys;
255 indexstate->iss_IndexPtr = 0;
257 /* it's possible in subselects */
258 if (exprCtxt == NULL)
259 exprCtxt = node->scan.scanstate->cstate.cs_ExprContext;
261 node->scan.scanstate->cstate.cs_ExprContext->ecxt_outertuple =
262 exprCtxt->ecxt_outertuple;
265 * get the index qualifications and recalculate the appropriate
268 for (i = 0; i < numIndices; i++)
270 qual = nth(i, indxqual);
271 n_keys = numScanKeys[i];
272 run_keys = (int *) runtimeKeyInfo[i];
273 scan_keys = (ScanKey) scanKeys[i];
275 for (j = 0; j < n_keys; j++)
278 * If we have a run-time key, then extract the run-time
279 * expression and evaluate it with respect to the current
280 * outer tuple. We then stick the result into the scan key.
282 if (run_keys[j] != NO_OP)
284 clause = nth(j, qual);
285 scanexpr = (run_keys[j] == RIGHT_OP) ?
286 (Node *) get_rightop(clause) : (Node *) get_leftop(clause);
289 * pass in isDone but ignore it. We don't iterate in
293 ExecEvalExpr(scanexpr, exprCtxt, &isNull, &isDone);
294 scan_keys[j].sk_argument = scanvalue;
296 scan_keys[j].sk_flags |= SK_ISNULL;
298 scan_keys[j].sk_flags &= ~SK_ISNULL;
301 sdesc = scanDescs[i];
303 index_rescan(sdesc, direction, skey);
306 * perhaps return something meaningful
312 /* ----------------------------------------------------------------
316 * Releases any storage allocated through C routines.
318 * ----------------------------------------------------------------
321 ExecEndIndexScan(IndexScan *node)
323 CommonScanState *scanstate;
324 IndexScanState *indexstate;
325 Pointer *runtimeKeyInfo;
332 scanstate = node->scan.scanstate;
333 indexstate = node->indxstate;
334 indxqual = node->indxqual;
335 runtimeKeyInfo = (Pointer *) indexstate->iss_RuntimeKeyInfo;
338 * extract information from the node
341 numIndices = indexstate->iss_NumIndices;
342 scanKeys = indexstate->iss_ScanKeys;
343 numScanKeys = indexstate->iss_NumScanKeys;
346 * Free the projection info and the scan attribute info
348 * Note: we don't ExecFreeResultType(scanstate)
349 * because the rule manager depends on the tupType
350 * returned by ExecMain(). So for now, this
351 * is freed at end-transaction time. -cim 6/2/91
354 ExecFreeProjectionInfo(&scanstate->cstate);
357 * close the heap and index relations
360 ExecCloseR((Plan *) node);
363 * free the scan keys used in scanning the indices
366 for (i = 0; i < numIndices; i++)
368 if (scanKeys[i] != NULL)
376 for (i = 0; i < numIndices; i++)
381 qual = nth(i, indxqual);
382 n_keys = length(qual);
384 pfree(runtimeKeyInfo[i]);
386 pfree(runtimeKeyInfo);
390 * clear out tuple table slots
393 ExecClearTuple(scanstate->cstate.cs_ResultTupleSlot);
394 ExecClearTuple(scanstate->css_ScanTupleSlot);
395 /* ExecClearTuple(scanstate->css_RawTupleSlot); */
398 /* ----------------------------------------------------------------
402 * Marks scan position by marking the current index.
404 * ----------------------------------------------------------------
407 ExecIndexMarkPos(IndexScan *node)
409 IndexScanState *indexstate;
410 IndexScanDescPtr indexScanDescs;
411 IndexScanDesc scanDesc;
414 indexstate = node->indxstate;
415 indexPtr = indexstate->iss_MarkIndexPtr = indexstate->iss_IndexPtr;
416 indexScanDescs = indexstate->iss_ScanDescs;
417 scanDesc = indexScanDescs[indexPtr];
420 IndexScanMarkPosition(scanDesc);
422 index_markpos (scanDesc);
425 /* ----------------------------------------------------------------
429 * Restores scan position by restoring the current index.
432 * XXX Assumes previously marked scan position belongs to current index
433 * ----------------------------------------------------------------
436 ExecIndexRestrPos(IndexScan *node)
438 IndexScanState *indexstate;
439 IndexScanDescPtr indexScanDescs;
440 IndexScanDesc scanDesc;
443 indexstate = node->indxstate;
444 indexPtr = indexstate->iss_IndexPtr = indexstate->iss_MarkIndexPtr;
445 indexScanDescs = indexstate->iss_ScanDescs;
446 scanDesc = indexScanDescs[indexPtr];
449 IndexScanRestorePosition(scanDesc);
451 index_restrpos (scanDesc);
454 /* ----------------------------------------------------------------
457 * Initializes the index scan's state information, creates
458 * scan keys, and opens the base and index relations.
460 * Note: index scans have 2 sets of state information because
461 * we have to keep track of the base relation and the
465 * Creates the run-time state information for the node and
466 * sets the relation id to contain relevant decriptors.
469 * node: IndexNode node produced by the planner.
470 * estate: the execution state initialized in InitPlan.
471 * ----------------------------------------------------------------
474 ExecInitIndexScan(IndexScan *node, EState *estate, Plan *parent)
476 IndexScanState *indexstate;
477 CommonScanState *scanstate;
485 RelationPtr relationDescs;
486 IndexScanDescPtr scanDescs;
487 Pointer *runtimeKeyInfo;
488 bool have_runtime_keys;
490 RangeTblEntry *rtentry;
494 Relation currentRelation;
495 HeapScanDesc currentScanDesc;
496 ScanDirection direction;
499 List *execParam = NULL;
502 * assign execution state to node
505 node->scan.plan.state = estate;
507 /* --------------------------------
508 * Part 1) initialize scan state
510 * create new CommonScanState for node
511 * --------------------------------
513 scanstate = makeNode(CommonScanState);
515 scanstate->ss_ProcOuterFlag = false;
516 scanstate->ss_OldRelId = 0;
519 node->scan.scanstate = scanstate;
522 * assign node's base_id .. we don't use AssignNodeBaseid() because
523 * the increment is done later on after we assign the index scan's
524 * scanstate. see below.
527 baseid = estate->es_BaseId;
528 /* scanstate->csstate.cstate.bnode.base_id = baseid; */
529 scanstate->cstate.cs_base_id = baseid;
532 * create expression context for node
535 ExecAssignExprContext(estate, &scanstate->cstate);
537 #define INDEXSCAN_NSLOTS 3
539 * tuple table initialization
542 ExecInitResultTupleSlot(estate, &scanstate->cstate);
543 ExecInitScanTupleSlot(estate, scanstate);
544 /* ExecInitRawTupleSlot(estate, scanstate); */
547 * initialize projection info. result type comes from scan desc
551 ExecAssignProjectionInfo((Plan *) node, &scanstate->cstate);
553 /* --------------------------------
554 * Part 2) initialize index scan state
556 * create new IndexScanState for node
557 * --------------------------------
559 indexstate = makeNode(IndexScanState);
560 indexstate->iss_NumIndices = 0;
561 indexstate->iss_IndexPtr = 0;
562 indexstate->iss_ScanKeys = NULL;
563 indexstate->iss_NumScanKeys = NULL;
564 indexstate->iss_RuntimeKeyInfo = NULL;
565 indexstate->iss_RelationDescs = NULL;
566 indexstate->iss_ScanDescs = NULL;
568 node->indxstate = indexstate;
571 * assign base id to index scan state also
574 indexstate->cstate.cs_base_id = baseid;
576 estate->es_BaseId = baseid;
579 * get the index node information
582 indxid = node->indxid;
583 indxqual = node->indxqual;
584 numIndices = length(indxid);
587 CXT1_printf("ExecInitIndexScan: context is %d\n", CurrentMemoryContext);
590 * scanKeys is used to keep track of the ScanKey's. This is needed
591 * because a single scan may use several indices and each index has
595 numScanKeys = (int *) palloc(numIndices * sizeof(int));
596 scanKeys = (ScanKey *) palloc(numIndices * sizeof(ScanKey));
597 relationDescs = (RelationPtr) palloc(numIndices * sizeof(Relation));
598 scanDescs = (IndexScanDescPtr) palloc(numIndices * sizeof(IndexScanDesc));
601 * initialize runtime key info.
604 have_runtime_keys = false;
605 runtimeKeyInfo = (Pointer *)
606 palloc(numIndices * sizeof(Pointer));
609 * build the index scan keys from the index qualification
612 for (i = 0; i < numIndices; i++)
620 qual = nth(i, indxqual);
621 n_keys = length(qual);
622 scan_keys = (n_keys <= 0) ? NULL :
623 (ScanKey) palloc(n_keys * sizeof(ScanKeyData));
624 run_keys = (n_keys <= 0) ? NULL :
625 (int *) palloc(n_keys * sizeof(int));
627 CXT1_printf("ExecInitIndexScan: context is %d\n",
628 CurrentMemoryContext);
631 * for each opclause in the given qual,
632 * convert each qual's opclause into a single scan key
635 for (j = 0; j < n_keys; j++)
637 Expr *clause; /* one part of index qual */
638 Oper *op; /* operator used in scan.. */
639 Node *leftop; /* expr on lhs of operator */
640 Node *rightop;/* expr on rhs ... */
643 int scanvar;/* which var identifies varattno */
644 AttrNumber varattno = 0; /* att number used in scan */
645 Oid opid; /* operator id used in scan */
646 Datum scanvalue = 0; /* value used in scan (if const) */
649 * extract clause information from the qualification
652 clause = nth(j, qual);
654 op = (Oper *) clause->oper;
656 elog(ERROR, "ExecInitIndexScan: op not an Oper!");
661 * Here we figure out the contents of the index qual.
662 * The usual case is (op var const) or (op const var)
663 * which means we form a scan key for the attribute
664 * listed in the var node and use the value of the const.
666 * If we don't have a const node, then it means that
667 * one of the var nodes refers to the "scan" tuple and
668 * is used to determine which attribute to scan, and the
669 * other expression is used to calculate the value used in
670 * scanning the index.
672 * This means our index scan's scan key is a function of
673 * information obtained during the execution of the plan
674 * in which case we need to recalculate the index scan key
677 * Hence, we set have_runtime_keys to true and then set
678 * the appropriate flag in run_keys to LEFT_OP or RIGHT_OP.
679 * The corresponding scan keys are recomputed at run time.
686 * determine information in leftop
689 leftop = (Node *) get_leftop(clause);
691 if (IsA(leftop, Var) &&var_is_rel((Var *) leftop))
694 * if the leftop is a "rel-var", then it means
695 * that it is a var node which tells us which
696 * attribute to use for our scan key.
699 varattno = ((Var *) leftop)->varattno;
702 else if (IsA(leftop, Const))
705 * if the leftop is a const node then it means
706 * it identifies the value to place in our scan key.
710 scanvalue = ((Const *) leftop)->constvalue;
712 else if (IsA(leftop, Param))
717 * if the leftop is a Param node then it means
718 * it identifies the value to place in our scan key.
722 /* Life was so easy before ... subselects */
723 if ( ((Param *) leftop)->paramkind == PARAM_EXEC )
725 have_runtime_keys = true;
726 run_keys[j] = LEFT_OP;
727 execParam = lappendi (execParam, ((Param*) leftop)->paramid);
731 scanvalue = ExecEvalParam((Param *) leftop,
732 scanstate->cstate.cs_ExprContext,
740 else if (leftop != NULL &&
741 is_funcclause(leftop) &&
742 var_is_rel(lfirst(((Expr *) leftop)->args)))
745 * if the leftop is a func node then it means
746 * it identifies the value to place in our scan key.
747 * Since functional indices have only one attribute
748 * the attno must always be set to 1.
758 * otherwise, the leftop contains information usable
759 * at runtime to figure out the value to place in our
763 have_runtime_keys = true;
764 run_keys[j] = LEFT_OP;
765 scanvalue = Int32GetDatum((int32) true);
769 * now determine information in rightop
772 rightop = (Node *) get_rightop(clause);
774 if (IsA(rightop, Var) &&var_is_rel((Var *) rightop))
777 * here we make sure only one op identifies the
781 if (scanvar == LEFT_OP)
782 elog(ERROR, "ExecInitIndexScan: %s",
783 "both left and right op's are rel-vars");
786 * if the rightop is a "rel-var", then it means
787 * that it is a var node which tells us which
788 * attribute to use for our scan key.
791 varattno = ((Var *) rightop)->varattno;
795 else if (IsA(rightop, Const))
798 * if the leftop is a const node then it means
799 * it identifies the value to place in our scan key.
803 scanvalue = ((Const *) rightop)->constvalue;
805 else if (IsA(rightop, Param))
810 * if the rightop is a Param node then it means
811 * it identifies the value to place in our scan key.
815 /* Life was so easy before ... subselects */
816 if ( ((Param *) rightop)->paramkind == PARAM_EXEC )
818 have_runtime_keys = true;
819 run_keys[j] = RIGHT_OP;
820 execParam = lappendi (execParam, ((Param*) rightop)->paramid);
824 scanvalue = ExecEvalParam((Param *) rightop,
825 scanstate->cstate.cs_ExprContext,
833 else if (rightop != NULL &&
834 is_funcclause(rightop) &&
835 var_is_rel(lfirst(((Expr *) rightop)->args)))
838 * if the rightop is a func node then it means
839 * it identifies the value to place in our scan key.
840 * Since functional indices have only one attribute
841 * the attno must always be set to 1.
844 if (scanvar == LEFT_OP)
845 elog(ERROR, "ExecInitIndexScan: %s",
846 "both left and right ops are rel-vars");
855 * otherwise, the leftop contains information usable
856 * at runtime to figure out the value to place in our
860 have_runtime_keys = true;
861 run_keys[j] = RIGHT_OP;
862 scanvalue = Int32GetDatum((int32) true);
866 * now check that at least one op tells us the scan
870 if (scanvar == NO_OP)
871 elog(ERROR, "ExecInitIndexScan: %s",
872 "neither leftop nor rightop refer to scan relation");
875 * initialize the scan key's fields appropriately
878 ScanKeyEntryInitialize(&scan_keys[j],
880 varattno, /* attribute number to
882 (RegProcedure) opid, /* reg proc to use */
883 (Datum) scanvalue); /* constant */
887 * store the key information into our array.
890 numScanKeys[i] = n_keys;
891 scanKeys[i] = scan_keys;
892 runtimeKeyInfo[i] = (Pointer) run_keys;
895 indexstate->iss_NumIndices = numIndices;
896 indexstate->iss_IndexPtr = indexPtr;
897 indexstate->iss_ScanKeys = scanKeys;
898 indexstate->iss_NumScanKeys = numScanKeys;
901 * If all of our keys have the form (op var const) , then we have no
902 * runtime keys so we store NULL in the runtime key info.
903 * Otherwise runtime key info contains an array of pointers
904 * (one for each index) to arrays of flags (one for each key)
905 * which indicate that the qual needs to be evaluated at runtime.
909 if (have_runtime_keys)
910 indexstate->iss_RuntimeKeyInfo = (Pointer) runtimeKeyInfo;
912 indexstate->iss_RuntimeKeyInfo = NULL;
915 * get the range table and direction information
916 * from the execution state (these are needed to
917 * open the relations).
920 rangeTable = estate->es_range_table;
921 direction = estate->es_direction;
924 * open the base relation
927 relid = node->scan.scanrelid;
928 rtentry = rt_fetch(relid, rangeTable);
929 reloid = rtentry->relid;
931 ExecOpenScanR(reloid, /* relation */
933 (ScanKey) NULL, /* scan key */
935 direction, /* scan direction */
936 estate->es_snapshot, /* */
937 ¤tRelation, /* return: rel desc */
938 (Pointer *) ¤tScanDesc); /* return: scan desc */
940 scanstate->css_currentRelation = currentRelation;
941 scanstate->css_currentScanDesc = currentScanDesc;
945 * get the scan type from the relation descriptor.
948 ExecAssignScanType(scanstate, RelationGetTupleDescriptor(currentRelation));
949 ExecAssignResultTypeFromTL((Plan *) node, &scanstate->cstate);
952 * index scans don't have subtrees..
955 /* scanstate->ss_ProcOuterFlag = false; */
958 * open the index relations and initialize
959 * relation and scan descriptors.
962 for (i = 0; i < numIndices; i++)
966 indexOid = (Oid) nthi(i, indxid);
970 ExecOpenScanR(indexOid, /* relation */
971 numScanKeys[i], /* nkeys */
972 scanKeys[i], /* scan key */
974 direction, /* scan direction */
976 &(relationDescs[i]), /* return: rel desc */
977 (Pointer *) &(scanDescs[i]));
978 /* return: scan desc */
982 indexstate->iss_RelationDescs = relationDescs;
983 indexstate->iss_ScanDescs = scanDescs;
985 indexstate->cstate.cs_TupFromTlist = false;
988 * if there are some PARAM_EXEC in skankeys then
989 * force index rescan on first scan.
991 ((Plan*) node)->chgParam = execParam;
1001 ExecCountSlotsIndexScan(IndexScan *node)
1003 return ExecCountSlotsNode(outerPlan((Plan *) node)) +
1004 ExecCountSlotsNode(innerPlan((Plan *) node)) + INDEXSCAN_NSLOTS;