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 ExecInitStoredGenerated (ResultRelInfo *resultRelInfo, EState *estate, CmdType cmdtype)
 
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)
 
void ExecInitMergeTupleSlots (ModifyTableState *mtstate, ResultRelInfo *resultRelInfo)
 

Function Documentation

◆ ExecComputeStoredGenerated()

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

Definition at line 443 of file nodeModifyTable.c.

446 {
447  Relation rel = resultRelInfo->ri_RelationDesc;
448  TupleDesc tupdesc = RelationGetDescr(rel);
449  int natts = tupdesc->natts;
450  ExprContext *econtext = GetPerTupleExprContext(estate);
451  ExprState **ri_GeneratedExprs;
452  MemoryContext oldContext;
453  Datum *values;
454  bool *nulls;
455 
456  /* We should not be called unless this is true */
457  Assert(tupdesc->constr && tupdesc->constr->has_generated_stored);
458 
459  /*
460  * Initialize the expressions if we didn't already, and check whether we
461  * can exit early because nothing needs to be computed.
462  */
463  if (cmdtype == CMD_UPDATE)
464  {
465  if (resultRelInfo->ri_GeneratedExprsU == NULL)
466  ExecInitStoredGenerated(resultRelInfo, estate, cmdtype);
467  if (resultRelInfo->ri_NumGeneratedNeededU == 0)
468  return;
469  ri_GeneratedExprs = resultRelInfo->ri_GeneratedExprsU;
470  }
471  else
472  {
473  if (resultRelInfo->ri_GeneratedExprsI == NULL)
474  ExecInitStoredGenerated(resultRelInfo, estate, cmdtype);
475  /* Early exit is impossible given the prior Assert */
476  Assert(resultRelInfo->ri_NumGeneratedNeededI > 0);
477  ri_GeneratedExprs = resultRelInfo->ri_GeneratedExprsI;
478  }
479 
480  oldContext = MemoryContextSwitchTo(GetPerTupleMemoryContext(estate));
481 
482  values = palloc(sizeof(*values) * natts);
483  nulls = palloc(sizeof(*nulls) * natts);
484 
485  slot_getallattrs(slot);
486  memcpy(nulls, slot->tts_isnull, sizeof(*nulls) * natts);
487 
488  for (int i = 0; i < natts; i++)
489  {
490  Form_pg_attribute attr = TupleDescAttr(tupdesc, i);
491 
492  if (ri_GeneratedExprs[i])
493  {
494  Datum val;
495  bool isnull;
496 
497  Assert(attr->attgenerated == ATTRIBUTE_GENERATED_STORED);
498 
499  econtext->ecxt_scantuple = slot;
500 
501  val = ExecEvalExpr(ri_GeneratedExprs[i], econtext, &isnull);
502 
503  /*
504  * We must make a copy of val as we have no guarantees about where
505  * memory for a pass-by-reference Datum is located.
506  */
507  if (!isnull)
508  val = datumCopy(val, attr->attbyval, attr->attlen);
509 
510  values[i] = val;
511  nulls[i] = isnull;
512  }
513  else
514  {
515  if (!nulls[i])
516  values[i] = datumCopy(slot->tts_values[i], attr->attbyval, attr->attlen);
517  }
518  }
519 
520  ExecClearTuple(slot);
521  memcpy(slot->tts_values, values, sizeof(*values) * natts);
522  memcpy(slot->tts_isnull, nulls, sizeof(*nulls) * natts);
523  ExecStoreVirtualTuple(slot);
524  ExecMaterializeSlot(slot);
525 
526  MemoryContextSwitchTo(oldContext);
527 }
static Datum values[MAXATTR]
Definition: bootstrap.c:152
#define Assert(condition)
Definition: c.h:858
Datum datumCopy(Datum value, bool typByVal, int typLen)
Definition: datum.c:132
TupleTableSlot * ExecStoreVirtualTuple(TupleTableSlot *slot)
Definition: execTuples.c:1639
#define GetPerTupleExprContext(estate)
Definition: executor.h:550
#define GetPerTupleMemoryContext(estate)
Definition: executor.h:555
static Datum ExecEvalExpr(ExprState *state, ExprContext *econtext, bool *isNull)
Definition: executor.h:333
long val
Definition: informix.c:670
int i
Definition: isn.c:73
void * palloc(Size size)
Definition: mcxt.c:1316
void ExecInitStoredGenerated(ResultRelInfo *resultRelInfo, EState *estate, CmdType cmdtype)
@ CMD_UPDATE
Definition: nodes.h:266
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:209
uintptr_t Datum
Definition: postgres.h:64
MemoryContextSwitchTo(old_ctx)
#define RelationGetDescr(relation)
Definition: rel.h:531
TupleTableSlot * ecxt_scantuple
Definition: execnodes.h:255
Relation ri_RelationDesc
Definition: execnodes.h:456
ExprState ** ri_GeneratedExprsI
Definition: execnodes.h:528
int ri_NumGeneratedNeededU
Definition: execnodes.h:533
ExprState ** ri_GeneratedExprsU
Definition: execnodes.h:529
int ri_NumGeneratedNeededI
Definition: execnodes.h:532
bool has_generated_stored
Definition: tupdesc.h:45
TupleConstr * constr
Definition: tupdesc.h:85
bool * tts_isnull
Definition: tuptable.h:127
Datum * tts_values
Definition: tuptable.h:125
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92
static TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition: tuptable.h:454
static void slot_getallattrs(TupleTableSlot *slot)
Definition: tuptable.h:368
static void ExecMaterializeSlot(TupleTableSlot *slot)
Definition: tuptable.h:472

References Assert, CMD_UPDATE, TupleDescData::constr, datumCopy(), ExprContext::ecxt_scantuple, ExecClearTuple(), ExecEvalExpr(), ExecInitStoredGenerated(), ExecMaterializeSlot(), ExecStoreVirtualTuple(), GetPerTupleExprContext, GetPerTupleMemoryContext, TupleConstr::has_generated_stored, i, MemoryContextSwitchTo(), TupleDescData::natts, palloc(), RelationGetDescr, ResultRelInfo::ri_GeneratedExprsI, ResultRelInfo::ri_GeneratedExprsU, ResultRelInfo::ri_NumGeneratedNeededI, ResultRelInfo::ri_NumGeneratedNeededU, ResultRelInfo::ri_RelationDesc, slot_getallattrs(), TupleTableSlot::tts_isnull, TupleTableSlot::tts_values, TupleDescAttr, val, and values.

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

