LCOV - code coverage report
Current view: top level - src/backend/executor - nodeBitmapIndexscan.c (source / functions) Coverage Total Hit
Test: PostgreSQL 20devel Lines: 76.1 % 117 89
Test Date: 2026-07-12 21:15:34 Functions: 77.8 % 9 7
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
Branches: 74.2 % 62 46

             Branch data     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                 :       15977 : MultiExecBitmapIndexScan(BitmapIndexScanState *node)
      52                 :             : {
      53                 :             :     TIDBitmap  *tbm;
      54                 :             :     IndexScanDesc scandesc;
      55                 :       15977 :     double      nTuples = 0;
      56                 :             :     bool        doscan;
      57                 :             : 
      58                 :             :     /* must provide our own instrumentation support */
      59         [ +  + ]:       15977 :     if (node->ss.ps.instrument)
      60                 :         290 :         InstrStartNode(node->ss.ps.instrument);
      61                 :             : 
      62                 :             :     /*
      63                 :             :      * extract necessary information from index scan node
      64                 :             :      */
      65                 :       15977 :     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         [ +  + ]:       15977 :     if (!node->biss_RuntimeKeysReady &&
      74   [ +  +  +  + ]:       12894 :         (node->biss_NumRuntimeKeys != 0 || node->biss_NumArrayKeys != 0))
      75                 :             :     {
      76                 :         340 :         ExecReScan((PlanState *) node);
      77                 :         340 :         doscan = node->biss_RuntimeKeysReady;
      78                 :             :     }
      79                 :             :     else
      80                 :       15637 :         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         [ +  + ]:       15977 :     if (node->biss_result)
      89                 :             :     {
      90                 :         314 :         tbm = node->biss_result;
      91                 :         314 :         node->biss_result = NULL;    /* reset for next time */
      92                 :             :     }
      93                 :             :     else
      94                 :             :     {
      95                 :             :         /* XXX should we use less than work_mem for this? */
      96                 :       15663 :         tbm = tbm_create(work_mem * (Size) 1024,
      97         [ +  + ]:       15663 :                          ((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         [ +  + ]:       31991 :     while (doscan)
     105                 :             :     {
     106                 :       16014 :         nTuples += (double) index_getbitmap(scandesc, tbm);
     107                 :             : 
     108         [ -  + ]:       16014 :         CHECK_FOR_INTERRUPTS();
     109                 :             : 
     110                 :       16014 :         doscan = ExecIndexAdvanceArrayKeys(node->biss_ArrayKeys,
     111                 :             :                                            node->biss_NumArrayKeys);
     112         [ +  + ]:       16014 :         if (doscan)             /* reset index scan */
     113                 :          37 :             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         [ +  + ]:       15977 :     if (node->ss.ps.instrument)
     120                 :         290 :         InstrStopNode(node->ss.ps.instrument, nTuples);
     121                 :             : 
     122                 :       15977 :     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                 :        3431 : ExecReScanBitmapIndexScan(BitmapIndexScanState *node)
     134                 :             : {
     135                 :        3431 :     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         [ +  + ]:        3431 :     if (econtext)
     143                 :        3163 :         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         [ +  + ]:        3431 :     if (node->biss_NumRuntimeKeys != 0)
     154                 :        3126 :         ExecIndexEvalRuntimeKeys(econtext,
     155                 :             :                                  node->biss_RuntimeKeys,
     156                 :             :                                  node->biss_NumRuntimeKeys);
     157         [ +  + ]:        3431 :     if (node->biss_NumArrayKeys != 0)
     158                 :          37 :         node->biss_RuntimeKeysReady =
     159                 :          37 :             ExecIndexEvalArrayKeys(econtext,
     160                 :             :                                    node->biss_ArrayKeys,
     161                 :             :                                    node->biss_NumArrayKeys);
     162                 :             :     else
     163                 :        3394 :         node->biss_RuntimeKeysReady = true;
     164                 :             : 
     165                 :             :     /* reset index scan */
     166         [ +  - ]:        3431 :     if (node->biss_RuntimeKeysReady)
     167                 :        3431 :         index_rescan(node->biss_ScanDesc,
     168                 :             :                      node->biss_ScanKeys, node->biss_NumScanKeys,
     169                 :             :                      NULL, 0);
     170                 :        3431 : }
     171                 :             : 
     172                 :             : /* ----------------------------------------------------------------
     173                 :             :  *      ExecEndBitmapIndexScan
     174                 :             :  * ----------------------------------------------------------------
     175                 :             :  */
     176                 :             : void
     177                 :       17162 : ExecEndBitmapIndexScan(BitmapIndexScanState *node)
     178                 :             : {
     179                 :             :     Relation    indexRelationDesc;
     180                 :             :     IndexScanDesc indexScanDesc;
     181                 :             : 
     182                 :             :     /*
     183                 :             :      * extract information from the node
     184                 :             :      */
     185                 :       17162 :     indexRelationDesc = node->biss_RelationDesc;
     186                 :       17162 :     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   [ -  +  -  - ]:       17162 :     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         [ +  + ]:       17162 :     if (indexScanDesc)
     213                 :       14607 :         index_endscan(indexScanDesc);
     214         [ +  + ]:       17162 :     if (indexRelationDesc)
     215                 :       14607 :         index_close(indexRelationDesc, NoLock);
     216                 :       17162 : }
     217                 :             : 
     218                 :             : /* ----------------------------------------------------------------
     219                 :             :  *      ExecInitBitmapIndexScan
     220                 :             :  *
     221                 :             :  *      Initializes the index scan's state information.
     222                 :             :  * ----------------------------------------------------------------
     223                 :             :  */
     224                 :             : BitmapIndexScanState *
     225                 :       17242 : 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                 :       17242 :     indexstate = makeNode(BitmapIndexScanState);
     237                 :       17242 :     indexstate->ss.ps.plan = (Plan *) node;
     238                 :       17242 :     indexstate->ss.ps.state = estate;
     239                 :       17242 :     indexstate->ss.ps.ExecProcNode = ExecBitmapIndexScan;
     240                 :             : 
     241                 :             :     /* normally we don't make the result bitmap till runtime */
     242                 :       17242 :     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                 :       17242 :     indexstate->ss.ss_currentRelation = NULL;
     251                 :       17242 :     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         [ +  + ]:       17242 :     if (eflags & EXEC_FLAG_EXPLAIN_ONLY)
     275                 :        2555 :         return indexstate;
     276                 :             : 
     277                 :             :     /* Set up instrumentation of bitmap index scans if requested */
     278         [ +  + ]:       14687 :     if (estate->es_instrument)
     279                 :         338 :         indexstate->biss_Instrument = palloc0_object(IndexScanInstrumentation);
     280                 :             : 
     281                 :             :     /* Open the index relation. */
     282                 :       14687 :     lockmode = exec_rt_fetch(node->scan.scanrelid, estate)->rellockmode;
     283                 :       14687 :     indexstate->biss_RelationDesc = index_open(node->indexid, lockmode);
     284                 :             : 
     285                 :             :     /*
     286                 :             :      * Initialize index-specific scan state
     287                 :             :      */
     288                 :       14687 :     indexstate->biss_RuntimeKeysReady = false;
     289                 :       14687 :     indexstate->biss_RuntimeKeys = NULL;
     290                 :       14687 :     indexstate->biss_NumRuntimeKeys = 0;
     291                 :             : 
     292                 :             :     /*
     293                 :             :      * build the index scan keys from the index qualification
     294                 :             :      */
     295                 :       14687 :     ExecIndexBuildScanKeys((PlanState *) indexstate,
     296                 :             :                            indexstate->biss_RelationDesc,
     297                 :             :                            node->indexqual,
     298                 :             :                            false,
     299                 :       14687 :                            &indexstate->biss_ScanKeys,
     300                 :             :                            &indexstate->biss_NumScanKeys,
     301                 :             :                            &indexstate->biss_RuntimeKeys,
     302                 :             :                            &indexstate->biss_NumRuntimeKeys,
     303                 :             :                            &indexstate->biss_ArrayKeys,
     304                 :             :                            &indexstate->biss_NumArrayKeys);
     305                 :             : 
     306                 :             :     /*
     307                 :             :      * If we have runtime keys or array keys, we need an ExprContext to
     308                 :             :      * evaluate them. We could just create a "standard" plan node exprcontext,
     309                 :             :      * but to keep the code looking similar to nodeIndexscan.c, it seems
     310                 :             :      * better to stick with the approach of using a separate ExprContext.
     311                 :             :      */
     312         [ +  + ]:       14687 :     if (indexstate->biss_NumRuntimeKeys != 0 ||
     313         [ +  + ]:       13378 :         indexstate->biss_NumArrayKeys != 0)
     314                 :        1346 :     {
     315                 :        1346 :         ExprContext *stdecontext = indexstate->ss.ps.ps_ExprContext;
     316                 :             : 
     317                 :        1346 :         ExecAssignExprContext(estate, &indexstate->ss.ps);
     318                 :        1346 :         indexstate->biss_RuntimeContext = indexstate->ss.ps.ps_ExprContext;
     319                 :        1346 :         indexstate->ss.ps.ps_ExprContext = stdecontext;
     320                 :             :     }
     321                 :             :     else
     322                 :             :     {
     323                 :       13341 :         indexstate->biss_RuntimeContext = NULL;
     324                 :             :     }
     325                 :             : 
     326                 :             :     /*
     327                 :             :      * Initialize scan descriptor.
     328                 :             :      */
     329                 :       14687 :     indexstate->biss_ScanDesc =
     330                 :       14687 :         index_beginscan_bitmap(indexstate->biss_RelationDesc,
     331                 :             :                                estate->es_snapshot,
     332                 :             :                                indexstate->biss_Instrument,
     333                 :             :                                indexstate->biss_NumScanKeys);
     334                 :             : 
     335                 :             :     /*
     336                 :             :      * If no run-time keys to calculate, go ahead and pass the scankeys to the
     337                 :             :      * index AM.
     338                 :             :      */
     339         [ +  + ]:       14687 :     if (indexstate->biss_NumRuntimeKeys == 0 &&
     340         [ +  + ]:       13378 :         indexstate->biss_NumArrayKeys == 0)
     341                 :       13341 :         index_rescan(indexstate->biss_ScanDesc,
     342                 :             :                      indexstate->biss_ScanKeys, indexstate->biss_NumScanKeys,
     343                 :             :                      NULL, 0);
     344                 :             : 
     345                 :             :     /*
     346                 :             :      * all done.
     347                 :             :      */
     348                 :       14687 :     return indexstate;
     349                 :             : }
     350                 :             : 
     351                 :             : /* ----------------------------------------------------------------
     352                 :             :  *      ExecBitmapIndexScanEstimate
     353                 :             :  *
     354                 :             :  *      Compute the amount of space we'll need in the parallel
     355                 :             :  *      query DSM, and inform pcxt->estimator about our needs.
     356                 :             :  * ----------------------------------------------------------------
     357                 :             :  */
     358                 :             : void
     359                 :          13 : ExecBitmapIndexScanEstimate(BitmapIndexScanState *node, ParallelContext *pcxt)
     360                 :             : {
     361                 :             :     Size        size;
     362                 :             : 
     363                 :             :     /*
     364                 :             :      * Parallel bitmap index scans are not supported, but we still need to
     365                 :             :      * store the scan's instrumentation in DSM during parallel query
     366                 :             :      */
     367   [ -  +  -  - ]:          13 :     if (!node->ss.ps.instrument || pcxt->nworkers == 0)
     368                 :          13 :         return;
     369                 :             : 
     370                 :           0 :     size = offsetof(SharedIndexScanInstrumentation, winstrument) +
     371                 :           0 :         pcxt->nworkers * sizeof(IndexScanInstrumentation);
     372                 :           0 :     shm_toc_estimate_chunk(&pcxt->estimator, size);
     373                 :           0 :     shm_toc_estimate_keys(&pcxt->estimator, 1);
     374                 :             : }
     375                 :             : 
     376                 :             : /* ----------------------------------------------------------------
     377                 :             :  *      ExecBitmapIndexScanInitializeDSM
     378                 :             :  *
     379                 :             :  *      Set up bitmap index scan shared instrumentation.
     380                 :             :  * ----------------------------------------------------------------
     381                 :             :  */
     382                 :             : void
     383                 :          13 : ExecBitmapIndexScanInitializeDSM(BitmapIndexScanState *node,
     384                 :             :                                  ParallelContext *pcxt)
     385                 :             : {
     386                 :             :     Size        size;
     387                 :             : 
     388                 :             :     /* don't need this if not instrumenting or no workers */
     389   [ -  +  -  - ]:          13 :     if (!node->ss.ps.instrument || pcxt->nworkers == 0)
     390                 :          13 :         return;
     391                 :             : 
     392                 :           0 :     size = offsetof(SharedIndexScanInstrumentation, winstrument) +
     393                 :           0 :         pcxt->nworkers * sizeof(IndexScanInstrumentation);
     394                 :           0 :     node->biss_SharedInfo =
     395                 :           0 :         (SharedIndexScanInstrumentation *) shm_toc_allocate(pcxt->toc,
     396                 :             :                                                             size);
     397                 :           0 :     shm_toc_insert(pcxt->toc,
     398                 :           0 :                    node->ss.ps.plan->plan_node_id +
     399                 :             :                    PARALLEL_KEY_SCAN_INSTRUMENT_OFFSET,
     400                 :           0 :                    node->biss_SharedInfo);
     401                 :             : 
     402                 :             :     /* Each per-worker area must start out as zeroes */
     403                 :           0 :     memset(node->biss_SharedInfo, 0, size);
     404                 :           0 :     node->biss_SharedInfo->num_workers = pcxt->nworkers;
     405                 :             : }
     406                 :             : 
     407                 :             : /* ----------------------------------------------------------------
     408                 :             :  *      ExecBitmapIndexScanInitializeWorker
     409                 :             :  *
     410                 :             :  *      Copy relevant information from TOC into planstate.
     411                 :             :  * ----------------------------------------------------------------
     412                 :             :  */
     413                 :             : void
     414                 :         181 : ExecBitmapIndexScanInitializeWorker(BitmapIndexScanState *node,
     415                 :             :                                     ParallelWorkerContext *pwcxt)
     416                 :             : {
     417                 :             :     /* don't need this if not instrumenting */
     418         [ +  - ]:         181 :     if (!node->ss.ps.instrument)
     419                 :         181 :         return;
     420                 :             : 
     421                 :           0 :     node->biss_SharedInfo = (SharedIndexScanInstrumentation *)
     422                 :           0 :         shm_toc_lookup(pwcxt->toc,
     423                 :           0 :                        node->ss.ps.plan->plan_node_id +
     424                 :             :                        PARALLEL_KEY_SCAN_INSTRUMENT_OFFSET,
     425                 :             :                        false);
     426                 :             : }
     427                 :             : 
     428                 :             : /* ----------------------------------------------------------------
     429                 :             :  * ExecBitmapIndexScanRetrieveInstrumentation
     430                 :             :  *
     431                 :             :  *      Transfer bitmap index scan statistics from DSM to private memory.
     432                 :             :  * ----------------------------------------------------------------
     433                 :             :  */
     434                 :             : void
     435                 :           0 : ExecBitmapIndexScanRetrieveInstrumentation(BitmapIndexScanState *node)
     436                 :             : {
     437                 :           0 :     SharedIndexScanInstrumentation *SharedInfo = node->biss_SharedInfo;
     438                 :             :     size_t      size;
     439                 :             : 
     440         [ #  # ]:           0 :     if (SharedInfo == NULL)
     441                 :           0 :         return;
     442                 :             : 
     443                 :             :     /* Create a copy of SharedInfo in backend-local memory */
     444                 :           0 :     size = offsetof(SharedIndexScanInstrumentation, winstrument) +
     445                 :           0 :         SharedInfo->num_workers * sizeof(IndexScanInstrumentation);
     446                 :           0 :     node->biss_SharedInfo = palloc(size);
     447                 :           0 :     memcpy(node->biss_SharedInfo, SharedInfo, size);
     448                 :             : }
        

Generated by: LCOV version 2.0-1