LCOV - code coverage report
Current view: top level - src/backend/executor - nodeIndexonlyscan.c (source / functions) Coverage Total Hit
Test: PostgreSQL 20devel Lines: 73.4 % 173 127
Test Date: 2026-10-02 21:15:44 Functions: 81.2 % 16 13
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
Branches: 51.1 % 92 47

             Branch data     Line data    Source code
       1                 :             : /*-------------------------------------------------------------------------
       2                 :             :  *
       3                 :             :  * nodeIndexonlyscan.c
       4                 :             :  *    Routines to support index-only scans
       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/nodeIndexonlyscan.c
      12                 :             :  *
      13                 :             :  *-------------------------------------------------------------------------
      14                 :             :  */
      15                 :             : /*
      16                 :             :  * INTERFACE ROUTINES
      17                 :             :  *      ExecIndexOnlyScan           scans an index
      18                 :             :  *      IndexOnlyNext               retrieve next tuple
      19                 :             :  *      ExecInitIndexOnlyScan       creates and initializes state info.
      20                 :             :  *      ExecReScanIndexOnlyScan     rescans the indexed relation.
      21                 :             :  *      ExecEndIndexOnlyScan        releases all storage.
      22                 :             :  *      ExecIndexOnlyMarkPos        marks scan position.
      23                 :             :  *      ExecIndexOnlyRestrPos       restores scan position.
      24                 :             :  *      ExecIndexOnlyScanEstimate   estimates DSM space needed for
      25                 :             :  *                      parallel index-only scan
      26                 :             :  *      ExecIndexOnlyScanInitializeDSM  initialize DSM for parallel
      27                 :             :  *                      index-only scan
      28                 :             :  *      ExecIndexOnlyScanReInitializeDSM    reinitialize DSM for fresh scan
      29                 :             :  *      ExecIndexOnlyScanInitializeWorker attach to DSM info in parallel worker
      30                 :             :  */
      31                 :             : #include "postgres.h"
      32                 :             : 
      33                 :             : #include "access/genam.h"
      34                 :             : #include "access/relscan.h"
      35                 :             : #include "access/tableam.h"
      36                 :             : #include "executor/executor.h"
      37                 :             : #include "executor/instrument.h"
      38                 :             : #include "executor/nodeIndexonlyscan.h"
      39                 :             : #include "executor/nodeIndexscan.h"
      40                 :             : #include "miscadmin.h"
      41                 :             : #include "utils/rel.h"
      42                 :             : 
      43                 :             : 
      44                 :             : static TupleTableSlot *IndexOnlyNext(IndexOnlyScanState *node);
      45                 :             : 
      46                 :             : 
      47                 :             : /* ----------------------------------------------------------------
      48                 :             :  *      IndexOnlyNext
      49                 :             :  *
      50                 :             :  *      Retrieve a tuple from the IndexOnlyScan node's index.
      51                 :             :  * ----------------------------------------------------------------
      52                 :             :  */
      53                 :             : static TupleTableSlot *
      54                 :     4015370 : IndexOnlyNext(IndexOnlyScanState *node)
      55                 :             : {
      56                 :             :     EState     *estate;
      57                 :             :     ExprContext *econtext;
      58                 :             :     ScanDirection direction;
      59                 :             :     IndexScanDesc scandesc;
      60                 :             :     TupleTableSlot *slot;
      61                 :             : 
      62                 :             :     /*
      63                 :             :      * extract necessary information from index scan node
      64                 :             :      */
      65                 :     4015370 :     estate = node->ss.ps.state;
      66                 :             : 
      67                 :             :     /*
      68                 :             :      * Determine which direction to scan the index in based on the plan's scan
      69                 :             :      * direction and the current direction of execution.
      70                 :             :      */
      71                 :     4015370 :     direction = ScanDirectionCombine(estate->es_direction,
      72                 :             :                                      ((IndexOnlyScan *) node->ss.ps.plan)->indexorderdir);
      73                 :     4015370 :     scandesc = node->ioss_ScanDesc;
      74                 :     4015370 :     econtext = node->ss.ps.ps_ExprContext;
      75                 :     4015370 :     slot = node->ss.ss_ScanTupleSlot;
      76                 :             : 
      77         [ +  + ]:     4015370 :     if (scandesc == NULL)
      78                 :             :     {
      79                 :             :         /*
      80                 :             :          * We reach here if the index only scan is not parallel, or if we're
      81                 :             :          * serially executing an index only scan that was planned to be
      82                 :             :          * parallel.
      83                 :             :          */
      84         [ +  - ]:        6801 :         scandesc = index_beginscan(node->ss.ss_currentRelation,
      85                 :             :                                    node->ioss_RelationDesc,
      86                 :             :                                    true,
      87                 :             :                                    estate->es_snapshot,
      88                 :             :                                    node->ioss_Instrument,
      89                 :             :                                    node->ioss_NumScanKeys,
      90                 :             :                                    node->ioss_NumOrderByKeys,
      91                 :        6801 :                                    ScanRelIsReadOnly(&node->ss) ?
      92                 :             :                                    SO_HINT_REL_READ_ONLY : SO_NONE);
      93                 :             : 
      94                 :        6801 :         node->ioss_ScanDesc = scandesc;
      95                 :             :         Assert(node->ioss_ScanDesc->xs_want_itup);
      96                 :             : 
      97                 :             :         /*
      98                 :             :          * If no run-time keys to calculate or they are ready, go ahead and
      99                 :             :          * pass the scankeys to the index AM.
     100                 :             :          */
     101   [ +  +  +  - ]:        6801 :         if (node->ioss_NumRuntimeKeys == 0 || node->ioss_RuntimeKeysReady)
     102                 :        6801 :             index_rescan(scandesc,
     103                 :             :                          node->ioss_ScanKeys,
     104                 :             :                          node->ioss_NumScanKeys,
     105                 :             :                          node->ioss_OrderByKeys,
     106                 :             :                          node->ioss_NumOrderByKeys);
     107                 :             :     }
     108                 :             : 
     109                 :             :     /*
     110                 :             :      * OK, now that we have what we need, fetch the next tuple.
     111                 :             :      */
     112         [ +  + ]:     4015374 :     while (table_index_getnext_slot(scandesc, direction, slot))
     113                 :             :     {
     114         [ +  + ]:     3884424 :         CHECK_FOR_INTERRUPTS();
     115                 :             : 
     116                 :             :         /*
     117                 :             :          * If the index was lossy, we have to recheck the index quals.
     118                 :             :          */
     119         [ +  + ]:     3884424 :         if (scandesc->xs_recheck)
     120                 :             :         {
     121                 :           9 :             econtext->ecxt_scantuple = slot;
     122         [ +  + ]:           9 :             if (!ExecQualAndReset(node->recheckqual, econtext))
     123                 :             :             {
     124                 :             :                 /* Fails recheck, so drop it and loop back for another */
     125         [ -  + ]:           4 :                 InstrCountFiltered2(node, 1);
     126                 :           4 :                 continue;
     127                 :             :             }
     128                 :             :         }
     129                 :             : 
     130                 :             :         /*
     131                 :             :          * We don't currently support rechecking ORDER BY distances.  (In
     132                 :             :          * principle, if the index can support retrieval of the originally
     133                 :             :          * indexed value, it should be able to produce an exact distance
     134                 :             :          * calculation too.  So it's not clear that adding code here for
     135                 :             :          * recheck/re-sort would be worth the trouble.  But we should at least
     136                 :             :          * throw an error if someone tries it.)
     137                 :             :          */
     138   [ +  +  +  + ]:     3884420 :         if (scandesc->numberOfOrderBys > 0 && scandesc->xs_recheckorderby)
     139         [ +  - ]:           4 :             ereport(ERROR,
     140                 :             :                     (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
     141                 :             :                      errmsg("lossy distance functions are not supported in index-only scans")));
     142                 :     3884416 :         return slot;
     143                 :             :     }
     144                 :             : 
     145                 :             :     /*
     146                 :             :      * if we get here it means the index scan failed so we are at the end of
     147                 :             :      * the scan..
     148                 :             :      */
     149                 :      130950 :     return ExecClearTuple(slot);
     150                 :             : }
     151                 :             : 
     152                 :             : /*
     153                 :             :  * IndexOnlyRecheck -- access method routine to recheck a tuple in EvalPlanQual
     154                 :             :  *
     155                 :             :  * This can't really happen, since an index can't supply CTID which would
     156                 :             :  * be necessary data for any potential EvalPlanQual target relation.  If it
     157                 :             :  * did happen, the EPQ code would pass us the wrong data, namely a heap
     158                 :             :  * tuple not an index tuple.  So throw an error.
     159                 :             :  */
     160                 :             : static bool
     161                 :           0 : IndexOnlyRecheck(IndexOnlyScanState *node, TupleTableSlot *slot)
     162                 :             : {
     163         [ #  # ]:           0 :     elog(ERROR, "EvalPlanQual recheck is not supported in index-only scans");
     164                 :             :     return false;               /* keep compiler quiet */
     165                 :             : }
     166                 :             : 
     167                 :             : /* ----------------------------------------------------------------
     168                 :             :  *      ExecIndexOnlyScan(node)
     169                 :             :  * ----------------------------------------------------------------
     170                 :             :  */
     171                 :             : static TupleTableSlot *
     172                 :     3811450 : ExecIndexOnlyScan(PlanState *pstate)
     173                 :             : {
     174                 :     3811450 :     IndexOnlyScanState *node = castNode(IndexOnlyScanState, pstate);
     175                 :             : 
     176                 :             :     /*
     177                 :             :      * If we have runtime keys and they've not already been set up, do it now.
     178                 :             :      */
     179   [ +  +  +  + ]:     3811450 :     if (node->ioss_NumRuntimeKeys != 0 && !node->ioss_RuntimeKeysReady)
     180                 :         370 :         ExecReScan((PlanState *) node);
     181                 :             : 
     182                 :     3811450 :     return ExecScan(&node->ss,
     183                 :             :                     (ExecScanAccessMtd) IndexOnlyNext,
     184                 :             :                     (ExecScanRecheckMtd) IndexOnlyRecheck);
     185                 :             : }
     186                 :             : 
     187                 :             : /* ----------------------------------------------------------------
     188                 :             :  *      ExecReScanIndexOnlyScan(node)
     189                 :             :  *
     190                 :             :  *      Recalculates the values of any scan keys whose value depends on
     191                 :             :  *      information known at runtime, then rescans the indexed relation.
     192                 :             :  *
     193                 :             :  *      Updating the scan key was formerly done separately in
     194                 :             :  *      ExecUpdateIndexScanKeys. Integrating it into ReScan makes
     195                 :             :  *      rescans of indices and relations/general streams more uniform.
     196                 :             :  * ----------------------------------------------------------------
     197                 :             :  */
     198                 :             : void
     199                 :      143368 : ExecReScanIndexOnlyScan(IndexOnlyScanState *node)
     200                 :             : {
     201                 :             :     /*
     202                 :             :      * If we are doing runtime key calculations (ie, any of the index key
     203                 :             :      * values weren't simple Consts), compute the new key values.  But first,
     204                 :             :      * reset the context so we don't leak memory as each outer tuple is
     205                 :             :      * scanned.  Note this assumes that we will recalculate *all* runtime keys
     206                 :             :      * on each call.
     207                 :             :      */
     208         [ +  + ]:      143368 :     if (node->ioss_NumRuntimeKeys != 0)
     209                 :             :     {
     210                 :      143294 :         ExprContext *econtext = node->ioss_RuntimeContext;
     211                 :             : 
     212                 :      143294 :         ResetExprContext(econtext);
     213                 :      143294 :         ExecIndexEvalRuntimeKeys(econtext,
     214                 :             :                                  node->ioss_RuntimeKeys,
     215                 :             :                                  node->ioss_NumRuntimeKeys);
     216                 :             :     }
     217                 :      143368 :     node->ioss_RuntimeKeysReady = true;
     218                 :             : 
     219                 :             :     /* reset index scan */
     220         [ +  + ]:      143368 :     if (node->ioss_ScanDesc)
     221                 :      141724 :         index_rescan(node->ioss_ScanDesc,
     222                 :             :                      node->ioss_ScanKeys, node->ioss_NumScanKeys,
     223                 :             :                      node->ioss_OrderByKeys, node->ioss_NumOrderByKeys);
     224                 :             : 
     225                 :      143368 :     ExecScanReScan(&node->ss);
     226                 :      143368 : }
     227                 :             : 
     228                 :             : 
     229                 :             : /* ----------------------------------------------------------------
     230                 :             :  *      ExecEndIndexOnlyScan
     231                 :             :  * ----------------------------------------------------------------
     232                 :             :  */
     233                 :             : void
     234                 :       11591 : ExecEndIndexOnlyScan(IndexOnlyScanState *node)
     235                 :             : {
     236                 :             :     Relation    indexRelationDesc;
     237                 :             :     IndexScanDesc indexScanDesc;
     238                 :             : 
     239                 :             :     /*
     240                 :             :      * extract information from the node
     241                 :             :      */
     242                 :       11591 :     indexRelationDesc = node->ioss_RelationDesc;
     243                 :       11591 :     indexScanDesc = node->ioss_ScanDesc;
     244                 :             : 
     245                 :             :     /*
     246                 :             :      * When ending a parallel worker, copy the statistics gathered by the
     247                 :             :      * worker back into shared memory so that it can be picked up by the main
     248                 :             :      * process to report in EXPLAIN ANALYZE
     249                 :             :      */
     250   [ -  +  -  - ]:       11591 :     if (node->ioss_SharedInfo != NULL && IsParallelWorker())
     251                 :             :     {
     252                 :             :         IndexScanInstrumentation *winstrument;
     253                 :             : 
     254                 :             :         Assert(ParallelWorkerNumber < node->ioss_SharedInfo->num_workers);
     255                 :           0 :         winstrument = &node->ioss_SharedInfo->winstrument[ParallelWorkerNumber];
     256                 :             : 
     257                 :             :         /*
     258                 :             :          * We have to accumulate the stats rather than performing a memcpy.
     259                 :             :          * When a Gather/GatherMerge node finishes it will perform planner
     260                 :             :          * shutdown on the workers.  On rescan it will spin up new workers
     261                 :             :          * which will have a new IndexOnlyScanState and zeroed stats.
     262                 :             :          */
     263                 :           0 :         winstrument->nsearches += node->ioss_Instrument->nsearches;
     264                 :           0 :         winstrument->ntabletuplefetches += node->ioss_Instrument->ntabletuplefetches;
     265                 :             :     }
     266                 :             : 
     267                 :             :     /*
     268                 :             :      * close the index relation (no-op if we didn't open it)
     269                 :             :      */
     270         [ +  + ]:       11591 :     if (indexScanDesc)
     271                 :        6934 :         index_endscan(indexScanDesc);
     272         [ +  + ]:       11591 :     if (indexRelationDesc)
     273                 :        9758 :         index_close(indexRelationDesc, NoLock);
     274                 :       11591 : }
     275                 :             : 
     276                 :             : /* ----------------------------------------------------------------
     277                 :             :  *      ExecIndexOnlyMarkPos
     278                 :             :  *
     279                 :             :  * Note: we assume that no caller attempts to set a mark before having read
     280                 :             :  * at least one tuple.  Otherwise, ioss_ScanDesc might still be NULL.
     281                 :             :  * ----------------------------------------------------------------
     282                 :             :  */
     283                 :             : void
     284                 :       82019 : ExecIndexOnlyMarkPos(IndexOnlyScanState *node)
     285                 :             : {
     286                 :       82019 :     EState     *estate = node->ss.ps.state;
     287                 :       82019 :     EPQState   *epqstate = estate->es_epq_active;
     288                 :             : 
     289         [ -  + ]:       82019 :     if (epqstate != NULL)
     290                 :             :     {
     291                 :             :         /*
     292                 :             :          * We are inside an EvalPlanQual recheck.  If a test tuple exists for
     293                 :             :          * this relation, then we shouldn't access the index at all.  We would
     294                 :             :          * instead need to save, and later restore, the state of the
     295                 :             :          * relsubs_done flag, so that re-fetching the test tuple is possible.
     296                 :             :          * However, given the assumption that no caller sets a mark at the
     297                 :             :          * start of the scan, we can only get here with relsubs_done[i]
     298                 :             :          * already set, and so no state need be saved.
     299                 :             :          */
     300                 :           0 :         Index       scanrelid = ((Scan *) node->ss.ps.plan)->scanrelid;
     301                 :             : 
     302                 :             :         Assert(scanrelid > 0);
     303         [ #  # ]:           0 :         if (epqstate->relsubs_slot[scanrelid - 1] != NULL ||
     304         [ #  # ]:           0 :             epqstate->relsubs_rowmark[scanrelid - 1] != NULL)
     305                 :             :         {
     306                 :             :             /* Verify the claim above */
     307         [ #  # ]:           0 :             if (!epqstate->relsubs_done[scanrelid - 1])
     308         [ #  # ]:           0 :                 elog(ERROR, "unexpected ExecIndexOnlyMarkPos call in EPQ recheck");
     309                 :           0 :             return;
     310                 :             :         }
     311                 :             :     }
     312                 :             : 
     313                 :       82019 :     index_markpos(node->ioss_ScanDesc);
     314                 :             : }
     315                 :             : 
     316                 :             : /* ----------------------------------------------------------------
     317                 :             :  *      ExecIndexOnlyRestrPos
     318                 :             :  * ----------------------------------------------------------------
     319                 :             :  */
     320                 :             : void
     321                 :           0 : ExecIndexOnlyRestrPos(IndexOnlyScanState *node)
     322                 :             : {
     323                 :           0 :     EState     *estate = node->ss.ps.state;
     324                 :           0 :     EPQState   *epqstate = estate->es_epq_active;
     325                 :             : 
     326         [ #  # ]:           0 :     if (estate->es_epq_active != NULL)
     327                 :             :     {
     328                 :             :         /* See comments in ExecIndexMarkPos */
     329                 :           0 :         Index       scanrelid = ((Scan *) node->ss.ps.plan)->scanrelid;
     330                 :             : 
     331                 :             :         Assert(scanrelid > 0);
     332         [ #  # ]:           0 :         if (epqstate->relsubs_slot[scanrelid - 1] != NULL ||
     333         [ #  # ]:           0 :             epqstate->relsubs_rowmark[scanrelid - 1] != NULL)
     334                 :             :         {
     335                 :             :             /* Verify the claim above */
     336         [ #  # ]:           0 :             if (!epqstate->relsubs_done[scanrelid - 1])
     337         [ #  # ]:           0 :                 elog(ERROR, "unexpected ExecIndexOnlyRestrPos call in EPQ recheck");
     338                 :           0 :             return;
     339                 :             :         }
     340                 :             :     }
     341                 :             : 
     342                 :           0 :     index_restrpos(node->ioss_ScanDesc);
     343                 :             : }
     344                 :             : 
     345                 :             : /* ----------------------------------------------------------------
     346                 :             :  *      ExecInitIndexOnlyScan
     347                 :             :  *
     348                 :             :  *      Initializes the index scan's state information, creates
     349                 :             :  *      scan keys, and opens the base and index relations.
     350                 :             :  *
     351                 :             :  *      Note: index scans have 2 sets of state information because
     352                 :             :  *            we have to keep track of the base relation and the
     353                 :             :  *            index relation.
     354                 :             :  * ----------------------------------------------------------------
     355                 :             :  */
     356                 :             : IndexOnlyScanState *
     357                 :       11624 : ExecInitIndexOnlyScan(IndexOnlyScan *node, EState *estate, int eflags)
     358                 :             : {
     359                 :             :     IndexOnlyScanState *indexstate;
     360                 :             :     Relation    currentRelation;
     361                 :             :     Relation    indexRelation;
     362                 :             :     LOCKMODE    lockmode;
     363                 :             :     TupleDesc   tupDesc;
     364                 :             : 
     365                 :             :     /*
     366                 :             :      * create state structure
     367                 :             :      */
     368                 :       11624 :     indexstate = makeNode(IndexOnlyScanState);
     369                 :       11624 :     indexstate->ss.ps.plan = (Plan *) node;
     370                 :       11624 :     indexstate->ss.ps.state = estate;
     371                 :       11624 :     indexstate->ss.ps.ExecProcNode = ExecIndexOnlyScan;
     372                 :             : 
     373                 :             :     /*
     374                 :             :      * Miscellaneous initialization
     375                 :             :      *
     376                 :             :      * create expression context for node
     377                 :             :      */
     378                 :       11624 :     ExecAssignExprContext(estate, &indexstate->ss.ps);
     379                 :             : 
     380                 :             :     /*
     381                 :             :      * open the scan relation
     382                 :             :      */
     383                 :       11624 :     currentRelation = ExecOpenScanRelation(estate, node->scan.scanrelid, eflags);
     384                 :             : 
     385                 :       11624 :     indexstate->ss.ss_currentRelation = currentRelation;
     386                 :       11624 :     indexstate->ss.ss_currentScanDesc = NULL;    /* no heap scan here */
     387                 :             : 
     388                 :             :     /*
     389                 :             :      * Build the scan tuple type using the indextlist generated by the
     390                 :             :      * planner.  We use this, rather than the index's physical tuple
     391                 :             :      * descriptor, because the latter contains storage column types not the
     392                 :             :      * types of the original datums.  (It's the index AM's responsibility to
     393                 :             :      * return suitable data anyway.  The table AM fills our slot with that
     394                 :             :      * returned data.)
     395                 :             :      */
     396                 :       11624 :     tupDesc = ExecTypeFromTL(node->indextlist);
     397                 :       11624 :     ExecInitScanTupleSlot(estate, &indexstate->ss, tupDesc,
     398                 :             :                           &TTSOpsVirtual,
     399                 :             :                           0);
     400                 :             : 
     401                 :             :     /*
     402                 :             :      * Initialize result type and projection info.  The node's targetlist will
     403                 :             :      * contain Vars with varno = INDEX_VAR, referencing the scan tuple.
     404                 :             :      */
     405                 :       11624 :     ExecInitResultTypeTL(&indexstate->ss.ps);
     406                 :       11624 :     ExecAssignScanProjectionInfoWithVarno(&indexstate->ss, INDEX_VAR);
     407                 :             : 
     408                 :             :     /*
     409                 :             :      * initialize child expressions
     410                 :             :      *
     411                 :             :      * Note: we don't initialize all of the indexorderby expression, only the
     412                 :             :      * sub-parts corresponding to runtime keys (see below).
     413                 :             :      */
     414                 :       11624 :     indexstate->ss.ps.qual =
     415                 :       11624 :         ExecInitQual(node->scan.plan.qual, (PlanState *) indexstate);
     416                 :       11624 :     indexstate->recheckqual =
     417                 :       11624 :         ExecInitQual(node->recheckqual, (PlanState *) indexstate);
     418                 :             : 
     419                 :             :     /*
     420                 :             :      * If we are just doing EXPLAIN (ie, aren't going to run the plan), stop
     421                 :             :      * here.  This allows an index-advisor plugin to EXPLAIN a plan containing
     422                 :             :      * references to nonexistent indexes.
     423                 :             :      */
     424         [ +  + ]:       11624 :     if (eflags & EXEC_FLAG_EXPLAIN_ONLY)
     425                 :        1833 :         return indexstate;
     426                 :             : 
     427                 :             :     /* Set up instrumentation of index-only scans if requested */
     428         [ +  + ]:        9791 :     if (estate->es_instrument)
     429                 :          80 :         indexstate->ioss_Instrument = palloc0_object(IndexScanInstrumentation);
     430                 :             : 
     431                 :             :     /* Open the index relation. */
     432                 :        9791 :     lockmode = exec_rt_fetch(node->scan.scanrelid, estate)->rellockmode;
     433                 :        9791 :     indexRelation = index_open(node->indexid, lockmode);
     434                 :        9791 :     indexstate->ioss_RelationDesc = indexRelation;
     435                 :             : 
     436                 :             :     /*
     437                 :             :      * Initialize index-specific scan state
     438                 :             :      */
     439                 :        9791 :     indexstate->ioss_RuntimeKeysReady = false;
     440                 :        9791 :     indexstate->ioss_RuntimeKeys = NULL;
     441                 :        9791 :     indexstate->ioss_NumRuntimeKeys = 0;
     442                 :             : 
     443                 :             :     /*
     444                 :             :      * build the index scan keys from the index qualification
     445                 :             :      */
     446                 :        9791 :     ExecIndexBuildScanKeys((PlanState *) indexstate,
     447                 :             :                            indexRelation,
     448                 :             :                            node->indexqual,
     449                 :             :                            false,
     450                 :        9791 :                            &indexstate->ioss_ScanKeys,
     451                 :             :                            &indexstate->ioss_NumScanKeys,
     452                 :             :                            &indexstate->ioss_RuntimeKeys,
     453                 :             :                            &indexstate->ioss_NumRuntimeKeys,
     454                 :             :                            NULL,    /* no ArrayKeys */
     455                 :             :                            NULL);
     456                 :             : 
     457                 :             :     /*
     458                 :             :      * any ORDER BY exprs have to be turned into scankeys in the same way
     459                 :             :      */
     460                 :        9791 :     ExecIndexBuildScanKeys((PlanState *) indexstate,
     461                 :             :                            indexRelation,
     462                 :             :                            node->indexorderby,
     463                 :             :                            true,
     464                 :        9791 :                            &indexstate->ioss_OrderByKeys,
     465                 :             :                            &indexstate->ioss_NumOrderByKeys,
     466                 :             :                            &indexstate->ioss_RuntimeKeys,
     467                 :             :                            &indexstate->ioss_NumRuntimeKeys,
     468                 :             :                            NULL,    /* no ArrayKeys */
     469                 :             :                            NULL);
     470                 :             : 
     471                 :             :     /*
     472                 :             :      * If we have runtime keys, we need an ExprContext to evaluate them. The
     473                 :             :      * node's standard context won't do because we want to reset that context
     474                 :             :      * for every tuple.  So, build another context just like the other one...
     475                 :             :      * -tgl 7/11/00
     476                 :             :      */
     477         [ +  + ]:        9791 :     if (indexstate->ioss_NumRuntimeKeys != 0)
     478                 :             :     {
     479                 :        4343 :         ExprContext *stdecontext = indexstate->ss.ps.ps_ExprContext;
     480                 :             : 
     481                 :        4343 :         ExecAssignExprContext(estate, &indexstate->ss.ps);
     482                 :        4343 :         indexstate->ioss_RuntimeContext = indexstate->ss.ps.ps_ExprContext;
     483                 :        4343 :         indexstate->ss.ps.ps_ExprContext = stdecontext;
     484                 :             :     }
     485                 :             :     else
     486                 :             :     {
     487                 :        5448 :         indexstate->ioss_RuntimeContext = NULL;
     488                 :             :     }
     489                 :             : 
     490                 :             :     /*
     491                 :             :      * all done.
     492                 :             :      */
     493                 :        9791 :     return indexstate;
     494                 :             : }
     495                 :             : 
     496                 :             : /* ----------------------------------------------------------------
     497                 :             :  *      Parallel Index-only Scan Support
     498                 :             :  * ----------------------------------------------------------------
     499                 :             :  */
     500                 :             : 
     501                 :             : /* ----------------------------------------------------------------
     502                 :             :  *      ExecIndexOnlyScanEstimate
     503                 :             :  *
     504                 :             :  *      Compute the amount of space we'll need in the parallel
     505                 :             :  *      query DSM, and inform pcxt->estimator about our needs.
     506                 :             :  * ----------------------------------------------------------------
     507                 :             :  */
     508                 :             : void
     509                 :          30 : ExecIndexOnlyScanEstimate(IndexOnlyScanState *node,
     510                 :             :                           ParallelContext *pcxt)
     511                 :             : {
     512                 :          30 :     EState     *estate = node->ss.ps.state;
     513                 :             : 
     514                 :          30 :     node->ioss_PscanLen = index_parallelscan_estimate(node->ioss_RelationDesc,
     515                 :             :                                                       node->ioss_NumScanKeys,
     516                 :             :                                                       node->ioss_NumOrderByKeys,
     517                 :             :                                                       estate->es_snapshot);
     518                 :          30 :     shm_toc_estimate_chunk(&pcxt->estimator, node->ioss_PscanLen);
     519                 :          30 :     shm_toc_estimate_keys(&pcxt->estimator, 1);
     520                 :          30 : }
     521                 :             : 
     522                 :             : /* ----------------------------------------------------------------
     523                 :             :  *      ExecIndexOnlyScanInitializeDSM
     524                 :             :  *
     525                 :             :  *      Set up a parallel index-only scan descriptor.
     526                 :             :  * ----------------------------------------------------------------
     527                 :             :  */
     528                 :             : void
     529                 :          30 : ExecIndexOnlyScanInitializeDSM(IndexOnlyScanState *node,
     530                 :             :                                ParallelContext *pcxt)
     531                 :             : {
     532                 :          30 :     EState     *estate = node->ss.ps.state;
     533                 :             :     ParallelIndexScanDesc piscan;
     534                 :             : 
     535                 :          30 :     piscan = shm_toc_allocate(pcxt->toc, node->ioss_PscanLen);
     536                 :          30 :     index_parallelscan_initialize(node->ss.ss_currentRelation,
     537                 :             :                                   node->ioss_RelationDesc,
     538                 :             :                                   estate->es_snapshot,
     539                 :             :                                   piscan);
     540                 :          30 :     shm_toc_insert(pcxt->toc, node->ss.ps.plan->plan_node_id, piscan);
     541                 :             : 
     542                 :          30 :     node->ioss_ScanDesc =
     543         [ +  - ]:          30 :         index_beginscan_parallel(node->ss.ss_currentRelation,
     544                 :             :                                  node->ioss_RelationDesc,
     545                 :             :                                  true,
     546                 :             :                                  node->ioss_Instrument,
     547                 :             :                                  node->ioss_NumScanKeys,
     548                 :             :                                  node->ioss_NumOrderByKeys,
     549                 :             :                                  piscan,
     550                 :          30 :                                  ScanRelIsReadOnly(&node->ss) ?
     551                 :             :                                  SO_HINT_REL_READ_ONLY : SO_NONE);
     552                 :             :     Assert(node->ioss_ScanDesc->xs_want_itup);
     553                 :             : 
     554                 :             :     /*
     555                 :             :      * If no run-time keys to calculate or they are ready, go ahead and pass
     556                 :             :      * the scankeys to the index AM.
     557                 :             :      */
     558   [ -  +  -  - ]:          30 :     if (node->ioss_NumRuntimeKeys == 0 || node->ioss_RuntimeKeysReady)
     559                 :          30 :         index_rescan(node->ioss_ScanDesc,
     560                 :             :                      node->ioss_ScanKeys, node->ioss_NumScanKeys,
     561                 :             :                      node->ioss_OrderByKeys, node->ioss_NumOrderByKeys);
     562                 :          30 : }
     563                 :             : 
     564                 :             : /* ----------------------------------------------------------------
     565                 :             :  *      ExecIndexOnlyScanReInitializeDSM
     566                 :             :  *
     567                 :             :  *      Reset shared state before beginning a fresh scan.
     568                 :             :  * ----------------------------------------------------------------
     569                 :             :  */
     570                 :             : void
     571                 :           8 : ExecIndexOnlyScanReInitializeDSM(IndexOnlyScanState *node,
     572                 :             :                                  ParallelContext *pcxt)
     573                 :             : {
     574                 :             :     Assert(node->ss.ps.plan->parallel_aware);
     575                 :           8 :     index_parallelrescan(node->ioss_ScanDesc);
     576                 :           8 : }
     577                 :             : 
     578                 :             : /* ----------------------------------------------------------------
     579                 :             :  *      ExecIndexOnlyScanInitializeWorker
     580                 :             :  *
     581                 :             :  *      Copy relevant information from TOC into planstate.
     582                 :             :  * ----------------------------------------------------------------
     583                 :             :  */
     584                 :             : void
     585                 :         136 : ExecIndexOnlyScanInitializeWorker(IndexOnlyScanState *node,
     586                 :             :                                   ParallelWorkerContext *pwcxt)
     587                 :             : {
     588                 :             :     ParallelIndexScanDesc piscan;
     589                 :             : 
     590                 :         136 :     piscan = shm_toc_lookup(pwcxt->toc, node->ss.ps.plan->plan_node_id, false);
     591                 :             : 
     592                 :         136 :     node->ioss_ScanDesc =
     593         [ +  - ]:         136 :         index_beginscan_parallel(node->ss.ss_currentRelation,
     594                 :             :                                  node->ioss_RelationDesc,
     595                 :             :                                  true,
     596                 :             :                                  node->ioss_Instrument,
     597                 :             :                                  node->ioss_NumScanKeys,
     598                 :             :                                  node->ioss_NumOrderByKeys,
     599                 :             :                                  piscan,
     600                 :         136 :                                  ScanRelIsReadOnly(&node->ss) ?
     601                 :             :                                  SO_HINT_REL_READ_ONLY : SO_NONE);
     602                 :             :     Assert(node->ioss_ScanDesc->xs_want_itup);
     603                 :             : 
     604                 :             :     /*
     605                 :             :      * If no run-time keys to calculate or they are ready, go ahead and pass
     606                 :             :      * the scankeys to the index AM.
     607                 :             :      */
     608   [ -  +  -  - ]:         136 :     if (node->ioss_NumRuntimeKeys == 0 || node->ioss_RuntimeKeysReady)
     609                 :         136 :         index_rescan(node->ioss_ScanDesc,
     610                 :             :                      node->ioss_ScanKeys, node->ioss_NumScanKeys,
     611                 :             :                      node->ioss_OrderByKeys, node->ioss_NumOrderByKeys);
     612                 :         136 : }
     613                 :             : 
     614                 :             : /*
     615                 :             :  * Compute the amount of space we'll need for the shared instrumentation and
     616                 :             :  * inform pcxt->estimator.
     617                 :             :  */
     618                 :             : void
     619                 :          38 : ExecIndexOnlyScanInstrumentEstimate(IndexOnlyScanState *node,
     620                 :             :                                     ParallelContext *pcxt)
     621                 :             : {
     622                 :             :     Size        size;
     623                 :             : 
     624   [ -  +  -  - ]:          38 :     if (!node->ss.ps.instrument || pcxt->nworkers == 0)
     625                 :          38 :         return;
     626                 :             : 
     627                 :             :     /*
     628                 :             :      * This size calculation is trivial enough that we don't bother saving it
     629                 :             :      * in the IndexOnlyScanState. We'll recalculate the needed size in
     630                 :             :      * ExecIndexOnlyScanInstrumentInitDSM().
     631                 :             :      */
     632                 :           0 :     size = add_size(offsetof(SharedIndexScanInstrumentation, winstrument),
     633                 :           0 :                     mul_size(pcxt->nworkers, sizeof(IndexScanInstrumentation)));
     634                 :           0 :     shm_toc_estimate_chunk(&pcxt->estimator, size);
     635                 :           0 :     shm_toc_estimate_keys(&pcxt->estimator, 1);
     636                 :             : }
     637                 :             : 
     638                 :             : /*
     639                 :             :  * Set up parallel index-only scan instrumentation.
     640                 :             :  */
     641                 :             : void
     642                 :          38 : ExecIndexOnlyScanInstrumentInitDSM(IndexOnlyScanState *node,
     643                 :             :                                    ParallelContext *pcxt)
     644                 :             : {
     645                 :             :     Size        size;
     646                 :             : 
     647   [ -  +  -  - ]:          38 :     if (!node->ss.ps.instrument || pcxt->nworkers == 0)
     648                 :          38 :         return;
     649                 :             : 
     650                 :           0 :     size = add_size(offsetof(SharedIndexScanInstrumentation, winstrument),
     651                 :           0 :                     mul_size(pcxt->nworkers, sizeof(IndexScanInstrumentation)));
     652                 :           0 :     node->ioss_SharedInfo =
     653                 :           0 :         (SharedIndexScanInstrumentation *) shm_toc_allocate(pcxt->toc, size);
     654                 :             : 
     655                 :             :     /* Each per-worker area must start out as zeroes */
     656                 :           0 :     memset(node->ioss_SharedInfo, 0, size);
     657                 :           0 :     node->ioss_SharedInfo->num_workers = pcxt->nworkers;
     658                 :           0 :     shm_toc_insert(pcxt->toc,
     659                 :           0 :                    node->ss.ps.plan->plan_node_id +
     660                 :             :                    PARALLEL_KEY_SCAN_INSTRUMENT_OFFSET,
     661                 :           0 :                    node->ioss_SharedInfo);
     662                 :             : }
     663                 :             : 
     664                 :             : /*
     665                 :             :  * Look up and save the location of the shared instrumentation.
     666                 :             :  */
     667                 :             : void
     668                 :         160 : ExecIndexOnlyScanInstrumentInitWorker(IndexOnlyScanState *node,
     669                 :             :                                       ParallelWorkerContext *pwcxt)
     670                 :             : {
     671         [ +  - ]:         160 :     if (!node->ss.ps.instrument)
     672                 :         160 :         return;
     673                 :             : 
     674                 :           0 :     node->ioss_SharedInfo = (SharedIndexScanInstrumentation *)
     675                 :           0 :         shm_toc_lookup(pwcxt->toc,
     676                 :           0 :                        node->ss.ps.plan->plan_node_id +
     677                 :             :                        PARALLEL_KEY_SCAN_INSTRUMENT_OFFSET,
     678                 :             :                        false);
     679                 :             : }
     680                 :             : 
     681                 :             : /* ----------------------------------------------------------------
     682                 :             :  *      ExecIndexOnlyScanRetrieveInstrumentation
     683                 :             :  *
     684                 :             :  *      Transfer index-only scan statistics from DSM to private memory.
     685                 :             :  * ----------------------------------------------------------------
     686                 :             :  */
     687                 :             : void
     688                 :           0 : ExecIndexOnlyScanRetrieveInstrumentation(IndexOnlyScanState *node)
     689                 :             : {
     690                 :           0 :     SharedIndexScanInstrumentation *SharedInfo = node->ioss_SharedInfo;
     691                 :             :     size_t      size;
     692                 :             : 
     693         [ #  # ]:           0 :     if (SharedInfo == NULL)
     694                 :           0 :         return;
     695                 :             : 
     696                 :             :     /* Create a copy of SharedInfo in backend-local memory */
     697                 :           0 :     size = offsetof(SharedIndexScanInstrumentation, winstrument) +
     698                 :           0 :         SharedInfo->num_workers * sizeof(IndexScanInstrumentation);
     699                 :           0 :     node->ioss_SharedInfo = palloc(size);
     700                 :           0 :     memcpy(node->ioss_SharedInfo, SharedInfo, size);
     701                 :             : }
        

Generated by: LCOV version 2.0-1