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