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 */
38static TupleTableSlot *
39ExecBitmapIndexScan(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 */
49Node *
50MultiExecBitmapIndexScan(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 */
131void
132ExecReScanBitmapIndexScan(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 */
175void
176ExecEndBitmapIndexScan(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 */
210BitmapIndexScanState *
211ExecInitBitmapIndexScan(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