1 /*-------------------------------------------------------------------------
2 *
3 * nodeBitmapIndexscan.c
4 * Routines to support bitmapped index scans of relations
5 *
6 * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
8 *
9 *
10 * IDENTIFICATION
11 * src/backend/executor/nodeBitmapIndexscan.c
12 *
13 *-------------------------------------------------------------------------
14 */
15 /*
16 * INTERFACE ROUTINES
17 * MultiExecBitmapIndexScan scans a relation using index.
18 * ExecInitBitmapIndexScan creates and initializes state info.
19 * ExecReScanBitmapIndexScan prepares to rescan the plan.
20 * ExecEndBitmapIndexScan releases all storage.
21 */
22 #include "postgres.h"
23
24 #include "executor/execdebug.h"
25 #include "executor/nodeBitmapIndexscan.h"
26 #include "executor/nodeIndexscan.h"
27 #include "miscadmin.h"
28 #include "utils/memutils.h"
29
30
31 /* ----------------------------------------------------------------
32 * MultiExecBitmapIndexScan(node)
33 * ----------------------------------------------------------------
34 */
35 Node *
MultiExecBitmapIndexScan(BitmapIndexScanState * node)36 MultiExecBitmapIndexScan(BitmapIndexScanState *node)
37 {
38 TIDBitmap *tbm;
39 IndexScanDesc scandesc;
40 double nTuples = 0;
41 bool doscan;
42
43 /* must provide our own instrumentation support */
44 if (node->ss.ps.instrument)
45 InstrStartNode(node->ss.ps.instrument);
46
47 /*
48 * extract necessary information from index scan node
49 */
50 scandesc = node->biss_ScanDesc;
51
52 /*
53 * If we have runtime keys and they've not already been set up, do it now.
54 * Array keys are also treated as runtime keys; note that if ExecReScan
55 * returns with biss_RuntimeKeysReady still false, then there is an empty
56 * array key so we should do nothing.
57 */
58 if (!node->biss_RuntimeKeysReady &&
59 (node->biss_NumRuntimeKeys != 0 || node->biss_NumArrayKeys != 0))
60 {
61 ExecReScan((PlanState *) node);
62 doscan = node->biss_RuntimeKeysReady;
63 }
64 else
65 doscan = true;
66
67 /*
68 * Prepare the result bitmap. Normally we just create a new one to pass
69 * back; however, our parent node is allowed to store a pre-made one into
70 * node->biss_result, in which case we just OR our tuple IDs into the
71 * existing bitmap. (This saves needing explicit UNION steps.)
72 */
73 if (node->biss_result)
74 {
75 tbm = node->biss_result;
76 node->biss_result = NULL; /* reset for next time */
77 }
78 else
79 {
80 /* XXX should we use less than work_mem for this? */
81 tbm = tbm_create(work_mem * 1024L);
82 }
83
84 /*
85 * Get TIDs from index and insert into bitmap
86 */
87 while (doscan)
88 {
89 nTuples += (double) index_getbitmap(scandesc, tbm);
90
91 CHECK_FOR_INTERRUPTS();
92
93 doscan = ExecIndexAdvanceArrayKeys(node->biss_ArrayKeys,
94 node->biss_NumArrayKeys);
95 if (doscan) /* reset index scan */
96 index_rescan(node->biss_ScanDesc,
97 node->biss_ScanKeys, node->biss_NumScanKeys,
98 NULL, 0);
99 }
100
101 /* must provide our own instrumentation support */
102 if (node->ss.ps.instrument)
103 InstrStopNode(node->ss.ps.instrument, nTuples);
104
105 return (Node *) tbm;
106 }
107
108 /* ----------------------------------------------------------------
109 * ExecReScanBitmapIndexScan(node)
110 *
111 * Recalculates the values of any scan keys whose value depends on
112 * information known at runtime, then rescans the indexed relation.
113 * ----------------------------------------------------------------
114 */
115 void
ExecReScanBitmapIndexScan(BitmapIndexScanState * node)116 ExecReScanBitmapIndexScan(BitmapIndexScanState *node)
117 {
118 ExprContext *econtext = node->biss_RuntimeContext;
119
120 /*
121 * Reset the runtime-key context so we don't leak memory as each outer
122 * tuple is scanned. Note this assumes that we will recalculate *all*
123 * runtime keys on each call.
124 */
125 if (econtext)
126 ResetExprContext(econtext);
127
128 /*
129 * If we are doing runtime key calculations (ie, any of the index key
130 * values weren't simple Consts), compute the new key values.
131 *
132 * Array keys are also treated as runtime keys; note that if we return
133 * with biss_RuntimeKeysReady still false, then there is an empty array
134 * key so no index scan is needed.
135 */
136 if (node->biss_NumRuntimeKeys != 0)
137 ExecIndexEvalRuntimeKeys(econtext,
138 node->biss_RuntimeKeys,
139 node->biss_NumRuntimeKeys);
140 if (node->biss_NumArrayKeys != 0)
141 node->biss_RuntimeKeysReady =
142 ExecIndexEvalArrayKeys(econtext,
143 node->biss_ArrayKeys,
144 node->biss_NumArrayKeys);
145 else
146 node->biss_RuntimeKeysReady = true;
147
148 /* reset index scan */
149 if (node->biss_RuntimeKeysReady)
150 index_rescan(node->biss_ScanDesc,
151 node->biss_ScanKeys, node->biss_NumScanKeys,
152 NULL, 0);
153 }
154
155 /* ----------------------------------------------------------------
156 * ExecEndBitmapIndexScan
157 * ----------------------------------------------------------------
158 */
159 void
ExecEndBitmapIndexScan(BitmapIndexScanState * node)160 ExecEndBitmapIndexScan(BitmapIndexScanState *node)
161 {
162 Relation indexRelationDesc;
163 IndexScanDesc indexScanDesc;
164
165 /*
166 * extract information from the node
167 */
168 indexRelationDesc = node->biss_RelationDesc;
169 indexScanDesc = node->biss_ScanDesc;
170
171 /*
172 * Free the exprcontext ... now dead code, see ExecFreeExprContext
173 */
174 #ifdef NOT_USED
175 if (node->biss_RuntimeContext)
176 FreeExprContext(node->biss_RuntimeContext, true);
177 #endif
178
179 /*
180 * close the index relation (no-op if we didn't open it)
181 */
182 if (indexScanDesc)
183 index_endscan(indexScanDesc);
184 if (indexRelationDesc)
185 index_close(indexRelationDesc, NoLock);
186 }
187
188 /* ----------------------------------------------------------------
189 * ExecInitBitmapIndexScan
190 *
191 * Initializes the index scan's state information.
192 * ----------------------------------------------------------------
193 */
194 BitmapIndexScanState *
ExecInitBitmapIndexScan(BitmapIndexScan * node,EState * estate,int eflags)195 ExecInitBitmapIndexScan(BitmapIndexScan *node, EState *estate, int eflags)
196 {
197 BitmapIndexScanState *indexstate;
198 bool relistarget;
199
200 /* check for unsupported flags */
201 Assert(!(eflags & (EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK)));
202
203 /*
204 * create state structure
205 */
206 indexstate = makeNode(BitmapIndexScanState);
207 indexstate->ss.ps.plan = (Plan *) node;
208 indexstate->ss.ps.state = estate;
209
210 /* normally we don't make the result bitmap till runtime */
211 indexstate->biss_result = NULL;
212
213 /*
214 * Miscellaneous initialization
215 *
216 * We do not need a standard exprcontext for this node, though we may
217 * decide below to create a runtime-key exprcontext
218 */
219
220 /*
221 * initialize child expressions
222 *
223 * We don't need to initialize targetlist or qual since neither are used.
224 *
225 * Note: we don't initialize all of the indexqual expression, only the
226 * sub-parts corresponding to runtime keys (see below).
227 */
228
229 /*
230 * We do not open or lock the base relation here. We assume that an
231 * ancestor BitmapHeapScan node is holding AccessShareLock (or better) on
232 * the heap relation throughout the execution of the plan tree.
233 */
234
235 indexstate->ss.ss_currentRelation = NULL;
236 indexstate->ss.ss_currentScanDesc = NULL;
237
238 /*
239 * If we are just doing EXPLAIN (ie, aren't going to run the plan), stop
240 * here. This allows an index-advisor plugin to EXPLAIN a plan containing
241 * references to nonexistent indexes.
242 */
243 if (eflags & EXEC_FLAG_EXPLAIN_ONLY)
244 return indexstate;
245
246 /*
247 * Open the index relation.
248 *
249 * If the parent table is one of the target relations of the query, then
250 * InitPlan already opened and write-locked the index, so we can avoid
251 * taking another lock here. Otherwise we need a normal reader's lock.
252 */
253 relistarget = ExecRelationIsTargetRelation(estate, node->scan.scanrelid);
254 indexstate->biss_RelationDesc = index_open(node->indexid,
255 relistarget ? NoLock : AccessShareLock);
256
257 /*
258 * Initialize index-specific scan state
259 */
260 indexstate->biss_RuntimeKeysReady = false;
261 indexstate->biss_RuntimeKeys = NULL;
262 indexstate->biss_NumRuntimeKeys = 0;
263
264 /*
265 * build the index scan keys from the index qualification
266 */
267 ExecIndexBuildScanKeys((PlanState *) indexstate,
268 indexstate->biss_RelationDesc,
269 node->indexqual,
270 false,
271 &indexstate->biss_ScanKeys,
272 &indexstate->biss_NumScanKeys,
273 &indexstate->biss_RuntimeKeys,
274 &indexstate->biss_NumRuntimeKeys,
275 &indexstate->biss_ArrayKeys,
276 &indexstate->biss_NumArrayKeys);
277
278 /*
279 * If we have runtime keys or array keys, we need an ExprContext to
280 * evaluate them. We could just create a "standard" plan node exprcontext,
281 * but to keep the code looking similar to nodeIndexscan.c, it seems
282 * better to stick with the approach of using a separate ExprContext.
283 */
284 if (indexstate->biss_NumRuntimeKeys != 0 ||
285 indexstate->biss_NumArrayKeys != 0)
286 {
287 ExprContext *stdecontext = indexstate->ss.ps.ps_ExprContext;
288
289 ExecAssignExprContext(estate, &indexstate->ss.ps);
290 indexstate->biss_RuntimeContext = indexstate->ss.ps.ps_ExprContext;
291 indexstate->ss.ps.ps_ExprContext = stdecontext;
292 }
293 else
294 {
295 indexstate->biss_RuntimeContext = NULL;
296 }
297
298 /*
299 * Initialize scan descriptor.
300 */
301 indexstate->biss_ScanDesc =
302 index_beginscan_bitmap(indexstate->biss_RelationDesc,
303 estate->es_snapshot,
304 indexstate->biss_NumScanKeys);
305
306 /*
307 * If no run-time keys to calculate, go ahead and pass the scankeys to the
308 * index AM.
309 */
310 if (indexstate->biss_NumRuntimeKeys == 0 &&
311 indexstate->biss_NumArrayKeys == 0)
312 index_rescan(indexstate->biss_ScanDesc,
313 indexstate->biss_ScanKeys, indexstate->biss_NumScanKeys,
314 NULL, 0);
315
316 /*
317 * all done.
318 */
319 return indexstate;
320 }
321