LCOV - code coverage report
Current view: top level - src/backend/executor - nodeMaterial.c (source / functions) Hit Total Coverage
Test: PostgreSQL Lines: 85 91 93.4 %
Date: 2017-09-29 15:12:54 Functions: 6 6 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*-------------------------------------------------------------------------
       2             :  *
       3             :  * nodeMaterial.c
       4             :  *    Routines to handle materialization nodes.
       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/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     8231671 : ExecMaterial(PlanState *pstate)
      40             : {
      41     8231671 :     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     8231671 :     CHECK_FOR_INTERRUPTS();
      50             : 
      51             :     /*
      52             :      * get state info from node
      53             :      */
      54     8231671 :     estate = node->ss.ps.state;
      55     8231671 :     dir = estate->es_direction;
      56     8231671 :     forward = ScanDirectionIsForward(dir);
      57     8231671 :     tuplestorestate = node->tuplestorestate;
      58             : 
      59             :     /*
      60             :      * If first time through, and we need a tuplestore, initialize it.
      61             :      */
      62     8231671 :     if (tuplestorestate == NULL && node->eflags != 0)
      63             :     {
      64         172 :         tuplestorestate = tuplestore_begin_heap(true, false, work_mem);
      65         172 :         tuplestore_set_eflags(tuplestorestate, node->eflags);
      66         172 :         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          12 :             ptrno = tuplestore_alloc_read_pointer(tuplestorestate,
      75             :                                                   node->eflags);
      76          12 :             Assert(ptrno == 1);
      77             :         }
      78         172 :         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    16463342 :     eof_tuplestore = (tuplestorestate == NULL) ||
      86     8231671 :         tuplestore_ateof(tuplestorestate);
      87             : 
      88     8231671 :     if (!forward && eof_tuplestore)
      89             :     {
      90           2 :         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           0 :             if (!tuplestore_advance(tuplestorestate, forward))
      99           0 :                 return NULL;    /* the tuplestore must be empty */
     100             :         }
     101           2 :         eof_tuplestore = false;
     102             :     }
     103             : 
     104             :     /*
     105             :      * If we can fetch another tuple from the tuplestore, return it.
     106             :      */
     107     8231671 :     slot = node->ss.ps.ps_ResultTupleSlot;
     108     8231671 :     if (!eof_tuplestore)
     109             :     {
     110     8219334 :         if (tuplestore_gettupleslot(tuplestorestate, forward, false, slot))
     111     8211760 :             return slot;
     112        7574 :         if (forward)
     113        7572 :             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       19911 :     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       12513 :         outerNode = outerPlanState(node);
     134       12513 :         outerslot = ExecProcNode(outerNode);
     135       12513 :         if (TupIsNull(outerslot))
     136             :         {
     137         165 :             node->eof_underlying = true;
     138         165 :             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       12348 :         if (tuplestorestate)
     147       12348 :             tuplestore_puttupleslot(tuplestorestate, outerslot);
     148             : 
     149             :         /*
     150             :          * We can just return the subplan's returned tuple, without copying.
     151             :          */
     152       12348 :         return outerslot;
     153             :     }
     154             : 
     155             :     /*
     156             :      * Nothing left ...
     157             :      */
     158        7398 :     return ExecClearTuple(slot);
     159             : }
     160             : 
     161             : /* ----------------------------------------------------------------
     162             :  *      ExecInitMaterial
     163             :  * ----------------------------------------------------------------
     164             :  */
     165             : MaterialState *
     166         219 : ExecInitMaterial(Material *node, EState *estate, int eflags)
     167             : {
     168             :     MaterialState *matstate;
     169             :     Plan       *outerPlan;
     170             : 
     171             :     /*
     172             :      * create state structure
     173             :      */
     174         219 :     matstate = makeNode(MaterialState);
     175         219 :     matstate->ss.ps.plan = (Plan *) node;
     176         219 :     matstate->ss.ps.state = estate;
     177         219 :     matstate->ss.ps.ExecProcNode = ExecMaterial;
     178             : 
     179             :     /*
     180             :      * We must have a tuplestore buffering the subplan output to do backward
     181             :      * scan or mark/restore.  We also prefer to materialize the subplan output
     182             :      * if we might be called on to rewind and replay it many times. However,
     183             :      * if none of these cases apply, we can skip storing the data.
     184             :      */
     185         219 :     matstate->eflags = (eflags & (EXEC_FLAG_REWIND |
     186             :                                   EXEC_FLAG_BACKWARD |
     187             :                                   EXEC_FLAG_MARK));
     188             : 
     189             :     /*
     190             :      * Tuplestore's interpretation of the flag bits is subtly different from
     191             :      * the general executor meaning: it doesn't think BACKWARD necessarily
     192             :      * means "backwards all the way to start".  If told to support BACKWARD we
     193             :      * must include REWIND in the tuplestore eflags, else tuplestore_trim
     194             :      * might throw away too much.
     195             :      */
     196         219 :     if (eflags & EXEC_FLAG_BACKWARD)
     197           2 :         matstate->eflags |= EXEC_FLAG_REWIND;
     198             : 
     199         219 :     matstate->eof_underlying = false;
     200         219 :     matstate->tuplestorestate = NULL;
     201             : 
     202             :     /*
     203             :      * Miscellaneous initialization
     204             :      *
     205             :      * Materialization nodes don't need ExprContexts because they never call
     206             :      * ExecQual or ExecProject.
     207             :      */
     208             : 
     209             :     /*
     210             :      * tuple table initialization
     211             :      *
     212             :      * material nodes only return tuples from their materialized relation.
     213             :      */
     214         219 :     ExecInitResultTupleSlot(estate, &matstate->ss.ps);
     215         219 :     ExecInitScanTupleSlot(estate, &matstate->ss);
     216             : 
     217             :     /*
     218             :      * initialize child nodes
     219             :      *
     220             :      * We shield the child node from the need to support REWIND, BACKWARD, or
     221             :      * MARK/RESTORE.
     222             :      */
     223         219 :     eflags &= ~(EXEC_FLAG_REWIND | EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK);
     224             : 
     225         219 :     outerPlan = outerPlan(node);
     226         219 :     outerPlanState(matstate) = ExecInitNode(outerPlan, estate, eflags);
     227             : 
     228             :     /*
     229             :      * initialize tuple type.  no need to initialize projection info because
     230             :      * this node doesn't do projections.
     231             :      */
     232         219 :     ExecAssignResultTypeFromTL(&matstate->ss.ps);
     233         219 :     ExecAssignScanTypeFromOuterPlan(&matstate->ss);
     234         219 :     matstate->ss.ps.ps_ProjInfo = NULL;
     235             : 
     236         219 :     return matstate;
     237             : }
     238             : 
     239             : /* ----------------------------------------------------------------
     240             :  *      ExecEndMaterial
     241             :  * ----------------------------------------------------------------
     242             :  */
     243             : void
     244         215 : ExecEndMaterial(MaterialState *node)
     245             : {
     246             :     /*
     247             :      * clean out the tuple table
     248             :      */
     249         215 :     ExecClearTuple(node->ss.ss_ScanTupleSlot);
     250             : 
     251             :     /*
     252             :      * Release tuplestore resources
     253             :      */
     254         215 :     if (node->tuplestorestate != NULL)
     255         167 :         tuplestore_end(node->tuplestorestate);
     256         215 :     node->tuplestorestate = NULL;
     257             : 
     258             :     /*
     259             :      * shut down the subplan
     260             :      */
     261         215 :     ExecEndNode(outerPlanState(node));
     262         215 : }
     263             : 
     264             : /* ----------------------------------------------------------------
     265             :  *      ExecMaterialMarkPos
     266             :  *
     267             :  *      Calls tuplestore to save the current position in the stored file.
     268             :  * ----------------------------------------------------------------
     269             :  */
     270             : void
     271          44 : ExecMaterialMarkPos(MaterialState *node)
     272             : {
     273          44 :     Assert(node->eflags & EXEC_FLAG_MARK);
     274             : 
     275             :     /*
     276             :      * if we haven't materialized yet, just return.
     277             :      */
     278          44 :     if (!node->tuplestorestate)
     279          44 :         return;
     280             : 
     281             :     /*
     282             :      * copy the active read pointer to the mark.
     283             :      */
     284          44 :     tuplestore_copy_read_pointer(node->tuplestorestate, 0, 1);
     285             : 
     286             :     /*
     287             :      * since we may have advanced the mark, try to truncate the tuplestore.
     288             :      */
     289          44 :     tuplestore_trim(node->tuplestorestate);
     290             : }
     291             : 
     292             : /* ----------------------------------------------------------------
     293             :  *      ExecMaterialRestrPos
     294             :  *
     295             :  *      Calls tuplestore to restore the last saved file position.
     296             :  * ----------------------------------------------------------------
     297             :  */
     298             : void
     299           4 : ExecMaterialRestrPos(MaterialState *node)
     300             : {
     301           4 :     Assert(node->eflags & EXEC_FLAG_MARK);
     302             : 
     303             :     /*
     304             :      * if we haven't materialized yet, just return.
     305             :      */
     306           4 :     if (!node->tuplestorestate)
     307           4 :         return;
     308             : 
     309             :     /*
     310             :      * copy the mark to the active read pointer.
     311             :      */
     312           4 :     tuplestore_copy_read_pointer(node->tuplestorestate, 1, 0);
     313             : }
     314             : 
     315             : /* ----------------------------------------------------------------
     316             :  *      ExecReScanMaterial
     317             :  *
     318             :  *      Rescans the materialized relation.
     319             :  * ----------------------------------------------------------------
     320             :  */
     321             : void
     322        7620 : ExecReScanMaterial(MaterialState *node)
     323             : {
     324        7620 :     PlanState  *outerPlan = outerPlanState(node);
     325             : 
     326        7620 :     ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
     327             : 
     328        7620 :     if (node->eflags != 0)
     329             :     {
     330             :         /*
     331             :          * If we haven't materialized yet, just return. If outerplan's
     332             :          * chgParam is not NULL then it will be re-scanned by ExecProcNode,
     333             :          * else no reason to re-scan it at all.
     334             :          */
     335        7620 :         if (!node->tuplestorestate)
     336        7777 :             return;
     337             : 
     338             :         /*
     339             :          * If subnode is to be rescanned then we forget previous stored
     340             :          * results; we have to re-read the subplan and re-store.  Also, if we
     341             :          * told tuplestore it needn't support rescan, we lose and must
     342             :          * re-read.  (This last should not happen in common cases; else our
     343             :          * caller lied by not passing EXEC_FLAG_REWIND to us.)
     344             :          *
     345             :          * Otherwise we can just rewind and rescan the stored output. The
     346             :          * state of the subnode does not change.
     347             :          */
     348       14925 :         if (outerPlan->chgParam != NULL ||
     349        7462 :             (node->eflags & EXEC_FLAG_REWIND) == 0)
     350             :         {
     351           1 :             tuplestore_end(node->tuplestorestate);
     352           1 :             node->tuplestorestate = NULL;
     353           1 :             if (outerPlan->chgParam == NULL)
     354           0 :                 ExecReScan(outerPlan);
     355           1 :             node->eof_underlying = false;
     356             :         }
     357             :         else
     358        7462 :             tuplestore_rescan(node->tuplestorestate);
     359             :     }
     360             :     else
     361             :     {
     362             :         /* In this case we are just passing on the subquery's output */
     363             : 
     364             :         /*
     365             :          * if chgParam of subnode is not null then plan will be re-scanned by
     366             :          * first ExecProcNode.
     367             :          */
     368           0 :         if (outerPlan->chgParam == NULL)
     369           0 :             ExecReScan(outerPlan);
     370           0 :         node->eof_underlying = false;
     371             :     }
     372             : }

Generated by: LCOV version 1.11