* Support routines for scanning Values lists
* ("VALUES (...), (...), ..." in rangetable).
*
- * Portions Copyright (c) 1996-2010, 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.13 2010/07/12 17:01:05 tgl Exp $
+ * src/backend/executor/nodeValuesscan.c
*
*-------------------------------------------------------------------------
*/
#include "executor/executor.h"
#include "executor/nodeValuesscan.h"
-#include "utils/memutils.h"
+#include "jit/jit.h"
+#include "utils/expandeddatum.h"
static TupleTableSlot *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
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);
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++;
}
* access method functions.
* ----------------------------------------------------------------
*/
-TupleTableSlot *
-ExecValuesScan(ValuesScanState *node)
+static TupleTableSlot *
+ExecValuesScan(PlanState *pstate)
{
+ ValuesScanState *node = castNode(ValuesScanState, pstate);
+
return ExecScan(&node->ss,
(ExecScanAccessMtd) ValuesNext,
(ExecScanRecheckMtd) ValuesRecheck);
scanstate = makeNode(ValuesScanState);
scanstate->ss.ps.plan = (Plan *) node;
scanstate->ss.ps.state = estate;
+ scanstate->ss.ps.ExecProcNode = ExecValuesScan;
/*
* Miscellaneous initialization
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.
*/
ExecAssignExprContext(estate, planstate);
/*
- * 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);
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;
}
/*
* 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;
-}
-
/* ----------------------------------------------------------------
* ExecReScanValuesScan
*
void
ExecReScanValuesScan(ValuesScanState *node)
{
- ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
+ if (node->ss.ps.ps_ResultTupleSlot)
+ ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
ExecScanReScan(&node->ss);