PostgreSQL Source Code  git master
nodeModifyTable.h File Reference
#include "nodes/execnodes.h"
Include dependency graph for nodeModifyTable.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Functions

void ExecComputeStoredGenerated (EState *estate, TupleTableSlot *slot, CmdType cmdtype)
 
ModifyTableStateExecInitModifyTable (ModifyTable *node, EState *estate, int eflags)
 
void ExecEndModifyTable (ModifyTableState *node)
 
void ExecReScanModifyTable (ModifyTableState *node)
 

Function Documentation

◆ ExecComputeStoredGenerated()

void ExecComputeStoredGenerated ( EState estate,
TupleTableSlot slot,
CmdType  cmdtype 
)

Definition at line 249 of file nodeModifyTable.c.

References Assert, bms_is_member(), build_column_default(), CMD_UPDATE, TupleDescData::constr, datumCopy(), ExprContext::ecxt_scantuple, elog, ERROR, EState::es_query_cxt, EState::es_result_relation_info, exec_rt_fetch(), ExecClearTuple(), ExecEvalExpr(), ExecMaterializeSlot(), ExecPrepareExpr(), ExecStoreVirtualTuple(), RangeTblEntry::extraUpdatedCols, FirstLowInvalidHeapAttributeNumber, GetPerTupleExprContext, GetPerTupleMemoryContext, TupleConstr::has_generated_stored, i, MemoryContextSwitchTo(), TupleDescData::natts, palloc(), RelationGetDescr, RelationGetRelationName, ResultRelInfo::ri_GeneratedExprs, ResultRelInfo::ri_NumGeneratedNeeded, ResultRelInfo::ri_RangeTableIndex, ResultRelInfo::ri_RelationDesc, slot_getallattrs(), TriggerDesc::trig_update_before_row, RelationData::trigdesc, TupleTableSlot::tts_isnull, TupleTableSlot::tts_values, TupleDescAttr, val, and values.

Referenced by CopyFrom(), ExecInsert(), ExecSimpleRelationInsert(), ExecSimpleRelationUpdate(), and ExecUpdate().

