Line data Source code
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 *
38 0 : ExecBitmapIndexScan(PlanState *pstate)
39 : {
40 0 : elog(ERROR, "BitmapIndexScan node does not support ExecProcNode call convention");
41 : return NULL;
42 : }
43 :
44 : /* ----------------------------------------------------------------
45 : * MultiExecBitmapIndexScan(node)
46 : * ----------------------------------------------------------------
47 : */
48 : Node *
49 1113 : MultiExecBitmapIndexScan(BitmapIndexScanState *node)
50 : {
51 : TIDBitmap *tbm;
52 : IndexScanDesc scandesc;
53 1113 : double nTuples = 0;
54 : bool doscan;
55 :
56 : /* must provide our own instrumentation support */
57 1113 : if (node->ss.ps.instrument)
58 0 : InstrStartNode(node->ss.ps.instrument);
59 :
60 : /*
61 : * extract necessary information from index scan node
62 : */
63 1113 : 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 2093 : if (!node->biss_RuntimeKeysReady &&
72 1907 : (node->biss_NumRuntimeKeys != 0 || node->biss_NumArrayKeys != 0))
73 : {
74 55 : ExecReScan((PlanState *) node);
75 55 : doscan = node->biss_RuntimeKeysReady;
76 : }
77 : else
78 1058 : 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 1113 : if (node->biss_result)
87 : {
88 17 : tbm = node->biss_result;
89 17 : node->biss_result = NULL; /* reset for next time */
90 : }
91 : else
92 : {
93 : /* XXX should we use less than work_mem for this? */
94 1107 : tbm = tbm_create(work_mem * 1024L,
95 1096 : ((BitmapIndexScan *) node->ss.ps.plan)->isshared ?
96 11 : node->ss.ps.state->es_query_dsa : NULL);
97 : }
98 :
99 : /*
100 : * Get TIDs from index and insert into bitmap
101 : */
102 3341 : while (doscan)
103 : {
104 1115 : nTuples += (double) index_getbitmap(scandesc, tbm);
105 :
106 1115 : CHECK_FOR_INTERRUPTS();
107 :
108 1115 : doscan = ExecIndexAdvanceArrayKeys(node->biss_ArrayKeys,
109 : node->biss_NumArrayKeys);
110 1115 : if (doscan) /* reset index scan */
111 2 : 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 1113 : if (node->ss.ps.instrument)
118 0 : InstrStopNode(node->ss.ps.instrument, nTuples);
119 :
120 1113 : 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
131 188 : ExecReScanBitmapIndexScan(BitmapIndexScanState *node)
132 : {
133 188 : 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 188 : if (econtext)
141 160 : 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 188 : if (node->biss_NumRuntimeKeys != 0)
152 158 : ExecIndexEvalRuntimeKeys(econtext,
153 : node->biss_RuntimeKeys,
154 : node->biss_NumRuntimeKeys);
155 188 : if (node->biss_NumArrayKeys != 0)
156 2 : node->biss_RuntimeKeysReady =
157 2 : ExecIndexEvalArrayKeys(econtext,
158 : node->biss_ArrayKeys,
159 : node->biss_NumArrayKeys);
160 : else
161 186 : node->biss_RuntimeKeysReady = true;
162 :
163 : /* reset index scan */
164 188 : if (node->biss_RuntimeKeysReady)
165 188 : index_rescan(node->biss_ScanDesc,
166 : node->biss_ScanKeys, node->biss_NumScanKeys,
167 : NULL, 0);
168 188 : }
169 :
170 : /* ----------------------------------------------------------------
171 : * ExecEndBitmapIndexScan
172 : * ----------------------------------------------------------------
173 : */
174 : void
175 1653 : ExecEndBitmapIndexScan(BitmapIndexScanState *node)
176 : {
177 : Relation indexRelationDesc;
178 : IndexScanDesc indexScanDesc;
179 :
180 : /*
181 : * extract information from the node
182 : */
183 1653 : indexRelationDesc = node->biss_RelationDesc;
184 1653 : 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 1653 : if (indexScanDesc)
198 1326 : index_endscan(indexScanDesc);
199 1653 : if (indexRelationDesc)
200 1326 : index_close(indexRelationDesc, NoLock);
201 1653 : }
202 :
203 : /* ----------------------------------------------------------------
204 : * ExecInitBitmapIndexScan
205 : *
206 : * Initializes the index scan's state information.
207 : * ----------------------------------------------------------------
208 : */
209 : BitmapIndexScanState *
210 1657 : ExecInitBitmapIndexScan(BitmapIndexScan *node, EState *estate, int eflags)
211 : {
212 : BitmapIndexScanState *indexstate;
213 : bool relistarget;
214 :
215 : /* check for unsupported flags */
216 1657 : Assert(!(eflags & (EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK)));
217 :
218 : /*
219 : * create state structure
220 : */
221 1657 : indexstate = makeNode(BitmapIndexScanState);
222 1657 : indexstate->ss.ps.plan = (Plan *) node;
223 1657 : indexstate->ss.ps.state = estate;
224 1657 : indexstate->ss.ps.ExecProcNode = ExecBitmapIndexScan;
225 :
226 : /* normally we don't make the result bitmap till runtime */
227 1657 : 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 1657 : indexstate->ss.ss_currentRelation = NULL;
252 1657 : 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 1657 : if (eflags & EXEC_FLAG_EXPLAIN_ONLY)
260 327 : 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 1330 : relistarget = ExecRelationIsTargetRelation(estate, node->scan.scanrelid);
270 1330 : indexstate->biss_RelationDesc = index_open(node->indexid,
271 : relistarget ? NoLock : AccessShareLock);
272 :
273 : /*
274 : * Initialize index-specific scan state
275 : */
276 1330 : indexstate->biss_RuntimeKeysReady = false;
277 1330 : indexstate->biss_RuntimeKeys = NULL;
278 1330 : indexstate->biss_NumRuntimeKeys = 0;
279 :
280 : /*
281 : * build the index scan keys from the index qualification
282 : */
283 1330 : 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 2582 : if (indexstate->biss_NumRuntimeKeys != 0 ||
301 1252 : indexstate->biss_NumArrayKeys != 0)
302 80 : {
303 80 : ExprContext *stdecontext = indexstate->ss.ps.ps_ExprContext;
304 :
305 80 : ExecAssignExprContext(estate, &indexstate->ss.ps);
306 80 : indexstate->biss_RuntimeContext = indexstate->ss.ps.ps_ExprContext;
307 80 : indexstate->ss.ps.ps_ExprContext = stdecontext;
308 : }
309 : else
310 : {
311 1250 : indexstate->biss_RuntimeContext = NULL;
312 : }
313 :
314 : /*
315 : * Initialize scan descriptor.
316 : */
317 1330 : indexstate->biss_ScanDesc =
318 1330 : 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 2582 : if (indexstate->biss_NumRuntimeKeys == 0 &&
327 1252 : indexstate->biss_NumArrayKeys == 0)
328 1250 : index_rescan(indexstate->biss_ScanDesc,
329 : indexstate->biss_ScanKeys, indexstate->biss_NumScanKeys,
330 : NULL, 0);
331 :
332 : /*
333 : * all done.
334 : */
335 1330 : return indexstate;
336 : }
|