LCOV - code coverage report
Current view: top level - src/backend/executor - nodeBitmapIndexscan.c (source / functions) Coverage Total Hit
Test: PostgreSQL 19devel Lines: 77.0 % 113 87
Test Date: 2026-03-21 04:16:06 Functions: 77.8 % 9 7
Legend: Lines:     hit not hit

            Line data    Source code
       1              : /*-------------------------------------------------------------------------
       2              :  *
       3              :  * nodeBitmapIndexscan.c
       4              :  *    Routines to support bitmapped index scans of relations
       5              :  *
       6              :  * Portions Copyright (c) 1996-2026, 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/executor.h"
      26              : #include "executor/instrument.h"
      27              : #include "executor/nodeBitmapIndexscan.h"
      28              : #include "executor/nodeIndexscan.h"
      29              : #include "miscadmin.h"
      30              : #include "nodes/tidbitmap.h"
      31              : 
      32              : 
      33              : /* ----------------------------------------------------------------
      34              :  *      ExecBitmapIndexScan
      35              :  *
      36              :  *      stub for pro forma compliance
      37              :  * ----------------------------------------------------------------
      38              :  */
      39              : static TupleTableSlot *
      40            0 : ExecBitmapIndexScan(PlanState *pstate)
      41              : {
      42            0 :     elog(ERROR, "BitmapIndexScan node does not support ExecProcNode call convention");
      43              :     return NULL;
      44              : }
      45              : 
      46              : /* ----------------------------------------------------------------
      47              :  *      MultiExecBitmapIndexScan(node)
      48              :  * ----------------------------------------------------------------
      49              :  */
      50              : Node *
      51        15766 : MultiExecBitmapIndexScan(BitmapIndexScanState *node)
      52              : {
      53              :     TIDBitmap  *tbm;
      54              :     IndexScanDesc scandesc;
      55        15766 :     double      nTuples = 0;
      56              :     bool        doscan;
      57              : 
      58              :     /* must provide our own instrumentation support */
      59        15766 :     if (node->ss.ps.instrument)
      60          290 :         InstrStartNode(node->ss.ps.instrument);
      61              : 
      62              :     /*
      63              :      * extract necessary information from index scan node
      64              :      */
      65        15766 :     scandesc = node->biss_ScanDesc;
      66              : 
      67              :     /*
      68              :      * If we have runtime keys and they've not already been set up, do it now.
      69              :      * Array keys are also treated as runtime keys; note that if ExecReScan
      70              :      * returns with biss_RuntimeKeysReady still false, then there is an empty
      71              :      * array key so we should do nothing.
      72              :      */
      73        15766 :     if (!node->biss_RuntimeKeysReady &&
      74        12744 :         (node->biss_NumRuntimeKeys != 0 || node->biss_NumArrayKeys != 0))
      75              :     {
      76          315 :         ExecReScan((PlanState *) node);
      77          315 :         doscan = node->biss_RuntimeKeysReady;
      78              :     }
      79              :     else
      80        15451 :         doscan = true;
      81              : 
      82              :     /*
      83              :      * Prepare the result bitmap.  Normally we just create a new one to pass
      84              :      * back; however, our parent node is allowed to store a pre-made one into
      85              :      * node->biss_result, in which case we just OR our tuple IDs into the
      86              :      * existing bitmap.  (This saves needing explicit UNION steps.)
      87              :      */
      88        15766 :     if (node->biss_result)
      89              :     {
      90          354 :         tbm = node->biss_result;
      91          354 :         node->biss_result = NULL;    /* reset for next time */
      92              :     }
      93              :     else
      94              :     {
      95              :         /* XXX should we use less than work_mem for this? */
      96        15412 :         tbm = tbm_create(work_mem * (Size) 1024,
      97        15412 :                          ((BitmapIndexScan *) node->ss.ps.plan)->isshared ?
      98           48 :                          node->ss.ps.state->es_query_dsa : NULL);
      99              :     }
     100              : 
     101              :     /*
     102              :      * Get TIDs from index and insert into bitmap
     103              :      */
     104        31549 :     while (doscan)
     105              :     {
     106        15783 :         nTuples += (double) index_getbitmap(scandesc, tbm);
     107              : 
     108        15783 :         CHECK_FOR_INTERRUPTS();
     109              : 
     110        15783 :         doscan = ExecIndexAdvanceArrayKeys(node->biss_ArrayKeys,
     111              :                                            node->biss_NumArrayKeys);
     112        15783 :         if (doscan)             /* reset index scan */
     113           17 :             index_rescan(node->biss_ScanDesc,
     114              :                          node->biss_ScanKeys, node->biss_NumScanKeys,
     115              :                          NULL, 0);
     116              :     }
     117              : 
     118              :     /* must provide our own instrumentation support */
     119        15766 :     if (node->ss.ps.instrument)
     120          290 :         InstrStopNode(node->ss.ps.instrument, nTuples);
     121              : 
     122        15766 :     return (Node *) tbm;
     123              : }
     124              : 
     125              : /* ----------------------------------------------------------------
     126              :  *      ExecReScanBitmapIndexScan(node)
     127              :  *
     128              :  *      Recalculates the values of any scan keys whose value depends on
     129              :  *      information known at runtime, then rescans the indexed relation.
     130              :  * ----------------------------------------------------------------
     131              :  */
     132              : void
     133         3345 : ExecReScanBitmapIndexScan(BitmapIndexScanState *node)
     134              : {
     135         3345 :     ExprContext *econtext = node->biss_RuntimeContext;
     136              : 
     137              :     /*
     138              :      * Reset the runtime-key context so we don't leak memory as each outer
     139              :      * tuple is scanned.  Note this assumes that we will recalculate *all*
     140              :      * runtime keys on each call.
     141              :      */
     142         3345 :     if (econtext)
     143         3036 :         ResetExprContext(econtext);
     144              : 
     145              :     /*
     146              :      * If we are doing runtime key calculations (ie, any of the index key
     147              :      * values weren't simple Consts), compute the new key values.
     148              :      *
     149              :      * Array keys are also treated as runtime keys; note that if we return
     150              :      * with biss_RuntimeKeysReady still false, then there is an empty array
     151              :      * key so no index scan is needed.
     152              :      */
     153         3345 :     if (node->biss_NumRuntimeKeys != 0)
     154         3019 :         ExecIndexEvalRuntimeKeys(econtext,
     155              :                                  node->biss_RuntimeKeys,
     156              :                                  node->biss_NumRuntimeKeys);
     157         3345 :     if (node->biss_NumArrayKeys != 0)
     158           17 :         node->biss_RuntimeKeysReady =
     159           17 :             ExecIndexEvalArrayKeys(econtext,
     160              :                                    node->biss_ArrayKeys,
     161              :                                    node->biss_NumArrayKeys);
     162              :     else
     163         3328 :         node->biss_RuntimeKeysReady = true;
     164              : 
     165              :     /* reset index scan */
     166         3345 :     if (node->biss_RuntimeKeysReady)
     167         3345 :         index_rescan(node->biss_ScanDesc,
     168              :                      node->biss_ScanKeys, node->biss_NumScanKeys,
     169              :                      NULL, 0);
     170         3345 : }
     171              : 
     172              : /* ----------------------------------------------------------------
     173              :  *      ExecEndBitmapIndexScan
     174              :  * ----------------------------------------------------------------
     175              :  */
     176              : void
     177        16712 : ExecEndBitmapIndexScan(BitmapIndexScanState *node)
     178              : {
     179              :     Relation    indexRelationDesc;
     180              :     IndexScanDesc indexScanDesc;
     181              : 
     182              :     /*
     183              :      * extract information from the node
     184              :      */
     185        16712 :     indexRelationDesc = node->biss_RelationDesc;
     186        16712 :     indexScanDesc = node->biss_ScanDesc;
     187              : 
     188              :     /*
     189              :      * When ending a parallel worker, copy the statistics gathered by the
     190              :      * worker back into shared memory so that it can be picked up by the main
     191              :      * process to report in EXPLAIN ANALYZE
     192              :      */
     193        16712 :     if (node->biss_SharedInfo != NULL && IsParallelWorker())
     194              :     {
     195              :         IndexScanInstrumentation *winstrument;
     196              : 
     197              :         Assert(ParallelWorkerNumber < node->biss_SharedInfo->num_workers);
     198            0 :         winstrument = &node->biss_SharedInfo->winstrument[ParallelWorkerNumber];
     199              : 
     200              :         /*
     201              :          * We have to accumulate the stats rather than performing a memcpy.
     202              :          * When a Gather/GatherMerge node finishes it will perform planner
     203              :          * shutdown on the workers.  On rescan it will spin up new workers
     204              :          * which will have a new BitmapIndexScanState and zeroed stats.
     205              :          */
     206            0 :         winstrument->nsearches += node->biss_Instrument.nsearches;
     207              :     }
     208              : 
     209              :     /*
     210              :      * close the index relation (no-op if we didn't open it)
     211              :      */
     212        16712 :     if (indexScanDesc)
     213        14159 :         index_endscan(indexScanDesc);
     214        16712 :     if (indexRelationDesc)
     215        14159 :         index_close(indexRelationDesc, NoLock);
     216        16712 : }
     217              : 
     218              : /* ----------------------------------------------------------------
     219              :  *      ExecInitBitmapIndexScan
     220              :  *
     221              :  *      Initializes the index scan's state information.
     222              :  * ----------------------------------------------------------------
     223              :  */
     224              : BitmapIndexScanState *
     225        16793 : ExecInitBitmapIndexScan(BitmapIndexScan *node, EState *estate, int eflags)
     226              : {
     227              :     BitmapIndexScanState *indexstate;
     228              :     LOCKMODE    lockmode;
     229              : 
     230              :     /* check for unsupported flags */
     231              :     Assert(!(eflags & (EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK)));
     232              : 
     233              :     /*
     234              :      * create state structure
     235              :      */
     236        16793 :     indexstate = makeNode(BitmapIndexScanState);
     237        16793 :     indexstate->ss.ps.plan = (Plan *) node;
     238        16793 :     indexstate->ss.ps.state = estate;
     239        16793 :     indexstate->ss.ps.ExecProcNode = ExecBitmapIndexScan;
     240              : 
     241              :     /* normally we don't make the result bitmap till runtime */
     242        16793 :     indexstate->biss_result = NULL;
     243              : 
     244              :     /*
     245              :      * We do not open or lock the base relation here.  We assume that an
     246              :      * ancestor BitmapHeapScan node is holding AccessShareLock (or better) on
     247              :      * the heap relation throughout the execution of the plan tree.
     248              :      */
     249              : 
     250        16793 :     indexstate->ss.ss_currentRelation = NULL;
     251        16793 :     indexstate->ss.ss_currentScanDesc = NULL;
     252              : 
     253              :     /*
     254              :      * Miscellaneous initialization
     255              :      *
     256              :      * We do not need a standard exprcontext for this node, though we may
     257              :      * decide below to create a runtime-key exprcontext
     258              :      */
     259              : 
     260              :     /*
     261              :      * initialize child expressions
     262              :      *
     263              :      * We don't need to initialize targetlist or qual since neither are used.
     264              :      *
     265              :      * Note: we don't initialize all of the indexqual expression, only the
     266              :      * sub-parts corresponding to runtime keys (see below).
     267              :      */
     268              : 
     269              :     /*
     270              :      * If we are just doing EXPLAIN (ie, aren't going to run the plan), stop
     271              :      * here.  This allows an index-advisor plugin to EXPLAIN a plan containing
     272              :      * references to nonexistent indexes.
     273              :      */
     274        16793 :     if (eflags & EXEC_FLAG_EXPLAIN_ONLY)
     275         2553 :         return indexstate;
     276              : 
     277              :     /* Open the index relation. */
     278        14240 :     lockmode = exec_rt_fetch(node->scan.scanrelid, estate)->rellockmode;
     279        14240 :     indexstate->biss_RelationDesc = index_open(node->indexid, lockmode);
     280              : 
     281              :     /*
     282              :      * Initialize index-specific scan state
     283              :      */
     284        14240 :     indexstate->biss_RuntimeKeysReady = false;
     285        14240 :     indexstate->biss_RuntimeKeys = NULL;
     286        14240 :     indexstate->biss_NumRuntimeKeys = 0;
     287              : 
     288              :     /*
     289              :      * build the index scan keys from the index qualification
     290              :      */
     291        14240 :     ExecIndexBuildScanKeys((PlanState *) indexstate,
     292              :                            indexstate->biss_RelationDesc,
     293              :                            node->indexqual,
     294              :                            false,
     295        14240 :                            &indexstate->biss_ScanKeys,
     296              :                            &indexstate->biss_NumScanKeys,
     297              :                            &indexstate->biss_RuntimeKeys,
     298              :                            &indexstate->biss_NumRuntimeKeys,
     299              :                            &indexstate->biss_ArrayKeys,
     300              :                            &indexstate->biss_NumArrayKeys);
     301              : 
     302              :     /*
     303              :      * If we have runtime keys or array keys, we need an ExprContext to
     304              :      * evaluate them. We could just create a "standard" plan node exprcontext,
     305              :      * but to keep the code looking similar to nodeIndexscan.c, it seems
     306              :      * better to stick with the approach of using a separate ExprContext.
     307              :      */
     308        14240 :     if (indexstate->biss_NumRuntimeKeys != 0 ||
     309        13203 :         indexstate->biss_NumArrayKeys != 0)
     310         1054 :     {
     311         1054 :         ExprContext *stdecontext = indexstate->ss.ps.ps_ExprContext;
     312              : 
     313         1054 :         ExecAssignExprContext(estate, &indexstate->ss.ps);
     314         1054 :         indexstate->biss_RuntimeContext = indexstate->ss.ps.ps_ExprContext;
     315         1054 :         indexstate->ss.ps.ps_ExprContext = stdecontext;
     316              :     }
     317              :     else
     318              :     {
     319        13186 :         indexstate->biss_RuntimeContext = NULL;
     320              :     }
     321              : 
     322              :     /*
     323              :      * Initialize scan descriptor.
     324              :      */
     325        14240 :     indexstate->biss_ScanDesc =
     326        14240 :         index_beginscan_bitmap(indexstate->biss_RelationDesc,
     327              :                                estate->es_snapshot,
     328              :                                &indexstate->biss_Instrument,
     329              :                                indexstate->biss_NumScanKeys);
     330              : 
     331              :     /*
     332              :      * If no run-time keys to calculate, go ahead and pass the scankeys to the
     333              :      * index AM.
     334              :      */
     335        14240 :     if (indexstate->biss_NumRuntimeKeys == 0 &&
     336        13203 :         indexstate->biss_NumArrayKeys == 0)
     337        13186 :         index_rescan(indexstate->biss_ScanDesc,
     338              :                      indexstate->biss_ScanKeys, indexstate->biss_NumScanKeys,
     339              :                      NULL, 0);
     340              : 
     341              :     /*
     342              :      * all done.
     343              :      */
     344        14240 :     return indexstate;
     345              : }
     346              : 
     347              : /* ----------------------------------------------------------------
     348              :  *      ExecBitmapIndexScanEstimate
     349              :  *
     350              :  *      Compute the amount of space we'll need in the parallel
     351              :  *      query DSM, and inform pcxt->estimator about our needs.
     352              :  * ----------------------------------------------------------------
     353              :  */
     354              : void
     355           13 : ExecBitmapIndexScanEstimate(BitmapIndexScanState *node, ParallelContext *pcxt)
     356              : {
     357              :     Size        size;
     358              : 
     359              :     /*
     360              :      * Parallel bitmap index scans are not supported, but we still need to
     361              :      * store the scan's instrumentation in DSM during parallel query
     362              :      */
     363           13 :     if (!node->ss.ps.instrument || pcxt->nworkers == 0)
     364           13 :         return;
     365              : 
     366            0 :     size = offsetof(SharedIndexScanInstrumentation, winstrument) +
     367            0 :         pcxt->nworkers * sizeof(IndexScanInstrumentation);
     368            0 :     shm_toc_estimate_chunk(&pcxt->estimator, size);
     369            0 :     shm_toc_estimate_keys(&pcxt->estimator, 1);
     370              : }
     371              : 
     372              : /* ----------------------------------------------------------------
     373              :  *      ExecBitmapIndexScanInitializeDSM
     374              :  *
     375              :  *      Set up bitmap index scan shared instrumentation.
     376              :  * ----------------------------------------------------------------
     377              :  */
     378              : void
     379           13 : ExecBitmapIndexScanInitializeDSM(BitmapIndexScanState *node,
     380              :                                  ParallelContext *pcxt)
     381              : {
     382              :     Size        size;
     383              : 
     384              :     /* don't need this if not instrumenting or no workers */
     385           13 :     if (!node->ss.ps.instrument || pcxt->nworkers == 0)
     386           13 :         return;
     387              : 
     388            0 :     size = offsetof(SharedIndexScanInstrumentation, winstrument) +
     389            0 :         pcxt->nworkers * sizeof(IndexScanInstrumentation);
     390            0 :     node->biss_SharedInfo =
     391            0 :         (SharedIndexScanInstrumentation *) shm_toc_allocate(pcxt->toc,
     392              :                                                             size);
     393            0 :     shm_toc_insert(pcxt->toc, node->ss.ps.plan->plan_node_id,
     394            0 :                    node->biss_SharedInfo);
     395              : 
     396              :     /* Each per-worker area must start out as zeroes */
     397            0 :     memset(node->biss_SharedInfo, 0, size);
     398            0 :     node->biss_SharedInfo->num_workers = pcxt->nworkers;
     399              : }
     400              : 
     401              : /* ----------------------------------------------------------------
     402              :  *      ExecBitmapIndexScanInitializeWorker
     403              :  *
     404              :  *      Copy relevant information from TOC into planstate.
     405              :  * ----------------------------------------------------------------
     406              :  */
     407              : void
     408          180 : ExecBitmapIndexScanInitializeWorker(BitmapIndexScanState *node,
     409              :                                     ParallelWorkerContext *pwcxt)
     410              : {
     411              :     /* don't need this if not instrumenting */
     412          180 :     if (!node->ss.ps.instrument)
     413          180 :         return;
     414              : 
     415            0 :     node->biss_SharedInfo = (SharedIndexScanInstrumentation *)
     416            0 :         shm_toc_lookup(pwcxt->toc, node->ss.ps.plan->plan_node_id, false);
     417              : }
     418              : 
     419              : /* ----------------------------------------------------------------
     420              :  * ExecBitmapIndexScanRetrieveInstrumentation
     421              :  *
     422              :  *      Transfer bitmap index scan statistics from DSM to private memory.
     423              :  * ----------------------------------------------------------------
     424              :  */
     425              : void
     426            0 : ExecBitmapIndexScanRetrieveInstrumentation(BitmapIndexScanState *node)
     427              : {
     428            0 :     SharedIndexScanInstrumentation *SharedInfo = node->biss_SharedInfo;
     429              :     size_t      size;
     430              : 
     431            0 :     if (SharedInfo == NULL)
     432            0 :         return;
     433              : 
     434              :     /* Create a copy of SharedInfo in backend-local memory */
     435            0 :     size = offsetof(SharedIndexScanInstrumentation, winstrument) +
     436            0 :         SharedInfo->num_workers * sizeof(IndexScanInstrumentation);
     437            0 :     node->biss_SharedInfo = palloc(size);
     438            0 :     memcpy(node->biss_SharedInfo, SharedInfo, size);
     439              : }
        

Generated by: LCOV version 2.0-1