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 17:13:01 Functions: 100.0 % 6 6 6
Baseline: 15 Line coverage date bins:
Baseline Date: 2023-04-08 15:09:40 (240..) days: 94.4 % 90 85 5 85
Legend: Lines: hit not hit Function coverage date bins:
(240..) days: 100.0 % 6 6 6

 Age         Owner                  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 */
 2092 andres                     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                 : 
 2084                            49         2279531 :     CHECK_FOR_INTERRUPTS();
                                 50                 : 
                                 51                 :     /*
                                 52                 :      * get state info from node
                                 53                 :      */
 7430 tgl                        54         2279531 :     estate = node->ss.ps.state;
 9345 bruce                      55         2279531 :     dir = estate->es_direction;
 7336 tgl                        56         2279531 :     forward = ScanDirectionIsForward(dir);
 5303                            57         2279531 :     tuplestorestate = node->tuplestorestate;
                                 58                 : 
                                 59                 :     /*
                                 60                 :      * If first time through, and we need a tuplestore, initialize it.
                                 61                 :      */
 5802                            62         2279531 :     if (tuplestorestate == NULL && node->eflags != 0)
                                 63                 :     {
 7005                            64            1534 :         tuplestorestate = tuplestore_begin_heap(true, false, work_mem);
 5802                            65            1534 :         tuplestore_set_eflags(tuplestorestate, node->eflags);
 5303                            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                 : 
 5216                            74              60 :             ptrno = tuplestore_alloc_read_pointer(tuplestorestate,
                                 75                 :                                                   node->eflags);
                                 76              60 :             Assert(ptrno == 1);
                                 77                 :         }
 5303                            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                 :      */
 6249                            85         4558997 :     eof_tuplestore = (tuplestorestate == NULL) ||
                                 86         2279466 :         tuplestore_ateof(tuplestorestate);
                                 87                 : 
 7336                            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                 :              */
 6130 tgl                        98 UBC           0 :             if (!tuplestore_advance(tuplestorestate, forward))
 7188 bruce                      99               0 :                 return NULL;    /* the tuplestore must be empty */
                                100                 :         }
 7336 tgl                       101 CBC           6 :         eof_tuplestore = false;
                                102                 :     }
                                103                 : 
                                104                 :     /*
                                105                 :      * If we can fetch another tuple from the tuplestore, return it.
                                106                 :      */
 6130                           107         2279531 :     slot = node->ss.ps.ps_ResultTupleSlot;
 7336                           108         2279531 :     if (!eof_tuplestore)
                                109                 :     {
 5126                           110         2266989 :         if (tuplestore_gettupleslot(tuplestorestate, forward, false, slot))
 6130                           111         1999894 :             return slot;
                                112          267095 :         if (forward)
 7336                           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                 :          */
 6249                           146           15716 :         if (tuplestorestate)
 6130                           147           15654 :             tuplestore_puttupleslot(tuplestorestate, outerslot);
                                148                 : 
 1606 andres                    149           15716 :         ExecCopySlot(slot, outerslot);
                                150           15716 :         return slot;
                                151                 :     }
                                152                 : 
                                153                 :     /*
                                154                 :      * Nothing left ...
                                155                 :      */
 6130 tgl                       156          262463 :     return ExecClearTuple(slot);
                                157                 : }
                                158                 : 
                                159                 : /* ----------------------------------------------------------------
                                160                 :  *      ExecInitMaterial
                                161                 :  * ----------------------------------------------------------------
                                162                 :  */
                                163                 : MaterialState *
 6249                           164            1826 : ExecInitMaterial(Material *node, EState *estate, int eflags)
                                165                 : {
                                166                 :     MaterialState *matstate;
                                167                 :     Plan       *outerPlan;
                                168                 : 
                                169                 :     /*
                                170                 :      * create state structure
                                171                 :      */
 9345 bruce                     172            1826 :     matstate = makeNode(MaterialState);
 7430 tgl                       173            1826 :     matstate->ss.ps.plan = (Plan *) node;
                                174            1826 :     matstate->ss.ps.state = estate;
 2092 andres                    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                 :      */
 5802 tgl                       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                 :      */
 5216                           194            1826 :     if (eflags & EXEC_FLAG_BACKWARD)
                                195               9 :         matstate->eflags |= EXEC_FLAG_REWIND;
                                196                 : 
 7336                           197            1826 :     matstate->eof_underlying = false;
 6249                           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                 : 
 7430                           215            1826 :     outerPlan = outerPlan(node);
 6249                           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                 :      */
 1606 andres                    224            1826 :     ExecInitResultTupleSlotTL(&matstate->ss.ps, &TTSOpsMinimalTuple);
 7430 tgl                       225            1826 :     matstate->ss.ps.ps_ProjInfo = NULL;
                                226                 : 
                                227                 :     /*
                                228                 :      * initialize tuple type.
                                229                 :      */
 1606 andres                    230            1826 :     ExecCreateScanSlotFromOuterPlan(estate, &matstate->ss, &TTSOpsMinimalTuple);
                                231                 : 
 7430 tgl                       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)
 5303                           251            1497 :         tuplestore_end(node->tuplestorestate);
 7430                           252            1795 :     node->tuplestorestate = NULL;
                                253                 : 
                                254                 :     /*
                                255                 :      * shut down the subplan
                                256                 :      */
 7420                           257            1795 :     ExecEndNode(outerPlanState(node));
 9345 bruce                     258            1795 : }
                                259                 : 
                                260                 : /* ----------------------------------------------------------------
                                261                 :  *      ExecMaterialMarkPos
                                262                 :  *
                                263                 :  *      Calls tuplestore to save the current position in the stored file.
                                264                 :  * ----------------------------------------------------------------
                                265                 :  */
                                266                 : void
 7430 tgl                       267            3287 : ExecMaterialMarkPos(MaterialState *node)
                                268                 : {
 5802                           269            3287 :     Assert(node->eflags & EXEC_FLAG_MARK);
                                270                 : 
                                271                 :     /*
                                272                 :      * if we haven't materialized yet, just return.
                                273                 :      */
 7430                           274            3287 :     if (!node->tuplestorestate)
 9186 vadim4o                   275               6 :         return;
                                276                 : 
                                277                 :     /*
                                278                 :      * copy the active read pointer to the mark.
                                279                 :      */
 5303 tgl                       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                 :      */
 5216                           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
 7430                           295           27122 : ExecMaterialRestrPos(MaterialState *node)
                                296                 : {
 5802                           297           27122 :     Assert(node->eflags & EXEC_FLAG_MARK);
                                298                 : 
                                299                 :     /*
                                300                 :      * if we haven't materialized yet, just return.
                                301                 :      */
 7430                           302           27122 :     if (!node->tuplestorestate)
 8330 tgl                       303 UBC           0 :         return;
                                304                 : 
                                305                 :     /*
                                306                 :      * copy the mark to the active read pointer.
                                307                 :      */
 5303 tgl                       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
 4654                           318          267910 : ExecReScanMaterial(MaterialState *node)
                                319                 : {
 2878 bruce                     320          267910 :     PlanState  *outerPlan = outerPlanState(node);
                                321                 : 
 7430 tgl                       322          267910 :     ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
                                323                 : 
 5802                           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                 :          */
 6249                           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                 :          */
 2897 rhaas                     344          266443 :         if (outerPlan->chgParam != NULL ||
 5802 tgl                       345          266437 :             (node->eflags & EXEC_FLAG_REWIND) == 0)
                                346                 :         {
 5303                           347               6 :             tuplestore_end(node->tuplestorestate);
 6249                           348               6 :             node->tuplestorestate = NULL;
 2897 rhaas                     349               6 :             if (outerPlan->chgParam == NULL)
 2897 rhaas                     350 UBC           0 :                 ExecReScan(outerPlan);
 6249 tgl                       351 CBC           6 :             node->eof_underlying = false;
                                352                 :         }
                                353                 :         else
 5303                           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                 :          */
 2897 rhaas                     364               2 :         if (outerPlan->chgParam == NULL)
 2897 rhaas                     365 UBC           0 :             ExecReScan(outerPlan);
 6249 tgl                       366 CBC           2 :         node->eof_underlying = false;
                                367                 :     }
                                368                 : }
        

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