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)
 
void ExecInitMergeTupleSlots (ModifyTableState *mtstate, ResultRelInfo *resultRelInfo)
 

Function Documentation

◆ ExecComputeStoredGenerated()

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

Definition at line 359 of file nodeModifyTable.c.

362 {
363  Relation rel = resultRelInfo->ri_RelationDesc;
364  TupleDesc tupdesc = RelationGetDescr(rel);
365  int natts = tupdesc->natts;
366  MemoryContext oldContext;
367  Datum *values;
368  bool *nulls;
369 
370  Assert(tupdesc->constr && tupdesc->constr->has_generated_stored);
371 
372  /*
373  * If first time through for this result relation, build expression
374  * nodetrees for rel's stored generation expressions. Keep them in the
375  * per-query memory context so they'll survive throughout the query.
376  */
377  if (resultRelInfo->ri_GeneratedExprs == NULL)
378  {
379  oldContext = MemoryContextSwitchTo(estate->es_query_cxt);
380 
381  resultRelInfo->ri_GeneratedExprs =
382  (ExprState **) palloc(natts * sizeof(ExprState *));
383  resultRelInfo->ri_NumGeneratedNeeded = 0;
384 
385  for (int i = 0; i < natts; i++)
386  {
387  if (TupleDescAttr(tupdesc, i)->attgenerated == ATTRIBUTE_GENERATED_STORED)
388  {
389  Expr *expr;
390 
391  /*
392  * If it's an update and the current column was not marked as
393  * being updated, then we can skip the computation. But if
394  * there is a BEFORE ROW UPDATE trigger, we cannot skip
395  * because the trigger might affect additional columns.
396  */
397  if (cmdtype == CMD_UPDATE &&
398  !(rel->trigdesc && rel->trigdesc->trig_update_before_row) &&
400  ExecGetExtraUpdatedCols(resultRelInfo, estate)))
401  {
402  resultRelInfo->ri_GeneratedExprs[i] = NULL;
403  continue;
404  }
405 
406  expr = (Expr *) build_column_default(rel, i + 1);
407  if (expr == NULL)
408  elog(ERROR, "no generation expression found for column number %d of table \"%s\"",
409  i + 1, RelationGetRelationName(rel));
410 
411  resultRelInfo->ri_GeneratedExprs[i] = ExecPrepareExpr(expr, estate);
412  resultRelInfo->ri_NumGeneratedNeeded++;
413  }
414  }
415 
416  MemoryContextSwitchTo(oldContext);
417  }
418 
419  /*
420  * If no generated columns have been affected by this change, then skip
421  * the rest.
422  */
423  if (resultRelInfo->ri_NumGeneratedNeeded == 0)
424  return;
425 
426  oldContext = MemoryContextSwitchTo(GetPerTupleMemoryContext(estate));
427 
428  values = palloc(sizeof(*values) * natts);
429  nulls = palloc(sizeof(*nulls) * natts);
430 
431  slot_getallattrs(slot);
432  memcpy(nulls, slot->tts_isnull, sizeof(*nulls) * natts);
433 
434  for (int i = 0; i < natts; i++)
435  {
436  Form_pg_attribute attr = TupleDescAttr(tupdesc, i);
437 
438  if (attr->attgenerated == ATTRIBUTE_GENERATED_STORED &&
439  resultRelInfo->ri_GeneratedExprs[i])
440  {
441  ExprContext *econtext;
442  Datum val;
443  bool isnull;
444 
445  econtext = GetPerTupleExprContext(estate);
446  econtext->ecxt_scantuple = slot;
447 
448  val = ExecEvalExpr(resultRelInfo->ri_GeneratedExprs[i], econtext, &isnull);
449 
450  /*
451  * We must make a copy of val as we have no guarantees about where
452  * memory for a pass-by-reference Datum is located.
453  */
454  if (!isnull)
455  val = datumCopy(val, attr->attbyval, attr->attlen);
456 
457  values[i] = val;
458  nulls[i] = isnull;
459  }
460  else
461  {
462  if (!nulls[i])
463  values[i] = datumCopy(slot->tts_values[i], attr->attbyval, attr->attlen);
464  }
465  }
466 
467  ExecClearTuple(slot);
468  memcpy(slot->tts_values, values, sizeof(*values) * natts);
469  memcpy(slot->tts_isnull, nulls, sizeof(*nulls) * natts);
470  ExecStoreVirtualTuple(slot);
471  ExecMaterializeSlot(slot);
472 
473  MemoryContextSwitchTo(oldContext);
474 }
bool bms_is_member(int x, const Bitmapset *a)
Definition: bitmapset.c:428
static Datum values[MAXATTR]
Definition: bootstrap.c:156
Datum datumCopy(Datum value, bool typByVal, int typLen)
Definition: datum.c:132
#define ERROR
Definition: elog.h:35
ExprState * ExecPrepareExpr(Expr *node, EState *estate)
Definition: execExpr.c:747
TupleTableSlot * ExecStoreVirtualTuple(TupleTableSlot *slot)
Definition: execTuples.c:1552
Bitmapset * ExecGetExtraUpdatedCols(ResultRelInfo *relinfo, EState *estate)
Definition: execUtils.c:1322
#define GetPerTupleExprContext(estate)
Definition: executor.h:535
#define GetPerTupleMemoryContext(estate)
Definition: executor.h:540
static Datum ExecEvalExpr(ExprState *state, ExprContext *econtext, bool *isNull)
Definition: executor.h:318
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:1199
@ CMD_UPDATE
Definition: nodes.h:260
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:135
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:207
uintptr_t Datum
Definition: postgres.h:412
#define RelationGetDescr(relation)
Definition: rel.h:527
#define RelationGetRelationName(relation)
Definition: rel.h:535
Node * build_column_default(Relation rel, int attrno)
MemoryContext es_query_cxt
Definition: execnodes.h:650
TupleTableSlot * ecxt_scantuple
Definition: execnodes.h:247
TriggerDesc * trigdesc
Definition: rel.h:116
Relation ri_RelationDesc
Definition: execnodes.h:448
ExprState ** ri_GeneratedExprs
Definition: execnodes.h:517
int ri_NumGeneratedNeeded
Definition: execnodes.h:520
bool trig_update_before_row
Definition: reltrigger.h:61
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 FirstLowInvalidHeapAttributeNumber
Definition: sysattr.h:27
#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(), bms_is_member(), build_column_default(), CMD_UPDATE, TupleDescData::constr, datumCopy(), ExprContext::ecxt_scantuple, elog(), ERROR, EState::es_query_cxt, ExecClearTuple(), ExecEvalExpr(), ExecGetExtraUpdatedCols(), ExecMaterializeSlot(), ExecPrepareExpr(), ExecStoreVirtualTuple(), FirstLowInvalidHeapAttributeNumber, GetPerTupleExprContext, GetPerTupleMemoryContext, TupleConstr::has_generated_stored, i, MemoryContextSwitchTo(), TupleDescData::natts, palloc(), RelationGetDescr, RelationGetRelationName, ResultRelInfo::ri_GeneratedExprs, ResultRelInfo::ri_NumGeneratedNeeded, ResultRelInfo::ri_RelationDesc, slot_getallattrs(), TriggerDesc::trig_update_before_row, RelationData::trigdesc, TupleTableSlot::tts_isnull, TupleTableSlot::tts_values, TupleDescAttr, val, and values.

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

