LCOV - differential code coverage report
Current view: top level - src/backend/executor - nodeMaterial.c (source / functions) Coverage Total Hit UBC CBC
Current: Differential Code Coverage HEAD vs 15 Lines: 94.4 % 90 85 5 85
Current Date: 2023-04-08 15:15:32 Functions: 100.0 % 6 6 6
Baseline: 15
Baseline Date: 2023-04-08 15:09:40
Legend: Lines: hit not hit

           TLA  Line data    Source code
       1                 : /*-------------------------------------------------------------------------
       2                 :  *
       3                 :  * nodeMaterial.c
       4                 :  *    Routines to handle materialization nodes.
       5                 :  *
       6                 :  * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group
       7                 :  * Portions Copyright (c) 1994, Regents of the University of California
       8                 :  *
       9                 :  *
      10                 :  * IDENTIFICATION
      11                 :  *    src/backend/executor/nodeMaterial.c
      12                 :  *
      13                 :  *-------------------------------------------------------------------------
      14                 :  */
      15                 : /*
      16                 :  * INTERFACE ROUTINES
      17                 :  *      ExecMaterial            - materialize the result of a subplan
      18                 :  *      ExecInitMaterial        - initialize node and subnodes
      19                 :  *      ExecEndMaterial         - shutdown node and subnodes
      20                 :  *
      21                 :  */
      22                 : #include "postgres.h"
      23                 : 
      24                 : #include "executor/executor.h"
      25                 : #include "executor/nodeMaterial.h"
      26                 : #include "miscadmin.h"
      27                 : 
      28                 : /* ----------------------------------------------------------------
      29                 :  *      ExecMaterial
      30                 :  *
      31                 :  *      As long as we are at the end of the data collected in the tuplestore,
      32                 :  *      we collect one new row from the subplan on each call, and stash it
      33                 :  *      aside in the tuplestore before returning it.  The tuplestore is
      34                 :  *      only read if we are asked to scan backwards, rescan, or mark/restore.
      35                 :  *
      36                 :  * ----------------------------------------------------------------
      37                 :  */
      38                 : static TupleTableSlot *         /* result tuple from subplan */
      39 CBC     2279531 : ExecMaterial(PlanState *pstate)
      40                 : {
      41         2279531 :     MaterialState *node = castNode(MaterialState, pstate);
      42                 :     EState     *estate;
      43                 :     ScanDirection dir;
      44                 :     bool        forward;
      45                 :     Tuplestorestate *tuplestorestate;
      46                 :     bool        eof_tuplestore;
      47                 :     TupleTableSlot *slot;
      48                 : 
      49         2279531 :     CHECK_FOR_INTERRUPTS();
      50                 : 
      51                 :     /*
      52                 :      * get state info from node
      53                 :      */
      54         2279531 :     estate = node->ss.ps.state;
      55         2279531 :     dir = estate->es_direction;
      56         2279531 :     forward = ScanDirectionIsForward(dir);
      57         2279531 :     tuplestorestate = node->tuplestorestate;
      58                 : 
      59                 :     /*
      60                 :      * If first time through, and we need a tuplestore, initialize it.
      61                 :      */
      62         2279531 :     if (tuplestorestate == NULL && node->eflags != 0)
      63                 :     {
      64            1534 :         tuplestorestate = tuplestore_begin_heap(true, false, work_mem);
      65            1534 :         tuplestore_set_eflags(tuplestorestate, node->eflags);
      66            1534 :         if (node->eflags & EXEC_FLAG_MARK)
      67                 :         {
      68                 :             /*
      69                 :              * Allocate a second read pointer to serve as the mark. We know it
      70                 :              * must have index 1, so needn't store that.
      71                 :              */
      72                 :             int         ptrno PG_USED_FOR_ASSERTS_ONLY;
      73                 : 
      74              60 :             ptrno = tuplestore_alloc_read_pointer(tuplestorestate,
      75                 :                                                   node->eflags);
      76              60 :             Assert(ptrno == 1);
      77                 :         }
      78            1534 :         node->tuplestorestate = tuplestorestate;
      79                 :     }
      80                 : 
      81                 :     /*
      82                 :      * If we are not at the end of the tuplestore, or are going backwards, try
      83                 :      * to fetch a tuple from tuplestore.
      84                 :      */
      85         4558997 :     eof_tuplestore = (tuplestorestate == NULL) ||
      86         2279466 :         tuplestore_ateof(tuplestorestate);
      87                 : 
      88         2279531 :     if (!forward && eof_tuplestore)
      89                 :     {
      90               6 :         if (!node->eof_underlying)
      91                 :         {
      92                 :             /*
      93                 :              * When reversing direction at tuplestore EOF, the first
      94                 :              * gettupleslot call will fetch the last-added tuple; but we want
      95                 :              * to return the one before that, if possible. So do an extra
      96                 :              * fetch.
      97                 :              */
      98 UBC           0 :             if (!tuplestore_advance(tuplestorestate, forward))
      99               0 :                 return NULL;    /* the tuplestore must be empty */
     100                 :         }
     101 CBC           6 :         eof_tuplestore = false;
     102                 :     }
     103                 : 
     104                 :     /*
     105                 :      * If we can fetch another tuple from the tuplestore, return it.
     106                 :      */
     107         2279531 :     slot = node->ss.ps.ps_ResultTupleSlot;
     108         2279531 :     if (!eof_tuplestore)
     109                 :     {
     110         2266989 :         if (tuplestore_gettupleslot(tuplestorestate, forward, false, slot))
     111         1999894 :             return slot;
     112          267095 :         if (forward)
     113          267089 :             eof_tuplestore = true;
     114                 :     }
     115                 : 
     116                 :     /*
     117                 :      * If necessary, try to fetch another row from the subplan.
     118                 :      *
     119                 :      * Note: the eof_underlying state variable exists to short-circuit further
     120                 :      * subplan calls.  It's not optional, unfortunately, because some plan
     121                 :      * node types are not robust about being called again when they've already
     122                 :      * returned NULL.
     123                 :      */
     124          279637 :     if (eof_tuplestore && !node->eof_underlying)
     125                 :     {
     126                 :         PlanState  *outerNode;
     127                 :         TupleTableSlot *outerslot;
     128                 : 
     129                 :         /*
     130                 :          * We can only get here with forward==true, so no need to worry about
     131                 :          * which direction the subplan will go.
     132                 :          */
     133           17174 :         outerNode = outerPlanState(node);
     134           17174 :         outerslot = ExecProcNode(outerNode);
     135           17174 :         if (TupIsNull(outerslot))
     136                 :         {
     137            1458 :             node->eof_underlying = true;
     138            1458 :             return NULL;
     139                 :         }
     140                 : 
     141                 :         /*
     142                 :          * Append a copy of the returned tuple to tuplestore.  NOTE: because
     143                 :          * the tuplestore is certainly in EOF state, its read position will
     144                 :          * move forward over the added tuple.  This is what we want.
     145                 :          */
     146           15716 :         if (tuplestorestate)
     147           15654 :             tuplestore_puttupleslot(tuplestorestate, outerslot);
     148                 : 
     149           15716 :         ExecCopySlot(slot, outerslot);
     150           15716 :         return slot;
     151                 :     }
     152                 : 
     153                 :     /*
     154                 :      * Nothing left ...
     155                 :      */
     156          262463 :     return ExecClearTuple(slot);
     157                 : }
     158                 : 
     159                 : /* ----------------------------------------------------------------
     160                 :  *      ExecInitMaterial
     161                 :  * ----------------------------------------------------------------
     162                 :  */
     163                 : MaterialState *
     164            1826 : ExecInitMaterial(Material *node, EState *estate, int eflags)
     165                 : {
     166                 :     MaterialState *matstate;
     167                 :     Plan       *outerPlan;
     168                 : 
     169                 :     /*
     170                 :      * create state structure
     171                 :      */
     172            1826 :     matstate = makeNode(MaterialState);
     173            1826 :     matstate->ss.ps.plan = (Plan *) node;
     174            1826 :     matstate->ss.ps.state = estate;
     175            1826 :     matstate->ss.ps.ExecProcNode = ExecMaterial;
     176                 : 
     177                 :     /*
     178                 :      * We must have a tuplestore buffering the subplan output to do backward
     179                 :      * scan or mark/restore.  We also prefer to materialize the subplan output
     180                 :      * if we might be called on to rewind and replay it many times. However,
     181                 :      * if none of these cases apply, we can skip storing the data.
     182                 :      */
     183            1826 :     matstate->eflags = (eflags & (EXEC_FLAG_REWIND |
     184                 :                                   EXEC_FLAG_BACKWARD |
     185                 :                                   EXEC_FLAG_MARK));
     186                 : 
     187                 :     /*
     188                 :      * Tuplestore's interpretation of the flag bits is subtly different from
     189                 :      * the general executor meaning: it doesn't think BACKWARD necessarily
     190                 :      * means "backwards all the way to start".  If told to support BACKWARD we
     191                 :      * must include REWIND in the tuplestore eflags, else tuplestore_trim
     192                 :      * might throw away too much.
     193                 :      */
     194            1826 :     if (eflags & EXEC_FLAG_BACKWARD)
     195               9 :         matstate->eflags |= EXEC_FLAG_REWIND;
     196                 : 
     197            1826 :     matstate->eof_underlying = false;
     198            1826 :     matstate->tuplestorestate = NULL;
     199                 : 
     200                 :     /*
     201                 :      * Miscellaneous initialization
     202                 :      *
     203                 :      * Materialization nodes don't need ExprContexts because they never call
     204                 :      * ExecQual or ExecProject.
     205                 :      */
     206                 : 
     207                 :     /*
     208                 :      * initialize child nodes
     209                 :      *
     210                 :      * We shield the child node from the need to support REWIND, BACKWARD, or
     211                 :      * MARK/RESTORE.
     212                 :      */
     213            1826 :     eflags &= ~(EXEC_FLAG_REWIND | EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK);
     214                 : 
     215            1826 :     outerPlan = outerPlan(node);
     216            1826 :     outerPlanState(matstate) = ExecInitNode(outerPlan, estate, eflags);
     217                 : 
     218                 :     /*
     219                 :      * Initialize result type and slot. No need to initialize projection info
     220                 :      * because this node doesn't do projections.
     221                 :      *
     222                 :      * material nodes only return tuples from their materialized relation.
     223                 :      */
     224            1826 :     ExecInitResultTupleSlotTL(&matstate->ss.ps, &TTSOpsMinimalTuple);
     225            1826 :     matstate->ss.ps.ps_ProjInfo = NULL;
     226                 : 
     227                 :     /*
     228                 :      * initialize tuple type.
     229                 :      */
     230            1826 :     ExecCreateScanSlotFromOuterPlan(estate, &matstate->ss, &TTSOpsMinimalTuple);
     231                 : 
     232            1826 :     return matstate;
     233                 : }
     234                 : 
     235                 : /* ----------------------------------------------------------------
     236                 :  *      ExecEndMaterial
     237                 :  * ----------------------------------------------------------------
     238                 :  */
     239                 : void
     240            1795 : ExecEndMaterial(MaterialState *node)
     241                 : {
     242                 :     /*
     243                 :      * clean out the tuple table
     244                 :      */
     245            1795 :     ExecClearTuple(node->ss.ss_ScanTupleSlot);
     246                 : 
     247                 :     /*
     248                 :      * Release tuplestore resources
     249                 :      */
     250            1795 :     if (node->tuplestorestate != NULL)
     251            1497 :         tuplestore_end(node->tuplestorestate);
     252            1795 :     node->tuplestorestate = NULL;
     253                 : 
     254                 :     /*
     255                 :      * shut down the subplan
     256                 :      */
     257            1795 :     ExecEndNode(outerPlanState(node));
     258            1795 : }
     259                 : 
     260                 : /* ----------------------------------------------------------------
     261                 :  *      ExecMaterialMarkPos
     262                 :  *
     263                 :  *      Calls tuplestore to save the current position in the stored file.
     264                 :  * ----------------------------------------------------------------
     265                 :  */
     266                 : void
     267            3287 : ExecMaterialMarkPos(MaterialState *node)
     268                 : {
     269            3287 :     Assert(node->eflags & EXEC_FLAG_MARK);
     270                 : 
     271                 :     /*
     272                 :      * if we haven't materialized yet, just return.
     273                 :      */
     274            3287 :     if (!node->tuplestorestate)
     275               6 :         return;
     276                 : 
     277                 :     /*
     278                 :      * copy the active read pointer to the mark.
     279                 :      */
     280            3281 :     tuplestore_copy_read_pointer(node->tuplestorestate, 0, 1);
     281                 : 
     282                 :     /*
     283                 :      * since we may have advanced the mark, try to truncate the tuplestore.
     284                 :      */
     285            3281 :     tuplestore_trim(node->tuplestorestate);
     286                 : }
     287                 : 
     288                 : /* ----------------------------------------------------------------
     289                 :  *      ExecMaterialRestrPos
     290                 :  *
     291                 :  *      Calls tuplestore to restore the last saved file position.
     292                 :  * ----------------------------------------------------------------
     293                 :  */
     294                 : void
     295           27122 : ExecMaterialRestrPos(MaterialState *node)
     296                 : {
     297           27122 :     Assert(node->eflags & EXEC_FLAG_MARK);
     298                 : 
     299                 :     /*
     300                 :      * if we haven't materialized yet, just return.
     301                 :      */
     302           27122 :     if (!node->tuplestorestate)
     303 UBC           0 :         return;
     304                 : 
     305                 :     /*
     306                 :      * copy the mark to the active read pointer.
     307                 :      */
     308 CBC       27122 :     tuplestore_copy_read_pointer(node->tuplestorestate, 1, 0);
     309                 : }
     310                 : 
     311                 : /* ----------------------------------------------------------------
     312                 :  *      ExecReScanMaterial
     313                 :  *
     314                 :  *      Rescans the materialized relation.
     315                 :  * ----------------------------------------------------------------
     316                 :  */
     317                 : void
     318          267910 : ExecReScanMaterial(MaterialState *node)
     319                 : {
     320          267910 :     PlanState  *outerPlan = outerPlanState(node);
     321                 : 
     322          267910 :     ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
     323                 : 
     324          267910 :     if (node->eflags != 0)
     325                 :     {
     326                 :         /*
     327                 :          * If we haven't materialized yet, just return. If outerplan's
     328                 :          * chgParam is not NULL then it will be re-scanned by ExecProcNode,
     329                 :          * else no reason to re-scan it at all.
     330                 :          */
     331          267908 :         if (!node->tuplestorestate)
     332            1465 :             return;
     333                 : 
     334                 :         /*
     335                 :          * If subnode is to be rescanned then we forget previous stored
     336                 :          * results; we have to re-read the subplan and re-store.  Also, if we
     337                 :          * told tuplestore it needn't support rescan, we lose and must
     338                 :          * re-read.  (This last should not happen in common cases; else our
     339                 :          * caller lied by not passing EXEC_FLAG_REWIND to us.)
     340                 :          *
     341                 :          * Otherwise we can just rewind and rescan the stored output. The
     342                 :          * state of the subnode does not change.
     343                 :          */
     344          266443 :         if (outerPlan->chgParam != NULL ||
     345          266437 :             (node->eflags & EXEC_FLAG_REWIND) == 0)
     346                 :         {
     347               6 :             tuplestore_end(node->tuplestorestate);
     348               6 :             node->tuplestorestate = NULL;
     349               6 :             if (outerPlan->chgParam == NULL)
     350 UBC           0 :                 ExecReScan(outerPlan);
     351 CBC           6 :             node->eof_underlying = false;
     352                 :         }
     353                 :         else
     354          266437 :             tuplestore_rescan(node->tuplestorestate);
     355                 :     }
     356                 :     else
     357                 :     {
     358                 :         /* In this case we are just passing on the subquery's output */
     359                 : 
     360                 :         /*
     361                 :          * if chgParam of subnode is not null then plan will be re-scanned by
     362                 :          * first ExecProcNode.
     363                 :          */
     364               2 :         if (outerPlan->chgParam == NULL)
     365 UBC           0 :             ExecReScan(outerPlan);
     366 CBC           2 :         node->eof_underlying = false;
     367                 :     }
     368                 : }
        

Generated by: LCOV version v1.16-55-g56c0a2a