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 (ResultRelInfo *resultRelInfo, 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 ( ResultRelInfo resultRelInfo,
EState estate,
TupleTableSlot slot,
CmdType  cmdtype 
)

Definition at line 253 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, ExecClearTuple(), ExecEvalExpr(), ExecGetExtraUpdatedCols(), ExecMaterializeSlot(), ExecPrepareExpr(), ExecStoreVirtualTuple(), FirstLowInvalidHeapAttributeNumber, GetPerTupleExprContext, GetPerTupleMemoryContext, TupleConstr::has_generated_stored, i, MemoryContextSwitchTo(), TupleDescData::natts, palloc(), RelationGetDescr, RelationGetRelationName, ResultRelInfo::ri_GeneratedExprs, ResultRelInfo::ri_NumGeneratedNeeded, 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().

256 {
257  Relation rel = resultRelInfo->ri_RelationDesc;
258  TupleDesc tupdesc = RelationGetDescr(rel);
259  int natts = tupdesc->natts;
260  MemoryContext oldContext;
261  Datum *values;
262  bool *nulls;
263 
264  Assert(tupdesc->constr && tupdesc->constr->has_generated_stored);
265 
266  /*
267  * If first time through for this result relation, build expression
268  * nodetrees for rel's stored generation expressions. Keep them in the
269  * per-query memory context so they'll survive throughout the query.
270  */
271  if (resultRelInfo->ri_GeneratedExprs == NULL)
272  {
273  oldContext = MemoryContextSwitchTo(estate->es_query_cxt);
274 
275  resultRelInfo->ri_GeneratedExprs =
276  (ExprState **) palloc(natts * sizeof(ExprState *));
277  resultRelInfo->ri_NumGeneratedNeeded = 0;
278 
279  for (int i = 0; i < natts; i++)
280  {
281  if (TupleDescAttr(tupdesc, i)->attgenerated == ATTRIBUTE_GENERATED_STORED)
282  {
283  Expr *expr;
284 
285  /*
286  * If it's an update and the current column was not marked as
287  * being updated, then we can skip the computation. But if
288  * there is a BEFORE ROW UPDATE trigger, we cannot skip
289  * because the trigger might affect additional columns.
290  */
291  if (cmdtype == CMD_UPDATE &&
292  !(rel->trigdesc && rel->trigdesc->trig_update_before_row) &&
294  ExecGetExtraUpdatedCols(resultRelInfo, estate)))
295  {
296  resultRelInfo->ri_GeneratedExprs[i] = NULL;
297  continue;
298  }
299 
300  expr = (Expr *) build_column_default(rel, i + 1);
301  if (expr == NULL)
302  elog(ERROR, "no generation expression found for column number %d of table \"%s\"",
303  i + 1, RelationGetRelationName(rel));
304 
305  resultRelInfo->ri_GeneratedExprs[i] = ExecPrepareExpr(expr, estate);
306  resultRelInfo->ri_NumGeneratedNeeded++;
307  }
308  }
309 
310  MemoryContextSwitchTo(oldContext);
311  }
312 
313  /*
314  * If no generated columns have been affected by this change, then skip
315  * the rest.
316  */
317  if (resultRelInfo->ri_NumGeneratedNeeded == 0)
318  return;
319 
320  oldContext = MemoryContextSwitchTo(GetPerTupleMemoryContext(estate));
321 
322  values = palloc(sizeof(*values) * natts);
323  nulls = palloc(sizeof(*nulls) * natts);
324 
325  slot_getallattrs(slot);
326  memcpy(nulls, slot->tts_isnull, sizeof(*nulls) * natts);
327 
328  for (int i = 0; i < natts; i++)
329  {
330  Form_pg_attribute attr = TupleDescAttr(tupdesc, i);
331 
332  if (attr->attgenerated == ATTRIBUTE_GENERATED_STORED &&
333  resultRelInfo->ri_GeneratedExprs[i])
334  {
335  ExprContext *econtext;
336  Datum val;
337  bool isnull;
338 
339  econtext = GetPerTupleExprContext(estate);
340  econtext->ecxt_scantuple = slot;
341 
342  val = ExecEvalExpr(resultRelInfo->ri_GeneratedExprs[i], econtext, &isnull);
343 
344  /*
345  * We must make a copy of val as we have no guarantees about where
346  * memory for a pass-by-reference Datum is located.
347  */
348  if (!isnull)
349  val = datumCopy(val, attr->attbyval, attr->attlen);
350 
351  values[i] = val;
352  nulls[i] = isnull;
353  }
354  else
355  {
356  if (!nulls[i])
357  values[i] = datumCopy(slot->tts_values[i], attr->attbyval, attr->attlen);
358  }
359  }
360 
361  ExecClearTuple(slot);
362  memcpy(slot->tts_values, values, sizeof(*values) * natts);
363  memcpy(slot->tts_isnull, nulls, sizeof(*nulls) * natts);
364  ExecStoreVirtualTuple(slot);
365  ExecMaterializeSlot(slot);
366 
367  MemoryContextSwitchTo(oldContext);
368 }
Relation ri_RelationDesc
Definition: execnodes.h:415
Bitmapset * ExecGetExtraUpdatedCols(ResultRelInfo *relinfo, EState *estate)
Definition: execUtils.c:1295
static TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition: tuptable.h:425
#define RelationGetDescr(relation)
Definition: rel.h:483
#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
#define GetPerTupleExprContext(estate)
Definition: executor.h:509
bool has_generated_stored
Definition: tupdesc.h:45
MemoryContext es_query_cxt
Definition: execnodes.h:572
#define ERROR
Definition: elog.h:45
TriggerDesc * trigdesc
Definition: rel.h:116
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:292
TupleConstr * constr
Definition: tupdesc.h:85
ExprState ** ri_GeneratedExprs
Definition: execnodes.h:468
bool trig_update_before_row
Definition: reltrigger.h:61
#define RelationGetRelationName(relation)
Definition: rel.h:491
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:197
Datum datumCopy(Datum value, bool typByVal, int typLen)
Definition: datum.c:131
int ri_NumGeneratedNeeded
Definition: execnodes.h:471
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:804
TupleTableSlot * ecxt_scantuple
Definition: execnodes.h:225
#define GetPerTupleMemoryContext(estate)
Definition: executor.h:514
static Datum values[MAXATTR]
Definition: bootstrap.c:165
void * palloc(Size size)
Definition: mcxt.c:950
#define elog(elevel,...)
Definition: elog.h:227
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

