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 446 of file nodeModifyTable.c.

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

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 4406 of file nodeModifyTable.c.

4407 {
4408  int i;
4409 
4410  /*
4411  * Allow any FDWs to shut down
4412  */
4413  for (i = 0; i < node->mt_nrels; i++)
4414  {
4415  int j;
4416  ResultRelInfo *resultRelInfo = node->resultRelInfo + i;
4417 
4418  if (!resultRelInfo->ri_usesFdwDirectModify &&
4419  resultRelInfo->ri_FdwRoutine != NULL &&
4420  resultRelInfo->ri_FdwRoutine->EndForeignModify != NULL)
4421  resultRelInfo->ri_FdwRoutine->EndForeignModify(node->ps.state,
4422  resultRelInfo);
4423 
4424  /*
4425  * Cleanup the initialized batch slots. This only matters for FDWs
4426  * with batching, but the other cases will have ri_NumSlotsInitialized
4427  * == 0.
4428  */
4429  for (j = 0; j < resultRelInfo->ri_NumSlotsInitialized; j++)
4430  {
4431  ExecDropSingleTupleTableSlot(resultRelInfo->ri_Slots[j]);
4432  ExecDropSingleTupleTableSlot(resultRelInfo->ri_PlanSlots[j]);
4433  }
4434  }
4435 
4436  /*
4437  * Close all the partitioned tables, leaf partitions, and their indices
4438  * and release the slot used for tuple routing, if set.
4439  */
4440  if (node->mt_partition_tuple_routing)
4441  {
4443 
4444  if (node->mt_root_tuple_slot)
4446  }
4447 
4448  /*
4449  * Free the exprcontext
4450  */
4451  ExecFreeExprContext(&node->ps);
4452 
4453  /*
4454  * clean out the tuple table
4455  */
4456  if (node->ps.ps_ResultTupleSlot)
4458 
4459  /*
4460  * Terminate EPQ execution if active
4461  */
4462  EvalPlanQualEnd(&node->mt_epqstate);
4463 
4464  /*
4465  * shut down subplan
4466  */
4467  ExecEndNode(outerPlanState(node));
4468 }
void EvalPlanQualEnd(EPQState *epqstate)
Definition: execMain.c:2997
void ExecCleanupTupleRouting(ModifyTableState *mtstate, PartitionTupleRouting *proute)
void ExecEndNode(PlanState *node)
Definition: execProcnode.c:557
void ExecDropSingleTupleTableSlot(TupleTableSlot *slot)
Definition: execTuples.c:1255
void ExecFreeExprContext(PlanState *planstate)
Definition: execUtils.c:658
#define outerPlanState(node)
Definition: execnodes.h:1133
int j
Definition: isn.c:74
EndForeignModify_function EndForeignModify
Definition: fdwapi.h:237
ResultRelInfo * resultRelInfo
Definition: execnodes.h:1280
struct PartitionTupleRouting * mt_partition_tuple_routing
Definition: execnodes.h:1311
TupleTableSlot * mt_root_tuple_slot
Definition: execnodes.h:1308
EPQState mt_epqstate
Definition: execnodes.h:1290
PlanState ps
Definition: execnodes.h:1275
EState * state
Definition: execnodes.h:1039
TupleTableSlot * ps_ResultTupleSlot
Definition: execnodes.h:1075
TupleTableSlot ** ri_Slots
Definition: execnodes.h:509
int ri_NumSlotsInitialized
Definition: execnodes.h:507
struct FdwRoutine * ri_FdwRoutine
Definition: execnodes.h:497
TupleTableSlot ** ri_PlanSlots
Definition: execnodes.h:510
bool ri_usesFdwDirectModify
Definition: execnodes.h:503

References FdwRoutine::EndForeignModify, EvalPlanQualEnd(), ExecCleanupTupleRouting(), ExecClearTuple(), ExecDropSingleTupleTableSlot(), ExecEndNode(), ExecFreeExprContext(), i, j, ModifyTableState::mt_epqstate, ModifyTableState::mt_nrels, ModifyTableState::mt_partition_tuple_routing, ModifyTableState::mt_root_tuple_slot, outerPlanState, ModifyTableState::ps, PlanState::ps_ResultTupleSlot, 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 3347 of file nodeModifyTable.c.

