1 /*-------------------------------------------------------------------------
4 * Routines to support indexes and indexed scans of relations
6 * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
11 * $Header: /cvsroot/pgsql/src/backend/executor/nodeIndexscan.c,v 1.85 2003/11/09 21:30:36 tgl Exp $
13 *-------------------------------------------------------------------------
17 * ExecIndexScan scans a relation using indices
18 * ExecIndexNext using index to retrieve next tuple
19 * ExecInitIndexScan creates and initializes state info.
20 * ExecIndexReScan rescans the indexed relation.
21 * ExecEndIndexScan releases all storage.
22 * ExecIndexMarkPos marks scan position.
23 * ExecIndexRestrPos restores scan position.
27 #include "access/genam.h"
28 #include "access/heapam.h"
29 #include "executor/execdebug.h"
30 #include "executor/nodeIndexscan.h"
31 #include "miscadmin.h"
32 #include "nodes/nodeFuncs.h"
33 #include "optimizer/clauses.h"
34 #include "parser/parse_expr.h"
35 #include "parser/parsetree.h"
39 * In a multiple-index plan, we must take care to return any given tuple
40 * only once, even if it matches conditions of several index scans. Our
41 * preferred way to do this is to record already-returned tuples in a hash
42 * table (using the TID as unique identifier). However, in a very large
43 * scan this could conceivably run out of memory. We limit the hash table
44 * to no more than SortMem KB; if it grows past that, we fall back to the
45 * pre-7.4 technique: evaluate the prior-scan index quals again for each
46 * tuple (which is space-efficient, but slow).
48 * When scanning backwards, we use scannum to determine when to emit the
49 * tuple --- we have to re-emit a tuple in the same scan as it was first
52 * Note: this code would break if the planner were ever to create a multiple
53 * index plan with overall backwards direction, because the hashtable code
54 * will emit a tuple the first time it is encountered (which would be the
55 * highest scan in which it matches the index), but the evaluate-the-quals
56 * code will emit a tuple in the lowest-numbered scan in which it's valid.
57 * This could be fixed at need by making the evaluate-the-quals case more
58 * complex. Currently the planner will never create such a plan (since it
59 * considers multi-index plans unordered anyway), so there's no need for
64 /* tid is the hash key and so must be first! */
65 ItemPointerData tid; /* TID of a tuple we've returned */
66 int scannum; /* number of scan we returned it in */
70 static TupleTableSlot *IndexNext(IndexScanState *node);
71 static void create_duphash(IndexScanState *node);
74 /* ----------------------------------------------------------------
77 * Retrieve a tuple from the IndexScan node's currentRelation
78 * using the indices in the IndexScanState information.
80 * note: the old code mentions 'Primary indices'. to my knowledge
81 * we only support a single secondary index. -cim 9/11/89
84 * retrieve a tuple from relation using the indices given.
85 * The indices are used in the order they appear in 'indices'.
86 * The indices may be primary or secondary indices:
87 * * primary index -- scan the relation 'relID' using keys supplied.
88 * * secondary index -- scan the index relation to get the 'tid' for
89 * a tuple in the relation 'relID'.
90 * If the current index(pointed by 'indexPtr') fails to return a
91 * tuple, the next index in the indices is used.
93 * bug fix so that it should retrieve on a null scan key.
94 * ----------------------------------------------------------------
96 static TupleTableSlot *
97 IndexNext(IndexScanState *node)
100 ExprContext *econtext;
101 ScanDirection direction;
102 IndexScanDescPtr scanDescs;
103 IndexScanDesc scandesc;
106 TupleTableSlot *slot;
112 * extract necessary information from index scan node
114 estate = node->ss.ps.state;
115 direction = estate->es_direction;
116 if (ScanDirectionIsBackward(((IndexScan *) node->ss.ps.plan)->indxorderdir))
118 if (ScanDirectionIsForward(direction))
119 direction = BackwardScanDirection;
120 else if (ScanDirectionIsBackward(direction))
121 direction = ForwardScanDirection;
123 scanDescs = node->iss_ScanDescs;
124 numIndices = node->iss_NumIndices;
125 econtext = node->ss.ps.ps_ExprContext;
126 slot = node->ss.ss_ScanTupleSlot;
127 scanrelid = ((IndexScan *) node->ss.ps.plan)->scan.scanrelid;
130 * Check if we are evaluating PlanQual for tuple of this relation.
131 * Additional checking is not good, but no other way for now. We could
132 * introduce new nodes for this case and handle IndexScan --> NewNode
133 * switching in Init/ReScan plan...
135 if (estate->es_evTuple != NULL &&
136 estate->es_evTuple[scanrelid - 1] != NULL)
140 ExecClearTuple(slot);
141 if (estate->es_evTupleNull[scanrelid - 1])
142 return slot; /* return empty slot */
144 ExecStoreTuple(estate->es_evTuple[scanrelid - 1],
145 slot, InvalidBuffer, false);
147 /* Does the tuple meet any of the OR'd indxqual conditions? */
148 econtext->ecxt_scantuple = slot;
150 ResetExprContext(econtext);
152 foreach(qual, node->indxqualorig)
154 if (ExecQual((List *) lfirst(qual), econtext, false))
157 if (qual == NIL) /* would not be returned by indices */
160 /* Flag for the next call that no more tuples */
161 estate->es_evTupleNull[scanrelid - 1] = true;
167 * ok, now that we have what we need, fetch an index tuple. if
168 * scanning this index succeeded then return the appropriate heap
169 * tuple.. else return NULL.
171 bBackward = ScanDirectionIsBackward(direction);
174 indexNumber = numIndices - node->iss_IndexPtr - 1;
178 node->iss_IndexPtr = numIndices - 1;
183 if ((indexNumber = node->iss_IndexPtr) < 0)
186 node->iss_IndexPtr = 0;
189 while (indexNumber < numIndices)
191 scandesc = scanDescs[node->iss_IndexPtr];
192 while ((tuple = index_getnext(scandesc, direction)) != NULL)
195 * Store the scanned tuple in the scan tuple slot of the scan
196 * state. Note: we pass 'false' because tuples returned by
197 * amgetnext are pointers onto disk pages and must not be
200 ExecStoreTuple(tuple, /* tuple to store */
201 slot, /* slot to store in */
202 scandesc->xs_cbuf, /* buffer containing tuple */
203 false); /* don't pfree */
206 * If it's a multiple-index scan, make sure not to double-report
207 * a tuple matched by more than one index. (See notes above.)
211 /* First try the hash table */
212 if (node->iss_DupHash)
214 DupHashTabEntry *entry;
217 entry = (DupHashTabEntry *)
218 hash_search(node->iss_DupHash,
219 &tuple->t_data->t_ctid,
223 node->iss_DupHash->hctl->nentries > node->iss_MaxHash)
225 /* out of memory (either hard or soft limit) */
226 /* release hash table and fall thru to old code */
227 hash_destroy(node->iss_DupHash);
228 node->iss_DupHash = NULL;
232 /* pre-existing entry */
235 * It's duplicate if first emitted in a different
236 * scan. If same scan, we must be backing up, so
237 * okay to emit again.
239 if (entry->scannum != node->iss_IndexPtr)
241 /* Dup, so drop it and loop back for another */
242 ExecClearTuple(slot);
248 /* new entry, finish filling it in */
249 entry->scannum = node->iss_IndexPtr;
252 /* If hash table has overflowed, do it the hard way */
253 if (node->iss_DupHash == NULL &&
254 node->iss_IndexPtr > 0)
256 bool prev_matches = false;
260 econtext->ecxt_scantuple = slot;
261 ResetExprContext(econtext);
262 qual = node->indxqualorig;
264 prev_index < node->iss_IndexPtr;
267 if (ExecQual((List *) lfirst(qual), econtext, false))
276 /* Dup, so drop it and loop back for another */
277 ExecClearTuple(slot);
283 return slot; /* OK to return tuple */
286 if (indexNumber < numIndices)
290 node->iss_IndexPtr--;
292 node->iss_IndexPtr++;
297 * if we get here it means the index scan failed so we are at the end
300 return ExecClearTuple(slot);
303 /* ----------------------------------------------------------------
304 * ExecIndexScan(node)
307 * Scans the relation using primary or secondary indices and returns
308 * the next qualifying tuple in the direction specified.
309 * It calls ExecScan() and passes it the access methods which returns
310 * the next tuple using the indices.
313 * -- the "cursor" maintained by the AMI is positioned at the tuple
314 * returned previously.
317 * -- the relation indicated is opened for scanning so that the
318 * "cursor" is positioned before the first qualifying tuple.
319 * -- all index realtions are opened for scanning.
320 * -- indexPtr points to the first index.
321 * -- state variable ruleFlag = nil.
322 * ----------------------------------------------------------------
325 ExecIndexScan(IndexScanState *node)
328 * If we have runtime keys and they've not already been set up, do it
331 if (node->iss_RuntimeKeyInfo && !node->iss_RuntimeKeysReady)
332 ExecReScan((PlanState *) node, NULL);
335 * use IndexNext as access method
337 return ExecScan(&node->ss, (ExecScanAccessMtd) IndexNext);
340 /* ----------------------------------------------------------------
341 * ExecIndexReScan(node)
343 * Recalculates the value of the scan keys whose value depends on
344 * information known at runtime and rescans the indexed relation.
345 * Updating the scan key was formerly done separately in
346 * ExecUpdateIndexScanKeys. Integrating it into ReScan makes
347 * rescans of indices and relations/general streams more uniform.
349 * ----------------------------------------------------------------
352 ExecIndexReScan(IndexScanState *node, ExprContext *exprCtxt)
355 ExprContext *econtext;
357 IndexScanDescPtr scanDescs;
359 ExprState ***runtimeKeyInfo;
365 estate = node->ss.ps.state;
366 econtext = node->iss_RuntimeContext; /* context for runtime
368 numIndices = node->iss_NumIndices;
369 scanDescs = node->iss_ScanDescs;
370 scanKeys = node->iss_ScanKeys;
371 runtimeKeyInfo = node->iss_RuntimeKeyInfo;
372 numScanKeys = node->iss_NumScanKeys;
373 scanrelid = ((IndexScan *) node->ss.ps.plan)->scan.scanrelid;
378 * If we are being passed an outer tuple, save it for runtime key
379 * calc. We also need to link it into the "regular" per-tuple
380 * econtext, so it can be used during indexqualorig evaluations.
382 if (exprCtxt != NULL)
384 ExprContext *stdecontext;
386 econtext->ecxt_outertuple = exprCtxt->ecxt_outertuple;
387 stdecontext = node->ss.ps.ps_ExprContext;
388 stdecontext->ecxt_outertuple = exprCtxt->ecxt_outertuple;
392 * Reset the runtime-key context so we don't leak memory as each
393 * outer tuple is scanned. Note this assumes that we will
394 * recalculate *all* runtime keys on each call.
396 ResetExprContext(econtext);
400 * If we are doing runtime key calculations (ie, the index keys depend
401 * on data from an outer scan), compute the new key values
405 for (i = 0; i < numIndices; i++)
409 ExprState **run_keys;
411 n_keys = numScanKeys[i];
412 scan_keys = scanKeys[i];
413 run_keys = runtimeKeyInfo[i];
415 for (j = 0; j < n_keys; j++)
418 * If we have a run-time key, then extract the run-time
419 * expression and evaluate it with respect to the current
420 * outer tuple. We then stick the result into the scan
423 * Note: the result of the eval could be a pass-by-ref value
424 * that's stored in the outer scan's tuple, not in
425 * econtext->ecxt_per_tuple_memory. We assume that the
426 * outer tuple will stay put throughout our scan. If this
427 * is wrong, we could copy the result into our context
428 * explicitly, but I think that's not necessary...
430 if (run_keys[j] != NULL)
435 scanvalue = ExecEvalExprSwitchContext(run_keys[j],
439 scan_keys[j].sk_argument = scanvalue;
441 scan_keys[j].sk_flags |= SK_ISNULL;
443 scan_keys[j].sk_flags &= ~SK_ISNULL;
448 node->iss_RuntimeKeysReady = true;
451 /* If this is re-scanning of PlanQual ... */
452 if (estate->es_evTuple != NULL &&
453 estate->es_evTuple[scanrelid - 1] != NULL)
455 estate->es_evTupleNull[scanrelid - 1] = false;
459 /* reset hash table */
462 if (node->iss_DupHash)
463 hash_destroy(node->iss_DupHash);
464 create_duphash(node);
467 /* reset index scans */
468 if (ScanDirectionIsBackward(((IndexScan *) node->ss.ps.plan)->indxorderdir))
469 node->iss_IndexPtr = numIndices;
471 node->iss_IndexPtr = -1;
473 for (i = 0; i < numIndices; i++)
475 IndexScanDesc scan = scanDescs[i];
476 ScanKey skey = scanKeys[i];
478 index_rescan(scan, skey);
482 /* ----------------------------------------------------------------
484 * ----------------------------------------------------------------
487 ExecEndIndexScan(IndexScanState *node)
490 RelationPtr indexRelationDescs;
491 IndexScanDescPtr indexScanDescs;
496 * extract information from the node
498 numIndices = node->iss_NumIndices;
499 indexRelationDescs = node->iss_RelationDescs;
500 indexScanDescs = node->iss_ScanDescs;
501 relation = node->ss.ss_currentRelation;
504 * Free the exprcontext(s)
506 ExecFreeExprContext(&node->ss.ps);
507 if (node->iss_RuntimeContext)
508 FreeExprContext(node->iss_RuntimeContext);
511 * clear out tuple table slots
513 ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
514 ExecClearTuple(node->ss.ss_ScanTupleSlot);
516 /* drop hash table */
517 if (node->iss_DupHash)
518 hash_destroy(node->iss_DupHash);
521 * close the index relations
523 for (i = 0; i < numIndices; i++)
525 if (indexScanDescs[i] != NULL)
526 index_endscan(indexScanDescs[i]);
528 if (indexRelationDescs[i] != NULL)
529 index_close(indexRelationDescs[i]);
533 * close the heap relation.
535 * Currently, we do not release the AccessShareLock acquired by
536 * ExecInitIndexScan. This lock should be held till end of
537 * transaction. (There is a faction that considers this too much
540 heap_close(relation, NoLock);
543 /* ----------------------------------------------------------------
547 * Marks scan position by marking the current index.
549 * ----------------------------------------------------------------
552 ExecIndexMarkPos(IndexScanState *node)
554 IndexScanDescPtr indexScanDescs;
555 IndexScanDesc scanDesc;
558 indexPtr = node->iss_MarkIndexPtr = node->iss_IndexPtr;
559 if (indexPtr >= 0 && indexPtr < node->iss_NumIndices)
561 indexScanDescs = node->iss_ScanDescs;
562 scanDesc = indexScanDescs[indexPtr];
564 index_markpos(scanDesc);
568 /* ----------------------------------------------------------------
572 * Restores scan position by restoring the current index.
574 * ----------------------------------------------------------------
577 ExecIndexRestrPos(IndexScanState *node)
579 IndexScanDescPtr indexScanDescs;
580 IndexScanDesc scanDesc;
583 indexPtr = node->iss_IndexPtr = node->iss_MarkIndexPtr;
584 if (indexPtr >= 0 && indexPtr < node->iss_NumIndices)
586 indexScanDescs = node->iss_ScanDescs;
587 scanDesc = indexScanDescs[indexPtr];
589 index_restrpos(scanDesc);
593 /* ----------------------------------------------------------------
596 * Initializes the index scan's state information, creates
597 * scan keys, and opens the base and index relations.
599 * Note: index scans have 2 sets of state information because
600 * we have to keep track of the base relation and the
604 * Creates the run-time state information for the node and
605 * sets the relation id to contain relevant descriptors.
608 * node: IndexNode node produced by the planner.
609 * estate: the execution state initialized in InitPlan.
610 * ----------------------------------------------------------------
613 ExecInitIndexScan(IndexScan *node, EState *estate)
615 IndexScanState *indexstate;
624 RelationPtr indexDescs;
625 IndexScanDescPtr scanDescs;
626 ExprState ***runtimeKeyInfo;
627 bool have_runtime_keys;
628 RangeTblEntry *rtentry;
631 Relation currentRelation;
634 * create state structure
636 indexstate = makeNode(IndexScanState);
637 indexstate->ss.ps.plan = (Plan *) node;
638 indexstate->ss.ps.state = estate;
641 * Miscellaneous initialization
643 * create expression context for node
645 ExecAssignExprContext(estate, &indexstate->ss.ps);
648 * initialize child expressions
650 indexstate->ss.ps.targetlist = (List *)
651 ExecInitExpr((Expr *) node->scan.plan.targetlist,
652 (PlanState *) indexstate);
653 indexstate->ss.ps.qual = (List *)
654 ExecInitExpr((Expr *) node->scan.plan.qual,
655 (PlanState *) indexstate);
656 indexstate->indxqual = (List *)
657 ExecInitExpr((Expr *) node->indxqual,
658 (PlanState *) indexstate);
659 indexstate->indxqualorig = (List *)
660 ExecInitExpr((Expr *) node->indxqualorig,
661 (PlanState *) indexstate);
663 #define INDEXSCAN_NSLOTS 2
666 * tuple table initialization
668 ExecInitResultTupleSlot(estate, &indexstate->ss.ps);
669 ExecInitScanTupleSlot(estate, &indexstate->ss);
672 * Initialize index-specific scan state
674 indexstate->iss_NumIndices = 0;
675 indexstate->iss_IndexPtr = -1;
676 indexstate->iss_ScanKeys = NULL;
677 indexstate->iss_NumScanKeys = NULL;
678 indexstate->iss_RuntimeKeyInfo = NULL;
679 indexstate->iss_RuntimeContext = NULL;
680 indexstate->iss_RuntimeKeysReady = false;
681 indexstate->iss_RelationDescs = NULL;
682 indexstate->iss_ScanDescs = NULL;
685 * get the index node information
687 indxid = node->indxid;
688 numIndices = length(indxid);
691 CXT1_printf("ExecInitIndexScan: context is %d\n", CurrentMemoryContext);
694 * scanKeys is used to keep track of the ScanKey's. This is needed
695 * because a single scan may use several indices and each index has
698 numScanKeys = (int *) palloc(numIndices * sizeof(int));
699 scanKeys = (ScanKey *) palloc(numIndices * sizeof(ScanKey));
700 indexDescs = (RelationPtr) palloc(numIndices * sizeof(Relation));
701 scanDescs = (IndexScanDescPtr) palloc(numIndices * sizeof(IndexScanDesc));
704 * initialize space for runtime key info (may not be needed)
706 have_runtime_keys = false;
707 runtimeKeyInfo = (ExprState ***) palloc0(numIndices * sizeof(ExprState **));
710 * build the index scan keys from the index qualification
712 indxqual = node->indxqual;
713 indxstrategy = node->indxstrategy;
714 for (i = 0; i < numIndices; i++)
720 ExprState **run_keys;
723 quals = lfirst(indxqual);
724 indxqual = lnext(indxqual);
725 strategies = lfirst(indxstrategy);
726 indxstrategy = lnext(indxstrategy);
727 n_keys = length(quals);
728 scan_keys = (n_keys <= 0) ? (ScanKey) NULL :
729 (ScanKey) palloc(n_keys * sizeof(ScanKeyData));
730 run_keys = (n_keys <= 0) ? (ExprState **) NULL :
731 (ExprState **) palloc(n_keys * sizeof(ExprState *));
734 * for each opclause in the given qual, convert each qual's
735 * opclause into a single scan key
737 for (j = 0; j < n_keys; j++)
739 OpExpr *clause; /* one clause of index qual */
740 Expr *leftop; /* expr on lhs of operator */
741 Expr *rightop; /* expr on rhs ... */
743 AttrNumber varattno; /* att number used in scan */
744 StrategyNumber strategy; /* op's strategy number */
745 RegProcedure opfuncid; /* operator proc id used in scan */
746 Datum scanvalue; /* value used in scan (if const) */
747 Oid rhstype; /* datatype of comparison value */
750 * extract clause information from the qualification
752 clause = (OpExpr *) lfirst(quals);
753 quals = lnext(quals);
754 strategy = lfirsti(strategies);
755 strategies = lnext(strategies);
757 if (!IsA(clause, OpExpr))
758 elog(ERROR, "indxqual is not an OpExpr");
760 opfuncid = clause->opfuncid;
763 * Here we figure out the contents of the index qual. The
764 * usual case is (var op const) which means we form a scan key
765 * for the attribute listed in the var node and use the value of
766 * the const as comparison data.
768 * If we don't have a const node, it means our scan key is a
769 * function of information obtained during the execution of the
770 * plan, in which case we need to recalculate the index scan key
771 * at run time. Hence, we set have_runtime_keys to true and place
772 * the appropriate subexpression in run_keys. The corresponding
773 * scan key values are recomputed at run time.
778 * determine information in leftop
780 leftop = (Expr *) get_leftop((Expr *) clause);
782 if (leftop && IsA(leftop, RelabelType))
783 leftop = ((RelabelType *) leftop)->arg;
785 Assert(leftop != NULL);
787 if (!(IsA(leftop, Var) &&
788 var_is_rel((Var *) leftop)))
789 elog(ERROR, "indxqual doesn't have key on left side");
791 varattno = ((Var *) leftop)->varattno;
794 * now determine information in rightop
796 rightop = (Expr *) get_rightop((Expr *) clause);
798 rhstype = exprType((Node *) rightop);
800 if (rightop && IsA(rightop, RelabelType))
801 rightop = ((RelabelType *) rightop)->arg;
803 Assert(rightop != NULL);
805 if (IsA(rightop, Const))
808 * if the rightop is a const node then it means it
809 * identifies the value to place in our scan key.
811 scanvalue = ((Const *) rightop)->constvalue;
812 if (((Const *) rightop)->constisnull)
818 * otherwise, the rightop contains an expression evaluable
819 * at runtime to figure out the value to place in our scan
822 have_runtime_keys = true;
823 run_keys[j] = ExecInitExpr(rightop, (PlanState *) indexstate);
824 scanvalue = (Datum) 0;
828 * initialize the scan key's fields appropriately
830 ScanKeyEntryInitialize(&scan_keys[j],
832 varattno, /* attribute number to
834 strategy, /* op's strategy */
835 opfuncid, /* reg proc to use */
836 scanvalue, /* constant */
837 rhstype); /* constant's type */
841 * store the key information into our arrays.
843 numScanKeys[i] = n_keys;
844 scanKeys[i] = scan_keys;
845 runtimeKeyInfo[i] = run_keys;
848 indexstate->iss_NumIndices = numIndices;
849 if (ScanDirectionIsBackward(node->indxorderdir))
850 indexPtr = numIndices;
851 indexstate->iss_IndexPtr = indexPtr;
852 indexstate->iss_ScanKeys = scanKeys;
853 indexstate->iss_NumScanKeys = numScanKeys;
856 * If all of our keys have the form (var op const), then we have no
857 * runtime keys so we store NULL in the runtime key info. Otherwise
858 * runtime key info contains an array of pointers (one for each index)
859 * to arrays of flags (one for each key) which indicate that the qual
860 * needs to be evaluated at runtime. -cim 10/24/89
862 * If we do have runtime keys, we need an ExprContext to evaluate them;
863 * the node's standard context won't do because we want to reset that
864 * context for every tuple. So, build another context just like the
865 * other one... -tgl 7/11/00
867 if (have_runtime_keys)
869 ExprContext *stdecontext = indexstate->ss.ps.ps_ExprContext;
871 ExecAssignExprContext(estate, &indexstate->ss.ps);
872 indexstate->iss_RuntimeKeyInfo = runtimeKeyInfo;
873 indexstate->iss_RuntimeContext = indexstate->ss.ps.ps_ExprContext;
874 indexstate->ss.ps.ps_ExprContext = stdecontext;
878 indexstate->iss_RuntimeKeyInfo = NULL;
879 indexstate->iss_RuntimeContext = NULL;
880 /* Get rid of the speculatively-allocated flag arrays, too */
881 for (i = 0; i < numIndices; i++)
883 if (runtimeKeyInfo[i] != NULL)
884 pfree(runtimeKeyInfo[i]);
886 pfree(runtimeKeyInfo);
890 * open the base relation and acquire AccessShareLock on it.
892 relid = node->scan.scanrelid;
893 rtentry = rt_fetch(relid, estate->es_range_table);
894 reloid = rtentry->relid;
896 currentRelation = heap_open(reloid, AccessShareLock);
898 indexstate->ss.ss_currentRelation = currentRelation;
899 indexstate->ss.ss_currentScanDesc = NULL; /* no heap scan here */
902 * get the scan type from the relation descriptor.
904 ExecAssignScanType(&indexstate->ss, RelationGetDescr(currentRelation), false);
907 * open the index relations and initialize relation and scan
908 * descriptors. Note we acquire no locks here; the index machinery
909 * does its own locks and unlocks. (We rely on having AccessShareLock
910 * on the parent table to ensure the index won't go away!)
912 for (i = 0; i < numIndices; i++)
914 Oid indexOid = lfirsto(indxid);
916 indexDescs[i] = index_open(indexOid);
917 scanDescs[i] = index_beginscan(currentRelation,
922 indxid = lnext(indxid);
925 indexstate->iss_RelationDescs = indexDescs;
926 indexstate->iss_ScanDescs = scanDescs;
929 * Initialize result tuple type and projection info.
931 ExecAssignResultTypeFromTL(&indexstate->ss.ps);
932 ExecAssignScanProjectionInfo(&indexstate->ss);
935 * Initialize hash table if needed.
938 create_duphash(indexstate);
940 indexstate->iss_DupHash = NULL;
949 create_duphash(IndexScanState *node)
953 MemSet(&hash_ctl, 0, sizeof(hash_ctl));
954 hash_ctl.keysize = SizeOfIptrData;
955 hash_ctl.entrysize = sizeof(DupHashTabEntry);
956 hash_ctl.hash = tag_hash;
957 hash_ctl.hcxt = CurrentMemoryContext;
958 node->iss_DupHash = hash_create("DupHashTable",
959 (long) ceil(node->ss.ps.plan->plan_rows),
961 HASH_ELEM | HASH_FUNCTION | HASH_CONTEXT);
962 if (node->iss_DupHash == NULL)
964 (errcode(ERRCODE_OUT_OF_MEMORY),
965 errmsg("out of memory")));
966 node->iss_MaxHash = (SortMem * 1024L) /
967 (MAXALIGN(sizeof(HASHELEMENT)) + MAXALIGN(sizeof(DupHashTabEntry)));
971 ExecCountSlotsIndexScan(IndexScan *node)
973 return ExecCountSlotsNode(outerPlan((Plan *) node)) +
974 ExecCountSlotsNode(innerPlan((Plan *) node)) + INDEXSCAN_NSLOTS;