◆ ExecEndModifyTable()

void ExecEndModifyTable ( ModifyTableState node)

Definition at line 2849 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().

2850 {
2851  int i;
2852 
2853  /*
2854  * Allow any FDWs to shut down
2855  */
2856  for (i = 0; i < node->mt_nplans; i++)
2857  {
2858  ResultRelInfo *resultRelInfo = node->resultRelInfo + i;
2859 
2860  if (!resultRelInfo->ri_usesFdwDirectModify &&
2861  resultRelInfo->ri_FdwRoutine != NULL &&
2862  resultRelInfo->ri_FdwRoutine->EndForeignModify != NULL)
2863  resultRelInfo->ri_FdwRoutine->EndForeignModify(node->ps.state,
2864  resultRelInfo);
2865  }
2866 
2867  /*
2868  * Close all the partitioned tables, leaf partitions, and their indices
2869  * and release the slot used for tuple routing, if set.
2870  */
2871  if (node->mt_partition_tuple_routing)
2872  {
2874 
2875  if (node->mt_root_tuple_slot)
2877  }
2878 
2879  /*
2880  * Free the exprcontext
2881  */
2882  ExecFreeExprContext(&node->ps);
2883 
2884  /*
2885  * clean out the tuple table
2886  */
2887  if (node->ps.ps_ResultTupleSlot)
2889 
2890  /*
2891  * Terminate EPQ execution if active
2892  */
2893  EvalPlanQualEnd(&node->mt_epqstate);
2894 
2895  /*
2896  * shut down subplans
2897  */
2898  for (i = 0; i < node->mt_nplans; i++)
2899  ExecEndNode(node->mt_plans[i]);
2900 }
static TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition: tuptable.h:425
struct PartitionTupleRouting * mt_partition_tuple_routing
Definition: execnodes.h:1189
void ExecEndNode(PlanState *node)
Definition: execProcnode.c:549
ResultRelInfo * resultRelInfo
Definition: execnodes.h:1170
EState * state
Definition: execnodes.h:943
void ExecFreeExprContext(PlanState *planstate)
Definition: execUtils.c:650
void EvalPlanQualEnd(EPQState *epqstate)
Definition: execMain.c:2801
TupleTableSlot * ps_ResultTupleSlot
Definition: execnodes.h:979
PlanState ps
Definition: execnodes.h:1161
void ExecCleanupTupleRouting(ModifyTableState *mtstate, PartitionTupleRouting *proute)
bool ri_usesFdwDirectModify
Definition: execnodes.h:450
void ExecDropSingleTupleTableSlot(TupleTableSlot *slot)
Definition: execTuples.c:1224
EPQState mt_epqstate
Definition: execnodes.h:1179
struct FdwRoutine * ri_FdwRoutine
Definition: execnodes.h:444
EndForeignModify_function EndForeignModify
Definition: fdwapi.h:224
PlanState ** mt_plans
Definition: execnodes.h:1165
TupleTableSlot * mt_root_tuple_slot
Definition: execnodes.h:1186
int i

◆ ExecInitModifyTable()

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