250 {
251  ResultRelInfo *resultRelInfo = estate->es_result_relation_info;
252  Relation rel = resultRelInfo->ri_RelationDesc;
253  TupleDesc tupdesc = RelationGetDescr(rel);
254  int natts = tupdesc->natts;
255  MemoryContext oldContext;
256  Datum *values;
257  bool *nulls;
258 
259  Assert(tupdesc->constr && tupdesc->constr->has_generated_stored);
260 
261  /*
262  * If first time through for this result relation, build expression
263  * nodetrees for rel's stored generation expressions. Keep them in the
264  * per-query memory context so they'll survive throughout the query.
265  */
266  if (resultRelInfo->ri_GeneratedExprs == NULL)
267  {
268  oldContext = MemoryContextSwitchTo(estate->es_query_cxt);
269 
270  resultRelInfo->ri_GeneratedExprs =
271  (ExprState **) palloc(natts * sizeof(ExprState *));
272  resultRelInfo->ri_NumGeneratedNeeded = 0;
273 
274  for (int i = 0; i < natts; i++)
275  {
276  if (TupleDescAttr(tupdesc, i)->attgenerated == ATTRIBUTE_GENERATED_STORED)
277  {
278  Expr *expr;
279 
280  /*
281  * If it's an update and the current column was not marked as
282  * being updated, then we can skip the computation. But if
283  * there is a BEFORE ROW UPDATE trigger, we cannot skip
284  * because the trigger might affect additional columns.
285  */
286  if (cmdtype == CMD_UPDATE &&
287  !(rel->trigdesc && rel->trigdesc->trig_update_before_row) &&
289  exec_rt_fetch(resultRelInfo->ri_RangeTableIndex, estate)->extraUpdatedCols))
290  {
291  resultRelInfo->ri_GeneratedExprs[i] = NULL;
292  continue;
293  }
294 
295  expr = (Expr *) build_column_default(rel, i + 1);
296  if (expr == NULL)
297  elog(ERROR, "no generation expression found for column number %d of table \"%s\"",
298  i + 1, RelationGetRelationName(rel));
299 
300  resultRelInfo->ri_GeneratedExprs[i] = ExecPrepareExpr(expr, estate);
301  resultRelInfo->ri_NumGeneratedNeeded++;
302  }
303  }
304 
305  MemoryContextSwitchTo(oldContext);
306  }
307 
308  /*
309  * If no generated columns have been affected by this change, then skip
310  * the rest.
311  */
312  if (resultRelInfo->ri_NumGeneratedNeeded == 0)
313  return;
314 
315  oldContext = MemoryContextSwitchTo(GetPerTupleMemoryContext(estate));
316 
317  values = palloc(sizeof(*values) * natts);
318  nulls = palloc(sizeof(*nulls) * natts);
319 
320  slot_getallattrs(slot);
321  memcpy(nulls, slot->tts_isnull, sizeof(*nulls) * natts);
322 
323  for (int i = 0; i < natts; i++)
324  {
325  Form_pg_attribute attr = TupleDescAttr(tupdesc, i);
326 
327  if (attr->attgenerated == ATTRIBUTE_GENERATED_STORED &&
328  resultRelInfo->ri_GeneratedExprs[i])
329  {
330  ExprContext *econtext;
331  Datum val;
332  bool isnull;
333 
334  econtext = GetPerTupleExprContext(estate);
335  econtext->ecxt_scantuple = slot;
336 
337  val = ExecEvalExpr(resultRelInfo->ri_GeneratedExprs[i], econtext, &isnull);
338 
339  /*
340  * We must make a copy of val as we have no guarantees about where
341  * memory for a pass-by-reference Datum is located.
342  */
343  if (!isnull)
344  val = datumCopy(val, attr->attbyval, attr->attlen);
345 
346  values[i] = val;
347  nulls[i] = isnull;
348  }
349  else
350  {
351  if (!nulls[i])
352  values[i] = datumCopy(slot->tts_values[i], attr->attbyval, attr->attlen);
353  }
354  }
355 
356  ExecClearTuple(slot);
357  memcpy(slot->tts_values, values, sizeof(*values) * natts);
358  memcpy(slot->tts_isnull, nulls, sizeof(*nulls) * natts);
359  ExecStoreVirtualTuple(slot);
360  ExecMaterializeSlot(slot);
361 
362  MemoryContextSwitchTo(oldContext);
363 }
Relation ri_RelationDesc
Definition: execnodes.h:413
static TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition: tuptable.h:425
#define RelationGetDescr(relation)
Definition: rel.h:482
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
Datum * tts_values
Definition: tuptable.h:126
#define FirstLowInvalidHeapAttributeNumber
Definition: sysattr.h:27
ExprState * ExecPrepareExpr(Expr *node, EState *estate)
Definition: execExpr.c:492
Index ri_RangeTableIndex
Definition: execnodes.h:410
#define GetPerTupleExprContext(estate)
Definition: executor.h:507
bool has_generated_stored
Definition: tupdesc.h:45
Bitmapset * extraUpdatedCols
Definition: parsenodes.h:1124
MemoryContext es_query_cxt
Definition: execnodes.h:555
#define ERROR
Definition: elog.h:43
TriggerDesc * trigdesc
Definition: rel.h:115
static void slot_getallattrs(TupleTableSlot *slot)
Definition: tuptable.h:354
bool * tts_isnull
Definition: tuptable.h:128
static Datum ExecEvalExpr(ExprState *state, ExprContext *econtext, bool *isNull)
Definition: executor.h:290
TupleConstr * constr
Definition: tupdesc.h:85
ExprState ** ri_GeneratedExprs
Definition: execnodes.h:460
bool trig_update_before_row
Definition: reltrigger.h:61
#define RelationGetRelationName(relation)
Definition: rel.h:490
static RangeTblEntry * exec_rt_fetch(Index rti, EState *estate)
Definition: executor.h:543
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:193
Datum datumCopy(Datum value, bool typByVal, int typLen)
Definition: datum.c:131
int ri_NumGeneratedNeeded
Definition: execnodes.h:463
Node * build_column_default(Relation rel, int attrno)
uintptr_t Datum
Definition: postgres.h:367
static void ExecMaterializeSlot(TupleTableSlot *slot)
Definition: tuptable.h:443
#define Assert(condition)
Definition: c.h:745
TupleTableSlot * ecxt_scantuple
Definition: execnodes.h:226
#define GetPerTupleMemoryContext(estate)
Definition: executor.h:512
static Datum values[MAXATTR]
Definition: bootstrap.c:167
void * palloc(Size size)
Definition: mcxt.c:949
#define elog(elevel,...)
Definition: elog.h:214
int i
bool bms_is_member(int x, const Bitmapset *a)
Definition: bitmapset.c:427
long val
Definition: informix.c:664
TupleTableSlot * ExecStoreVirtualTuple(TupleTableSlot *slot)
Definition: execTuples.c:1522
ResultRelInfo * es_result_relation_info
Definition: execnodes.h:527

◆ ExecEndModifyTable()

void ExecEndModifyTable ( ModifyTableState node)

Definition at line 2761 of file nodeModifyTable.c.

References FdwRoutine::EndForeignModify, EvalPlanQualEnd(), ExecCleanupTupleRouting(), ExecClearTuple(), ExecDropSingleTupleTableSlot(), ExecEndNode(), ExecFreeExprContext(), i, ModifyTableState::mt_epqstate, ModifyTableState::mt_nplans, ModifyTableState::mt_partition_tuple_routing, ModifyTableState::mt_plans, ModifyTableState::mt_root_tuple_slot, ModifyTableState::ps, PlanState::ps_ResultTupleSlot, ModifyTableState::resultRelInfo, ResultRelInfo::ri_FdwRoutine, ResultRelInfo::ri_usesFdwDirectModify, and PlanState::state.

Referenced by ExecEndNode().

