PostgreSQL Source Code  git master
nodeBitmapIndexscan.c
Go to the documentation of this file.
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"
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 *
39 {
40  elog(ERROR, "BitmapIndexScan node does not support ExecProcNode call convention");
41  return NULL;
42 }
43 
44 /* ----------------------------------------------------------------
45  * MultiExecBitmapIndexScan(node)
46  * ----------------------------------------------------------------
47  */
48 Node *
50 {
51  TIDBitmap *tbm;
52  IndexScanDesc scandesc;
53  double nTuples = 0;
54  bool doscan;
55 
56  /* must provide our own instrumentation support */
57  if (node->ss.ps.instrument)
59 
60  /*
61  * extract necessary information from index scan node
62  */
63  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  if (!node->biss_RuntimeKeysReady &&
72  (node->biss_NumRuntimeKeys != 0 || node->biss_NumArrayKeys != 0))
73  {
74  ExecReScan((PlanState *) node);
75  doscan = node->biss_RuntimeKeysReady;
76  }
77  else
78  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  if (node->biss_result)
87  {
88  tbm = node->biss_result;
89  node->biss_result = NULL; /* reset for next time */
90  }
91  else
92  {
93  /* XXX should we use less than work_mem for this? */
94  tbm = tbm_create(work_mem * 1024L,
95  ((BitmapIndexScan *) node->ss.ps.plan)->isshared ?
96  node->ss.ps.state->es_query_dsa : NULL);
97  }
98 
99  /*
100  * Get TIDs from index and insert into bitmap
101  */
102  while (doscan)
103  {
104  nTuples += (double) index_getbitmap(scandesc, tbm);
105 
107 
109  node->biss_NumArrayKeys);
110  if (doscan) /* reset index scan */
112  node->biss_ScanKeys, node->biss_NumScanKeys,
113  NULL, 0);
114  }
115 
116  /* must provide our own instrumentation support */
117  if (node->ss.ps.instrument)
118  InstrStopNode(node->ss.ps.instrument, nTuples);
119 
120  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
132 {
133  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  if (econtext)
141  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  if (node->biss_NumRuntimeKeys != 0)
152  ExecIndexEvalRuntimeKeys(econtext,
153  node->biss_RuntimeKeys,
154  node->biss_NumRuntimeKeys);
155  if (node->biss_NumArrayKeys != 0)
156  node->biss_RuntimeKeysReady =
157  ExecIndexEvalArrayKeys(econtext,
158  node->biss_ArrayKeys,
159  node->biss_NumArrayKeys);
160  else
161  node->biss_RuntimeKeysReady = true;
162 
163  /* reset index scan */
164  if (node->biss_RuntimeKeysReady)
166  node->biss_ScanKeys, node->biss_NumScanKeys,
167  NULL, 0);
168 }
169 
170 /* ----------------------------------------------------------------
171  * ExecEndBitmapIndexScan
172  * ----------------------------------------------------------------
173  */
174 void
176 {
177  Relation indexRelationDesc;
178  IndexScanDesc indexScanDesc;
179 
180  /*
181  * extract information from the node
182  */
183  indexRelationDesc = node->biss_RelationDesc;
184  indexScanDesc = node->biss_ScanDesc;
185 
186  /*
187  * close the index relation (no-op if we didn't open it)
188  */
189  if (indexScanDesc)
190  index_endscan(indexScanDesc);
191  if (indexRelationDesc)
192  index_close(indexRelationDesc, NoLock);
193 }
194 
195 /* ----------------------------------------------------------------
196  * ExecInitBitmapIndexScan
197  *
198  * Initializes the index scan's state information.
199  * ----------------------------------------------------------------
200  */
202 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  indexstate = makeNode(BitmapIndexScanState);
214  indexstate->ss.ps.plan = (Plan *) node;
215  indexstate->ss.ps.state = estate;
216  indexstate->ss.ps.ExecProcNode = ExecBitmapIndexScan;
217 
218  /* normally we don't make the result bitmap till runtime */
219  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  indexstate->ss.ss_currentRelation = NULL;
228  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  if (eflags & EXEC_FLAG_EXPLAIN_ONLY)
252  return indexstate;
253 
254  /* Open the index relation. */
255  lockmode = exec_rt_fetch(node->scan.scanrelid, estate)->rellockmode;
256  indexstate->biss_RelationDesc = index_open(node->indexid, lockmode);
257 
258  /*
259  * Initialize index-specific scan state
260  */
261  indexstate->biss_RuntimeKeysReady = false;
262  indexstate->biss_RuntimeKeys = NULL;
263  indexstate->biss_NumRuntimeKeys = 0;
264 
265  /*
266  * build the index scan keys from the index qualification
267  */
268  ExecIndexBuildScanKeys((PlanState *) indexstate,
269  indexstate->biss_RelationDesc,
270  node->indexqual,
271  false,
272  &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  if (indexstate->biss_NumRuntimeKeys != 0 ||
286  indexstate->biss_NumArrayKeys != 0)
287  {
288  ExprContext *stdecontext = indexstate->ss.ps.ps_ExprContext;
289 
290  ExecAssignExprContext(estate, &indexstate->ss.ps);
291  indexstate->biss_RuntimeContext = indexstate->ss.ps.ps_ExprContext;
292  indexstate->ss.ps.ps_ExprContext = stdecontext;
293  }
294  else
295  {
296  indexstate->biss_RuntimeContext = NULL;
297  }
298 
299  /*
300  * Initialize scan descriptor.
301  */
302  indexstate->biss_ScanDesc =
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  if (indexstate->biss_NumRuntimeKeys == 0 &&
312  indexstate->biss_NumArrayKeys == 0)
313  index_rescan(indexstate->biss_ScanDesc,
314  indexstate->biss_ScanKeys, indexstate->biss_NumScanKeys,
315  NULL, 0);
316 
317  /*
318  * all done.
319  */
320  return indexstate;
321 }
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:224
void ExecReScan(PlanState *node)
Definition: execAmi.c:76
void ExecAssignExprContext(EState *estate, PlanState *planstate)
Definition: execUtils.c:483
#define EXEC_FLAG_BACKWARD
Definition: executor.h:68
static RangeTblEntry * exec_rt_fetch(Index rti, EState *estate)
Definition: executor.h:587
#define ResetExprContext(econtext)
Definition: executor.h:544
#define EXEC_FLAG_EXPLAIN_ONLY
Definition: executor.h:65
#define EXEC_FLAG_MARK
Definition: executor.h:69
int work_mem
Definition: globals.c:128
IndexScanDesc index_beginscan_bitmap(Relation indexRelation, Snapshot snapshot, int nkeys)
Definition: indexam.c:288
void index_close(Relation relation, LOCKMODE lockmode)
Definition: indexam.c:177
void index_endscan(IndexScanDesc scan)
Definition: indexam.c:379
Relation index_open(Oid relationId, LOCKMODE lockmode)
Definition: indexam.c:133
int64 index_getbitmap(IndexScanDesc scan, TIDBitmap *bitmap)
Definition: indexam.c:721
void index_rescan(IndexScanDesc scan, ScanKey keys, int nkeys, ScanKey orderbys, int norderbys)
Definition: indexam.c:353
void InstrStartNode(Instrumentation *instr)
Definition: instrument.c:68
void InstrStopNode(Instrumentation *instr, double nTuples)
Definition: instrument.c:84
Assert(fmt[strlen(fmt) - 1] !='\n')
int LOCKMODE
Definition: lockdefs.h:26
#define NoLock
Definition: lockdefs.h:34
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:122
BitmapIndexScanState * ExecInitBitmapIndexScan(BitmapIndexScan *node, EState *estate, int eflags)
void ExecEndBitmapIndexScan(BitmapIndexScanState *node)
Node * MultiExecBitmapIndexScan(BitmapIndexScanState *node)
static TupleTableSlot * ExecBitmapIndexScan(PlanState *pstate)
void ExecReScanBitmapIndexScan(BitmapIndexScanState *node)
void ExecIndexBuildScanKeys(PlanState *planstate, Relation index, List *quals, bool isorderby, ScanKey *scanKeys, int *numScanKeys, IndexRuntimeKeyInfo **runtimeKeys, int *numRuntimeKeys, IndexArrayKeyInfo **arrayKeys, int *numArrayKeys)
bool ExecIndexEvalArrayKeys(ExprContext *econtext, IndexArrayKeyInfo *arrayKeys, int numArrayKeys)
void ExecIndexEvalRuntimeKeys(ExprContext *econtext, IndexRuntimeKeyInfo *runtimeKeys, int numRuntimeKeys)
bool ExecIndexAdvanceArrayKeys(IndexArrayKeyInfo *arrayKeys, int numArrayKeys)
#define makeNode(_type_)
Definition: nodes.h:155
ExprContext * biss_RuntimeContext
Definition: execnodes.h:1660
IndexArrayKeyInfo * biss_ArrayKeys
Definition: execnodes.h:1657
IndexRuntimeKeyInfo * biss_RuntimeKeys
Definition: execnodes.h:1655
TIDBitmap * biss_result
Definition: execnodes.h:1652
struct ScanKeyData * biss_ScanKeys
Definition: execnodes.h:1653
struct IndexScanDescData * biss_ScanDesc
Definition: execnodes.h:1662
Relation biss_RelationDesc
Definition: execnodes.h:1661
List * indexqual
Definition: plannodes.h:523
struct dsa_area * es_query_dsa
Definition: execnodes.h:702
Snapshot es_snapshot
Definition: execnodes.h:622
Definition: nodes.h:129
Instrumentation * instrument
Definition: execnodes.h:1053
Plan * plan
Definition: execnodes.h:1043
EState * state
Definition: execnodes.h:1045
ExprContext * ps_ExprContext
Definition: execnodes.h:1082
ExecProcNodeMtd ExecProcNode
Definition: execnodes.h:1049
Relation ss_currentRelation
Definition: execnodes.h:1484
PlanState ps
Definition: execnodes.h:1483
struct TableScanDescData * ss_currentScanDesc
Definition: execnodes.h:1485
Index scanrelid
Definition: plannodes.h:387
TIDBitmap * tbm_create(long maxbytes, dsa_area *dsa)
Definition: tidbitmap.c:266