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