LCOV - differential code coverage report
Current view: top level - src/backend/executor - nodeValuesscan.c (source / functions) Coverage Total Hit UBC CBC
Current: Differential Code Coverage HEAD vs 15 Lines: 96.5 % 86 83 3 83
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                 :  * nodeValuesscan.c
       4                 :  *    Support routines for scanning Values lists
       5                 :  *    ("VALUES (...), (...), ..." in rangetable).
       6                 :  *
       7                 :  * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group
       8                 :  * Portions Copyright (c) 1994, Regents of the University of California
       9                 :  *
      10                 :  *
      11                 :  * IDENTIFICATION
      12                 :  *    src/backend/executor/nodeValuesscan.c
      13                 :  *
      14                 :  *-------------------------------------------------------------------------
      15                 :  */
      16                 : /*
      17                 :  * INTERFACE ROUTINES
      18                 :  *      ExecValuesScan          scans a values list.
      19                 :  *      ExecValuesNext          retrieve next tuple in sequential order.
      20                 :  *      ExecInitValuesScan      creates and initializes a valuesscan node.
      21                 :  *      ExecEndValuesScan       releases any storage allocated.
      22                 :  *      ExecReScanValuesScan    rescans the values list
      23                 :  */
      24                 : #include "postgres.h"
      25                 : 
      26                 : #include "executor/executor.h"
      27                 : #include "executor/nodeValuesscan.h"
      28                 : #include "jit/jit.h"
      29                 : #include "optimizer/clauses.h"
      30                 : #include "utils/expandeddatum.h"
      31                 : 
      32                 : 
      33                 : static TupleTableSlot *ValuesNext(ValuesScanState *node);
      34                 : 
      35                 : 
      36                 : /* ----------------------------------------------------------------
      37                 :  *                      Scan Support
      38                 :  * ----------------------------------------------------------------
      39                 :  */
      40                 : 
      41                 : /* ----------------------------------------------------------------
      42                 :  *      ValuesNext
      43                 :  *
      44                 :  *      This is a workhorse for ExecValuesScan
      45                 :  * ----------------------------------------------------------------
      46                 :  */
      47                 : static TupleTableSlot *
      48 CBC      179791 : ValuesNext(ValuesScanState *node)
      49                 : {
      50                 :     TupleTableSlot *slot;
      51                 :     EState     *estate;
      52                 :     ExprContext *econtext;
      53                 :     ScanDirection direction;
      54                 :     int         curr_idx;
      55                 : 
      56                 :     /*
      57                 :      * get information from the estate and scan state
      58                 :      */
      59          179791 :     estate = node->ss.ps.state;
      60          179791 :     direction = estate->es_direction;
      61          179791 :     slot = node->ss.ss_ScanTupleSlot;
      62          179791 :     econtext = node->rowcontext;
      63                 : 
      64                 :     /*
      65                 :      * Get the next tuple. Return NULL if no more tuples.
      66                 :      */
      67          179791 :     if (ScanDirectionIsForward(direction))
      68                 :     {
      69          179791 :         if (node->curr_idx < node->array_len)
      70          179791 :             node->curr_idx++;
      71                 :     }
      72                 :     else
      73                 :     {
      74 UBC           0 :         if (node->curr_idx >= 0)
      75               0 :             node->curr_idx--;
      76                 :     }
      77                 : 
      78                 :     /*
      79                 :      * Always clear the result slot; this is appropriate if we are at the end
      80                 :      * of the data, and if we're not, we still need it as the first step of
      81                 :      * the store-virtual-tuple protocol.  It seems wise to clear the slot
      82                 :      * before we reset the context it might have pointers into.
      83                 :      */
      84 CBC      179791 :     ExecClearTuple(slot);
      85                 : 
      86          179791 :     curr_idx = node->curr_idx;
      87          179791 :     if (curr_idx >= 0 && curr_idx < node->array_len)
      88                 :     {
      89          145971 :         List       *exprlist = node->exprlists[curr_idx];
      90          145971 :         List       *exprstatelist = node->exprstatelists[curr_idx];
      91                 :         MemoryContext oldContext;
      92                 :         Datum      *values;
      93                 :         bool       *isnull;
      94                 :         ListCell   *lc;
      95                 :         int         resind;
      96                 : 
      97                 :         /*
      98                 :          * Get rid of any prior cycle's leftovers.  We use ReScanExprContext
      99                 :          * not just ResetExprContext because we want any registered shutdown
     100                 :          * callbacks to be called.
     101                 :          */
     102          145971 :         ReScanExprContext(econtext);
     103                 : 
     104                 :         /*
     105                 :          * Do per-VALUES-row work in the per-tuple context.
     106                 :          */
     107          145971 :         oldContext = MemoryContextSwitchTo(econtext->ecxt_per_tuple_memory);
     108                 : 
     109                 :         /*
     110                 :          * Unless we already made the expression eval state for this row,
     111                 :          * build it in the econtext's per-tuple memory.  This is a tad
     112                 :          * unusual, but we want to delete the eval state again when we move to
     113                 :          * the next row, to avoid growth of memory requirements over a long
     114                 :          * values list.  For rows in which that won't work, we already built
     115                 :          * the eval state at plan startup.
     116                 :          */
     117          145971 :         if (exprstatelist == NIL)
     118                 :         {
     119                 :             /*
     120                 :              * Pass parent as NULL, not my plan node, because we don't want
     121                 :              * anything in this transient state linking into permanent state.
     122                 :              * The only expression type that might wish to do so is a SubPlan,
     123                 :              * and we already checked that there aren't any.
     124                 :              *
     125                 :              * Note that passing parent = NULL also disables JIT compilation
     126                 :              * of the expressions, which is a win, because they're only going
     127                 :              * to be used once under normal circumstances.
     128                 :              */
     129          145941 :             exprstatelist = ExecInitExprList(exprlist, NULL);
     130                 :         }
     131                 : 
     132                 :         /* parser should have checked all sublists are the same length */
     133          145971 :         Assert(list_length(exprstatelist) == slot->tts_tupleDescriptor->natts);
     134                 : 
     135                 :         /*
     136                 :          * Compute the expressions and build a virtual result tuple. We
     137                 :          * already did ExecClearTuple(slot).
     138                 :          */
     139          145971 :         values = slot->tts_values;
     140          145971 :         isnull = slot->tts_isnull;
     141                 : 
     142          145971 :         resind = 0;
     143          302832 :         foreach(lc, exprstatelist)
     144                 :         {
     145          156861 :             ExprState  *estate = (ExprState *) lfirst(lc);
     146          156861 :             Form_pg_attribute attr = TupleDescAttr(slot->tts_tupleDescriptor,
     147                 :                                                    resind);
     148                 : 
     149          156861 :             values[resind] = ExecEvalExpr(estate,
     150                 :                                           econtext,
     151                 :                                           &isnull[resind]);
     152                 : 
     153                 :             /*
     154                 :              * We must force any R/W expanded datums to read-only state, in
     155                 :              * case they are multiply referenced in the plan node's output
     156                 :              * expressions, or in case we skip the output projection and the
     157                 :              * output column is multiply referenced in higher plan nodes.
     158                 :              */
     159          156861 :             values[resind] = MakeExpandedObjectReadOnly(values[resind],
     160                 :                                                         isnull[resind],
     161                 :                                                         attr->attlen);
     162                 : 
     163          156861 :             resind++;
     164                 :         }
     165                 : 
     166          145971 :         MemoryContextSwitchTo(oldContext);
     167                 : 
     168                 :         /*
     169                 :          * And return the virtual tuple.
     170                 :          */
     171          145971 :         ExecStoreVirtualTuple(slot);
     172                 :     }
     173                 : 
     174          179791 :     return slot;
     175                 : }
     176                 : 
     177                 : /*
     178                 :  * ValuesRecheck -- access method routine to recheck a tuple in EvalPlanQual
     179                 :  */
     180                 : static bool
     181               1 : ValuesRecheck(ValuesScanState *node, TupleTableSlot *slot)
     182                 : {
     183                 :     /* nothing to check */
     184               1 :     return true;
     185                 : }
     186                 : 
     187                 : /* ----------------------------------------------------------------
     188                 :  *      ExecValuesScan(node)
     189                 :  *
     190                 :  *      Scans the values lists sequentially and returns the next qualifying
     191                 :  *      tuple.
     192                 :  *      We call the ExecScan() routine and pass it the appropriate
     193                 :  *      access method functions.
     194                 :  * ----------------------------------------------------------------
     195                 :  */
     196                 : static TupleTableSlot *
     197          179316 : ExecValuesScan(PlanState *pstate)
     198                 : {
     199          179316 :     ValuesScanState *node = castNode(ValuesScanState, pstate);
     200                 : 
     201          179316 :     return ExecScan(&node->ss,
     202                 :                     (ExecScanAccessMtd) ValuesNext,
     203                 :                     (ExecScanRecheckMtd) ValuesRecheck);
     204                 : }
     205                 : 
     206                 : /* ----------------------------------------------------------------
     207                 :  *      ExecInitValuesScan
     208                 :  * ----------------------------------------------------------------
     209                 :  */
     210                 : ValuesScanState *
     211            3958 : ExecInitValuesScan(ValuesScan *node, EState *estate, int eflags)
     212                 : {
     213                 :     ValuesScanState *scanstate;
     214                 :     TupleDesc   tupdesc;
     215                 :     ListCell   *vtl;
     216                 :     int         i;
     217                 :     PlanState  *planstate;
     218                 : 
     219                 :     /*
     220                 :      * ValuesScan should not have any children.
     221                 :      */
     222            3958 :     Assert(outerPlan(node) == NULL);
     223            3958 :     Assert(innerPlan(node) == NULL);
     224                 : 
     225                 :     /*
     226                 :      * create new ScanState for node
     227                 :      */
     228            3958 :     scanstate = makeNode(ValuesScanState);
     229            3958 :     scanstate->ss.ps.plan = (Plan *) node;
     230            3958 :     scanstate->ss.ps.state = estate;
     231            3958 :     scanstate->ss.ps.ExecProcNode = ExecValuesScan;
     232                 : 
     233                 :     /*
     234                 :      * Miscellaneous initialization
     235                 :      */
     236            3958 :     planstate = &scanstate->ss.ps;
     237                 : 
     238                 :     /*
     239                 :      * Create expression contexts.  We need two, one for per-sublist
     240                 :      * processing and one for execScan.c to use for quals and projections. We
     241                 :      * cheat a little by using ExecAssignExprContext() to build both.
     242                 :      */
     243            3958 :     ExecAssignExprContext(estate, planstate);
     244            3958 :     scanstate->rowcontext = planstate->ps_ExprContext;
     245            3958 :     ExecAssignExprContext(estate, planstate);
     246                 : 
     247                 :     /*
     248                 :      * Get info about values list, initialize scan slot with it.
     249                 :      */
     250            3958 :     tupdesc = ExecTypeFromExprList((List *) linitial(node->values_lists));
     251            3958 :     ExecInitScanTupleSlot(estate, &scanstate->ss, tupdesc, &TTSOpsVirtual);
     252                 : 
     253                 :     /*
     254                 :      * Initialize result type and projection.
     255                 :      */
     256            3958 :     ExecInitResultTypeTL(&scanstate->ss.ps);
     257            3958 :     ExecAssignScanProjectionInfo(&scanstate->ss);
     258                 : 
     259                 :     /*
     260                 :      * initialize child expressions
     261                 :      */
     262            3958 :     scanstate->ss.ps.qual =
     263            3958 :         ExecInitQual(node->scan.plan.qual, (PlanState *) scanstate);
     264                 : 
     265                 :     /*
     266                 :      * Other node-specific setup
     267                 :      */
     268            3958 :     scanstate->curr_idx = -1;
     269            3958 :     scanstate->array_len = list_length(node->values_lists);
     270                 : 
     271                 :     /*
     272                 :      * Convert the list of expression sublists into an array for easier
     273                 :      * addressing at runtime.  Also, detect whether any sublists contain
     274                 :      * SubPlans; for just those sublists, go ahead and do expression
     275                 :      * initialization.  (This avoids problems with SubPlans wanting to connect
     276                 :      * themselves up to the outer plan tree.  Notably, EXPLAIN won't see the
     277                 :      * subplans otherwise; also we will have troubles with dangling pointers
     278                 :      * and/or leaked resources if we try to handle SubPlans the same as
     279                 :      * simpler expressions.)
     280                 :      */
     281            3958 :     scanstate->exprlists = (List **)
     282            3958 :         palloc(scanstate->array_len * sizeof(List *));
     283            3958 :     scanstate->exprstatelists = (List **)
     284            3958 :         palloc0(scanstate->array_len * sizeof(List *));
     285            3958 :     i = 0;
     286           90197 :     foreach(vtl, node->values_lists)
     287                 :     {
     288           86239 :         List       *exprs = lfirst_node(List, vtl);
     289                 : 
     290           86239 :         scanstate->exprlists[i] = exprs;
     291                 : 
     292                 :         /*
     293                 :          * We can avoid the cost of a contain_subplans() scan in the simple
     294                 :          * case where there are no SubPlans anywhere.
     295                 :          */
     296           86448 :         if (estate->es_subplanstates &&
     297             209 :             contain_subplans((Node *) exprs))
     298                 :         {
     299                 :             int         saved_jit_flags;
     300                 : 
     301                 :             /*
     302                 :              * As these expressions are only used once, disable JIT for them.
     303                 :              * This is worthwhile because it's common to insert significant
     304                 :              * amounts of data via VALUES().  Note that this doesn't prevent
     305                 :              * use of JIT *within* a subplan, since that's initialized
     306                 :              * separately; this just affects the upper-level subexpressions.
     307                 :              */
     308               9 :             saved_jit_flags = estate->es_jit_flags;
     309               9 :             estate->es_jit_flags = PGJIT_NONE;
     310                 : 
     311               9 :             scanstate->exprstatelists[i] = ExecInitExprList(exprs,
     312                 :                                                             &scanstate->ss.ps);
     313                 : 
     314               9 :             estate->es_jit_flags = saved_jit_flags;
     315                 :         }
     316           86239 :         i++;
     317                 :     }
     318                 : 
     319            3958 :     return scanstate;
     320                 : }
     321                 : 
     322                 : /* ----------------------------------------------------------------
     323                 :  *      ExecEndValuesScan
     324                 :  *
     325                 :  *      frees any storage allocated through C routines.
     326                 :  * ----------------------------------------------------------------
     327                 :  */
     328                 : void
     329            3894 : ExecEndValuesScan(ValuesScanState *node)
     330                 : {
     331                 :     /*
     332                 :      * Free both exprcontexts
     333                 :      */
     334            3894 :     ExecFreeExprContext(&node->ss.ps);
     335            3894 :     node->ss.ps.ps_ExprContext = node->rowcontext;
     336            3894 :     ExecFreeExprContext(&node->ss.ps);
     337                 : 
     338                 :     /*
     339                 :      * clean out the tuple table
     340                 :      */
     341            3894 :     if (node->ss.ps.ps_ResultTupleSlot)
     342             809 :         ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
     343            3894 :     ExecClearTuple(node->ss.ss_ScanTupleSlot);
     344            3894 : }
     345                 : 
     346                 : /* ----------------------------------------------------------------
     347                 :  *      ExecReScanValuesScan
     348                 :  *
     349                 :  *      Rescans the relation.
     350                 :  * ----------------------------------------------------------------
     351                 :  */
     352                 : void
     353           30193 : ExecReScanValuesScan(ValuesScanState *node)
     354                 : {
     355           30193 :     if (node->ss.ps.ps_ResultTupleSlot)
     356 UBC           0 :         ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
     357                 : 
     358 CBC       30193 :     ExecScanReScan(&node->ss);
     359                 : 
     360           30193 :     node->curr_idx = -1;
     361           30193 : }
        

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