◆ ExecEndModifyTable()

void ExecEndModifyTable ( ModifyTableState node)

Definition at line 4379 of file nodeModifyTable.c.

4380 {
4381  int i;
4382 
4383  /*
4384  * Allow any FDWs to shut down
4385  */
4386  for (i = 0; i < node->mt_nrels; i++)
4387  {
4388  int j;
4389  ResultRelInfo *resultRelInfo = node->resultRelInfo + i;
4390 
4391  if (!resultRelInfo->ri_usesFdwDirectModify &&
4392  resultRelInfo->ri_FdwRoutine != NULL &&
4393  resultRelInfo->ri_FdwRoutine->EndForeignModify != NULL)
4394  resultRelInfo->ri_FdwRoutine->EndForeignModify(node->ps.state,
4395  resultRelInfo);
4396 
4397  /*
4398  * Cleanup the initialized batch slots. This only matters for FDWs
4399  * with batching, but the other cases will have ri_NumSlotsInitialized
4400  * == 0.
4401  */
4402  for (j = 0; j < resultRelInfo->ri_NumSlotsInitialized; j++)
4403  {
4404  ExecDropSingleTupleTableSlot(resultRelInfo->ri_Slots[j]);
4405  ExecDropSingleTupleTableSlot(resultRelInfo->ri_PlanSlots[j]);
4406  }
4407  }
4408 
4409  /*
4410  * Close all the partitioned tables, leaf partitions, and their indices
4411  * and release the slot used for tuple routing, if set.
4412  */
4413  if (node->mt_partition_tuple_routing)
4414  {
4416 
4417  if (node->mt_root_tuple_slot)
4419  }
4420 
4421  /*
4422  * Free the exprcontext
4423  */
4424  ExecFreeExprContext(&node->ps);
4425 
4426  /*
4427  * clean out the tuple table
4428  */
4429  if (node->ps.ps_ResultTupleSlot)
4431 
4432  /*
4433  * Terminate EPQ execution if active
4434  */
4435  EvalPlanQualEnd(&node->mt_epqstate);
4436 
4437  /*
4438  * shut down subplan
4439  */
4440  ExecEndNode(outerPlanState(node));
4441 }
void EvalPlanQualEnd(EPQState *epqstate)
Definition: execMain.c:2933
void ExecCleanupTupleRouting(ModifyTableState *mtstate, PartitionTupleRouting *proute)
void ExecEndNode(PlanState *node)
Definition: execProcnode.c:557
void ExecDropSingleTupleTableSlot(TupleTableSlot *slot)
Definition: execTuples.c:1254
void ExecFreeExprContext(PlanState *planstate)
Definition: execUtils.c:651
#define outerPlanState(node)
Definition: execnodes.h:1120
int j
Definition: isn.c:74
EndForeignModify_function EndForeignModify
Definition: fdwapi.h:237
ResultRelInfo * resultRelInfo
Definition: execnodes.h:1256
struct PartitionTupleRouting * mt_partition_tuple_routing
Definition: execnodes.h:1287
TupleTableSlot * mt_root_tuple_slot
Definition: execnodes.h:1284
EPQState mt_epqstate
Definition: execnodes.h:1266
PlanState ps
Definition: execnodes.h:1251
EState * state
Definition: execnodes.h:1026
TupleTableSlot * ps_ResultTupleSlot
Definition: execnodes.h:1062
TupleTableSlot ** ri_Slots
Definition: execnodes.h:504
int ri_NumSlotsInitialized
Definition: execnodes.h:502
struct FdwRoutine * ri_FdwRoutine
Definition: execnodes.h:492
TupleTableSlot ** ri_PlanSlots
Definition: execnodes.h:505
bool ri_usesFdwDirectModify
Definition: execnodes.h:498

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

