Age Owner 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-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 *
2092 andres 39 UBC 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 *
6564 tgl 50 CBC 8691 : MultiExecBitmapIndexScan(BitmapIndexScanState *node)
51 : {
52 : TIDBitmap *tbm;
53 : IndexScanDesc scandesc;
54 8691 : double nTuples = 0;
55 : bool doscan;
56 :
57 : /* must provide our own instrumentation support */
58 8691 : if (node->ss.ps.instrument)
59 219 : InstrStartNode(node->ss.ps.instrument);
60 :
61 : /*
62 : * extract necessary information from index scan node
63 : */
6548 64 8691 : 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 : */
6344 72 8691 : if (!node->biss_RuntimeKeysReady &&
73 6940 : (node->biss_NumRuntimeKeys != 0 || node->biss_NumArrayKeys != 0))
74 : {
4654 75 263 : ExecReScan((PlanState *) node);
6344 76 263 : doscan = node->biss_RuntimeKeysReady;
77 : }
78 : else
79 8428 : 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 : */
6563 87 8691 : if (node->biss_result)
88 : {
89 185 : tbm = node->biss_result;
2118 90 185 : node->biss_result = NULL; /* reset for next time */
91 : }
92 : else
93 : {
94 : /* XXX should we use less than work_mem for this? */
2223 rhaas 95 8506 : tbm = tbm_create(work_mem * 1024L,
96 8506 : ((BitmapIndexScan *) node->ss.ps.plan)->isshared ?
97 36 : node->ss.ps.state->es_query_dsa : NULL);
98 : }
99 :
100 : /*
101 : * Get TIDs from index and insert into bitmap
102 : */
6344 tgl 103 17394 : while (doscan)
104 : {
5477 105 8703 : nTuples += (double) index_getbitmap(scandesc, tbm);
106 :
6564 107 8703 : CHECK_FOR_INTERRUPTS();
108 :
5477 109 8703 : doscan = ExecIndexAdvanceArrayKeys(node->biss_ArrayKeys,
110 : node->biss_NumArrayKeys);
5050 bruce 111 8703 : if (doscan) /* reset index scan */
4511 tgl 112 12 : index_rescan(node->biss_ScanDesc,
113 12 : node->biss_ScanKeys, node->biss_NumScanKeys,
114 : NULL, 0);
115 : }
116 :
117 : /* must provide our own instrumentation support */
6564 118 8691 : if (node->ss.ps.instrument)
6158 bruce 119 219 : InstrStopNode(node->ss.ps.instrument, nTuples);
120 :
6564 tgl 121 8691 : 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
4654 132 2014 : ExecReScanBitmapIndexScan(BitmapIndexScanState *node)
133 : {
134 2014 : 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 : */
6564 141 2014 : if (econtext)
142 1906 : 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 : */
6344 152 2014 : if (node->biss_NumRuntimeKeys != 0)
6558 153 1894 : ExecIndexEvalRuntimeKeys(econtext,
154 : node->biss_RuntimeKeys,
155 : node->biss_NumRuntimeKeys);
6344 156 2014 : if (node->biss_NumArrayKeys != 0)
157 12 : node->biss_RuntimeKeysReady =
158 12 : ExecIndexEvalArrayKeys(econtext,
159 : node->biss_ArrayKeys,
160 : node->biss_NumArrayKeys);
161 : else
6564 162 2002 : node->biss_RuntimeKeysReady = true;
163 :
164 : /* reset index scan */
6344 165 2014 : if (node->biss_RuntimeKeysReady)
4511 166 2014 : index_rescan(node->biss_ScanDesc,
167 2014 : node->biss_ScanKeys, node->biss_NumScanKeys,
168 : NULL, 0);
6564 169 2014 : }
170 :
171 : /* ----------------------------------------------------------------
172 : * ExecEndBitmapIndexScan
173 : * ----------------------------------------------------------------
174 : */
175 : void
176 10743 : ExecEndBitmapIndexScan(BitmapIndexScanState *node)
177 : {
178 : Relation indexRelationDesc;
179 : IndexScanDesc indexScanDesc;
180 :
181 : /*
182 : * extract information from the node
183 : */
6548 184 10743 : indexRelationDesc = node->biss_RelationDesc;
185 10743 : 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 : */
5798 198 10743 : if (indexScanDesc)
199 9039 : index_endscan(indexScanDesc);
200 10743 : if (indexRelationDesc)
201 9039 : index_close(indexRelationDesc, NoLock);
6564 202 10743 : }
203 :
204 : /* ----------------------------------------------------------------
205 : * ExecInitBitmapIndexScan
206 : *
207 : * Initializes the index scan's state information.
208 : * ----------------------------------------------------------------
209 : */
210 : BitmapIndexScanState *
6249 211 10774 : ExecInitBitmapIndexScan(BitmapIndexScan *node, EState *estate, int eflags)
212 : {
213 : BitmapIndexScanState *indexstate;
214 : LOCKMODE lockmode;
215 :
216 : /* check for unsupported flags */
217 10774 : Assert(!(eflags & (EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK)));
218 :
219 : /*
220 : * create state structure
221 : */
6564 222 10774 : indexstate = makeNode(BitmapIndexScanState);
223 10774 : indexstate->ss.ps.plan = (Plan *) node;
224 10774 : indexstate->ss.ps.state = estate;
2092 andres 225 10774 : indexstate->ss.ps.ExecProcNode = ExecBitmapIndexScan;
226 :
227 : /* normally we don't make the result bitmap till runtime */
6563 tgl 228 10774 : 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 :
1878 andres 236 10774 : indexstate->ss.ss_currentRelation = NULL;
237 10774 : 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 : */
5798 tgl 260 10774 : if (eflags & EXEC_FLAG_EXPLAIN_ONLY)
261 1704 : return indexstate;
262 :
263 : /* Open the index relation. */
1466 264 9070 : lockmode = exec_rt_fetch(node->scan.scanrelid, estate)->rellockmode;
265 9070 : indexstate->biss_RelationDesc = index_open(node->indexid, lockmode);
266 :
267 : /*
268 : * Initialize index-specific scan state
269 : */
6564 270 9070 : indexstate->biss_RuntimeKeysReady = false;
4511 271 9070 : indexstate->biss_RuntimeKeys = NULL;
272 9070 : indexstate->biss_NumRuntimeKeys = 0;
273 :
274 : /*
275 : * build the index scan keys from the index qualification
276 : */
6344 277 9070 : ExecIndexBuildScanKeys((PlanState *) indexstate,
278 : indexstate->biss_RelationDesc,
279 : node->indexqual,
280 : false,
281 9070 : &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 9070 : if (indexstate->biss_NumRuntimeKeys != 0 ||
295 8428 : indexstate->biss_NumArrayKeys != 0)
6564 296 654 : {
297 654 : ExprContext *stdecontext = indexstate->ss.ps.ps_ExprContext;
298 :
299 654 : ExecAssignExprContext(estate, &indexstate->ss.ps);
300 654 : indexstate->biss_RuntimeContext = indexstate->ss.ps.ps_ExprContext;
301 654 : indexstate->ss.ps.ps_ExprContext = stdecontext;
302 : }
303 : else
304 : {
305 8416 : indexstate->biss_RuntimeContext = NULL;
306 : }
307 :
308 : /*
309 : * Initialize scan descriptor.
310 : */
6548 311 9070 : indexstate->biss_ScanDesc =
5477 312 9070 : 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 : */
4511 320 9070 : if (indexstate->biss_NumRuntimeKeys == 0 &&
321 8428 : indexstate->biss_NumArrayKeys == 0)
322 8416 : index_rescan(indexstate->biss_ScanDesc,
323 8416 : indexstate->biss_ScanKeys, indexstate->biss_NumScanKeys,
324 : NULL, 0);
325 :
326 : /*
327 : * all done.
328 : */
6564 329 9070 : return indexstate;
330 : }
|