Age Owner Branch data TLA 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 *
2463 andres@anarazel.de 38 :UBC 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 *
6935 tgl@sss.pgh.pa.us 49 :CBC 9352 : MultiExecBitmapIndexScan(BitmapIndexScanState *node)
50 : : {
51 : : TIDBitmap *tbm;
52 : : IndexScanDesc scandesc;
53 : 9352 : double nTuples = 0;
54 : : bool doscan;
55 : :
56 : : /* must provide our own instrumentation support */
57 [ + + ]: 9352 : if (node->ss.ps.instrument)
58 : 246 : InstrStartNode(node->ss.ps.instrument);
59 : :
60 : : /*
61 : : * extract necessary information from index scan node
62 : : */
6919 63 : 9352 : 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 : : */
6715 71 [ + + ]: 9352 : if (!node->biss_RuntimeKeysReady &&
72 [ + + + + ]: 7050 : (node->biss_NumRuntimeKeys != 0 || node->biss_NumArrayKeys != 0))
73 : : {
5025 74 : 284 : ExecReScan((PlanState *) node);
6715 75 : 284 : doscan = node->biss_RuntimeKeysReady;
76 : : }
77 : : else
78 : 9068 : 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 : : */
6934 86 [ + + ]: 9352 : if (node->biss_result)
87 : : {
88 : 245 : tbm = node->biss_result;
2489 89 : 245 : node->biss_result = NULL; /* reset for next time */
90 : : }
91 : : else
92 : : {
93 : : /* XXX should we use less than work_mem for this? */
2594 rhaas@postgresql.org 94 : 9107 : tbm = tbm_create(work_mem * 1024L,
95 [ + + ]: 9107 : ((BitmapIndexScan *) node->ss.ps.plan)->isshared ?
96 : 36 : node->ss.ps.state->es_query_dsa : NULL);
97 : : }
98 : :
99 : : /*
100 : : * Get TIDs from index and insert into bitmap
101 : : */
6715 tgl@sss.pgh.pa.us 102 [ + + ]: 18717 : while (doscan)
103 : : {
5848 104 : 9365 : nTuples += (double) index_getbitmap(scandesc, tbm);
105 : :
6935 106 [ - + ]: 9365 : CHECK_FOR_INTERRUPTS();
107 : :
5848 108 : 9365 : doscan = ExecIndexAdvanceArrayKeys(node->biss_ArrayKeys,
109 : : node->biss_NumArrayKeys);
5421 bruce@momjian.us 110 [ + + ]: 9365 : if (doscan) /* reset index scan */
4882 tgl@sss.pgh.pa.us 111 : 13 : index_rescan(node->biss_ScanDesc,
112 : 13 : node->biss_ScanKeys, node->biss_NumScanKeys,
113 : : NULL, 0);
114 : : }
115 : :
116 : : /* must provide our own instrumentation support */
6935 117 [ + + ]: 9352 : if (node->ss.ps.instrument)
6529 bruce@momjian.us 118 : 246 : InstrStopNode(node->ss.ps.instrument, nTuples);
119 : :
6935 tgl@sss.pgh.pa.us 120 : 9352 : 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
5025 131 : 2586 : ExecReScanBitmapIndexScan(BitmapIndexScanState *node)
132 : : {
133 : 2586 : 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 : : */
6935 140 [ + + ]: 2586 : if (econtext)
141 : 2449 : 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 : : */
6715 151 [ + + ]: 2586 : if (node->biss_NumRuntimeKeys != 0)
6929 152 : 2436 : ExecIndexEvalRuntimeKeys(econtext,
153 : : node->biss_RuntimeKeys,
154 : : node->biss_NumRuntimeKeys);
6715 155 [ + + ]: 2586 : if (node->biss_NumArrayKeys != 0)
156 : 13 : node->biss_RuntimeKeysReady =
157 : 13 : ExecIndexEvalArrayKeys(econtext,
158 : : node->biss_ArrayKeys,
159 : : node->biss_NumArrayKeys);
160 : : else
6935 161 : 2573 : node->biss_RuntimeKeysReady = true;
162 : :
163 : : /* reset index scan */
6715 164 [ + - ]: 2586 : if (node->biss_RuntimeKeysReady)
4882 165 : 2586 : index_rescan(node->biss_ScanDesc,
166 : 2586 : node->biss_ScanKeys, node->biss_NumScanKeys,
167 : : NULL, 0);
6935 168 : 2586 : }
169 : :
170 : : /* ----------------------------------------------------------------
171 : : * ExecEndBitmapIndexScan
172 : : * ----------------------------------------------------------------
173 : : */
174 : : void
175 : 9671 : ExecEndBitmapIndexScan(BitmapIndexScanState *node)
176 : : {
177 : : Relation indexRelationDesc;
178 : : IndexScanDesc indexScanDesc;
179 : :
180 : : /*
181 : : * extract information from the node
182 : : */
6919 183 : 9671 : indexRelationDesc = node->biss_RelationDesc;
184 : 9671 : indexScanDesc = node->biss_ScanDesc;
185 : :
186 : : /*
187 : : * close the index relation (no-op if we didn't open it)
188 : : */
6169 189 [ + + ]: 9671 : if (indexScanDesc)
190 : 7940 : index_endscan(indexScanDesc);
191 [ + + ]: 9671 : if (indexRelationDesc)
192 : 7940 : index_close(indexRelationDesc, NoLock);
6935 193 : 9671 : }
194 : :
195 : : /* ----------------------------------------------------------------
196 : : * ExecInitBitmapIndexScan
197 : : *
198 : : * Initializes the index scan's state information.
199 : : * ----------------------------------------------------------------
200 : : */
201 : : BitmapIndexScanState *
6620 202 : 9718 : ExecInitBitmapIndexScan(BitmapIndexScan *node, EState *estate, int eflags)
203 : : {
204 : : BitmapIndexScanState *indexstate;
205 : : LOCKMODE lockmode;
206 : :
207 : : /* check for unsupported flags */
208 [ - + ]: 9718 : Assert(!(eflags & (EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK)));
209 : :
210 : : /*
211 : : * create state structure
212 : : */
6935 213 : 9718 : indexstate = makeNode(BitmapIndexScanState);
214 : 9718 : indexstate->ss.ps.plan = (Plan *) node;
215 : 9718 : indexstate->ss.ps.state = estate;
2463 andres@anarazel.de 216 : 9718 : indexstate->ss.ps.ExecProcNode = ExecBitmapIndexScan;
217 : :
218 : : /* normally we don't make the result bitmap till runtime */
6934 tgl@sss.pgh.pa.us 219 : 9718 : 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 : :
2249 andres@anarazel.de 227 : 9718 : indexstate->ss.ss_currentRelation = NULL;
228 : 9718 : 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 : : */
6169 tgl@sss.pgh.pa.us 251 [ + + ]: 9718 : if (eflags & EXEC_FLAG_EXPLAIN_ONLY)
252 : 1731 : return indexstate;
253 : :
254 : : /* Open the index relation. */
1837 255 : 7987 : lockmode = exec_rt_fetch(node->scan.scanrelid, estate)->rellockmode;
256 : 7987 : indexstate->biss_RelationDesc = index_open(node->indexid, lockmode);
257 : :
258 : : /*
259 : : * Initialize index-specific scan state
260 : : */
6935 261 : 7987 : indexstate->biss_RuntimeKeysReady = false;
4882 262 : 7987 : indexstate->biss_RuntimeKeys = NULL;
263 : 7987 : indexstate->biss_NumRuntimeKeys = 0;
264 : :
265 : : /*
266 : : * build the index scan keys from the index qualification
267 : : */
6715 268 : 7987 : ExecIndexBuildScanKeys((PlanState *) indexstate,
269 : : indexstate->biss_RelationDesc,
270 : : node->indexqual,
271 : : false,
272 : 7987 : &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 [ + + ]: 7987 : if (indexstate->biss_NumRuntimeKeys != 0 ||
286 [ + + ]: 7255 : indexstate->biss_NumArrayKeys != 0)
6935 287 : 745 : {
288 : 745 : ExprContext *stdecontext = indexstate->ss.ps.ps_ExprContext;
289 : :
290 : 745 : ExecAssignExprContext(estate, &indexstate->ss.ps);
291 : 745 : indexstate->biss_RuntimeContext = indexstate->ss.ps.ps_ExprContext;
292 : 745 : indexstate->ss.ps.ps_ExprContext = stdecontext;
293 : : }
294 : : else
295 : : {
296 : 7242 : indexstate->biss_RuntimeContext = NULL;
297 : : }
298 : :
299 : : /*
300 : : * Initialize scan descriptor.
301 : : */
6919 302 : 7987 : indexstate->biss_ScanDesc =
5848 303 : 7987 : 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 : : */
4882 311 [ + + ]: 7987 : if (indexstate->biss_NumRuntimeKeys == 0 &&
312 [ + + ]: 7255 : indexstate->biss_NumArrayKeys == 0)
313 : 7242 : index_rescan(indexstate->biss_ScanDesc,
314 : 7242 : indexstate->biss_ScanKeys, indexstate->biss_NumScanKeys,
315 : : NULL, 0);
316 : :
317 : : /*
318 : : * all done.
319 : : */
6935 320 : 7987 : return indexstate;
321 : : }
|