LCOV - code coverage report
Current view: top level - src/backend/executor - nodeValuesscan.c (source / functions) Hit Total Coverage
Test: PostgreSQL 17devel Lines: 73 75 97.3 %
Date: 2024-04-26 15:11:27 Functions: 5 5 100.0 %
Legend: Lines: hit not hit

          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-2024, 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      221942 : 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      221942 :     estate = node->ss.ps.state;
      60      221942 :     direction = estate->es_direction;
      61      221942 :     slot = node->ss.ss_ScanTupleSlot;
      62      221942 :     econtext = node->rowcontext;
      63             : 
      64             :     /*
      65             :      * Get the next tuple. Return NULL if no more tuples.
      66             :      */
      67      221942 :     if (ScanDirectionIsForward(direction))
      68             :     {
      69      221942 :         if (node->curr_idx < node->array_len)
      70      221942 :             node->curr_idx++;
      71             :     }
      72             :     else
      73             :     {
      74           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      221942 :     ExecClearTuple(slot);
      85             : 
      86      221942 :     curr_idx = node->curr_idx;
      87      221942 :     if (curr_idx >= 0 && curr_idx < node->array_len)
      88             :     {
      89      153696 :         List       *exprlist = node->exprlists[curr_idx];
      90      153696 :         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      153696 :         ReScanExprContext(econtext);
     103             : 
     104             :         /*
     105             :          * Do per-VALUES-row work in the per-tuple context.
     106             :          */
     107      153696 :         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      153696 :         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      153636 :             exprstatelist = ExecInitExprList(exprlist, NULL);
     130             :         }
     131             : 
     132             :         /* parser should have checked all sublists are the same length */
     133             :         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      153696 :         values = slot->tts_values;
     140      153696 :         isnull = slot->tts_isnull;
     141             : 
     142      153696 :         resind = 0;
     143      330690 :         foreach(lc, exprstatelist)
     144             :         {
     145      176994 :             ExprState  *estate = (ExprState *) lfirst(lc);
     146      176994 :             Form_pg_attribute attr = TupleDescAttr(slot->tts_tupleDescriptor,
     147             :                                                    resind);
     148             : 
     149      176994 :             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      176994 :             values[resind] = MakeExpandedObjectReadOnly(values[resind],
     160             :                                                         isnull[resind],
     161             :                                                         attr->attlen);
     162             : 
     163      176994 :             resind++;
     164             :         }
     165             : 
     166      153696 :         MemoryContextSwitchTo(oldContext);
     167             : 
     168             :         /*
     169             :          * And return the virtual tuple.
     170             :          */
     171      153696 :         ExecStoreVirtualTuple(slot);
     172             :     }
     173             : 
     174      221942 :     return slot;
     175             : }
     176             : 
     177             : /*
     178             :  * ValuesRecheck -- access method routine to recheck a tuple in EvalPlanQual
     179             :  */
     180             : static bool
     181           4 : ValuesRecheck(ValuesScanState *node, TupleTableSlot *slot)
     182             : {
     183             :     /* nothing to check */
     184           4 :     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      220982 : ExecValuesScan(PlanState *pstate)
     198             : {
     199      220982 :     ValuesScanState *node = castNode(ValuesScanState, pstate);
     200             : 
     201      220982 :     return ExecScan(&node->ss,
     202             :                     (ExecScanAccessMtd) ValuesNext,
     203             :                     (ExecScanRecheckMtd) ValuesRecheck);
     204             : }
     205             : 
     206             : /* ----------------------------------------------------------------
     207             :  *      ExecInitValuesScan
     208             :  * ----------------------------------------------------------------
     209             :  */
     210             : ValuesScanState *
     211        8554 : 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             :     Assert(outerPlan(node) == NULL);
     223             :     Assert(innerPlan(node) == NULL);
     224             : 
     225             :     /*
     226             :      * create new ScanState for node
     227             :      */
     228        8554 :     scanstate = makeNode(ValuesScanState);
     229        8554 :     scanstate->ss.ps.plan = (Plan *) node;
     230        8554 :     scanstate->ss.ps.state = estate;
     231        8554 :     scanstate->ss.ps.ExecProcNode = ExecValuesScan;
     232             : 
     233             :     /*
     234             :      * Miscellaneous initialization
     235             :      */
     236        8554 :     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        8554 :     ExecAssignExprContext(estate, planstate);
     244        8554 :     scanstate->rowcontext = planstate->ps_ExprContext;
     245        8554 :     ExecAssignExprContext(estate, planstate);
     246             : 
     247             :     /*
     248             :      * Get info about values list, initialize scan slot with it.
     249             :      */
     250        8554 :     tupdesc = ExecTypeFromExprList((List *) linitial(node->values_lists));
     251        8554 :     ExecInitScanTupleSlot(estate, &scanstate->ss, tupdesc, &TTSOpsVirtual);
     252             : 
     253             :     /*
     254             :      * Initialize result type and projection.
     255             :      */
     256        8554 :     ExecInitResultTypeTL(&scanstate->ss.ps);
     257        8554 :     ExecAssignScanProjectionInfo(&scanstate->ss);
     258             : 
     259             :     /*
     260             :      * initialize child expressions
     261             :      */
     262        8554 :     scanstate->ss.ps.qual =
     263        8554 :         ExecInitQual(node->scan.plan.qual, (PlanState *) scanstate);
     264             : 
     265             :     /*
     266             :      * Other node-specific setup
     267             :      */
     268        8554 :     scanstate->curr_idx = -1;
     269        8554 :     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        8554 :     scanstate->exprlists = (List **)
     282        8554 :         palloc(scanstate->array_len * sizeof(List *));
     283        8554 :     scanstate->exprstatelists = (List **)
     284        8554 :         palloc0(scanstate->array_len * sizeof(List *));
     285        8554 :     i = 0;
     286       42814 :     foreach(vtl, node->values_lists)
     287             :     {
     288       34260 :         List       *exprs = lfirst_node(List, vtl);
     289             : 
     290       34260 :         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       34678 :         if (estate->es_subplanstates &&
     297         418 :             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          18 :             saved_jit_flags = estate->es_jit_flags;
     309          18 :             estate->es_jit_flags = PGJIT_NONE;
     310             : 
     311          18 :             scanstate->exprstatelists[i] = ExecInitExprList(exprs,
     312             :                                                             &scanstate->ss.ps);
     313             : 
     314          18 :             estate->es_jit_flags = saved_jit_flags;
     315             :         }
     316       34260 :         i++;
     317             :     }
     318             : 
     319        8554 :     return scanstate;
     320             : }
     321             : 
     322             : /* ----------------------------------------------------------------
     323             :  *      ExecReScanValuesScan
     324             :  *
     325             :  *      Rescans the relation.
     326             :  * ----------------------------------------------------------------
     327             :  */
     328             : void
     329       60398 : ExecReScanValuesScan(ValuesScanState *node)
     330             : {
     331       60398 :     if (node->ss.ps.ps_ResultTupleSlot)
     332          12 :         ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
     333             : 
     334       60398 :     ExecScanReScan(&node->ss);
     335             : 
     336       60398 :     node->curr_idx = -1;
     337       60398 : }

Generated by: LCOV version 1.14