1 /*-------------------------------------------------------------------------
3 * nodeBitmapIndexscan.c
4 * Routines to support bitmapped index scans of relations
6 * Portions Copyright (c) 1996-2007, 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.23 2007/05/25 17:54:25 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 "executor/execdebug.h"
26 #include "executor/instrument.h"
27 #include "executor/nodeBitmapIndexscan.h"
28 #include "executor/nodeIndexscan.h"
29 #include "miscadmin.h"
30 #include "utils/memutils.h"
33 /* ----------------------------------------------------------------
34 * MultiExecBitmapIndexScan(node)
35 * ----------------------------------------------------------------
38 MultiExecBitmapIndexScan(BitmapIndexScanState *node)
42 IndexScanDesc scandesc;
43 ItemPointerData tids[MAX_TIDS];
48 /* must provide our own instrumentation support */
49 if (node->ss.ps.instrument)
50 InstrStartNode(node->ss.ps.instrument);
53 * extract necessary information from index scan node
55 scandesc = node->biss_ScanDesc;
58 * If we have runtime keys and they've not already been set up, do it now.
59 * Array keys are also treated as runtime keys; note that if ExecReScan
60 * returns with biss_RuntimeKeysReady still false, then there is an empty
61 * array key so we should do nothing.
63 if (!node->biss_RuntimeKeysReady &&
64 (node->biss_NumRuntimeKeys != 0 || node->biss_NumArrayKeys != 0))
66 ExecReScan((PlanState *) node, NULL);
67 doscan = node->biss_RuntimeKeysReady;
73 * Prepare the result bitmap. Normally we just create a new one to pass
74 * back; however, our parent node is allowed to store a pre-made one into
75 * node->biss_result, in which case we just OR our tuple IDs into the
76 * existing bitmap. (This saves needing explicit UNION steps.)
78 if (node->biss_result)
80 tbm = node->biss_result;
81 node->biss_result = NULL; /* reset for next time */
85 /* XXX should we use less than work_mem for this? */
86 tbm = tbm_create(work_mem * 1024L);
90 * Get TIDs from index and insert into bitmap
94 bool more = index_getmulti(scandesc, tids, MAX_TIDS, &ntids);
98 tbm_add_tuples(tbm, tids, ntids);
102 CHECK_FOR_INTERRUPTS();
106 doscan = ExecIndexAdvanceArrayKeys(node->biss_ArrayKeys,
107 node->biss_NumArrayKeys);
108 if (doscan) /* reset index scan */
109 index_rescan(node->biss_ScanDesc, node->biss_ScanKeys);
113 /* must provide our own instrumentation support */
114 if (node->ss.ps.instrument)
115 InstrStopNode(node->ss.ps.instrument, nTuples);
120 /* ----------------------------------------------------------------
121 * ExecBitmapIndexReScan(node)
123 * Recalculates the value of the scan keys whose value depends on
124 * information known at runtime and rescans the indexed relation.
125 * ----------------------------------------------------------------
128 ExecBitmapIndexReScan(BitmapIndexScanState *node, ExprContext *exprCtxt)
130 ExprContext *econtext;
132 econtext = node->biss_RuntimeContext; /* context for runtime keys */
137 * If we are being passed an outer tuple, save it for runtime key
140 if (exprCtxt != NULL)
141 econtext->ecxt_outertuple = exprCtxt->ecxt_outertuple;
144 * Reset the runtime-key context so we don't leak memory as each outer
145 * tuple is scanned. Note this assumes that we will recalculate *all*
146 * runtime keys on each call.
148 ResetExprContext(econtext);
152 * If we are doing runtime key calculations (ie, the index keys depend on
153 * data from an outer scan), compute the new key values.
155 * Array keys are also treated as runtime keys; note that if we return
156 * with biss_RuntimeKeysReady still false, then there is an empty array
157 * key so no index scan is needed.
159 if (node->biss_NumRuntimeKeys != 0)
160 ExecIndexEvalRuntimeKeys(econtext,
161 node->biss_RuntimeKeys,
162 node->biss_NumRuntimeKeys);
163 if (node->biss_NumArrayKeys != 0)
164 node->biss_RuntimeKeysReady =
165 ExecIndexEvalArrayKeys(econtext,
166 node->biss_ArrayKeys,
167 node->biss_NumArrayKeys);
169 node->biss_RuntimeKeysReady = true;
171 /* reset index scan */
172 if (node->biss_RuntimeKeysReady)
173 index_rescan(node->biss_ScanDesc, node->biss_ScanKeys);
176 /* ----------------------------------------------------------------
177 * ExecEndBitmapIndexScan
178 * ----------------------------------------------------------------
181 ExecEndBitmapIndexScan(BitmapIndexScanState *node)
183 Relation indexRelationDesc;
184 IndexScanDesc indexScanDesc;
187 * extract information from the node
189 indexRelationDesc = node->biss_RelationDesc;
190 indexScanDesc = node->biss_ScanDesc;
193 * Free the exprcontext ... now dead code, see ExecFreeExprContext
196 if (node->biss_RuntimeContext)
197 FreeExprContext(node->biss_RuntimeContext);
201 * close the index relation (no-op if we didn't open it)
204 index_endscan(indexScanDesc);
205 if (indexRelationDesc)
206 index_close(indexRelationDesc, NoLock);
209 /* ----------------------------------------------------------------
210 * ExecInitBitmapIndexScan
212 * Initializes the index scan's state information.
213 * ----------------------------------------------------------------
215 BitmapIndexScanState *
216 ExecInitBitmapIndexScan(BitmapIndexScan *node, EState *estate, int eflags)
218 BitmapIndexScanState *indexstate;
221 /* check for unsupported flags */
222 Assert(!(eflags & (EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK)));
225 * create state structure
227 indexstate = makeNode(BitmapIndexScanState);
228 indexstate->ss.ps.plan = (Plan *) node;
229 indexstate->ss.ps.state = estate;
231 /* normally we don't make the result bitmap till runtime */
232 indexstate->biss_result = NULL;
235 * Miscellaneous initialization
237 * We do not need a standard exprcontext for this node, though we may
238 * decide below to create a runtime-key exprcontext
242 * initialize child expressions
244 * We don't need to initialize targetlist or qual since neither are used.
246 * Note: we don't initialize all of the indexqual expression, only the
247 * sub-parts corresponding to runtime keys (see below).
250 #define BITMAPINDEXSCAN_NSLOTS 0
253 * We do not open or lock the base relation here. We assume that an
254 * ancestor BitmapHeapScan node is holding AccessShareLock (or better) on
255 * the heap relation throughout the execution of the plan tree.
258 indexstate->ss.ss_currentRelation = NULL;
259 indexstate->ss.ss_currentScanDesc = NULL;
262 * If we are just doing EXPLAIN (ie, aren't going to run the plan),
263 * stop here. This allows an index-advisor plugin to EXPLAIN a plan
264 * containing references to nonexistent indexes.
266 if (eflags & EXEC_FLAG_EXPLAIN_ONLY)
270 * Open the index relation.
272 * If the parent table is one of the target relations of the query, then
273 * InitPlan already opened and write-locked the index, so we can avoid
274 * taking another lock here. Otherwise we need a normal reader's lock.
276 relistarget = ExecRelationIsTargetRelation(estate, node->scan.scanrelid);
277 indexstate->biss_RelationDesc = index_open(node->indexid,
278 relistarget ? NoLock : AccessShareLock);
281 * Initialize index-specific scan state
283 indexstate->biss_RuntimeKeysReady = false;
286 * build the index scan keys from the index qualification
288 ExecIndexBuildScanKeys((PlanState *) indexstate,
289 indexstate->biss_RelationDesc,
293 &indexstate->biss_ScanKeys,
294 &indexstate->biss_NumScanKeys,
295 &indexstate->biss_RuntimeKeys,
296 &indexstate->biss_NumRuntimeKeys,
297 &indexstate->biss_ArrayKeys,
298 &indexstate->biss_NumArrayKeys);
301 * If we have runtime keys or array keys, we need an ExprContext to
302 * evaluate them. We could just create a "standard" plan node exprcontext,
303 * but to keep the code looking similar to nodeIndexscan.c, it seems
304 * better to stick with the approach of using a separate ExprContext.
306 if (indexstate->biss_NumRuntimeKeys != 0 ||
307 indexstate->biss_NumArrayKeys != 0)
309 ExprContext *stdecontext = indexstate->ss.ps.ps_ExprContext;
311 ExecAssignExprContext(estate, &indexstate->ss.ps);
312 indexstate->biss_RuntimeContext = indexstate->ss.ps.ps_ExprContext;
313 indexstate->ss.ps.ps_ExprContext = stdecontext;
317 indexstate->biss_RuntimeContext = NULL;
321 * Initialize scan descriptor.
323 indexstate->biss_ScanDesc =
324 index_beginscan_multi(indexstate->biss_RelationDesc,
326 indexstate->biss_NumScanKeys,
327 indexstate->biss_ScanKeys);
336 ExecCountSlotsBitmapIndexScan(BitmapIndexScan *node)
338 return ExecCountSlotsNode(outerPlan((Plan *) node)) +
339 ExecCountSlotsNode(innerPlan((Plan *) node)) + BITMAPINDEXSCAN_NSLOTS;