Line data Source code
1 : /*-------------------------------------------------------------------------
2 : *
3 : * nodeBitmapIndexscan.c
4 : * Routines to support bitmapped index scans of relations
5 : *
6 : * Portions Copyright (c) 1996-2023, 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 0 : ExecBitmapIndexScan(PlanState *pstate)
40 : {
41 0 : elog(ERROR, "BitmapIndexScan node does not support ExecProcNode call convention");
42 : return NULL;
43 : }
44 :
45 : /* ----------------------------------------------------------------
46 : * MultiExecBitmapIndexScan(node)
47 : * ----------------------------------------------------------------
48 : */
49 : Node *
50 16520 : MultiExecBitmapIndexScan(BitmapIndexScanState *node)
51 : {
52 : TIDBitmap *tbm;
53 : IndexScanDesc scandesc;
54 16520 : double nTuples = 0;
55 : bool doscan;
56 :
57 : /* must provide our own instrumentation support */
58 16520 : if (node->ss.ps.instrument)
59 492 : InstrStartNode(node->ss.ps.instrument);
60 :
61 : /*
62 : * extract necessary information from index scan node
63 : */
64 16520 : 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 16520 : if (!node->biss_RuntimeKeysReady &&
73 12058 : (node->biss_NumRuntimeKeys != 0 || node->biss_NumArrayKeys != 0))
74 : {
75 524 : ExecReScan((PlanState *) node);
76 524 : doscan = node->biss_RuntimeKeysReady;
77 : }
78 : else
79 15996 : 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 16520 : if (node->biss_result)
88 : {
89 442 : tbm = node->biss_result;
90 442 : node->biss_result = NULL; /* reset for next time */
91 : }
92 : else
93 : {
94 : /* XXX should we use less than work_mem for this? */
95 16078 : tbm = tbm_create(work_mem * 1024L,
96 16078 : ((BitmapIndexScan *) node->ss.ps.plan)->isshared ?
97 72 : node->ss.ps.state->es_query_dsa : NULL);
98 : }
99 :
100 : /*
101 : * Get TIDs from index and insert into bitmap
102 : */
103 33066 : while (doscan)
104 : {
105 16546 : nTuples += (double) index_getbitmap(scandesc, tbm);
106 :
107 16546 : CHECK_FOR_INTERRUPTS();
108 :
109 16546 : doscan = ExecIndexAdvanceArrayKeys(node->biss_ArrayKeys,
110 : node->biss_NumArrayKeys);
111 16546 : if (doscan) /* reset index scan */
112 26 : index_rescan(node->biss_ScanDesc,
113 26 : node->biss_ScanKeys, node->biss_NumScanKeys,
114 : NULL, 0);
115 : }
116 :
117 : /* must provide our own instrumentation support */
118 16520 : if (node->ss.ps.instrument)
119 492 : InstrStopNode(node->ss.ps.instrument, nTuples);
120 :
121 16520 : 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 4986 : ExecReScanBitmapIndexScan(BitmapIndexScanState *node)
133 : {
134 4986 : 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 4986 : if (econtext)
142 4740 : 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 4986 : if (node->biss_NumRuntimeKeys != 0)
153 4714 : ExecIndexEvalRuntimeKeys(econtext,
154 : node->biss_RuntimeKeys,
155 : node->biss_NumRuntimeKeys);
156 4986 : if (node->biss_NumArrayKeys != 0)
157 26 : node->biss_RuntimeKeysReady =
158 26 : ExecIndexEvalArrayKeys(econtext,
159 : node->biss_ArrayKeys,
160 : node->biss_NumArrayKeys);
161 : else
162 4960 : node->biss_RuntimeKeysReady = true;
163 :
164 : /* reset index scan */
165 4986 : if (node->biss_RuntimeKeysReady)
166 4986 : index_rescan(node->biss_ScanDesc,
167 4986 : node->biss_ScanKeys, node->biss_NumScanKeys,
168 : NULL, 0);
169 4986 : }
170 :
171 : /* ----------------------------------------------------------------
172 : * ExecEndBitmapIndexScan
173 : * ----------------------------------------------------------------
174 : */
175 : void
176 17056 : ExecEndBitmapIndexScan(BitmapIndexScanState *node)
177 : {
178 : Relation indexRelationDesc;
179 : IndexScanDesc indexScanDesc;
180 :
181 : /*
182 : * extract information from the node
183 : */
184 17056 : indexRelationDesc = node->biss_RelationDesc;
185 17056 : indexScanDesc = node->biss_ScanDesc;
186 :
187 : /*
188 : * close the index relation (no-op if we didn't open it)
189 : */
190 17056 : if (indexScanDesc)
191 13636 : index_endscan(indexScanDesc);
192 17056 : if (indexRelationDesc)
193 13636 : index_close(indexRelationDesc, NoLock);
194 17056 : }
195 :
196 : /* ----------------------------------------------------------------
197 : * ExecInitBitmapIndexScan
198 : *
199 : * Initializes the index scan's state information.
200 : * ----------------------------------------------------------------
201 : */
202 : BitmapIndexScanState *
203 17122 : ExecInitBitmapIndexScan(BitmapIndexScan *node, EState *estate, int eflags)
204 : {
205 : BitmapIndexScanState *indexstate;
206 : LOCKMODE lockmode;
207 :
208 : /* check for unsupported flags */
209 : Assert(!(eflags & (EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK)));
210 :
211 : /*
212 : * create state structure
213 : */
214 17122 : indexstate = makeNode(BitmapIndexScanState);
215 17122 : indexstate->ss.ps.plan = (Plan *) node;
216 17122 : indexstate->ss.ps.state = estate;
217 17122 : indexstate->ss.ps.ExecProcNode = ExecBitmapIndexScan;
218 :
219 : /* normally we don't make the result bitmap till runtime */
220 17122 : indexstate->biss_result = NULL;
221 :
222 : /*
223 : * We do not open or lock the base relation here. We assume that an
224 : * ancestor BitmapHeapScan node is holding AccessShareLock (or better) on
225 : * the heap relation throughout the execution of the plan tree.
226 : */
227 :
228 17122 : indexstate->ss.ss_currentRelation = NULL;
229 17122 : indexstate->ss.ss_currentScanDesc = NULL;
230 :
231 : /*
232 : * Miscellaneous initialization
233 : *
234 : * We do not need a standard exprcontext for this node, though we may
235 : * decide below to create a runtime-key exprcontext
236 : */
237 :
238 : /*
239 : * initialize child expressions
240 : *
241 : * We don't need to initialize targetlist or qual since neither are used.
242 : *
243 : * Note: we don't initialize all of the indexqual expression, only the
244 : * sub-parts corresponding to runtime keys (see below).
245 : */
246 :
247 : /*
248 : * If we are just doing EXPLAIN (ie, aren't going to run the plan), stop
249 : * here. This allows an index-advisor plugin to EXPLAIN a plan containing
250 : * references to nonexistent indexes.
251 : */
252 17122 : if (eflags & EXEC_FLAG_EXPLAIN_ONLY)
253 3420 : return indexstate;
254 :
255 : /* Open the index relation. */
256 13702 : lockmode = exec_rt_fetch(node->scan.scanrelid, estate)->rellockmode;
257 13702 : indexstate->biss_RelationDesc = index_open(node->indexid, lockmode);
258 :
259 : /*
260 : * Initialize index-specific scan state
261 : */
262 13702 : indexstate->biss_RuntimeKeysReady = false;
263 13702 : indexstate->biss_RuntimeKeys = NULL;
264 13702 : indexstate->biss_NumRuntimeKeys = 0;
265 :
266 : /*
267 : * build the index scan keys from the index qualification
268 : */
269 13702 : ExecIndexBuildScanKeys((PlanState *) indexstate,
270 : indexstate->biss_RelationDesc,
271 : node->indexqual,
272 : false,
273 13702 : &indexstate->biss_ScanKeys,
274 : &indexstate->biss_NumScanKeys,
275 : &indexstate->biss_RuntimeKeys,
276 : &indexstate->biss_NumRuntimeKeys,
277 : &indexstate->biss_ArrayKeys,
278 : &indexstate->biss_NumArrayKeys);
279 :
280 : /*
281 : * If we have runtime keys or array keys, we need an ExprContext to
282 : * evaluate them. We could just create a "standard" plan node exprcontext,
283 : * but to keep the code looking similar to nodeIndexscan.c, it seems
284 : * better to stick with the approach of using a separate ExprContext.
285 : */
286 13702 : if (indexstate->biss_NumRuntimeKeys != 0 ||
287 12372 : indexstate->biss_NumArrayKeys != 0)
288 1356 : {
289 1356 : ExprContext *stdecontext = indexstate->ss.ps.ps_ExprContext;
290 :
291 1356 : ExecAssignExprContext(estate, &indexstate->ss.ps);
292 1356 : indexstate->biss_RuntimeContext = indexstate->ss.ps.ps_ExprContext;
293 1356 : indexstate->ss.ps.ps_ExprContext = stdecontext;
294 : }
295 : else
296 : {
297 12346 : indexstate->biss_RuntimeContext = NULL;
298 : }
299 :
300 : /*
301 : * Initialize scan descriptor.
302 : */
303 13702 : indexstate->biss_ScanDesc =
304 13702 : index_beginscan_bitmap(indexstate->biss_RelationDesc,
305 : estate->es_snapshot,
306 : indexstate->biss_NumScanKeys);
307 :
308 : /*
309 : * If no run-time keys to calculate, go ahead and pass the scankeys to the
310 : * index AM.
311 : */
312 13702 : if (indexstate->biss_NumRuntimeKeys == 0 &&
313 12372 : indexstate->biss_NumArrayKeys == 0)
314 12346 : index_rescan(indexstate->biss_ScanDesc,
315 12346 : indexstate->biss_ScanKeys, indexstate->biss_NumScanKeys,
316 : NULL, 0);
317 :
318 : /*
319 : * all done.
320 : */
321 13702 : return indexstate;
322 : }
|