◆ ExecEndModifyTable()

void ExecEndModifyTable ( ModifyTableState node)

Definition at line 4680 of file nodeModifyTable.c.

4681 {
4682  int i;
4683 
4684  /*
4685  * Allow any FDWs to shut down
4686  */
4687  for (i = 0; i < node->mt_nrels; i++)
4688  {
4689  int j;
4690  ResultRelInfo *resultRelInfo = node->resultRelInfo + i;
4691 
4692  if (!resultRelInfo->ri_usesFdwDirectModify &&
4693  resultRelInfo->ri_FdwRoutine != NULL &&
4694  resultRelInfo->ri_FdwRoutine->EndForeignModify != NULL)
4695  resultRelInfo->ri_FdwRoutine->EndForeignModify(node->ps.state,
4696  resultRelInfo);
4697 
4698  /*
4699  * Cleanup the initialized batch slots. This only matters for FDWs
4700  * with batching, but the other cases will have ri_NumSlotsInitialized
4701  * == 0.
4702  */
4703  for (j = 0; j < resultRelInfo->ri_NumSlotsInitialized; j++)
4704  {
4705  ExecDropSingleTupleTableSlot(resultRelInfo->ri_Slots[j]);
4706  ExecDropSingleTupleTableSlot(resultRelInfo->ri_PlanSlots[j]);
4707  }
4708  }
4709 
4710  /*
4711  * Close all the partitioned tables, leaf partitions, and their indices
4712  * and release the slot used for tuple routing, if set.
4713  */
4714  if (node->mt_partition_tuple_routing)
4715  {
4717 
4718  if (node->mt_root_tuple_slot)
4720  }
4721 
4722  /*
4723  * Terminate EPQ execution if active
4724  */
4725  EvalPlanQualEnd(&node->mt_epqstate);
4726 
4727  /*
4728  * shut down subplan
4729  */
4730  ExecEndNode(outerPlanState(node));
4731 }
void EvalPlanQualEnd(EPQState *epqstate)
Definition: execMain.c:2982
void ExecCleanupTupleRouting(ModifyTableState *mtstate, PartitionTupleRouting *proute)
void ExecEndNode(PlanState *node)
Definition: execProcnode.c:557
void ExecDropSingleTupleTableSlot(TupleTableSlot *slot)
Definition: execTuples.c:1341
#define outerPlanState(node)
Definition: execnodes.h:1213
int j
Definition: isn.c:74
EndForeignModify_function EndForeignModify
Definition: fdwapi.h:237
ResultRelInfo * resultRelInfo
Definition: execnodes.h:1360
struct PartitionTupleRouting * mt_partition_tuple_routing
Definition: execnodes.h:1391
TupleTableSlot * mt_root_tuple_slot
Definition: execnodes.h:1388
EPQState mt_epqstate
Definition: execnodes.h:1370
PlanState ps
Definition: execnodes.h:1355
EState * state
Definition: execnodes.h:1119
TupleTableSlot ** ri_Slots
Definition: execnodes.h:515
int ri_NumSlotsInitialized
Definition: execnodes.h:513
struct FdwRoutine * ri_FdwRoutine
Definition: execnodes.h:503
TupleTableSlot ** ri_PlanSlots
Definition: execnodes.h:516
bool ri_usesFdwDirectModify
Definition: execnodes.h:509

References FdwRoutine::EndForeignModify, EvalPlanQualEnd(), ExecCleanupTupleRouting(), ExecDropSingleTupleTableSlot(), ExecEndNode(), i, j, ModifyTableState::mt_epqstate, ModifyTableState::mt_nrels, ModifyTableState::mt_partition_tuple_routing, ModifyTableState::mt_root_tuple_slot, outerPlanState, ModifyTableState::ps, ModifyTableState::resultRelInfo, ResultRelInfo::ri_FdwRoutine, ResultRelInfo::ri_NumSlotsInitialized, ResultRelInfo::ri_PlanSlots, ResultRelInfo::ri_Slots, ResultRelInfo::ri_usesFdwDirectModify, and PlanState::state.

Referenced by ExecEndNode().

◆ ExecInitMergeTupleSlots()

void ExecInitMergeTupleSlots ( ModifyTableState mtstate,
ResultRelInfo resultRelInfo 
)

Definition at line 3547 of file nodeModifyTable.c.

3549 {
3550  EState *estate = mtstate->ps.state;
3551 
3552  Assert(!resultRelInfo->ri_projectNewInfoValid);
3553 
3554  resultRelInfo->ri_oldTupleSlot =
3555  table_slot_create(resultRelInfo->ri_RelationDesc,
3556  &estate->es_tupleTable);
3557  resultRelInfo->ri_newTupleSlot =
3558  table_slot_create(resultRelInfo->ri_RelationDesc,
3559  &estate->es_tupleTable);
3560  resultRelInfo->ri_projectNewInfoValid = true;
3561 }
List * es_tupleTable
Definition: execnodes.h:669
bool ri_projectNewInfoValid
Definition: execnodes.h:483
TupleTableSlot * ri_oldTupleSlot
Definition: execnodes.h:481
TupleTableSlot * ri_newTupleSlot
Definition: execnodes.h:479
TupleTableSlot * table_slot_create(Relation relation, List **reglist)
Definition: tableam.c:91

References Assert, EState::es_tupleTable, ModifyTableState::ps, ResultRelInfo::ri_newTupleSlot, ResultRelInfo::ri_oldTupleSlot, ResultRelInfo::ri_projectNewInfoValid, ResultRelInfo::ri_RelationDesc, PlanState::state, and table_slot_create().

Referenced by ExecInitMerge(), and ExecInitPartitionInfo().

◆ ExecInitModifyTable()

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

Definition at line 4195 of file nodeModifyTable.c.