2762 {
2763  int i;
2764 
2765  /*
2766  * Allow any FDWs to shut down
2767  */
2768  for (i = 0; i < node->mt_nplans; i++)
2769  {
2770  ResultRelInfo *resultRelInfo = node->resultRelInfo + i;
2771 
2772  if (!resultRelInfo->ri_usesFdwDirectModify &&
2773  resultRelInfo->ri_FdwRoutine != NULL &&
2774  resultRelInfo->ri_FdwRoutine->EndForeignModify != NULL)
2775  resultRelInfo->ri_FdwRoutine->EndForeignModify(node->ps.state,
2776  resultRelInfo);
2777  }
2778 
2779  /*
2780  * Close all the partitioned tables, leaf partitions, and their indices
2781  * and release the slot used for tuple routing, if set.
2782  */
2783  if (node->mt_partition_tuple_routing)
2784  {
2786 
2787  if (node->mt_root_tuple_slot)
2789  }
2790 
2791  /*
2792  * Free the exprcontext
2793  */
2794  ExecFreeExprContext(&node->ps);
2795 
2796  /*
2797  * clean out the tuple table
2798  */
2799  if (node->ps.ps_ResultTupleSlot)
2801 
2802  /*
2803  * Terminate EPQ execution if active
2804  */
2805  EvalPlanQualEnd(&node->mt_epqstate);
2806 
2807  /*
2808  * shut down subplans
2809  */
2810  for (i = 0; i < node->mt_nplans; i++)
2811  ExecEndNode(node->mt_plans[i]);
2812 }
static TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition: tuptable.h:425
struct PartitionTupleRouting * mt_partition_tuple_routing
Definition: execnodes.h:1188
void ExecEndNode(PlanState *node)
Definition: execProcnode.c:543
ResultRelInfo * resultRelInfo
Definition: execnodes.h:1174
EState * state
Definition: execnodes.h:947
void ExecFreeExprContext(PlanState *planstate)
Definition: execUtils.c:655
void EvalPlanQualEnd(EPQState *epqstate)
Definition: execMain.c:2932
TupleTableSlot * ps_ResultTupleSlot
Definition: execnodes.h:983
PlanState ps
Definition: execnodes.h:1165
void ExecCleanupTupleRouting(ModifyTableState *mtstate, PartitionTupleRouting *proute)
bool ri_usesFdwDirectModify
Definition: execnodes.h:448
void ExecDropSingleTupleTableSlot(TupleTableSlot *slot)
Definition: execTuples.c:1224
EPQState mt_epqstate
Definition: execnodes.h:1178
struct FdwRoutine * ri_FdwRoutine
Definition: execnodes.h:442
EndForeignModify_function EndForeignModify
Definition: fdwapi.h:214
PlanState ** mt_plans
Definition: execnodes.h:1169
TupleTableSlot * mt_root_tuple_slot
Definition: execnodes.h:1185
int i

◆ ExecInitModifyTable()

ModifyTableState* ExecInitModifyTable ( ModifyTable node,
EState estate,
int  eflags 
)

Definition at line 2296 of file nodeModifyTable.c.

References ModifyTable::arbiterIndexes, Assert, AttributeNumberIsValid, FdwRoutine::BeginForeignModify, bms_is_member(), ModifyTable::canSetTag, ModifyTableState::canSetTag, CheckValidResultRel(), CMD_DELETE, CMD_INSERT, CMD_UPDATE, elog, ModifyTable::epqParam, ERROR, EState::es_auxmodifytables, EState::es_result_relation_info, EState::es_result_relations, EState::es_root_result_relations, EState::es_tupleTable, EvalPlanQualInit(), EvalPlanQualSetPlan(), EXEC_FLAG_BACKWARD, EXEC_FLAG_EXPLAIN_ONLY, EXEC_FLAG_MARK, ExecAssignExprContext(), ExecBuildAuxRowMark(), ExecBuildProjectionInfo(), ExecCheckPlanOutput(), ExecFindJunkAttribute(), ExecFindRowMark(), ExecGetResultType(), ExecInitExtraTupleSlot(), ExecInitJunkFilter(), ExecInitNode(), ExecInitQual(), ExecInitResultTupleSlotTL(), ExecInitResultTypeTL(), ExecModifyTable(), ExecOpenIndices(), PlanState::ExecProcNode, ExecSetupChildParentMapForSubplan(), ExecSetupPartitionTupleRouting(), ExecSetupTransitionCaptureState(), ExecTypeFromTL(), ModifyTable::fdwDirectModifyPlans, ModifyTable::fdwPrivLists, ModifyTableState::fireBSTriggers, getTargetResultRelInfo(), i, PlanRowMark::isParent, JunkFilter::jf_junkAttNo, lappend(), lcons(), lfirst, lfirst_node, linitial, list_length(), list_nth(), makeNode, ModifyTableState::mt_arowmarks, ModifyTableState::mt_done, ModifyTableState::mt_epqstate, ModifyTableState::mt_nplans, ModifyTableState::mt_partition_tuple_routing, ModifyTableState::mt_plans, ModifyTableState::mt_root_tuple_slot, ModifyTableState::mt_scans, ModifyTableState::mt_whichplan, NIL, OnConflictSetState::oc_Existing, OnConflictSetState::oc_ProjInfo, OnConflictSetState::oc_ProjSlot, OnConflictSetState::oc_WhereClause, ONCONFLICT_NONE, ONCONFLICT_UPDATE, ModifyTable::onConflictAction, ModifyTable::onConflictSet, ModifyTable::onConflictWhere, ModifyTable::operation, ModifyTableState::operation, palloc0(), ModifyTable::partColsUpdated, PlanState::plan, ModifyTable::plans, ModifyTableState::ps, PlanState::ps_ExprContext, PlanState::ps_ResultTupleSlot, WithCheckOption::qual, RelationData::rd_att, RelationData::rd_rel, TargetEntry::resjunk, ModifyTable::resultRelIndex, ModifyTableState::resultRelInfo, ModifyTable::returningLists, ResultRelInfo::ri_FdwRoutine, ResultRelInfo::ri_IndexRelationDescs, ResultRelInfo::ri_junkFilter, ResultRelInfo::ri_onConflict, ResultRelInfo::ri_onConflictArbiterIndexes, ResultRelInfo::ri_projectReturning, ResultRelInfo::ri_RelationDesc, ResultRelInfo::ri_returningList, ResultRelInfo::ri_TrigDesc, ResultRelInfo::ri_usesFdwDirectModify, ResultRelInfo::ri_WithCheckOptionExprs, ResultRelInfo::ri_WithCheckOptions, ModifyTable::rootResultRelIndex, ModifyTableState::rootResultRelInfo, ModifyTable::rowMarks, PlanRowMark::rti, PlanState::state, table_slot_callbacks(), table_slot_create(), Plan::targetlist, TriggerDesc::trig_update_before_row, TTSOpsVirtual, and ModifyTable::withCheckOptionLists.

