LCOV - code coverage report
Current view: top level - src/backend/executor - execAmi.c (source / functions) Hit Total Coverage
Test: PostgreSQL 15devel Lines: 229 289 79.2 %
Date: 2021-12-03 03:09:03 Functions: 7 7 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*-------------------------------------------------------------------------
       2             :  *
       3             :  * execAmi.c
       4             :  *    miscellaneous executor access method routines
       5             :  *
       6             :  * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group
       7             :  * Portions Copyright (c) 1994, Regents of the University of California
       8             :  *
       9             :  *  src/backend/executor/execAmi.c
      10             :  *
      11             :  *-------------------------------------------------------------------------
      12             :  */
      13             : #include "postgres.h"
      14             : 
      15             : #include "access/amapi.h"
      16             : #include "access/htup_details.h"
      17             : #include "executor/execdebug.h"
      18             : #include "executor/nodeAgg.h"
      19             : #include "executor/nodeAppend.h"
      20             : #include "executor/nodeBitmapAnd.h"
      21             : #include "executor/nodeBitmapHeapscan.h"
      22             : #include "executor/nodeBitmapIndexscan.h"
      23             : #include "executor/nodeBitmapOr.h"
      24             : #include "executor/nodeCtescan.h"
      25             : #include "executor/nodeCustom.h"
      26             : #include "executor/nodeForeignscan.h"
      27             : #include "executor/nodeFunctionscan.h"
      28             : #include "executor/nodeGather.h"
      29             : #include "executor/nodeGatherMerge.h"
      30             : #include "executor/nodeGroup.h"
      31             : #include "executor/nodeHash.h"
      32             : #include "executor/nodeHashjoin.h"
      33             : #include "executor/nodeIncrementalSort.h"
      34             : #include "executor/nodeIndexonlyscan.h"
      35             : #include "executor/nodeIndexscan.h"
      36             : #include "executor/nodeLimit.h"
      37             : #include "executor/nodeLockRows.h"
      38             : #include "executor/nodeMaterial.h"
      39             : #include "executor/nodeMemoize.h"
      40             : #include "executor/nodeMergeAppend.h"
      41             : #include "executor/nodeMergejoin.h"
      42             : #include "executor/nodeModifyTable.h"
      43             : #include "executor/nodeNamedtuplestorescan.h"
      44             : #include "executor/nodeNestloop.h"
      45             : #include "executor/nodeProjectSet.h"
      46             : #include "executor/nodeRecursiveunion.h"
      47             : #include "executor/nodeResult.h"
      48             : #include "executor/nodeSamplescan.h"
      49             : #include "executor/nodeSeqscan.h"
      50             : #include "executor/nodeSetOp.h"
      51             : #include "executor/nodeSort.h"
      52             : #include "executor/nodeSubplan.h"
      53             : #include "executor/nodeSubqueryscan.h"
      54             : #include "executor/nodeTableFuncscan.h"
      55             : #include "executor/nodeTidrangescan.h"
      56             : #include "executor/nodeTidscan.h"
      57             : #include "executor/nodeUnique.h"
      58             : #include "executor/nodeValuesscan.h"
      59             : #include "executor/nodeWindowAgg.h"
      60             : #include "executor/nodeWorktablescan.h"
      61             : #include "nodes/extensible.h"
      62             : #include "nodes/nodeFuncs.h"
      63             : #include "nodes/pathnodes.h"
      64             : #include "utils/rel.h"
      65             : #include "utils/syscache.h"
      66             : 
      67             : static bool IndexSupportsBackwardScan(Oid indexid);
      68             : 
      69             : 
      70             : /*
      71             :  * ExecReScan
      72             :  *      Reset a plan node so that its output can be re-scanned.
      73             :  *
      74             :  * Note that if the plan node has parameters that have changed value,
      75             :  * the output might be different from last time.
      76             :  */
      77             : void
      78     8617146 : ExecReScan(PlanState *node)
      79             : {
      80             :     /* If collecting timing stats, update them */
      81     8617146 :     if (node->instrument)
      82       19678 :         InstrEndLoop(node->instrument);
      83             : 
      84             :     /*
      85             :      * If we have changed parameters, propagate that info.
      86             :      *
      87             :      * Note: ExecReScanSetParamPlan() can add bits to node->chgParam,
      88             :      * corresponding to the output param(s) that the InitPlan will update.
      89             :      * Since we make only one pass over the list, that means that an InitPlan
      90             :      * can depend on the output param(s) of a sibling InitPlan only if that
      91             :      * sibling appears earlier in the list.  This is workable for now given
      92             :      * the limited ways in which one InitPlan could depend on another, but
      93             :      * eventually we might need to work harder (or else make the planner
      94             :      * enlarge the extParam/allParam sets to include the params of depended-on
      95             :      * InitPlans).
      96             :      */
      97     8617146 :     if (node->chgParam != NULL)
      98             :     {
      99             :         ListCell   *l;
     100             : 
     101     7525620 :         foreach(l, node->initPlan)
     102             :         {
     103         806 :             SubPlanState *sstate = (SubPlanState *) lfirst(l);
     104         806 :             PlanState  *splan = sstate->planstate;
     105             : 
     106         806 :             if (splan->plan->extParam != NULL)    /* don't care about child
     107             :                                                  * local Params */
     108         706 :                 UpdateChangedParamSet(splan, node->chgParam);
     109         806 :             if (splan->chgParam != NULL)
     110         546 :                 ExecReScanSetParamPlan(sstate, node);
     111             :         }
     112     7624878 :         foreach(l, node->subPlan)
     113             :         {
     114      100064 :             SubPlanState *sstate = (SubPlanState *) lfirst(l);
     115      100064 :             PlanState  *splan = sstate->planstate;
     116             : 
     117      100064 :             if (splan->plan->extParam != NULL)
     118      100052 :                 UpdateChangedParamSet(splan, node->chgParam);
     119             :         }
     120             :         /* Well. Now set chgParam for left/right trees. */
     121     7524814 :         if (node->lefttree != NULL)
     122     3943450 :             UpdateChangedParamSet(node->lefttree, node->chgParam);
     123     7524814 :         if (node->righttree != NULL)
     124     1419868 :             UpdateChangedParamSet(node->righttree, node->chgParam);
     125             :     }
     126             : 
     127             :     /* Call expression callbacks */
     128     8617146 :     if (node->ps_ExprContext)
     129     7375602 :         ReScanExprContext(node->ps_ExprContext);
     130             : 
     131             :     /* And do node-type-specific processing */
     132     8617146 :     switch (nodeTag(node))
     133             :     {
     134      125456 :         case T_ResultState:
     135      125456 :             ExecReScanResult((ResultState *) node);
     136      125456 :             break;
     137             : 
     138       60172 :         case T_ProjectSetState:
     139       60172 :             ExecReScanProjectSet((ProjectSetState *) node);
     140       60172 :             break;
     141             : 
     142           0 :         case T_ModifyTableState:
     143           0 :             ExecReScanModifyTable((ModifyTableState *) node);
     144           0 :             break;
     145             : 
     146       63186 :         case T_AppendState:
     147       63186 :             ExecReScanAppend((AppendState *) node);
     148       63186 :             break;
     149             : 
     150          12 :         case T_MergeAppendState:
     151          12 :             ExecReScanMergeAppend((MergeAppendState *) node);
     152          12 :             break;
     153             : 
     154           8 :         case T_RecursiveUnionState:
     155           8 :             ExecReScanRecursiveUnion((RecursiveUnionState *) node);
     156           8 :             break;
     157             : 
     158          32 :         case T_BitmapAndState:
     159          32 :             ExecReScanBitmapAnd((BitmapAndState *) node);
     160          32 :             break;
     161             : 
     162          26 :         case T_BitmapOrState:
     163          26 :             ExecReScanBitmapOr((BitmapOrState *) node);
     164          26 :             break;
     165             : 
     166     1086602 :         case T_SeqScanState:
     167     1086602 :             ExecReScanSeqScan((SeqScanState *) node);
     168     1086602 :             break;
     169             : 
     170          42 :         case T_SampleScanState:
     171          42 :             ExecReScanSampleScan((SampleScanState *) node);
     172          42 :             break;
     173             : 
     174         200 :         case T_GatherState:
     175         200 :             ExecReScanGather((GatherState *) node);
     176         200 :             break;
     177             : 
     178          32 :         case T_GatherMergeState:
     179          32 :             ExecReScanGatherMerge((GatherMergeState *) node);
     180          32 :             break;
     181             : 
     182      393836 :         case T_IndexScanState:
     183      393836 :             ExecReScanIndexScan((IndexScanState *) node);
     184      393832 :             break;
     185             : 
     186       54056 :         case T_IndexOnlyScanState:
     187       54056 :             ExecReScanIndexOnlyScan((IndexOnlyScanState *) node);
     188       54056 :             break;
     189             : 
     190        4244 :         case T_BitmapIndexScanState:
     191        4244 :             ExecReScanBitmapIndexScan((BitmapIndexScanState *) node);
     192        4244 :             break;
     193             : 
     194        3920 :         case T_BitmapHeapScanState:
     195        3920 :             ExecReScanBitmapHeapScan((BitmapHeapScanState *) node);
     196        3920 :             break;
     197             : 
     198          12 :         case T_TidScanState:
     199          12 :             ExecReScanTidScan((TidScanState *) node);
     200          12 :             break;
     201             : 
     202          44 :         case T_TidRangeScanState:
     203          44 :             ExecReScanTidRangeScan((TidRangeScanState *) node);
     204          44 :             break;
     205             : 
     206        1462 :         case T_SubqueryScanState:
     207        1462 :             ExecReScanSubqueryScan((SubqueryScanState *) node);
     208        1462 :             break;
     209             : 
     210     1988958 :         case T_FunctionScanState:
     211     1988958 :             ExecReScanFunctionScan((FunctionScanState *) node);
     212     1988958 :             break;
     213             : 
     214         128 :         case T_TableFuncScanState:
     215         128 :             ExecReScanTableFuncScan((TableFuncScanState *) node);
     216         128 :             break;
     217             : 
     218       40250 :         case T_ValuesScanState:
     219       40250 :             ExecReScanValuesScan((ValuesScanState *) node);
     220       40250 :             break;
     221             : 
     222        3208 :         case T_CteScanState:
     223        3208 :             ExecReScanCteScan((CteScanState *) node);
     224        3208 :             break;
     225             : 
     226           0 :         case T_NamedTuplestoreScanState:
     227           0 :             ExecReScanNamedTuplestoreScan((NamedTuplestoreScanState *) node);
     228           0 :             break;
     229             : 
     230        4016 :         case T_WorkTableScanState:
     231        4016 :             ExecReScanWorkTableScan((WorkTableScanState *) node);
     232        4016 :             break;
     233             : 
     234         790 :         case T_ForeignScanState:
     235         790 :             ExecReScanForeignScan((ForeignScanState *) node);
     236         790 :             break;
     237             : 
     238           0 :         case T_CustomScanState:
     239           0 :             ExecReScanCustomScan((CustomScanState *) node);
     240           0 :             break;
     241             : 
     242       57490 :         case T_NestLoopState:
     243       57490 :             ExecReScanNestLoop((NestLoopState *) node);
     244       57490 :             break;
     245             : 
     246         222 :         case T_MergeJoinState:
     247         222 :             ExecReScanMergeJoin((MergeJoinState *) node);
     248         222 :             break;
     249             : 
     250     1372906 :         case T_HashJoinState:
     251     1372906 :             ExecReScanHashJoin((HashJoinState *) node);
     252     1372906 :             break;
     253             : 
     254      943922 :         case T_MaterialState:
     255      943922 :             ExecReScanMaterial((MaterialState *) node);
     256      943922 :             break;
     257             : 
     258      285954 :         case T_MemoizeState:
     259      285954 :             ExecReScanMemoize((MemoizeState *) node);
     260      285954 :             break;
     261             : 
     262      232270 :         case T_SortState:
     263      232270 :             ExecReScanSort((SortState *) node);
     264      232270 :             break;
     265             : 
     266           8 :         case T_IncrementalSortState:
     267           8 :             ExecReScanIncrementalSort((IncrementalSortState *) node);
     268           8 :             break;
     269             : 
     270          18 :         case T_GroupState:
     271          18 :             ExecReScanGroup((GroupState *) node);
     272          18 :             break;
     273             : 
     274     1532588 :         case T_AggState:
     275     1532588 :             ExecReScanAgg((AggState *) node);
     276     1532588 :             break;
     277             : 
     278          52 :         case T_WindowAggState:
     279          52 :             ExecReScanWindowAgg((WindowAggState *) node);
     280          52 :             break;
     281             : 
     282           0 :         case T_UniqueState:
     283           0 :             ExecReScanUnique((UniqueState *) node);
     284           0 :             break;
     285             : 
     286      360132 :         case T_HashState:
     287      360132 :             ExecReScanHash((HashState *) node);
     288      360132 :             break;
     289             : 
     290         400 :         case T_SetOpState:
     291         400 :             ExecReScanSetOp((SetOpState *) node);
     292         400 :             break;
     293             : 
     294          16 :         case T_LockRowsState:
     295          16 :             ExecReScanLockRows((LockRowsState *) node);
     296          16 :             break;
     297             : 
     298         476 :         case T_LimitState:
     299         476 :             ExecReScanLimit((LimitState *) node);
     300         476 :             break;
     301             : 
     302           0 :         default:
     303           0 :             elog(ERROR, "unrecognized node type: %d", (int) nodeTag(node));
     304             :             break;
     305             :     }
     306             : 
     307     8617142 :     if (node->chgParam != NULL)
     308             :     {
     309     7524814 :         bms_free(node->chgParam);
     310     7524814 :         node->chgParam = NULL;
     311             :     }
     312     8617142 : }
     313             : 
     314             : /*
     315             :  * ExecMarkPos
     316             :  *
     317             :  * Marks the current scan position.
     318             :  *
     319             :  * NOTE: mark/restore capability is currently needed only for plan nodes
     320             :  * that are the immediate inner child of a MergeJoin node.  Since MergeJoin
     321             :  * requires sorted input, there is never any need to support mark/restore in
     322             :  * node types that cannot produce sorted output.  There are some cases in
     323             :  * which a node can pass through sorted data from its child; if we don't
     324             :  * implement mark/restore for such a node type, the planner compensates by
     325             :  * inserting a Material node above that node.
     326             :  */
     327             : void
     328      446514 : ExecMarkPos(PlanState *node)
     329             : {
     330      446514 :     switch (nodeTag(node))
     331             :     {
     332        4046 :         case T_IndexScanState:
     333        4046 :             ExecIndexMarkPos((IndexScanState *) node);
     334        4046 :             break;
     335             : 
     336       84008 :         case T_IndexOnlyScanState:
     337       84008 :             ExecIndexOnlyMarkPos((IndexOnlyScanState *) node);
     338       84008 :             break;
     339             : 
     340           0 :         case T_CustomScanState:
     341           0 :             ExecCustomMarkPos((CustomScanState *) node);
     342           0 :             break;
     343             : 
     344        4240 :         case T_MaterialState:
     345        4240 :             ExecMaterialMarkPos((MaterialState *) node);
     346        4240 :             break;
     347             : 
     348      354220 :         case T_SortState:
     349      354220 :             ExecSortMarkPos((SortState *) node);
     350      354220 :             break;
     351             : 
     352           0 :         case T_ResultState:
     353           0 :             ExecResultMarkPos((ResultState *) node);
     354           0 :             break;
     355             : 
     356           0 :         default:
     357             :             /* don't make hard error unless caller asks to restore... */
     358           0 :             elog(DEBUG2, "unrecognized node type: %d", (int) nodeTag(node));
     359           0 :             break;
     360             :     }
     361      446514 : }
     362             : 
     363             : /*
     364             :  * ExecRestrPos
     365             :  *
     366             :  * restores the scan position previously saved with ExecMarkPos()
     367             :  *
     368             :  * NOTE: the semantics of this are that the first ExecProcNode following
     369             :  * the restore operation will yield the same tuple as the first one following
     370             :  * the mark operation.  It is unspecified what happens to the plan node's
     371             :  * result TupleTableSlot.  (In most cases the result slot is unchanged by
     372             :  * a restore, but the node may choose to clear it or to load it with the
     373             :  * restored-to tuple.)  Hence the caller should discard any previously
     374             :  * returned TupleTableSlot after doing a restore.
     375             :  */
     376             : void
     377       89098 : ExecRestrPos(PlanState *node)
     378             : {
     379       89098 :     switch (nodeTag(node))
     380             :     {
     381       36020 :         case T_IndexScanState:
     382       36020 :             ExecIndexRestrPos((IndexScanState *) node);
     383       36020 :             break;
     384             : 
     385           4 :         case T_IndexOnlyScanState:
     386           4 :             ExecIndexOnlyRestrPos((IndexOnlyScanState *) node);
     387           4 :             break;
     388             : 
     389           0 :         case T_CustomScanState:
     390           0 :             ExecCustomRestrPos((CustomScanState *) node);
     391           0 :             break;
     392             : 
     393       36024 :         case T_MaterialState:
     394       36024 :             ExecMaterialRestrPos((MaterialState *) node);
     395       36024 :             break;
     396             : 
     397       17050 :         case T_SortState:
     398       17050 :             ExecSortRestrPos((SortState *) node);
     399       17050 :             break;
     400             : 
     401           0 :         case T_ResultState:
     402           0 :             ExecResultRestrPos((ResultState *) node);
     403           0 :             break;
     404             : 
     405           0 :         default:
     406           0 :             elog(ERROR, "unrecognized node type: %d", (int) nodeTag(node));
     407             :             break;
     408             :     }
     409       89098 : }
     410             : 
     411             : /*
     412             :  * ExecSupportsMarkRestore - does a Path support mark/restore?
     413             :  *
     414             :  * This is used during planning and so must accept a Path, not a Plan.
     415             :  * We keep it here to be adjacent to the routines above, which also must
     416             :  * know which plan types support mark/restore.
     417             :  */
     418             : bool
     419       20786 : ExecSupportsMarkRestore(Path *pathnode)
     420             : {
     421             :     /*
     422             :      * For consistency with the routines above, we do not examine the nodeTag
     423             :      * but rather the pathtype, which is the Plan node type the Path would
     424             :      * produce.
     425             :      */
     426       20786 :     switch (pathnode->pathtype)
     427             :     {
     428        1608 :         case T_IndexScan:
     429             :         case T_IndexOnlyScan:
     430             : 
     431             :             /*
     432             :              * Not all index types support mark/restore.
     433             :              */
     434        1608 :             return castNode(IndexPath, pathnode)->indexinfo->amcanmarkpos;
     435             : 
     436           0 :         case T_Material:
     437             :         case T_Sort:
     438           0 :             return true;
     439             : 
     440           0 :         case T_CustomScan:
     441           0 :             if (castNode(CustomPath, pathnode)->flags & CUSTOMPATH_SUPPORT_MARK_RESTORE)
     442           0 :                 return true;
     443           0 :             return false;
     444             : 
     445           0 :         case T_Result:
     446             : 
     447             :             /*
     448             :              * Result supports mark/restore iff it has a child plan that does.
     449             :              *
     450             :              * We have to be careful here because there is more than one Path
     451             :              * type that can produce a Result plan node.
     452             :              */
     453           0 :             if (IsA(pathnode, ProjectionPath))
     454           0 :                 return ExecSupportsMarkRestore(((ProjectionPath *) pathnode)->subpath);
     455           0 :             else if (IsA(pathnode, MinMaxAggPath))
     456           0 :                 return false;   /* childless Result */
     457           0 :             else if (IsA(pathnode, GroupResultPath))
     458           0 :                 return false;   /* childless Result */
     459             :             else
     460             :             {
     461             :                 /* Simple RTE_RESULT base relation */
     462             :                 Assert(IsA(pathnode, Path));
     463           0 :                 return false;   /* childless Result */
     464             :             }
     465             : 
     466          80 :         case T_Append:
     467             :             {
     468          80 :                 AppendPath *appendPath = castNode(AppendPath, pathnode);
     469             : 
     470             :                 /*
     471             :                  * If there's exactly one child, then there will be no Append
     472             :                  * in the final plan, so we can handle mark/restore if the
     473             :                  * child plan node can.
     474             :                  */
     475          80 :                 if (list_length(appendPath->subpaths) == 1)
     476           0 :                     return ExecSupportsMarkRestore((Path *) linitial(appendPath->subpaths));
     477             :                 /* Otherwise, Append can't handle it */
     478          80 :                 return false;
     479             :             }
     480             : 
     481          32 :         case T_MergeAppend:
     482             :             {
     483          32 :                 MergeAppendPath *mapath = castNode(MergeAppendPath, pathnode);
     484             : 
     485             :                 /*
     486             :                  * Like the Append case above, single-subpath MergeAppends
     487             :                  * won't be in the final plan, so just return the child's
     488             :                  * mark/restore ability.
     489             :                  */
     490          32 :                 if (list_length(mapath->subpaths) == 1)
     491           0 :                     return ExecSupportsMarkRestore((Path *) linitial(mapath->subpaths));
     492             :                 /* Otherwise, MergeAppend can't handle it */
     493          32 :                 return false;
     494             :             }
     495             : 
     496       19066 :         default:
     497       19066 :             break;
     498             :     }
     499             : 
     500       19066 :     return false;
     501             : }
     502             : 
     503             : /*
     504             :  * ExecSupportsBackwardScan - does a plan type support backwards scanning?
     505             :  *
     506             :  * Ideally, all plan types would support backwards scan, but that seems
     507             :  * unlikely to happen soon.  In some cases, a plan node passes the backwards
     508             :  * scan down to its children, and so supports backwards scan only if its
     509             :  * children do.  Therefore, this routine must be passed a complete plan tree.
     510             :  */
     511             : bool
     512        2598 : ExecSupportsBackwardScan(Plan *node)
     513             : {
     514        2598 :     if (node == NULL)
     515           0 :         return false;
     516             : 
     517             :     /*
     518             :      * Parallel-aware nodes return a subset of the tuples in each worker, and
     519             :      * in general we can't expect to have enough bookkeeping state to know
     520             :      * which ones we returned in this worker as opposed to some other worker.
     521             :      */
     522        2598 :     if (node->parallel_aware)
     523           0 :         return false;
     524             : 
     525        2598 :     switch (nodeTag(node))
     526             :     {
     527          40 :         case T_Result:
     528          40 :             if (outerPlan(node) != NULL)
     529           0 :                 return ExecSupportsBackwardScan(outerPlan(node));
     530             :             else
     531          40 :                 return false;
     532             : 
     533          30 :         case T_Append:
     534             :             {
     535             :                 ListCell   *l;
     536             : 
     537             :                 /* With async, tuples may be interleaved, so can't back up. */
     538          30 :                 if (((Append *) node)->nasyncplans > 0)
     539           0 :                     return false;
     540             : 
     541         100 :                 foreach(l, ((Append *) node)->appendplans)
     542             :                 {
     543          72 :                     if (!ExecSupportsBackwardScan((Plan *) lfirst(l)))
     544           2 :                         return false;
     545             :                 }
     546             :                 /* need not check tlist because Append doesn't evaluate it */
     547          28 :                 return true;
     548             :             }
     549             : 
     550           4 :         case T_SampleScan:
     551             :             /* Simplify life for tablesample methods by disallowing this */
     552           4 :             return false;
     553             : 
     554           0 :         case T_Gather:
     555           0 :             return false;
     556             : 
     557         350 :         case T_IndexScan:
     558         350 :             return IndexSupportsBackwardScan(((IndexScan *) node)->indexid);
     559             : 
     560          88 :         case T_IndexOnlyScan:
     561          88 :             return IndexSupportsBackwardScan(((IndexOnlyScan *) node)->indexid);
     562             : 
     563           0 :         case T_SubqueryScan:
     564           0 :             return ExecSupportsBackwardScan(((SubqueryScan *) node)->subplan);
     565             : 
     566           0 :         case T_CustomScan:
     567           0 :             if (((CustomScan *) node)->flags & CUSTOMPATH_SUPPORT_BACKWARD_SCAN)
     568           0 :                 return true;
     569           0 :             return false;
     570             : 
     571        1286 :         case T_SeqScan:
     572             :         case T_TidScan:
     573             :         case T_TidRangeScan:
     574             :         case T_FunctionScan:
     575             :         case T_ValuesScan:
     576             :         case T_CteScan:
     577             :         case T_Material:
     578             :         case T_Sort:
     579             :             /* these don't evaluate tlist */
     580        1286 :             return true;
     581             : 
     582           4 :         case T_IncrementalSort:
     583             : 
     584             :             /*
     585             :              * Unlike full sort, incremental sort keeps only a single group of
     586             :              * tuples in memory, so it can't scan backwards.
     587             :              */
     588           4 :             return false;
     589             : 
     590         116 :         case T_LockRows:
     591             :         case T_Limit:
     592         116 :             return ExecSupportsBackwardScan(outerPlan(node));
     593             : 
     594         680 :         default:
     595         680 :             return false;
     596             :     }
     597             : }
     598             : 
     599             : /*
     600             :  * An IndexScan or IndexOnlyScan node supports backward scan only if the
     601             :  * index's AM does.
     602             :  */
     603             : static bool
     604         438 : IndexSupportsBackwardScan(Oid indexid)
     605             : {
     606             :     bool        result;
     607             :     HeapTuple   ht_idxrel;
     608             :     Form_pg_class idxrelrec;
     609             :     IndexAmRoutine *amroutine;
     610             : 
     611             :     /* Fetch the pg_class tuple of the index relation */
     612         438 :     ht_idxrel = SearchSysCache1(RELOID, ObjectIdGetDatum(indexid));
     613         438 :     if (!HeapTupleIsValid(ht_idxrel))
     614           0 :         elog(ERROR, "cache lookup failed for relation %u", indexid);
     615         438 :     idxrelrec = (Form_pg_class) GETSTRUCT(ht_idxrel);
     616             : 
     617             :     /* Fetch the index AM's API struct */
     618         438 :     amroutine = GetIndexAmRoutineByAmId(idxrelrec->relam, false);
     619             : 
     620         438 :     result = amroutine->amcanbackward;
     621             : 
     622         438 :     pfree(amroutine);
     623         438 :     ReleaseSysCache(ht_idxrel);
     624             : 
     625         438 :     return result;
     626             : }
     627             : 
     628             : /*
     629             :  * ExecMaterializesOutput - does a plan type materialize its output?
     630             :  *
     631             :  * Returns true if the plan node type is one that automatically materializes
     632             :  * its output (typically by keeping it in a tuplestore).  For such plans,
     633             :  * a rescan without any parameter change will have zero startup cost and
     634             :  * very low per-tuple cost.
     635             :  */
     636             : bool
     637      838650 : ExecMaterializesOutput(NodeTag plantype)
     638             : {
     639      838650 :     switch (plantype)
     640             :     {
     641       13498 :         case T_Material:
     642             :         case T_FunctionScan:
     643             :         case T_TableFuncScan:
     644             :         case T_CteScan:
     645             :         case T_NamedTuplestoreScan:
     646             :         case T_WorkTableScan:
     647             :         case T_Sort:
     648       13498 :             return true;
     649             : 
     650      825152 :         default:
     651      825152 :             break;
     652             :     }
     653             : 
     654      825152 :     return false;
     655             : }

Generated by: LCOV version 1.14