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.1 2005/04/19 22:35:12 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 result bitmap
68 tbm = tbm_create(work_mem * 1024L);
71 * Get TIDs from index and insert into bitmap
75 bool more = index_getmulti(scandesc, tids, MAX_TIDS, &ntids);
79 tbm_add_tuples(tbm, tids, ntids);
86 CHECK_FOR_INTERRUPTS();
89 /* must provide our own instrumentation support */
90 if (node->ss.ps.instrument)
91 InstrStopNodeMulti(node->ss.ps.instrument, nTuples);
96 /* ----------------------------------------------------------------
97 * ExecBitmapIndexReScan(node)
99 * Recalculates the value of the scan keys whose value depends on
100 * information known at runtime and rescans the indexed relation.
101 * Updating the scan key was formerly done separately in
102 * ExecUpdateIndexScanKeys. Integrating it into ReScan makes
103 * rescans of indices and relations/general streams more uniform.
105 * ----------------------------------------------------------------
108 ExecBitmapIndexReScan(BitmapIndexScanState *node, ExprContext *exprCtxt)
110 ExprContext *econtext;
111 ExprState **runtimeKeyInfo;
114 econtext = node->biss_RuntimeContext; /* context for runtime
116 runtimeKeyInfo = node->biss_RuntimeKeyInfo;
117 scanrelid = ((BitmapIndexScan *) node->ss.ps.plan)->scan.scanrelid;
122 * If we are being passed an outer tuple, save it for runtime key
123 * calc. We also need to link it into the "regular" per-tuple
126 if (exprCtxt != NULL)
128 ExprContext *stdecontext;
130 econtext->ecxt_outertuple = exprCtxt->ecxt_outertuple;
131 stdecontext = node->ss.ps.ps_ExprContext;
132 stdecontext->ecxt_outertuple = exprCtxt->ecxt_outertuple;
136 * Reset the runtime-key context so we don't leak memory as each
137 * outer tuple is scanned. Note this assumes that we will
138 * recalculate *all* runtime keys on each call.
140 ResetExprContext(econtext);
144 * If we are doing runtime key calculations (ie, the index keys depend
145 * on data from an outer scan), compute the new key values
151 ExprState **run_keys;
154 n_keys = node->biss_NumScanKeys;
155 scan_keys = node->biss_ScanKeys;
156 run_keys = runtimeKeyInfo;
158 for (j = 0; j < n_keys; j++)
161 * If we have a run-time key, then extract the run-time
162 * expression and evaluate it with respect to the current
163 * outer tuple. We then stick the result into the scan
166 * Note: the result of the eval could be a pass-by-ref value
167 * that's stored in the outer scan's tuple, not in
168 * econtext->ecxt_per_tuple_memory. We assume that the
169 * outer tuple will stay put throughout our scan. If this
170 * is wrong, we could copy the result into our context
171 * explicitly, but I think that's not necessary...
173 if (run_keys[j] != NULL)
178 scanvalue = ExecEvalExprSwitchContext(run_keys[j],
182 scan_keys[j].sk_argument = scanvalue;
184 scan_keys[j].sk_flags |= SK_ISNULL;
186 scan_keys[j].sk_flags &= ~SK_ISNULL;
190 node->biss_RuntimeKeysReady = true;
193 index_rescan(node->biss_ScanDesc, node->biss_ScanKeys);
196 /* ----------------------------------------------------------------
197 * ExecEndBitmapIndexScan
198 * ----------------------------------------------------------------
201 ExecEndBitmapIndexScan(BitmapIndexScanState *node)
206 * extract information from the node
208 relation = node->ss.ss_currentRelation;
211 * Free the exprcontext(s)
213 ExecFreeExprContext(&node->ss.ps);
214 if (node->biss_RuntimeContext)
215 FreeExprContext(node->biss_RuntimeContext);
218 * close the index relation
220 if (node->biss_ScanDesc != NULL)
221 index_endscan(node->biss_ScanDesc);
223 if (node->biss_RelationDesc != NULL)
224 index_close(node->biss_RelationDesc);
227 * close the heap relation.
229 * Currently, we do not release the AccessShareLock acquired by
230 * ExecInitBitmapIndexScan. This lock should be held till end of
231 * transaction. (There is a faction that considers this too much
234 heap_close(relation, NoLock);
237 /* ----------------------------------------------------------------
238 * ExecInitBitmapIndexScan
240 * Initializes the index scan's state information, creates
241 * scan keys, and opens the base and index relations.
243 * Note: index scans have 2 sets of state information because
244 * we have to keep track of the base relation and the
248 * Creates the run-time state information for the node and
249 * sets the relation id to contain relevant descriptors.
252 * node: BitmapIndexNode node produced by the planner.
253 * estate: the execution state initialized in InitPlan.
254 * ----------------------------------------------------------------
256 BitmapIndexScanState *
257 ExecInitBitmapIndexScan(BitmapIndexScan *node, EState *estate)
259 BitmapIndexScanState *indexstate;
260 ExprState **runtimeKeyInfo;
261 bool have_runtime_keys;
262 RangeTblEntry *rtentry;
265 Relation currentRelation;
268 * create state structure
270 indexstate = makeNode(BitmapIndexScanState);
271 indexstate->ss.ps.plan = (Plan *) node;
272 indexstate->ss.ps.state = estate;
275 * Miscellaneous initialization
277 * create expression context for node
279 ExecAssignExprContext(estate, &indexstate->ss.ps);
282 * initialize child expressions
284 * We don't need to initialize targetlist or qual since neither are used.
286 * Note: we don't initialize all of the indxqual expression, only the
287 * sub-parts corresponding to runtime keys (see below).
290 #define BITMAPINDEXSCAN_NSLOTS 0
293 * Initialize index-specific scan state
295 indexstate->biss_ScanKeys = NULL;
296 indexstate->biss_NumScanKeys = 0;
297 indexstate->biss_RuntimeKeyInfo = NULL;
298 indexstate->biss_RuntimeContext = NULL;
299 indexstate->biss_RuntimeKeysReady = false;
300 indexstate->biss_RelationDesc = NULL;
301 indexstate->biss_ScanDesc = NULL;
303 CXT1_printf("ExecInitBitmapIndexScan: context is %d\n", CurrentMemoryContext);
306 * initialize space for runtime key info (may not be needed)
308 have_runtime_keys = false;
311 * build the index scan keys from the index qualification
318 ListCell *strategy_cell;
319 ListCell *subtype_cell;
322 ExprState **run_keys;
325 quals = node->indxqual;
326 strategies = node->indxstrategy;
327 subtypes = node->indxsubtype;
328 n_keys = list_length(quals);
329 scan_keys = (n_keys <= 0) ? NULL :
330 (ScanKey) palloc(n_keys * sizeof(ScanKeyData));
331 run_keys = (n_keys <= 0) ? NULL :
332 (ExprState **) palloc(n_keys * sizeof(ExprState *));
335 * for each opclause in the given qual, convert each qual's
336 * opclause into a single scan key
338 qual_cell = list_head(quals);
339 strategy_cell = list_head(strategies);
340 subtype_cell = list_head(subtypes);
341 for (j = 0; j < n_keys; j++)
343 OpExpr *clause; /* one clause of index qual */
344 Expr *leftop; /* expr on lhs of operator */
345 Expr *rightop; /* expr on rhs ... */
347 AttrNumber varattno; /* att number used in scan */
348 StrategyNumber strategy; /* op's strategy number */
349 Oid subtype; /* op's strategy subtype */
350 RegProcedure opfuncid; /* operator proc id used in scan */
351 Datum scanvalue; /* value used in scan (if const) */
354 * extract clause information from the qualification
356 clause = (OpExpr *) lfirst(qual_cell);
357 qual_cell = lnext(qual_cell);
358 strategy = lfirst_int(strategy_cell);
359 strategy_cell = lnext(strategy_cell);
360 subtype = lfirst_oid(subtype_cell);
361 subtype_cell = lnext(subtype_cell);
363 if (!IsA(clause, OpExpr))
364 elog(ERROR, "indxqual is not an OpExpr");
366 opfuncid = clause->opfuncid;
369 * Here we figure out the contents of the index qual. The
370 * usual case is (var op const) which means we form a scan key
371 * for the attribute listed in the var node and use the value
372 * of the const as comparison data.
374 * If we don't have a const node, it means our scan key is a
375 * function of information obtained during the execution of
376 * the plan, in which case we need to recalculate the index
377 * scan key at run time. Hence, we set have_runtime_keys to
378 * true and place the appropriate subexpression in run_keys.
379 * The corresponding scan key values are recomputed at run
385 * determine information in leftop
387 leftop = (Expr *) get_leftop((Expr *) clause);
389 if (leftop && IsA(leftop, RelabelType))
390 leftop = ((RelabelType *) leftop)->arg;
392 Assert(leftop != NULL);
394 if (!(IsA(leftop, Var) &&
395 var_is_rel((Var *) leftop)))
396 elog(ERROR, "indxqual doesn't have key on left side");
398 varattno = ((Var *) leftop)->varattno;
401 * now determine information in rightop
403 rightop = (Expr *) get_rightop((Expr *) clause);
405 if (rightop && IsA(rightop, RelabelType))
406 rightop = ((RelabelType *) rightop)->arg;
408 Assert(rightop != NULL);
410 if (IsA(rightop, Const))
413 * if the rightop is a const node then it means it
414 * identifies the value to place in our scan key.
416 scanvalue = ((Const *) rightop)->constvalue;
417 if (((Const *) rightop)->constisnull)
423 * otherwise, the rightop contains an expression evaluable
424 * at runtime to figure out the value to place in our scan
427 have_runtime_keys = true;
428 run_keys[j] = ExecInitExpr(rightop, (PlanState *) indexstate);
429 scanvalue = (Datum) 0;
433 * initialize the scan key's fields appropriately
435 ScanKeyEntryInitialize(&scan_keys[j],
437 varattno, /* attribute number to
439 strategy, /* op's strategy */
440 subtype, /* strategy subtype */
441 opfuncid, /* reg proc to use */
442 scanvalue); /* constant */
446 * store the key information into the node.
448 indexstate->biss_NumScanKeys = n_keys;
449 indexstate->biss_ScanKeys = scan_keys;
450 runtimeKeyInfo = run_keys;
455 * If all of our keys have the form (var op const), then we have no
456 * runtime keys so we store NULL in the runtime key info. Otherwise
457 * runtime key info contains an array of pointers (one for each index)
458 * to arrays of flags (one for each key) which indicate that the qual
459 * needs to be evaluated at runtime. -cim 10/24/89
461 * If we do have runtime keys, we need an ExprContext to evaluate them;
462 * the node's standard context won't do because we want to reset that
463 * context for every tuple. So, build another context just like the
464 * other one... -tgl 7/11/00
466 if (have_runtime_keys)
468 ExprContext *stdecontext = indexstate->ss.ps.ps_ExprContext;
470 ExecAssignExprContext(estate, &indexstate->ss.ps);
471 indexstate->biss_RuntimeKeyInfo = runtimeKeyInfo;
472 indexstate->biss_RuntimeContext = indexstate->ss.ps.ps_ExprContext;
473 indexstate->ss.ps.ps_ExprContext = stdecontext;
477 indexstate->biss_RuntimeKeyInfo = NULL;
478 indexstate->biss_RuntimeContext = NULL;
479 /* Get rid of the speculatively-allocated flag array, too */
480 pfree(runtimeKeyInfo);
484 * open the base relation and acquire AccessShareLock on it.
486 relid = node->scan.scanrelid;
487 rtentry = rt_fetch(relid, estate->es_range_table);
488 reloid = rtentry->relid;
490 currentRelation = heap_open(reloid, AccessShareLock);
492 indexstate->ss.ss_currentRelation = currentRelation;
493 indexstate->ss.ss_currentScanDesc = NULL; /* no heap scan here */
496 * open the index relation and initialize relation and scan
497 * descriptors. Note we acquire no locks here; the index machinery
498 * does its own locks and unlocks. (We rely on having AccessShareLock
499 * on the parent table to ensure the index won't go away!)
501 indexstate->biss_RelationDesc = index_open(node->indxid);
502 indexstate->biss_ScanDesc =
503 index_beginscan_multi(indexstate->biss_RelationDesc,
505 indexstate->biss_NumScanKeys,
506 indexstate->biss_ScanKeys);
515 ExecCountSlotsBitmapIndexScan(BitmapIndexScan *node)
517 return ExecCountSlotsNode(outerPlan((Plan *) node)) +
518 ExecCountSlotsNode(innerPlan((Plan *) node)) + BITMAPINDEXSCAN_NSLOTS;