]> granicus.if.org Git - postgresql/blob - src/backend/executor/nodeBitmapIndexscan.c
8.4 pgindent run, with new combined Linux/FreeBSD/MinGW typedef list
[postgresql] / src / backend / executor / nodeBitmapIndexscan.c
1 /*-------------------------------------------------------------------------
2  *
3  * nodeBitmapIndexscan.c
4  *        Routines to support bitmapped index scans of relations
5  *
6  * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
7  * Portions Copyright (c) 1994, Regents of the University of California
8  *
9  *
10  * IDENTIFICATION
11  *        $PostgreSQL: pgsql/src/backend/executor/nodeBitmapIndexscan.c,v 1.30 2009/06/11 14:48:57 momjian Exp $
12  *
13  *-------------------------------------------------------------------------
14  */
15 /*
16  * INTERFACE ROUTINES
17  *              MultiExecBitmapIndexScan        scans a relation using index.
18  *              ExecInitBitmapIndexScan         creates and initializes state info.
19  *              ExecBitmapIndexReScan           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/instrument.h"
27 #include "executor/nodeBitmapIndexscan.h"
28 #include "executor/nodeIndexscan.h"
29 #include "miscadmin.h"
30 #include "utils/memutils.h"
31
32
33 /* ----------------------------------------------------------------
34  *              MultiExecBitmapIndexScan(node)
35  * ----------------------------------------------------------------
36  */
37 Node *
38 MultiExecBitmapIndexScan(BitmapIndexScanState *node)
39 {
40         TIDBitmap  *tbm;
41         IndexScanDesc scandesc;
42         double          nTuples = 0;
43         bool            doscan;
44
45         /* must provide our own instrumentation support */
46         if (node->ss.ps.instrument)
47                 InstrStartNode(node->ss.ps.instrument);
48
49         /*
50          * extract necessary information from index scan node
51          */
52         scandesc = node->biss_ScanDesc;
53
54         /*
55          * If we have runtime keys and they've not already been set up, do it now.
56          * Array keys are also treated as runtime keys; note that if ExecReScan
57          * returns with biss_RuntimeKeysReady still false, then there is an empty
58          * array key so we should do nothing.
59          */
60         if (!node->biss_RuntimeKeysReady &&
61                 (node->biss_NumRuntimeKeys != 0 || node->biss_NumArrayKeys != 0))
62         {
63                 ExecReScan((PlanState *) node, NULL);
64                 doscan = node->biss_RuntimeKeysReady;
65         }
66         else
67                 doscan = true;
68
69         /*
70          * Prepare the result bitmap.  Normally we just create a new one to pass
71          * back; however, our parent node is allowed to store a pre-made one into
72          * node->biss_result, in which case we just OR our tuple IDs into the
73          * existing bitmap.  (This saves needing explicit UNION steps.)
74          */
75         if (node->biss_result)
76         {
77                 tbm = node->biss_result;
78                 node->biss_result = NULL;               /* reset for next time */
79         }
80         else
81         {
82                 /* XXX should we use less than work_mem for this? */
83                 tbm = tbm_create(work_mem * 1024L);
84         }
85
86         /*
87          * Get TIDs from index and insert into bitmap
88          */
89         while (doscan)
90         {
91                 nTuples += (double) index_getbitmap(scandesc, tbm);
92
93                 CHECK_FOR_INTERRUPTS();
94
95                 doscan = ExecIndexAdvanceArrayKeys(node->biss_ArrayKeys,
96                                                                                    node->biss_NumArrayKeys);
97                 if (doscan)                             /* reset index scan */
98                         index_rescan(node->biss_ScanDesc, node->biss_ScanKeys);
99         }
100
101         /* must provide our own instrumentation support */
102         if (node->ss.ps.instrument)
103                 InstrStopNode(node->ss.ps.instrument, nTuples);
104
105         return (Node *) tbm;
106 }
107
108 /* ----------------------------------------------------------------
109  *              ExecBitmapIndexReScan(node)
110  *
111  *              Recalculates the value of the scan keys whose value depends on
112  *              information known at runtime and rescans the indexed relation.
113  * ----------------------------------------------------------------
114  */
115 void
116 ExecBitmapIndexReScan(BitmapIndexScanState *node, ExprContext *exprCtxt)
117 {
118         ExprContext *econtext;
119
120         econtext = node->biss_RuntimeContext;           /* context for runtime keys */
121
122         if (econtext)
123         {
124                 /*
125                  * If we are being passed an outer tuple, save it for runtime key
126                  * calc.
127                  */
128                 if (exprCtxt != NULL)
129                         econtext->ecxt_outertuple = exprCtxt->ecxt_outertuple;
130
131                 /*
132                  * Reset the runtime-key context so we don't leak memory as each outer
133                  * tuple is scanned.  Note this assumes that we will recalculate *all*
134                  * runtime keys on each call.
135                  */
136                 ResetExprContext(econtext);
137         }
138
139         /*
140          * If we are doing runtime key calculations (ie, the index keys depend on
141          * data from an outer scan), compute the new key values.
142          *
143          * Array keys are also treated as runtime keys; note that if we return
144          * with biss_RuntimeKeysReady still false, then there is an empty array
145          * key so no index scan is needed.
146          */
147         if (node->biss_NumRuntimeKeys != 0)
148                 ExecIndexEvalRuntimeKeys(econtext,
149                                                                  node->biss_RuntimeKeys,
150                                                                  node->biss_NumRuntimeKeys);
151         if (node->biss_NumArrayKeys != 0)
152                 node->biss_RuntimeKeysReady =
153                         ExecIndexEvalArrayKeys(econtext,
154                                                                    node->biss_ArrayKeys,
155                                                                    node->biss_NumArrayKeys);
156         else
157                 node->biss_RuntimeKeysReady = true;
158
159         /* reset index scan */
160         if (node->biss_RuntimeKeysReady)
161                 index_rescan(node->biss_ScanDesc, node->biss_ScanKeys);
162 }
163
164 /* ----------------------------------------------------------------
165  *              ExecEndBitmapIndexScan
166  * ----------------------------------------------------------------
167  */
168 void
169 ExecEndBitmapIndexScan(BitmapIndexScanState *node)
170 {
171         Relation        indexRelationDesc;
172         IndexScanDesc indexScanDesc;
173
174         /*
175          * extract information from the node
176          */
177         indexRelationDesc = node->biss_RelationDesc;
178         indexScanDesc = node->biss_ScanDesc;
179
180         /*
181          * Free the exprcontext ... now dead code, see ExecFreeExprContext
182          */
183 #ifdef NOT_USED
184         if (node->biss_RuntimeContext)
185                 FreeExprContext(node->biss_RuntimeContext);
186 #endif
187
188         /*
189          * close the index relation (no-op if we didn't open it)
190          */
191         if (indexScanDesc)
192                 index_endscan(indexScanDesc);
193         if (indexRelationDesc)
194                 index_close(indexRelationDesc, NoLock);
195 }
196
197 /* ----------------------------------------------------------------
198  *              ExecInitBitmapIndexScan
199  *
200  *              Initializes the index scan's state information.
201  * ----------------------------------------------------------------
202  */
203 BitmapIndexScanState *
204 ExecInitBitmapIndexScan(BitmapIndexScan *node, EState *estate, int eflags)
205 {
206         BitmapIndexScanState *indexstate;
207         bool            relistarget;
208
209         /* check for unsupported flags */
210         Assert(!(eflags & (EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK)));
211
212         /*
213          * create state structure
214          */
215         indexstate = makeNode(BitmapIndexScanState);
216         indexstate->ss.ps.plan = (Plan *) node;
217         indexstate->ss.ps.state = estate;
218
219         /* normally we don't make the result bitmap till runtime */
220         indexstate->biss_result = NULL;
221
222         /*
223          * Miscellaneous initialization
224          *
225          * We do not need a standard exprcontext for this node, though we may
226          * decide below to create a runtime-key exprcontext
227          */
228
229         /*
230          * initialize child expressions
231          *
232          * We don't need to initialize targetlist or qual since neither are used.
233          *
234          * Note: we don't initialize all of the indexqual expression, only the
235          * sub-parts corresponding to runtime keys (see below).
236          */
237
238 #define BITMAPINDEXSCAN_NSLOTS 0
239
240         /*
241          * We do not open or lock the base relation here.  We assume that an
242          * ancestor BitmapHeapScan node is holding AccessShareLock (or better) on
243          * the heap relation throughout the execution of the plan tree.
244          */
245
246         indexstate->ss.ss_currentRelation = NULL;
247         indexstate->ss.ss_currentScanDesc = NULL;
248
249         /*
250          * If we are just doing EXPLAIN (ie, aren't going to run the plan), stop
251          * here.  This allows an index-advisor plugin to EXPLAIN a plan containing
252          * references to nonexistent indexes.
253          */
254         if (eflags & EXEC_FLAG_EXPLAIN_ONLY)
255                 return indexstate;
256
257         /*
258          * Open the index relation.
259          *
260          * If the parent table is one of the target relations of the query, then
261          * InitPlan already opened and write-locked the index, so we can avoid
262          * taking another lock here.  Otherwise we need a normal reader's lock.
263          */
264         relistarget = ExecRelationIsTargetRelation(estate, node->scan.scanrelid);
265         indexstate->biss_RelationDesc = index_open(node->indexid,
266                                                                          relistarget ? NoLock : AccessShareLock);
267
268         /*
269          * Initialize index-specific scan state
270          */
271         indexstate->biss_RuntimeKeysReady = false;
272
273         /*
274          * build the index scan keys from the index qualification
275          */
276         ExecIndexBuildScanKeys((PlanState *) indexstate,
277                                                    indexstate->biss_RelationDesc,
278                                                    node->scan.scanrelid,
279                                                    node->indexqual,
280                                                    &indexstate->biss_ScanKeys,
281                                                    &indexstate->biss_NumScanKeys,
282                                                    &indexstate->biss_RuntimeKeys,
283                                                    &indexstate->biss_NumRuntimeKeys,
284                                                    &indexstate->biss_ArrayKeys,
285                                                    &indexstate->biss_NumArrayKeys);
286
287         /*
288          * If we have runtime keys or array keys, we need an ExprContext to
289          * evaluate them. We could just create a "standard" plan node exprcontext,
290          * but to keep the code looking similar to nodeIndexscan.c, it seems
291          * better to stick with the approach of using a separate ExprContext.
292          */
293         if (indexstate->biss_NumRuntimeKeys != 0 ||
294                 indexstate->biss_NumArrayKeys != 0)
295         {
296                 ExprContext *stdecontext = indexstate->ss.ps.ps_ExprContext;
297
298                 ExecAssignExprContext(estate, &indexstate->ss.ps);
299                 indexstate->biss_RuntimeContext = indexstate->ss.ps.ps_ExprContext;
300                 indexstate->ss.ps.ps_ExprContext = stdecontext;
301         }
302         else
303         {
304                 indexstate->biss_RuntimeContext = NULL;
305         }
306
307         /*
308          * Initialize scan descriptor.
309          */
310         indexstate->biss_ScanDesc =
311                 index_beginscan_bitmap(indexstate->biss_RelationDesc,
312                                                            estate->es_snapshot,
313                                                            indexstate->biss_NumScanKeys,
314                                                            indexstate->biss_ScanKeys);
315
316         /*
317          * all done.
318          */
319         return indexstate;
320 }
321
322 int
323 ExecCountSlotsBitmapIndexScan(BitmapIndexScan *node)
324 {
325         return ExecCountSlotsNode(outerPlan((Plan *) node)) +
326                 ExecCountSlotsNode(innerPlan((Plan *) node)) + BITMAPINDEXSCAN_NSLOTS;
327 }