aboutsummaryrefslogtreecommitdiff
path: root/src/backend/executor/execExpr.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/executor/execExpr.c')
-rw-r--r--src/backend/executor/execExpr.c112
1 files changed, 83 insertions, 29 deletions
diff --git a/src/backend/executor/execExpr.c b/src/backend/executor/execExpr.c
index 77c9d785d99..8c9f8a6aeb6 100644
--- a/src/backend/executor/execExpr.c
+++ b/src/backend/executor/execExpr.c
@@ -485,14 +485,21 @@ ExecBuildProjectionInfo(List *targetList,
* be stored into the given tuple slot. (Caller must have ensured that tuple
* slot has a descriptor matching the target rel!)
*
- * subTargetList is the tlist of the subplan node feeding ModifyTable.
- * We use this mainly to cross-check that the expressions being assigned
- * are of the correct types. The values from this tlist are assumed to be
- * available from the "outer" tuple slot. They are assigned to target columns
- * listed in the corresponding targetColnos elements. (Only non-resjunk tlist
- * entries are assigned.) Columns not listed in targetColnos are filled from
- * the UPDATE's old tuple, which is assumed to be available in the "scan"
- * tuple slot.
+ * When evalTargetList is false, targetList contains the UPDATE ... SET
+ * expressions that have already been computed by a subplan node; the values
+ * from this tlist are assumed to be available in the "outer" tuple slot.
+ * When evalTargetList is true, targetList contains the UPDATE ... SET
+ * expressions that must be computed (which could contain references to
+ * the outer, inner, or scan tuple slots).
+ *
+ * In either case, targetColnos contains a list of the target column numbers
+ * corresponding to the non-resjunk entries of targetList. The tlist values
+ * are assigned into these columns of the result tuple slot. Target columns
+ * not listed in targetColnos are filled from the UPDATE's old tuple, which
+ * is assumed to be available in the "scan" tuple slot.
+ *
+ * targetList can also contain resjunk columns. These must be evaluated
+ * if evalTargetList is true, but their values are discarded.
*
* relDesc must describe the relation we intend to update.
*
@@ -503,7 +510,8 @@ ExecBuildProjectionInfo(List *targetList,
* ExecCheckPlanOutput, so we must do our safety checks here.
*/
ProjectionInfo *
-ExecBuildUpdateProjection(List *subTargetList,
+ExecBuildUpdateProjection(List *targetList,
+ bool evalTargetList,
List *targetColnos,
TupleDesc relDesc,
ExprContext *econtext,
@@ -525,19 +533,22 @@ ExecBuildUpdateProjection(List *subTargetList,
/* We embed ExprState into ProjectionInfo instead of doing extra palloc */
projInfo->pi_state.tag = T_ExprState;
state = &projInfo->pi_state;
- state->expr = NULL; /* not used */
+ if (evalTargetList)
+ state->expr = (Expr *) targetList;
+ else
+ state->expr = NULL; /* not used */
state->parent = parent;
state->ext_params = NULL;
state->resultslot = slot;
/*
- * Examine the subplan tlist to see how many non-junk columns there are,
- * and to verify that the non-junk columns come before the junk ones.
+ * Examine the targetList to see how many non-junk columns there are, and
+ * to verify that the non-junk columns come before the junk ones.
*/
nAssignableCols = 0;
sawJunk = false;
- foreach(lc, subTargetList)
+ foreach(lc, targetList)
{
TargetEntry *tle = lfirst_node(TargetEntry, lc);
@@ -569,12 +580,10 @@ ExecBuildUpdateProjection(List *subTargetList,
}
/*
- * We want to insert EEOP_*_FETCHSOME steps to ensure the outer and scan
- * tuples are sufficiently deconstructed. Outer tuple is easy, but for
- * scan tuple we must find out the last old column we need.
+ * We need to insert EEOP_*_FETCHSOME steps to ensure the input tuples are
+ * sufficiently deconstructed. The scan tuple must be deconstructed at
+ * least as far as the last old column we need.
*/
- deform.last_outer = nAssignableCols;
-
for (int attnum = relDesc->natts; attnum > 0; attnum--)
{
Form_pg_attribute attr = TupleDescAttr(relDesc, attnum - 1);
@@ -587,15 +596,26 @@ ExecBuildUpdateProjection(List *subTargetList,
break;
}
+ /*
+ * If we're actually evaluating the tlist, incorporate its input
+ * requirements too; otherwise, we'll just need to fetch the appropriate
+ * number of columns of the "outer" tuple.
+ */
+ if (evalTargetList)
+ get_last_attnums_walker((Node *) targetList, &deform);
+ else
+ deform.last_outer = nAssignableCols;
+
ExecPushExprSlots(state, &deform);
/*
- * Now generate code to fetch data from the outer tuple, incidentally
- * validating that it'll be of the right type. The checks above ensure
- * that the forboth() will iterate over exactly the non-junk columns.
+ * Now generate code to evaluate the tlist's assignable expressions or
+ * fetch them from the outer tuple, incidentally validating that they'll
+ * be of the right data type. The checks above ensure that the forboth()
+ * will iterate over exactly the non-junk columns.
*/
outerattnum = 0;
- forboth(lc, subTargetList, lc2, targetColnos)
+ forboth(lc, targetList, lc2, targetColnos)
{
TargetEntry *tle = lfirst_node(TargetEntry, lc);
AttrNumber targetattnum = lfirst_int(lc2);
@@ -628,13 +648,47 @@ ExecBuildUpdateProjection(List *subTargetList,
targetattnum,
format_type_be(exprType((Node *) tle->expr)))));
- /*
- * OK, build an outer-tuple reference.
- */
- scratch.opcode = EEOP_ASSIGN_OUTER_VAR;
- scratch.d.assign_var.attnum = outerattnum++;
- scratch.d.assign_var.resultnum = targetattnum - 1;
- ExprEvalPushStep(state, &scratch);
+ /* OK, generate code to perform the assignment. */
+ if (evalTargetList)
+ {
+ /*
+ * We must evaluate the TLE's expression and assign it. We do not
+ * bother jumping through hoops for "safe" Vars like
+ * ExecBuildProjectionInfo does; this is a relatively less-used
+ * path and it doesn't seem worth expending code for that.
+ */
+ ExecInitExprRec(tle->expr, state,
+ &state->resvalue, &state->resnull);
+ /* Needn't worry about read-only-ness here, either. */
+ scratch.opcode = EEOP_ASSIGN_TMP;
+ scratch.d.assign_tmp.resultnum = targetattnum - 1;
+ ExprEvalPushStep(state, &scratch);
+ }
+ else
+ {
+ /* Just assign from the outer tuple. */
+ scratch.opcode = EEOP_ASSIGN_OUTER_VAR;
+ scratch.d.assign_var.attnum = outerattnum;
+ scratch.d.assign_var.resultnum = targetattnum - 1;
+ ExprEvalPushStep(state, &scratch);
+ }
+ outerattnum++;
+ }
+
+ /*
+ * If we're evaluating the tlist, must evaluate any resjunk columns too.
+ * (This matters for things like MULTIEXPR_SUBLINK SubPlans.)
+ */
+ if (evalTargetList)
+ {
+ for_each_cell(lc, targetList, lc)
+ {
+ TargetEntry *tle = lfirst_node(TargetEntry, lc);
+
+ Assert(tle->resjunk);
+ ExecInitExprRec(tle->expr, state,
+ &state->resvalue, &state->resnull);
+ }
}
/*