1 /*-------------------------------------------------------------------------
4 * Routines to support indexed scans of relations
6 * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
11 * $PostgreSQL: pgsql/src/backend/executor/nodeIndexscan.c,v 1.106 2005/11/25 04:24:48 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/parsetree.h"
35 #include "utils/memutils.h"
38 static TupleTableSlot *IndexNext(IndexScanState *node);
41 /* ----------------------------------------------------------------
44 * Retrieve a tuple from the IndexScan node's currentRelation
45 * using the index specified in the IndexScanState information.
46 * ----------------------------------------------------------------
48 static TupleTableSlot *
49 IndexNext(IndexScanState *node)
52 ExprContext *econtext;
53 ScanDirection direction;
54 IndexScanDesc scandesc;
60 * extract necessary information from index scan node
62 estate = node->ss.ps.state;
63 direction = estate->es_direction;
64 /* flip direction if this is an overall backward scan */
65 if (ScanDirectionIsBackward(((IndexScan *) node->ss.ps.plan)->indexorderdir))
67 if (ScanDirectionIsForward(direction))
68 direction = BackwardScanDirection;
69 else if (ScanDirectionIsBackward(direction))
70 direction = ForwardScanDirection;
72 scandesc = node->iss_ScanDesc;
73 econtext = node->ss.ps.ps_ExprContext;
74 slot = node->ss.ss_ScanTupleSlot;
75 scanrelid = ((IndexScan *) node->ss.ps.plan)->scan.scanrelid;
78 * Check if we are evaluating PlanQual for tuple of this relation.
79 * Additional checking is not good, but no other way for now. We could
80 * introduce new nodes for this case and handle IndexScan --> NewNode
81 * switching in Init/ReScan plan...
83 if (estate->es_evTuple != NULL &&
84 estate->es_evTuple[scanrelid - 1] != NULL)
86 if (estate->es_evTupleNull[scanrelid - 1])
87 return ExecClearTuple(slot);
89 ExecStoreTuple(estate->es_evTuple[scanrelid - 1],
90 slot, InvalidBuffer, false);
92 /* Does the tuple meet the indexqual condition? */
93 econtext->ecxt_scantuple = slot;
95 ResetExprContext(econtext);
97 if (!ExecQual(node->indexqualorig, econtext, false))
98 ExecClearTuple(slot); /* would not be returned by scan */
100 /* Flag for the next call that no more tuples */
101 estate->es_evTupleNull[scanrelid - 1] = true;
107 * ok, now that we have what we need, fetch the next tuple.
109 if ((tuple = index_getnext(scandesc, direction)) != NULL)
112 * Store the scanned tuple in the scan tuple slot of the scan state.
113 * Note: we pass 'false' because tuples returned by amgetnext are
114 * pointers onto disk pages and must not be pfree()'d.
116 ExecStoreTuple(tuple, /* tuple to store */
117 slot, /* slot to store in */
118 scandesc->xs_cbuf, /* buffer containing tuple */
119 false); /* don't pfree */
125 * if we get here it means the index scan failed so we are at the end of
128 return ExecClearTuple(slot);
131 /* ----------------------------------------------------------------
132 * ExecIndexScan(node)
133 * ----------------------------------------------------------------
136 ExecIndexScan(IndexScanState *node)
139 * If we have runtime keys and they've not already been set up, do it now.
141 if (node->iss_RuntimeKeyInfo && !node->iss_RuntimeKeysReady)
142 ExecReScan((PlanState *) node, NULL);
145 * use IndexNext as access method
147 return ExecScan(&node->ss, (ExecScanAccessMtd) IndexNext);
150 /* ----------------------------------------------------------------
151 * ExecIndexReScan(node)
153 * Recalculates the value of the scan keys whose value depends on
154 * information known at runtime and rescans the indexed relation.
155 * Updating the scan key was formerly done separately in
156 * ExecUpdateIndexScanKeys. Integrating it into ReScan makes
157 * rescans of indices and relations/general streams more uniform.
158 * ----------------------------------------------------------------
161 ExecIndexReScan(IndexScanState *node, ExprContext *exprCtxt)
164 ExprContext *econtext;
166 ExprState **runtimeKeyInfo;
170 estate = node->ss.ps.state;
171 econtext = node->iss_RuntimeContext; /* context for runtime keys */
172 scanKeys = node->iss_ScanKeys;
173 runtimeKeyInfo = node->iss_RuntimeKeyInfo;
174 numScanKeys = node->iss_NumScanKeys;
175 scanrelid = ((IndexScan *) node->ss.ps.plan)->scan.scanrelid;
180 * If we are being passed an outer tuple, save it for runtime key
181 * calc. We also need to link it into the "regular" per-tuple
182 * econtext, so it can be used during indexqualorig evaluations.
184 if (exprCtxt != NULL)
186 ExprContext *stdecontext;
188 econtext->ecxt_outertuple = exprCtxt->ecxt_outertuple;
189 stdecontext = node->ss.ps.ps_ExprContext;
190 stdecontext->ecxt_outertuple = exprCtxt->ecxt_outertuple;
194 * Reset the runtime-key context so we don't leak memory as each outer
195 * tuple is scanned. Note this assumes that we will recalculate *all*
196 * runtime keys on each call.
198 ResetExprContext(econtext);
202 * If we are doing runtime key calculations (ie, the index keys depend on
203 * data from an outer scan), compute the new key values
207 ExecIndexEvalRuntimeKeys(econtext,
211 node->iss_RuntimeKeysReady = true;
214 /* If this is re-scanning of PlanQual ... */
215 if (estate->es_evTuple != NULL &&
216 estate->es_evTuple[scanrelid - 1] != NULL)
218 estate->es_evTupleNull[scanrelid - 1] = false;
222 /* reset index scan */
223 index_rescan(node->iss_ScanDesc, scanKeys);
228 * ExecIndexEvalRuntimeKeys
229 * Evaluate any runtime key values, and update the scankeys.
232 ExecIndexEvalRuntimeKeys(ExprContext *econtext,
233 ExprState **run_keys,
239 for (j = 0; j < n_keys; j++)
242 * If we have a run-time key, then extract the run-time expression and
243 * evaluate it with respect to the current outer tuple. We then stick
244 * the result into the scan key.
246 * Note: the result of the eval could be a pass-by-ref value that's
247 * stored in the outer scan's tuple, not in
248 * econtext->ecxt_per_tuple_memory. We assume that the outer tuple
249 * will stay put throughout our scan. If this is wrong, we could copy
250 * the result into our context explicitly, but I think that's not
253 if (run_keys[j] != NULL)
258 scanvalue = ExecEvalExprSwitchContext(run_keys[j],
262 scan_keys[j].sk_argument = scanvalue;
264 scan_keys[j].sk_flags |= SK_ISNULL;
266 scan_keys[j].sk_flags &= ~SK_ISNULL;
271 /* ----------------------------------------------------------------
273 * ----------------------------------------------------------------
276 ExecEndIndexScan(IndexScanState *node)
278 Relation indexRelationDesc;
279 IndexScanDesc indexScanDesc;
283 * extract information from the node
285 indexRelationDesc = node->iss_RelationDesc;
286 indexScanDesc = node->iss_ScanDesc;
287 relation = node->ss.ss_currentRelation;
290 * Free the exprcontext(s) ... now dead code, see ExecFreeExprContext
293 ExecFreeExprContext(&node->ss.ps);
294 if (node->iss_RuntimeContext)
295 FreeExprContext(node->iss_RuntimeContext);
299 * clear out tuple table slots
301 ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
302 ExecClearTuple(node->ss.ss_ScanTupleSlot);
305 * close the index relation
307 index_endscan(indexScanDesc);
308 index_close(indexRelationDesc);
311 * close the heap relation.
313 * Currently, we do not release the AccessShareLock acquired by
314 * ExecInitIndexScan. This lock should be held till end of transaction.
315 * (There is a faction that considers this too much locking, however.)
317 heap_close(relation, NoLock);
320 /* ----------------------------------------------------------------
322 * ----------------------------------------------------------------
325 ExecIndexMarkPos(IndexScanState *node)
327 index_markpos(node->iss_ScanDesc);
330 /* ----------------------------------------------------------------
332 * ----------------------------------------------------------------
335 ExecIndexRestrPos(IndexScanState *node)
337 index_restrpos(node->iss_ScanDesc);
340 /* ----------------------------------------------------------------
343 * Initializes the index scan's state information, creates
344 * scan keys, and opens the base and index relations.
346 * Note: index scans have 2 sets of state information because
347 * we have to keep track of the base relation and the
349 * ----------------------------------------------------------------
352 ExecInitIndexScan(IndexScan *node, EState *estate)
354 IndexScanState *indexstate;
357 ExprState **runtimeKeyInfo;
358 bool have_runtime_keys;
359 RangeTblEntry *rtentry;
362 Relation currentRelation;
365 * create state structure
367 indexstate = makeNode(IndexScanState);
368 indexstate->ss.ps.plan = (Plan *) node;
369 indexstate->ss.ps.state = estate;
372 * Miscellaneous initialization
374 * create expression context for node
376 ExecAssignExprContext(estate, &indexstate->ss.ps);
379 * initialize child expressions
381 * Note: we don't initialize all of the indexqual expression, only the
382 * sub-parts corresponding to runtime keys (see below). The indexqualorig
383 * expression is always initialized even though it will only be used in
384 * some uncommon cases --- would be nice to improve that. (Problem is
385 * that any SubPlans present in the expression must be found now...)
387 indexstate->ss.ps.targetlist = (List *)
388 ExecInitExpr((Expr *) node->scan.plan.targetlist,
389 (PlanState *) indexstate);
390 indexstate->ss.ps.qual = (List *)
391 ExecInitExpr((Expr *) node->scan.plan.qual,
392 (PlanState *) indexstate);
393 indexstate->indexqualorig = (List *)
394 ExecInitExpr((Expr *) node->indexqualorig,
395 (PlanState *) indexstate);
397 #define INDEXSCAN_NSLOTS 2
400 * tuple table initialization
402 ExecInitResultTupleSlot(estate, &indexstate->ss.ps);
403 ExecInitScanTupleSlot(estate, &indexstate->ss);
406 * Initialize index-specific scan state
408 indexstate->iss_RuntimeKeysReady = false;
410 CXT1_printf("ExecInitIndexScan: context is %d\n", CurrentMemoryContext);
413 * build the index scan keys from the index qualification
416 ExecIndexBuildScanKeys((PlanState *) indexstate,
424 indexstate->iss_RuntimeKeyInfo = runtimeKeyInfo;
425 indexstate->iss_ScanKeys = scanKeys;
426 indexstate->iss_NumScanKeys = numScanKeys;
429 * If we have runtime keys, we need an ExprContext to evaluate them. The
430 * node's standard context won't do because we want to reset that context
431 * for every tuple. So, build another context just like the other one...
434 if (have_runtime_keys)
436 ExprContext *stdecontext = indexstate->ss.ps.ps_ExprContext;
438 ExecAssignExprContext(estate, &indexstate->ss.ps);
439 indexstate->iss_RuntimeContext = indexstate->ss.ps.ps_ExprContext;
440 indexstate->ss.ps.ps_ExprContext = stdecontext;
444 indexstate->iss_RuntimeContext = NULL;
448 * open the base relation and acquire AccessShareLock on it.
450 relid = node->scan.scanrelid;
451 rtentry = rt_fetch(relid, estate->es_range_table);
452 reloid = rtentry->relid;
454 currentRelation = heap_open(reloid, AccessShareLock);
456 indexstate->ss.ss_currentRelation = currentRelation;
457 indexstate->ss.ss_currentScanDesc = NULL; /* no heap scan here */
460 * get the scan type from the relation descriptor.
462 ExecAssignScanType(&indexstate->ss, RelationGetDescr(currentRelation), false);
465 * open the index relation and initialize relation and scan descriptors.
466 * Note we acquire no locks here; the index machinery does its own locks
467 * and unlocks. (We rely on having AccessShareLock on the parent table to
468 * ensure the index won't go away!)
470 indexstate->iss_RelationDesc = index_open(node->indexid);
471 indexstate->iss_ScanDesc = index_beginscan(currentRelation,
472 indexstate->iss_RelationDesc,
478 * Initialize result tuple type and projection info.
480 ExecAssignResultTypeFromTL(&indexstate->ss.ps);
481 ExecAssignScanProjectionInfo(&indexstate->ss);
491 * ExecIndexBuildScanKeys
492 * Build the index scan keys from the index qualification
496 * planstate: executor state node we are working for
497 * quals: indexquals expressions
498 * strategies: associated operator strategy numbers
499 * subtypes: associated operator subtype OIDs
503 * *runtimeKeyInfo: receives ptr to array of runtime key exprstates
504 * (NULL if no runtime keys)
505 * *scanKeys: receives ptr to array of ScanKeys
506 * *numScanKeys: receives number of scankeys/runtime keys
508 * Return value is TRUE if any runtime key expressions were found, else FALSE.
511 ExecIndexBuildScanKeys(PlanState *planstate, List *quals,
512 List *strategies, List *subtypes,
513 ExprState ***runtimeKeyInfo,
514 ScanKey *scanKeys, int *numScanKeys)
516 bool have_runtime_keys = false;
518 ListCell *strategy_cell;
519 ListCell *subtype_cell;
522 ExprState **run_keys;
525 n_keys = list_length(quals);
526 scan_keys = (n_keys <= 0) ? NULL :
527 (ScanKey) palloc(n_keys * sizeof(ScanKeyData));
528 run_keys = (n_keys <= 0) ? NULL :
529 (ExprState **) palloc(n_keys * sizeof(ExprState *));
532 * for each opclause in the given qual, convert each qual's opclause into
535 qual_cell = list_head(quals);
536 strategy_cell = list_head(strategies);
537 subtype_cell = list_head(subtypes);
539 for (j = 0; j < n_keys; j++)
541 OpExpr *clause; /* one clause of index qual */
542 Expr *leftop; /* expr on lhs of operator */
543 Expr *rightop; /* expr on rhs ... */
545 AttrNumber varattno; /* att number used in scan */
546 StrategyNumber strategy; /* op's strategy number */
547 Oid subtype; /* op's strategy subtype */
548 RegProcedure opfuncid; /* operator proc id used in scan */
549 Datum scanvalue; /* value used in scan (if const) */
552 * extract clause information from the qualification
554 clause = (OpExpr *) lfirst(qual_cell);
555 qual_cell = lnext(qual_cell);
556 strategy = lfirst_int(strategy_cell);
557 strategy_cell = lnext(strategy_cell);
558 subtype = lfirst_oid(subtype_cell);
559 subtype_cell = lnext(subtype_cell);
561 if (!IsA(clause, OpExpr))
562 elog(ERROR, "indexqual is not an OpExpr");
564 opfuncid = clause->opfuncid;
567 * Here we figure out the contents of the index qual. The usual case
568 * is (var op const) which means we form a scan key for the attribute
569 * listed in the var node and use the value of the const as comparison
572 * If we don't have a const node, it means our scan key is a function
573 * of information obtained during the execution of the plan, in which
574 * case we need to recalculate the index scan key at run time. Hence,
575 * we set have_runtime_keys to true and place the appropriate
576 * subexpression in run_keys. The corresponding scan key values are
577 * recomputed at run time.
582 * determine information in leftop
584 leftop = (Expr *) get_leftop((Expr *) clause);
586 if (leftop && IsA(leftop, RelabelType))
587 leftop = ((RelabelType *) leftop)->arg;
589 Assert(leftop != NULL);
591 if (!(IsA(leftop, Var) &&
592 var_is_rel((Var *) leftop)))
593 elog(ERROR, "indexqual doesn't have key on left side");
595 varattno = ((Var *) leftop)->varattno;
598 * now determine information in rightop
600 rightop = (Expr *) get_rightop((Expr *) clause);
602 if (rightop && IsA(rightop, RelabelType))
603 rightop = ((RelabelType *) rightop)->arg;
605 Assert(rightop != NULL);
607 if (IsA(rightop, Const))
610 * if the rightop is a const node then it means it identifies the
611 * value to place in our scan key.
613 scanvalue = ((Const *) rightop)->constvalue;
614 if (((Const *) rightop)->constisnull)
620 * otherwise, the rightop contains an expression evaluable at
621 * runtime to figure out the value to place in our scan key.
623 have_runtime_keys = true;
624 run_keys[j] = ExecInitExpr(rightop, planstate);
625 scanvalue = (Datum) 0;
629 * initialize the scan key's fields appropriately
631 ScanKeyEntryInitialize(&scan_keys[j],
633 varattno, /* attribute number to scan */
634 strategy, /* op's strategy */
635 subtype, /* strategy subtype */
636 opfuncid, /* reg proc to use */
637 scanvalue); /* constant */
640 /* If no runtime keys, get rid of speculatively-allocated array */
641 if (run_keys && !have_runtime_keys)
648 * Return the info to our caller.
650 *numScanKeys = n_keys;
651 *scanKeys = scan_keys;
652 *runtimeKeyInfo = run_keys;
654 return have_runtime_keys;
658 ExecCountSlotsIndexScan(IndexScan *node)
660 return ExecCountSlotsNode(outerPlan((Plan *) node)) +
661 ExecCountSlotsNode(innerPlan((Plan *) node)) + INDEXSCAN_NSLOTS;