4196 {
4197  ModifyTableState *mtstate;
4198  Plan *subplan = outerPlan(node);
4199  CmdType operation = node->operation;
4200  int nrels = list_length(node->resultRelations);
4201  ResultRelInfo *resultRelInfo;
4202  List *arowmarks;
4203  ListCell *l;
4204  int i;
4205  Relation rel;
4206 
4207  /* check for unsupported flags */
4208  Assert(!(eflags & (EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK)));
4209 
4210  /*
4211  * create state structure
4212  */
4213  mtstate = makeNode(ModifyTableState);
4214  mtstate->ps.plan = (Plan *) node;
4215  mtstate->ps.state = estate;
4216  mtstate->ps.ExecProcNode = ExecModifyTable;
4217 
4218  mtstate->operation = operation;
4219  mtstate->canSetTag = node->canSetTag;
4220  mtstate->mt_done = false;
4221 
4222  mtstate->mt_nrels = nrels;
4223  mtstate->resultRelInfo = (ResultRelInfo *)
4224  palloc(nrels * sizeof(ResultRelInfo));
4225 
4226  mtstate->mt_merge_pending_not_matched = NULL;
4227  mtstate->mt_merge_inserted = 0;
4228  mtstate->mt_merge_updated = 0;
4229  mtstate->mt_merge_deleted = 0;
4230 
4231  /*----------
4232  * Resolve the target relation. This is the same as:
4233  *
4234  * - the relation for which we will fire FOR STATEMENT triggers,
4235  * - the relation into whose tuple format all captured transition tuples
4236  * must be converted, and
4237  * - the root partitioned table used for tuple routing.
4238  *
4239  * If it's a partitioned or inherited table, the root partition or
4240  * appendrel RTE doesn't appear elsewhere in the plan and its RT index is
4241  * given explicitly in node->rootRelation. Otherwise, the target relation
4242  * is the sole relation in the node->resultRelations list.
4243  *----------
4244  */
4245  if (node->rootRelation > 0)
4246  {
4248  ExecInitResultRelation(estate, mtstate->rootResultRelInfo,
4249  node->rootRelation);
4250  }
4251  else
4252  {
4253  Assert(list_length(node->resultRelations) == 1);
4254  mtstate->rootResultRelInfo = mtstate->resultRelInfo;
4255  ExecInitResultRelation(estate, mtstate->resultRelInfo,
4256  linitial_int(node->resultRelations));
4257  }
4258 
4259  /* set up epqstate with dummy subplan data for the moment */
4260  EvalPlanQualInit(&mtstate->mt_epqstate, estate, NULL, NIL,
4261  node->epqParam, node->resultRelations);
4262  mtstate->fireBSTriggers = true;
4263 
4264  /*
4265  * Build state for collecting transition tuples. This requires having a
4266  * valid trigger query context, so skip it in explain-only mode.
4267  */
4268  if (!(eflags & EXEC_FLAG_EXPLAIN_ONLY))
4269  ExecSetupTransitionCaptureState(mtstate, estate);
4270 
4271  /*
4272  * Open all the result relations and initialize the ResultRelInfo structs.
4273  * (But root relation was initialized above, if it's part of the array.)
4274  * We must do this before initializing the subplan, because direct-modify
4275  * FDWs expect their ResultRelInfos to be available.
4276  */
4277  resultRelInfo = mtstate->resultRelInfo;
4278  i = 0;
4279  foreach(l, node->resultRelations)
4280  {
4281  Index resultRelation = lfirst_int(l);
4282  List *mergeActions = NIL;
4283 
4284  if (node->mergeActionLists)
4285  mergeActions = list_nth(node->mergeActionLists, i);
4286 
4287  if (resultRelInfo != mtstate->rootResultRelInfo)
4288  {
4289  ExecInitResultRelation(estate, resultRelInfo, resultRelation);
4290 
4291  /*
4292  * For child result relations, store the root result relation
4293  * pointer. We do so for the convenience of places that want to
4294  * look at the query's original target relation but don't have the
4295  * mtstate handy.
4296  */
4297  resultRelInfo->ri_RootResultRelInfo = mtstate->rootResultRelInfo;
4298  }
4299 
4300  /* Initialize the usesFdwDirectModify flag */
4301  resultRelInfo->ri_usesFdwDirectModify =
4303 
4304  /*
4305  * Verify result relation is a valid target for the current operation
4306  */
4307  CheckValidResultRel(resultRelInfo, operation, mergeActions);
4308 
4309  resultRelInfo++;
4310  i++;
4311  }
4312 
4313  /*
4314  * Now we may initialize the subplan.
4315  */
4316  outerPlanState(mtstate) = ExecInitNode(subplan, estate, eflags);
4317 
4318  /*
4319  * Do additional per-result-relation initialization.
4320  */
4321  for (i = 0; i < nrels; i++)
4322  {
4323  resultRelInfo = &mtstate->resultRelInfo[i];
4324 
4325  /* Let FDWs init themselves for foreign-table result rels */
4326  if (!resultRelInfo->ri_usesFdwDirectModify &&
4327  resultRelInfo->ri_FdwRoutine != NULL &&
4328  resultRelInfo->ri_FdwRoutine->BeginForeignModify != NULL)
4329  {
4330  List *fdw_private = (List *) list_nth(node->fdwPrivLists, i);
4331 
4332  resultRelInfo->ri_FdwRoutine->BeginForeignModify(mtstate,
4333  resultRelInfo,
4334  fdw_private,
4335  i,
4336  eflags);
4337  }
4338 
4339  /*
4340  * For UPDATE/DELETE/MERGE, find the appropriate junk attr now, either
4341  * a 'ctid' or 'wholerow' attribute depending on relkind. For foreign
4342  * tables, the FDW might have created additional junk attr(s), but
4343  * those are no concern of ours.
4344  */
4345  if (operation == CMD_UPDATE || operation == CMD_DELETE ||
4346  operation == CMD_MERGE)
4347  {
4348  char relkind;
4349 
4350  relkind = resultRelInfo->ri_RelationDesc->rd_rel->relkind;
4351  if (relkind == RELKIND_RELATION ||
4352  relkind == RELKIND_MATVIEW ||
4353  relkind == RELKIND_PARTITIONED_TABLE)
4354  {
4355  resultRelInfo->ri_RowIdAttNo =
4356  ExecFindJunkAttributeInTlist(subplan->targetlist, "ctid");
4357  if (!AttributeNumberIsValid(resultRelInfo->ri_RowIdAttNo))
4358  elog(ERROR, "could not find junk ctid column");
4359  }
4360  else if (relkind == RELKIND_FOREIGN_TABLE)
4361  {
4362  /*
4363  * We don't support MERGE with foreign tables for now. (It's
4364  * problematic because the implementation uses CTID.)
4365  */
4366  Assert(operation != CMD_MERGE);
4367 
4368  /*
4369  * When there is a row-level trigger, there should be a
4370  * wholerow attribute. We also require it to be present in
4371  * UPDATE and MERGE, so we can get the values of unchanged
4372  * columns.
4373  */
4374  resultRelInfo->ri_RowIdAttNo =
4376  "wholerow");
4377  if ((mtstate->operation == CMD_UPDATE || mtstate->operation == CMD_MERGE) &&
4378  !AttributeNumberIsValid(resultRelInfo->ri_RowIdAttNo))
4379  elog(ERROR, "could not find junk wholerow column");
4380  }
4381  else
4382  {
4383  /* Other valid target relkinds must provide wholerow */
4384  resultRelInfo->ri_RowIdAttNo =
4386  "wholerow");
4387  if (!AttributeNumberIsValid(resultRelInfo->ri_RowIdAttNo))
4388  elog(ERROR, "could not find junk wholerow column");
4389  }
4390  }
4391  }
4392 
4393  /*
4394  * If this is an inherited update/delete/merge, there will be a junk
4395  * attribute named "tableoid" present in the subplan's targetlist. It
4396  * will be used to identify the result relation for a given tuple to be
4397  * updated/deleted/merged.
4398  */
4399  mtstate->mt_resultOidAttno =
4400  ExecFindJunkAttributeInTlist(subplan->targetlist, "tableoid");
4401  Assert(AttributeNumberIsValid(mtstate->mt_resultOidAttno) || nrels == 1);
4402  mtstate->mt_lastResultOid = InvalidOid; /* force lookup at first tuple */
4403  mtstate->mt_lastResultIndex = 0; /* must be zero if no such attr */
4404 
4405  /* Get the root target relation */
4406  rel = mtstate->rootResultRelInfo->ri_RelationDesc;
4407 
4408  /*
4409  * Build state for tuple routing if it's a partitioned INSERT. An UPDATE
4410  * or MERGE might need this too, but only if it actually moves tuples
4411  * between partitions; in that case setup is done by
4412  * ExecCrossPartitionUpdate.
4413  */
4414  if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE &&
4415  operation == CMD_INSERT)
4416  mtstate->mt_partition_tuple_routing =
4417  ExecSetupPartitionTupleRouting(estate, rel);
4418 
4419  /*
4420  * Initialize any WITH CHECK OPTION constraints if needed.
4421  */
4422  resultRelInfo = mtstate->resultRelInfo;
4423  foreach(l, node->withCheckOptionLists)
4424  {
4425  List *wcoList = (List *) lfirst(l);
4426  List *wcoExprs = NIL;
4427  ListCell *ll;
4428 
4429  foreach(ll, wcoList)
4430  {
4431  WithCheckOption *wco = (WithCheckOption *) lfirst(ll);
4432  ExprState *wcoExpr = ExecInitQual((List *) wco->qual,
4433  &mtstate->ps);
4434 
4435  wcoExprs = lappend(wcoExprs, wcoExpr);
4436  }
4437 
4438  resultRelInfo->ri_WithCheckOptions = wcoList;
4439  resultRelInfo->ri_WithCheckOptionExprs = wcoExprs;
4440  resultRelInfo++;
4441  }
4442 
4443  /*
4444  * Initialize RETURNING projections if needed.
4445  */
4446  if (node->returningLists)
4447  {
4448  TupleTableSlot *slot;
4449  ExprContext *econtext;
4450 
4451  /*
4452  * Initialize result tuple slot and assign its rowtype using the first
4453  * RETURNING list. We assume the rest will look the same.
4454  */
4455  mtstate->ps.plan->targetlist = (List *) linitial(node->returningLists);
4456 
4457  /* Set up a slot for the output of the RETURNING projection(s) */
4459  slot = mtstate->ps.ps_ResultTupleSlot;
4460 
4461  /* Need an econtext too */
4462  if (mtstate->ps.ps_ExprContext == NULL)
4463  ExecAssignExprContext(estate, &mtstate->ps);
4464  econtext = mtstate->ps.ps_ExprContext;
4465 
4466  /*
4467  * Build a projection for each result rel.
4468  */
4469  resultRelInfo = mtstate->resultRelInfo;
4470  foreach(l, node->returningLists)
4471  {
4472  List *rlist = (List *) lfirst(l);
4473 
4474  resultRelInfo->ri_returningList = rlist;
4475  resultRelInfo->ri_projectReturning =
4476  ExecBuildProjectionInfo(rlist, econtext, slot, &mtstate->ps,
4477  resultRelInfo->ri_RelationDesc->rd_att);
4478  resultRelInfo++;
4479  }
4480  }
4481  else
4482  {
4483  /*
4484  * We still must construct a dummy result tuple type, because InitPlan
4485  * expects one (maybe should change that?).
4486  */
4487  mtstate->ps.plan->targetlist = NIL;
4488  ExecInitResultTypeTL(&mtstate->ps);
4489 
4490  mtstate->ps.ps_ExprContext = NULL;
4491  }
4492 
4493  /* Set the list of arbiter indexes if needed for ON CONFLICT */
4494  resultRelInfo = mtstate->resultRelInfo;
4495  if (node->onConflictAction != ONCONFLICT_NONE)
4496  {
4497  /* insert may only have one relation, inheritance is not expanded */
4498  Assert(nrels == 1);
4499  resultRelInfo->ri_onConflictArbiterIndexes = node->arbiterIndexes;
4500  }
4501 
4502  /*
4503  * If needed, Initialize target list, projection and qual for ON CONFLICT
4504  * DO UPDATE.
4505  */
4506  if (node->onConflictAction == ONCONFLICT_UPDATE)
4507  {
4509  ExprContext *econtext;
4510  TupleDesc relationDesc;
4511 
4512  /* already exists if created by RETURNING processing above */
4513  if (mtstate->ps.ps_ExprContext == NULL)
4514  ExecAssignExprContext(estate, &mtstate->ps);
4515 
4516  econtext = mtstate->ps.ps_ExprContext;
4517  relationDesc = resultRelInfo->ri_RelationDesc->rd_att;
4518 
4519  /* create state for DO UPDATE SET operation */
4520  resultRelInfo->ri_onConflict = onconfl;
4521 
4522  /* initialize slot for the existing tuple */
4523  onconfl->oc_Existing =
4524  table_slot_create(resultRelInfo->ri_RelationDesc,
4525  &mtstate->ps.state->es_tupleTable);
4526 
4527  /*
4528  * Create the tuple slot for the UPDATE SET projection. We want a slot
4529  * of the table's type here, because the slot will be used to insert
4530  * into the table, and for RETURNING processing - which may access
4531  * system attributes.
4532  */
4533  onconfl->oc_ProjSlot =
4534  table_slot_create(resultRelInfo->ri_RelationDesc,
4535  &mtstate->ps.state->es_tupleTable);
4536 
4537  /* build UPDATE SET projection state */
4538  onconfl->oc_ProjInfo =
4540  true,
4541  node->onConflictCols,
4542  relationDesc,
4543  econtext,
4544  onconfl->oc_ProjSlot,
4545  &mtstate->ps);
4546 
4547  /* initialize state to evaluate the WHERE clause, if any */
4548  if (node->onConflictWhere)
4549  {
4550  ExprState *qualexpr;
4551 
4552  qualexpr = ExecInitQual((List *) node->onConflictWhere,
4553  &mtstate->ps);
4554  onconfl->oc_WhereClause = qualexpr;
4555  }
4556  }
4557 
4558  /*
4559  * If we have any secondary relations in an UPDATE or DELETE, they need to
4560  * be treated like non-locked relations in SELECT FOR UPDATE, i.e., the
4561  * EvalPlanQual mechanism needs to be told about them. This also goes for
4562  * the source relations in a MERGE. Locate the relevant ExecRowMarks.
4563  */
4564  arowmarks = NIL;
4565  foreach(l, node->rowMarks)
4566  {
4568  ExecRowMark *erm;
4569  ExecAuxRowMark *aerm;
4570 
4571  /* ignore "parent" rowmarks; they are irrelevant at runtime */
4572  if (rc->isParent)
4573  continue;
4574 
4575  /* Find ExecRowMark and build ExecAuxRowMark */
4576  erm = ExecFindRowMark(estate, rc->rti, false);
4577  aerm = ExecBuildAuxRowMark(erm, subplan->targetlist);
4578  arowmarks = lappend(arowmarks, aerm);
4579  }
4580 
4581  /* For a MERGE command, initialize its state */
4582  if (mtstate->operation == CMD_MERGE)
4583  ExecInitMerge(mtstate, estate);
4584 
4585  EvalPlanQualSetPlan(&mtstate->mt_epqstate, subplan, arowmarks);
4586 
4587  /*
4588  * If there are a lot of result relations, use a hash table to speed the
4589  * lookups. If there are not a lot, a simple linear search is faster.
4590  *
4591  * It's not clear where the threshold is, but try 64 for starters. In a
4592  * debugging build, use a small threshold so that we get some test
4593  * coverage of both code paths.
4594  */
4595 #ifdef USE_ASSERT_CHECKING
4596 #define MT_NRELS_HASH 4
4597 #else
4598 #define MT_NRELS_HASH 64
4599 #endif
4600  if (nrels >= MT_NRELS_HASH)
4601  {
4602  HASHCTL hash_ctl;
4603 
4604  hash_ctl.keysize = sizeof(Oid);
4605  hash_ctl.entrysize = sizeof(MTTargetRelLookup);
4606  hash_ctl.hcxt = CurrentMemoryContext;
4607  mtstate->mt_resultOidHash =
4608  hash_create("ModifyTable target hash",
4609  nrels, &hash_ctl,
4611  for (i = 0; i < nrels; i++)
4612  {
4613  Oid hashkey;
4614  MTTargetRelLookup *mtlookup;
4615  bool found;
4616 
4617  resultRelInfo = &mtstate->resultRelInfo[i];
4618  hashkey = RelationGetRelid(resultRelInfo->ri_RelationDesc);
4619  mtlookup = (MTTargetRelLookup *)
4620  hash_search(mtstate->mt_resultOidHash, &hashkey,
4621  HASH_ENTER, &found);
4622  Assert(!found);
4623  mtlookup->relationIndex = i;
4624  }
4625  }
4626  else
4627  mtstate->mt_resultOidHash = NULL;
4628 
4629  /*
4630  * Determine if the FDW supports batch insert and determine the batch size
4631  * (a FDW may support batching, but it may be disabled for the
4632  * server/table).
4633  *
4634  * We only do this for INSERT, so that for UPDATE/DELETE the batch size
4635  * remains set to 0.
4636  */
4637  if (operation == CMD_INSERT)
4638  {
4639  /* insert may only have one relation, inheritance is not expanded */
4640  Assert(nrels == 1);
4641  resultRelInfo = mtstate->resultRelInfo;
4642  if (!resultRelInfo->ri_usesFdwDirectModify &&
4643  resultRelInfo->ri_FdwRoutine != NULL &&
4644  resultRelInfo->ri_FdwRoutine->GetForeignModifyBatchSize &&
4645  resultRelInfo->ri_FdwRoutine->ExecForeignBatchInsert)
4646  {
4647  resultRelInfo->ri_BatchSize =
4648  resultRelInfo->ri_FdwRoutine->GetForeignModifyBatchSize(resultRelInfo);
4649  Assert(resultRelInfo->ri_BatchSize >= 1);
4650  }
4651  else
4652  resultRelInfo->ri_BatchSize = 1;
4653  }
4654 
4655  /*
4656  * Lastly, if this is not the primary (canSetTag) ModifyTable node, add it
4657  * to estate->es_auxmodifytables so that it will be run to completion by
4658  * ExecPostprocessPlan. (It'd actually work fine to add the primary
4659  * ModifyTable node too, but there's no need.) Note the use of lcons not
4660  * lappend: we need later-initialized ModifyTable nodes to be shut down
4661  * before earlier ones. This ensures that we don't throw away RETURNING
4662  * rows that need to be seen by a later CTE subplan.
4663  */
4664  if (!mtstate->canSetTag)
4665  estate->es_auxmodifytables = lcons(mtstate,
4666  estate->es_auxmodifytables);
4667 
4668  return mtstate;
4669 }
#define AttributeNumberIsValid(attributeNumber)
Definition: attnum.h:34
bool bms_is_member(int x, const Bitmapset *a)
Definition: bitmapset.c:510
unsigned int Index
Definition: c.h:614
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:955
HTAB * hash_create(const char *tabname, long nelem, const HASHCTL *info, int flags)
Definition: dynahash.c:352
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:224
ProjectionInfo * ExecBuildUpdateProjection(List *targetList, bool evalTargetList, List *targetColnos, TupleDesc relDesc, ExprContext *econtext, TupleTableSlot *slot, PlanState *parent)
Definition: execExpr.c:521
ExprState * ExecInitQual(List *qual, PlanState *parent)
Definition: execExpr.c:220
ProjectionInfo * ExecBuildProjectionInfo(List *targetList, ExprContext *econtext, TupleTableSlot *slot, PlanState *parent, TupleDesc inputDesc)
Definition: execExpr.c:361
AttrNumber ExecFindJunkAttributeInTlist(List *targetlist, const char *attrName)
Definition: execJunk.c:222
void CheckValidResultRel(ResultRelInfo *resultRelInfo, CmdType operation, List *mergeActions)
Definition: execMain.c:1026
void EvalPlanQualInit(EPQState *epqstate, EState *parentestate, Plan *subplan, List *auxrowmarks, int epqParam, List *resultRelations)
Definition: execMain.c:2539
ExecAuxRowMark * ExecBuildAuxRowMark(ExecRowMark *erm, List *targetlist)
Definition: execMain.c:2400
void EvalPlanQualSetPlan(EPQState *epqstate, Plan *subplan, List *auxrowmarks)
Definition: execMain.c:2581
ExecRowMark * ExecFindRowMark(EState *estate, Index rti, bool missing_ok)
Definition: execMain.c:2377
PartitionTupleRouting * ExecSetupPartitionTupleRouting(EState *estate, Relation rel)
PlanState * ExecInitNode(Plan *node, EState *estate, int eflags)
Definition: execProcnode.c:142
const TupleTableSlotOps TTSOpsVirtual
Definition: execTuples.c:84
void ExecInitResultTypeTL(PlanState *planstate)
Definition: execTuples.c:1842
void ExecInitResultTupleSlotTL(PlanState *planstate, const TupleTableSlotOps *tts_ops)
Definition: execTuples.c:1886
void ExecInitResultRelation(EState *estate, ResultRelInfo *resultRelInfo, Index rti)
Definition: execUtils.c:814
void ExecAssignExprContext(EState *estate, PlanState *planstate)
Definition: execUtils.c:483
#define EXEC_FLAG_BACKWARD
Definition: executor.h:68
#define EXEC_FLAG_EXPLAIN_ONLY
Definition: executor.h:65
#define EXEC_FLAG_MARK
Definition: executor.h:69
@ HASH_ENTER
Definition: hsearch.h:114
#define HASH_CONTEXT
Definition: hsearch.h:102
#define HASH_ELEM
Definition: hsearch.h:95
#define HASH_BLOBS
Definition: hsearch.h:97
List * lappend(List *list, void *datum)
Definition: list.c:339
List * lcons(void *datum, List *list)
Definition: list.c:495
MemoryContext CurrentMemoryContext
Definition: mcxt.c:143
static void ExecSetupTransitionCaptureState(ModifyTableState *mtstate, EState *estate)
static TupleTableSlot * ExecModifyTable(PlanState *pstate)
struct MTTargetRelLookup MTTargetRelLookup
#define MT_NRELS_HASH
static void ExecInitMerge(ModifyTableState *mtstate, EState *estate)
@ ONCONFLICT_NONE
Definition: nodes.h:417
@ ONCONFLICT_UPDATE
Definition: nodes.h:419
CmdType
Definition: nodes.h:263
@ CMD_MERGE
Definition: nodes.h:269
@ CMD_INSERT
Definition: nodes.h:267
@ CMD_DELETE
Definition: nodes.h:268
#define makeNode(_type_)
Definition: nodes.h:155
#define lfirst(lc)
Definition: pg_list.h:172
#define lfirst_node(type, lc)
Definition: pg_list.h:176
static int list_length(const List *l)
Definition: pg_list.h:152
#define NIL
Definition: pg_list.h:68
#define lfirst_int(lc)
Definition: pg_list.h:173
#define linitial_int(l)
Definition: pg_list.h:179
#define linitial(l)
Definition: pg_list.h:178
static void * list_nth(const List *list, int n)
Definition: pg_list.h:299
#define outerPlan(node)
Definition: plannodes.h:182
#define InvalidOid
Definition: postgres_ext.h:36
unsigned int Oid
Definition: postgres_ext.h:31
#define RelationGetRelid(relation)
Definition: rel.h:505
List * es_auxmodifytables
Definition: execnodes.h:684
BeginForeignModify_function BeginForeignModify
Definition: fdwapi.h:231
ExecForeignBatchInsert_function ExecForeignBatchInsert
Definition: fdwapi.h:233
GetForeignModifyBatchSize_function GetForeignModifyBatchSize
Definition: fdwapi.h:234
Size keysize
Definition: hsearch.h:75
Size entrysize
Definition: hsearch.h:76
MemoryContext hcxt
Definition: hsearch.h:86
Definition: pg_list.h:54
CmdType operation
Definition: execnodes.h:1356
TupleTableSlot * mt_merge_pending_not_matched
Definition: execnodes.h:1410
double mt_merge_deleted
Definition: execnodes.h:1415
double mt_merge_inserted
Definition: execnodes.h:1413
double mt_merge_updated
Definition: execnodes.h:1414
HTAB * mt_resultOidHash
Definition: execnodes.h:1382
ResultRelInfo * rootResultRelInfo
Definition: execnodes.h:1368
List * arbiterIndexes
Definition: plannodes.h:246
List * onConflictCols
Definition: plannodes.h:248
CmdType operation
Definition: plannodes.h:232
int epqParam
Definition: plannodes.h:244
List * resultRelations
Definition: plannodes.h:237
Bitmapset * fdwDirectModifyPlans
Definition: plannodes.h:242
List * onConflictSet
Definition: plannodes.h:247
List * mergeActionLists
Definition: plannodes.h:252
bool canSetTag
Definition: plannodes.h:233
List * fdwPrivLists
Definition: plannodes.h:241
List * returningLists
Definition: plannodes.h:240
List * withCheckOptionLists
Definition: plannodes.h:239
Index rootRelation
Definition: plannodes.h:235
Node * onConflictWhere
Definition: plannodes.h:249
List * rowMarks
Definition: plannodes.h:243
OnConflictAction onConflictAction
Definition: plannodes.h:245
TupleTableSlot * oc_ProjSlot
Definition: execnodes.h:410
TupleTableSlot * oc_Existing
Definition: execnodes.h:409
ExprState * oc_WhereClause
Definition: execnodes.h:412
ProjectionInfo * oc_ProjInfo
Definition: execnodes.h:411
bool isParent
Definition: plannodes.h:1389
Plan * plan
Definition: execnodes.h:1117
ExprContext * ps_ExprContext
Definition: execnodes.h:1156
TupleTableSlot * ps_ResultTupleSlot
Definition: execnodes.h:1155
ExecProcNodeMtd ExecProcNode
Definition: execnodes.h:1123
List * targetlist
Definition: plannodes.h:152
TupleDesc rd_att
Definition: rel.h:112
Form_pg_class rd_rel
Definition: rel.h:111
OnConflictSetState * ri_onConflict
Definition: execnodes.h:545
List * ri_onConflictArbiterIndexes
Definition: execnodes.h:542
struct ResultRelInfo * ri_RootResultRelInfo
Definition: execnodes.h:582
List * ri_WithCheckOptions
Definition: execnodes.h:519
List * ri_WithCheckOptionExprs
Definition: execnodes.h:522
ProjectionInfo * ri_projectReturning
Definition: execnodes.h:539
List * ri_returningList
Definition: execnodes.h:536
AttrNumber ri_RowIdAttNo
Definition: execnodes.h:471
int ri_BatchSize
Definition: execnodes.h:514

