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 246 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, 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().

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

◆ ExecEndModifyTable()

void ExecEndModifyTable ( ModifyTableState node)

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

2672 {
2673  int i;
2674 
2675  /*
2676  * Allow any FDWs to shut down
2677  */
2678  for (i = 0; i < node->mt_nplans; i++)
2679  {
2680  ResultRelInfo *resultRelInfo = node->resultRelInfo + i;
2681 
2682  if (!resultRelInfo->ri_usesFdwDirectModify &&
2683  resultRelInfo->ri_FdwRoutine != NULL &&
2684  resultRelInfo->ri_FdwRoutine->EndForeignModify != NULL)
2685  resultRelInfo->ri_FdwRoutine->EndForeignModify(node->ps.state,
2686  resultRelInfo);
2687  }
2688 
2689  /*
2690  * Close all the partitioned tables, leaf partitions, and their indices
2691  * and release the slot used for tuple routing, if set.
2692  */
2693  if (node->mt_partition_tuple_routing)
2694  {
2696 
2697  if (node->mt_root_tuple_slot)
2699  }
2700 
2701  /*
2702  * Free the exprcontext
2703  */
2704  ExecFreeExprContext(&node->ps);
2705 
2706  /*
2707  * clean out the tuple table
2708  */
2709  if (node->ps.ps_ResultTupleSlot)
2711 
2712  /*
2713  * Terminate EPQ execution if active
2714  */
2715  EvalPlanQualEnd(&node->mt_epqstate);
2716 
2717  /*
2718  * shut down subplans
2719  */
2720  for (i = 0; i < node->mt_nplans; i++)
2721  ExecEndNode(node->mt_plans[i]);
2722 }
static TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition: tuptable.h:425
struct PartitionTupleRouting * mt_partition_tuple_routing
Definition: execnodes.h:1187
void ExecEndNode(PlanState *node)
Definition: execProcnode.c:543
ResultRelInfo * resultRelInfo
Definition: execnodes.h:1168
EState * state
Definition: execnodes.h:941
void ExecFreeExprContext(PlanState *planstate)
Definition: execUtils.c:649
void EvalPlanQualEnd(EPQState *epqstate)
Definition: execMain.c:2810
TupleTableSlot * ps_ResultTupleSlot
Definition: execnodes.h:977
PlanState ps
Definition: execnodes.h:1159
void ExecCleanupTupleRouting(ModifyTableState *mtstate, PartitionTupleRouting *proute)
bool ri_usesFdwDirectModify
Definition: execnodes.h:447
void ExecDropSingleTupleTableSlot(TupleTableSlot *slot)
Definition: execTuples.c:1224
EPQState mt_epqstate
Definition: execnodes.h:1177
struct FdwRoutine * ri_FdwRoutine
Definition: execnodes.h:441
EndForeignModify_function EndForeignModify
Definition: fdwapi.h:214
PlanState ** mt_plans
Definition: execnodes.h:1163
TupleTableSlot * mt_root_tuple_slot
Definition: execnodes.h:1184
int i

◆ ExecInitModifyTable()

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

Definition at line 2173 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(), ExecGetResultType(), ExecInitExtraTupleSlot(), ExecInitJunkFilter(), ExecInitNode(), ExecInitQual(), ExecInitResultRelation(), ExecInitResultTupleSlotTL(), ExecInitResultTypeTL(), ExecModifyTable(), ExecOpenIndices(), PlanState::ExecProcNode, ExecSetupPartitionTupleRouting(), ExecSetupTransitionCaptureState(), ExecTypeFromTL(), ModifyTable::fdwDirectModifyPlans, ModifyTable::fdwPrivLists, ModifyTableState::fireBSTriggers, forboth, 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_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().