Definition at line 2313 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, convert_tuples_by_name(), elog, ModifyTable::epqParam, ERROR, EState::es_auxmodifytables, EState::es_tupleTable, EvalPlanQualInit(), EvalPlanQualSetPlan(), EXEC_FLAG_BACKWARD, EXEC_FLAG_EXPLAIN_ONLY, EXEC_FLAG_MARK, ExecAssignExprContext(), ExecBuildAuxRowMark(), ExecBuildProjectionInfo(), ExecCheckPlanOutput(), ExecFindJunkAttribute(), ExecFindRowMark(), FdwRoutine::ExecForeignBatchInsert, ExecGetResultType(), ExecInitExtraTupleSlot(), ExecInitJunkFilter(), ExecInitJunkFilterInsertion(), ExecInitNode(), ExecInitQual(), ExecInitResultRelation(), ExecInitResultTupleSlotTL(), ExecInitResultTypeTL(), ExecModifyTable(), ExecOpenIndices(), PlanState::ExecProcNode, ExecSetupPartitionTupleRouting(), ExecSetupTransitionCaptureState(), ExecTypeFromTL(), ModifyTable::fdwDirectModifyPlans, ModifyTable::fdwPrivLists, ModifyTableState::fireBSTriggers, forboth, FdwRoutine::GetForeignModifyBatchSize, i, PlanRowMark::isParent, JunkFilter::jf_junkAttNo, lappend(), lcons(), lfirst, lfirst_int, lfirst_node, linitial, linitial_int, 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_transition_capture, 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, palloc(), palloc0(), ModifyTable::partColsUpdated, PlanState::plan, ModifyTable::plans, ModifyTableState::ps, PlanState::ps_ExprContext, PlanState::ps_ResultTupleSlot, WithCheckOption::qual, RelationData::rd_att, RelationData::rd_rel, RelationGetDescr, TargetEntry::resjunk, ModifyTable::resultRelations, ModifyTableState::resultRelInfo, ModifyTable::returningLists, ResultRelInfo::ri_BatchSize, ResultRelInfo::ri_ChildToRootMap, 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::rootRelation, 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().

