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.5 1996/11/08 00:45:57 scrappy 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;
97 Buffer buffer = InvalidBuffer;
100 * extract necessary information from index scan node
103 estate = node->scan.plan.state;
104 direction = estate->es_direction;
105 scanstate = node->scan.scanstate;
106 indexstate = node->indxstate;
107 indexPtr = indexstate->iss_IndexPtr;
108 scanDescs = indexstate->iss_ScanDescs;
109 scandesc = scanDescs[ indexPtr ];
110 heapRelation = scanstate->css_currentRelation;
112 slot = scanstate->css_ScanTupleSlot;
115 * ok, now that we have what we need, fetch an index tuple.
120 result = index_getnext(scandesc, direction);
122 * if scanning this index succeeded then return the
123 * appropriate heap tuple.. else return NULL.
127 iptr = &result->heap_iptr;
128 tuple = heap_fetch(heapRelation,
137 * we found a deleted tuple, so keep on scanning..
140 if (BufferIsValid(buffer))
141 ReleaseBuffer(buffer);
146 * store the scanned tuple in the scan tuple slot of
147 * the scan state. Eventually we will only do this and not
148 * return a tuple. Note: we pass 'false' because tuples
149 * returned by amgetnext are pointers onto disk pages and
150 * were not created with palloc() and so should not be pfree()'d.
153 ExecStoreTuple(tuple, /* tuple to store */
154 slot, /* slot to store in */
155 buffer, /* buffer associated with tuple */
156 false); /* don't pfree */
162 * if we get here it means the index scan failed so we
163 * are at the end of the scan..
166 return ExecClearTuple(slot);
170 /* ----------------------------------------------------------------
171 * ExecIndexScan(node)
174 * Scans the relation using primary or secondary indices and returns
175 * the next qualifying tuple in the direction specified.
176 * It calls ExecScan() and passes it the access methods which returns
177 * the next tuple using the indices.
180 * -- the "cursor" maintained by the AMI is positioned at the tuple
181 * returned previously.
184 * -- the relation indicated is opened for scanning so that the
185 * "cursor" is positioned before the first qualifying tuple.
186 * -- all index realtions are opened for scanning.
187 * -- indexPtr points to the first index.
188 * -- state variable ruleFlag = nil.
189 * ----------------------------------------------------------------
192 ExecIndexScan(IndexScan *node)
194 TupleTableSlot *returnTuple;
197 * use IndexNext as access method
200 returnTuple = ExecScan(&node->scan, IndexNext);
204 /* ----------------------------------------------------------------
205 * ExecIndexReScan(node)
207 * Recalculates the value of the scan keys whose value depends on
208 * information known at runtime and rescans the indexed relation.
209 * Updating the scan key was formerly done separately in
210 * ExecUpdateIndexScanKeys. Integrating it into ReScan
211 * makes rescans of indices and
212 * relations/general streams more uniform.
214 * ----------------------------------------------------------------
217 ExecIndexReScan(IndexScan *node, ExprContext *exprCtxt, Plan* parent)
220 IndexScanState *indexstate;
221 ScanDirection direction;
222 IndexScanDescPtr scanDescs;
229 Pointer *runtimeKeyInfo;
244 indexstate = node->indxstate;
245 estate = node->scan.plan.state;
246 direction = estate->es_direction;
247 indexstate = node->indxstate;
248 numIndices = indexstate->iss_NumIndices;
249 scanDescs = indexstate->iss_ScanDescs;
250 scanKeys = indexstate->iss_ScanKeys;
252 runtimeKeyInfo = (Pointer *) indexstate->iss_RuntimeKeyInfo;
254 if (runtimeKeyInfo != NULL) {
256 * get the index qualifications and
257 * recalculate the appropriate values
259 indexPtr = indexstate->iss_IndexPtr;
260 indxqual = node->indxqual;
261 qual = nth(indexPtr, indxqual);
262 numScanKeys = indexstate->iss_NumScanKeys;
263 n_keys = numScanKeys[indexPtr];
264 run_keys = (int *) runtimeKeyInfo[indexPtr];
265 scan_keys = (ScanKey) scanKeys[indexPtr];
267 for (j=0; j < n_keys; j++) {
269 * If we have a run-time key, then extract the run-time
270 * expression and evaluate it with respect to the current
271 * outer tuple. We then stick the result into the scan
274 if (run_keys[j] != NO_OP) {
275 clause = nth(j, qual);
276 scanexpr = (run_keys[j] == RIGHT_OP) ?
277 (Node*) get_rightop(clause) : (Node*) get_leftop(clause) ;
278 /* pass in isDone but ignore it. We don't iterate in quals */
280 ExecEvalExpr(scanexpr, exprCtxt, &isNull, &isDone);
281 scan_keys[j].sk_argument = scanvalue;
283 scan_keys[j].sk_flags |= SK_ISNULL;
285 scan_keys[j].sk_flags &= ~SK_ISNULL;
292 * rescans all indices
294 * note: AMrescan assumes only one scan key. This may have
295 * to change if we ever decide to support multiple keys.
297 for (i = 0; i < numIndices; i++) {
298 sdesc = scanDescs[ i ];
299 skey = scanKeys[ i ];
300 index_rescan(sdesc, direction, skey);
304 * perhaps return something meaningful
310 /* ----------------------------------------------------------------
314 * Releases any storage allocated through C routines.
316 * ----------------------------------------------------------------
319 ExecEndIndexScan(IndexScan *node)
321 CommonScanState *scanstate;
322 IndexScanState *indexstate;
327 scanstate = node->scan.scanstate;
328 indexstate = node->indxstate;
331 * extract information from the node
334 numIndices = indexstate->iss_NumIndices;
335 scanKeys = indexstate->iss_ScanKeys;
338 * Free the projection info and the scan attribute info
340 * Note: we don't ExecFreeResultType(scanstate)
341 * because the rule manager depends on the tupType
342 * returned by ExecMain(). So for now, this
343 * is freed at end-transaction time. -cim 6/2/91
346 ExecFreeProjectionInfo(&scanstate->cstate);
349 * close the heap and index relations
352 ExecCloseR((Plan *) node);
355 * free the scan keys used in scanning the indices
358 for (i=0; i<numIndices; i++) {
359 if (scanKeys[i]!=NULL)
365 * clear out tuple table slots
368 ExecClearTuple(scanstate->cstate.cs_ResultTupleSlot);
369 ExecClearTuple(scanstate->css_ScanTupleSlot);
370 /* ExecClearTuple(scanstate->css_RawTupleSlot); */
373 /* ----------------------------------------------------------------
377 * Marks scan position by marking the current index.
379 * ----------------------------------------------------------------
382 ExecIndexMarkPos(IndexScan *node)
384 IndexScanState *indexstate;
385 IndexScanDescPtr indexScanDescs;
386 IndexScanDesc scanDesc;
389 indexstate = node->indxstate;
390 indexPtr = indexstate->iss_IndexPtr;
391 indexScanDescs = indexstate->iss_ScanDescs;
392 scanDesc = indexScanDescs[ indexPtr ];
395 * XXX access methods don't return marked positions so
398 IndexScanMarkPosition( scanDesc );
402 /* ----------------------------------------------------------------
406 * Restores scan position by restoring the current index.
409 * XXX Assumes previously marked scan position belongs to current index
410 * ----------------------------------------------------------------
413 ExecIndexRestrPos(IndexScan *node)
415 IndexScanState *indexstate;
416 IndexScanDescPtr indexScanDescs;
417 IndexScanDesc scanDesc;
420 indexstate = node->indxstate;
421 indexPtr = indexstate->iss_IndexPtr;
422 indexScanDescs = indexstate->iss_ScanDescs;
423 scanDesc = indexScanDescs[ indexPtr ];
425 IndexScanRestorePosition( scanDesc );
428 /* ----------------------------------------------------------------
431 * Initializes the index scan's state information, creates
432 * scan keys, and opens the base and index relations.
434 * Note: index scans have 2 sets of state information because
435 * we have to keep track of the base relation and the
439 * Creates the run-time state information for the node and
440 * sets the relation id to contain relevant decriptors.
443 * node: IndexNode node produced by the planner.
444 * estate: the execution state initialized in InitPlan.
445 * ----------------------------------------------------------------
448 ExecInitIndexScan(IndexScan *node, EState *estate, Plan *parent)
450 IndexScanState *indexstate;
451 CommonScanState *scanstate;
459 RelationPtr relationDescs;
460 IndexScanDescPtr scanDescs;
461 Pointer *runtimeKeyInfo;
462 bool have_runtime_keys;
464 RangeTblEntry *rtentry;
469 Relation currentRelation;
470 HeapScanDesc currentScanDesc;
471 ScanDirection direction;
475 * assign execution state to node
478 node->scan.plan.state = estate;
480 /* --------------------------------
481 * Part 1) initialize scan state
483 * create new CommonScanState for node
484 * --------------------------------
486 scanstate = makeNode(CommonScanState);
488 scanstate->ss_ProcOuterFlag = false;
489 scanstate->ss_OldRelId = 0;
492 node->scan.scanstate = scanstate;
495 * assign node's base_id .. we don't use AssignNodeBaseid() because
496 * the increment is done later on after we assign the index scan's
497 * scanstate. see below.
500 baseid = estate->es_BaseId;
501 /* scanstate->csstate.cstate.bnode.base_id = baseid; */
502 scanstate->cstate.cs_base_id = baseid;
505 * create expression context for node
508 ExecAssignExprContext(estate, &scanstate->cstate);
510 #define INDEXSCAN_NSLOTS 3
512 * tuple table initialization
515 ExecInitResultTupleSlot(estate, &scanstate->cstate);
516 ExecInitScanTupleSlot(estate, scanstate);
517 /* ExecInitRawTupleSlot(estate, scanstate); */
520 * initialize projection info. result type comes from scan desc
524 ExecAssignProjectionInfo((Plan *) node, &scanstate->cstate);
526 /* --------------------------------
527 * Part 2) initialize index scan state
529 * create new IndexScanState for node
530 * --------------------------------
532 indexstate = makeNode(IndexScanState);
533 indexstate->iss_NumIndices = 0;
534 indexstate->iss_IndexPtr = 0;
535 indexstate->iss_ScanKeys = NULL;
536 indexstate->iss_NumScanKeys = NULL;
537 indexstate->iss_RuntimeKeyInfo = NULL;
538 indexstate->iss_RelationDescs = NULL;
539 indexstate->iss_ScanDescs = NULL;
541 node->indxstate = indexstate;
544 * assign base id to index scan state also
547 indexstate->cstate.cs_base_id = baseid;
549 estate->es_BaseId = baseid;
552 * get the index node information
555 indxid = node->indxid;
556 indxqual = node->indxqual;
557 numIndices = length(indxid);
560 CXT1_printf("ExecInitIndexScan: context is %d\n", CurrentMemoryContext);
563 * scanKeys is used to keep track of the ScanKey's. This is needed
564 * because a single scan may use several indices and each index has
568 numScanKeys = (int *) palloc(numIndices * sizeof(int));
569 scanKeys = (ScanKey *) palloc(numIndices * sizeof(ScanKey));
570 relationDescs = (RelationPtr) palloc(numIndices * sizeof(Relation));
571 scanDescs = (IndexScanDescPtr) palloc(numIndices * sizeof(IndexScanDesc));
574 * initialize runtime key info.
577 have_runtime_keys = false;
578 runtimeKeyInfo = (Pointer *)
579 palloc(numIndices * sizeof(Pointer));
582 * build the index scan keys from the index qualification
585 for (i=0; i < numIndices; i++) {
592 qual = nth(i, indxqual);
593 n_keys = length(qual);
594 scan_keys = (n_keys <= 0) ? NULL :
595 (ScanKey)palloc(n_keys * sizeof(ScanKeyData));
596 run_keys = (n_keys <= 0) ? NULL :
597 (int *)palloc(n_keys * sizeof(int));
599 CXT1_printf("ExecInitIndexScan: context is %d\n",
600 CurrentMemoryContext);
603 * for each opclause in the given qual,
604 * convert each qual's opclause into a single scan key
607 for (j=0; j < n_keys; j++) {
608 Expr *clause; /* one part of index qual */
609 Oper *op; /* operator used in scan.. */
610 Node *leftop; /* expr on lhs of operator */
611 Node *rightop; /* expr on rhs ... */
613 int scanvar; /* which var identifies varattno */
614 AttrNumber varattno = 0; /* att number used in scan */
615 Oid opid; /* operator id used in scan */
616 Datum scanvalue = 0; /* value used in scan (if const) */
619 * extract clause information from the qualification
622 clause = nth(j, qual);
624 op = (Oper*)clause->oper;
626 elog(WARN, "ExecInitIndexScan: op not an Oper!");
631 * Here we figure out the contents of the index qual.
632 * The usual case is (op var const) or (op const var)
633 * which means we form a scan key for the attribute
634 * listed in the var node and use the value of the const.
636 * If we don't have a const node, then it means that
637 * one of the var nodes refers to the "scan" tuple and
638 * is used to determine which attribute to scan, and the
639 * other expression is used to calculate the value used in
640 * scanning the index.
642 * This means our index scan's scan key is a function of
643 * information obtained during the execution of the plan
644 * in which case we need to recalculate the index scan key
647 * Hence, we set have_runtime_keys to true and then set
648 * the appropriate flag in run_keys to LEFT_OP or RIGHT_OP.
649 * The corresponding scan keys are recomputed at run time.
656 * determine information in leftop
659 leftop = (Node*) get_leftop(clause);
661 if (IsA(leftop,Var) && var_is_rel((Var*)leftop)) {
663 * if the leftop is a "rel-var", then it means
664 * that it is a var node which tells us which
665 * attribute to use for our scan key.
668 varattno = ((Var*) leftop)->varattno;
670 } else if (IsA(leftop,Const)) {
672 * if the leftop is a const node then it means
673 * it identifies the value to place in our scan key.
676 run_keys[ j ] = NO_OP;
677 scanvalue = ((Const*) leftop)->constvalue;
678 } else if (leftop != NULL &&
679 is_funcclause(leftop) &&
680 var_is_rel(lfirst(((Expr*)leftop)->args))) {
682 * if the leftop is a func node then it means
683 * it identifies the value to place in our scan key.
684 * Since functional indices have only one attribute
685 * the attno must always be set to 1.
693 * otherwise, the leftop contains information usable
694 * at runtime to figure out the value to place in our
698 have_runtime_keys = true;
699 run_keys[ j ] = LEFT_OP;
700 scanvalue = Int32GetDatum((int32) true);
704 * now determine information in rightop
707 rightop = (Node*) get_rightop(clause);
709 if (IsA(rightop,Var) && var_is_rel((Var*)rightop)) {
711 * here we make sure only one op identifies the
715 if (scanvar == LEFT_OP)
716 elog(WARN, "ExecInitIndexScan: %s",
717 "both left and right op's are rel-vars");
720 * if the rightop is a "rel-var", then it means
721 * that it is a var node which tells us which
722 * attribute to use for our scan key.
725 varattno = ((Var*) rightop)->varattno;
728 } else if (IsA(rightop,Const)) {
730 * if the leftop is a const node then it means
731 * it identifies the value to place in our scan key.
734 run_keys[ j ] = NO_OP;
735 scanvalue = ((Const*) rightop)->constvalue;
737 } else if (rightop!=NULL &&
738 is_funcclause(rightop) &&
739 var_is_rel(lfirst(((Expr*)rightop)->args))) {
741 * if the rightop is a func node then it means
742 * it identifies the value to place in our scan key.
743 * Since functional indices have only one attribute
744 * the attno must always be set to 1.
747 if (scanvar == LEFT_OP)
748 elog(WARN, "ExecInitIndexScan: %s",
749 "both left and right ops are rel-vars");
756 * otherwise, the leftop contains information usable
757 * at runtime to figure out the value to place in our
761 have_runtime_keys = true;
762 run_keys[ j ] = RIGHT_OP;
763 scanvalue = Int32GetDatum((int32) true);
767 * now check that at least one op tells us the scan
771 if (scanvar == NO_OP)
772 elog(WARN, "ExecInitIndexScan: %s",
773 "neither leftop nor rightop refer to scan relation");
776 * initialize the scan key's fields appropriately
779 ScanKeyEntryInitialize(&scan_keys[j],
781 varattno, /* attribute number to scan */
782 (RegProcedure) opid, /* reg proc to use */
783 (Datum) scanvalue); /* constant */
787 * store the key information into our array.
790 numScanKeys[ i ] = n_keys;
791 scanKeys[ i ] = scan_keys;
792 runtimeKeyInfo[ i ] = (Pointer) run_keys;
795 indexstate->iss_NumIndices = numIndices;
796 indexstate->iss_IndexPtr = indexPtr;
797 indexstate->iss_ScanKeys = scanKeys;
798 indexstate->iss_NumScanKeys = numScanKeys;
801 * If all of our keys have the form (op var const) , then we have no
802 * runtime keys so we store NULL in the runtime key info.
803 * Otherwise runtime key info contains an array of pointers
804 * (one for each index) to arrays of flags (one for each key)
805 * which indicate that the qual needs to be evaluated at runtime.
809 if (have_runtime_keys)
811 indexstate->iss_RuntimeKeyInfo = (Pointer) runtimeKeyInfo;
814 indexstate->iss_RuntimeKeyInfo = NULL;
815 for (i=0; i < numIndices; i++) {
818 qual = nth(i, indxqual);
819 n_keys = length(qual);
821 pfree(runtimeKeyInfo[i]);
823 pfree(runtimeKeyInfo);
827 * get the range table and direction information
828 * from the execution state (these are needed to
829 * open the relations).
832 rangeTable = estate->es_range_table;
833 direction = estate->es_direction;
836 * open the base relation
839 relid = node->scan.scanrelid;
840 rtentry = rt_fetch(relid, rangeTable);
841 reloid = rtentry->relid;
842 timeQual = rtentry->timeQual;
844 ExecOpenScanR(reloid, /* relation */
846 (ScanKey) NULL, /* scan key */
848 direction, /* scan direction */
849 timeQual, /* time qual */
850 ¤tRelation, /* return: rel desc */
851 (Pointer *) ¤tScanDesc); /* return: scan desc */
853 scanstate->css_currentRelation = currentRelation;
854 scanstate->css_currentScanDesc = currentScanDesc;
858 * get the scan type from the relation descriptor.
861 ExecAssignScanType(scanstate, RelationGetTupleDescriptor(currentRelation));
862 ExecAssignResultTypeFromTL((Plan *) node, &scanstate->cstate);
865 * index scans don't have subtrees..
868 /* scanstate->ss_ProcOuterFlag = false; */
871 * open the index relations and initialize
872 * relation and scan descriptors.
875 for (i=0; i < numIndices; i++) {
878 indexOid = (Oid)nth(i, indxid);
881 ExecOpenScanR(indexOid, /* relation */
882 numScanKeys[ i ], /* nkeys */
883 scanKeys[ i ], /* scan key */
885 direction, /* scan direction */
886 timeQual, /* time qual */
887 &(relationDescs[ i ]), /* return: rel desc */
888 (Pointer *) &(scanDescs[ i ]));
889 /* return: scan desc */
893 indexstate->iss_RelationDescs = relationDescs;
894 indexstate->iss_ScanDescs = scanDescs;
896 indexstate->cstate.cs_TupFromTlist = false;
906 ExecCountSlotsIndexScan(IndexScan *node)
908 return ExecCountSlotsNode(outerPlan((Plan *)node)) +
909 ExecCountSlotsNode(innerPlan((Plan *)node)) +