3296 {
3297  EState *estate = mtstate->ps.state;
3298 
3299  Assert(!resultRelInfo->ri_projectNewInfoValid);
3300 
3301  resultRelInfo->ri_oldTupleSlot =
3302  table_slot_create(resultRelInfo->ri_RelationDesc,
3303  &estate->es_tupleTable);
3304  resultRelInfo->ri_newTupleSlot =
3305  table_slot_create(resultRelInfo->ri_RelationDesc,
3306  &estate->es_tupleTable);
3307  resultRelInfo->ri_projectNewInfoValid = true;
3308 }
List * es_tupleTable
Definition: execnodes.h:652
bool ri_projectNewInfoValid
Definition: execnodes.h:472
TupleTableSlot * ri_oldTupleSlot
Definition: execnodes.h:470
TupleTableSlot * ri_newTupleSlot
Definition: execnodes.h:468
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 3892 of file nodeModifyTable.c.

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

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

◆ ExecReScanModifyTable()

void ExecReScanModifyTable ( ModifyTableState node)

Definition at line 4444 of file nodeModifyTable.c.

4445 {
4446  /*
4447  * Currently, we don't need to support rescan on ModifyTable nodes. The
4448  * semantics of that would be a bit debatable anyway.
4449  */
4450  elog(ERROR, "ExecReScanModifyTable is not implemented");
4451 }

References elog(), and ERROR.

Referenced by ExecReScan().