Referenced by ExecInitNode().

2297 {
2298  ModifyTableState *mtstate;
2299  CmdType operation = node->operation;
2300  int nplans = list_length(node->plans);
2301  ResultRelInfo *saved_resultRelInfo;
2302  ResultRelInfo *resultRelInfo;
2303  Plan *subplan;
2304  ListCell *l;
2305  int i;
2306  Relation rel;
2307  bool update_tuple_routing_needed = node->partColsUpdated;
2308 
2309  /* check for unsupported flags */
2310  Assert(!(eflags & (EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK)));
2311 
2312  /*
2313  * create state structure
2314  */
2315  mtstate = makeNode(ModifyTableState);
2316  mtstate->ps.plan = (Plan *) node;
2317  mtstate->ps.state = estate;
2318  mtstate->ps.ExecProcNode = ExecModifyTable;
2319 
2320  mtstate->operation = operation;
2321  mtstate->canSetTag = node->canSetTag;
2322  mtstate->mt_done = false;
2323 
2324  mtstate->mt_plans = (PlanState **) palloc0(sizeof(PlanState *) * nplans);
2325  mtstate->resultRelInfo = estate->es_result_relations + node->resultRelIndex;
2326  mtstate->mt_scans = (TupleTableSlot **) palloc0(sizeof(TupleTableSlot *) * nplans);
2327 
2328  /* If modifying a partitioned table, initialize the root table info */
2329  if (node->rootResultRelIndex >= 0)
2330  mtstate->rootResultRelInfo = estate->es_root_result_relations +
2331  node->rootResultRelIndex;
2332 
2333  mtstate->mt_arowmarks = (List **) palloc0(sizeof(List *) * nplans);
2334  mtstate->mt_nplans = nplans;
2335 
2336  /* set up epqstate with dummy subplan data for the moment */
2337  EvalPlanQualInit(&mtstate->mt_epqstate, estate, NULL, NIL, node->epqParam);
2338  mtstate->fireBSTriggers = true;
2339 
2340  /*
2341  * call ExecInitNode on each of the plans to be executed and save the
2342  * results into the array "mt_plans". This is also a convenient place to
2343  * verify that the proposed target relations are valid and open their
2344  * indexes for insertion of new index entries. Note we *must* set
2345  * estate->es_result_relation_info correctly while we initialize each
2346  * sub-plan; external modules such as FDWs may depend on that (see
2347  * contrib/postgres_fdw/postgres_fdw.c: postgresBeginDirectModify() as one
2348  * example).
2349  */
2350  saved_resultRelInfo = estate->es_result_relation_info;
2351 
2352  resultRelInfo = mtstate->resultRelInfo;
2353  i = 0;
2354  foreach(l, node->plans)
2355  {
2356  subplan = (Plan *) lfirst(l);
2357 
2358  /* Initialize the usesFdwDirectModify flag */
2359  resultRelInfo->ri_usesFdwDirectModify = bms_is_member(i,
2360  node->fdwDirectModifyPlans);
2361 
2362  /*
2363  * Verify result relation is a valid target for the current operation
2364  */
2365  CheckValidResultRel(resultRelInfo, operation);
2366 
2367  /*
2368  * If there are indices on the result relation, open them and save
2369  * descriptors in the result relation info, so that we can add new
2370  * index entries for the tuples we add/update. We need not do this
2371  * for a DELETE, however, since deletion doesn't affect indexes. Also,
2372  * inside an EvalPlanQual operation, the indexes might be open
2373  * already, since we share the resultrel state with the original
2374  * query.
2375  */
2376  if (resultRelInfo->ri_RelationDesc->rd_rel->relhasindex &&
2377  operation != CMD_DELETE &&
2378  resultRelInfo->ri_IndexRelationDescs == NULL)
2379  ExecOpenIndices(resultRelInfo,
2381 
2382  /*
2383  * If this is an UPDATE and a BEFORE UPDATE trigger is present, the
2384  * trigger itself might modify the partition-key values. So arrange
2385  * for tuple routing.
2386  */
2387  if (resultRelInfo->ri_TrigDesc &&
2388  resultRelInfo->ri_TrigDesc->trig_update_before_row &&
2389  operation == CMD_UPDATE)
2390  update_tuple_routing_needed = true;
2391 
2392  /* Now init the plan for this result rel */
2393  estate->es_result_relation_info = resultRelInfo;
2394  mtstate->mt_plans[i] = ExecInitNode(subplan, estate, eflags);
2395  mtstate->mt_scans[i] =
2396  ExecInitExtraTupleSlot(mtstate->ps.state, ExecGetResultType(mtstate->mt_plans[i]),
2397  table_slot_callbacks(resultRelInfo->ri_RelationDesc));
2398 
2399  /* Also let FDWs init themselves for foreign-table result rels */
2400  if (!resultRelInfo->ri_usesFdwDirectModify &&
2401  resultRelInfo->ri_FdwRoutine != NULL &&
2402  resultRelInfo->ri_FdwRoutine->BeginForeignModify != NULL)
2403  {
2404  List *fdw_private = (List *) list_nth(node->fdwPrivLists, i);
2405 
2406  resultRelInfo->ri_FdwRoutine->BeginForeignModify(mtstate,
2407  resultRelInfo,
2408  fdw_private,
2409  i,
2410  eflags);
2411  }
2412 
2413  resultRelInfo++;
2414  i++;
2415  }
2416 
2417  estate->es_result_relation_info = saved_resultRelInfo;
2418 
2419  /* Get the target relation */
2420  rel = (getTargetResultRelInfo(mtstate))->ri_RelationDesc;
2421 
2422  /*
2423  * If it's not a partitioned table after all, UPDATE tuple routing should
2424  * not be attempted.
2425  */
2426  if (rel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
2427  update_tuple_routing_needed = false;
2428 
2429  /*
2430  * Build state for tuple routing if it's an INSERT or if it's an UPDATE of
2431  * partition key.
2432  */
2433  if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE &&
2434  (operation == CMD_INSERT || update_tuple_routing_needed))
2435  mtstate->mt_partition_tuple_routing =
2436  ExecSetupPartitionTupleRouting(estate, mtstate, rel);
2437 
2438  /*
2439  * Build state for collecting transition tuples. This requires having a
2440  * valid trigger query context, so skip it in explain-only mode.
2441  */
2442  if (!(eflags & EXEC_FLAG_EXPLAIN_ONLY))
2443  ExecSetupTransitionCaptureState(mtstate, estate);
2444 
2445  /*
2446  * Construct mapping from each of the per-subplan partition attnos to the
2447  * root attno. This is required when during update row movement the tuple
2448  * descriptor of a source partition does not match the root partitioned
2449  * table descriptor. In such a case we need to convert tuples to the root
2450  * tuple descriptor, because the search for destination partition starts
2451  * from the root. We'll also need a slot to store these converted tuples.
2452  * We can skip this setup if it's not a partition key update.
2453  */
2454  if (update_tuple_routing_needed)
2455  {
2457  mtstate->mt_root_tuple_slot = table_slot_create(rel, NULL);
2458  }
2459 
2460  /*
2461  * Initialize any WITH CHECK OPTION constraints if needed.
2462  */
2463  resultRelInfo = mtstate->resultRelInfo;
2464  i = 0;
2465  foreach(l, node->withCheckOptionLists)
2466  {
2467  List *wcoList = (List *) lfirst(l);
2468  List *wcoExprs = NIL;
2469  ListCell *ll;
2470 
2471  foreach(ll, wcoList)
2472  {
2473  WithCheckOption *wco = (WithCheckOption *) lfirst(ll);
2474  ExprState *wcoExpr = ExecInitQual((List *) wco->qual,
2475  &mtstate->ps);
2476 
2477  wcoExprs = lappend(wcoExprs, wcoExpr);
2478  }
2479 
2480  resultRelInfo->ri_WithCheckOptions = wcoList;
2481  resultRelInfo->ri_WithCheckOptionExprs = wcoExprs;
2482  resultRelInfo++;
2483  i++;
2484  }
2485 
2486  /*
2487  * Initialize RETURNING projections if needed.
2488  */
2489  if (node->returningLists)
2490  {
2491  TupleTableSlot *slot;
2492  ExprContext *econtext;
2493 
2494  /*
2495  * Initialize result tuple slot and assign its rowtype using the first
2496  * RETURNING list. We assume the rest will look the same.
2497  */
2498  mtstate->ps.plan->targetlist = (List *) linitial(node->returningLists);
2499 
2500  /* Set up a slot for the output of the RETURNING projection(s) */
2502  slot = mtstate->ps.ps_ResultTupleSlot;
2503 
2504  /* Need an econtext too */
2505  if (mtstate->ps.ps_ExprContext == NULL)
2506  ExecAssignExprContext(estate, &mtstate->ps);
2507  econtext = mtstate->ps.ps_ExprContext;
2508 
2509  /*
2510  * Build a projection for each result rel.
2511  */
2512  resultRelInfo = mtstate->resultRelInfo;
2513  foreach(l, node->returningLists)
2514  {
2515  List *rlist = (List *) lfirst(l);
2516 
2517  resultRelInfo->ri_returningList = rlist;
2518  resultRelInfo->ri_projectReturning =
2519  ExecBuildProjectionInfo(rlist, econtext, slot, &mtstate->ps,
2520  resultRelInfo->ri_RelationDesc->rd_att);
2521  resultRelInfo++;
2522  }
2523  }
2524  else
2525  {
2526  /*
2527  * We still must construct a dummy result tuple type, because InitPlan
2528  * expects one (maybe should change that?).
2529  */
2530  mtstate->ps.plan->targetlist = NIL;
2531  ExecInitResultTypeTL(&mtstate->ps);
2532 
2533  mtstate->ps.ps_ExprContext = NULL;
2534  }
2535 
2536  /* Set the list of arbiter indexes if needed for ON CONFLICT */
2537  resultRelInfo = mtstate->resultRelInfo;
2538  if (node->onConflictAction != ONCONFLICT_NONE)
2539  resultRelInfo->ri_onConflictArbiterIndexes = node->arbiterIndexes;
2540 
2541  /*
2542  * If needed, Initialize target list, projection and qual for ON CONFLICT
2543  * DO UPDATE.
2544  */
2545  if (node->onConflictAction == ONCONFLICT_UPDATE)
2546  {
2547  ExprContext *econtext;
2548  TupleDesc relationDesc;
2549  TupleDesc tupDesc;
2550 
2551  /* insert may only have one plan, inheritance is not expanded */
2552  Assert(nplans == 1);
2553 
2554  /* already exists if created by RETURNING processing above */
2555  if (mtstate->ps.ps_ExprContext == NULL)
2556  ExecAssignExprContext(estate, &mtstate->ps);
2557 
2558  econtext = mtstate->ps.ps_ExprContext;
2559  relationDesc = resultRelInfo->ri_RelationDesc->rd_att;
2560 
2561  /* create state for DO UPDATE SET operation */
2562  resultRelInfo->ri_onConflict = makeNode(OnConflictSetState);
2563 
2564  /* initialize slot for the existing tuple */
2565  resultRelInfo->ri_onConflict->oc_Existing =
2566  table_slot_create(resultRelInfo->ri_RelationDesc,
2567  &mtstate->ps.state->es_tupleTable);
2568 
2569  /*
2570  * Create the tuple slot for the UPDATE SET projection. We want a slot
2571  * of the table's type here, because the slot will be used to insert
2572  * into the table, and for RETURNING processing - which may access
2573  * system attributes.
2574  */
2575  tupDesc = ExecTypeFromTL((List *) node->onConflictSet);
2576  resultRelInfo->ri_onConflict->oc_ProjSlot =
2577  ExecInitExtraTupleSlot(mtstate->ps.state, tupDesc,
2578  table_slot_callbacks(resultRelInfo->ri_RelationDesc));
2579 
2580  /* build UPDATE SET projection state */
2581  resultRelInfo->ri_onConflict->oc_ProjInfo =
2582  ExecBuildProjectionInfo(node->onConflictSet, econtext,
2583  resultRelInfo->ri_onConflict->oc_ProjSlot,
2584  &mtstate->ps,
2585  relationDesc);
2586 
2587  /* initialize state to evaluate the WHERE clause, if any */
2588  if (node->onConflictWhere)
2589  {
2590  ExprState *qualexpr;
2591 
2592  qualexpr = ExecInitQual((List *) node->onConflictWhere,
2593  &mtstate->ps);
2594  resultRelInfo->ri_onConflict->oc_WhereClause = qualexpr;
2595  }
2596  }
2597 
2598  /*
2599  * If we have any secondary relations in an UPDATE or DELETE, they need to
2600  * be treated like non-locked relations in SELECT FOR UPDATE, ie, the
2601  * EvalPlanQual mechanism needs to be told about them. Locate the
2602  * relevant ExecRowMarks.
2603  */
2604  foreach(l, node->rowMarks)
2605  {
2607  ExecRowMark *erm;
2608 
2609  /* ignore "parent" rowmarks; they are irrelevant at runtime */
2610  if (rc->isParent)
2611  continue;
2612 
2613  /* find ExecRowMark (same for all subplans) */
2614  erm = ExecFindRowMark(estate, rc->rti, false);
2615 
2616  /* build ExecAuxRowMark for each subplan */
2617  for (i = 0; i < nplans; i++)
2618  {
2619  ExecAuxRowMark *aerm;
2620 
2621  subplan = mtstate->mt_plans[i]->plan;
2622  aerm = ExecBuildAuxRowMark(erm, subplan->targetlist);
2623  mtstate->mt_arowmarks[i] = lappend(mtstate->mt_arowmarks[i], aerm);
2624  }
2625  }
2626 
2627  /* select first subplan */
2628  mtstate->mt_whichplan = 0;
2629  subplan = (Plan *) linitial(node->plans);
2630  EvalPlanQualSetPlan(&mtstate->mt_epqstate, subplan,
2631  mtstate->mt_arowmarks[0]);
2632 
2633  /*
2634  * Initialize the junk filter(s) if needed. INSERT queries need a filter
2635  * if there are any junk attrs in the tlist. UPDATE and DELETE always
2636  * need a filter, since there's always at least one junk attribute present
2637  * --- no need to look first. Typically, this will be a 'ctid' or
2638  * 'wholerow' attribute, but in the case of a foreign data wrapper it
2639  * might be a set of junk attributes sufficient to identify the remote
2640  * row.
2641  *
2642  * If there are multiple result relations, each one needs its own junk
2643  * filter. Note multiple rels are only possible for UPDATE/DELETE, so we
2644  * can't be fooled by some needing a filter and some not.
2645  *
2646  * This section of code is also a convenient place to verify that the
2647  * output of an INSERT or UPDATE matches the target table(s).
2648  */
2649  {
2650  bool junk_filter_needed = false;
2651 
2652  switch (operation)
2653  {
2654  case CMD_INSERT:
2655  foreach(l, subplan->targetlist)
2656  {
2657  TargetEntry *tle = (TargetEntry *) lfirst(l);
2658 
2659  if (tle->resjunk)
2660  {
2661  junk_filter_needed = true;
2662  break;
2663  }
2664  }
2665  break;
2666  case CMD_UPDATE:
2667  case CMD_DELETE:
2668  junk_filter_needed = true;
2669  break;
2670  default:
2671  elog(ERROR, "unknown operation");
2672  break;
2673  }
2674 
2675  if (junk_filter_needed)
2676  {
2677  resultRelInfo = mtstate->resultRelInfo;
2678  for (i = 0; i < nplans; i++)
2679  {
2680  JunkFilter *j;
2681  TupleTableSlot *junkresslot;
2682 
2683  subplan = mtstate->mt_plans[i]->plan;
2684  if (operation == CMD_INSERT || operation == CMD_UPDATE)
2685  ExecCheckPlanOutput(resultRelInfo->ri_RelationDesc,
2686  subplan->targetlist);
2687 
2688  junkresslot =
2689  ExecInitExtraTupleSlot(estate, NULL,
2690  table_slot_callbacks(resultRelInfo->ri_RelationDesc));
2691  j = ExecInitJunkFilter(subplan->targetlist,
2692  junkresslot);
2693 
2694  if (operation == CMD_UPDATE || operation == CMD_DELETE)
2695  {
2696  /* For UPDATE/DELETE, find the appropriate junk attr now */
2697  char relkind;
2698 
2699  relkind = resultRelInfo->ri_RelationDesc->rd_rel->relkind;
2700  if (relkind == RELKIND_RELATION ||
2701  relkind == RELKIND_MATVIEW ||
2702  relkind == RELKIND_PARTITIONED_TABLE)
2703  {
2704  j->jf_junkAttNo = ExecFindJunkAttribute(j, "ctid");
2706  elog(ERROR, "could not find junk ctid column");
2707  }
2708  else if (relkind == RELKIND_FOREIGN_TABLE)
2709  {
2710  /*
2711  * When there is a row-level trigger, there should be
2712  * a wholerow attribute.
2713  */
2714  j->jf_junkAttNo = ExecFindJunkAttribute(j, "wholerow");
2715  }
2716  else
2717  {
2718  j->jf_junkAttNo = ExecFindJunkAttribute(j, "wholerow");
2720  elog(ERROR, "could not find junk wholerow column");
2721  }
2722  }
2723 
2724  resultRelInfo->ri_junkFilter = j;
2725  resultRelInfo++;
2726  }
2727  }
2728  else
2729  {
2730  if (operation == CMD_INSERT)
2732  subplan->targetlist);
2733  }
2734  }
2735 
2736  /*
2737  * Lastly, if this is not the primary (canSetTag) ModifyTable node, add it
2738  * to estate->es_auxmodifytables so that it will be run to completion by
2739  * ExecPostprocessPlan. (It'd actually work fine to add the primary
2740  * ModifyTable node too, but there's no need.) Note the use of lcons not
2741  * lappend: we need later-initialized ModifyTable nodes to be shut down
2742  * before earlier ones. This ensures that we don't throw away RETURNING
2743  * rows that need to be seen by a later CTE subplan.
2744  */
2745  if (!mtstate->canSetTag)
2746  estate->es_auxmodifytables = lcons(mtstate,
2747  estate->es_auxmodifytables);
2748 
2749  return mtstate;
2750 }
TupleTableSlot * table_slot_create(Relation relation, List **reglist)
Definition: tableam.c:91
AttrNumber jf_junkAttNo
Definition: execnodes.h:373
#define NIL
Definition: pg_list.h:65
JunkFilter * ri_junkFilter
Definition: execnodes.h:466
List * arbiterIndexes
Definition: plannodes.h:237
Relation ri_RelationDesc
Definition: execnodes.h:413
Bitmapset * fdwDirectModifyPlans
Definition: plannodes.h:233
TupleTableSlot * ExecInitExtraTupleSlot(EState *estate, TupleDesc tupledesc, const TupleTableSlotOps *tts_ops)
Definition: execTuples.c:1801
static ResultRelInfo * getTargetResultRelInfo(ModifyTableState *node)
struct PartitionTupleRouting * mt_partition_tuple_routing
Definition: execnodes.h:1188
List * withCheckOptionLists
Definition: plannodes.h:230
int resultRelIndex
Definition: plannodes.h:227
ResultRelInfo * resultRelInfo
Definition: execnodes.h:1174
AttrNumber ExecFindJunkAttribute(JunkFilter *junkfilter, const char *attrName)
Definition: execJunk.c:208
ExprContext * ps_ExprContext
Definition: execnodes.h:984
TupleTableSlot ** mt_scans
Definition: execnodes.h:1172
const TupleTableSlotOps * table_slot_callbacks(Relation relation)
Definition: tableam.c:58
const TupleTableSlotOps TTSOpsVirtual
Definition: execTuples.c:83
bool partColsUpdated
Definition: plannodes.h:225
bool canSetTag
Definition: plannodes.h:222
CmdType operation
Definition: execnodes.h:1166
ResultRelInfo * rootResultRelInfo
Definition: execnodes.h:1175
void EvalPlanQualSetPlan(EPQState *epqstate, Plan *subplan, List *auxrowmarks)
Definition: execMain.c:2524
EState * state
Definition: execnodes.h:947
Form_pg_class rd_rel
Definition: rel.h:109
List * plans
Definition: plannodes.h:229
ExprState * ExecInitQual(List *qual, PlanState *parent)
Definition: execExpr.c:209
List * onConflictSet
Definition: plannodes.h:238
int rootResultRelIndex
Definition: plannodes.h:228
void ExecOpenIndices(ResultRelInfo *resultRelInfo, bool speculative)
Definition: execIndexing.c:151
List * ri_WithCheckOptionExprs
Definition: execnodes.h:454
TupleTableSlot * oc_Existing
Definition: execnodes.h:385
TupleTableSlot * ps_ResultTupleSlot
Definition: execnodes.h:983
static void ExecSetupChildParentMapForSubplan(ModifyTableState *mtstate)
List * rowMarks
Definition: plannodes.h:234
bool resjunk
Definition: primnodes.h:1414
#define linitial(l)
Definition: pg_list.h:195
#define ERROR
Definition: elog.h:43
PlanState ps
Definition: execnodes.h:1165
ProjectionInfo * oc_ProjInfo
Definition: execnodes.h:387
static void * list_nth(const List *list, int n)
Definition: pg_list.h:277
bool ri_usesFdwDirectModify
Definition: execnodes.h:448
static void ExecSetupTransitionCaptureState(ModifyTableState *mtstate, EState *estate)
void CheckValidResultRel(ResultRelInfo *resultRelInfo, CmdType operation)
Definition: execMain.c:1076
#define EXEC_FLAG_BACKWARD
Definition: executor.h:58
#define lfirst_node(type, lc)
Definition: pg_list.h:193
ResultRelInfo * es_result_relations
Definition: execnodes.h:525
void ExecInitResultTypeTL(PlanState *planstate)
Definition: execTuples.c:1725
List * fdwPrivLists
Definition: plannodes.h:232
EPQState mt_epqstate
Definition: execnodes.h:1178
bool trig_update_before_row
Definition: reltrigger.h:61
ProjectionInfo * ri_projectReturning
Definition: execnodes.h:472
struct FdwRoutine * ri_FdwRoutine
Definition: execnodes.h:442
ExprState * oc_WhereClause
Definition: execnodes.h:388
PartitionTupleRouting * ExecSetupPartitionTupleRouting(EState *estate, ModifyTableState *mtstate, Relation rel)
TriggerDesc * ri_TrigDesc
Definition: execnodes.h:425
List * lappend(List *list, void *datum)
Definition: list.c:321
PlanState ** mt_plans
Definition: execnodes.h:1169
void EvalPlanQualInit(EPQState *epqstate, EState *parentestate, Plan *subplan, List *auxrowmarks, int epqParam)
Definition: execMain.c:2486
OnConflictSetState * ri_onConflict
Definition: execnodes.h:478
#define AttributeNumberIsValid(attributeNumber)
Definition: attnum.h:34
static TupleTableSlot * ExecModifyTable(PlanState *pstate)
List * es_tupleTable
Definition: execnodes.h:557
void * palloc0(Size size)
Definition: mcxt.c:980
List * es_auxmodifytables
Definition: execnodes.h:569
ExecProcNodeMtd ExecProcNode
Definition: execnodes.h:951
List * ri_WithCheckOptions
Definition: execnodes.h:451
TupleDesc rd_att
Definition: rel.h:110
Plan * plan
Definition: execnodes.h:945
TupleTableSlot * oc_ProjSlot
Definition: execnodes.h:386
List * lcons(void *datum, List *list)
Definition: list.c:453
#define makeNode(_type_)
Definition: nodes.h:577
static void ExecCheckPlanOutput(Relation resultRel, List *targetList)
#define Assert(condition)
Definition: c.h:745
#define lfirst(lc)
Definition: pg_list.h:190
#define EXEC_FLAG_MARK
Definition: executor.h:59
OnConflictAction onConflictAction
Definition: plannodes.h:236
void ExecAssignExprContext(EState *estate, PlanState *planstate)
Definition: execUtils.c:485
static int list_length(const List *l)
Definition: pg_list.h:169
TupleDesc ExecTypeFromTL(List *targetList)
Definition: execTuples.c:1908
void ExecInitResultTupleSlotTL(PlanState *planstate, const TupleTableSlotOps *tts_ops)
Definition: execTuples.c:1769
TupleTableSlot * mt_root_tuple_slot
Definition: execnodes.h:1185
TupleDesc ExecGetResultType(PlanState *planstate)
Definition: execUtils.c:495
List * targetlist
Definition: plannodes.h:142
ProjectionInfo * ExecBuildProjectionInfo(List *targetList, ExprContext *econtext, TupleTableSlot *slot, PlanState *parent, TupleDesc inputDesc)
Definition: execExpr.c:353
CmdType operation
Definition: plannodes.h:221
ResultRelInfo * es_root_result_relations
Definition: execnodes.h:535
#define elog(elevel,...)
Definition: elog.h:214
int i
List * returningLists
Definition: plannodes.h:231
bool isParent
Definition: plannodes.h:1084
BeginForeignModify_function BeginForeignModify
Definition: fdwapi.h:210
PlanState * ExecInitNode(Plan *node, EState *estate, int eflags)
Definition: execProcnode.c:139
Definition: pg_list.h:50
bool bms_is_member(int x, const Bitmapset *a)
Definition: bitmapset.c:427
#define EXEC_FLAG_EXPLAIN_ONLY
Definition: executor.h:56
JunkFilter * ExecInitJunkFilter(List *targetList, TupleTableSlot *slot)
Definition: execJunk.c:60
List * ri_onConflictArbiterIndexes
Definition: execnodes.h:475
CmdType
Definition: nodes.h:672
RelationPtr ri_IndexRelationDescs
Definition: execnodes.h:419
ExecAuxRowMark * ExecBuildAuxRowMark(ExecRowMark *erm, List *targetlist)
Definition: execMain.c:2362
List * ri_returningList
Definition: execnodes.h:469
List ** mt_arowmarks
Definition: execnodes.h:1177
int epqParam
Definition: plannodes.h:235
Node * onConflictWhere
Definition: plannodes.h:239
ExecRowMark * ExecFindRowMark(EState *estate, Index rti, bool missing_ok)
Definition: execMain.c:2339
ResultRelInfo * es_result_relation_info
Definition: execnodes.h:527

◆ ExecReScanModifyTable()

void ExecReScanModifyTable ( ModifyTableState node)

Definition at line 2815 of file nodeModifyTable.c.

References elog, and ERROR.

Referenced by ExecReScan().

2816 {
2817  /*
2818  * Currently, we don't need to support rescan on ModifyTable nodes. The
2819  * semantics of that would be a bit debatable anyway.
2820  */
2821  elog(ERROR, "ExecReScanModifyTable is not implemented");
2822 }
#define ERROR
Definition: elog.h:43
#define elog(elevel,...)
Definition: elog.h:214