References ModifyTable::arbiterIndexes, Assert, AttributeNumberIsValid, FdwRoutine::BeginForeignModify, bms_is_member(), ModifyTableState::canSetTag, ModifyTable::canSetTag, CheckValidResultRel(), CMD_DELETE, CMD_INSERT, CMD_MERGE, CMD_UPDATE, CurrentMemoryContext, elog, HASHCTL::entrysize, ModifyTable::epqParam, ERROR, EState::es_auxmodifytables, EState::es_tupleTable, EvalPlanQualInit(), EvalPlanQualSetPlan(), EXEC_FLAG_BACKWARD, EXEC_FLAG_EXPLAIN_ONLY, EXEC_FLAG_MARK, ExecAssignExprContext(), ExecBuildAuxRowMark(), ExecBuildProjectionInfo(), ExecBuildUpdateProjection(), ExecFindJunkAttributeInTlist(), ExecFindRowMark(), FdwRoutine::ExecForeignBatchInsert, ExecInitMerge(), ExecInitNode(), ExecInitQual(), ExecInitResultRelation(), ExecInitResultTupleSlotTL(), ExecInitResultTypeTL(), ExecModifyTable(), PlanState::ExecProcNode, ExecSetupPartitionTupleRouting(), ExecSetupTransitionCaptureState(), ModifyTable::fdwDirectModifyPlans, ModifyTable::fdwPrivLists, ModifyTableState::fireBSTriggers, FdwRoutine::GetForeignModifyBatchSize, HASH_BLOBS, HASH_CONTEXT, hash_create(), HASH_ELEM, HASH_ENTER, hash_search(), HASHCTL::hcxt, i, InvalidOid, PlanRowMark::isParent, HASHCTL::keysize, lappend(), lcons(), lfirst, lfirst_int, lfirst_node, linitial, linitial_int, list_length(), list_nth(), makeNode, ModifyTable::mergeActionLists, ModifyTableState::mt_done, ModifyTableState::mt_epqstate, ModifyTableState::mt_lastResultIndex, ModifyTableState::mt_lastResultOid, ModifyTableState::mt_merge_deleted, ModifyTableState::mt_merge_inserted, ModifyTableState::mt_merge_pending_not_matched, ModifyTableState::mt_merge_updated, ModifyTableState::mt_nrels, MT_NRELS_HASH, ModifyTableState::mt_partition_tuple_routing, ModifyTableState::mt_resultOidAttno, ModifyTableState::mt_resultOidHash, NIL, OnConflictSetState::oc_Existing, OnConflictSetState::oc_ProjInfo, OnConflictSetState::oc_ProjSlot, OnConflictSetState::oc_WhereClause, ONCONFLICT_NONE, ONCONFLICT_UPDATE, ModifyTable::onConflictAction, ModifyTable::onConflictCols, ModifyTable::onConflictSet, ModifyTable::onConflictWhere, ModifyTableState::operation, ModifyTable::operation, outerPlan, outerPlanState, palloc(), PlanState::plan, ModifyTableState::ps, PlanState::ps_ExprContext, PlanState::ps_ResultTupleSlot, WithCheckOption::qual, RelationData::rd_att, RelationData::rd_rel, RelationGetRelid, MTTargetRelLookup::relationIndex, ModifyTable::resultRelations, ModifyTableState::resultRelInfo, ModifyTable::returningLists, ResultRelInfo::ri_BatchSize, ResultRelInfo::ri_FdwRoutine, ResultRelInfo::ri_onConflict, ResultRelInfo::ri_onConflictArbiterIndexes, ResultRelInfo::ri_projectReturning, ResultRelInfo::ri_RelationDesc, ResultRelInfo::ri_returningList, ResultRelInfo::ri_RootResultRelInfo, ResultRelInfo::ri_RowIdAttNo, ResultRelInfo::ri_usesFdwDirectModify, ResultRelInfo::ri_WithCheckOptionExprs, ResultRelInfo::ri_WithCheckOptions, ModifyTable::rootRelation, ModifyTableState::rootResultRelInfo, ModifyTable::rowMarks, PlanRowMark::rti, PlanState::state, table_slot_create(), Plan::targetlist, TTSOpsVirtual, and ModifyTable::withCheckOptionLists.