2314 {
2315  ModifyTableState *mtstate;
2316  CmdType operation = node->operation;
2317  int nplans = list_length(node->plans);
2318  ResultRelInfo *resultRelInfo;
2319  Plan *subplan;
2320  ListCell *l,
2321  *l1;
2322  int i;
2323  Relation rel;
2324  bool update_tuple_routing_needed = node->partColsUpdated;
2325 
2326  /* check for unsupported flags */
2327  Assert(!(eflags & (EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK)));
2328 
2329  /*
2330  * create state structure
2331  */
2332  mtstate = makeNode(ModifyTableState);
2333  mtstate->ps.plan = (Plan *) node;
2334  mtstate->ps.state = estate;
2335  mtstate->ps.ExecProcNode = ExecModifyTable;
2336 
2337  mtstate->operation = operation;
2338  mtstate->canSetTag = node->canSetTag;
2339  mtstate->mt_done = false;
2340 
2341  mtstate->mt_plans = (PlanState **) palloc0(sizeof(PlanState *) * nplans);
2342  mtstate->resultRelInfo = (ResultRelInfo *)
2343  palloc(nplans * sizeof(ResultRelInfo));
2344  mtstate->mt_scans = (TupleTableSlot **) palloc0(sizeof(TupleTableSlot *) * nplans);
2345 
2346  /*----------
2347  * Resolve the target relation. This is the same as:
2348  *
2349  * - the relation for which we will fire FOR STATEMENT triggers,
2350  * - the relation into whose tuple format all captured transition tuples
2351  * must be converted, and
2352  * - the root partitioned table used for tuple routing.
2353  *
2354  * If it's a partitioned table, the root partition doesn't appear
2355  * elsewhere in the plan and its RT index is given explicitly in
2356  * node->rootRelation. Otherwise (i.e. table inheritance) the target
2357  * relation is the first relation in the node->resultRelations list.
2358  *----------
2359  */
2360  if (node->rootRelation > 0)
2361  {
2363  ExecInitResultRelation(estate, mtstate->rootResultRelInfo,
2364  node->rootRelation);
2365  }
2366  else
2367  {
2368  mtstate->rootResultRelInfo = mtstate->resultRelInfo;
2369  ExecInitResultRelation(estate, mtstate->resultRelInfo,
2370  linitial_int(node->resultRelations));
2371  }
2372 
2373  mtstate->mt_arowmarks = (List **) palloc0(sizeof(List *) * nplans);
2374  mtstate->mt_nplans = nplans;
2375 
2376  /* set up epqstate with dummy subplan data for the moment */
2377  EvalPlanQualInit(&mtstate->mt_epqstate, estate, NULL, NIL, node->epqParam);
2378  mtstate->fireBSTriggers = true;
2379 
2380  /*
2381  * Build state for collecting transition tuples. This requires having a
2382  * valid trigger query context, so skip it in explain-only mode.
2383  */
2384  if (!(eflags & EXEC_FLAG_EXPLAIN_ONLY))
2385  ExecSetupTransitionCaptureState(mtstate, estate);
2386 
2387  /*
2388  * call ExecInitNode on each of the plans to be executed and save the
2389  * results into the array "mt_plans". This is also a convenient place to
2390  * verify that the proposed target relations are valid and open their
2391  * indexes for insertion of new index entries.
2392  */
2393  resultRelInfo = mtstate->resultRelInfo;
2394  i = 0;
2395  forboth(l, node->resultRelations, l1, node->plans)
2396  {
2397  Index resultRelation = lfirst_int(l);
2398 
2399  subplan = (Plan *) lfirst(l1);
2400 
2401  /*
2402  * This opens result relation and fills ResultRelInfo. (root relation
2403  * was initialized already.)
2404  */
2405  if (resultRelInfo != mtstate->rootResultRelInfo)
2406  ExecInitResultRelation(estate, resultRelInfo, resultRelation);
2407 
2408  /* Initialize the usesFdwDirectModify flag */
2409  resultRelInfo->ri_usesFdwDirectModify = bms_is_member(i,
2410  node->fdwDirectModifyPlans);
2411 
2412  /*
2413  * Verify result relation is a valid target for the current operation
2414  */
2415  CheckValidResultRel(resultRelInfo, operation);
2416 
2417  /*
2418  * If there are indices on the result relation, open them and save
2419  * descriptors in the result relation info, so that we can add new
2420  * index entries for the tuples we add/update. We need not do this
2421  * for a DELETE, however, since deletion doesn't affect indexes. Also,
2422  * inside an EvalPlanQual operation, the indexes might be open
2423  * already, since we share the resultrel state with the original
2424  * query.
2425  */
2426  if (resultRelInfo->ri_RelationDesc->rd_rel->relhasindex &&
2427  operation != CMD_DELETE &&
2428  resultRelInfo->ri_IndexRelationDescs == NULL)
2429  ExecOpenIndices(resultRelInfo,
2431 
2432  /*
2433  * If this is an UPDATE and a BEFORE UPDATE trigger is present, the
2434  * trigger itself might modify the partition-key values. So arrange
2435  * for tuple routing.
2436  */
2437  if (resultRelInfo->ri_TrigDesc &&
2438  resultRelInfo->ri_TrigDesc->trig_update_before_row &&
2439  operation == CMD_UPDATE)
2440  update_tuple_routing_needed = true;
2441 
2442  /* Now init the plan for this result rel */
2443  mtstate->mt_plans[i] = ExecInitNode(subplan, estate, eflags);
2444  mtstate->mt_scans[i] =
2445  ExecInitExtraTupleSlot(mtstate->ps.state, ExecGetResultType(mtstate->mt_plans[i]),
2446  table_slot_callbacks(resultRelInfo->ri_RelationDesc));
2447 
2448  /* Also let FDWs init themselves for foreign-table result rels */
2449  if (!resultRelInfo->ri_usesFdwDirectModify &&
2450  resultRelInfo->ri_FdwRoutine != NULL &&
2451  resultRelInfo->ri_FdwRoutine->BeginForeignModify != NULL)
2452  {
2453  List *fdw_private = (List *) list_nth(node->fdwPrivLists, i);
2454 
2455  resultRelInfo->ri_FdwRoutine->BeginForeignModify(mtstate,
2456  resultRelInfo,
2457  fdw_private,
2458  i,
2459  eflags);
2460  }
2461 
2462  /*
2463  * If needed, initialize a map to convert tuples in the child format
2464  * to the format of the table mentioned in the query (root relation).
2465  * It's needed for update tuple routing, because the routing starts
2466  * from the root relation. It's also needed for capturing transition
2467  * tuples, because the transition tuple store can only store tuples in
2468  * the root table format.
2469  *
2470  * For INSERT, the map is only initialized for a given partition when
2471  * the partition itself is first initialized by ExecFindPartition().
2472  */
2473  if (update_tuple_routing_needed ||
2474  (mtstate->mt_transition_capture &&
2475  mtstate->operation != CMD_INSERT))
2476  resultRelInfo->ri_ChildToRootMap =
2479  resultRelInfo++;
2480  i++;
2481  }
2482 
2483  /* Get the target relation */
2484  rel = mtstate->rootResultRelInfo->ri_RelationDesc;
2485 
2486  /*
2487  * If it's not a partitioned table after all, UPDATE tuple routing should
2488  * not be attempted.
2489  */
2490  if (rel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
2491  update_tuple_routing_needed = false;
2492 
2493  /*
2494  * Build state for tuple routing if it's an INSERT or if it's an UPDATE of
2495  * partition key.
2496  */
2497  if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE &&
2498  (operation == CMD_INSERT || update_tuple_routing_needed))
2499  mtstate->mt_partition_tuple_routing =
2500  ExecSetupPartitionTupleRouting(estate, mtstate, rel);
2501 
2502  /*
2503  * For update row movement we'll need a dedicated slot to store the tuples
2504  * that have been converted from partition format to the root table
2505  * format.
2506  */
2507  if (update_tuple_routing_needed)
2508  mtstate->mt_root_tuple_slot = table_slot_create(rel, NULL);
2509 
2510  /*
2511  * Initialize any WITH CHECK OPTION constraints if needed.
2512  */
2513  resultRelInfo = mtstate->resultRelInfo;
2514  foreach(l, node->withCheckOptionLists)
2515  {
2516  List *wcoList = (List *) lfirst(l);
2517  List *wcoExprs = NIL;
2518  ListCell *ll;
2519 
2520  foreach(ll, wcoList)
2521  {
2522  WithCheckOption *wco = (WithCheckOption *) lfirst(ll);
2523  ExprState *wcoExpr = ExecInitQual((List *) wco->qual,
2524  &mtstate->ps);
2525 
2526  wcoExprs = lappend(wcoExprs, wcoExpr);
2527  }
2528 
2529  resultRelInfo->ri_WithCheckOptions = wcoList;
2530  resultRelInfo->ri_WithCheckOptionExprs = wcoExprs;
2531  resultRelInfo++;
2532  }
2533 
2534  /*
2535  * Initialize RETURNING projections if needed.
2536  */
2537  if (node->returningLists)
2538  {
2539  TupleTableSlot *slot;
2540  ExprContext *econtext;
2541 
2542  /*
2543  * Initialize result tuple slot and assign its rowtype using the first
2544  * RETURNING list. We assume the rest will look the same.
2545  */
2546  mtstate->ps.plan->targetlist = (List *) linitial(node->returningLists);
2547 
2548  /* Set up a slot for the output of the RETURNING projection(s) */
2550  slot = mtstate->ps.ps_ResultTupleSlot;
2551 
2552  /* Need an econtext too */
2553  if (mtstate->ps.ps_ExprContext == NULL)
2554  ExecAssignExprContext(estate, &mtstate->ps);
2555  econtext = mtstate->ps.ps_ExprContext;
2556 
2557  /*
2558  * Build a projection for each result rel.
2559  */
2560  resultRelInfo = mtstate->resultRelInfo;
2561  foreach(l, node->returningLists)
2562  {
2563  List *rlist = (List *) lfirst(l);
2564 
2565  resultRelInfo->ri_returningList = rlist;
2566  resultRelInfo->ri_projectReturning =
2567  ExecBuildProjectionInfo(rlist, econtext, slot, &mtstate->ps,
2568  resultRelInfo->ri_RelationDesc->rd_att);
2569  resultRelInfo++;
2570  }
2571  }
2572  else
2573  {
2574  /*
2575  * We still must construct a dummy result tuple type, because InitPlan
2576  * expects one (maybe should change that?).
2577  */
2578  mtstate->ps.plan->targetlist = NIL;
2579  ExecInitResultTypeTL(&mtstate->ps);
2580 
2581  mtstate->ps.ps_ExprContext = NULL;
2582  }
2583 
2584  /* Set the list of arbiter indexes if needed for ON CONFLICT */
2585  resultRelInfo = mtstate->resultRelInfo;
2586  if (node->onConflictAction != ONCONFLICT_NONE)
2587  resultRelInfo->ri_onConflictArbiterIndexes = node->arbiterIndexes;
2588 
2589  /*
2590  * If needed, Initialize target list, projection and qual for ON CONFLICT
2591  * DO UPDATE.
2592  */
2593  if (node->onConflictAction == ONCONFLICT_UPDATE)
2594  {
2595  ExprContext *econtext;
2596  TupleDesc relationDesc;
2597  TupleDesc tupDesc;
2598 
2599  /* insert may only have one plan, inheritance is not expanded */
2600  Assert(nplans == 1);
2601 
2602  /* already exists if created by RETURNING processing above */
2603  if (mtstate->ps.ps_ExprContext == NULL)
2604  ExecAssignExprContext(estate, &mtstate->ps);
2605 
2606  econtext = mtstate->ps.ps_ExprContext;
2607  relationDesc = resultRelInfo->ri_RelationDesc->rd_att;
2608 
2609  /* create state for DO UPDATE SET operation */
2610  resultRelInfo->ri_onConflict = makeNode(OnConflictSetState);
2611 
2612  /* initialize slot for the existing tuple */
2613  resultRelInfo->ri_onConflict->oc_Existing =
2614  table_slot_create(resultRelInfo->ri_RelationDesc,
2615  &mtstate->ps.state->es_tupleTable);
2616 
2617  /*
2618  * Create the tuple slot for the UPDATE SET projection. We want a slot
2619  * of the table's type here, because the slot will be used to insert
2620  * into the table, and for RETURNING processing - which may access
2621  * system attributes.
2622  */
2623  tupDesc = ExecTypeFromTL((List *) node->onConflictSet);
2624  resultRelInfo->ri_onConflict->oc_ProjSlot =
2625  ExecInitExtraTupleSlot(mtstate->ps.state, tupDesc,
2626  table_slot_callbacks(resultRelInfo->ri_RelationDesc));
2627 
2628  /* build UPDATE SET projection state */
2629  resultRelInfo->ri_onConflict->oc_ProjInfo =
2630  ExecBuildProjectionInfo(node->onConflictSet, econtext,
2631  resultRelInfo->ri_onConflict->oc_ProjSlot,
2632  &mtstate->ps,
2633  relationDesc);
2634 
2635  /* initialize state to evaluate the WHERE clause, if any */
2636  if (node->onConflictWhere)
2637  {
2638  ExprState *qualexpr;
2639 
2640  qualexpr = ExecInitQual((List *) node->onConflictWhere,
2641  &mtstate->ps);
2642  resultRelInfo->ri_onConflict->oc_WhereClause = qualexpr;
2643  }
2644  }
2645 
2646  /*
2647  * If we have any secondary relations in an UPDATE or DELETE, they need to
2648  * be treated like non-locked relations in SELECT FOR UPDATE, ie, the
2649  * EvalPlanQual mechanism needs to be told about them. Locate the
2650  * relevant ExecRowMarks.
2651  */
2652  foreach(l, node->rowMarks)
2653  {
2655  ExecRowMark *erm;
2656 
2657  /* ignore "parent" rowmarks; they are irrelevant at runtime */
2658  if (rc->isParent)
2659  continue;
2660 
2661  /* find ExecRowMark (same for all subplans) */
2662  erm = ExecFindRowMark(estate, rc->rti, false);
2663 
2664  /* build ExecAuxRowMark for each subplan */
2665  for (i = 0; i < nplans; i++)
2666  {
2667  ExecAuxRowMark *aerm;
2668 
2669  subplan = mtstate->mt_plans[i]->plan;
2670  aerm = ExecBuildAuxRowMark(erm, subplan->targetlist);
2671  mtstate->mt_arowmarks[i] = lappend(mtstate->mt_arowmarks[i], aerm);
2672  }
2673  }
2674 
2675  /* select first subplan */
2676  mtstate->mt_whichplan = 0;
2677  subplan = (Plan *) linitial(node->plans);
2678  EvalPlanQualSetPlan(&mtstate->mt_epqstate, subplan,
2679  mtstate->mt_arowmarks[0]);
2680 
2681  /*
2682  * Initialize the junk filter(s) if needed. INSERT queries need a filter
2683  * if there are any junk attrs in the tlist. UPDATE and DELETE always
2684  * need a filter, since there's always at least one junk attribute present
2685  * --- no need to look first. Typically, this will be a 'ctid' or
2686  * 'wholerow' attribute, but in the case of a foreign data wrapper it
2687  * might be a set of junk attributes sufficient to identify the remote
2688  * row.
2689  *
2690  * If there are multiple result relations, each one needs its own junk
2691  * filter. Note multiple rels are only possible for UPDATE/DELETE, so we
2692  * can't be fooled by some needing a filter and some not.
2693  *
2694  * This section of code is also a convenient place to verify that the
2695  * output of an INSERT or UPDATE matches the target table(s).
2696  */
2697  {
2698  bool junk_filter_needed = false;
2699 
2700  switch (operation)
2701  {
2702  case CMD_INSERT:
2703  foreach(l, subplan->targetlist)
2704  {
2705  TargetEntry *tle = (TargetEntry *) lfirst(l);
2706 
2707  if (tle->resjunk)
2708  {
2709  junk_filter_needed = true;
2710  break;
2711  }
2712  }
2713  break;
2714  case CMD_UPDATE:
2715  case CMD_DELETE:
2716  junk_filter_needed = true;
2717  break;
2718  default:
2719  elog(ERROR, "unknown operation");
2720  break;
2721  }
2722 
2723  if (junk_filter_needed)
2724  {
2725  resultRelInfo = mtstate->resultRelInfo;
2726  for (i = 0; i < nplans; i++)
2727  {
2728  JunkFilter *j;
2729  TupleTableSlot *junkresslot;
2730 
2731  subplan = mtstate->mt_plans[i]->plan;
2732 
2733  junkresslot =
2734  ExecInitExtraTupleSlot(estate, NULL,
2735  table_slot_callbacks(resultRelInfo->ri_RelationDesc));
2736 
2737  /*
2738  * For an INSERT or UPDATE, the result tuple must always match
2739  * the target table's descriptor. For a DELETE, it won't
2740  * (indeed, there's probably no non-junk output columns).
2741  */
2742  if (operation == CMD_INSERT || operation == CMD_UPDATE)
2743  {
2744  ExecCheckPlanOutput(resultRelInfo->ri_RelationDesc,
2745  subplan->targetlist);
2747  RelationGetDescr(resultRelInfo->ri_RelationDesc),
2748  junkresslot);
2749  }
2750  else
2751  j = ExecInitJunkFilter(subplan->targetlist,
2752  junkresslot);
2753 
2754  if (operation == CMD_UPDATE || operation == CMD_DELETE)
2755  {
2756  /* For UPDATE/DELETE, find the appropriate junk attr now */
2757  char relkind;
2758 
2759  relkind = resultRelInfo->ri_RelationDesc->rd_rel->relkind;
2760  if (relkind == RELKIND_RELATION ||
2761  relkind == RELKIND_MATVIEW ||
2762  relkind == RELKIND_PARTITIONED_TABLE)
2763  {
2764  j->jf_junkAttNo = ExecFindJunkAttribute(j, "ctid");
2766  elog(ERROR, "could not find junk ctid column");
2767  }
2768  else if (relkind == RELKIND_FOREIGN_TABLE)
2769  {
2770  /*
2771  * When there is a row-level trigger, there should be
2772  * a wholerow attribute.
2773  */
2774  j->jf_junkAttNo = ExecFindJunkAttribute(j, "wholerow");
2775  }
2776  else
2777  {
2778  j->jf_junkAttNo = ExecFindJunkAttribute(j, "wholerow");
2780  elog(ERROR, "could not find junk wholerow column");
2781  }
2782  }
2783 
2784  resultRelInfo->ri_junkFilter = j;
2785  resultRelInfo++;
2786  }
2787  }
2788  else
2789  {
2790  if (operation == CMD_INSERT)
2792  subplan->targetlist);
2793  }
2794  }
2795 
2796  /*
2797  * Determine if the FDW supports batch insert and determine the batch
2798  * size (a FDW may support batching, but it may be disabled for the
2799  * server/table).
2800  *
2801  * We only do this for INSERT, so that for UPDATE/DELETE the batch
2802  * size remains set to 0.
2803  */
2804  if (operation == CMD_INSERT)
2805  {
2806  resultRelInfo = mtstate->resultRelInfo;
2807  for (i = 0; i < nplans; i++)
2808  {
2809  if (!resultRelInfo->ri_usesFdwDirectModify &&
2810  resultRelInfo->ri_FdwRoutine != NULL &&
2811  resultRelInfo->ri_FdwRoutine->GetForeignModifyBatchSize &&
2812  resultRelInfo->ri_FdwRoutine->ExecForeignBatchInsert)
2813  resultRelInfo->ri_BatchSize =
2814  resultRelInfo->ri_FdwRoutine->GetForeignModifyBatchSize(resultRelInfo);
2815  else
2816  resultRelInfo->ri_BatchSize = 1;
2817 
2818  Assert(resultRelInfo->ri_BatchSize >= 1);
2819 
2820  resultRelInfo++;
2821  }
2822  }
2823 
2824  /*
2825  * Lastly, if this is not the primary (canSetTag) ModifyTable node, add it
2826  * to estate->es_auxmodifytables so that it will be run to completion by
2827  * ExecPostprocessPlan. (It'd actually work fine to add the primary
2828  * ModifyTable node too, but there's no need.) Note the use of lcons not
2829  * lappend: we need later-initialized ModifyTable nodes to be shut down
2830  * before earlier ones. This ensures that we don't throw away RETURNING
2831  * rows that need to be seen by a later CTE subplan.
2832  */
2833  if (!mtstate->canSetTag)
2834  estate->es_auxmodifytables = lcons(mtstate,
2835  estate->es_auxmodifytables);
2836 
2837  return mtstate;
2838 }
TupleTableSlot * table_slot_create(Relation relation, List **reglist)
Definition: tableam.c:91
AttrNumber jf_junkAttNo
Definition: execnodes.h:372
#define NIL
Definition: pg_list.h:65
JunkFilter * ri_junkFilter
Definition: execnodes.h:474
List * arbiterIndexes
Definition: plannodes.h:229
Relation ri_RelationDesc
Definition: execnodes.h:415
Bitmapset * fdwDirectModifyPlans
Definition: plannodes.h:225
#define forboth(cell1, list1, cell2, list2)
Definition: pg_list.h:446
TupleTableSlot * ExecInitExtraTupleSlot(EState *estate, TupleDesc tupledesc, const TupleTableSlotOps *tts_ops)
Definition: execTuples.c:1801
struct PartitionTupleRouting * mt_partition_tuple_routing
Definition: execnodes.h:1189
#define RelationGetDescr(relation)
Definition: rel.h:483
List * withCheckOptionLists
Definition: plannodes.h:222
void ExecInitResultRelation(EState *estate, ResultRelInfo *resultRelInfo, Index rti)
Definition: execUtils.c:834
ResultRelInfo * resultRelInfo
Definition: execnodes.h:1170
AttrNumber ExecFindJunkAttribute(JunkFilter *junkfilter, const char *attrName)
Definition: execJunk.c:234
ExprContext * ps_ExprContext
Definition: execnodes.h:980
TupleTableSlot ** mt_scans
Definition: execnodes.h:1168
const TupleTableSlotOps * table_slot_callbacks(Relation relation)
Definition: tableam.c:58
const TupleTableSlotOps TTSOpsVirtual
Definition: execTuples.c:83
TupleConversionMap * ri_ChildToRootMap
Definition: execnodes.h:512
JunkFilter * ExecInitJunkFilterInsertion(List *targetList, TupleDesc cleanTupType, TupleTableSlot *slot)
Definition: execJunk.c:89
bool partColsUpdated
Definition: plannodes.h:219
bool canSetTag
Definition: plannodes.h:216
CmdType operation
Definition: execnodes.h:1162
ResultRelInfo * rootResultRelInfo
Definition: execnodes.h:1176
void EvalPlanQualSetPlan(EPQState *epqstate, Plan *subplan, List *auxrowmarks)
Definition: execMain.c:2419
EState * state
Definition: execnodes.h:943
Form_pg_class rd_rel
Definition: rel.h:110
List * plans
Definition: plannodes.h:221
ExprState * ExecInitQual(List *qual, PlanState *parent)
Definition: execExpr.c:209
List * onConflictSet
Definition: plannodes.h:230
Index rootRelation
Definition: plannodes.h:218
List * resultRelations
Definition: plannodes.h:220
void ExecOpenIndices(ResultRelInfo *resultRelInfo, bool speculative)
Definition: execIndexing.c:156
List * ri_WithCheckOptionExprs
Definition: execnodes.h:462
#define linitial_int(l)
Definition: pg_list.h:175
TupleTableSlot * oc_Existing
Definition: execnodes.h:384
TupleTableSlot * ps_ResultTupleSlot
Definition: execnodes.h:979
List * rowMarks
Definition: plannodes.h:226
bool resjunk
Definition: primnodes.h:1438
#define linitial(l)
Definition: pg_list.h:174
#define ERROR
Definition: elog.h:45
PlanState ps
Definition: execnodes.h:1161
ProjectionInfo * oc_ProjInfo
Definition: execnodes.h:386
#define lfirst_int(lc)
Definition: pg_list.h:170
static void * list_nth(const List *list, int n)
Definition: pg_list.h:278
bool ri_usesFdwDirectModify
Definition: execnodes.h:450
static void ExecSetupTransitionCaptureState(ModifyTableState *mtstate, EState *estate)
void CheckValidResultRel(ResultRelInfo *resultRelInfo, CmdType operation)
Definition: execMain.c:981
#define EXEC_FLAG_BACKWARD
Definition: executor.h:58
#define lfirst_node(type, lc)
Definition: pg_list.h:172
TupleConversionMap * convert_tuples_by_name(TupleDesc indesc, TupleDesc outdesc)
Definition: tupconvert.c:102
struct TransitionCaptureState * mt_transition_capture
Definition: execnodes.h:1192
void ExecInitResultTypeTL(PlanState *planstate)
Definition: execTuples.c:1725
List * fdwPrivLists
Definition: plannodes.h:224
EPQState mt_epqstate
Definition: execnodes.h:1179
bool trig_update_before_row
Definition: reltrigger.h:61
ProjectionInfo * ri_projectReturning
Definition: execnodes.h:480
struct FdwRoutine * ri_FdwRoutine
Definition: execnodes.h:444
ExprState * oc_WhereClause
Definition: execnodes.h:387
PartitionTupleRouting * ExecSetupPartitionTupleRouting(EState *estate, ModifyTableState *mtstate, Relation rel)
GetForeignModifyBatchSize_function GetForeignModifyBatchSize
Definition: fdwapi.h:221
TriggerDesc * ri_TrigDesc
Definition: execnodes.h:427
List * lappend(List *list, void *datum)
Definition: list.c:336
PlanState ** mt_plans
Definition: execnodes.h:1165
void EvalPlanQualInit(EPQState *epqstate, EState *parentestate, Plan *subplan, List *auxrowmarks, int epqParam)
Definition: execMain.c:2381
OnConflictSetState * ri_onConflict
Definition: execnodes.h:486
#define AttributeNumberIsValid(attributeNumber)
Definition: attnum.h:34
static TupleTableSlot * ExecModifyTable(PlanState *pstate)
List * es_tupleTable
Definition: execnodes.h:574
void * palloc0(Size size)
Definition: mcxt.c:981
List * es_auxmodifytables
Definition: execnodes.h:586
ExecProcNodeMtd ExecProcNode
Definition: execnodes.h:947
List * ri_WithCheckOptions
Definition: execnodes.h:459
unsigned int Index
Definition: c.h:549
TupleDesc rd_att
Definition: rel.h:111
Plan * plan
Definition: execnodes.h:941
TupleTableSlot * oc_ProjSlot
Definition: execnodes.h:385
List * lcons(void *datum, List *list)
Definition: list.c:468
ExecForeignBatchInsert_function ExecForeignBatchInsert
Definition: fdwapi.h:220
#define makeNode(_type_)
Definition: nodes.h:581
static void ExecCheckPlanOutput(Relation resultRel, List *targetList)
int ri_BatchSize
Definition: execnodes.h:454
#define Assert(condition)
Definition: c.h:804
#define lfirst(lc)
Definition: pg_list.h:169
#define EXEC_FLAG_MARK
Definition: executor.h:59
OnConflictAction onConflictAction
Definition: plannodes.h:228
void ExecAssignExprContext(EState *estate, PlanState *planstate)
Definition: execUtils.c:480
static int list_length(const List *l)
Definition: pg_list.h:149
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:1186
TupleDesc ExecGetResultType(PlanState *planstate)
Definition: execUtils.c:490
List * targetlist
Definition: plannodes.h:136
void * palloc(Size size)
Definition: mcxt.c:950
ProjectionInfo * ExecBuildProjectionInfo(List *targetList, ExprContext *econtext, TupleTableSlot *slot, PlanState *parent, TupleDesc inputDesc)
Definition: execExpr.c:353
CmdType operation
Definition: plannodes.h:215
#define elog(elevel,...)
Definition: elog.h:227
int i
List * returningLists
Definition: plannodes.h:223
bool isParent
Definition: plannodes.h:1097
BeginForeignModify_function BeginForeignModify
Definition: fdwapi.h:218
PlanState * ExecInitNode(Plan *node, EState *estate, int eflags)
Definition: execProcnode.c:140
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:483
CmdType
Definition: nodes.h:676
RelationPtr ri_IndexRelationDescs
Definition: execnodes.h:421
ExecAuxRowMark * ExecBuildAuxRowMark(ExecRowMark *erm, List *targetlist)
Definition: execMain.c:2257
List * ri_returningList
Definition: execnodes.h:477
List ** mt_arowmarks
Definition: execnodes.h:1178
int epqParam
Definition: plannodes.h:227
Node * onConflictWhere
Definition: plannodes.h:231
ExecRowMark * ExecFindRowMark(EState *estate, Index rti, bool missing_ok)
Definition: execMain.c:2234

◆ ExecReScanModifyTable()

void ExecReScanModifyTable ( ModifyTableState node)

Definition at line 2903 of file nodeModifyTable.c.

References elog, and ERROR.

Referenced by ExecReScan().

2904 {
2905  /*
2906  * Currently, we don't need to support rescan on ModifyTable nodes. The
2907  * semantics of that would be a bit debatable anyway.
2908  */
2909  elog(ERROR, "ExecReScanModifyTable is not implemented");
2910 }
#define ERROR
Definition: elog.h:45
#define elog(elevel,...)
Definition: elog.h:227