2174 {
2175  ModifyTableState *mtstate;
2176  CmdType operation = node->operation;
2177  int nplans = list_length(node->plans);
2178  ResultRelInfo *resultRelInfo;
2179  Plan *subplan;
2180  ListCell *l,
2181  *l1;
2182  int i;
2183  Relation rel;
2184  bool update_tuple_routing_needed = node->partColsUpdated;
2185 
2186  /* check for unsupported flags */
2187  Assert(!(eflags & (EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK)));
2188 
2189  /*
2190  * create state structure
2191  */
2192  mtstate = makeNode(ModifyTableState);
2193  mtstate->ps.plan = (Plan *) node;
2194  mtstate->ps.state = estate;
2195  mtstate->ps.ExecProcNode = ExecModifyTable;
2196 
2197  mtstate->operation = operation;
2198  mtstate->canSetTag = node->canSetTag;
2199  mtstate->mt_done = false;
2200 
2201  mtstate->mt_plans = (PlanState **) palloc0(sizeof(PlanState *) * nplans);
2202  mtstate->resultRelInfo = (ResultRelInfo *)
2203  palloc(nplans * sizeof(ResultRelInfo));
2204  mtstate->mt_scans = (TupleTableSlot **) palloc0(sizeof(TupleTableSlot *) * nplans);
2205 
2206  /*----------
2207  * Resolve the target relation. This is the same as:
2208  *
2209  * - the relation for which we will fire FOR STATEMENT triggers,
2210  * - the relation into whose tuple format all captured transition tuples
2211  * must be converted, and
2212  * - the root partitioned table used for tuple routing.
2213  *
2214  * If it's a partitioned table, the root partition doesn't appear
2215  * elsewhere in the plan and its RT index is given explicitly in
2216  * node->rootRelation. Otherwise (i.e. table inheritance) the target
2217  * relation is the first relation in the node->resultRelations list.
2218  *----------
2219  */
2220  if (node->rootRelation > 0)
2221  {
2223  ExecInitResultRelation(estate, mtstate->rootResultRelInfo,
2224  node->rootRelation);
2225  }
2226  else
2227  {
2228  mtstate->rootResultRelInfo = mtstate->resultRelInfo;
2229  ExecInitResultRelation(estate, mtstate->resultRelInfo,
2230  linitial_int(node->resultRelations));
2231  }
2232 
2233  mtstate->mt_arowmarks = (List **) palloc0(sizeof(List *) * nplans);
2234  mtstate->mt_nplans = nplans;
2235 
2236  /* set up epqstate with dummy subplan data for the moment */
2237  EvalPlanQualInit(&mtstate->mt_epqstate, estate, NULL, NIL, node->epqParam);
2238  mtstate->fireBSTriggers = true;
2239 
2240  /*
2241  * Build state for collecting transition tuples. This requires having a
2242  * valid trigger query context, so skip it in explain-only mode.
2243  */
2244  if (!(eflags & EXEC_FLAG_EXPLAIN_ONLY))
2245  ExecSetupTransitionCaptureState(mtstate, estate);
2246 
2247  /*
2248  * call ExecInitNode on each of the plans to be executed and save the
2249  * results into the array "mt_plans". This is also a convenient place to
2250  * verify that the proposed target relations are valid and open their
2251  * indexes for insertion of new index entries.
2252  */
2253  resultRelInfo = mtstate->resultRelInfo;
2254  i = 0;
2255  forboth(l, node->resultRelations, l1, node->plans)
2256  {
2257  Index resultRelation = lfirst_int(l);
2258 
2259  subplan = (Plan *) lfirst(l1);
2260 
2261  /*
2262  * This opens result relation and fills ResultRelInfo. (root relation
2263  * was initialized already.)
2264  */
2265  if (resultRelInfo != mtstate->rootResultRelInfo)
2266  ExecInitResultRelation(estate, resultRelInfo, resultRelation);
2267 
2268  /* Initialize the usesFdwDirectModify flag */
2269  resultRelInfo->ri_usesFdwDirectModify = bms_is_member(i,
2270  node->fdwDirectModifyPlans);
2271 
2272  /*
2273  * Verify result relation is a valid target for the current operation
2274  */
2275  CheckValidResultRel(resultRelInfo, operation);
2276 
2277  /*
2278  * If there are indices on the result relation, open them and save
2279  * descriptors in the result relation info, so that we can add new
2280  * index entries for the tuples we add/update. We need not do this
2281  * for a DELETE, however, since deletion doesn't affect indexes. Also,
2282  * inside an EvalPlanQual operation, the indexes might be open
2283  * already, since we share the resultrel state with the original
2284  * query.
2285  */
2286  if (resultRelInfo->ri_RelationDesc->rd_rel->relhasindex &&
2287  operation != CMD_DELETE &&
2288  resultRelInfo->ri_IndexRelationDescs == NULL)
2289  ExecOpenIndices(resultRelInfo,
2291 
2292  /*
2293  * If this is an UPDATE and a BEFORE UPDATE trigger is present, the
2294  * trigger itself might modify the partition-key values. So arrange
2295  * for tuple routing.
2296  */
2297  if (resultRelInfo->ri_TrigDesc &&
2298  resultRelInfo->ri_TrigDesc->trig_update_before_row &&
2299  operation == CMD_UPDATE)
2300  update_tuple_routing_needed = true;
2301 
2302  /* Now init the plan for this result rel */
2303  mtstate->mt_plans[i] = ExecInitNode(subplan, estate, eflags);
2304  mtstate->mt_scans[i] =
2305  ExecInitExtraTupleSlot(mtstate->ps.state, ExecGetResultType(mtstate->mt_plans[i]),
2306  table_slot_callbacks(resultRelInfo->ri_RelationDesc));
2307 
2308  /* Also let FDWs init themselves for foreign-table result rels */
2309  if (!resultRelInfo->ri_usesFdwDirectModify &&
2310  resultRelInfo->ri_FdwRoutine != NULL &&
2311  resultRelInfo->ri_FdwRoutine->BeginForeignModify != NULL)
2312  {
2313  List *fdw_private = (List *) list_nth(node->fdwPrivLists, i);
2314 
2315  resultRelInfo->ri_FdwRoutine->BeginForeignModify(mtstate,
2316  resultRelInfo,
2317  fdw_private,
2318  i,
2319  eflags);
2320  }
2321 
2322  /*
2323  * If needed, initialize a map to convert tuples in the child format
2324  * to the format of the table mentioned in the query (root relation).
2325  * It's needed for update tuple routing, because the routing starts
2326  * from the root relation. It's also needed for capturing transition
2327  * tuples, because the transition tuple store can only store tuples in
2328  * the root table format.
2329  *
2330  * For INSERT, the map is only initialized for a given partition when
2331  * the partition itself is first initialized by ExecFindPartition().
2332  */
2333  if (update_tuple_routing_needed ||
2334  (mtstate->mt_transition_capture &&
2335  mtstate->operation != CMD_INSERT))
2336  resultRelInfo->ri_ChildToRootMap =
2339  resultRelInfo++;
2340  i++;
2341  }
2342 
2343  /* Get the target relation */
2344  rel = mtstate->rootResultRelInfo->ri_RelationDesc;
2345 
2346  /*
2347  * If it's not a partitioned table after all, UPDATE tuple routing should
2348  * not be attempted.
2349  */
2350  if (rel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
2351  update_tuple_routing_needed = false;
2352 
2353  /*
2354  * Build state for tuple routing if it's an INSERT or if it's an UPDATE of
2355  * partition key.
2356  */
2357  if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE &&
2358  (operation == CMD_INSERT || update_tuple_routing_needed))
2359  mtstate->mt_partition_tuple_routing =
2360  ExecSetupPartitionTupleRouting(estate, mtstate, rel);
2361 
2362  /*
2363  * For update row movement we'll need a dedicated slot to store the tuples
2364  * that have been converted from partition format to the root table
2365  * format.
2366  */
2367  if (update_tuple_routing_needed)
2368  mtstate->mt_root_tuple_slot = table_slot_create(rel, NULL);
2369 
2370  /*
2371  * Initialize any WITH CHECK OPTION constraints if needed.
2372  */
2373  resultRelInfo = mtstate->resultRelInfo;
2374  i = 0;
2375  foreach(l, node->withCheckOptionLists)
2376  {
2377  List *wcoList = (List *) lfirst(l);
2378  List *wcoExprs = NIL;
2379  ListCell *ll;
2380 
2381  foreach(ll, wcoList)
2382  {
2383  WithCheckOption *wco = (WithCheckOption *) lfirst(ll);
2384  ExprState *wcoExpr = ExecInitQual((List *) wco->qual,
2385  &mtstate->ps);
2386 
2387  wcoExprs = lappend(wcoExprs, wcoExpr);
2388  }
2389 
2390  resultRelInfo->ri_WithCheckOptions = wcoList;
2391  resultRelInfo->ri_WithCheckOptionExprs = wcoExprs;
2392  resultRelInfo++;
2393  i++;
2394  }
2395 
2396  /*
2397  * Initialize RETURNING projections if needed.
2398  */
2399  if (node->returningLists)
2400  {
2401  TupleTableSlot *slot;
2402  ExprContext *econtext;
2403 
2404  /*
2405  * Initialize result tuple slot and assign its rowtype using the first
2406  * RETURNING list. We assume the rest will look the same.
2407  */
2408  mtstate->ps.plan->targetlist = (List *) linitial(node->returningLists);
2409 
2410  /* Set up a slot for the output of the RETURNING projection(s) */
2412  slot = mtstate->ps.ps_ResultTupleSlot;
2413 
2414  /* Need an econtext too */
2415  if (mtstate->ps.ps_ExprContext == NULL)
2416  ExecAssignExprContext(estate, &mtstate->ps);
2417  econtext = mtstate->ps.ps_ExprContext;
2418 
2419  /*
2420  * Build a projection for each result rel.
2421  */
2422  resultRelInfo = mtstate->resultRelInfo;
2423  foreach(l, node->returningLists)
2424  {
2425  List *rlist = (List *) lfirst(l);
2426 
2427  resultRelInfo->ri_returningList = rlist;
2428  resultRelInfo->ri_projectReturning =
2429  ExecBuildProjectionInfo(rlist, econtext, slot, &mtstate->ps,
2430  resultRelInfo->ri_RelationDesc->rd_att);
2431  resultRelInfo++;
2432  }
2433  }
2434  else
2435  {
2436  /*
2437  * We still must construct a dummy result tuple type, because InitPlan
2438  * expects one (maybe should change that?).
2439  */
2440  mtstate->ps.plan->targetlist = NIL;
2441  ExecInitResultTypeTL(&mtstate->ps);
2442 
2443  mtstate->ps.ps_ExprContext = NULL;
2444  }
2445 
2446  /* Set the list of arbiter indexes if needed for ON CONFLICT */
2447  resultRelInfo = mtstate->resultRelInfo;
2448  if (node->onConflictAction != ONCONFLICT_NONE)
2449  resultRelInfo->ri_onConflictArbiterIndexes = node->arbiterIndexes;
2450 
2451  /*
2452  * If needed, Initialize target list, projection and qual for ON CONFLICT
2453  * DO UPDATE.
2454  */
2455  if (node->onConflictAction == ONCONFLICT_UPDATE)
2456  {
2457  ExprContext *econtext;
2458  TupleDesc relationDesc;
2459  TupleDesc tupDesc;
2460 
2461  /* insert may only have one plan, inheritance is not expanded */
2462  Assert(nplans == 1);
2463 
2464  /* already exists if created by RETURNING processing above */
2465  if (mtstate->ps.ps_ExprContext == NULL)
2466  ExecAssignExprContext(estate, &mtstate->ps);
2467 
2468  econtext = mtstate->ps.ps_ExprContext;
2469  relationDesc = resultRelInfo->ri_RelationDesc->rd_att;
2470 
2471  /* create state for DO UPDATE SET operation */
2472  resultRelInfo->ri_onConflict = makeNode(OnConflictSetState);
2473 
2474  /* initialize slot for the existing tuple */
2475  resultRelInfo->ri_onConflict->oc_Existing =
2476  table_slot_create(resultRelInfo->ri_RelationDesc,
2477  &mtstate->ps.state->es_tupleTable);
2478 
2479  /*
2480  * Create the tuple slot for the UPDATE SET projection. We want a slot
2481  * of the table's type here, because the slot will be used to insert
2482  * into the table, and for RETURNING processing - which may access
2483  * system attributes.
2484  */
2485  tupDesc = ExecTypeFromTL((List *) node->onConflictSet);
2486  resultRelInfo->ri_onConflict->oc_ProjSlot =
2487  ExecInitExtraTupleSlot(mtstate->ps.state, tupDesc,
2488  table_slot_callbacks(resultRelInfo->ri_RelationDesc));
2489 
2490  /* build UPDATE SET projection state */
2491  resultRelInfo->ri_onConflict->oc_ProjInfo =
2492  ExecBuildProjectionInfo(node->onConflictSet, econtext,
2493  resultRelInfo->ri_onConflict->oc_ProjSlot,
2494  &mtstate->ps,
2495  relationDesc);
2496 
2497  /* initialize state to evaluate the WHERE clause, if any */
2498  if (node->onConflictWhere)
2499  {
2500  ExprState *qualexpr;
2501 
2502  qualexpr = ExecInitQual((List *) node->onConflictWhere,
2503  &mtstate->ps);
2504  resultRelInfo->ri_onConflict->oc_WhereClause = qualexpr;
2505  }
2506  }
2507 
2508  /*
2509  * If we have any secondary relations in an UPDATE or DELETE, they need to
2510  * be treated like non-locked relations in SELECT FOR UPDATE, ie, the
2511  * EvalPlanQual mechanism needs to be told about them. Locate the
2512  * relevant ExecRowMarks.
2513  */
2514  foreach(l, node->rowMarks)
2515  {
2517  ExecRowMark *erm;
2518 
2519  /* ignore "parent" rowmarks; they are irrelevant at runtime */
2520  if (rc->isParent)
2521  continue;
2522 
2523  /* find ExecRowMark (same for all subplans) */
2524  erm = ExecFindRowMark(estate, rc->rti, false);
2525 
2526  /* build ExecAuxRowMark for each subplan */
2527  for (i = 0; i < nplans; i++)
2528  {
2529  ExecAuxRowMark *aerm;
2530 
2531  subplan = mtstate->mt_plans[i]->plan;
2532  aerm = ExecBuildAuxRowMark(erm, subplan->targetlist);
2533  mtstate->mt_arowmarks[i] = lappend(mtstate->mt_arowmarks[i], aerm);
2534  }
2535  }
2536 
2537  /* select first subplan */
2538  mtstate->mt_whichplan = 0;
2539  subplan = (Plan *) linitial(node->plans);
2540  EvalPlanQualSetPlan(&mtstate->mt_epqstate, subplan,
2541  mtstate->mt_arowmarks[0]);
2542 
2543  /*
2544  * Initialize the junk filter(s) if needed. INSERT queries need a filter
2545  * if there are any junk attrs in the tlist. UPDATE and DELETE always
2546  * need a filter, since there's always at least one junk attribute present
2547  * --- no need to look first. Typically, this will be a 'ctid' or
2548  * 'wholerow' attribute, but in the case of a foreign data wrapper it
2549  * might be a set of junk attributes sufficient to identify the remote
2550  * row.
2551  *
2552  * If there are multiple result relations, each one needs its own junk
2553  * filter. Note multiple rels are only possible for UPDATE/DELETE, so we
2554  * can't be fooled by some needing a filter and some not.
2555  *
2556  * This section of code is also a convenient place to verify that the
2557  * output of an INSERT or UPDATE matches the target table(s).
2558  */
2559  {
2560  bool junk_filter_needed = false;
2561 
2562  switch (operation)
2563  {
2564  case CMD_INSERT:
2565  foreach(l, subplan->targetlist)
2566  {
2567  TargetEntry *tle = (TargetEntry *) lfirst(l);
2568 
2569  if (tle->resjunk)
2570  {
2571  junk_filter_needed = true;
2572  break;
2573  }
2574  }
2575  break;
2576  case CMD_UPDATE:
2577  case CMD_DELETE:
2578  junk_filter_needed = true;
2579  break;
2580  default:
2581  elog(ERROR, "unknown operation");
2582  break;
2583  }
2584 
2585  if (junk_filter_needed)
2586  {
2587  resultRelInfo = mtstate->resultRelInfo;
2588  for (i = 0; i < nplans; i++)
2589  {
2590  JunkFilter *j;
2591  TupleTableSlot *junkresslot;
2592 
2593  subplan = mtstate->mt_plans[i]->plan;
2594  if (operation == CMD_INSERT || operation == CMD_UPDATE)
2595  ExecCheckPlanOutput(resultRelInfo->ri_RelationDesc,
2596  subplan->targetlist);
2597 
2598  junkresslot =
2599  ExecInitExtraTupleSlot(estate, NULL,
2600  table_slot_callbacks(resultRelInfo->ri_RelationDesc));
2601  j = ExecInitJunkFilter(subplan->targetlist,
2602  junkresslot);
2603 
2604  if (operation == CMD_UPDATE || operation == CMD_DELETE)
2605  {
2606  /* For UPDATE/DELETE, find the appropriate junk attr now */
2607  char relkind;
2608 
2609  relkind = resultRelInfo->ri_RelationDesc->rd_rel->relkind;
2610  if (relkind == RELKIND_RELATION ||
2611  relkind == RELKIND_MATVIEW ||
2612  relkind == RELKIND_PARTITIONED_TABLE)
2613  {
2614  j->jf_junkAttNo = ExecFindJunkAttribute(j, "ctid");
2616  elog(ERROR, "could not find junk ctid column");
2617  }
2618  else if (relkind == RELKIND_FOREIGN_TABLE)
2619  {
2620  /*
2621  * When there is a row-level trigger, there should be
2622  * a wholerow attribute.
2623  */
2624  j->jf_junkAttNo = ExecFindJunkAttribute(j, "wholerow");
2625  }
2626  else
2627  {
2628  j->jf_junkAttNo = ExecFindJunkAttribute(j, "wholerow");
2630  elog(ERROR, "could not find junk wholerow column");
2631  }
2632  }
2633 
2634  resultRelInfo->ri_junkFilter = j;
2635  resultRelInfo++;
2636  }
2637  }
2638  else
2639  {
2640  if (operation == CMD_INSERT)
2642  subplan->targetlist);
2643  }
2644  }
2645 
2646  /*
2647  * Lastly, if this is not the primary (canSetTag) ModifyTable node, add it
2648  * to estate->es_auxmodifytables so that it will be run to completion by
2649  * ExecPostprocessPlan. (It'd actually work fine to add the primary
2650  * ModifyTable node too, but there's no need.) Note the use of lcons not
2651  * lappend: we need later-initialized ModifyTable nodes to be shut down
2652  * before earlier ones. This ensures that we don't throw away RETURNING
2653  * rows that need to be seen by a later CTE subplan.
2654  */
2655  if (!mtstate->canSetTag)
2656  estate->es_auxmodifytables = lcons(mtstate,
2657  estate->es_auxmodifytables);
2658 
2659  return mtstate;
2660 }
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:465
List * arbiterIndexes
Definition: plannodes.h:229
Relation ri_RelationDesc
Definition: execnodes.h:412
Bitmapset * fdwDirectModifyPlans
Definition: plannodes.h:225
#define forboth(cell1, list1, cell2, list2)
Definition: pg_list.h:434
TupleTableSlot * ExecInitExtraTupleSlot(EState *estate, TupleDesc tupledesc, const TupleTableSlotOps *tts_ops)
Definition: execTuples.c:1801
struct PartitionTupleRouting * mt_partition_tuple_routing
Definition: execnodes.h:1187
#define RelationGetDescr(relation)
Definition: rel.h:482
List * withCheckOptionLists
Definition: plannodes.h:222
void ExecInitResultRelation(EState *estate, ResultRelInfo *resultRelInfo, Index rti)
Definition: execUtils.c:833
ResultRelInfo * resultRelInfo
Definition: execnodes.h:1168
AttrNumber ExecFindJunkAttribute(JunkFilter *junkfilter, const char *attrName)
Definition: execJunk.c:208
ExprContext * ps_ExprContext
Definition: execnodes.h:978
TupleTableSlot ** mt_scans
Definition: execnodes.h:1166
const TupleTableSlotOps * table_slot_callbacks(Relation relation)
Definition: tableam.c:58
const TupleTableSlotOps TTSOpsVirtual
Definition: execTuples.c:83
TupleConversionMap * ri_ChildToRootMap
Definition: execnodes.h:499
bool partColsUpdated
Definition: plannodes.h:219
bool canSetTag
Definition: plannodes.h:216
CmdType operation
Definition: execnodes.h:1160
ResultRelInfo * rootResultRelInfo
Definition: execnodes.h:1174
void EvalPlanQualSetPlan(EPQState *epqstate, Plan *subplan, List *auxrowmarks)
Definition: execMain.c:2428
EState * state
Definition: execnodes.h:941
Form_pg_class rd_rel
Definition: rel.h:109
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:151
List * ri_WithCheckOptionExprs
Definition: execnodes.h:453
#define linitial_int(l)
Definition: pg_list.h:175
TupleTableSlot * oc_Existing
Definition: execnodes.h:384
TupleTableSlot * ps_ResultTupleSlot
Definition: execnodes.h:977
List * rowMarks
Definition: plannodes.h:226
bool resjunk
Definition: primnodes.h:1417
#define linitial(l)
Definition: pg_list.h:174
#define ERROR
Definition: elog.h:43
PlanState ps
Definition: execnodes.h:1159
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:266
bool ri_usesFdwDirectModify
Definition: execnodes.h:447
static void ExecSetupTransitionCaptureState(ModifyTableState *mtstate, EState *estate)
void CheckValidResultRel(ResultRelInfo *resultRelInfo, CmdType operation)
Definition: execMain.c:995
#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:1190
void ExecInitResultTypeTL(PlanState *planstate)
Definition: execTuples.c:1725
List * fdwPrivLists
Definition: plannodes.h:224
EPQState mt_epqstate
Definition: execnodes.h:1177
bool trig_update_before_row
Definition: reltrigger.h:61
ProjectionInfo * ri_projectReturning
Definition: execnodes.h:471
struct FdwRoutine * ri_FdwRoutine
Definition: execnodes.h:441
ExprState * oc_WhereClause
Definition: execnodes.h:387
PartitionTupleRouting * ExecSetupPartitionTupleRouting(EState *estate, ModifyTableState *mtstate, Relation rel)
TriggerDesc * ri_TrigDesc
Definition: execnodes.h:424
List * lappend(List *list, void *datum)
Definition: list.c:321
PlanState ** mt_plans
Definition: execnodes.h:1163
void EvalPlanQualInit(EPQState *epqstate, EState *parentestate, Plan *subplan, List *auxrowmarks, int epqParam)
Definition: execMain.c:2390
OnConflictSetState * ri_onConflict
Definition: execnodes.h:477
#define AttributeNumberIsValid(attributeNumber)
Definition: attnum.h:34
static TupleTableSlot * ExecModifyTable(PlanState *pstate)
List * es_tupleTable
Definition: execnodes.h:561
void * palloc0(Size size)
Definition: mcxt.c:981
List * es_auxmodifytables
Definition: execnodes.h:573
ExecProcNodeMtd ExecProcNode
Definition: execnodes.h:945
List * ri_WithCheckOptions
Definition: execnodes.h:450
unsigned int Index
Definition: c.h:483
TupleDesc rd_att
Definition: rel.h:110
Plan * plan
Definition: execnodes.h:939
TupleTableSlot * oc_ProjSlot
Definition: execnodes.h:385
List * lcons(void *datum, List *list)
Definition: list.c:453
#define makeNode(_type_)
Definition: nodes.h:576
static void ExecCheckPlanOutput(Relation resultRel, List *targetList)
#define Assert(condition)
Definition: c.h:746
#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:479
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:1184
TupleDesc ExecGetResultType(PlanState *planstate)
Definition: execUtils.c:489
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:214
int i
List * returningLists
Definition: plannodes.h:223
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:474
CmdType
Definition: nodes.h:671
RelationPtr ri_IndexRelationDescs
Definition: execnodes.h:418
ExecAuxRowMark * ExecBuildAuxRowMark(ExecRowMark *erm, List *targetlist)
Definition: execMain.c:2266
List * ri_returningList
Definition: execnodes.h:468
List ** mt_arowmarks
Definition: execnodes.h:1176
int epqParam
Definition: plannodes.h:227
Node * onConflictWhere
Definition: plannodes.h:231
ExecRowMark * ExecFindRowMark(EState *estate, Index rti, bool missing_ok)
Definition: execMain.c:2243

◆ ExecReScanModifyTable()

void ExecReScanModifyTable ( ModifyTableState node)

Definition at line 2725 of file nodeModifyTable.c.

References elog, and ERROR.

Referenced by ExecReScan().

2726 {
2727  /*
2728  * Currently, we don't need to support rescan on ModifyTable nodes. The
2729  * semantics of that would be a bit debatable anyway.
2730  */
2731  elog(ERROR, "ExecReScanModifyTable is not implemented");
2732 }
#define ERROR
Definition: elog.h:43
#define elog(elevel,...)
Definition: elog.h:214