3349 {
3350  EState *estate = mtstate->ps.state;
3351 
3352  Assert(!resultRelInfo->ri_projectNewInfoValid);
3353 
3354  resultRelInfo->ri_oldTupleSlot =
3355  table_slot_create(resultRelInfo->ri_RelationDesc,
3356  &estate->es_tupleTable);
3357  resultRelInfo->ri_newTupleSlot =
3358  table_slot_create(resultRelInfo->ri_RelationDesc,
3359  &estate->es_tupleTable);
3360  resultRelInfo->ri_projectNewInfoValid = true;
3361 }
List * es_tupleTable
Definition: execnodes.h:661
bool ri_projectNewInfoValid
Definition: execnodes.h:477
TupleTableSlot * ri_oldTupleSlot
Definition: execnodes.h:475
TupleTableSlot * ri_newTupleSlot
Definition: execnodes.h:473
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 3925 of file nodeModifyTable.c.

3926 {
3927  ModifyTableState *mtstate;
3928  Plan *subplan = outerPlan(node);
3929  CmdType operation = node->operation;
3930  int nrels = list_length(node->resultRelations);
3931  ResultRelInfo *resultRelInfo;
3932  List *arowmarks;
3933  ListCell *l;
3934  int i;
3935  Relation rel;
3936 
3937  /* check for unsupported flags */
3938  Assert(!(eflags & (EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK)));
3939 
3940  /*
3941  * create state structure
3942  */
3943  mtstate = makeNode(ModifyTableState);
3944  mtstate->ps.plan = (Plan *) node;
3945  mtstate->ps.state = estate;
3946  mtstate->ps.ExecProcNode = ExecModifyTable;
3947 
3948  mtstate->operation = operation;
3949  mtstate->canSetTag = node->canSetTag;
3950  mtstate->mt_done = false;
3951 
3952  mtstate->mt_nrels = nrels;
3953  mtstate->resultRelInfo = (ResultRelInfo *)
3954  palloc(nrels * sizeof(ResultRelInfo));
3955 
3956  mtstate->mt_merge_inserted = 0;
3957  mtstate->mt_merge_updated = 0;
3958  mtstate->mt_merge_deleted = 0;
3959 
3960  /*----------
3961  * Resolve the target relation. This is the same as:
3962  *
3963  * - the relation for which we will fire FOR STATEMENT triggers,
3964  * - the relation into whose tuple format all captured transition tuples
3965  * must be converted, and
3966  * - the root partitioned table used for tuple routing.
3967  *
3968  * If it's a partitioned table, the root partition doesn't appear
3969  * elsewhere in the plan and its RT index is given explicitly in
3970  * node->rootRelation. Otherwise (i.e. table inheritance) the target
3971  * relation is the first relation in the node->resultRelations list.
3972  *----------
3973  */
3974  if (node->rootRelation > 0)
3975  {
3977  ExecInitResultRelation(estate, mtstate->rootResultRelInfo,
3978  node->rootRelation);
3979  }
3980  else
3981  {
3982  mtstate->rootResultRelInfo = mtstate->resultRelInfo;
3983  ExecInitResultRelation(estate, mtstate->resultRelInfo,
3984  linitial_int(node->resultRelations));
3985  }
3986 
3987  /* set up epqstate with dummy subplan data for the moment */
3988  EvalPlanQualInit(&mtstate->mt_epqstate, estate, NULL, NIL,
3989  node->epqParam, node->resultRelations);
3990  mtstate->fireBSTriggers = true;
3991 
3992  /*
3993  * Build state for collecting transition tuples. This requires having a
3994  * valid trigger query context, so skip it in explain-only mode.
3995  */
3996  if (!(eflags & EXEC_FLAG_EXPLAIN_ONLY))
3997  ExecSetupTransitionCaptureState(mtstate, estate);
3998 
3999  /*
4000  * Open all the result relations and initialize the ResultRelInfo structs.
4001  * (But root relation was initialized above, if it's part of the array.)
4002  * We must do this before initializing the subplan, because direct-modify
4003  * FDWs expect their ResultRelInfos to be available.
4004  */
4005  resultRelInfo = mtstate->resultRelInfo;
4006  i = 0;
4007  foreach(l, node->resultRelations)
4008  {
4009  Index resultRelation = lfirst_int(l);
4010 
4011  if (resultRelInfo != mtstate->rootResultRelInfo)
4012  {
4013  ExecInitResultRelation(estate, resultRelInfo, resultRelation);
4014 
4015  /*
4016  * For child result relations, store the root result relation
4017  * pointer. We do so for the convenience of places that want to
4018  * look at the query's original target relation but don't have the
4019  * mtstate handy.
4020  */
4021  resultRelInfo->ri_RootResultRelInfo = mtstate->rootResultRelInfo;
4022  }
4023 
4024  /* Initialize the usesFdwDirectModify flag */
4025  resultRelInfo->ri_usesFdwDirectModify =
4027 
4028  /*
4029  * Verify result relation is a valid target for the current operation
4030  */
4031  CheckValidResultRel(resultRelInfo, operation);
4032 
4033  resultRelInfo++;
4034  i++;
4035  }
4036 
4037  /*
4038  * Now we may initialize the subplan.
4039  */
4040  outerPlanState(mtstate) = ExecInitNode(subplan, estate, eflags);
4041 
4042  /*
4043  * Do additional per-result-relation initialization.
4044  */
4045  for (i = 0; i < nrels; i++)
4046  {
4047  resultRelInfo = &mtstate->resultRelInfo[i];
4048 
4049  /* Let FDWs init themselves for foreign-table result rels */
4050  if (!resultRelInfo->ri_usesFdwDirectModify &&
4051  resultRelInfo->ri_FdwRoutine != NULL &&
4052  resultRelInfo->ri_FdwRoutine->BeginForeignModify != NULL)
4053  {
4054  List *fdw_private = (List *) list_nth(node->fdwPrivLists, i);
4055 
4056  resultRelInfo->ri_FdwRoutine->BeginForeignModify(mtstate,
4057  resultRelInfo,
4058  fdw_private,
4059  i,
4060  eflags);
4061  }
4062 
4063  /*
4064  * For UPDATE/DELETE/MERGE, find the appropriate junk attr now, either
4065  * a 'ctid' or 'wholerow' attribute depending on relkind. For foreign
4066  * tables, the FDW might have created additional junk attr(s), but
4067  * those are no concern of ours.
4068  */
4069  if (operation == CMD_UPDATE || operation == CMD_DELETE ||
4070  operation == CMD_MERGE)
4071  {
4072  char relkind;
4073 
4074  relkind = resultRelInfo->ri_RelationDesc->rd_rel->relkind;
4075  if (relkind == RELKIND_RELATION ||
4076  relkind == RELKIND_MATVIEW ||
4077  relkind == RELKIND_PARTITIONED_TABLE)
4078  {
4079  resultRelInfo->ri_RowIdAttNo =
4080  ExecFindJunkAttributeInTlist(subplan->targetlist, "ctid");
4081  if (!AttributeNumberIsValid(resultRelInfo->ri_RowIdAttNo))
4082  elog(ERROR, "could not find junk ctid column");
4083  }
4084  else if (relkind == RELKIND_FOREIGN_TABLE)
4085  {
4086  /*
4087  * We don't support MERGE with foreign tables for now. (It's
4088  * problematic because the implementation uses CTID.)
4089  */
4090  Assert(operation != CMD_MERGE);
4091 
4092  /*
4093  * When there is a row-level trigger, there should be a
4094  * wholerow attribute. We also require it to be present in
4095  * UPDATE and MERGE, so we can get the values of unchanged
4096  * columns.
4097  */
4098  resultRelInfo->ri_RowIdAttNo =
4100  "wholerow");
4101  if ((mtstate->operation == CMD_UPDATE || mtstate->operation == CMD_MERGE) &&
4102  !AttributeNumberIsValid(resultRelInfo->ri_RowIdAttNo))
4103  elog(ERROR, "could not find junk wholerow column");
4104  }
4105  else
4106  {
4107  /* No support for MERGE */
4108  Assert(operation != CMD_MERGE);
4109  /* Other valid target relkinds must provide wholerow */
4110  resultRelInfo->ri_RowIdAttNo =
4112  "wholerow");
4113  if (!AttributeNumberIsValid(resultRelInfo->ri_RowIdAttNo))
4114  elog(ERROR, "could not find junk wholerow column");
4115  }
4116  }
4117  }
4118 
4119  /*
4120  * If this is an inherited update/delete/merge, there will be a junk
4121  * attribute named "tableoid" present in the subplan's targetlist. It
4122  * will be used to identify the result relation for a given tuple to be
4123  * updated/deleted/merged.
4124  */
4125  mtstate->mt_resultOidAttno =
4126  ExecFindJunkAttributeInTlist(subplan->targetlist, "tableoid");
4127  Assert(AttributeNumberIsValid(mtstate->mt_resultOidAttno) || nrels == 1);
4128  mtstate->mt_lastResultOid = InvalidOid; /* force lookup at first tuple */
4129  mtstate->mt_lastResultIndex = 0; /* must be zero if no such attr */
4130 
4131  /* Get the root target relation */
4132  rel = mtstate->rootResultRelInfo->ri_RelationDesc;
4133 
4134  /*
4135  * Build state for tuple routing if it's a partitioned INSERT. An UPDATE
4136  * or MERGE might need this too, but only if it actually moves tuples
4137  * between partitions; in that case setup is done by
4138  * ExecCrossPartitionUpdate.
4139  */
4140  if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE &&
4141  operation == CMD_INSERT)
4142  mtstate->mt_partition_tuple_routing =
4143  ExecSetupPartitionTupleRouting(estate, rel);
4144 
4145  /*
4146  * Initialize any WITH CHECK OPTION constraints if needed.
4147  */
4148  resultRelInfo = mtstate->resultRelInfo;
4149  foreach(l, node->withCheckOptionLists)
4150  {
4151  List *wcoList = (List *) lfirst(l);
4152  List *wcoExprs = NIL;
4153  ListCell *ll;
4154 
4155  foreach(ll, wcoList)
4156  {
4157  WithCheckOption *wco = (WithCheckOption *) lfirst(ll);
4158  ExprState *wcoExpr = ExecInitQual((List *) wco->qual,
4159  &mtstate->ps);
4160 
4161  wcoExprs = lappend(wcoExprs, wcoExpr);
4162  }
4163 
4164  resultRelInfo->ri_WithCheckOptions = wcoList;
4165  resultRelInfo->ri_WithCheckOptionExprs = wcoExprs;
4166  resultRelInfo++;
4167  }
4168 
4169  /*
4170  * Initialize RETURNING projections if needed.
4171  */
4172  if (node->returningLists)
4173  {
4174  TupleTableSlot *slot;
4175  ExprContext *econtext;
4176 
4177  /*
4178  * Initialize result tuple slot and assign its rowtype using the first
4179  * RETURNING list. We assume the rest will look the same.
4180  */
4181  mtstate->ps.plan->targetlist = (List *) linitial(node->returningLists);
4182 
4183  /* Set up a slot for the output of the RETURNING projection(s) */
4185  slot = mtstate->ps.ps_ResultTupleSlot;
4186 
4187  /* Need an econtext too */
4188  if (mtstate->ps.ps_ExprContext == NULL)
4189  ExecAssignExprContext(estate, &mtstate->ps);
4190  econtext = mtstate->ps.ps_ExprContext;
4191 
4192  /*
4193  * Build a projection for each result rel.
4194  */
4195  resultRelInfo = mtstate->resultRelInfo;
4196  foreach(l, node->returningLists)
4197  {
4198  List *rlist = (List *) lfirst(l);
4199 
4200  resultRelInfo->ri_returningList = rlist;
4201  resultRelInfo->ri_projectReturning =
4202  ExecBuildProjectionInfo(rlist, econtext, slot, &mtstate->ps,
4203  resultRelInfo->ri_RelationDesc->rd_att);
4204  resultRelInfo++;
4205  }
4206  }
4207  else
4208  {
4209  /*
4210  * We still must construct a dummy result tuple type, because InitPlan
4211  * expects one (maybe should change that?).
4212  */
4213  mtstate->ps.plan->targetlist = NIL;
4214  ExecInitResultTypeTL(&mtstate->ps);
4215 
4216  mtstate->ps.ps_ExprContext = NULL;
4217  }
4218 
4219  /* Set the list of arbiter indexes if needed for ON CONFLICT */
4220  resultRelInfo = mtstate->resultRelInfo;
4221  if (node->onConflictAction != ONCONFLICT_NONE)
4222  {
4223  /* insert may only have one relation, inheritance is not expanded */
4224  Assert(nrels == 1);
4225  resultRelInfo->ri_onConflictArbiterIndexes = node->arbiterIndexes;
4226  }
4227 
4228  /*
4229  * If needed, Initialize target list, projection and qual for ON CONFLICT
4230  * DO UPDATE.
4231  */
4232  if (node->onConflictAction == ONCONFLICT_UPDATE)
4233  {
4235  ExprContext *econtext;
4236  TupleDesc relationDesc;
4237 
4238  /* already exists if created by RETURNING processing above */
4239  if (mtstate->ps.ps_ExprContext == NULL)
4240  ExecAssignExprContext(estate, &mtstate->ps);
4241 
4242  econtext = mtstate->ps.ps_ExprContext;
4243  relationDesc = resultRelInfo->ri_RelationDesc->rd_att;
4244 
4245  /* create state for DO UPDATE SET operation */
4246  resultRelInfo->ri_onConflict = onconfl;
4247 
4248  /* initialize slot for the existing tuple */
4249  onconfl->oc_Existing =
4250  table_slot_create(resultRelInfo->ri_RelationDesc,
4251  &mtstate->ps.state->es_tupleTable);
4252 
4253  /*
4254  * Create the tuple slot for the UPDATE SET projection. We want a slot
4255  * of the table's type here, because the slot will be used to insert
4256  * into the table, and for RETURNING processing - which may access
4257  * system attributes.
4258  */
4259  onconfl->oc_ProjSlot =
4260  table_slot_create(resultRelInfo->ri_RelationDesc,
4261  &mtstate->ps.state->es_tupleTable);
4262 
4263  /* build UPDATE SET projection state */
4264  onconfl->oc_ProjInfo =
4266  true,
4267  node->onConflictCols,
4268  relationDesc,
4269  econtext,
4270  onconfl->oc_ProjSlot,
4271  &mtstate->ps);
4272 
4273  /* initialize state to evaluate the WHERE clause, if any */
4274  if (node->onConflictWhere)
4275  {
4276  ExprState *qualexpr;
4277 
4278  qualexpr = ExecInitQual((List *) node->onConflictWhere,
4279  &mtstate->ps);
4280  onconfl->oc_WhereClause = qualexpr;
4281  }
4282  }
4283 
4284  /*
4285  * If we have any secondary relations in an UPDATE or DELETE, they need to
4286  * be treated like non-locked relations in SELECT FOR UPDATE, ie, the
4287  * EvalPlanQual mechanism needs to be told about them. Locate the
4288  * relevant ExecRowMarks.
4289  */
4290  arowmarks = NIL;
4291  foreach(l, node->rowMarks)
4292  {
4294  ExecRowMark *erm;
4295  ExecAuxRowMark *aerm;
4296 
4297  /* ignore "parent" rowmarks; they are irrelevant at runtime */
4298  if (rc->isParent)
4299  continue;
4300 
4301  /* Find ExecRowMark and build ExecAuxRowMark */
4302  erm = ExecFindRowMark(estate, rc->rti, false);
4303  aerm = ExecBuildAuxRowMark(erm, subplan->targetlist);
4304  arowmarks = lappend(arowmarks, aerm);
4305  }
4306 
4307  /* For a MERGE command, initialize its state */
4308  if (mtstate->operation == CMD_MERGE)
4309  ExecInitMerge(mtstate, estate);
4310 
4311  EvalPlanQualSetPlan(&mtstate->mt_epqstate, subplan, arowmarks);
4312 
4313  /*
4314  * If there are a lot of result relations, use a hash table to speed the
4315  * lookups. If there are not a lot, a simple linear search is faster.
4316  *
4317  * It's not clear where the threshold is, but try 64 for starters. In a
4318  * debugging build, use a small threshold so that we get some test
4319  * coverage of both code paths.
4320  */
4321 #ifdef USE_ASSERT_CHECKING
4322 #define MT_NRELS_HASH 4
4323 #else
4324 #define MT_NRELS_HASH 64
4325 #endif
4326  if (nrels >= MT_NRELS_HASH)
4327  {
4328  HASHCTL hash_ctl;
4329 
4330  hash_ctl.keysize = sizeof(Oid);
4331  hash_ctl.entrysize = sizeof(MTTargetRelLookup);
4332  hash_ctl.hcxt = CurrentMemoryContext;
4333  mtstate->mt_resultOidHash =
4334  hash_create("ModifyTable target hash",
4335  nrels, &hash_ctl,
4337  for (i = 0; i < nrels; i++)
4338  {
4339  Oid hashkey;
4340  MTTargetRelLookup *mtlookup;
4341  bool found;
4342 
4343  resultRelInfo = &mtstate->resultRelInfo[i];
4344  hashkey = RelationGetRelid(resultRelInfo->ri_RelationDesc);
4345  mtlookup = (MTTargetRelLookup *)
4346  hash_search(mtstate->mt_resultOidHash, &hashkey,
4347  HASH_ENTER, &found);
4348  Assert(!found);
4349  mtlookup->relationIndex = i;
4350  }
4351  }
4352  else
4353  mtstate->mt_resultOidHash = NULL;
4354 
4355  /*
4356  * Determine if the FDW supports batch insert and determine the batch size
4357  * (a FDW may support batching, but it may be disabled for the
4358  * server/table).
4359  *
4360  * We only do this for INSERT, so that for UPDATE/DELETE the batch size
4361  * remains set to 0.
4362  */
4363  if (operation == CMD_INSERT)
4364  {
4365  /* insert may only have one relation, inheritance is not expanded */
4366  Assert(nrels == 1);
4367  resultRelInfo = mtstate->resultRelInfo;
4368  if (!resultRelInfo->ri_usesFdwDirectModify &&
4369  resultRelInfo->ri_FdwRoutine != NULL &&
4370  resultRelInfo->ri_FdwRoutine->GetForeignModifyBatchSize &&
4371  resultRelInfo->ri_FdwRoutine->ExecForeignBatchInsert)
4372  {
4373  resultRelInfo->ri_BatchSize =
4374  resultRelInfo->ri_FdwRoutine->GetForeignModifyBatchSize(resultRelInfo);
4375  Assert(resultRelInfo->ri_BatchSize >= 1);
4376  }
4377  else
4378  resultRelInfo->ri_BatchSize = 1;
4379  }
4380 
4381  /*
4382  * Lastly, if this is not the primary (canSetTag) ModifyTable node, add it
4383  * to estate->es_auxmodifytables so that it will be run to completion by
4384  * ExecPostprocessPlan. (It'd actually work fine to add the primary
4385  * ModifyTable node too, but there's no need.) Note the use of lcons not
4386  * lappend: we need later-initialized ModifyTable nodes to be shut down
4387  * before earlier ones. This ensures that we don't throw away RETURNING
4388  * rows that need to be seen by a later CTE subplan.
4389  */
4390  if (!mtstate->canSetTag)
4391  estate->es_auxmodifytables = lcons(mtstate,
4392  estate->es_auxmodifytables);
4393 
4394  return mtstate;
4395 }
#define AttributeNumberIsValid(attributeNumber)
Definition: attnum.h:34
bool bms_is_member(int x, const Bitmapset *a)
Definition: bitmapset.c:444
unsigned int Index
Definition: c.h:598
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:953
HTAB * hash_create(const char *tabname, long nelem, const HASHCTL *info, int flags)
Definition: dynahash.c:350
#define ERROR
Definition: elog.h:39
ProjectionInfo * ExecBuildUpdateProjection(List *targetList, bool evalTargetList, List *targetColnos, TupleDesc relDesc, ExprContext *econtext, TupleTableSlot *slot, PlanState *parent)
Definition: execExpr.c:517
ExprState * ExecInitQual(List *qual, PlanState *parent)
Definition: execExpr.c:213
ProjectionInfo * ExecBuildProjectionInfo(List *targetList, ExprContext *econtext, TupleTableSlot *slot, PlanState *parent, TupleDesc inputDesc)
Definition: execExpr.c:357
AttrNumber ExecFindJunkAttributeInTlist(List *targetlist, const char *attrName)
Definition: execJunk.c:222
void EvalPlanQualInit(EPQState *epqstate, EState *parentestate, Plan *subplan, List *auxrowmarks, int epqParam, List *resultRelations)
Definition: execMain.c:2554
ExecAuxRowMark * ExecBuildAuxRowMark(ExecRowMark *erm, List *targetlist)
Definition: execMain.c:2415
void EvalPlanQualSetPlan(EPQState *epqstate, Plan *subplan, List *auxrowmarks)
Definition: execMain.c:2596
ExecRowMark * ExecFindRowMark(EState *estate, Index rti, bool missing_ok)
Definition: execMain.c:2392
void CheckValidResultRel(ResultRelInfo *resultRelInfo, CmdType operation)
Definition: execMain.c:1015
PartitionTupleRouting * ExecSetupPartitionTupleRouting(EState *estate, Relation rel)
PlanState * ExecInitNode(Plan *node, EState *estate, int eflags)
Definition: execProcnode.c:142
const TupleTableSlotOps TTSOpsVirtual
Definition: execTuples.c:83
void ExecInitResultTypeTL(PlanState *planstate)
Definition: execTuples.c:1756
void ExecInitResultTupleSlotTL(PlanState *planstate, const TupleTableSlotOps *tts_ops)
Definition: execTuples.c:1800
void ExecInitResultRelation(EState *estate, ResultRelInfo *resultRelInfo, Index rti)
Definition: execUtils.c:845
void ExecAssignExprContext(EState *estate, PlanState *planstate)
Definition: execUtils.c:488
#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:338
List * lcons(void *datum, List *list)
Definition: list.c:494
MemoryContext CurrentMemoryContext
Definition: mcxt.c:135
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:428
@ ONCONFLICT_UPDATE
Definition: nodes.h:430
CmdType
Definition: nodes.h:274
@ CMD_MERGE
Definition: nodes.h:280
@ CMD_INSERT
Definition: nodes.h:278
@ CMD_DELETE
Definition: nodes.h:279
#define makeNode(_type_)
Definition: nodes.h:176
#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:183
#define InvalidOid
Definition: postgres_ext.h:36
unsigned int Oid
Definition: postgres_ext.h:31
#define RelationGetRelid(relation)
Definition: rel.h:504
List * es_auxmodifytables
Definition: execnodes.h:676
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:1276
double mt_merge_deleted
Definition: execnodes.h:1325
double mt_merge_inserted
Definition: execnodes.h:1323
double mt_merge_updated
Definition: execnodes.h:1324
HTAB * mt_resultOidHash
Definition: execnodes.h:1302
ResultRelInfo * rootResultRelInfo
Definition: execnodes.h:1288
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
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:404
TupleTableSlot * oc_Existing
Definition: execnodes.h:403
ExprState * oc_WhereClause
Definition: execnodes.h:406
ProjectionInfo * oc_ProjInfo
Definition: execnodes.h:405
bool isParent
Definition: plannodes.h:1387
Plan * plan
Definition: execnodes.h:1037
ExprContext * ps_ExprContext
Definition: execnodes.h:1076
ExecProcNodeMtd ExecProcNode
Definition: execnodes.h:1043
List * targetlist
Definition: plannodes.h:153
TupleDesc rd_att
Definition: rel.h:112
Form_pg_class rd_rel
Definition: rel.h:111
OnConflictSetState * ri_onConflict
Definition: execnodes.h:539
List * ri_onConflictArbiterIndexes
Definition: execnodes.h:536
struct ResultRelInfo * ri_RootResultRelInfo
Definition: execnodes.h:574
List * ri_WithCheckOptions
Definition: execnodes.h:513
List * ri_WithCheckOptionExprs
Definition: execnodes.h:516
ProjectionInfo * ri_projectReturning
Definition: execnodes.h:533
List * ri_returningList
Definition: execnodes.h:530
AttrNumber ri_RowIdAttNo
Definition: execnodes.h:465
int ri_BatchSize
Definition: execnodes.h:508

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, ModifyTableState::mt_done, ModifyTableState::mt_epqstate, ModifyTableState::mt_lastResultIndex, ModifyTableState::mt_lastResultOid, ModifyTableState::mt_merge_deleted, ModifyTableState::mt_merge_inserted, 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 346 of file nodeModifyTable.c.

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

4472 {
4473  /*
4474  * Currently, we don't need to support rescan on ModifyTable nodes. The
4475  * semantics of that would be a bit debatable anyway.
4476  */
4477  elog(ERROR, "ExecReScanModifyTable is not implemented");
4478 }

References elog(), and ERROR.

Referenced by ExecReScan().