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