Referenced by ExecInitNode().

◆ ExecInitStoredGenerated()

void ExecInitStoredGenerated ( ResultRelInfo resultRelInfo,
EState estate,
CmdType  cmdtype 
)

Definition at line 343 of file nodeModifyTable.c.

346 {
347  Relation rel = resultRelInfo->ri_RelationDesc;
348  TupleDesc tupdesc = RelationGetDescr(rel);
349  int natts = tupdesc->natts;
350  ExprState **ri_GeneratedExprs;
351  int ri_NumGeneratedNeeded;
352  Bitmapset *updatedCols;
353  MemoryContext oldContext;
354 
355  /* Nothing to do if no generated columns */
356  if (!(tupdesc->constr && tupdesc->constr->has_generated_stored))
357  return;
358 
359  /*
360  * In an UPDATE, we can skip computing any generated columns that do not
361  * depend on any UPDATE target column. But if there is a BEFORE ROW
362  * UPDATE trigger, we cannot skip because the trigger might change more
363  * columns.
364  */
365  if (cmdtype == CMD_UPDATE &&
366  !(rel->trigdesc && rel->trigdesc->trig_update_before_row))
367  updatedCols = ExecGetUpdatedCols(resultRelInfo, estate);
368  else
369  updatedCols = NULL;
370 
371  /*
372  * Make sure these data structures are built in the per-query memory
373  * context so they'll survive throughout the query.
374  */
375  oldContext = MemoryContextSwitchTo(estate->es_query_cxt);
376 
377  ri_GeneratedExprs = (ExprState **) palloc0(natts * sizeof(ExprState *));
378  ri_NumGeneratedNeeded = 0;
379 
380  for (int i = 0; i < natts; i++)
381  {
382  if (TupleDescAttr(tupdesc, i)->attgenerated == ATTRIBUTE_GENERATED_STORED)
383  {
384  Expr *expr;
385 
386  /* Fetch the GENERATED AS expression tree */
387  expr = (Expr *) build_column_default(rel, i + 1);
388  if (expr == NULL)
389  elog(ERROR, "no generation expression found for column number %d of table \"%s\"",
390  i + 1, RelationGetRelationName(rel));
391 
392  /*
393  * If it's an update with a known set of update target columns,
394  * see if we can skip the computation.
395  */
396  if (updatedCols)
397  {
398  Bitmapset *attrs_used = NULL;
399 
400  pull_varattnos((Node *) expr, 1, &attrs_used);
401 
402  if (!bms_overlap(updatedCols, attrs_used))
403  continue; /* need not update this column */
404  }
405 
406  /* No luck, so prepare the expression for execution */
407  ri_GeneratedExprs[i] = ExecPrepareExpr(expr, estate);
408  ri_NumGeneratedNeeded++;
409 
410  /* If UPDATE, mark column in resultRelInfo->ri_extraUpdatedCols */
411  if (cmdtype == CMD_UPDATE)
412  resultRelInfo->ri_extraUpdatedCols =
413  bms_add_member(resultRelInfo->ri_extraUpdatedCols,
415  }
416  }
417 
418  /* Save in appropriate set of fields */
419  if (cmdtype == CMD_UPDATE)
420  {
421  /* Don't call twice */
422  Assert(resultRelInfo->ri_GeneratedExprsU == NULL);
423 
424  resultRelInfo->ri_GeneratedExprsU = ri_GeneratedExprs;
425  resultRelInfo->ri_NumGeneratedNeededU = ri_NumGeneratedNeeded;
426  }
427  else
428  {
429  /* Don't call twice */
430  Assert(resultRelInfo->ri_GeneratedExprsI == NULL);
431 
432  resultRelInfo->ri_GeneratedExprsI = ri_GeneratedExprs;
433  resultRelInfo->ri_NumGeneratedNeededI = ri_NumGeneratedNeeded;
434  }
435 
436  MemoryContextSwitchTo(oldContext);
437 }
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition: bitmapset.c:815
bool bms_overlap(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:582
ExprState * ExecPrepareExpr(Expr *node, EState *estate)
Definition: execExpr.c:739
Bitmapset * ExecGetUpdatedCols(ResultRelInfo *relinfo, EState *estate)
Definition: execUtils.c:1288
void * palloc0(Size size)
Definition: mcxt.c:1346
#define RelationGetRelationName(relation)
Definition: rel.h:539
Node * build_column_default(Relation rel, int attrno)
MemoryContext es_query_cxt
Definition: execnodes.h:667
Definition: nodes.h:129
TriggerDesc * trigdesc
Definition: rel.h:117
Bitmapset * ri_extraUpdatedCols
Definition: execnodes.h:474
bool trig_update_before_row
Definition: reltrigger.h:61
#define FirstLowInvalidHeapAttributeNumber
Definition: sysattr.h:27
void pull_varattnos(Node *node, Index varno, Bitmapset **varattnos)
Definition: var.c:291

References Assert, bms_add_member(), bms_overlap(), build_column_default(), CMD_UPDATE, TupleDescData::constr, elog, ERROR, EState::es_query_cxt, ExecGetUpdatedCols(), ExecPrepareExpr(), FirstLowInvalidHeapAttributeNumber, TupleConstr::has_generated_stored, i, MemoryContextSwitchTo(), TupleDescData::natts, palloc0(), pull_varattnos(), RelationGetDescr, RelationGetRelationName, ResultRelInfo::ri_extraUpdatedCols, ResultRelInfo::ri_GeneratedExprsI, ResultRelInfo::ri_GeneratedExprsU, ResultRelInfo::ri_NumGeneratedNeededI, ResultRelInfo::ri_NumGeneratedNeededU, ResultRelInfo::ri_RelationDesc, TriggerDesc::trig_update_before_row, RelationData::trigdesc, and TupleDescAttr.

Referenced by ExecComputeStoredGenerated(), and ExecGetExtraUpdatedCols().

◆ ExecReScanModifyTable()

void ExecReScanModifyTable ( ModifyTableState node)

Definition at line 4734 of file nodeModifyTable.c.

4735 {
4736  /*
4737  * Currently, we don't need to support rescan on ModifyTable nodes. The
4738  * semantics of that would be a bit debatable anyway.
4739  */
4740  elog(ERROR, "ExecReScanModifyTable is not implemented");
4741 }

References elog, and ERROR.

Referenced by ExecReScan().