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

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

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

4331 {
4332  int i;
4333 
4334  /*
4335  * Allow any FDWs to shut down
4336  */
4337  for (i = 0; i < node->mt_nrels; i++)
4338  {
4339  int j;
4340  ResultRelInfo *resultRelInfo = node->resultRelInfo + i;
4341 
4342  if (!resultRelInfo->ri_usesFdwDirectModify &&
4343  resultRelInfo->ri_FdwRoutine != NULL &&
4344  resultRelInfo->ri_FdwRoutine->EndForeignModify != NULL)
4345  resultRelInfo->ri_FdwRoutine->EndForeignModify(node->ps.state,
4346  resultRelInfo);
4347 
4348  /*
4349  * Cleanup the initialized batch slots. This only matters for FDWs
4350  * with batching, but the other cases will have ri_NumSlotsInitialized
4351  * == 0.
4352  */
4353  for (j = 0; j < resultRelInfo->ri_NumSlotsInitialized; j++)
4354  {
4355  ExecDropSingleTupleTableSlot(resultRelInfo->ri_Slots[j]);
4356  ExecDropSingleTupleTableSlot(resultRelInfo->ri_PlanSlots[j]);
4357  }
4358  }
4359 
4360  /*
4361  * Close all the partitioned tables, leaf partitions, and their indices
4362  * and release the slot used for tuple routing, if set.
4363  */
4364  if (node->mt_partition_tuple_routing)
4365  {
4367 
4368  if (node->mt_root_tuple_slot)
4370  }
4371 
4372  /*
4373  * Free the exprcontext
4374  */
4375  ExecFreeExprContext(&node->ps);
4376 
4377  /*
4378  * clean out the tuple table
4379  */
4380  if (node->ps.ps_ResultTupleSlot)
4382 
4383  /*
4384  * Terminate EPQ execution if active
4385  */
4386  EvalPlanQualEnd(&node->mt_epqstate);
4387 
4388  /*
4389  * shut down subplan
4390  */
4391  ExecEndNode(outerPlanState(node));
4392 }
void EvalPlanQualEnd(EPQState *epqstate)
Definition: execMain.c:2932
void ExecCleanupTupleRouting(ModifyTableState *mtstate, PartitionTupleRouting *proute)
void ExecEndNode(PlanState *node)
Definition: execProcnode.c:556
void ExecDropSingleTupleTableSlot(TupleTableSlot *slot)
Definition: execTuples.c:1254
void ExecFreeExprContext(PlanState *planstate)
Definition: execUtils.c:650
#define outerPlanState(node)
Definition: execnodes.h:1094
int j
Definition: isn.c:74
EndForeignModify_function EndForeignModify
Definition: fdwapi.h:237
ResultRelInfo * resultRelInfo
Definition: execnodes.h:1230
struct PartitionTupleRouting * mt_partition_tuple_routing
Definition: execnodes.h:1261
TupleTableSlot * mt_root_tuple_slot
Definition: execnodes.h:1258
EPQState mt_epqstate
Definition: execnodes.h:1240
PlanState ps
Definition: execnodes.h:1225
EState * state
Definition: execnodes.h:1000
TupleTableSlot * ps_ResultTupleSlot
Definition: execnodes.h:1036
TupleTableSlot ** ri_Slots
Definition: execnodes.h:489
int ri_NumSlotsInitialized
Definition: execnodes.h:487
struct FdwRoutine * ri_FdwRoutine
Definition: execnodes.h:477
TupleTableSlot ** ri_PlanSlots
Definition: execnodes.h:490
bool ri_usesFdwDirectModify
Definition: execnodes.h:483

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

3238 {
3239  EState *estate = mtstate->ps.state;
3240 
3241  Assert(!resultRelInfo->ri_projectNewInfoValid);
3242 
3243  resultRelInfo->ri_oldTupleSlot =
3244  table_slot_create(resultRelInfo->ri_RelationDesc,
3245  &estate->es_tupleTable);
3246  resultRelInfo->ri_newTupleSlot =
3247  table_slot_create(resultRelInfo->ri_RelationDesc,
3248  &estate->es_tupleTable);
3249  resultRelInfo->ri_projectNewInfoValid = true;
3250 }
List * es_tupleTable
Definition: execnodes.h:634
bool ri_projectNewInfoValid
Definition: execnodes.h:457
TupleTableSlot * ri_oldTupleSlot
Definition: execnodes.h:455
TupleTableSlot * ri_newTupleSlot
Definition: execnodes.h:453
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 3850 of file nodeModifyTable.c.

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

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

◆ ExecReScanModifyTable()

void ExecReScanModifyTable ( ModifyTableState node)

Definition at line 4395 of file nodeModifyTable.c.

4396 {
4397  /*
4398  * Currently, we don't need to support rescan on ModifyTable nodes. The
4399  * semantics of that would be a bit debatable anyway.
4400  */
4401  elog(ERROR, "ExecReScanModifyTable is not implemented");
4402 }

References elog, and ERROR.

Referenced by ExecReScan().