1 /*-------------------------------------------------------------------------
3 * nodeBitmapIndexscan.c
4 * Routines to support bitmapped index 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/nodeBitmapIndexscan.c,v 1.5 2005/04/24 17:32:46 tgl Exp $
13 *-------------------------------------------------------------------------
17 * MultiExecBitmapIndexScan scans a relation using index.
18 * ExecInitBitmapIndexScan creates and initializes state info.
19 * ExecBitmapIndexReScan prepares to rescan the plan.
20 * ExecEndBitmapIndexScan releases all storage.
24 #include "access/genam.h"
25 #include "access/heapam.h"
26 #include "executor/execdebug.h"
27 #include "executor/instrument.h"
28 #include "executor/nodeBitmapIndexscan.h"
29 #include "miscadmin.h"
30 #include "nodes/nodeFuncs.h"
31 #include "optimizer/clauses.h"
32 #include "parser/parsetree.h"
35 /* ----------------------------------------------------------------
36 * MultiExecBitmapIndexScan(node)
37 * ----------------------------------------------------------------
40 MultiExecBitmapIndexScan(BitmapIndexScanState *node)
44 IndexScanDesc scandesc;
45 ItemPointerData tids[MAX_TIDS];
49 /* must provide our own instrumentation support */
50 if (node->ss.ps.instrument)
51 InstrStartNode(node->ss.ps.instrument);
54 * If we have runtime keys and they've not already been set up, do it
57 if (node->biss_RuntimeKeyInfo && !node->biss_RuntimeKeysReady)
58 ExecReScan((PlanState *) node, NULL);
61 * extract necessary information from index scan node
63 scandesc = node->biss_ScanDesc;
66 * Prepare the result bitmap. Normally we just create a new one to pass
67 * back; however, our parent node is allowed to store a pre-made one
68 * into node->biss_result, in which case we just OR our tuple IDs into
69 * the existing bitmap. (This saves needing explicit UNION steps.)
71 if (node->biss_result)
73 tbm = node->biss_result;
74 node->biss_result = NULL; /* reset for next time */
78 /* XXX should we use less than work_mem for this? */
79 tbm = tbm_create(work_mem * 1024L);
83 * Get TIDs from index and insert into bitmap
87 bool more = index_getmulti(scandesc, tids, MAX_TIDS, &ntids);
91 tbm_add_tuples(tbm, tids, ntids);
98 CHECK_FOR_INTERRUPTS();
101 /* must provide our own instrumentation support */
102 if (node->ss.ps.instrument)
103 InstrStopNodeMulti(node->ss.ps.instrument, nTuples);
108 /* ----------------------------------------------------------------
109 * ExecBitmapIndexReScan(node)
111 * Recalculates the value of the scan keys whose value depends on
112 * information known at runtime and rescans the indexed relation.
113 * Updating the scan key was formerly done separately in
114 * ExecUpdateIndexScanKeys. Integrating it into ReScan makes
115 * rescans of indices and relations/general streams more uniform.
117 * ----------------------------------------------------------------
120 ExecBitmapIndexReScan(BitmapIndexScanState *node, ExprContext *exprCtxt)
122 ExprContext *econtext;
123 ExprState **runtimeKeyInfo;
126 econtext = node->biss_RuntimeContext; /* context for runtime
128 runtimeKeyInfo = node->biss_RuntimeKeyInfo;
129 scanrelid = ((BitmapIndexScan *) node->ss.ps.plan)->scan.scanrelid;
134 * If we are being passed an outer tuple, save it for runtime key
137 if (exprCtxt != NULL)
138 econtext->ecxt_outertuple = exprCtxt->ecxt_outertuple;
141 * Reset the runtime-key context so we don't leak memory as each
142 * outer tuple is scanned. Note this assumes that we will
143 * recalculate *all* runtime keys on each call.
145 ResetExprContext(econtext);
149 * If we are doing runtime key calculations (ie, the index keys depend
150 * on data from an outer scan), compute the new key values
156 ExprState **run_keys;
159 n_keys = node->biss_NumScanKeys;
160 scan_keys = node->biss_ScanKeys;
161 run_keys = runtimeKeyInfo;
163 for (j = 0; j < n_keys; j++)
166 * If we have a run-time key, then extract the run-time
167 * expression and evaluate it with respect to the current
168 * outer tuple. We then stick the result into the scan
171 * Note: the result of the eval could be a pass-by-ref value
172 * that's stored in the outer scan's tuple, not in
173 * econtext->ecxt_per_tuple_memory. We assume that the
174 * outer tuple will stay put throughout our scan. If this
175 * is wrong, we could copy the result into our context
176 * explicitly, but I think that's not necessary...
178 if (run_keys[j] != NULL)
183 scanvalue = ExecEvalExprSwitchContext(run_keys[j],
187 scan_keys[j].sk_argument = scanvalue;
189 scan_keys[j].sk_flags |= SK_ISNULL;
191 scan_keys[j].sk_flags &= ~SK_ISNULL;
195 node->biss_RuntimeKeysReady = true;
198 index_rescan(node->biss_ScanDesc, node->biss_ScanKeys);
201 /* ----------------------------------------------------------------
202 * ExecEndBitmapIndexScan
203 * ----------------------------------------------------------------
206 ExecEndBitmapIndexScan(BitmapIndexScanState *node)
211 * extract information from the node
213 relation = node->ss.ss_currentRelation;
216 * Free the exprcontext ... now dead code, see ExecFreeExprContext
219 if (node->biss_RuntimeContext)
220 FreeExprContext(node->biss_RuntimeContext);
224 * close the index relation
226 if (node->biss_ScanDesc != NULL)
227 index_endscan(node->biss_ScanDesc);
229 if (node->biss_RelationDesc != NULL)
230 index_close(node->biss_RelationDesc);
233 * close the heap relation.
235 * Currently, we do not release the AccessShareLock acquired by
236 * ExecInitBitmapIndexScan. This lock should be held till end of
237 * transaction. (There is a faction that considers this too much
240 heap_close(relation, NoLock);
243 /* ----------------------------------------------------------------
244 * ExecInitBitmapIndexScan
246 * Initializes the index scan's state information, creates
247 * scan keys, and opens the base and index relations.
249 * Note: index scans have 2 sets of state information because
250 * we have to keep track of the base relation and the
254 * Creates the run-time state information for the node and
255 * sets the relation id to contain relevant descriptors.
258 * node: BitmapIndexNode node produced by the planner.
259 * estate: the execution state initialized in InitPlan.
260 * ----------------------------------------------------------------
262 BitmapIndexScanState *
263 ExecInitBitmapIndexScan(BitmapIndexScan *node, EState *estate)
265 BitmapIndexScanState *indexstate;
266 ExprState **runtimeKeyInfo;
267 bool have_runtime_keys;
268 RangeTblEntry *rtentry;
271 Relation currentRelation;
274 * create state structure
276 indexstate = makeNode(BitmapIndexScanState);
277 indexstate->ss.ps.plan = (Plan *) node;
278 indexstate->ss.ps.state = estate;
280 /* normally we don't make the result bitmap till runtime */
281 indexstate->biss_result = NULL;
284 * Miscellaneous initialization
286 * We do not need a standard exprcontext for this node, though we may
287 * decide below to create a runtime-key exprcontext
291 * initialize child expressions
293 * We don't need to initialize targetlist or qual since neither are used.
295 * Note: we don't initialize all of the indxqual expression, only the
296 * sub-parts corresponding to runtime keys (see below).
299 #define BITMAPINDEXSCAN_NSLOTS 0
302 * Initialize index-specific scan state
304 indexstate->biss_ScanKeys = NULL;
305 indexstate->biss_NumScanKeys = 0;
306 indexstate->biss_RuntimeKeyInfo = NULL;
307 indexstate->biss_RuntimeContext = NULL;
308 indexstate->biss_RuntimeKeysReady = false;
309 indexstate->biss_RelationDesc = NULL;
310 indexstate->biss_ScanDesc = NULL;
312 CXT1_printf("ExecInitBitmapIndexScan: context is %d\n", CurrentMemoryContext);
315 * initialize space for runtime key info (may not be needed)
317 have_runtime_keys = false;
320 * build the index scan keys from the index qualification
327 ListCell *strategy_cell;
328 ListCell *subtype_cell;
331 ExprState **run_keys;
334 quals = node->indxqual;
335 strategies = node->indxstrategy;
336 subtypes = node->indxsubtype;
337 n_keys = list_length(quals);
338 scan_keys = (n_keys <= 0) ? NULL :
339 (ScanKey) palloc(n_keys * sizeof(ScanKeyData));
340 run_keys = (n_keys <= 0) ? NULL :
341 (ExprState **) palloc(n_keys * sizeof(ExprState *));
344 * for each opclause in the given qual, convert each qual's
345 * opclause into a single scan key
347 qual_cell = list_head(quals);
348 strategy_cell = list_head(strategies);
349 subtype_cell = list_head(subtypes);
350 for (j = 0; j < n_keys; j++)
352 OpExpr *clause; /* one clause of index qual */
353 Expr *leftop; /* expr on lhs of operator */
354 Expr *rightop; /* expr on rhs ... */
356 AttrNumber varattno; /* att number used in scan */
357 StrategyNumber strategy; /* op's strategy number */
358 Oid subtype; /* op's strategy subtype */
359 RegProcedure opfuncid; /* operator proc id used in scan */
360 Datum scanvalue; /* value used in scan (if const) */
363 * extract clause information from the qualification
365 clause = (OpExpr *) lfirst(qual_cell);
366 qual_cell = lnext(qual_cell);
367 strategy = lfirst_int(strategy_cell);
368 strategy_cell = lnext(strategy_cell);
369 subtype = lfirst_oid(subtype_cell);
370 subtype_cell = lnext(subtype_cell);
372 if (!IsA(clause, OpExpr))
373 elog(ERROR, "indxqual is not an OpExpr");
375 opfuncid = clause->opfuncid;
378 * Here we figure out the contents of the index qual. The
379 * usual case is (var op const) which means we form a scan key
380 * for the attribute listed in the var node and use the value
381 * of the const as comparison data.
383 * If we don't have a const node, it means our scan key is a
384 * function of information obtained during the execution of
385 * the plan, in which case we need to recalculate the index
386 * scan key at run time. Hence, we set have_runtime_keys to
387 * true and place the appropriate subexpression in run_keys.
388 * The corresponding scan key values are recomputed at run
394 * determine information in leftop
396 leftop = (Expr *) get_leftop((Expr *) clause);
398 if (leftop && IsA(leftop, RelabelType))
399 leftop = ((RelabelType *) leftop)->arg;
401 Assert(leftop != NULL);
403 if (!(IsA(leftop, Var) &&
404 var_is_rel((Var *) leftop)))
405 elog(ERROR, "indxqual doesn't have key on left side");
407 varattno = ((Var *) leftop)->varattno;
410 * now determine information in rightop
412 rightop = (Expr *) get_rightop((Expr *) clause);
414 if (rightop && IsA(rightop, RelabelType))
415 rightop = ((RelabelType *) rightop)->arg;
417 Assert(rightop != NULL);
419 if (IsA(rightop, Const))
422 * if the rightop is a const node then it means it
423 * identifies the value to place in our scan key.
425 scanvalue = ((Const *) rightop)->constvalue;
426 if (((Const *) rightop)->constisnull)
432 * otherwise, the rightop contains an expression evaluable
433 * at runtime to figure out the value to place in our scan
436 have_runtime_keys = true;
437 run_keys[j] = ExecInitExpr(rightop, (PlanState *) indexstate);
438 scanvalue = (Datum) 0;
442 * initialize the scan key's fields appropriately
444 ScanKeyEntryInitialize(&scan_keys[j],
446 varattno, /* attribute number to
448 strategy, /* op's strategy */
449 subtype, /* strategy subtype */
450 opfuncid, /* reg proc to use */
451 scanvalue); /* constant */
455 * store the key information into the node.
457 indexstate->biss_NumScanKeys = n_keys;
458 indexstate->biss_ScanKeys = scan_keys;
459 runtimeKeyInfo = run_keys;
464 * If all of our keys have the form (var op const), then we have no
465 * runtime keys so we store NULL in the runtime key info. Otherwise
466 * runtime key info contains an array of pointers to runtime key
469 * If we do have runtime keys, we need an ExprContext to evaluate them.
470 * We could just create a "standard" plan node exprcontext, but to
471 * keep the code looking similar to nodeIndexscan.c, it seems better
472 * to stick with the approach of using a separate ExprContext.
474 if (have_runtime_keys)
476 ExprContext *stdecontext = indexstate->ss.ps.ps_ExprContext;
478 ExecAssignExprContext(estate, &indexstate->ss.ps);
479 indexstate->biss_RuntimeKeyInfo = runtimeKeyInfo;
480 indexstate->biss_RuntimeContext = indexstate->ss.ps.ps_ExprContext;
481 indexstate->ss.ps.ps_ExprContext = stdecontext;
485 indexstate->biss_RuntimeKeyInfo = NULL;
486 indexstate->biss_RuntimeContext = NULL;
487 /* Get rid of the speculatively-allocated flag array, too */
489 pfree(runtimeKeyInfo);
493 * open the base relation and acquire AccessShareLock on it.
495 relid = node->scan.scanrelid;
496 rtentry = rt_fetch(relid, estate->es_range_table);
497 reloid = rtentry->relid;
499 currentRelation = heap_open(reloid, AccessShareLock);
501 indexstate->ss.ss_currentRelation = currentRelation;
502 indexstate->ss.ss_currentScanDesc = NULL; /* no heap scan here */
505 * open the index relation and initialize relation and scan
506 * descriptors. Note we acquire no locks here; the index machinery
507 * does its own locks and unlocks. (We rely on having AccessShareLock
508 * on the parent table to ensure the index won't go away!)
510 indexstate->biss_RelationDesc = index_open(node->indxid);
511 indexstate->biss_ScanDesc =
512 index_beginscan_multi(indexstate->biss_RelationDesc,
514 indexstate->biss_NumScanKeys,
515 indexstate->biss_ScanKeys);
524 ExecCountSlotsBitmapIndexScan(BitmapIndexScan *node)
526 return ExecCountSlotsNode(outerPlan((Plan *) node)) +
527 ExecCountSlotsNode(innerPlan((Plan *) node)) + BITMAPINDEXSCAN_NSLOTS;