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.18 1998/06/15 19:28:22 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;
99 * extract necessary information from index scan node
102 estate = node->scan.plan.state;
103 direction = estate->es_direction;
104 scanstate = node->scan.scanstate;
105 indexstate = node->indxstate;
106 indexPtr = indexstate->iss_IndexPtr;
107 scanDescs = indexstate->iss_ScanDescs;
108 scandesc = scanDescs[indexPtr];
109 heapRelation = scanstate->css_currentRelation;
111 slot = scanstate->css_ScanTupleSlot;
114 * ok, now that we have what we need, fetch an index tuple.
119 * if scanning this index succeeded then return the
120 * appropriate heap tuple.. else return NULL.
123 while ((result = index_getnext(scandesc, direction)) != NULL)
125 tuple = heap_fetch(heapRelation, false, &result->heap_iptr, &buffer);
132 * store the scanned tuple in the scan tuple slot of
133 * the scan state. Eventually we will only do this and not
134 * return a tuple. Note: we pass 'false' because tuples
135 * returned by amgetnext are pointers onto disk pages and
136 * were not created with palloc() and so should not be pfree()'d.
139 ExecStoreTuple(tuple, /* tuple to store */
140 slot, /* slot to store in */
141 buffer, /* buffer associated with tuple */
142 false); /* don't pfree */
148 if (BufferIsValid(buffer))
149 ReleaseBuffer(buffer);
154 * if we get here it means the index scan failed so we
155 * are at the end of the scan..
158 return ExecClearTuple(slot);
161 /* ----------------------------------------------------------------
162 * ExecIndexScan(node)
165 * Scans the relation using primary or secondary indices and returns
166 * the next qualifying tuple in the direction specified.
167 * It calls ExecScan() and passes it the access methods which returns
168 * the next tuple using the indices.
171 * -- the "cursor" maintained by the AMI is positioned at the tuple
172 * returned previously.
175 * -- the relation indicated is opened for scanning so that the
176 * "cursor" is positioned before the first qualifying tuple.
177 * -- all index realtions are opened for scanning.
178 * -- indexPtr points to the first index.
179 * -- state variable ruleFlag = nil.
180 * ----------------------------------------------------------------
183 ExecIndexScan(IndexScan *node)
186 * use IndexNext as access method
189 return ExecScan(&node->scan, IndexNext);
192 /* ----------------------------------------------------------------
193 * ExecIndexReScan(node)
195 * Recalculates the value of the scan keys whose value depends on
196 * information known at runtime and rescans the indexed relation.
197 * Updating the scan key was formerly done separately in
198 * ExecUpdateIndexScanKeys. Integrating it into ReScan
199 * makes rescans of indices and
200 * relations/general streams more uniform.
202 * ----------------------------------------------------------------
205 ExecIndexReScan(IndexScan *node, ExprContext *exprCtxt, Plan *parent)
208 IndexScanState *indexstate;
209 ScanDirection direction;
210 IndexScanDescPtr scanDescs;
217 Pointer *runtimeKeyInfo;
232 indexstate = node->indxstate;
233 estate = node->scan.plan.state;
234 direction = estate->es_direction;
235 numIndices = indexstate->iss_NumIndices;
236 scanDescs = indexstate->iss_ScanDescs;
237 scanKeys = indexstate->iss_ScanKeys;
239 runtimeKeyInfo = (Pointer *) indexstate->iss_RuntimeKeyInfo;
241 if (runtimeKeyInfo != NULL)
245 * get the index qualifications and recalculate the appropriate
248 indexPtr = indexstate->iss_IndexPtr;
249 indxqual = node->indxqual;
250 qual = nth(indexPtr, indxqual);
251 numScanKeys = indexstate->iss_NumScanKeys;
252 n_keys = numScanKeys[indexPtr];
253 run_keys = (int *) runtimeKeyInfo[indexPtr];
254 scan_keys = (ScanKey) scanKeys[indexPtr];
256 /* it's possible in subselects */
257 if (exprCtxt == NULL)
258 exprCtxt = node->scan.scanstate->cstate.cs_ExprContext;
260 for (j = 0; j < n_keys; j++)
264 * If we have a run-time key, then extract the run-time
265 * expression and evaluate it with respect to the current
266 * outer tuple. We then stick the result into the scan key.
268 if (run_keys[j] != NO_OP)
270 clause = nth(j, qual);
271 scanexpr = (run_keys[j] == RIGHT_OP) ?
272 (Node *) get_rightop(clause) : (Node *) get_leftop(clause);
275 * pass in isDone but ignore it. We don't iterate in
279 ExecEvalExpr(scanexpr, exprCtxt, &isNull, &isDone);
280 scan_keys[j].sk_argument = scanvalue;
282 scan_keys[j].sk_flags |= SK_ISNULL;
284 scan_keys[j].sk_flags &= ~SK_ISNULL;
290 * rescans all indices
292 * note: AMrescan assumes only one scan key. This may have to change if
293 * we ever decide to support multiple keys.
295 for (i = 0; i < numIndices; i++)
297 sdesc = scanDescs[i];
299 index_rescan(sdesc, direction, skey);
303 * perhaps return something meaningful
309 /* ----------------------------------------------------------------
313 * Releases any storage allocated through C routines.
315 * ----------------------------------------------------------------
318 ExecEndIndexScan(IndexScan *node)
320 CommonScanState *scanstate;
321 IndexScanState *indexstate;
326 scanstate = node->scan.scanstate;
327 indexstate = node->indxstate;
330 * extract information from the node
333 numIndices = indexstate->iss_NumIndices;
334 scanKeys = indexstate->iss_ScanKeys;
337 * Free the projection info and the scan attribute info
339 * Note: we don't ExecFreeResultType(scanstate)
340 * because the rule manager depends on the tupType
341 * returned by ExecMain(). So for now, this
342 * is freed at end-transaction time. -cim 6/2/91
345 ExecFreeProjectionInfo(&scanstate->cstate);
348 * close the heap and index relations
351 ExecCloseR((Plan *) node);
354 * free the scan keys used in scanning the indices
357 for (i = 0; i < numIndices; i++)
359 if (scanKeys[i] != NULL)
364 * clear out tuple table slots
367 ExecClearTuple(scanstate->cstate.cs_ResultTupleSlot);
368 ExecClearTuple(scanstate->css_ScanTupleSlot);
369 /* ExecClearTuple(scanstate->css_RawTupleSlot); */
372 /* ----------------------------------------------------------------
376 * Marks scan position by marking the current index.
378 * ----------------------------------------------------------------
381 ExecIndexMarkPos(IndexScan *node)
383 IndexScanState *indexstate;
384 IndexScanDescPtr indexScanDescs;
385 IndexScanDesc scanDesc;
388 indexstate = node->indxstate;
389 indexPtr = indexstate->iss_IndexPtr;
390 indexScanDescs = indexstate->iss_ScanDescs;
391 scanDesc = indexScanDescs[indexPtr];
394 IndexScanMarkPosition(scanDesc);
396 index_markpos (scanDesc);
399 /* ----------------------------------------------------------------
403 * Restores scan position by restoring the current index.
406 * XXX Assumes previously marked scan position belongs to current index
407 * ----------------------------------------------------------------
410 ExecIndexRestrPos(IndexScan *node)
412 IndexScanState *indexstate;
413 IndexScanDescPtr indexScanDescs;
414 IndexScanDesc scanDesc;
417 indexstate = node->indxstate;
418 indexPtr = indexstate->iss_IndexPtr;
419 indexScanDescs = indexstate->iss_ScanDescs;
420 scanDesc = indexScanDescs[indexPtr];
423 IndexScanRestorePosition(scanDesc);
425 index_restrpos (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;
468 Relation currentRelation;
469 HeapScanDesc currentScanDesc;
470 ScanDirection direction;
473 List *execParam = NULL;
476 * assign execution state to node
479 node->scan.plan.state = estate;
481 /* --------------------------------
482 * Part 1) initialize scan state
484 * create new CommonScanState for node
485 * --------------------------------
487 scanstate = makeNode(CommonScanState);
489 scanstate->ss_ProcOuterFlag = false;
490 scanstate->ss_OldRelId = 0;
493 node->scan.scanstate = scanstate;
496 * assign node's base_id .. we don't use AssignNodeBaseid() because
497 * the increment is done later on after we assign the index scan's
498 * scanstate. see below.
501 baseid = estate->es_BaseId;
502 /* scanstate->csstate.cstate.bnode.base_id = baseid; */
503 scanstate->cstate.cs_base_id = baseid;
506 * create expression context for node
509 ExecAssignExprContext(estate, &scanstate->cstate);
511 #define INDEXSCAN_NSLOTS 3
513 * tuple table initialization
516 ExecInitResultTupleSlot(estate, &scanstate->cstate);
517 ExecInitScanTupleSlot(estate, scanstate);
518 /* ExecInitRawTupleSlot(estate, scanstate); */
521 * initialize projection info. result type comes from scan desc
525 ExecAssignProjectionInfo((Plan *) node, &scanstate->cstate);
527 /* --------------------------------
528 * Part 2) initialize index scan state
530 * create new IndexScanState for node
531 * --------------------------------
533 indexstate = makeNode(IndexScanState);
534 indexstate->iss_NumIndices = 0;
535 indexstate->iss_IndexPtr = 0;
536 indexstate->iss_ScanKeys = NULL;
537 indexstate->iss_NumScanKeys = NULL;
538 indexstate->iss_RuntimeKeyInfo = NULL;
539 indexstate->iss_RelationDescs = NULL;
540 indexstate->iss_ScanDescs = NULL;
542 node->indxstate = indexstate;
545 * assign base id to index scan state also
548 indexstate->cstate.cs_base_id = baseid;
550 estate->es_BaseId = baseid;
553 * get the index node information
556 indxid = node->indxid;
557 indxqual = node->indxqual;
558 numIndices = length(indxid);
561 CXT1_printf("ExecInitIndexScan: context is %d\n", CurrentMemoryContext);
564 * scanKeys is used to keep track of the ScanKey's. This is needed
565 * because a single scan may use several indices and each index has
569 numScanKeys = (int *) palloc(numIndices * sizeof(int));
570 scanKeys = (ScanKey *) palloc(numIndices * sizeof(ScanKey));
571 relationDescs = (RelationPtr) palloc(numIndices * sizeof(Relation));
572 scanDescs = (IndexScanDescPtr) palloc(numIndices * sizeof(IndexScanDesc));
575 * initialize runtime key info.
578 have_runtime_keys = false;
579 runtimeKeyInfo = (Pointer *)
580 palloc(numIndices * sizeof(Pointer));
583 * build the index scan keys from the index qualification
586 for (i = 0; i < numIndices; i++)
594 qual = nth(i, indxqual);
595 n_keys = length(qual);
596 scan_keys = (n_keys <= 0) ? NULL :
597 (ScanKey) palloc(n_keys * sizeof(ScanKeyData));
598 run_keys = (n_keys <= 0) ? NULL :
599 (int *) palloc(n_keys * sizeof(int));
601 CXT1_printf("ExecInitIndexScan: context is %d\n",
602 CurrentMemoryContext);
605 * for each opclause in the given qual,
606 * convert each qual's opclause into a single scan key
609 for (j = 0; j < n_keys; j++)
611 Expr *clause; /* one part of index qual */
612 Oper *op; /* operator used in scan.. */
613 Node *leftop; /* expr on lhs of operator */
614 Node *rightop;/* expr on rhs ... */
617 int scanvar;/* which var identifies varattno */
618 AttrNumber varattno = 0; /* att number used in scan */
619 Oid opid; /* operator id used in scan */
620 Datum scanvalue = 0; /* value used in scan (if const) */
623 * extract clause information from the qualification
626 clause = nth(j, qual);
628 op = (Oper *) clause->oper;
630 elog(ERROR, "ExecInitIndexScan: op not an Oper!");
635 * Here we figure out the contents of the index qual.
636 * The usual case is (op var const) or (op const var)
637 * which means we form a scan key for the attribute
638 * listed in the var node and use the value of the const.
640 * If we don't have a const node, then it means that
641 * one of the var nodes refers to the "scan" tuple and
642 * is used to determine which attribute to scan, and the
643 * other expression is used to calculate the value used in
644 * scanning the index.
646 * This means our index scan's scan key is a function of
647 * information obtained during the execution of the plan
648 * in which case we need to recalculate the index scan key
651 * Hence, we set have_runtime_keys to true and then set
652 * the appropriate flag in run_keys to LEFT_OP or RIGHT_OP.
653 * The corresponding scan keys are recomputed at run time.
660 * determine information in leftop
663 leftop = (Node *) get_leftop(clause);
665 if (IsA(leftop, Var) &&var_is_rel((Var *) leftop))
668 * if the leftop is a "rel-var", then it means
669 * that it is a var node which tells us which
670 * attribute to use for our scan key.
673 varattno = ((Var *) leftop)->varattno;
676 else if (IsA(leftop, Const))
679 * if the leftop is a const node then it means
680 * it identifies the value to place in our scan key.
684 scanvalue = ((Const *) leftop)->constvalue;
686 else if (IsA(leftop, Param))
691 * if the leftop is a Param node then it means
692 * it identifies the value to place in our scan key.
696 /* Life was so easy before ... subselects */
697 if ( ((Param *) leftop)->paramkind == PARAM_EXEC )
699 have_runtime_keys = true;
700 run_keys[j] = LEFT_OP;
701 execParam = lappendi (execParam, ((Param*) leftop)->paramid);
705 scanvalue = ExecEvalParam((Param *) leftop,
706 scanstate->cstate.cs_ExprContext,
714 else if (leftop != NULL &&
715 is_funcclause(leftop) &&
716 var_is_rel(lfirst(((Expr *) leftop)->args)))
719 * if the leftop is a func node then it means
720 * it identifies the value to place in our scan key.
721 * Since functional indices have only one attribute
722 * the attno must always be set to 1.
732 * otherwise, the leftop contains information usable
733 * at runtime to figure out the value to place in our
737 have_runtime_keys = true;
738 run_keys[j] = LEFT_OP;
739 scanvalue = Int32GetDatum((int32) true);
743 * now determine information in rightop
746 rightop = (Node *) get_rightop(clause);
748 if (IsA(rightop, Var) &&var_is_rel((Var *) rightop))
751 * here we make sure only one op identifies the
755 if (scanvar == LEFT_OP)
756 elog(ERROR, "ExecInitIndexScan: %s",
757 "both left and right op's are rel-vars");
760 * if the rightop is a "rel-var", then it means
761 * that it is a var node which tells us which
762 * attribute to use for our scan key.
765 varattno = ((Var *) rightop)->varattno;
769 else if (IsA(rightop, Const))
772 * if the leftop is a const node then it means
773 * it identifies the value to place in our scan key.
777 scanvalue = ((Const *) rightop)->constvalue;
779 else if (IsA(rightop, Param))
784 * if the rightop is a Param node then it means
785 * it identifies the value to place in our scan key.
789 /* Life was so easy before ... subselects */
790 if ( ((Param *) rightop)->paramkind == PARAM_EXEC )
792 have_runtime_keys = true;
793 run_keys[j] = RIGHT_OP;
794 execParam = lappendi (execParam, ((Param*) rightop)->paramid);
798 scanvalue = ExecEvalParam((Param *) rightop,
799 scanstate->cstate.cs_ExprContext,
807 else if (rightop != NULL &&
808 is_funcclause(rightop) &&
809 var_is_rel(lfirst(((Expr *) rightop)->args)))
812 * if the rightop is a func node then it means
813 * it identifies the value to place in our scan key.
814 * Since functional indices have only one attribute
815 * the attno must always be set to 1.
818 if (scanvar == LEFT_OP)
819 elog(ERROR, "ExecInitIndexScan: %s",
820 "both left and right ops are rel-vars");
829 * otherwise, the leftop contains information usable
830 * at runtime to figure out the value to place in our
834 have_runtime_keys = true;
835 run_keys[j] = RIGHT_OP;
836 scanvalue = Int32GetDatum((int32) true);
840 * now check that at least one op tells us the scan
844 if (scanvar == NO_OP)
845 elog(ERROR, "ExecInitIndexScan: %s",
846 "neither leftop nor rightop refer to scan relation");
849 * initialize the scan key's fields appropriately
852 ScanKeyEntryInitialize(&scan_keys[j],
854 varattno, /* attribute number to
856 (RegProcedure) opid, /* reg proc to use */
857 (Datum) scanvalue); /* constant */
861 * store the key information into our array.
864 numScanKeys[i] = n_keys;
865 scanKeys[i] = scan_keys;
866 runtimeKeyInfo[i] = (Pointer) run_keys;
869 indexstate->iss_NumIndices = numIndices;
870 indexstate->iss_IndexPtr = indexPtr;
871 indexstate->iss_ScanKeys = scanKeys;
872 indexstate->iss_NumScanKeys = numScanKeys;
875 * If all of our keys have the form (op var const) , then we have no
876 * runtime keys so we store NULL in the runtime key info.
877 * Otherwise runtime key info contains an array of pointers
878 * (one for each index) to arrays of flags (one for each key)
879 * which indicate that the qual needs to be evaluated at runtime.
883 if (have_runtime_keys)
884 indexstate->iss_RuntimeKeyInfo = (Pointer) runtimeKeyInfo;
887 indexstate->iss_RuntimeKeyInfo = NULL;
888 for (i = 0; i < numIndices; i++)
893 qual = nth(i, indxqual);
894 n_keys = length(qual);
896 pfree(runtimeKeyInfo[i]);
898 pfree(runtimeKeyInfo);
902 * get the range table and direction information
903 * from the execution state (these are needed to
904 * open the relations).
907 rangeTable = estate->es_range_table;
908 direction = estate->es_direction;
911 * open the base relation
914 relid = node->scan.scanrelid;
915 rtentry = rt_fetch(relid, rangeTable);
916 reloid = rtentry->relid;
918 ExecOpenScanR(reloid, /* relation */
920 (ScanKey) NULL, /* scan key */
922 direction, /* scan direction */
923 ¤tRelation, /* return: rel desc */
924 (Pointer *) ¤tScanDesc); /* return: scan desc */
926 scanstate->css_currentRelation = currentRelation;
927 scanstate->css_currentScanDesc = currentScanDesc;
931 * get the scan type from the relation descriptor.
934 ExecAssignScanType(scanstate, RelationGetTupleDescriptor(currentRelation));
935 ExecAssignResultTypeFromTL((Plan *) node, &scanstate->cstate);
938 * index scans don't have subtrees..
941 /* scanstate->ss_ProcOuterFlag = false; */
944 * open the index relations and initialize
945 * relation and scan descriptors.
948 for (i = 0; i < numIndices; i++)
952 indexOid = (Oid) nthi(i, indxid);
956 ExecOpenScanR(indexOid, /* relation */
957 numScanKeys[i], /* nkeys */
958 scanKeys[i], /* scan key */
960 direction, /* scan direction */
961 &(relationDescs[i]), /* return: rel desc */
962 (Pointer *) &(scanDescs[i]));
963 /* return: scan desc */
967 indexstate->iss_RelationDescs = relationDescs;
968 indexstate->iss_ScanDescs = scanDescs;
970 indexstate->cstate.cs_TupFromTlist = false;
973 * if there are some PARAM_EXEC in skankeys then
974 * force index rescan on first scan.
976 ((Plan*) node)->chgParam = execParam;
986 ExecCountSlotsIndexScan(IndexScan *node)
988 return ExecCountSlotsNode(outerPlan((Plan *) node)) +
989 ExecCountSlotsNode(innerPlan((Plan *) node)) +