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