LCOV - code coverage report
Current view: top level - src/backend/executor - nodeIndexonlyscan.c (source / functions) Hit Total Coverage
Test: PostgreSQL Lines: 145 160 90.6 %
Date: 2017-09-29 15:12:54 Functions: 11 13 84.6 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*-------------------------------------------------------------------------
       2             :  *
       3             :  * nodeIndexonlyscan.c
       4             :  *    Routines to support index-only scans
       5             :  *
       6             :  * Portions Copyright (c) 1996-2017, 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/relscan.h"
      34             : #include "access/visibilitymap.h"
      35             : #include "executor/execdebug.h"
      36             : #include "executor/nodeIndexonlyscan.h"
      37             : #include "executor/nodeIndexscan.h"
      38             : #include "miscadmin.h"
      39             : #include "storage/bufmgr.h"
      40             : #include "storage/predicate.h"
      41             : #include "utils/memutils.h"
      42             : #include "utils/rel.h"
      43             : 
      44             : 
      45             : static TupleTableSlot *IndexOnlyNext(IndexOnlyScanState *node);
      46             : static void StoreIndexTuple(TupleTableSlot *slot, IndexTuple itup,
      47             :                 TupleDesc itupdesc);
      48             : 
      49             : 
      50             : /* ----------------------------------------------------------------
      51             :  *      IndexOnlyNext
      52             :  *
      53             :  *      Retrieve a tuple from the IndexOnlyScan node's index.
      54             :  * ----------------------------------------------------------------
      55             :  */
      56             : static TupleTableSlot *
      57      589259 : IndexOnlyNext(IndexOnlyScanState *node)
      58             : {
      59             :     EState     *estate;
      60             :     ExprContext *econtext;
      61             :     ScanDirection direction;
      62             :     IndexScanDesc scandesc;
      63             :     TupleTableSlot *slot;
      64             :     ItemPointer tid;
      65             : 
      66             :     /*
      67             :      * extract necessary information from index scan node
      68             :      */
      69      589259 :     estate = node->ss.ps.state;
      70      589259 :     direction = estate->es_direction;
      71             :     /* flip direction if this is an overall backward scan */
      72      589259 :     if (ScanDirectionIsBackward(((IndexOnlyScan *) node->ss.ps.plan)->indexorderdir))
      73             :     {
      74          46 :         if (ScanDirectionIsForward(direction))
      75          46 :             direction = BackwardScanDirection;
      76           0 :         else if (ScanDirectionIsBackward(direction))
      77           0 :             direction = ForwardScanDirection;
      78             :     }
      79      589259 :     scandesc = node->ioss_ScanDesc;
      80      589259 :     econtext = node->ss.ps.ps_ExprContext;
      81      589259 :     slot = node->ss.ss_ScanTupleSlot;
      82             : 
      83      589259 :     if (scandesc == NULL)
      84             :     {
      85             :         /*
      86             :          * We reach here if the index only scan is not parallel, or if we're
      87             :          * executing a index only scan that was intended to be parallel
      88             :          * serially.
      89             :          */
      90         540 :         scandesc = index_beginscan(node->ss.ss_currentRelation,
      91             :                                    node->ioss_RelationDesc,
      92             :                                    estate->es_snapshot,
      93             :                                    node->ioss_NumScanKeys,
      94             :                                    node->ioss_NumOrderByKeys);
      95             : 
      96         540 :         node->ioss_ScanDesc = scandesc;
      97             : 
      98             : 
      99             :         /* Set it up for index-only scan */
     100         540 :         node->ioss_ScanDesc->xs_want_itup = true;
     101         540 :         node->ioss_VMBuffer = InvalidBuffer;
     102             : 
     103             :         /*
     104             :          * If no run-time keys to calculate or they are ready, go ahead and
     105             :          * pass the scankeys to the index AM.
     106             :          */
     107         540 :         if (node->ioss_NumRuntimeKeys == 0 || node->ioss_RuntimeKeysReady)
     108         540 :             index_rescan(scandesc,
     109             :                          node->ioss_ScanKeys,
     110             :                          node->ioss_NumScanKeys,
     111             :                          node->ioss_OrderByKeys,
     112             :                          node->ioss_NumOrderByKeys);
     113             :     }
     114             : 
     115             :     /*
     116             :      * OK, now that we have what we need, fetch the next tuple.
     117             :      */
     118     1178557 :     while ((tid = index_getnext_tid(scandesc, direction)) != NULL)
     119             :     {
     120      588320 :         HeapTuple   tuple = NULL;
     121             : 
     122      588320 :         CHECK_FOR_INTERRUPTS();
     123             : 
     124             :         /*
     125             :          * We can skip the heap fetch if the TID references a heap page on
     126             :          * which all tuples are known visible to everybody.  In any case,
     127             :          * we'll use the index tuple not the heap tuple as the data source.
     128             :          *
     129             :          * Note on Memory Ordering Effects: visibilitymap_get_status does not
     130             :          * lock the visibility map buffer, and therefore the result we read
     131             :          * here could be slightly stale.  However, it can't be stale enough to
     132             :          * matter.
     133             :          *
     134             :          * We need to detect clearing a VM bit due to an insert right away,
     135             :          * because the tuple is present in the index page but not visible. The
     136             :          * reading of the TID by this scan (using a shared lock on the index
     137             :          * buffer) is serialized with the insert of the TID into the index
     138             :          * (using an exclusive lock on the index buffer). Because the VM bit
     139             :          * is cleared before updating the index, and locking/unlocking of the
     140             :          * index page acts as a full memory barrier, we are sure to see the
     141             :          * cleared bit if we see a recently-inserted TID.
     142             :          *
     143             :          * Deletes do not update the index page (only VACUUM will clear out
     144             :          * the TID), so the clearing of the VM bit by a delete is not
     145             :          * serialized with this test below, and we may see a value that is
     146             :          * significantly stale. However, we don't care about the delete right
     147             :          * away, because the tuple is still visible until the deleting
     148             :          * transaction commits or the statement ends (if it's our
     149             :          * transaction). In either case, the lock on the VM buffer will have
     150             :          * been released (acting as a write barrier) after clearing the bit.
     151             :          * And for us to have a snapshot that includes the deleting
     152             :          * transaction (making the tuple invisible), we must have acquired
     153             :          * ProcArrayLock after that time, acting as a read barrier.
     154             :          *
     155             :          * It's worth going through this complexity to avoid needing to lock
     156             :          * the VM buffer, which could cause significant contention.
     157             :          */
     158      588320 :         if (!VM_ALL_VISIBLE(scandesc->heapRelation,
     159             :                             ItemPointerGetBlockNumber(tid),
     160             :                             &node->ioss_VMBuffer))
     161             :         {
     162             :             /*
     163             :              * Rats, we have to visit the heap to check visibility.
     164             :              */
     165      147276 :             node->ioss_HeapFetches++;
     166      147276 :             tuple = index_fetch_heap(scandesc);
     167      147276 :             if (tuple == NULL)
     168          39 :                 continue;       /* no visible tuple, try next index entry */
     169             : 
     170             :             /*
     171             :              * Only MVCC snapshots are supported here, so there should be no
     172             :              * need to keep following the HOT chain once a visible entry has
     173             :              * been found.  If we did want to allow that, we'd need to keep
     174             :              * more state to remember not to call index_getnext_tid next time.
     175             :              */
     176      147237 :             if (scandesc->xs_continue_hot)
     177           0 :                 elog(ERROR, "non-MVCC snapshots are not supported in index-only scans");
     178             : 
     179             :             /*
     180             :              * Note: at this point we are holding a pin on the heap page, as
     181             :              * recorded in scandesc->xs_cbuf.  We could release that pin now,
     182             :              * but it's not clear whether it's a win to do so.  The next index
     183             :              * entry might require a visit to the same heap page.
     184             :              */
     185             :         }
     186             : 
     187             :         /*
     188             :          * Fill the scan tuple slot with data from the index.  This might be
     189             :          * provided in either HeapTuple or IndexTuple format.  Conceivably an
     190             :          * index AM might fill both fields, in which case we prefer the heap
     191             :          * format, since it's probably a bit cheaper to fill a slot from.
     192             :          */
     193      588281 :         if (scandesc->xs_hitup)
     194             :         {
     195             :             /*
     196             :              * We don't take the trouble to verify that the provided tuple has
     197             :              * exactly the slot's format, but it seems worth doing a quick
     198             :              * check on the number of fields.
     199             :              */
     200      142209 :             Assert(slot->tts_tupleDescriptor->natts ==
     201             :                    scandesc->xs_hitupdesc->natts);
     202      142209 :             ExecStoreTuple(scandesc->xs_hitup, slot, InvalidBuffer, false);
     203             :         }
     204      446072 :         else if (scandesc->xs_itup)
     205      446072 :             StoreIndexTuple(slot, scandesc->xs_itup, scandesc->xs_itupdesc);
     206             :         else
     207           0 :             elog(ERROR, "no data returned for index-only scan");
     208             : 
     209             :         /*
     210             :          * If the index was lossy, we have to recheck the index quals.
     211             :          * (Currently, this can never happen, but we should support the case
     212             :          * for possible future use, eg with GiST indexes.)
     213             :          */
     214      588281 :         if (scandesc->xs_recheck)
     215             :         {
     216           0 :             econtext->ecxt_scantuple = slot;
     217           0 :             ResetExprContext(econtext);
     218           0 :             if (!ExecQual(node->indexqual, econtext))
     219             :             {
     220             :                 /* Fails recheck, so drop it and loop back for another */
     221           0 :                 InstrCountFiltered2(node, 1);
     222           0 :                 continue;
     223             :             }
     224             :         }
     225             : 
     226             :         /*
     227             :          * We don't currently support rechecking ORDER BY distances.  (In
     228             :          * principle, if the index can support retrieval of the originally
     229             :          * indexed value, it should be able to produce an exact distance
     230             :          * calculation too.  So it's not clear that adding code here for
     231             :          * recheck/re-sort would be worth the trouble.  But we should at least
     232             :          * throw an error if someone tries it.)
     233             :          */
     234      588281 :         if (scandesc->numberOfOrderBys > 0 && scandesc->xs_recheckorderby)
     235           0 :             ereport(ERROR,
     236             :                     (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
     237             :                      errmsg("lossy distance functions are not supported in index-only scans")));
     238             : 
     239             :         /*
     240             :          * Predicate locks for index-only scans must be acquired at the page
     241             :          * level when the heap is not accessed, since tuple-level predicate
     242             :          * locks need the tuple's xmin value.  If we had to visit the tuple
     243             :          * anyway, then we already have the tuple-level lock and can skip the
     244             :          * page lock.
     245             :          */
     246      588281 :         if (tuple == NULL)
     247      882088 :             PredicateLockPage(scandesc->heapRelation,
     248      441044 :                               ItemPointerGetBlockNumber(tid),
     249             :                               estate->es_snapshot);
     250             : 
     251      588281 :         return slot;
     252             :     }
     253             : 
     254             :     /*
     255             :      * if we get here it means the index scan failed so we are at the end of
     256             :      * the scan..
     257             :      */
     258         978 :     return ExecClearTuple(slot);
     259             : }
     260             : 
     261             : /*
     262             :  * StoreIndexTuple
     263             :  *      Fill the slot with data from the index tuple.
     264             :  *
     265             :  * At some point this might be generally-useful functionality, but
     266             :  * right now we don't need it elsewhere.
     267             :  */
     268             : static void
     269      446072 : StoreIndexTuple(TupleTableSlot *slot, IndexTuple itup, TupleDesc itupdesc)
     270             : {
     271      446072 :     int         nindexatts = itupdesc->natts;
     272      446072 :     Datum      *values = slot->tts_values;
     273      446072 :     bool       *isnull = slot->tts_isnull;
     274             :     int         i;
     275             : 
     276             :     /*
     277             :      * Note: we must use the tupdesc supplied by the AM in index_getattr, not
     278             :      * the slot's tupdesc, in case the latter has different datatypes (this
     279             :      * happens for btree name_ops in particular).  They'd better have the same
     280             :      * number of columns though, as well as being datatype-compatible which is
     281             :      * something we can't so easily check.
     282             :      */
     283      446072 :     Assert(slot->tts_tupleDescriptor->natts == nindexatts);
     284             : 
     285      446072 :     ExecClearTuple(slot);
     286     1042610 :     for (i = 0; i < nindexatts; i++)
     287      596538 :         values[i] = index_getattr(itup, i + 1, itupdesc, &isnull[i]);
     288      446072 :     ExecStoreVirtualTuple(slot);
     289      446072 : }
     290             : 
     291             : /*
     292             :  * IndexOnlyRecheck -- access method routine to recheck a tuple in EvalPlanQual
     293             :  *
     294             :  * This can't really happen, since an index can't supply CTID which would
     295             :  * be necessary data for any potential EvalPlanQual target relation.  If it
     296             :  * did happen, the EPQ code would pass us the wrong data, namely a heap
     297             :  * tuple not an index tuple.  So throw an error.
     298             :  */
     299             : static bool
     300           0 : IndexOnlyRecheck(IndexOnlyScanState *node, TupleTableSlot *slot)
     301             : {
     302           0 :     elog(ERROR, "EvalPlanQual recheck is not supported in index-only scans");
     303             :     return false;               /* keep compiler quiet */
     304             : }
     305             : 
     306             : /* ----------------------------------------------------------------
     307             :  *      ExecIndexOnlyScan(node)
     308             :  * ----------------------------------------------------------------
     309             :  */
     310             : static TupleTableSlot *
     311      585629 : ExecIndexOnlyScan(PlanState *pstate)
     312             : {
     313      585629 :     IndexOnlyScanState *node = castNode(IndexOnlyScanState, pstate);
     314             : 
     315             :     /*
     316             :      * If we have runtime keys and they've not already been set up, do it now.
     317             :      */
     318      585629 :     if (node->ioss_NumRuntimeKeys != 0 && !node->ioss_RuntimeKeysReady)
     319          97 :         ExecReScan((PlanState *) node);
     320             : 
     321      585629 :     return ExecScan(&node->ss,
     322             :                     (ExecScanAccessMtd) IndexOnlyNext,
     323             :                     (ExecScanRecheckMtd) IndexOnlyRecheck);
     324             : }
     325             : 
     326             : /* ----------------------------------------------------------------
     327             :  *      ExecReScanIndexOnlyScan(node)
     328             :  *
     329             :  *      Recalculates the values of any scan keys whose value depends on
     330             :  *      information known at runtime, then rescans the indexed relation.
     331             :  *
     332             :  *      Updating the scan key was formerly done separately in
     333             :  *      ExecUpdateIndexScanKeys. Integrating it into ReScan makes
     334             :  *      rescans of indices and relations/general streams more uniform.
     335             :  * ----------------------------------------------------------------
     336             :  */
     337             : void
     338        2060 : ExecReScanIndexOnlyScan(IndexOnlyScanState *node)
     339             : {
     340             :     /*
     341             :      * If we are doing runtime key calculations (ie, any of the index key
     342             :      * values weren't simple Consts), compute the new key values.  But first,
     343             :      * reset the context so we don't leak memory as each outer tuple is
     344             :      * scanned.  Note this assumes that we will recalculate *all* runtime keys
     345             :      * on each call.
     346             :      */
     347        2060 :     if (node->ioss_NumRuntimeKeys != 0)
     348             :     {
     349        2041 :         ExprContext *econtext = node->ioss_RuntimeContext;
     350             : 
     351        2041 :         ResetExprContext(econtext);
     352        2041 :         ExecIndexEvalRuntimeKeys(econtext,
     353             :                                  node->ioss_RuntimeKeys,
     354             :                                  node->ioss_NumRuntimeKeys);
     355             :     }
     356        2060 :     node->ioss_RuntimeKeysReady = true;
     357             : 
     358             :     /* reset index scan */
     359        2060 :     if (node->ioss_ScanDesc)
     360        1850 :         index_rescan(node->ioss_ScanDesc,
     361             :                      node->ioss_ScanKeys, node->ioss_NumScanKeys,
     362             :                      node->ioss_OrderByKeys, node->ioss_NumOrderByKeys);
     363             : 
     364        2060 :     ExecScanReScan(&node->ss);
     365        2060 : }
     366             : 
     367             : 
     368             : /* ----------------------------------------------------------------
     369             :  *      ExecEndIndexOnlyScan
     370             :  * ----------------------------------------------------------------
     371             :  */
     372             : void
     373         777 : ExecEndIndexOnlyScan(IndexOnlyScanState *node)
     374             : {
     375             :     Relation    indexRelationDesc;
     376             :     IndexScanDesc indexScanDesc;
     377             :     Relation    relation;
     378             : 
     379             :     /*
     380             :      * extract information from the node
     381             :      */
     382         777 :     indexRelationDesc = node->ioss_RelationDesc;
     383         777 :     indexScanDesc = node->ioss_ScanDesc;
     384         777 :     relation = node->ss.ss_currentRelation;
     385             : 
     386             :     /* Release VM buffer pin, if any. */
     387         777 :     if (node->ioss_VMBuffer != InvalidBuffer)
     388             :     {
     389         228 :         ReleaseBuffer(node->ioss_VMBuffer);
     390         228 :         node->ioss_VMBuffer = InvalidBuffer;
     391             :     }
     392             : 
     393             :     /*
     394             :      * Free the exprcontext(s) ... now dead code, see ExecFreeExprContext
     395             :      */
     396             : #ifdef NOT_USED
     397             :     ExecFreeExprContext(&node->ss.ps);
     398             :     if (node->ioss_RuntimeContext)
     399             :         FreeExprContext(node->ioss_RuntimeContext, true);
     400             : #endif
     401             : 
     402             :     /*
     403             :      * clear out tuple table slots
     404             :      */
     405         777 :     ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
     406         777 :     ExecClearTuple(node->ss.ss_ScanTupleSlot);
     407             : 
     408             :     /*
     409             :      * close the index relation (no-op if we didn't open it)
     410             :      */
     411         777 :     if (indexScanDesc)
     412         556 :         index_endscan(indexScanDesc);
     413         777 :     if (indexRelationDesc)
     414         617 :         index_close(indexRelationDesc, NoLock);
     415             : 
     416             :     /*
     417             :      * close the heap relation.
     418             :      */
     419         777 :     ExecCloseScanRelation(relation);
     420         777 : }
     421             : 
     422             : /* ----------------------------------------------------------------
     423             :  *      ExecIndexOnlyMarkPos
     424             :  * ----------------------------------------------------------------
     425             :  */
     426             : void
     427       20000 : ExecIndexOnlyMarkPos(IndexOnlyScanState *node)
     428             : {
     429       20000 :     index_markpos(node->ioss_ScanDesc);
     430       20000 : }
     431             : 
     432             : /* ----------------------------------------------------------------
     433             :  *      ExecIndexOnlyRestrPos
     434             :  * ----------------------------------------------------------------
     435             :  */
     436             : void
     437           0 : ExecIndexOnlyRestrPos(IndexOnlyScanState *node)
     438             : {
     439           0 :     index_restrpos(node->ioss_ScanDesc);
     440           0 : }
     441             : 
     442             : /* ----------------------------------------------------------------
     443             :  *      ExecInitIndexOnlyScan
     444             :  *
     445             :  *      Initializes the index scan's state information, creates
     446             :  *      scan keys, and opens the base and index relations.
     447             :  *
     448             :  *      Note: index scans have 2 sets of state information because
     449             :  *            we have to keep track of the base relation and the
     450             :  *            index relation.
     451             :  * ----------------------------------------------------------------
     452             :  */
     453             : IndexOnlyScanState *
     454         785 : ExecInitIndexOnlyScan(IndexOnlyScan *node, EState *estate, int eflags)
     455             : {
     456             :     IndexOnlyScanState *indexstate;
     457             :     Relation    currentRelation;
     458             :     bool        relistarget;
     459             :     TupleDesc   tupDesc;
     460             : 
     461             :     /*
     462             :      * create state structure
     463             :      */
     464         785 :     indexstate = makeNode(IndexOnlyScanState);
     465         785 :     indexstate->ss.ps.plan = (Plan *) node;
     466         785 :     indexstate->ss.ps.state = estate;
     467         785 :     indexstate->ss.ps.ExecProcNode = ExecIndexOnlyScan;
     468         785 :     indexstate->ioss_HeapFetches = 0;
     469             : 
     470             :     /*
     471             :      * Miscellaneous initialization
     472             :      *
     473             :      * create expression context for node
     474             :      */
     475         785 :     ExecAssignExprContext(estate, &indexstate->ss.ps);
     476             : 
     477             :     /*
     478             :      * initialize child expressions
     479             :      *
     480             :      * Note: we don't initialize all of the indexorderby expression, only the
     481             :      * sub-parts corresponding to runtime keys (see below).
     482             :      */
     483         785 :     indexstate->ss.ps.qual =
     484         785 :         ExecInitQual(node->scan.plan.qual, (PlanState *) indexstate);
     485         785 :     indexstate->indexqual =
     486         785 :         ExecInitQual(node->indexqual, (PlanState *) indexstate);
     487             : 
     488             :     /*
     489             :      * tuple table initialization
     490             :      */
     491         785 :     ExecInitResultTupleSlot(estate, &indexstate->ss.ps);
     492         785 :     ExecInitScanTupleSlot(estate, &indexstate->ss);
     493             : 
     494             :     /*
     495             :      * open the base relation and acquire appropriate lock on it.
     496             :      */
     497         785 :     currentRelation = ExecOpenScanRelation(estate, node->scan.scanrelid, eflags);
     498             : 
     499         785 :     indexstate->ss.ss_currentRelation = currentRelation;
     500         785 :     indexstate->ss.ss_currentScanDesc = NULL;    /* no heap scan here */
     501             : 
     502             :     /*
     503             :      * Build the scan tuple type using the indextlist generated by the
     504             :      * planner.  We use this, rather than the index's physical tuple
     505             :      * descriptor, because the latter contains storage column types not the
     506             :      * types of the original datums.  (It's the AM's responsibility to return
     507             :      * suitable data anyway.)
     508             :      */
     509         785 :     tupDesc = ExecTypeFromTL(node->indextlist, false);
     510         785 :     ExecAssignScanType(&indexstate->ss, tupDesc);
     511             : 
     512             :     /*
     513             :      * Initialize result tuple type and projection info.  The node's
     514             :      * targetlist will contain Vars with varno = INDEX_VAR, referencing the
     515             :      * scan tuple.
     516             :      */
     517         785 :     ExecAssignResultTypeFromTL(&indexstate->ss.ps);
     518         785 :     ExecAssignScanProjectionInfoWithVarno(&indexstate->ss, INDEX_VAR);
     519             : 
     520             :     /*
     521             :      * If we are just doing EXPLAIN (ie, aren't going to run the plan), stop
     522             :      * here.  This allows an index-advisor plugin to EXPLAIN a plan containing
     523             :      * references to nonexistent indexes.
     524             :      */
     525         785 :     if (eflags & EXEC_FLAG_EXPLAIN_ONLY)
     526         160 :         return indexstate;
     527             : 
     528             :     /*
     529             :      * Open the index relation.
     530             :      *
     531             :      * If the parent table is one of the target relations of the query, then
     532             :      * InitPlan already opened and write-locked the index, so we can avoid
     533             :      * taking another lock here.  Otherwise we need a normal reader's lock.
     534             :      */
     535         625 :     relistarget = ExecRelationIsTargetRelation(estate, node->scan.scanrelid);
     536         625 :     indexstate->ioss_RelationDesc = index_open(node->indexid,
     537             :                                                relistarget ? NoLock : AccessShareLock);
     538             : 
     539             :     /*
     540             :      * Initialize index-specific scan state
     541             :      */
     542         625 :     indexstate->ioss_RuntimeKeysReady = false;
     543         625 :     indexstate->ioss_RuntimeKeys = NULL;
     544         625 :     indexstate->ioss_NumRuntimeKeys = 0;
     545             : 
     546             :     /*
     547             :      * build the index scan keys from the index qualification
     548             :      */
     549         625 :     ExecIndexBuildScanKeys((PlanState *) indexstate,
     550             :                            indexstate->ioss_RelationDesc,
     551             :                            node->indexqual,
     552             :                            false,
     553             :                            &indexstate->ioss_ScanKeys,
     554             :                            &indexstate->ioss_NumScanKeys,
     555             :                            &indexstate->ioss_RuntimeKeys,
     556             :                            &indexstate->ioss_NumRuntimeKeys,
     557             :                            NULL,    /* no ArrayKeys */
     558             :                            NULL);
     559             : 
     560             :     /*
     561             :      * any ORDER BY exprs have to be turned into scankeys in the same way
     562             :      */
     563         625 :     ExecIndexBuildScanKeys((PlanState *) indexstate,
     564             :                            indexstate->ioss_RelationDesc,
     565             :                            node->indexorderby,
     566             :                            true,
     567             :                            &indexstate->ioss_OrderByKeys,
     568             :                            &indexstate->ioss_NumOrderByKeys,
     569             :                            &indexstate->ioss_RuntimeKeys,
     570             :                            &indexstate->ioss_NumRuntimeKeys,
     571             :                            NULL,    /* no ArrayKeys */
     572             :                            NULL);
     573             : 
     574             :     /*
     575             :      * If we have runtime keys, we need an ExprContext to evaluate them. The
     576             :      * node's standard context won't do because we want to reset that context
     577             :      * for every tuple.  So, build another context just like the other one...
     578             :      * -tgl 7/11/00
     579             :      */
     580         625 :     if (indexstate->ioss_NumRuntimeKeys != 0)
     581             :     {
     582         249 :         ExprContext *stdecontext = indexstate->ss.ps.ps_ExprContext;
     583             : 
     584         249 :         ExecAssignExprContext(estate, &indexstate->ss.ps);
     585         249 :         indexstate->ioss_RuntimeContext = indexstate->ss.ps.ps_ExprContext;
     586         249 :         indexstate->ss.ps.ps_ExprContext = stdecontext;
     587             :     }
     588             :     else
     589             :     {
     590         376 :         indexstate->ioss_RuntimeContext = NULL;
     591             :     }
     592             : 
     593             :     /*
     594             :      * all done.
     595             :      */
     596         625 :     return indexstate;
     597             : }
     598             : 
     599             : /* ----------------------------------------------------------------
     600             :  *      Parallel Index-only Scan Support
     601             :  * ----------------------------------------------------------------
     602             :  */
     603             : 
     604             : /* ----------------------------------------------------------------
     605             :  *      ExecIndexOnlyScanEstimate
     606             :  *
     607             :  *  estimates the space required to serialize index-only scan node.
     608             :  * ----------------------------------------------------------------
     609             :  */
     610             : void
     611           3 : ExecIndexOnlyScanEstimate(IndexOnlyScanState *node,
     612             :                           ParallelContext *pcxt)
     613             : {
     614           3 :     EState     *estate = node->ss.ps.state;
     615             : 
     616           3 :     node->ioss_PscanLen = index_parallelscan_estimate(node->ioss_RelationDesc,
     617             :                                                       estate->es_snapshot);
     618           3 :     shm_toc_estimate_chunk(&pcxt->estimator, node->ioss_PscanLen);
     619           3 :     shm_toc_estimate_keys(&pcxt->estimator, 1);
     620           3 : }
     621             : 
     622             : /* ----------------------------------------------------------------
     623             :  *      ExecIndexOnlyScanInitializeDSM
     624             :  *
     625             :  *      Set up a parallel index-only scan descriptor.
     626             :  * ----------------------------------------------------------------
     627             :  */
     628             : void
     629           3 : ExecIndexOnlyScanInitializeDSM(IndexOnlyScanState *node,
     630             :                                ParallelContext *pcxt)
     631             : {
     632           3 :     EState     *estate = node->ss.ps.state;
     633             :     ParallelIndexScanDesc piscan;
     634             : 
     635           3 :     piscan = shm_toc_allocate(pcxt->toc, node->ioss_PscanLen);
     636           3 :     index_parallelscan_initialize(node->ss.ss_currentRelation,
     637             :                                   node->ioss_RelationDesc,
     638             :                                   estate->es_snapshot,
     639             :                                   piscan);
     640           3 :     shm_toc_insert(pcxt->toc, node->ss.ps.plan->plan_node_id, piscan);
     641           3 :     node->ioss_ScanDesc =
     642           3 :         index_beginscan_parallel(node->ss.ss_currentRelation,
     643             :                                  node->ioss_RelationDesc,
     644             :                                  node->ioss_NumScanKeys,
     645             :                                  node->ioss_NumOrderByKeys,
     646             :                                  piscan);
     647           3 :     node->ioss_ScanDesc->xs_want_itup = true;
     648           3 :     node->ioss_VMBuffer = InvalidBuffer;
     649             : 
     650             :     /*
     651             :      * If no run-time keys to calculate or they are ready, go ahead and pass
     652             :      * the scankeys to the index AM.
     653             :      */
     654           3 :     if (node->ioss_NumRuntimeKeys == 0 || node->ioss_RuntimeKeysReady)
     655           3 :         index_rescan(node->ioss_ScanDesc,
     656             :                      node->ioss_ScanKeys, node->ioss_NumScanKeys,
     657             :                      node->ioss_OrderByKeys, node->ioss_NumOrderByKeys);
     658           3 : }
     659             : 
     660             : /* ----------------------------------------------------------------
     661             :  *      ExecIndexOnlyScanReInitializeDSM
     662             :  *
     663             :  *      Reset shared state before beginning a fresh scan.
     664             :  * ----------------------------------------------------------------
     665             :  */
     666             : void
     667           2 : ExecIndexOnlyScanReInitializeDSM(IndexOnlyScanState *node,
     668             :                                  ParallelContext *pcxt)
     669             : {
     670           2 :     index_parallelrescan(node->ioss_ScanDesc);
     671           2 : }
     672             : 
     673             : /* ----------------------------------------------------------------
     674             :  *      ExecIndexOnlyScanInitializeWorker
     675             :  *
     676             :  *      Copy relevant information from TOC into planstate.
     677             :  * ----------------------------------------------------------------
     678             :  */
     679             : void
     680          20 : ExecIndexOnlyScanInitializeWorker(IndexOnlyScanState *node, shm_toc *toc)
     681             : {
     682             :     ParallelIndexScanDesc piscan;
     683             : 
     684          20 :     piscan = shm_toc_lookup(toc, node->ss.ps.plan->plan_node_id, false);
     685          20 :     node->ioss_ScanDesc =
     686          20 :         index_beginscan_parallel(node->ss.ss_currentRelation,
     687             :                                  node->ioss_RelationDesc,
     688             :                                  node->ioss_NumScanKeys,
     689             :                                  node->ioss_NumOrderByKeys,
     690             :                                  piscan);
     691          20 :     node->ioss_ScanDesc->xs_want_itup = true;
     692             : 
     693             :     /*
     694             :      * If no run-time keys to calculate or they are ready, go ahead and pass
     695             :      * the scankeys to the index AM.
     696             :      */
     697          20 :     if (node->ioss_NumRuntimeKeys == 0 || node->ioss_RuntimeKeysReady)
     698          20 :         index_rescan(node->ioss_ScanDesc,
     699             :                      node->ioss_ScanKeys, node->ioss_NumScanKeys,
     700             :                      node->ioss_OrderByKeys, node->ioss_NumOrderByKeys);
     701          20 : }

Generated by: LCOV version 1.11