/*------------------------------------------------------------------------- * * nodeBitmapIndexscan.c * Routines to support bitmapped index scans of relations * * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION * src/backend/executor/nodeBitmapIndexscan.c * *------------------------------------------------------------------------- */ /* * INTERFACE ROUTINES * MultiExecBitmapIndexScan scans a relation using index. * ExecInitBitmapIndexScan creates and initializes state info. * ExecReScanBitmapIndexScan prepares to rescan the plan. * ExecEndBitmapIndexScan releases all storage. */ #include "postgres.h" #include "access/genam.h" #include "executor/execdebug.h" #include "executor/nodeBitmapIndexscan.h" #include "executor/nodeIndexscan.h" #include "miscadmin.h" #include "utils/memutils.h" /* ---------------------------------------------------------------- * ExecBitmapIndexScan * * stub for pro forma compliance * ---------------------------------------------------------------- */ static TupleTableSlot * ExecBitmapIndexScan(PlanState *pstate) { elog(ERROR, "BitmapIndexScan node does not support ExecProcNode call convention"); return NULL; } /* ---------------------------------------------------------------- * MultiExecBitmapIndexScan(node) * ---------------------------------------------------------------- */ Node * MultiExecBitmapIndexScan(BitmapIndexScanState *node) { TIDBitmap *tbm; IndexScanDesc scandesc; double nTuples = 0; bool doscan; /* must provide our own instrumentation support */ if (node->ss.ps.instrument) InstrStartNode(node->ss.ps.instrument); /* * extract necessary information from index scan node */ scandesc = node->biss_ScanDesc; /* * If we have runtime keys and they've not already been set up, do it now. * Array keys are also treated as runtime keys; note that if ExecReScan * returns with biss_RuntimeKeysReady still false, then there is an empty * array key so we should do nothing. */ if (!node->biss_RuntimeKeysReady && (node->biss_NumRuntimeKeys != 0 || node->biss_NumArrayKeys != 0)) { ExecReScan((PlanState *) node); doscan = node->biss_RuntimeKeysReady; } else doscan = true; /* * Prepare the result bitmap. Normally we just create a new one to pass * back; however, our parent node is allowed to store a pre-made one into * node->biss_result, in which case we just OR our tuple IDs into the * existing bitmap. (This saves needing explicit UNION steps.) */ if (node->biss_result) { tbm = node->biss_result; node->biss_result = NULL; /* reset for next time */ } else { /* XXX should we use less than work_mem for this? */ tbm = tbm_create(work_mem * 1024L, ((BitmapIndexScan *) node->ss.ps.plan)->isshared ? node->ss.ps.state->es_query_dsa : NULL); } /* * Get TIDs from index and insert into bitmap */ while (doscan) { nTuples += (double) index_getbitmap(scandesc, tbm); CHECK_FOR_INTERRUPTS(); doscan = ExecIndexAdvanceArrayKeys(node->biss_ArrayKeys, node->biss_NumArrayKeys); if (doscan) /* reset index scan */ index_rescan(node->biss_ScanDesc, node->biss_ScanKeys, node->biss_NumScanKeys, NULL, 0); } /* must provide our own instrumentation support */ if (node->ss.ps.instrument) InstrStopNode(node->ss.ps.instrument, nTuples); return (Node *) tbm; } /* ---------------------------------------------------------------- * ExecReScanBitmapIndexScan(node) * * Recalculates the values of any scan keys whose value depends on * information known at runtime, then rescans the indexed relation. * ---------------------------------------------------------------- */ void ExecReScanBitmapIndexScan(BitmapIndexScanState *node) { ExprContext *econtext = node->biss_RuntimeContext; /* * Reset the runtime-key context so we don't leak memory as each outer * tuple is scanned. Note this assumes that we will recalculate *all* * runtime keys on each call. */ if (econtext) ResetExprContext(econtext); /* * If we are doing runtime key calculations (ie, any of the index key * values weren't simple Consts), compute the new key values. * * Array keys are also treated as runtime keys; note that if we return * with biss_RuntimeKeysReady still false, then there is an empty array * key so no index scan is needed. */ if (node->biss_NumRuntimeKeys != 0) ExecIndexEvalRuntimeKeys(econtext, node->biss_RuntimeKeys, node->biss_NumRuntimeKeys); if (node->biss_NumArrayKeys != 0) node->biss_RuntimeKeysReady = ExecIndexEvalArrayKeys(econtext, node->biss_ArrayKeys, node->biss_NumArrayKeys); else node->biss_RuntimeKeysReady = true; /* reset index scan */ if (node->biss_RuntimeKeysReady) index_rescan(node->biss_ScanDesc, node->biss_ScanKeys, node->biss_NumScanKeys, NULL, 0); } /* ---------------------------------------------------------------- * ExecEndBitmapIndexScan * ---------------------------------------------------------------- */ void ExecEndBitmapIndexScan(BitmapIndexScanState *node) { Relation indexRelationDesc; IndexScanDesc indexScanDesc; /* * extract information from the node */ indexRelationDesc = node->biss_RelationDesc; indexScanDesc = node->biss_ScanDesc; /* * Free the exprcontext ... now dead code, see ExecFreeExprContext */ #ifdef NOT_USED if (node->biss_RuntimeContext) FreeExprContext(node->biss_RuntimeContext, true); #endif /* * close the index relation (no-op if we didn't open it) */ if (indexScanDesc) index_endscan(indexScanDesc); if (indexRelationDesc) index_close(indexRelationDesc, NoLock); } /* ---------------------------------------------------------------- * ExecInitBitmapIndexScan * * Initializes the index scan's state information. * ---------------------------------------------------------------- */ BitmapIndexScanState * ExecInitBitmapIndexScan(BitmapIndexScan *node, EState *estate, int eflags) { BitmapIndexScanState *indexstate; LOCKMODE lockmode; /* check for unsupported flags */ Assert(!(eflags & (EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK))); /* * create state structure */ indexstate = makeNode(BitmapIndexScanState); indexstate->ss.ps.plan = (Plan *) node; indexstate->ss.ps.state = estate; indexstate->ss.ps.ExecProcNode = ExecBitmapIndexScan; /* normally we don't make the result bitmap till runtime */ indexstate->biss_result = NULL; /* * We do not open or lock the base relation here. We assume that an * ancestor BitmapHeapScan node is holding AccessShareLock (or better) on * the heap relation throughout the execution of the plan tree. */ indexstate->ss.ss_currentRelation = NULL; indexstate->ss.ss_currentScanDesc = NULL; /* * Miscellaneous initialization * * We do not need a standard exprcontext for this node, though we may * decide below to create a runtime-key exprcontext */ /* * initialize child expressions * * We don't need to initialize targetlist or qual since neither are used. * * Note: we don't initialize all of the indexqual expression, only the * sub-parts corresponding to runtime keys (see below). */ /* * If we are just doing EXPLAIN (ie, aren't going to run the plan), stop * here. This allows an index-advisor plugin to EXPLAIN a plan containing * references to nonexistent indexes. */ if (eflags & EXEC_FLAG_EXPLAIN_ONLY) return indexstate; /* Open the index relation. */ lockmode = exec_rt_fetch(node->scan.scanrelid, estate)->rellockmode; indexstate->biss_RelationDesc = index_open(node->indexid, lockmode); /* * Initialize index-specific scan state */ indexstate->biss_RuntimeKeysReady = false; indexstate->biss_RuntimeKeys = NULL; indexstate->biss_NumRuntimeKeys = 0; /* * build the index scan keys from the index qualification */ ExecIndexBuildScanKeys((PlanState *) indexstate, indexstate->biss_RelationDesc, node->indexqual, false, &indexstate->biss_ScanKeys, &indexstate->biss_NumScanKeys, &indexstate->biss_RuntimeKeys, &indexstate->biss_NumRuntimeKeys, &indexstate->biss_ArrayKeys, &indexstate->biss_NumArrayKeys); /* * If we have runtime keys or array keys, we need an ExprContext to * evaluate them. We could just create a "standard" plan node exprcontext, * but to keep the code looking similar to nodeIndexscan.c, it seems * better to stick with the approach of using a separate ExprContext. */ if (indexstate->biss_NumRuntimeKeys != 0 || indexstate->biss_NumArrayKeys != 0) { ExprContext *stdecontext = indexstate->ss.ps.ps_ExprContext; ExecAssignExprContext(estate, &indexstate->ss.ps); indexstate->biss_RuntimeContext = indexstate->ss.ps.ps_ExprContext; indexstate->ss.ps.ps_ExprContext = stdecontext; } else { indexstate->biss_RuntimeContext = NULL; } /* * Initialize scan descriptor. */ indexstate->biss_ScanDesc = index_beginscan_bitmap(indexstate->biss_RelationDesc, estate->es_snapshot, indexstate->biss_NumScanKeys); /* * If no run-time keys to calculate, go ahead and pass the scankeys to the * index AM. */ if (indexstate->biss_NumRuntimeKeys == 0 && indexstate->biss_NumArrayKeys == 0) index_rescan(indexstate->biss_ScanDesc, indexstate->biss_ScanKeys, indexstate->biss_NumScanKeys, NULL, 0); /* * all done. */ return indexstate; }