]> granicus.if.org Git - postgresql/blobdiff - src/backend/executor/nodeValuesscan.c
Make some small planner API cleanups.
[postgresql] / src / backend / executor / nodeValuesscan.c
index 96e4b98a4e25cd947c30d2b5f16ca85796264810..0069a73588ad666de879f7d6f7c1ee528a0606b8 100644 (file)
@@ -4,12 +4,12 @@
  *       Support routines for scanning Values lists
  *       ("VALUES (...), (...), ..." in rangetable).
  *
- * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/executor/nodeValuesscan.c,v 1.6 2007/02/19 02:23:11 tgl Exp $
+ *       src/backend/executor/nodeValuesscan.c
  *
  *-------------------------------------------------------------------------
  */
  *             ExecValuesNext                  retrieve next tuple in sequential order.
  *             ExecInitValuesScan              creates and initializes a valuesscan node.
  *             ExecEndValuesScan               releases any storage allocated.
- *             ExecValuesReScan                rescans the values list
+ *             ExecReScanValuesScan    rescans the values list
  */
 #include "postgres.h"
 
 #include "executor/executor.h"
 #include "executor/nodeValuesscan.h"
-#include "parser/parsetree.h"
-#include "utils/memutils.h"
+#include "jit/jit.h"
+#include "utils/expandeddatum.h"
 
 
 static TupleTableSlot *ValuesNext(ValuesScanState *node);
@@ -93,11 +93,13 @@ ValuesNext(ValuesScanState *node)
        if (exprlist)
        {
                MemoryContext oldContext;
+               List       *oldsubplans;
                List       *exprstatelist;
                Datum      *values;
                bool       *isnull;
                ListCell   *lc;
                int                     resind;
+               int                     saved_jit_flags;
 
                /*
                 * Get rid of any prior cycle's leftovers.  We use ReScanExprContext
@@ -115,12 +117,30 @@ ValuesNext(ValuesScanState *node)
                oldContext = MemoryContextSwitchTo(econtext->ecxt_per_tuple_memory);
 
                /*
-                * Pass NULL, not my plan node, because we don't want anything in this
-                * transient state linking into permanent state.  The only possibility
-                * is a SubPlan, and there shouldn't be any (any subselects in the
-                * VALUES list should be InitPlans).
+                * The expressions might contain SubPlans (this is currently only
+                * possible if there's a sub-select containing a LATERAL reference,
+                * otherwise sub-selects in a VALUES list should be InitPlans). Those
+                * subplans will want to hook themselves into our subPlan list, which
+                * would result in a corrupted list after we delete the eval state. We
+                * can work around this by saving and restoring the subPlan list.
+                * (There's no need for the functionality that would be enabled by
+                * having the list entries, since the SubPlans aren't going to be
+                * re-executed anyway.)
                 */
-               exprstatelist = (List *) ExecInitExpr((Expr *) exprlist, NULL);
+               oldsubplans = node->ss.ps.subPlan;
+               node->ss.ps.subPlan = NIL;
+
+               /*
+                * As the expressions are only ever used once, disable JIT for them.
+                * This is worthwhile because it's common to insert significant
+                * amounts of data via VALUES().
+                */
+               saved_jit_flags = econtext->ecxt_estate->es_jit_flags;
+               econtext->ecxt_estate->es_jit_flags = PGJIT_NONE;
+               exprstatelist = ExecInitExprList(exprlist, &node->ss.ps);
+               econtext->ecxt_estate->es_jit_flags = saved_jit_flags;
+
+               node->ss.ps.subPlan = oldsubplans;
 
                /* parser should have checked all sublists are the same length */
                Assert(list_length(exprstatelist) == slot->tts_tupleDescriptor->natts);
@@ -136,11 +156,23 @@ ValuesNext(ValuesScanState *node)
                foreach(lc, exprstatelist)
                {
                        ExprState  *estate = (ExprState *) lfirst(lc);
+                       Form_pg_attribute attr = TupleDescAttr(slot->tts_tupleDescriptor,
+                                                                                                  resind);
 
                        values[resind] = ExecEvalExpr(estate,
                                                                                  econtext,
-                                                                                 &isnull[resind],
-                                                                                 NULL);
+                                                                                 &isnull[resind]);
+
+                       /*
+                        * We must force any R/W expanded datums to read-only state, in
+                        * case they are multiply referenced in the plan node's output
+                        * expressions, or in case we skip the output projection and the
+                        * output column is multiply referenced in higher plan nodes.
+                        */
+                       values[resind] = MakeExpandedObjectReadOnly(values[resind],
+                                                                                                               isnull[resind],
+                                                                                                               attr->attlen);
+
                        resind++;
                }
 
@@ -155,23 +187,33 @@ ValuesNext(ValuesScanState *node)
        return slot;
 }
 
+/*
+ * ValuesRecheck -- access method routine to recheck a tuple in EvalPlanQual
+ */
+static bool
+ValuesRecheck(ValuesScanState *node, TupleTableSlot *slot)
+{
+       /* nothing to check */
+       return true;
+}
 
 /* ----------------------------------------------------------------
  *             ExecValuesScan(node)
  *
  *             Scans the values lists sequentially and returns the next qualifying
  *             tuple.
- *             It calls the ExecScan() routine and passes it the access method
- *             which retrieves tuples sequentially.
+ *             We call the ExecScan() routine and pass it the appropriate
+ *             access method functions.
  * ----------------------------------------------------------------
  */
