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