LCOV - code coverage report
Current view: top level - src/backend/executor - nodeBitmapIndexscan.c (source / functions) Coverage Total Hit
Test: Code coverage Lines: 78.7 % 155 122
Test Date: 2026-01-26 10:56:24 Functions: 77.8 % 9 7
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
Branches: 65.3 % 72 47

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

Generated by: LCOV version 2.3.2-1