-TupleTableSlot *
-ExecValuesScan(ValuesScanState *node)
+static TupleTableSlot *
+ExecValuesScan(PlanState *pstate)
 {
-       /*
-        * use ValuesNext as access method
-        */
-       return ExecScan(&node->ss, (ExecScanAccessMtd) ValuesNext);
+       ValuesScanState *node = castNode(ValuesScanState, pstate);
+
+       return ExecScan(&node->ss,
+                                       (ExecScanAccessMtd) ValuesNext,
+                                       (ExecScanRecheckMtd) ValuesRecheck);
 }
 
 /* ----------------------------------------------------------------
@@ -199,6 +241,7 @@ ExecInitValuesScan(ValuesScan *node, EState *estate, int eflags)
        scanstate = makeNode(ValuesScanState);
        scanstate->ss.ps.plan = (Plan *) node;
        scanstate->ss.ps.state = estate;
+       scanstate->ss.ps.ExecProcNode = ExecValuesScan;
 
        /*
         * Miscellaneous initialization
@@ -206,7 +249,7 @@ ExecInitValuesScan(ValuesScan *node, EState *estate, int eflags)
        planstate = &scanstate->ss.ps;
 
        /*
-        * Create expression contexts.  We need two, one for per-sublist
+        * Create expression contexts.  We need two, one for per-sublist
         * processing and one for execScan.c to use for quals and projections. We
         * cheat a little by using ExecAssignExprContext() to build both.
         */
@@ -214,35 +257,27 @@ ExecInitValuesScan(ValuesScan *node, EState *estate, int eflags)
        scanstate->rowcontext = planstate->ps_ExprContext;
        ExecAssignExprContext(estate, planstate);
 
-#define VALUESSCAN_NSLOTS 2
-
        /*
-        * tuple table initialization
+        * Get info about values list, initialize scan slot with it.
         */
-       ExecInitResultTupleSlot(estate, &scanstate->ss.ps);
-       ExecInitScanTupleSlot(estate, &scanstate->ss);
+       tupdesc = ExecTypeFromExprList((List *) linitial(node->values_lists));
+       ExecInitScanTupleSlot(estate, &scanstate->ss, tupdesc, &TTSOpsVirtual);
 
        /*
-        * initialize child expressions
+        * Initialize result type and projection.
         */
-       scanstate->ss.ps.targetlist = (List *)
-               ExecInitExpr((Expr *) node->scan.plan.targetlist,
-                                        (PlanState *) scanstate);
-       scanstate->ss.ps.qual = (List *)
-               ExecInitExpr((Expr *) node->scan.plan.qual,
-                                        (PlanState *) scanstate);
+       ExecInitResultTypeTL(&scanstate->ss.ps);
+       ExecAssignScanProjectionInfo(&scanstate->ss);
 
        /*
-        * get info about values list
+        * initialize child expressions
         */
-       tupdesc = ExecTypeFromExprList((List *) linitial(node->values_lists));
-
-       ExecAssignScanType(&scanstate->ss, tupdesc);
+       scanstate->ss.ps.qual =
+               ExecInitQual(node->scan.plan.qual, (PlanState *) scanstate);
 
        /*
         * Other node-specific setup
         */
-       scanstate->marked_idx = -1;
        scanstate->curr_idx = -1;
        scanstate->array_len = list_length(node->values_lists);
 
@@ -255,25 +290,9 @@ ExecInitValuesScan(ValuesScan *node, EState *estate, int eflags)
                scanstate->exprlists[i++] = (List *) lfirst(vtl);
        }
 
-       scanstate->ss.ps.ps_TupFromTlist = false;
-
-       /*
-        * Initialize result tuple type and projection info.
-        */
-       ExecAssignResultTypeFromTL(&scanstate->ss.ps);
-       ExecAssignScanProjectionInfo(&scanstate->ss);
-
        return scanstate;
 }
 
-int
-ExecCountSlotsValuesScan(ValuesScan *node)
-{
-       return ExecCountSlotsNode(outerPlan(node)) +
-               ExecCountSlotsNode(innerPlan(node)) +
-               VALUESSCAN_NSLOTS;
-}
-
 /* ----------------------------------------------------------------
  *             ExecEndValuesScan
  *
@@ -293,45 +312,24 @@ ExecEndValuesScan(ValuesScanState *node)
        /*
         * clean out the tuple table
         */
-       ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
+       if (node->ss.ps.ps_ResultTupleSlot)
+               ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
        ExecClearTuple(node->ss.ss_ScanTupleSlot);
 }
 
 /* ----------------------------------------------------------------
- *             ExecValuesMarkPos
- *
- *             Marks scan position.
- * ----------------------------------------------------------------
- */
-void
-ExecValuesMarkPos(ValuesScanState *node)
-{
-       node->marked_idx = node->curr_idx;
-}
-
-/* ----------------------------------------------------------------
- *             ExecValuesRestrPos
- *
- *             Restores scan position.
- * ----------------------------------------------------------------
- */
-void
-ExecValuesRestrPos(ValuesScanState *node)
-{
-       node->curr_idx = node->marked_idx;
-}
-
-/* ----------------------------------------------------------------
- *             ExecValuesReScan
+ *             ExecReScanValuesScan
  *
  *             Rescans the relation.
  * ----------------------------------------------------------------
  */
 void
-ExecValuesReScan(ValuesScanState *node, ExprContext *exprCtxt)
+ExecReScanValuesScan(ValuesScanState *node)
 {
-       ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
-       node->ss.ps.ps_TupFromTlist = false;
+       if (node->ss.ps.ps_ResultTupleSlot)
+               ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
+
+       ExecScanReScan(&node->ss);
 
        node->curr_idx = -1;
 }