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