PostgreSQL Source Code  git master
nodeModifyTable.c File Reference
#include "postgres.h"
#include "access/heapam.h"
#include "access/htup_details.h"
#include "access/tableam.h"
#include "access/xact.h"
#include "catalog/catalog.h"
#include "commands/trigger.h"
#include "executor/execPartition.h"
#include "executor/executor.h"
#include "executor/nodeModifyTable.h"
#include "foreign/fdwapi.h"
#include "miscadmin.h"
#include "nodes/nodeFuncs.h"
#include "rewrite/rewriteHandler.h"
#include "storage/bufmgr.h"
#include "storage/lmgr.h"
#include "utils/builtins.h"
#include "utils/datum.h"
#include "utils/memutils.h"
#include "utils/rel.h"
Include dependency graph for nodeModifyTable.c:

Go to the source code of this file.

Functions

static bool ExecOnConflictUpdate (ModifyTableState *mtstate, ResultRelInfo *resultRelInfo, ItemPointer conflictTid, TupleTableSlot *planSlot, TupleTableSlot *excludedSlot, EState *estate, bool canSetTag, TupleTableSlot **returning)
 
static TupleTableSlotExecPrepareTupleRouting (ModifyTableState *mtstate, EState *estate, PartitionTupleRouting *proute, ResultRelInfo *targetRelInfo, TupleTableSlot *slot)
 
static ResultRelInfogetTargetResultRelInfo (ModifyTableState *node)
 
static void ExecSetupChildParentMapForSubplan (ModifyTableState *mtstate)
 
static TupleConversionMaptupconv_map_for_subplan (ModifyTableState *node, int whichplan)
 
static void ExecCheckPlanOutput (Relation resultRel, List *targetList)
 
static TupleTableSlotExecProcessReturning (ResultRelInfo *resultRelInfo, TupleTableSlot *tupleSlot, TupleTableSlot *planSlot)
 
static void ExecCheckTupleVisible (EState *estate, Relation rel, TupleTableSlot *slot)
 
static void ExecCheckTIDVisible (EState *estate, ResultRelInfo *relinfo, ItemPointer tid, TupleTableSlot *tempSlot)
 
void ExecComputeStoredGenerated (EState *estate, TupleTableSlot *slot, CmdType cmdtype)
 
static TupleTableSlotExecInsert (ModifyTableState *mtstate, TupleTableSlot *slot, TupleTableSlot *planSlot, EState *estate, bool canSetTag)
 
static TupleTableSlotExecDelete (ModifyTableState *mtstate, ItemPointer tupleid, HeapTuple oldtuple, TupleTableSlot *planSlot, EPQState *epqstate, EState *estate, bool processReturning, bool canSetTag, bool changingPart, bool *tupleDeleted, TupleTableSlot **epqreturnslot)
 
static TupleTableSlotExecUpdate (ModifyTableState *mtstate, ItemPointer tupleid, HeapTuple oldtuple, TupleTableSlot *slot, TupleTableSlot *planSlot, EPQState *epqstate, EState *estate, bool canSetTag)
 
static void fireBSTriggers (ModifyTableState *node)
 
static void fireASTriggers (ModifyTableState *node)
 
static void ExecSetupTransitionCaptureState (ModifyTableState *mtstate, EState *estate)
 
static TupleTableSlotExecModifyTable (PlanState *pstate)
 
ModifyTableStateExecInitModifyTable (ModifyTable *node, EState *estate, int eflags)
 
void ExecEndModifyTable (ModifyTableState *node)
 
void ExecReScanModifyTable (ModifyTableState *node)
 

Function Documentation

◆ ExecCheckPlanOutput()

static void ExecCheckPlanOutput ( Relation  resultRel,
List targetList 
)
static

Definition at line 92 of file nodeModifyTable.c.

References ereport, errcode(), errdetail(), errmsg(), ERROR, TargetEntry::expr, exprType(), format_type_be(), IsA, lfirst, TupleDescData::natts, RelationGetDescr, TargetEntry::resjunk, and TupleDescAttr.

Referenced by ExecInitModifyTable().

93 {
94  TupleDesc resultDesc = RelationGetDescr(resultRel);
95  int attno = 0;
96  ListCell *lc;
97 
98  foreach(lc, targetList)
99  {
100  TargetEntry *tle = (TargetEntry *) lfirst(lc);
101  Form_pg_attribute attr;
102 
103  if (tle->resjunk)
104  continue; /* ignore junk tlist items */
105 
106  if (attno >= resultDesc->natts)
107  ereport(ERROR,
108  (errcode(ERRCODE_DATATYPE_MISMATCH),
109  errmsg("table row type and query-specified row type do not match"),
110  errdetail("Query has too many columns.")));
111  attr = TupleDescAttr(resultDesc, attno);
112  attno++;
113 
114  if (!attr->attisdropped)
115  {
116  /* Normal case: demand type match */
117  if (exprType((Node *) tle->expr) != attr->atttypid)
118  ereport(ERROR,
119  (errcode(ERRCODE_DATATYPE_MISMATCH),
120  errmsg("table row type and query-specified row type do not match"),
121  errdetail("Table has type %s at ordinal position %d, but query expects %s.",
122  format_type_be(attr->atttypid),
123  attno,
124  format_type_be(exprType((Node *) tle->expr)))));
125  }
126  else
127  {
128  /*
129  * For a dropped column, we can't check atttypid (it's likely 0).
130  * In any case the planner has most likely inserted an INT4 null.
131  * What we insist on is just *some* NULL constant.
132  */
133  if (!IsA(tle->expr, Const) ||
134  !((Const *) tle->expr)->constisnull)
135  ereport(ERROR,
136  (errcode(ERRCODE_DATATYPE_MISMATCH),
137  errmsg("table row type and query-specified row type do not match"),
138  errdetail("Query provides a value for a dropped column at ordinal position %d.",
139  attno)));
140  }
141  }
142  if (attno != resultDesc->natts)
143  ereport(ERROR,
144  (errcode(ERRCODE_DATATYPE_MISMATCH),
145  errmsg("table row type and query-specified row type do not match"),
146  errdetail("Query has too few columns.")));
147 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:580
#define RelationGetDescr(relation)
Definition: rel.h:482
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92
Definition: nodes.h:529
int errcode(int sqlerrcode)
Definition: elog.c:610
char * format_type_be(Oid type_oid)
Definition: format_type.c:339
bool resjunk
Definition: primnodes.h:1414
#define ERROR
Definition: elog.h:43
int errdetail(const char *fmt,...)
Definition: elog.c:957
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:193
#define ereport(elevel,...)
Definition: elog.h:144
#define lfirst(lc)
Definition: pg_list.h:190
Expr * expr
Definition: primnodes.h:1407
Oid exprType(const Node *expr)
Definition: nodeFuncs.c:41
int errmsg(const char *fmt,...)
Definition: elog.c:824

◆ ExecCheckTIDVisible()

static void ExecCheckTIDVisible ( EState estate,
ResultRelInfo relinfo,
ItemPointer  tid,
TupleTableSlot tempSlot 
)
static

Definition at line 228 of file nodeModifyTable.c.

References elog, ERROR, ExecCheckTupleVisible(), ExecClearTuple(), IsolationUsesXactSnapshot, ResultRelInfo::ri_RelationDesc, SnapshotAny, and table_tuple_fetch_row_version().

Referenced by ExecInsert().

232 {
233  Relation rel = relinfo->ri_RelationDesc;
234 
235  /* Redundantly check isolation level */
237  return;
238 
239  if (!table_tuple_fetch_row_version(rel, tid, SnapshotAny, tempSlot))
240  elog(ERROR, "failed to fetch conflicting tuple for ON CONFLICT");
241  ExecCheckTupleVisible(estate, rel, tempSlot);
242  ExecClearTuple(tempSlot);
243 }
Relation ri_RelationDesc
Definition: execnodes.h:413
static TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition: tuptable.h:425
#define IsolationUsesXactSnapshot()
Definition: xact.h:51
static void ExecCheckTupleVisible(EState *estate, Relation rel, TupleTableSlot *slot)
#define ERROR
Definition: elog.h:43
static bool table_tuple_fetch_row_version(Relation rel, ItemPointer tid, Snapshot snapshot, TupleTableSlot *slot)
Definition: tableam.h:1071
#define SnapshotAny
Definition: snapmgr.h:69
#define elog(elevel,...)
Definition: elog.h:214

◆ ExecCheckTupleVisible()

static void ExecCheckTupleVisible ( EState estate,
Relation  rel,
TupleTableSlot slot 
)
static

Definition at line 194 of file nodeModifyTable.c.

References Assert, DatumGetTransactionId, ereport, errcode(), errmsg(), ERROR, EState::es_snapshot, IsolationUsesXactSnapshot, MinTransactionIdAttributeNumber, slot_getsysattr(), table_tuple_satisfies_snapshot(), and TransactionIdIsCurrentTransactionId().

Referenced by ExecCheckTIDVisible(), and ExecOnConflictUpdate().

197 {
199  return;
200 
201  if (!table_tuple_satisfies_snapshot(rel, slot, estate->es_snapshot))
202  {
203  Datum xminDatum;
204  TransactionId xmin;
205  bool isnull;
206 
207  xminDatum = slot_getsysattr(slot, MinTransactionIdAttributeNumber, &isnull);
208  Assert(!isnull);
209  xmin = DatumGetTransactionId(xminDatum);
210 
211  /*
212  * We should not raise a serialization failure if the conflict is
213  * against a tuple inserted by our own transaction, even if it's not
214  * visible to our snapshot. (This would happen, for example, if
215  * conflicting keys are proposed for insertion in a single command.)
216  */
218  ereport(ERROR,
219  (errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
220  errmsg("could not serialize access due to concurrent update")));
221  }
222 }
uint32 TransactionId
Definition: c.h:520
bool TransactionIdIsCurrentTransactionId(TransactionId xid)
Definition: xact.c:869
#define IsolationUsesXactSnapshot()
Definition: xact.h:51
int errcode(int sqlerrcode)
Definition: elog.c:610
Snapshot es_snapshot
Definition: execnodes.h:508
#define ERROR
Definition: elog.h:43
uintptr_t Datum
Definition: postgres.h:367
#define ereport(elevel,...)
Definition: elog.h:144
#define Assert(condition)
Definition: c.h:745
static bool table_tuple_satisfies_snapshot(Relation rel, TupleTableSlot *slot, Snapshot snapshot)
Definition: tableam.h:1118
#define DatumGetTransactionId(X)
Definition: postgres.h:514
int errmsg(const char *fmt,...)
Definition: elog.c:824
static Datum slot_getsysattr(TupleTableSlot *slot, int attnum, bool *isnull)
Definition: tuptable.h:402
#define MinTransactionIdAttributeNumber
Definition: sysattr.h:22

◆ ExecComputeStoredGenerated()

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

Definition at line 249 of file nodeModifyTable.c.

References Assert, bms_is_member(), build_column_default(), CMD_UPDATE, TupleDescData::constr, datumCopy(), ExprContext::ecxt_scantuple, elog, ERROR, EState::es_query_cxt, EState::es_result_relation_info, exec_rt_fetch(), ExecClearTuple(), ExecEvalExpr(), ExecMaterializeSlot(), ExecPrepareExpr(), ExecStoreVirtualTuple(), RangeTblEntry::extraUpdatedCols, FirstLowInvalidHeapAttributeNumber, GetPerTupleExprContext, GetPerTupleMemoryContext, TupleConstr::has_generated_stored, i, MemoryContextSwitchTo(), TupleDescData::natts, palloc(), RelationGetDescr, RelationGetRelationName, ResultRelInfo::ri_GeneratedExprs, ResultRelInfo::ri_NumGeneratedNeeded, ResultRelInfo::ri_RangeTableIndex, ResultRelInfo::ri_RelationDesc, slot_getallattrs(), TriggerDesc::trig_update_before_row, RelationData::trigdesc, TupleTableSlot::tts_isnull, TupleTableSlot::tts_values, TupleDescAttr, val, and values.

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

250 {
251  ResultRelInfo *resultRelInfo = estate->es_result_relation_info;
252  Relation rel = resultRelInfo->ri_RelationDesc;
253  TupleDesc tupdesc = RelationGetDescr(rel);
254  int natts = tupdesc->natts;
255  MemoryContext oldContext;
256  Datum *values;
257  bool *nulls;
258 
259  Assert(tupdesc->constr && tupdesc->constr->has_generated_stored);
260 
261  /*
262  * If first time through for this result relation, build expression
263  * nodetrees for rel's stored generation expressions. Keep them in the
264  * per-query memory context so they'll survive throughout the query.
265  */
266  if (resultRelInfo->ri_GeneratedExprs == NULL)
267  {
268  oldContext = MemoryContextSwitchTo(estate->es_query_cxt);
269 
270  resultRelInfo->ri_GeneratedExprs =
271  (ExprState **) palloc(natts * sizeof(ExprState *));
272  resultRelInfo->ri_NumGeneratedNeeded = 0;
273 
274  for (int i = 0; i < natts; i++)
275  {
276  if (TupleDescAttr(tupdesc, i)->attgenerated == ATTRIBUTE_GENERATED_STORED)
277  {
278  Expr *expr;
279 
280  /*
281  * If it's an update and the current column was not marked as
282  * being updated, then we can skip the computation. But if
283  * there is a BEFORE ROW UPDATE trigger, we cannot skip
284  * because the trigger might affect additional columns.
285  */
286  if (cmdtype == CMD_UPDATE &&
287  !(rel->trigdesc && rel->trigdesc->trig_update_before_row) &&
289  exec_rt_fetch(resultRelInfo->ri_RangeTableIndex, estate)->extraUpdatedCols))
290  {
291  resultRelInfo->ri_GeneratedExprs[i] = NULL;
292  continue;
293  }
294 
295  expr = (Expr *) build_column_default(rel, i + 1);
296  if (expr == NULL)
297  elog(ERROR, "no generation expression found for column number %d of table \"%s\"",
298  i + 1, RelationGetRelationName(rel));
299 
300  resultRelInfo->ri_GeneratedExprs[i] = ExecPrepareExpr(expr, estate);
301  resultRelInfo->ri_NumGeneratedNeeded++;
302  }
303  }
304 
305  MemoryContextSwitchTo(oldContext);
306  }
307 
308  /*
309  * If no generated columns have been affected by this change, then skip
310  * the rest.
311  */
312  if (resultRelInfo->ri_NumGeneratedNeeded == 0)
313  return;
314 
315  oldContext = MemoryContextSwitchTo(GetPerTupleMemoryContext(estate));
316 
317  values = palloc(sizeof(*values) * natts);
318  nulls = palloc(sizeof(*nulls) * natts);
319 
320  slot_getallattrs(slot);
321  memcpy(nulls, slot->tts_isnull, sizeof(*nulls) * natts);
322 
323  for (int i = 0; i < natts; i++)
324  {
325  Form_pg_attribute attr = TupleDescAttr(tupdesc, i);
326 
327  if (attr->attgenerated == ATTRIBUTE_GENERATED_STORED &&
328  resultRelInfo->ri_GeneratedExprs[i])
329  {
330  ExprContext *econtext;
331  Datum val;
332  bool isnull;
333 
334  econtext = GetPerTupleExprContext(estate);
335  econtext->ecxt_scantuple = slot;
336 
337  val = ExecEvalExpr(resultRelInfo->ri_GeneratedExprs[i], econtext, &isnull);
338 
339  /*
340  * We must make a copy of val as we have no guarantees about where
341  * memory for a pass-by-reference Datum is located.
342  */
343  if (!isnull)
344  val = datumCopy(val, attr->attbyval, attr->attlen);
345 
346  values[i] = val;
347  nulls[i] = isnull;
348  }
349  else
350  {
351  if (!nulls[i])
352  values[i] = datumCopy(slot->tts_values[i], attr->attbyval, attr->attlen);
353  }
354  }
355 
356  ExecClearTuple(slot);
357  memcpy(slot->tts_values, values, sizeof(*values) * natts);
358  memcpy(slot->tts_isnull, nulls, sizeof(*nulls) * natts);
359  ExecStoreVirtualTuple(slot);
360  ExecMaterializeSlot(slot);
361 
362  MemoryContextSwitchTo(oldContext);
363 }
Relation ri_RelationDesc
Definition: execnodes.h:413
static TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition: tuptable.h:425
#define RelationGetDescr(relation)
Definition: rel.h:482
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
Datum * tts_values
Definition: tuptable.h:126
#define FirstLowInvalidHeapAttributeNumber
Definition: sysattr.h:27
ExprState * ExecPrepareExpr(Expr *node, EState *estate)
Definition: execExpr.c:492
Index ri_RangeTableIndex
Definition: execnodes.h:410
#define GetPerTupleExprContext(estate)
Definition: executor.h:507
bool has_generated_stored
Definition: tupdesc.h:45
Bitmapset * extraUpdatedCols
Definition: parsenodes.h:1124
MemoryContext es_query_cxt
Definition: execnodes.h:555
#define ERROR
Definition: elog.h:43
TriggerDesc * trigdesc
Definition: rel.h:115
static void slot_getallattrs(TupleTableSlot *slot)
Definition: tuptable.h:354
bool * tts_isnull
Definition: tuptable.h:128
static Datum ExecEvalExpr(ExprState *state, ExprContext *econtext, bool *isNull)
Definition: executor.h:290
TupleConstr * constr
Definition: tupdesc.h:85
ExprState ** ri_GeneratedExprs
Definition: execnodes.h:460
bool trig_update_before_row
Definition: reltrigger.h:61
#define RelationGetRelationName(relation)
Definition: rel.h:490
static RangeTblEntry * exec_rt_fetch(Index rti, EState *estate)
Definition: executor.h:543
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:193
Datum datumCopy(Datum value, bool typByVal, int typLen)
Definition: datum.c:131
int ri_NumGeneratedNeeded
Definition: execnodes.h:463
Node * build_column_default(Relation rel, int attrno)
uintptr_t Datum
Definition: postgres.h:367
static void ExecMaterializeSlot(TupleTableSlot *slot)
Definition: tuptable.h:443
#define Assert(condition)
Definition: c.h:745
TupleTableSlot * ecxt_scantuple
Definition: execnodes.h:226
#define GetPerTupleMemoryContext(estate)
Definition: executor.h:512
static Datum values[MAXATTR]
Definition: bootstrap.c:167
void * palloc(Size size)
Definition: mcxt.c:949
#define elog(elevel,...)
Definition: elog.h:214
int i
bool bms_is_member(int x, const Bitmapset *a)
Definition: bitmapset.c:427
long val
Definition: informix.c:664
TupleTableSlot * ExecStoreVirtualTuple(TupleTableSlot *slot)
Definition: execTuples.c:1522
ResultRelInfo * es_result_relation_info
Definition: execnodes.h:527

◆ ExecDelete()

static TupleTableSlot* ExecDelete ( ModifyTableState mtstate,
ItemPointer  tupleid,
HeapTuple  oldtuple,
TupleTableSlot planSlot,
EPQState epqstate,
EState estate,
bool  processReturning,
bool  canSetTag,
bool  changingPart,
bool tupleDeleted,
TupleTableSlot **  epqreturnslot 
)
static

Definition at line 709 of file nodeModifyTable.c.

References Assert, TM_FailureData::cmax, CMD_UPDATE, elog, ereport, errcode(), errhint(), errmsg(), ERROR, EState::es_crosscheck_snapshot, EState::es_output_cid, EState::es_processed, EState::es_result_relation_info, EState::es_snapshot, EvalPlanQual(), EvalPlanQualBegin(), EvalPlanQualSlot(), ExecARDeleteTriggers(), ExecARUpdateTriggers(), ExecBRDeleteTriggers(), ExecClearTuple(), ExecForceStoreHeapTuple(), FdwRoutine::ExecForeignDelete, ExecGetReturningSlot(), ExecIRDeleteTriggers(), ExecMaterializeSlot(), ExecProcessReturning(), ExecStoreAllNullTuple(), IsolationUsesXactSnapshot, LockTupleExclusive, LockWaitBlock, ModifyTableState::mt_transition_capture, ModifyTableState::operation, RelationGetRelid, ResultRelInfo::ri_FdwRoutine, ResultRelInfo::ri_projectReturning, ResultRelInfo::ri_RangeTableIndex, ResultRelInfo::ri_RelationDesc, ResultRelInfo::ri_TrigDesc, SnapshotAny, table_tuple_delete(), table_tuple_fetch_row_version(), table_tuple_lock(), TransitionCaptureState::tcs_update_old_table, TM_Deleted, TM_Ok, TM_SelfModified, TM_Updated, TM_FailureData::traversed, TriggerDesc::trig_delete_before_row, TriggerDesc::trig_delete_instead_row, TTS_EMPTY, TupleTableSlot::tts_tableOid, TupIsNull, and TUPLE_LOCK_FLAG_FIND_LAST_VERSION.

Referenced by ExecModifyTable(), and ExecUpdate().

720 {
721  ResultRelInfo *resultRelInfo;
722  Relation resultRelationDesc;
723  TM_Result result;
724  TM_FailureData tmfd;
725  TupleTableSlot *slot = NULL;
726  TransitionCaptureState *ar_delete_trig_tcs;
727 
728  if (tupleDeleted)
729  *tupleDeleted = false;
730 
731  /*
732  * get information on the (current) result relation
733  */
734  resultRelInfo = estate->es_result_relation_info;
735  resultRelationDesc = resultRelInfo->ri_RelationDesc;
736 
737  /* BEFORE ROW DELETE Triggers */
738  if (resultRelInfo->ri_TrigDesc &&
739  resultRelInfo->ri_TrigDesc->trig_delete_before_row)
740  {
741  bool dodelete;
742 
743  dodelete = ExecBRDeleteTriggers(estate, epqstate, resultRelInfo,
744  tupleid, oldtuple, epqreturnslot);
745 
746  if (!dodelete) /* "do nothing" */
747  return NULL;
748  }
749 
750  /* INSTEAD OF ROW DELETE Triggers */
751  if (resultRelInfo->ri_TrigDesc &&
752  resultRelInfo->ri_TrigDesc->trig_delete_instead_row)
753  {
754  bool dodelete;
755 
756  Assert(oldtuple != NULL);
757  dodelete = ExecIRDeleteTriggers(estate, resultRelInfo, oldtuple);
758 
759  if (!dodelete) /* "do nothing" */
760  return NULL;
761  }
762  else if (resultRelInfo->ri_FdwRoutine)
763  {
764  /*
765  * delete from foreign table: let the FDW do it
766  *
767  * We offer the returning slot as a place to store RETURNING data,
768  * although the FDW can return some other slot if it wants.
769  */
770  slot = ExecGetReturningSlot(estate, resultRelInfo);
771  slot = resultRelInfo->ri_FdwRoutine->ExecForeignDelete(estate,
772  resultRelInfo,
773  slot,
774  planSlot);
775 
776  if (slot == NULL) /* "do nothing" */
777  return NULL;
778 
779  /*
780  * RETURNING expressions might reference the tableoid column, so
781  * (re)initialize tts_tableOid before evaluating them.
782  */
783  if (TTS_EMPTY(slot))
784  ExecStoreAllNullTuple(slot);
785 
786  slot->tts_tableOid = RelationGetRelid(resultRelationDesc);
787  }
788  else
789  {
790  /*
791  * delete the tuple
792  *
793  * Note: if es_crosscheck_snapshot isn't InvalidSnapshot, we check
794  * that the row to be deleted is visible to that snapshot, and throw a
795  * can't-serialize error if not. This is a special-case behavior
796  * needed for referential integrity updates in transaction-snapshot
797  * mode transactions.
798  */
799 ldelete:;
800  result = table_tuple_delete(resultRelationDesc, tupleid,
801  estate->es_output_cid,
802  estate->es_snapshot,
803  estate->es_crosscheck_snapshot,
804  true /* wait for commit */ ,
805  &tmfd,
806  changingPart);
807 
808  switch (result)
809  {
810  case TM_SelfModified:
811 
812  /*
813  * The target tuple was already updated or deleted by the
814  * current command, or by a later command in the current
815  * transaction. The former case is possible in a join DELETE
816  * where multiple tuples join to the same target tuple. This
817  * is somewhat questionable, but Postgres has always allowed
818  * it: we just ignore additional deletion attempts.
819  *
820  * The latter case arises if the tuple is modified by a
821  * command in a BEFORE trigger, or perhaps by a command in a
822  * volatile function used in the query. In such situations we
823  * should not ignore the deletion, but it is equally unsafe to
824  * proceed. We don't want to discard the original DELETE
825  * while keeping the triggered actions based on its deletion;
826  * and it would be no better to allow the original DELETE
827  * while discarding updates that it triggered. The row update
828  * carries some information that might be important according
829  * to business rules; so throwing an error is the only safe
830  * course.
831  *
832  * If a trigger actually intends this type of interaction, it
833  * can re-execute the DELETE and then return NULL to cancel
834  * the outer delete.
835  */
836  if (tmfd.cmax != estate->es_output_cid)
837  ereport(ERROR,
838  (errcode(ERRCODE_TRIGGERED_DATA_CHANGE_VIOLATION),
839  errmsg("tuple to be deleted was already modified by an operation triggered by the current command"),
840  errhint("Consider using an AFTER trigger instead of a BEFORE trigger to propagate changes to other rows.")));
841 
842  /* Else, already deleted by self; nothing to do */
843  return NULL;
844 
845  case TM_Ok:
846  break;
847 
848  case TM_Updated:
849  {
850  TupleTableSlot *inputslot;
851  TupleTableSlot *epqslot;
852 
854  ereport(ERROR,
855  (errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
856  errmsg("could not serialize access due to concurrent update")));
857 
858  /*
859  * Already know that we're going to need to do EPQ, so
860  * fetch tuple directly into the right slot.
861  */
862  EvalPlanQualBegin(epqstate);
863  inputslot = EvalPlanQualSlot(epqstate, resultRelationDesc,
864  resultRelInfo->ri_RangeTableIndex);
865 
866  result = table_tuple_lock(resultRelationDesc, tupleid,
867  estate->es_snapshot,
868  inputslot, estate->es_output_cid,
871  &tmfd);
872 
873  switch (result)
874  {
875  case TM_Ok:
876  Assert(tmfd.traversed);
877  epqslot = EvalPlanQual(epqstate,
878  resultRelationDesc,
879  resultRelInfo->ri_RangeTableIndex,
880  inputslot);
881  if (TupIsNull(epqslot))
882  /* Tuple not passing quals anymore, exiting... */
883  return NULL;
884 
885  /*
886  * If requested, skip delete and pass back the
887  * updated row.
888  */
889  if (epqreturnslot)
890  {
891  *epqreturnslot = epqslot;
892  return NULL;
893  }
894  else
895  goto ldelete;
896 
897  case TM_SelfModified:
898 
899  /*
900  * This can be reached when following an update
901  * chain from a tuple updated by another session,
902  * reaching a tuple that was already updated in
903  * this transaction. If previously updated by this
904  * command, ignore the delete, otherwise error
905  * out.
906  *
907  * See also TM_SelfModified response to
908  * table_tuple_delete() above.
909  */
910  if (tmfd.cmax != estate->es_output_cid)
911  ereport(ERROR,
912  (errcode(ERRCODE_TRIGGERED_DATA_CHANGE_VIOLATION),
913  errmsg("tuple to be deleted was already modified by an operation triggered by the current command"),
914  errhint("Consider using an AFTER trigger instead of a BEFORE trigger to propagate changes to other rows.")));
915  return NULL;
916 
917  case TM_Deleted:
918  /* tuple already deleted; nothing to do */
919  return NULL;
920 
921  default:
922 
923  /*
924  * TM_Invisible should be impossible because we're
925  * waiting for updated row versions, and would
926  * already have errored out if the first version
927  * is invisible.
928  *
929  * TM_Updated should be impossible, because we're
930  * locking the latest version via
931  * TUPLE_LOCK_FLAG_FIND_LAST_VERSION.
932  */
933  elog(ERROR, "unexpected table_tuple_lock status: %u",
934  result);
935  return NULL;
936  }
937 
938  Assert(false);
939  break;
940  }
941 
942  case TM_Deleted:
944  ereport(ERROR,
945  (errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
946  errmsg("could not serialize access due to concurrent delete")));
947  /* tuple already deleted; nothing to do */
948  return NULL;
949 
950  default:
951  elog(ERROR, "unrecognized table_tuple_delete status: %u",
952  result);
953  return NULL;
954  }
955 
956  /*
957  * Note: Normally one would think that we have to delete index tuples
958  * associated with the heap tuple now...
959  *
960  * ... but in POSTGRES, we have no need to do this because VACUUM will
961  * take care of it later. We can't delete index tuples immediately
962  * anyway, since the tuple is still visible to other transactions.
963  */
964  }
965 
966  if (canSetTag)
967  (estate->es_processed)++;
968 
969  /* Tell caller that the delete actually happened. */
970  if (tupleDeleted)
971  *tupleDeleted = true;
972 
973  /*
974  * If this delete is the result of a partition key update that moved the
975  * tuple to a new partition, put this row into the transition OLD TABLE,
976  * if there is one. We need to do this separately for DELETE and INSERT
977  * because they happen on different tables.
978  */
979  ar_delete_trig_tcs = mtstate->mt_transition_capture;
980  if (mtstate->operation == CMD_UPDATE && mtstate->mt_transition_capture
982  {
983  ExecARUpdateTriggers(estate, resultRelInfo,
984  tupleid,
985  oldtuple,
986  NULL,
987  NULL,
988  mtstate->mt_transition_capture);
989 
990  /*
991  * We've already captured the NEW TABLE row, so make sure any AR
992  * DELETE trigger fired below doesn't capture it again.
993  */
994  ar_delete_trig_tcs = NULL;
995  }
996 
997  /* AFTER ROW DELETE Triggers */
998  ExecARDeleteTriggers(estate, resultRelInfo, tupleid, oldtuple,
999  ar_delete_trig_tcs);
1000 
1001  /* Process RETURNING if present and if requested */
1002  if (processReturning && resultRelInfo->ri_projectReturning)
1003  {
1004  /*
1005  * We have to put the target tuple into a slot, which means first we
1006  * gotta fetch it. We can use the trigger tuple slot.
1007  */
1008  TupleTableSlot *rslot;
1009 
1010  if (resultRelInfo->ri_FdwRoutine)
1011  {
1012  /* FDW must have provided a slot containing the deleted row */
1013  Assert(!TupIsNull(slot));
1014  }
1015  else
1016  {
1017  slot = ExecGetReturningSlot(estate, resultRelInfo);
1018  if (oldtuple != NULL)
1019  {
1020  ExecForceStoreHeapTuple(oldtuple, slot, false);
1021  }
1022  else
1023  {
1024  if (!table_tuple_fetch_row_version(resultRelationDesc, tupleid,
1025  SnapshotAny, slot))
1026  elog(ERROR, "failed to fetch deleted tuple for DELETE RETURNING");
1027  }
1028  }
1029 
1030  rslot = ExecProcessReturning(resultRelInfo, slot, planSlot);
1031 
1032  /*
1033  * Before releasing the target tuple again, make sure rslot has a
1034  * local copy of any pass-by-reference values.
1035  */
1036  ExecMaterializeSlot(rslot);
1037 
1038  ExecClearTuple(slot);
1039 
1040  return rslot;
1041  }
1042 
1043  return NULL;
1044 }
ExecForeignDelete_function ExecForeignDelete
Definition: fdwapi.h:213
Oid tts_tableOid
Definition: tuptable.h:131
Relation ri_RelationDesc
Definition: execnodes.h:413
bool ExecIRDeleteTriggers(EState *estate, ResultRelInfo *relinfo, HeapTuple trigtuple)
Definition: trigger.c:2528
int errhint(const char *fmt,...)
Definition: elog.c:1071
TupleTableSlot * ExecGetReturningSlot(EState *estate, ResultRelInfo *relInfo)
Definition: execUtils.c:1189
CommandId es_output_cid
Definition: execnodes.h:522
static TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition: tuptable.h:425
TupleTableSlot * ExecStoreAllNullTuple(TupleTableSlot *slot)
Definition: execTuples.c:1546
#define TTS_EMPTY(slot)
Definition: tuptable.h:97
CommandId cmax
Definition: tableam.h:127
#define IsolationUsesXactSnapshot()
Definition: xact.h:51
Snapshot es_crosscheck_snapshot
Definition: execnodes.h:509
int errcode(int sqlerrcode)
Definition: elog.c:610
CmdType operation
Definition: execnodes.h:1166
Snapshot es_snapshot
Definition: execnodes.h:508
void ExecForceStoreHeapTuple(HeapTuple tuple, TupleTableSlot *slot, bool shouldFree)
Definition: execTuples.c:1439
Index ri_RangeTableIndex
Definition: execnodes.h:410
bool ExecBRDeleteTriggers(EState *estate, EPQState *epqstate, ResultRelInfo *relinfo, ItemPointer tupleid, HeapTuple fdw_trigtuple, TupleTableSlot **epqslot)
Definition: trigger.c:2413
void ExecARDeleteTriggers(EState *estate, ResultRelInfo *relinfo, ItemPointer tupleid, HeapTuple fdw_trigtuple, TransitionCaptureState *transition_capture)
Definition: trigger.c:2498
#define ERROR
Definition: elog.h:43
static TM_Result table_tuple_lock(Relation rel, ItemPointer tid, Snapshot snapshot, TupleTableSlot *slot, CommandId cid, LockTupleMode mode, LockWaitPolicy wait_policy, uint8 flags, TM_FailureData *tmfd)
Definition: tableam.h:1356
TupleTableSlot * EvalPlanQualSlot(EPQState *epqstate, Relation relation, Index rti)
Definition: execMain.c:2541
struct TransitionCaptureState * mt_transition_capture
Definition: execnodes.h:1191
TupleTableSlot * EvalPlanQual(EPQState *epqstate, Relation relation, Index rti, TupleTableSlot *inputslot)
Definition: execMain.c:2432
ProjectionInfo * ri_projectReturning
Definition: execnodes.h:472
#define TupIsNull(slot)
Definition: tuptable.h:292
struct FdwRoutine * ri_FdwRoutine
Definition: execnodes.h:442
TriggerDesc * ri_TrigDesc
Definition: execnodes.h:425
static bool table_tuple_fetch_row_version(Relation rel, ItemPointer tid, Snapshot snapshot, TupleTableSlot *slot)
Definition: tableam.h:1071
static TupleTableSlot * ExecProcessReturning(ResultRelInfo *resultRelInfo, TupleTableSlot *tupleSlot, TupleTableSlot *planSlot)
void ExecARUpdateTriggers(EState *estate, ResultRelInfo *relinfo, ItemPointer tupleid, HeapTuple fdw_trigtuple, TupleTableSlot *newslot, List *recheckIndexes, TransitionCaptureState *transition_capture)
Definition: trigger.c:2783
TM_Result
Definition: tableam.h:70
bool trig_delete_instead_row
Definition: reltrigger.h:68
static TM_Result table_tuple_delete(Relation rel, ItemPointer tid, CommandId cid, Snapshot snapshot, Snapshot crosscheck, bool wait, TM_FailureData *tmfd, bool changingPart)
Definition: tableam.h:1267
static void ExecMaterializeSlot(TupleTableSlot *slot)
Definition: tuptable.h:443
#define ereport(elevel,...)
Definition: elog.h:144
#define Assert(condition)
Definition: c.h:745
Definition: tableam.h:76
uint64 es_processed
Definition: execnodes.h:559
#define TUPLE_LOCK_FLAG_FIND_LAST_VERSION
Definition: tableam.h:141
#define SnapshotAny
Definition: snapmgr.h:69
int errmsg(const char *fmt,...)
Definition: elog.c:824
#define elog(elevel,...)
Definition: elog.h:214
bool traversed
Definition: tableam.h:128
#define RelationGetRelid(relation)
Definition: rel.h:456
void EvalPlanQualBegin(EPQState *epqstate)
Definition: execMain.c:2694
bool trig_delete_before_row
Definition: reltrigger.h:66
ResultRelInfo * es_result_relation_info
Definition: execnodes.h:527

◆ ExecEndModifyTable()

void ExecEndModifyTable ( ModifyTableState node)

Definition at line 2761 of file nodeModifyTable.c.

References FdwRoutine::EndForeignModify, EvalPlanQualEnd(), ExecCleanupTupleRouting(), ExecClearTuple(), ExecDropSingleTupleTableSlot(), ExecEndNode(), ExecFreeExprContext(), i, ModifyTableState::mt_epqstate, ModifyTableState::mt_nplans, ModifyTableState::mt_partition_tuple_routing, ModifyTableState::mt_plans, ModifyTableState::mt_root_tuple_slot, ModifyTableState::ps, PlanState::ps_ResultTupleSlot, ModifyTableState::resultRelInfo, ResultRelInfo::ri_FdwRoutine, ResultRelInfo::ri_usesFdwDirectModify, and PlanState::state.

Referenced by ExecEndNode().

2762 {
2763  int i;
2764 
2765  /*
2766  * Allow any FDWs to shut down
2767  */
2768  for (i = 0; i < node->mt_nplans; i++)
2769  {
2770  ResultRelInfo *resultRelInfo = node->resultRelInfo + i;
2771 
2772  if (!resultRelInfo->ri_usesFdwDirectModify &&
2773  resultRelInfo->ri_FdwRoutine != NULL &&
2774  resultRelInfo->ri_FdwRoutine->EndForeignModify != NULL)
2775  resultRelInfo->ri_FdwRoutine->EndForeignModify(node->ps.state,
2776  resultRelInfo);
2777  }
2778 
2779  /*
2780  * Close all the partitioned tables, leaf partitions, and their indices
2781  * and release the slot used for tuple routing, if set.
2782  */
2783  if (node->mt_partition_tuple_routing)
2784  {
2786 
2787  if (node->mt_root_tuple_slot)
2789  }
2790 
2791  /*
2792  * Free the exprcontext
2793  */
2794  ExecFreeExprContext(&node->ps);
2795 
2796  /*
2797  * clean out the tuple table
2798  */
2799  if (node->ps.ps_ResultTupleSlot)
2801 
2802  /*
2803  * Terminate EPQ execution if active
2804  */
2805  EvalPlanQualEnd(&node->mt_epqstate);
2806 
2807  /*
2808  * shut down subplans
2809  */
2810  for (i = 0; i < node->mt_nplans; i++)
2811  ExecEndNode(node->mt_plans[i]);
2812 }
static TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition: tuptable.h:425
struct PartitionTupleRouting * mt_partition_tuple_routing
Definition: execnodes.h:1188
void ExecEndNode(PlanState *node)
Definition: execProcnode.c:543
ResultRelInfo * resultRelInfo
Definition: execnodes.h:1174
EState * state
Definition: execnodes.h:947
void ExecFreeExprContext(PlanState *planstate)
Definition: execUtils.c:655
void EvalPlanQualEnd(EPQState *epqstate)
Definition: execMain.c:2932
TupleTableSlot * ps_ResultTupleSlot
Definition: execnodes.h:983
PlanState ps
Definition: execnodes.h:1165
void ExecCleanupTupleRouting(ModifyTableState *mtstate, PartitionTupleRouting *proute)
bool ri_usesFdwDirectModify
Definition: execnodes.h:448
void ExecDropSingleTupleTableSlot(TupleTableSlot *slot)
Definition: execTuples.c:1224
EPQState mt_epqstate
Definition: execnodes.h:1178
struct FdwRoutine * ri_FdwRoutine
Definition: execnodes.h:442
EndForeignModify_function EndForeignModify
Definition: fdwapi.h:214
PlanState ** mt_plans
Definition: execnodes.h:1169
TupleTableSlot * mt_root_tuple_slot
Definition: execnodes.h:1185
int i

◆ ExecInitModifyTable()

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

Definition at line 2296 of file nodeModifyTable.c.

References ModifyTable::arbiterIndexes, Assert, AttributeNumberIsValid, FdwRoutine::BeginForeignModify, bms_is_member(), ModifyTable::canSetTag, ModifyTableState::canSetTag, CheckValidResultRel(), CMD_DELETE, CMD_INSERT, CMD_UPDATE, elog, ModifyTable::epqParam, ERROR, EState::es_auxmodifytables, EState::es_result_relation_info, EState::es_result_relations, EState::es_root_result_relations, EState::es_tupleTable, EvalPlanQualInit(), EvalPlanQualSetPlan(), EXEC_FLAG_BACKWARD, EXEC_FLAG_EXPLAIN_ONLY, EXEC_FLAG_MARK, ExecAssignExprContext(), ExecBuildAuxRowMark(), ExecBuildProjectionInfo(), ExecCheckPlanOutput(), ExecFindJunkAttribute(), ExecFindRowMark(), ExecGetResultType(), ExecInitExtraTupleSlot(), ExecInitJunkFilter(), ExecInitNode(), ExecInitQual(), ExecInitResultTupleSlotTL(), ExecInitResultTypeTL(), ExecModifyTable(), ExecOpenIndices(), PlanState::ExecProcNode, ExecSetupChildParentMapForSubplan(), ExecSetupPartitionTupleRouting(), ExecSetupTransitionCaptureState(), ExecTypeFromTL(), ModifyTable::fdwDirectModifyPlans, ModifyTable::fdwPrivLists, ModifyTableState::fireBSTriggers, getTargetResultRelInfo(), i, PlanRowMark::isParent, JunkFilter::jf_junkAttNo, lappend(), lcons(), lfirst, lfirst_node, linitial, list_length(), list_nth(), makeNode, ModifyTableState::mt_arowmarks, ModifyTableState::mt_done, ModifyTableState::mt_epqstate, ModifyTableState::mt_nplans, ModifyTableState::mt_partition_tuple_routing, ModifyTableState::mt_plans, ModifyTableState::mt_root_tuple_slot, ModifyTableState::mt_scans, ModifyTableState::mt_whichplan, NIL, OnConflictSetState::oc_Existing, OnConflictSetState::oc_ProjInfo, OnConflictSetState::oc_ProjSlot, OnConflictSetState::oc_WhereClause, ONCONFLICT_NONE, ONCONFLICT_UPDATE, ModifyTable::onConflictAction, ModifyTable::onConflictSet, ModifyTable::onConflictWhere, ModifyTable::operation, ModifyTableState::operation, palloc0(), ModifyTable::partColsUpdated, PlanState::plan, ModifyTable::plans, ModifyTableState::ps, PlanState::ps_ExprContext, PlanState::ps_ResultTupleSlot, WithCheckOption::qual, RelationData::rd_att, RelationData::rd_rel, TargetEntry::resjunk, ModifyTable::resultRelIndex, ModifyTableState::resultRelInfo, ModifyTable::returningLists, ResultRelInfo::ri_FdwRoutine, ResultRelInfo::ri_IndexRelationDescs, ResultRelInfo::ri_junkFilter, ResultRelInfo::ri_onConflict, ResultRelInfo::ri_onConflictArbiterIndexes, ResultRelInfo::ri_projectReturning, ResultRelInfo::ri_RelationDesc, ResultRelInfo::ri_returningList, ResultRelInfo::ri_TrigDesc, ResultRelInfo::ri_usesFdwDirectModify, ResultRelInfo::ri_WithCheckOptionExprs, ResultRelInfo::ri_WithCheckOptions, ModifyTable::rootResultRelIndex, ModifyTableState::rootResultRelInfo, ModifyTable::rowMarks, PlanRowMark::rti, PlanState::state, table_slot_callbacks(), table_slot_create(), Plan::targetlist, TriggerDesc::trig_update_before_row, TTSOpsVirtual, and ModifyTable::withCheckOptionLists.

Referenced by ExecInitNode().

2297 {
2298  ModifyTableState *mtstate;
2299  CmdType operation = node->operation;
2300  int nplans = list_length(node->plans);
2301  ResultRelInfo *saved_resultRelInfo;
2302  ResultRelInfo *resultRelInfo;
2303  Plan *subplan;
2304  ListCell *l;
2305  int i;
2306  Relation rel;
2307  bool update_tuple_routing_needed = node->partColsUpdated;
2308 
2309  /* check for unsupported flags */
2310  Assert(!(eflags & (EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK)));
2311 
2312  /*
2313  * create state structure
2314  */
2315  mtstate = makeNode(ModifyTableState);
2316  mtstate->ps.plan = (Plan *) node;
2317  mtstate->ps.state = estate;
2318  mtstate->ps.ExecProcNode = ExecModifyTable;
2319 
2320  mtstate->operation = operation;
2321  mtstate->canSetTag = node->canSetTag;
2322  mtstate->mt_done = false;
2323 
2324  mtstate->mt_plans = (PlanState **) palloc0(sizeof(PlanState *) * nplans);
2325  mtstate->resultRelInfo = estate->es_result_relations + node->resultRelIndex;
2326  mtstate->mt_scans = (TupleTableSlot **) palloc0(sizeof(TupleTableSlot *) * nplans);
2327 
2328  /* If modifying a partitioned table, initialize the root table info */
2329  if (node->rootResultRelIndex >= 0)
2330  mtstate->rootResultRelInfo = estate->es_root_result_relations +
2331  node->rootResultRelIndex;
2332 
2333  mtstate->mt_arowmarks = (List **) palloc0(sizeof(List *) * nplans);
2334  mtstate->mt_nplans = nplans;
2335 
2336  /* set up epqstate with dummy subplan data for the moment */
2337  EvalPlanQualInit(&mtstate->mt_epqstate, estate, NULL, NIL, node->epqParam);
2338  mtstate->fireBSTriggers = true;
2339 
2340  /*
2341  * call ExecInitNode on each of the plans to be executed and save the
2342  * results into the array "mt_plans". This is also a convenient place to
2343  * verify that the proposed target relations are valid and open their
2344  * indexes for insertion of new index entries. Note we *must* set
2345  * estate->es_result_relation_info correctly while we initialize each
2346  * sub-plan; external modules such as FDWs may depend on that (see
2347  * contrib/postgres_fdw/postgres_fdw.c: postgresBeginDirectModify() as one
2348  * example).
2349  */
2350  saved_resultRelInfo = estate->es_result_relation_info;
2351 
2352  resultRelInfo = mtstate->resultRelInfo;
2353  i = 0;
2354  foreach(l, node->plans)
2355  {
2356  subplan = (Plan *) lfirst(l);
2357 
2358  /* Initialize the usesFdwDirectModify flag */
2359  resultRelInfo->ri_usesFdwDirectModify = bms_is_member(i,
2360  node->fdwDirectModifyPlans);
2361 
2362  /*
2363  * Verify result relation is a valid target for the current operation
2364  */
2365  CheckValidResultRel(resultRelInfo, operation);
2366 
2367  /*
2368  * If there are indices on the result relation, open them and save
2369  * descriptors in the result relation info, so that we can add new
2370  * index entries for the tuples we add/update. We need not do this
2371  * for a DELETE, however, since deletion doesn't affect indexes. Also,
2372  * inside an EvalPlanQual operation, the indexes might be open
2373  * already, since we share the resultrel state with the original
2374  * query.
2375  */
2376  if (resultRelInfo->ri_RelationDesc->rd_rel->relhasindex &&
2377  operation != CMD_DELETE &&
2378  resultRelInfo->ri_IndexRelationDescs == NULL)
2379  ExecOpenIndices(resultRelInfo,
2381 
2382  /*
2383  * If this is an UPDATE and a BEFORE UPDATE trigger is present, the
2384  * trigger itself might modify the partition-key values. So arrange
2385  * for tuple routing.
2386  */
2387  if (resultRelInfo->ri_TrigDesc &&
2388  resultRelInfo->ri_TrigDesc->trig_update_before_row &&
2389  operation == CMD_UPDATE)
2390  update_tuple_routing_needed = true;
2391 
2392  /* Now init the plan for this result rel */
2393  estate->es_result_relation_info = resultRelInfo;
2394  mtstate->mt_plans[i] = ExecInitNode(subplan, estate, eflags);
2395  mtstate->mt_scans[i] =
2396  ExecInitExtraTupleSlot(mtstate->ps.state, ExecGetResultType(mtstate->mt_plans[i]),
2397  table_slot_callbacks(resultRelInfo->ri_RelationDesc));
2398 
2399  /* Also let FDWs init themselves for foreign-table result rels */
2400  if (!resultRelInfo->ri_usesFdwDirectModify &&
2401  resultRelInfo->ri_FdwRoutine != NULL &&
2402  resultRelInfo->ri_FdwRoutine->BeginForeignModify != NULL)
2403  {
2404  List *fdw_private = (List *) list_nth(node->fdwPrivLists, i);
2405 
2406  resultRelInfo->ri_FdwRoutine->BeginForeignModify(mtstate,
2407  resultRelInfo,
2408  fdw_private,
2409  i,
2410  eflags);
2411  }
2412 
2413  resultRelInfo++;
2414  i++;
2415  }
2416 
2417  estate->es_result_relation_info = saved_resultRelInfo;
2418 
2419  /* Get the target relation */
2420  rel = (getTargetResultRelInfo(mtstate))->ri_RelationDesc;
2421 
2422  /*
2423  * If it's not a partitioned table after all, UPDATE tuple routing should
2424  * not be attempted.
2425  */
2426  if (rel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
2427  update_tuple_routing_needed = false;
2428 
2429  /*
2430  * Build state for tuple routing if it's an INSERT or if it's an UPDATE of
2431  * partition key.
2432  */
2433  if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE &&
2434  (operation == CMD_INSERT || update_tuple_routing_needed))
2435  mtstate->mt_partition_tuple_routing =
2436  ExecSetupPartitionTupleRouting(estate, mtstate, rel);
2437 
2438  /*
2439  * Build state for collecting transition tuples. This requires having a
2440  * valid trigger query context, so skip it in explain-only mode.
2441  */
2442  if (!(eflags & EXEC_FLAG_EXPLAIN_ONLY))
2443  ExecSetupTransitionCaptureState(mtstate, estate);
2444 
2445  /*
2446  * Construct mapping from each of the per-subplan partition attnos to the
2447  * root attno. This is required when during update row movement the tuple
2448  * descriptor of a source partition does not match the root partitioned
2449  * table descriptor. In such a case we need to convert tuples to the root
2450  * tuple descriptor, because the search for destination partition starts
2451  * from the root. We'll also need a slot to store these converted tuples.
2452  * We can skip this setup if it's not a partition key update.
2453  */
2454  if (update_tuple_routing_needed)
2455  {
2457  mtstate->mt_root_tuple_slot = table_slot_create(rel, NULL);
2458  }
2459 
2460  /*
2461  * Initialize any WITH CHECK OPTION constraints if needed.
2462  */
2463  resultRelInfo = mtstate->resultRelInfo;
2464  i = 0;
2465  foreach(l, node->withCheckOptionLists)
2466  {
2467  List *wcoList = (List *) lfirst(l);
2468  List *wcoExprs = NIL;
2469  ListCell *ll;
2470 
2471  foreach(ll, wcoList)
2472  {
2473  WithCheckOption *wco = (WithCheckOption *) lfirst(ll);
2474  ExprState *wcoExpr = ExecInitQual((List *) wco->qual,
2475  &mtstate->ps);
2476 
2477  wcoExprs = lappend(wcoExprs, wcoExpr);
2478  }
2479 
2480  resultRelInfo->ri_WithCheckOptions = wcoList;
2481  resultRelInfo->ri_WithCheckOptionExprs = wcoExprs;
2482  resultRelInfo++;
2483  i++;
2484  }
2485 
2486  /*
2487  * Initialize RETURNING projections if needed.
2488  */
2489  if (node->returningLists)
2490  {
2491  TupleTableSlot *slot;
2492  ExprContext *econtext;
2493 
2494  /*
2495  * Initialize result tuple slot and assign its rowtype using the first
2496  * RETURNING list. We assume the rest will look the same.
2497  */
2498  mtstate->ps.plan->targetlist = (List *) linitial(node->returningLists);
2499 
2500  /* Set up a slot for the output of the RETURNING projection(s) */
2502  slot = mtstate->ps.ps_ResultTupleSlot;
2503 
2504  /* Need an econtext too */
2505  if (mtstate->ps.ps_ExprContext == NULL)
2506  ExecAssignExprContext(estate, &mtstate->ps);
2507  econtext = mtstate->ps.ps_ExprContext;
2508 
2509  /*
2510  * Build a projection for each result rel.
2511  */
2512  resultRelInfo = mtstate->resultRelInfo;
2513  foreach(l, node->returningLists)
2514  {
2515  List *rlist = (List *) lfirst(l);
2516 
2517  resultRelInfo->ri_returningList = rlist;
2518  resultRelInfo->ri_projectReturning =
2519  ExecBuildProjectionInfo(rlist, econtext, slot, &mtstate->ps,
2520  resultRelInfo->ri_RelationDesc->rd_att);
2521  resultRelInfo++;
2522  }
2523  }
2524  else
2525  {
2526  /*
2527  * We still must construct a dummy result tuple type, because InitPlan
2528  * expects one (maybe should change that?).
2529  */
2530  mtstate->ps.plan->targetlist = NIL;
2531  ExecInitResultTypeTL(&mtstate->ps);
2532 
2533  mtstate->ps.ps_ExprContext = NULL;
2534  }
2535 
2536  /* Set the list of arbiter indexes if needed for ON CONFLICT */
2537  resultRelInfo = mtstate->resultRelInfo;
2538  if (node->onConflictAction != ONCONFLICT_NONE)
2539  resultRelInfo->ri_onConflictArbiterIndexes = node->arbiterIndexes;
2540 
2541  /*
2542  * If needed, Initialize target list, projection and qual for ON CONFLICT
2543  * DO UPDATE.
2544  */
2545  if (node->onConflictAction == ONCONFLICT_UPDATE)
2546  {
2547  ExprContext *econtext;
2548  TupleDesc relationDesc;
2549  TupleDesc tupDesc;
2550 
2551  /* insert may only have one plan, inheritance is not expanded */
2552  Assert(nplans == 1);
2553 
2554  /* already exists if created by RETURNING processing above */
2555  if (mtstate->ps.ps_ExprContext == NULL)
2556  ExecAssignExprContext(estate, &mtstate->ps);
2557 
2558  econtext = mtstate->ps.ps_ExprContext;
2559  relationDesc = resultRelInfo->ri_RelationDesc->rd_att;
2560 
2561  /* create state for DO UPDATE SET operation */
2562  resultRelInfo->ri_onConflict = makeNode(OnConflictSetState);
2563 
2564  /* initialize slot for the existing tuple */
2565  resultRelInfo->ri_onConflict->oc_Existing =
2566  table_slot_create(resultRelInfo->ri_RelationDesc,
2567  &mtstate->ps.state->es_tupleTable);
2568 
2569  /*
2570  * Create the tuple slot for the UPDATE SET projection. We want a slot
2571  * of the table's type here, because the slot will be used to insert
2572  * into the table, and for RETURNING processing - which may access
2573  * system attributes.
2574  */
2575  tupDesc = ExecTypeFromTL((List *) node->onConflictSet);
2576  resultRelInfo->ri_onConflict->oc_ProjSlot =
2577  ExecInitExtraTupleSlot(mtstate->ps.state, tupDesc,
2578  table_slot_callbacks(resultRelInfo->ri_RelationDesc));
2579 
2580  /* build UPDATE SET projection state */
2581  resultRelInfo->ri_onConflict->oc_ProjInfo =
2582  ExecBuildProjectionInfo(node->onConflictSet, econtext,
2583  resultRelInfo->ri_onConflict->oc_ProjSlot,
2584  &mtstate->ps,
2585  relationDesc);
2586 
2587  /* initialize state to evaluate the WHERE clause, if any */
2588  if (node->onConflictWhere)
2589  {
2590  ExprState *qualexpr;
2591 
2592  qualexpr = ExecInitQual((List *) node->onConflictWhere,
2593  &mtstate->ps);
2594  resultRelInfo->ri_onConflict->oc_WhereClause = qualexpr;
2595  }
2596  }
2597 
2598  /*
2599  * If we have any secondary relations in an UPDATE or DELETE, they need to
2600  * be treated like non-locked relations in SELECT FOR UPDATE, ie, the
2601  * EvalPlanQual mechanism needs to be told about them. Locate the
2602  * relevant ExecRowMarks.
2603  */
2604  foreach(l, node->rowMarks)
2605  {
2607  ExecRowMark *erm;
2608 
2609  /* ignore "parent" rowmarks; they are irrelevant at runtime */
2610  if (rc->isParent)
2611  continue;
2612 
2613  /* find ExecRowMark (same for all subplans) */
2614  erm = ExecFindRowMark(estate, rc->rti, false);
2615 
2616  /* build ExecAuxRowMark for each subplan */
2617  for (i = 0; i < nplans; i++)
2618  {
2619  ExecAuxRowMark *aerm;
2620 
2621  subplan = mtstate->mt_plans[i]->plan;
2622  aerm = ExecBuildAuxRowMark(erm, subplan->targetlist);
2623  mtstate->mt_arowmarks[i] = lappend(mtstate->mt_arowmarks[i], aerm);
2624  }
2625  }
2626 
2627  /* select first subplan */
2628  mtstate->mt_whichplan = 0;
2629  subplan = (Plan *) linitial(node->plans);
2630  EvalPlanQualSetPlan(&mtstate->mt_epqstate, subplan,
2631  mtstate->mt_arowmarks[0]);
2632 
2633  /*
2634  * Initialize the junk filter(s) if needed. INSERT queries need a filter
2635  * if there are any junk attrs in the tlist. UPDATE and DELETE always
2636  * need a filter, since there's always at least one junk attribute present
2637  * --- no need to look first. Typically, this will be a 'ctid' or
2638  * 'wholerow' attribute, but in the case of a foreign data wrapper it
2639  * might be a set of junk attributes sufficient to identify the remote
2640  * row.
2641  *
2642  * If there are multiple result relations, each one needs its own junk
2643  * filter. Note multiple rels are only possible for UPDATE/DELETE, so we
2644  * can't be fooled by some needing a filter and some not.
2645  *
2646  * This section of code is also a convenient place to verify that the
2647  * output of an INSERT or UPDATE matches the target table(s).
2648  */
2649  {
2650  bool junk_filter_needed = false;
2651 
2652  switch (operation)
2653  {
2654  case CMD_INSERT:
2655  foreach(l, subplan->targetlist)
2656  {
2657  TargetEntry *tle = (TargetEntry *) lfirst(l);
2658 
2659  if (tle->resjunk)
2660  {
2661  junk_filter_needed = true;
2662  break;
2663  }
2664  }
2665  break;
2666  case CMD_UPDATE:
2667  case CMD_DELETE:
2668  junk_filter_needed = true;
2669  break;
2670  default:
2671  elog(ERROR, "unknown operation");
2672  break;
2673  }
2674 
2675  if (junk_filter_needed)
2676  {
2677  resultRelInfo = mtstate->resultRelInfo;
2678  for (i = 0; i < nplans; i++)
2679  {
2680  JunkFilter *j;
2681  TupleTableSlot *junkresslot;
2682 
2683  subplan = mtstate->mt_plans[i]->plan;
2684  if (operation == CMD_INSERT || operation == CMD_UPDATE)
2685  ExecCheckPlanOutput(resultRelInfo->ri_RelationDesc,
2686  subplan->targetlist);
2687 
2688  junkresslot =
2689  ExecInitExtraTupleSlot(estate, NULL,
2690  table_slot_callbacks(resultRelInfo->ri_RelationDesc));
2691  j = ExecInitJunkFilter(subplan->targetlist,
2692  junkresslot);
2693 
2694  if (operation == CMD_UPDATE || operation == CMD_DELETE)
2695  {
2696  /* For UPDATE/DELETE, find the appropriate junk attr now */
2697  char relkind;
2698 
2699  relkind = resultRelInfo->ri_RelationDesc->rd_rel->relkind;
2700  if (relkind == RELKIND_RELATION ||
2701  relkind == RELKIND_MATVIEW ||
2702  relkind == RELKIND_PARTITIONED_TABLE)
2703  {
2704  j->jf_junkAttNo = ExecFindJunkAttribute(j, "ctid");
2706  elog(ERROR, "could not find junk ctid column");
2707  }
2708  else if (relkind == RELKIND_FOREIGN_TABLE)
2709  {
2710  /*
2711  * When there is a row-level trigger, there should be
2712  * a wholerow attribute.
2713  */
2714  j->jf_junkAttNo = ExecFindJunkAttribute(j, "wholerow");
2715  }
2716  else
2717  {
2718  j->jf_junkAttNo = ExecFindJunkAttribute(j, "wholerow");
2720  elog(ERROR, "could not find junk wholerow column");
2721  }
2722  }
2723 
2724  resultRelInfo->ri_junkFilter = j;
2725  resultRelInfo++;
2726  }
2727  }
2728  else
2729  {
2730  if (operation == CMD_INSERT)
2732  subplan->targetlist);
2733  }
2734  }
2735 
2736  /*
2737  * Lastly, if this is not the primary (canSetTag) ModifyTable node, add it
2738  * to estate->es_auxmodifytables so that it will be run to completion by
2739  * ExecPostprocessPlan. (It'd actually work fine to add the primary
2740  * ModifyTable node too, but there's no need.) Note the use of lcons not
2741  * lappend: we need later-initialized ModifyTable nodes to be shut down
2742  * before earlier ones. This ensures that we don't throw away RETURNING
2743  * rows that need to be seen by a later CTE subplan.
2744  */
2745  if (!mtstate->canSetTag)
2746  estate->es_auxmodifytables = lcons(mtstate,
2747  estate->es_auxmodifytables);
2748 
2749  return mtstate;
2750 }
TupleTableSlot * table_slot_create(Relation relation, List **reglist)
Definition: tableam.c:91
AttrNumber jf_junkAttNo
Definition: execnodes.h:373
#define NIL
Definition: pg_list.h:65
JunkFilter * ri_junkFilter
Definition: execnodes.h:466
List * arbiterIndexes
Definition: plannodes.h:237
Relation ri_RelationDesc
Definition: execnodes.h:413
Bitmapset * fdwDirectModifyPlans
Definition: plannodes.h:233
TupleTableSlot * ExecInitExtraTupleSlot(EState *estate, TupleDesc tupledesc, const TupleTableSlotOps *tts_ops)
Definition: execTuples.c:1801
static ResultRelInfo * getTargetResultRelInfo(ModifyTableState *node)
struct PartitionTupleRouting * mt_partition_tuple_routing
Definition: execnodes.h:1188
List * withCheckOptionLists
Definition: plannodes.h:230
int resultRelIndex
Definition: plannodes.h:227
ResultRelInfo * resultRelInfo
Definition: execnodes.h:1174
AttrNumber ExecFindJunkAttribute(JunkFilter *junkfilter, const char *attrName)
Definition: execJunk.c:208
ExprContext * ps_ExprContext
Definition: execnodes.h:984
TupleTableSlot ** mt_scans
Definition: execnodes.h:1172
const TupleTableSlotOps * table_slot_callbacks(Relation relation)
Definition: tableam.c:58
const TupleTableSlotOps TTSOpsVirtual
Definition: execTuples.c:83
bool partColsUpdated
Definition: plannodes.h:225
bool canSetTag
Definition: plannodes.h:222
CmdType operation
Definition: execnodes.h:1166
ResultRelInfo * rootResultRelInfo
Definition: execnodes.h:1175
void EvalPlanQualSetPlan(EPQState *epqstate, Plan *subplan, List *auxrowmarks)
Definition: execMain.c:2524
EState * state
Definition: execnodes.h:947
Form_pg_class rd_rel
Definition: rel.h:109
List * plans
Definition: plannodes.h:229
ExprState * ExecInitQual(List *qual, PlanState *parent)
Definition: execExpr.c:209
List * onConflictSet
Definition: plannodes.h:238
int rootResultRelIndex
Definition: plannodes.h:228
void ExecOpenIndices(ResultRelInfo *resultRelInfo, bool speculative)
Definition: execIndexing.c:151
List * ri_WithCheckOptionExprs
Definition: execnodes.h:454
TupleTableSlot * oc_Existing
Definition: execnodes.h:385
TupleTableSlot * ps_ResultTupleSlot
Definition: execnodes.h:983
static void ExecSetupChildParentMapForSubplan(ModifyTableState *mtstate)
List * rowMarks
Definition: plannodes.h:234
bool resjunk
Definition: primnodes.h:1414
#define linitial(l)
Definition: pg_list.h:195
#define ERROR
Definition: elog.h:43
PlanState ps
Definition: execnodes.h:1165
ProjectionInfo * oc_ProjInfo
Definition: execnodes.h:387
static void * list_nth(const List *list, int n)
Definition: pg_list.h:277
bool ri_usesFdwDirectModify
Definition: execnodes.h:448
static void ExecSetupTransitionCaptureState(ModifyTableState *mtstate, EState *estate)
void CheckValidResultRel(ResultRelInfo *resultRelInfo, CmdType operation)
Definition: execMain.c:1076
#define EXEC_FLAG_BACKWARD
Definition: executor.h:58
#define lfirst_node(type, lc)
Definition: pg_list.h:193
ResultRelInfo * es_result_relations
Definition: execnodes.h:525
void ExecInitResultTypeTL(PlanState *planstate)
Definition: execTuples.c:1725
List * fdwPrivLists
Definition: plannodes.h:232
EPQState mt_epqstate
Definition: execnodes.h:1178
bool trig_update_before_row
Definition: reltrigger.h:61
ProjectionInfo * ri_projectReturning
Definition: execnodes.h:472
struct FdwRoutine * ri_FdwRoutine
Definition: execnodes.h:442
ExprState * oc_WhereClause
Definition: execnodes.h:388
PartitionTupleRouting * ExecSetupPartitionTupleRouting(EState *estate, ModifyTableState *mtstate, Relation rel)
TriggerDesc * ri_TrigDesc
Definition: execnodes.h:425
List * lappend(List *list, void *datum)
Definition: list.c:321
PlanState ** mt_plans
Definition: execnodes.h:1169
void EvalPlanQualInit(EPQState *epqstate, EState *parentestate, Plan *subplan, List *auxrowmarks, int epqParam)
Definition: execMain.c:2486
OnConflictSetState * ri_onConflict
Definition: execnodes.h:478
#define AttributeNumberIsValid(attributeNumber)
Definition: attnum.h:34
static TupleTableSlot * ExecModifyTable(PlanState *pstate)
List * es_tupleTable
Definition: execnodes.h:557
void * palloc0(Size size)
Definition: mcxt.c:980
List * es_auxmodifytables
Definition: execnodes.h:569
ExecProcNodeMtd ExecProcNode
Definition: execnodes.h:951
List * ri_WithCheckOptions
Definition: execnodes.h:451
TupleDesc rd_att
Definition: rel.h:110
Plan * plan
Definition: execnodes.h:945
TupleTableSlot * oc_ProjSlot
Definition: execnodes.h:386
List * lcons(void *datum, List *list)
Definition: list.c:453
#define makeNode(_type_)
Definition: nodes.h:577
static void ExecCheckPlanOutput(Relation resultRel, List *targetList)
#define Assert(condition)
Definition: c.h:745
#define lfirst(lc)
Definition: pg_list.h:190
#define EXEC_FLAG_MARK
Definition: executor.h:59
OnConflictAction onConflictAction
Definition: plannodes.h:236
void ExecAssignExprContext(EState *estate, PlanState *planstate)
Definition: execUtils.c:485
static int list_length(const List *l)
Definition: pg_list.h:169
TupleDesc ExecTypeFromTL(List *targetList)
Definition: execTuples.c:1908
void ExecInitResultTupleSlotTL(PlanState *planstate, const TupleTableSlotOps *tts_ops)
Definition: execTuples.c:1769
TupleTableSlot * mt_root_tuple_slot
Definition: execnodes.h:1185
TupleDesc ExecGetResultType(PlanState *planstate)
Definition: execUtils.c:495
List * targetlist
Definition: plannodes.h:142
ProjectionInfo * ExecBuildProjectionInfo(List *targetList, ExprContext *econtext, TupleTableSlot *slot, PlanState *parent, TupleDesc inputDesc)
Definition: execExpr.c:353
CmdType operation
Definition: plannodes.h:221
ResultRelInfo * es_root_result_relations
Definition: execnodes.h:535
#define elog(elevel,...)
Definition: elog.h:214
int i
List * returningLists
Definition: plannodes.h:231
bool isParent
Definition: plannodes.h:1084
BeginForeignModify_function BeginForeignModify
Definition: fdwapi.h:210
PlanState * ExecInitNode(Plan *node, EState *estate, int eflags)
Definition: execProcnode.c:139
Definition: pg_list.h:50
bool bms_is_member(int x, const Bitmapset *a)
Definition: bitmapset.c:427
#define EXEC_FLAG_EXPLAIN_ONLY
Definition: executor.h:56
JunkFilter * ExecInitJunkFilter(List *targetList, TupleTableSlot *slot)
Definition: execJunk.c:60
List * ri_onConflictArbiterIndexes
Definition: execnodes.h:475
CmdType
Definition: nodes.h:672
RelationPtr ri_IndexRelationDescs
Definition: execnodes.h:419
ExecAuxRowMark * ExecBuildAuxRowMark(ExecRowMark *erm, List *targetlist)
Definition: execMain.c:2362
List * ri_returningList
Definition: execnodes.h:469
List ** mt_arowmarks
Definition: execnodes.h:1177
int epqParam
Definition: plannodes.h:235
Node * onConflictWhere
Definition: plannodes.h:239
ExecRowMark * ExecFindRowMark(EState *estate, Index rti, bool missing_ok)
Definition: execMain.c:2339
ResultRelInfo * es_result_relation_info
Definition: execnodes.h:527

◆ ExecInsert()

static TupleTableSlot* ExecInsert ( ModifyTableState mtstate,
TupleTableSlot slot,
TupleTableSlot planSlot,
EState estate,
bool  canSetTag 
)
static

Definition at line 375 of file nodeModifyTable.c.

References Assert, CMD_INSERT, CMD_UPDATE, TupleDescData::constr, EState::es_output_cid, EState::es_processed, EState::es_result_relation_info, ExecARInsertTriggers(), ExecARUpdateTriggers(), ExecBRInsertTriggers(), ExecCheckIndexConstraints(), ExecCheckTIDVisible(), ExecComputeStoredGenerated(), ExecConstraints(), FdwRoutine::ExecForeignInsert, ExecGetReturningSlot(), ExecInsertIndexTuples(), ExecIRInsertTriggers(), ExecMaterializeSlot(), ExecOnConflictUpdate(), ExecPartitionCheck(), ExecProcessReturning(), ExecWithCheckOptions(), GetCurrentTransactionId(), TupleConstr::has_generated_stored, InstrCountTuples2, list_free(), ModifyTableState::mt_transition_capture, NIL, ONCONFLICT_NONE, ONCONFLICT_NOTHING, ONCONFLICT_UPDATE, ModifyTable::onConflictAction, ModifyTableState::operation, PlanState::plan, ModifyTableState::ps, RelationData::rd_att, RelationGetRelid, ResultRelInfo::ri_FdwRoutine, ResultRelInfo::ri_NumIndices, ResultRelInfo::ri_onConflictArbiterIndexes, ResultRelInfo::ri_PartitionCheck, ResultRelInfo::ri_PartitionRoot, ResultRelInfo::ri_projectReturning, ResultRelInfo::ri_RelationDesc, ResultRelInfo::ri_TrigDesc, ResultRelInfo::ri_WithCheckOptions, setLastTid(), SpeculativeInsertionLockAcquire(), SpeculativeInsertionLockRelease(), table_tuple_complete_speculative(), table_tuple_insert(), table_tuple_insert_speculative(), TransitionCaptureState::tcs_update_new_table, TriggerDesc::trig_insert_before_row, TriggerDesc::trig_insert_instead_row, TupleTableSlot::tts_tableOid, TupleTableSlot::tts_tid, WCO_RLS_INSERT_CHECK, WCO_RLS_UPDATE_CHECK, and WCO_VIEW_CHECK.

Referenced by ExecModifyTable(), and ExecUpdate().

380 {
381  ResultRelInfo *resultRelInfo;
382  Relation resultRelationDesc;
383  List *recheckIndexes = NIL;
384  TupleTableSlot *result = NULL;
385  TransitionCaptureState *ar_insert_trig_tcs;
386  ModifyTable *node = (ModifyTable *) mtstate->ps.plan;
387  OnConflictAction onconflict = node->onConflictAction;
388 
389  ExecMaterializeSlot(slot);
390 
391  /*
392  * get information on the (current) result relation
393  */
394  resultRelInfo = estate->es_result_relation_info;
395  resultRelationDesc = resultRelInfo->ri_RelationDesc;
396 
397  /*
398  * BEFORE ROW INSERT Triggers.
399  *
400  * Note: We fire BEFORE ROW TRIGGERS for every attempted insertion in an
401  * INSERT ... ON CONFLICT statement. We cannot check for constraint
402  * violations before firing these triggers, because they can change the
403  * values to insert. Also, they can run arbitrary user-defined code with
404  * side-effects that we can't cancel by just not inserting the tuple.
405  */
406  if (resultRelInfo->ri_TrigDesc &&
407  resultRelInfo->ri_TrigDesc->trig_insert_before_row)
408  {
409  if (!ExecBRInsertTriggers(estate, resultRelInfo, slot))
410  return NULL; /* "do nothing" */
411  }
412 
413  /* INSTEAD OF ROW INSERT Triggers */
414  if (resultRelInfo->ri_TrigDesc &&
415  resultRelInfo->ri_TrigDesc->trig_insert_instead_row)
416  {
417  if (!ExecIRInsertTriggers(estate, resultRelInfo, slot))
418  return NULL; /* "do nothing" */
419  }
420  else if (resultRelInfo->ri_FdwRoutine)
421  {
422  /*
423  * Compute stored generated columns
424  */
425  if (resultRelationDesc->rd_att->constr &&
426  resultRelationDesc->rd_att->constr->has_generated_stored)
427  ExecComputeStoredGenerated(estate, slot, CMD_INSERT);
428 
429  /*
430  * insert into foreign table: let the FDW do it
431  */
432  slot = resultRelInfo->ri_FdwRoutine->ExecForeignInsert(estate,
433  resultRelInfo,
434  slot,
435  planSlot);
436 
437  if (slot == NULL) /* "do nothing" */
438  return NULL;
439 
440  /*
441  * AFTER ROW Triggers or RETURNING expressions might reference the
442  * tableoid column, so (re-)initialize tts_tableOid before evaluating
443  * them.
444  */
445  slot->tts_tableOid = RelationGetRelid(resultRelInfo->ri_RelationDesc);
446  }
447  else
448  {
449  WCOKind wco_kind;
450 
451  /*
452  * Constraints might reference the tableoid column, so (re-)initialize
453  * tts_tableOid before evaluating them.
454  */
455  slot->tts_tableOid = RelationGetRelid(resultRelationDesc);
456 
457  /*
458  * Compute stored generated columns
459  */
460  if (resultRelationDesc->rd_att->constr &&
461  resultRelationDesc->rd_att->constr->has_generated_stored)
462  ExecComputeStoredGenerated(estate, slot, CMD_INSERT);
463 
464  /*
465  * Check any RLS WITH CHECK policies.
466  *
467  * Normally we should check INSERT policies. But if the insert is the
468  * result of a partition key update that moved the tuple to a new
469  * partition, we should instead check UPDATE policies, because we are
470  * executing policies defined on the target table, and not those
471  * defined on the child partitions.
472  */
473  wco_kind = (mtstate->operation == CMD_UPDATE) ?
475 
476  /*
477  * ExecWithCheckOptions() will skip any WCOs which are not of the kind
478  * we are looking for at this point.
479  */
480  if (resultRelInfo->ri_WithCheckOptions != NIL)
481  ExecWithCheckOptions(wco_kind, resultRelInfo, slot, estate);
482 
483  /*
484  * Check the constraints of the tuple.
485  */
486  if (resultRelationDesc->rd_att->constr)
487  ExecConstraints(resultRelInfo, slot, estate);
488 
489  /*
490  * Also check the tuple against the partition constraint, if there is
491  * one; except that if we got here via tuple-routing, we don't need to
492  * if there's no BR trigger defined on the partition.
493  */
494  if (resultRelInfo->ri_PartitionCheck &&
495  (resultRelInfo->ri_PartitionRoot == NULL ||
496  (resultRelInfo->ri_TrigDesc &&
497  resultRelInfo->ri_TrigDesc->trig_insert_before_row)))
498  ExecPartitionCheck(resultRelInfo, slot, estate, true);
499 
500  if (onconflict != ONCONFLICT_NONE && resultRelInfo->ri_NumIndices > 0)
501  {
502  /* Perform a speculative insertion. */
503  uint32 specToken;
504  ItemPointerData conflictTid;
505  bool specConflict;
506  List *arbiterIndexes;
507 
508  arbiterIndexes = resultRelInfo->ri_onConflictArbiterIndexes;
509 
510  /*
511  * Do a non-conclusive check for conflicts first.
512  *
513  * We're not holding any locks yet, so this doesn't guarantee that
514  * the later insert won't conflict. But it avoids leaving behind
515  * a lot of canceled speculative insertions, if you run a lot of
516  * INSERT ON CONFLICT statements that do conflict.
517  *
518  * We loop back here if we find a conflict below, either during
519  * the pre-check, or when we re-check after inserting the tuple
520  * speculatively.
521  */
522  vlock:
523  specConflict = false;
524  if (!ExecCheckIndexConstraints(slot, estate, &conflictTid,
525  arbiterIndexes))
526  {
527  /* committed conflict tuple found */
528  if (onconflict == ONCONFLICT_UPDATE)
529  {
530  /*
531  * In case of ON CONFLICT DO UPDATE, execute the UPDATE
532  * part. Be prepared to retry if the UPDATE fails because
533  * of another concurrent UPDATE/DELETE to the conflict
534  * tuple.
535  */
536  TupleTableSlot *returning = NULL;
537 
538  if (ExecOnConflictUpdate(mtstate, resultRelInfo,
539  &conflictTid, planSlot, slot,
540  estate, canSetTag, &returning))
541  {
542  InstrCountTuples2(&mtstate->ps, 1);
543  return returning;
544  }
545  else
546  goto vlock;
547  }
548  else
549  {
550  /*
551  * In case of ON CONFLICT DO NOTHING, do nothing. However,
552  * verify that the tuple is visible to the executor's MVCC
553  * snapshot at higher isolation levels.
554  *
555  * Using ExecGetReturningSlot() to store the tuple for the
556  * recheck isn't that pretty, but we can't trivially use
557  * the input slot, because it might not be of a compatible
558  * type. As there's no conflicting usage of
559  * ExecGetReturningSlot() in the DO NOTHING case...
560  */
561  Assert(onconflict == ONCONFLICT_NOTHING);
562  ExecCheckTIDVisible(estate, resultRelInfo, &conflictTid,
563  ExecGetReturningSlot(estate, resultRelInfo));
564  InstrCountTuples2(&mtstate->ps, 1);
565  return NULL;
566  }
567  }
568 
569  /*
570  * Before we start insertion proper, acquire our "speculative
571  * insertion lock". Others can use that to wait for us to decide
572  * if we're going to go ahead with the insertion, instead of
573  * waiting for the whole transaction to complete.
574  */
576 
577  /* insert the tuple, with the speculative token */
578  table_tuple_insert_speculative(resultRelationDesc, slot,
579  estate->es_output_cid,
580  0,
581  NULL,
582  specToken);
583 
584  /* insert index entries for tuple */
585  recheckIndexes = ExecInsertIndexTuples(slot, estate, true,
586  &specConflict,
587  arbiterIndexes);
588 
589  /* adjust the tuple's state accordingly */
590  table_tuple_complete_speculative(resultRelationDesc, slot,
591  specToken, !specConflict);
592 
593  /*
594  * Wake up anyone waiting for our decision. They will re-check
595  * the tuple, see that it's no longer speculative, and wait on our
596  * XID as if this was a regularly inserted tuple all along. Or if
597  * we killed the tuple, they will see it's dead, and proceed as if
598  * the tuple never existed.
599  */
601 
602  /*
603  * If there was a conflict, start from the beginning. We'll do
604  * the pre-check again, which will now find the conflicting tuple
605  * (unless it aborts before we get there).
606  */
607  if (specConflict)
608  {
609  list_free(recheckIndexes);
610  goto vlock;
611  }
612 
613  /* Since there was no insertion conflict, we're done */
614  }
615  else
616  {
617  /* insert the tuple normally */
618  table_tuple_insert(resultRelationDesc, slot,
619  estate->es_output_cid,
620  0, NULL);
621 
622  /* insert index entries for tuple */
623  if (resultRelInfo->ri_NumIndices > 0)
624  recheckIndexes = ExecInsertIndexTuples(slot, estate, false, NULL,
625  NIL);
626  }
627  }
628 
629  if (canSetTag)
630  {
631  (estate->es_processed)++;
632  setLastTid(&slot->tts_tid);
633  }
634 
635  /*
636  * If this insert is the result of a partition key update that moved the
637  * tuple to a new partition, put this row into the transition NEW TABLE,
638  * if there is one. We need to do this separately for DELETE and INSERT
639  * because they happen on different tables.
640  */
641  ar_insert_trig_tcs = mtstate->mt_transition_capture;
642  if (mtstate->operation == CMD_UPDATE && mtstate->mt_transition_capture
644  {
645  ExecARUpdateTriggers(estate, resultRelInfo, NULL,
646  NULL,
647  slot,
648  NULL,
649  mtstate->mt_transition_capture);
650 
651  /*
652  * We've already captured the NEW TABLE row, so make sure any AR
653  * INSERT trigger fired below doesn't capture it again.
654  */
655  ar_insert_trig_tcs = NULL;
656  }
657 
658  /* AFTER ROW INSERT Triggers */
659  ExecARInsertTriggers(estate, resultRelInfo, slot, recheckIndexes,
660  ar_insert_trig_tcs);
661 
662  list_free(recheckIndexes);
663 
664  /*
665  * Check any WITH CHECK OPTION constraints from parent views. We are
666  * required to do this after testing all constraints and uniqueness
667  * violations per the SQL spec, so we do it after actually inserting the
668  * record into the heap and all indexes.
669  *
670  * ExecWithCheckOptions will elog(ERROR) if a violation is found, so the
671  * tuple will never be seen, if it violates the WITH CHECK OPTION.
672  *
673  * ExecWithCheckOptions() will skip any WCOs which are not of the kind we
674  * are looking for at this point.
675  */
676  if (resultRelInfo->ri_WithCheckOptions != NIL)
677  ExecWithCheckOptions(WCO_VIEW_CHECK, resultRelInfo, slot, estate);
678 
679  /* Process RETURNING if present */
680  if (resultRelInfo->ri_projectReturning)
681  result = ExecProcessReturning(resultRelInfo, slot, planSlot);
682 
683  return result;
684 }
int ri_NumIndices
Definition: execnodes.h:416
#define NIL
Definition: pg_list.h:65
Oid tts_tableOid
Definition: tuptable.h:131
Relation ri_RelationDesc
Definition: execnodes.h:413
void SpeculativeInsertionLockRelease(TransactionId xid)
Definition: lmgr.c:765
static bool ExecOnConflictUpdate(ModifyTableState *mtstate, ResultRelInfo *resultRelInfo, ItemPointer conflictTid, TupleTableSlot *planSlot, TupleTableSlot *excludedSlot, EState *estate, bool canSetTag, TupleTableSlot **returning)
void ExecARInsertTriggers(EState *estate, ResultRelInfo *relinfo, TupleTableSlot *slot, List *recheckIndexes, TransitionCaptureState *transition_capture)
Definition: trigger.c:2268
void ExecWithCheckOptions(WCOKind kind, ResultRelInfo *resultRelInfo, TupleTableSlot *slot, EState *estate)
Definition: execMain.c:2028
TupleTableSlot * ExecGetReturningSlot(EState *estate, ResultRelInfo *relInfo)
Definition: execUtils.c:1189
CommandId es_output_cid
Definition: execnodes.h:522
ExecForeignInsert_function ExecForeignInsert
Definition: fdwapi.h:211
Relation ri_PartitionRoot
Definition: execnodes.h:487
void ExecComputeStoredGenerated(EState *estate, TupleTableSlot *slot, CmdType cmdtype)
void ExecConstraints(ResultRelInfo *resultRelInfo, TupleTableSlot *slot, EState *estate)
Definition: execMain.c:1897
uint32 SpeculativeInsertionLockAcquire(TransactionId xid)
Definition: lmgr.c:739
CmdType operation
Definition: execnodes.h:1166
static void table_tuple_complete_speculative(Relation rel, TupleTableSlot *slot, uint32 specToken, bool succeeded)
Definition: tableam.h:1211
bool ExecCheckIndexConstraints(TupleTableSlot *slot, EState *estate, ItemPointer conflictTid, List *arbiterIndexes)
Definition: execIndexing.c:482
static void table_tuple_insert(Relation rel, TupleTableSlot *slot, CommandId cid, int options, struct BulkInsertStateData *bistate)
Definition: tableam.h:1178
bool trig_insert_instead_row
Definition: reltrigger.h:58
bool has_generated_stored
Definition: tupdesc.h:45
PlanState ps
Definition: execnodes.h:1165
bool ExecBRInsertTriggers(EState *estate, ResultRelInfo *relinfo, TupleTableSlot *slot)
Definition: trigger.c:2192
static void ExecCheckTIDVisible(EState *estate, ResultRelInfo *relinfo, ItemPointer tid, TupleTableSlot *tempSlot)
List * ExecInsertIndexTuples(TupleTableSlot *slot, EState *estate, bool noDupErr, bool *specConflict, List *arbiterIndexes)
Definition: execIndexing.c:273
TransactionId GetCurrentTransactionId(void)
Definition: xact.c:438
struct TransitionCaptureState * mt_transition_capture
Definition: execnodes.h:1191
TupleConstr * constr
Definition: tupdesc.h:85
ProjectionInfo * ri_projectReturning
Definition: execnodes.h:472
struct FdwRoutine * ri_FdwRoutine
Definition: execnodes.h:442
unsigned int uint32
Definition: c.h:374
#define InstrCountTuples2(node, delta)
Definition: execnodes.h:1042
void setLastTid(const ItemPointer tid)
Definition: tid.c:281
WCOKind
Definition: parsenodes.h:1178
TriggerDesc * ri_TrigDesc
Definition: execnodes.h:425
static TupleTableSlot * ExecProcessReturning(ResultRelInfo *resultRelInfo, TupleTableSlot *tupleSlot, TupleTableSlot *planSlot)
void ExecARUpdateTriggers(EState *estate, ResultRelInfo *relinfo, ItemPointer tupleid, HeapTuple fdw_trigtuple, TupleTableSlot *newslot, List *recheckIndexes, TransitionCaptureState *transition_capture)
Definition: trigger.c:2783
bool trig_insert_before_row
Definition: reltrigger.h:56
static void table_tuple_insert_speculative(Relation rel, TupleTableSlot *slot, CommandId cid, int options, struct BulkInsertStateData *bistate, uint32 specToken)
Definition: tableam.h:1197
List * ri_WithCheckOptions
Definition: execnodes.h:451
List * ri_PartitionCheck
Definition: execnodes.h:481
TupleDesc rd_att
Definition: rel.h:110
static void ExecMaterializeSlot(TupleTableSlot *slot)
Definition: tuptable.h:443
Plan * plan
Definition: execnodes.h:945
#define Assert(condition)
Definition: c.h:745
bool ExecIRInsertTriggers(EState *estate, ResultRelInfo *relinfo, TupleTableSlot *slot)
Definition: trigger.c:2283
OnConflictAction onConflictAction
Definition: plannodes.h:236
uint64 es_processed
Definition: execnodes.h:559
void list_free(List *list)
Definition: list.c:1376
bool ExecPartitionCheck(ResultRelInfo *resultRelInfo, TupleTableSlot *slot, EState *estate, bool emitError)
Definition: execMain.c:1783
Definition: pg_list.h:50
ItemPointerData tts_tid
Definition: tuptable.h:130
OnConflictAction
Definition: nodes.h:822
#define RelationGetRelid(relation)
Definition: rel.h:456
List * ri_onConflictArbiterIndexes
Definition: execnodes.h:475
ResultRelInfo * es_result_relation_info
Definition: execnodes.h:527

◆ ExecModifyTable()

static TupleTableSlot* ExecModifyTable ( PlanState pstate)
static

Definition at line 2016 of file nodeModifyTable.c.

References Assert, AttributeNumberIsValid, ModifyTableState::canSetTag, castNode, CHECK_FOR_INTERRUPTS, CMD_DELETE, CMD_INSERT, CMD_UPDATE, DatumGetHeapTupleHeader, DatumGetPointer, elog, ERROR, EState::es_epq_active, EState::es_result_relation_info, EvalPlanQualSetPlan(), EvalPlanQualSetSlot, ExecCopySlot(), ExecDelete(), ExecFilterJunk(), ExecGetJunkAttribute(), ExecInsert(), ExecPrepareTupleRouting(), ExecProcessReturning(), ExecProcNode(), ExecUpdate(), fireASTriggers(), ModifyTableState::fireBSTriggers, fireBSTriggers(), HeapTupleHeaderGetDatumLength, InvalidOid, ItemPointerSetInvalid, JunkFilter::jf_junkAttNo, ModifyTableState::mt_arowmarks, ModifyTableState::mt_done, ModifyTableState::mt_epqstate, ModifyTableState::mt_nplans, ModifyTableState::mt_oc_transition_capture, ModifyTableState::mt_partition_tuple_routing, ModifyTableState::mt_plans, ModifyTableState::mt_scans, ModifyTableState::mt_transition_capture, ModifyTableState::mt_whichplan, ModifyTableState::operation, PlanState::plan, ModifyTableState::ps, PlanState::ps_ExprContext, RelationData::rd_rel, RelationGetRelid, ResetExprContext, ResetPerTupleExprContext, ModifyTableState::resultRelInfo, ResultRelInfo::ri_junkFilter, ResultRelInfo::ri_projectReturning, ResultRelInfo::ri_RelationDesc, ResultRelInfo::ri_usesFdwDirectModify, PlanState::state, HeapTupleData::t_data, HeapTupleData::t_len, HeapTupleData::t_self, HeapTupleData::t_tableOid, TransitionCaptureState::tcs_map, TupleTableSlot::tts_ops, tupconv_map_for_subplan(), and TupIsNull.

Referenced by ExecInitModifyTable().

2017 {
2018  ModifyTableState *node = castNode(ModifyTableState, pstate);
2020  EState *estate = node->ps.state;
2021  CmdType operation = node->operation;
2022  ResultRelInfo *saved_resultRelInfo;
2023  ResultRelInfo *resultRelInfo;
2024  PlanState *subplanstate;
2025  JunkFilter *junkfilter;
2026  TupleTableSlot *slot;
2027  TupleTableSlot *planSlot;
2028  ItemPointer tupleid;
2029  ItemPointerData tuple_ctid;
2030  HeapTupleData oldtupdata;
2031  HeapTuple oldtuple;
2032 
2034 
2035  /*
2036  * This should NOT get called during EvalPlanQual; we should have passed a
2037  * subplan tree to EvalPlanQual, instead. Use a runtime test not just
2038  * Assert because this condition is easy to miss in testing. (Note:
2039  * although ModifyTable should not get executed within an EvalPlanQual
2040  * operation, we do have to allow it to be initialized and shut down in
2041  * case it is within a CTE subplan. Hence this test must be here, not in
2042  * ExecInitModifyTable.)
2043  */
2044  if (estate->es_epq_active != NULL)
2045  elog(ERROR, "ModifyTable should not be called during EvalPlanQual");
2046 
2047  /*
2048  * If we've already completed processing, don't try to do more. We need
2049  * this test because ExecPostprocessPlan might call us an extra time, and
2050  * our subplan's nodes aren't necessarily robust against being called
2051  * extra times.
2052  */
2053  if (node->mt_done)
2054  return NULL;
2055 
2056  /*
2057  * On first call, fire BEFORE STATEMENT triggers before proceeding.
2058  */
2059  if (node->fireBSTriggers)
2060  {
2061  fireBSTriggers(node);
2062  node->fireBSTriggers = false;
2063  }
2064 
2065  /* Preload local variables */
2066  resultRelInfo = node->resultRelInfo + node->mt_whichplan;
2067  subplanstate = node->mt_plans[node->mt_whichplan];
2068  junkfilter = resultRelInfo->ri_junkFilter;
2069 
2070  /*
2071  * es_result_relation_info must point to the currently active result
2072  * relation while we are within this ModifyTable node. Even though
2073  * ModifyTable nodes can't be nested statically, they can be nested
2074  * dynamically (since our subplan could include a reference to a modifying
2075  * CTE). So we have to save and restore the caller's value.
2076  */
2077  saved_resultRelInfo = estate->es_result_relation_info;
2078 
2079  estate->es_result_relation_info = resultRelInfo;
2080 
2081  /*
2082  * Fetch rows from subplan(s), and execute the required table modification
2083  * for each row.
2084  */
2085  for (;;)
2086  {
2087  /*
2088  * Reset the per-output-tuple exprcontext. This is needed because
2089  * triggers expect to use that context as workspace. It's a bit ugly
2090  * to do this below the top level of the plan, however. We might need
2091  * to rethink this later.
2092  */
2093  ResetPerTupleExprContext(estate);
2094 
2095  /*
2096  * Reset per-tuple memory context used for processing on conflict and
2097  * returning clauses, to free any expression evaluation storage
2098  * allocated in the previous cycle.
2099  */
2100  if (pstate->ps_ExprContext)
2102 
2103  planSlot = ExecProcNode(subplanstate);
2104 
2105  if (TupIsNull(planSlot))
2106  {
2107  /* advance to next subplan if any */
2108  node->mt_whichplan++;
2109  if (node->mt_whichplan < node->mt_nplans)
2110  {
2111  resultRelInfo++;
2112  subplanstate = node->mt_plans[node->mt_whichplan];
2113  junkfilter = resultRelInfo->ri_junkFilter;
2114  estate->es_result_relation_info = resultRelInfo;
2115  EvalPlanQualSetPlan(&node->mt_epqstate, subplanstate->plan,
2116  node->mt_arowmarks[node->mt_whichplan]);
2117  /* Prepare to convert transition tuples from this child. */
2118  if (node->mt_transition_capture != NULL)
2119  {
2122  }
2123  if (node->mt_oc_transition_capture != NULL)
2124  {
2127  }
2128  continue;
2129  }
2130  else
2131  break;
2132  }
2133 
2134  /*
2135  * Ensure input tuple is the right format for the target relation.
2136  */
2137  if (node->mt_scans[node->mt_whichplan]->tts_ops != planSlot->tts_ops)
2138  {
2139  ExecCopySlot(node->mt_scans[node->mt_whichplan], planSlot);
2140  planSlot = node->mt_scans[node->mt_whichplan];
2141  }
2142 
2143  /*
2144  * If resultRelInfo->ri_usesFdwDirectModify is true, all we need to do
2145  * here is compute the RETURNING expressions.
2146  */
2147  if (resultRelInfo->ri_usesFdwDirectModify)
2148  {
2149  Assert(resultRelInfo->ri_projectReturning);
2150 
2151  /*
2152  * A scan slot containing the data that was actually inserted,
2153  * updated or deleted has already been made available to
2154  * ExecProcessReturning by IterateDirectModify, so no need to
2155  * provide it here.
2156  */
2157  slot = ExecProcessReturning(resultRelInfo, NULL, planSlot);
2158 
2159  estate->es_result_relation_info = saved_resultRelInfo;
2160  return slot;
2161  }
2162 
2163  EvalPlanQualSetSlot(&node->mt_epqstate, planSlot);
2164  slot = planSlot;
2165 
2166  tupleid = NULL;
2167  oldtuple = NULL;
2168  if (junkfilter != NULL)
2169  {
2170  /*
2171  * extract the 'ctid' or 'wholerow' junk attribute.
2172  */
2173  if (operation == CMD_UPDATE || operation == CMD_DELETE)
2174  {
2175  char relkind;
2176  Datum datum;
2177  bool isNull;
2178 
2179  relkind = resultRelInfo->ri_RelationDesc->rd_rel->relkind;
2180  if (relkind == RELKIND_RELATION || relkind == RELKIND_MATVIEW)
2181  {
2182  datum = ExecGetJunkAttribute(slot,
2183  junkfilter->jf_junkAttNo,
2184  &isNull);
2185  /* shouldn't ever get a null result... */
2186  if (isNull)
2187  elog(ERROR, "ctid is NULL");
2188 
2189  tupleid = (ItemPointer) DatumGetPointer(datum);
2190  tuple_ctid = *tupleid; /* be sure we don't free ctid!! */
2191  tupleid = &tuple_ctid;
2192  }
2193 
2194  /*
2195  * Use the wholerow attribute, when available, to reconstruct
2196  * the old relation tuple.
2197  *
2198  * Foreign table updates have a wholerow attribute when the
2199  * relation has a row-level trigger. Note that the wholerow
2200  * attribute does not carry system columns. Foreign table
2201  * triggers miss seeing those, except that we know enough here
2202  * to set t_tableOid. Quite separately from this, the FDW may
2203  * fetch its own junk attrs to identify the row.
2204  *
2205  * Other relevant relkinds, currently limited to views, always
2206  * have a wholerow attribute.
2207  */
2208  else if (AttributeNumberIsValid(junkfilter->jf_junkAttNo))
2209  {
2210  datum = ExecGetJunkAttribute(slot,
2211  junkfilter->jf_junkAttNo,
2212  &isNull);
2213  /* shouldn't ever get a null result... */
2214  if (isNull)
2215  elog(ERROR, "wholerow is NULL");
2216 
2217  oldtupdata.t_data = DatumGetHeapTupleHeader(datum);
2218  oldtupdata.t_len =
2220  ItemPointerSetInvalid(&(oldtupdata.t_self));
2221  /* Historically, view triggers see invalid t_tableOid. */
2222  oldtupdata.t_tableOid =
2223  (relkind == RELKIND_VIEW) ? InvalidOid :
2224  RelationGetRelid(resultRelInfo->ri_RelationDesc);
2225 
2226  oldtuple = &oldtupdata;
2227  }
2228  else
2229  Assert(relkind == RELKIND_FOREIGN_TABLE);
2230  }
2231 
2232  /*
2233  * apply the junkfilter if needed.
2234  */
2235  if (operation != CMD_DELETE)
2236  slot = ExecFilterJunk(junkfilter, slot);
2237  }
2238 
2239  switch (operation)
2240  {
2241  case CMD_INSERT:
2242  /* Prepare for tuple routing if needed. */
2243  if (proute)
2244  slot = ExecPrepareTupleRouting(node, estate, proute,
2245  resultRelInfo, slot);
2246  slot = ExecInsert(node, slot, planSlot,
2247  estate, node->canSetTag);
2248  /* Revert ExecPrepareTupleRouting's state change. */
2249  if (proute)
2250  estate->es_result_relation_info = resultRelInfo;
2251  break;
2252  case CMD_UPDATE:
2253  slot = ExecUpdate(node, tupleid, oldtuple, slot, planSlot,
2254  &node->mt_epqstate, estate, node->canSetTag);
2255  break;
2256  case CMD_DELETE:
2257  slot = ExecDelete(node, tupleid, oldtuple, planSlot,
2258  &node->mt_epqstate, estate,
2259  true, node->canSetTag,
2260  false /* changingPart */ , NULL, NULL);
2261  break;
2262  default:
2263  elog(ERROR, "unknown operation");
2264  break;
2265  }
2266 
2267  /*
2268  * If we got a RETURNING result, return it to caller. We'll continue
2269  * the work on next call.
2270  */
2271  if (slot)
2272  {
2273  estate->es_result_relation_info = saved_resultRelInfo;
2274  return slot;
2275  }
2276  }
2277 
2278  /* Restore es_result_relation_info before exiting */
2279  estate->es_result_relation_info = saved_resultRelInfo;
2280 
2281  /*
2282  * We're done, but fire AFTER STATEMENT triggers before exiting.
2283  */
2284  fireASTriggers(node);
2285 
2286  node->mt_done = true;
2287 
2288  return NULL;
2289 }
AttrNumber jf_junkAttNo
Definition: execnodes.h:373
static TupleTableSlot * ExecCopySlot(TupleTableSlot *dstslot, TupleTableSlot *srcslot)
Definition: tuptable.h:475
JunkFilter * ri_junkFilter
Definition: execnodes.h:466
struct TransitionCaptureState * mt_oc_transition_capture
Definition: execnodes.h:1194
static TupleTableSlot * ExecDelete(ModifyTableState *mtstate, ItemPointer tupleid, HeapTuple oldtuple, TupleTableSlot *planSlot, EPQState *epqstate, EState *estate, bool processReturning, bool canSetTag, bool changingPart, bool *tupleDeleted, TupleTableSlot **epqreturnslot)
Relation ri_RelationDesc
Definition: execnodes.h:413
static TupleTableSlot * ExecInsert(ModifyTableState *mtstate, TupleTableSlot *slot, TupleTableSlot *planSlot, EState *estate, bool canSetTag)
#define ResetPerTupleExprContext(estate)
Definition: executor.h:516
struct PartitionTupleRouting * mt_partition_tuple_routing
Definition: execnodes.h:1188
#define castNode(_type_, nodeptr)
Definition: nodes.h:598
ResultRelInfo * resultRelInfo
Definition: execnodes.h:1174
static TupleTableSlot * ExecUpdate(ModifyTableState *mtstate, ItemPointer tupleid, HeapTuple oldtuple, TupleTableSlot *slot, TupleTableSlot *planSlot, EPQState *epqstate, EState *estate, bool canSetTag)
ExprContext * ps_ExprContext
Definition: execnodes.h:984
TupleTableSlot ** mt_scans
Definition: execnodes.h:1172
static void fireBSTriggers(ModifyTableState *node)
static TupleConversionMap * tupconv_map_for_subplan(ModifyTableState *node, int whichplan)
const TupleTableSlotOps *const tts_ops
Definition: tuptable.h:122
CmdType operation
Definition: execnodes.h:1166
void EvalPlanQualSetPlan(EPQState *epqstate, Plan *subplan, List *auxrowmarks)
Definition: execMain.c:2524
EState * state
Definition: execnodes.h:947
Form_pg_class rd_rel
Definition: rel.h:109
#define DatumGetHeapTupleHeader(X)
Definition: fmgr.h:294
struct EPQState * es_epq_active
Definition: execnodes.h:584
ItemPointerData * ItemPointer
Definition: itemptr.h:49
HeapTupleHeader t_data
Definition: htup.h:68
#define ERROR
Definition: elog.h:43
PlanState ps
Definition: execnodes.h:1165
TupleConversionMap * tcs_map
Definition: trigger.h:74
ItemPointerData t_self
Definition: htup.h:65
bool ri_usesFdwDirectModify
Definition: execnodes.h:448
uint32 t_len
Definition: htup.h:64
struct TransitionCaptureState * mt_transition_capture
Definition: execnodes.h:1191
EPQState mt_epqstate
Definition: execnodes.h:1178
ProjectionInfo * ri_projectReturning
Definition: execnodes.h:472
#define TupIsNull(slot)
Definition: tuptable.h:292
Oid t_tableOid
Definition: htup.h:66
static TupleTableSlot * ExecProcessReturning(ResultRelInfo *resultRelInfo, TupleTableSlot *tupleSlot, TupleTableSlot *planSlot)
PlanState ** mt_plans
Definition: execnodes.h:1169
static TupleTableSlot * ExecPrepareTupleRouting(ModifyTableState *mtstate, EState *estate, PartitionTupleRouting *proute, ResultRelInfo *targetRelInfo, TupleTableSlot *slot)
#define AttributeNumberIsValid(attributeNumber)
Definition: attnum.h:34
static void fireASTriggers(ModifyTableState *node)
uintptr_t Datum
Definition: postgres.h:367
TupleTableSlot * ExecFilterJunk(JunkFilter *junkfilter, TupleTableSlot *slot)
Definition: execJunk.c:261
static TupleTableSlot * ExecProcNode(PlanState *node)
Definition: executor.h:240
Plan * plan
Definition: execnodes.h:945
#define InvalidOid
Definition: postgres_ext.h:36
#define Assert(condition)
Definition: c.h:745
#define DatumGetPointer(X)
Definition: postgres.h:549
#define ItemPointerSetInvalid(pointer)
Definition: itemptr.h:172
Datum ExecGetJunkAttribute(TupleTableSlot *slot, AttrNumber attno, bool *isNull)
Definition: execJunk.c:247
#define elog(elevel,...)
Definition: elog.h:214
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:99
#define RelationGetRelid(relation)
Definition: rel.h:456
CmdType
Definition: nodes.h:672
#define ResetExprContext(econtext)
Definition: executor.h:501
List ** mt_arowmarks
Definition: execnodes.h:1177
#define EvalPlanQualSetSlot(epqstate, slot)
Definition: executor.h:215
#define HeapTupleHeaderGetDatumLength(tup)
Definition: htup_details.h:452
ResultRelInfo * es_result_relation_info
Definition: execnodes.h:527

◆ ExecOnConflictUpdate()

static bool ExecOnConflictUpdate ( ModifyTableState mtstate,
ResultRelInfo resultRelInfo,
ItemPointer  conflictTid,
TupleTableSlot planSlot,
TupleTableSlot excludedSlot,
EState estate,
bool  canSetTag,
TupleTableSlot **  returning 
)
static

Definition at line 1525 of file nodeModifyTable.c.

References Assert, TM_FailureData::ctid, DatumGetTransactionId, ExprContext::ecxt_innertuple, ExprContext::ecxt_outertuple, ExprContext::ecxt_scantuple, elog, ereport, errcode(), errhint(), errmsg(), ERROR, EState::es_output_cid, EState::es_snapshot, ExecCheckTupleVisible(), ExecClearTuple(), ExecProject(), ExecQual(), ExecUpdate(), ExecUpdateLockMode(), ExecWithCheckOptions(), InstrCountFiltered1, IsolationUsesXactSnapshot, ItemPointerIndicatesMovedPartitions, LockWaitBlock, MinTransactionIdAttributeNumber, ModifyTableState::mt_epqstate, NIL, OnConflictSetState::oc_Existing, OnConflictSetState::oc_ProjInfo, OnConflictSetState::oc_ProjSlot, OnConflictSetState::oc_WhereClause, ModifyTableState::ps, PlanState::ps_ExprContext, ResultRelInfo::ri_onConflict, ResultRelInfo::ri_RelationDesc, ResultRelInfo::ri_WithCheckOptions, slot_getsysattr(), PlanState::state, table_tuple_lock(), test(), TM_Deleted, TM_Invisible, TM_Ok, TM_SelfModified, TM_Updated, TransactionIdIsCurrentTransactionId(), and WCO_RLS_CONFLICT_CHECK.

Referenced by ExecInsert().

1533 {
1534  ExprContext *econtext = mtstate->ps.ps_ExprContext;
1535  Relation relation = resultRelInfo->ri_RelationDesc;
1536  ExprState *onConflictSetWhere = resultRelInfo->ri_onConflict->oc_WhereClause;
1537  TupleTableSlot *existing = resultRelInfo->ri_onConflict->oc_Existing;
1538  TM_FailureData tmfd;
1539  LockTupleMode lockmode;
1540  TM_Result test;
1541  Datum xminDatum;
1542  TransactionId xmin;
1543  bool isnull;
1544 
1545  /* Determine lock mode to use */
1546  lockmode = ExecUpdateLockMode(estate, resultRelInfo);
1547 
1548  /*
1549  * Lock tuple for update. Don't follow updates when tuple cannot be
1550  * locked without doing so. A row locking conflict here means our
1551  * previous conclusion that the tuple is conclusively committed is not
1552  * true anymore.
1553  */
1554  test = table_tuple_lock(relation, conflictTid,
1555  estate->es_snapshot,
1556  existing, estate->es_output_cid,
1557  lockmode, LockWaitBlock, 0,
1558  &tmfd);
1559  switch (test)
1560  {
1561  case TM_Ok:
1562  /* success! */
1563  break;
1564 
1565  case TM_Invisible:
1566 
1567  /*
1568  * This can occur when a just inserted tuple is updated again in
1569  * the same command. E.g. because multiple rows with the same
1570  * conflicting key values are inserted.
1571  *
1572  * This is somewhat similar to the ExecUpdate() TM_SelfModified
1573  * case. We do not want to proceed because it would lead to the
1574  * same row being updated a second time in some unspecified order,
1575  * and in contrast to plain UPDATEs there's no historical behavior
1576  * to break.
1577  *
1578  * It is the user's responsibility to prevent this situation from
1579  * occurring. These problems are why SQL-2003 similarly specifies
1580  * that for SQL MERGE, an exception must be raised in the event of
1581  * an attempt to update the same row twice.
1582  */
1583  xminDatum = slot_getsysattr(existing,
1585  &isnull);
1586  Assert(!isnull);
1587  xmin = DatumGetTransactionId(xminDatum);
1588 
1590  ereport(ERROR,
1591  (errcode(ERRCODE_CARDINALITY_VIOLATION),
1592  errmsg("ON CONFLICT DO UPDATE command cannot affect row a second time"),
1593  errhint("Ensure that no rows proposed for insertion within the same command have duplicate constrained values.")));
1594 
1595  /* This shouldn't happen */
1596  elog(ERROR, "attempted to lock invisible tuple");
1597  break;
1598 
1599  case TM_SelfModified:
1600 
1601  /*
1602  * This state should never be reached. As a dirty snapshot is used
1603  * to find conflicting tuples, speculative insertion wouldn't have
1604  * seen this row to conflict with.
1605  */
1606  elog(ERROR, "unexpected self-updated tuple");
1607  break;
1608 
1609  case TM_Updated:
1611  ereport(ERROR,
1612  (errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
1613  errmsg("could not serialize access due to concurrent update")));
1614 
1615  /*
1616  * As long as we don't support an UPDATE of INSERT ON CONFLICT for
1617  * a partitioned table we shouldn't reach to a case where tuple to
1618  * be lock is moved to another partition due to concurrent update
1619  * of the partition key.
1620  */
1622 
1623  /*
1624  * Tell caller to try again from the very start.
1625  *
1626  * It does not make sense to use the usual EvalPlanQual() style
1627  * loop here, as the new version of the row might not conflict
1628  * anymore, or the conflicting tuple has actually been deleted.
1629  */
1630  ExecClearTuple(existing);
1631  return false;
1632 
1633  case TM_Deleted:
1635  ereport(ERROR,
1636  (errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
1637  errmsg("could not serialize access due to concurrent delete")));
1638 
1639  /* see TM_Updated case */
1641  ExecClearTuple(existing);
1642  return false;
1643 
1644  default:
1645  elog(ERROR, "unrecognized table_tuple_lock status: %u", test);
1646  }
1647 
1648  /* Success, the tuple is locked. */
1649 
1650  /*
1651  * Verify that the tuple is visible to our MVCC snapshot if the current
1652  * isolation level mandates that.
1653  *
1654  * It's not sufficient to rely on the check within ExecUpdate() as e.g.
1655  * CONFLICT ... WHERE clause may prevent us from reaching that.
1656  *
1657  * This means we only ever continue when a new command in the current
1658  * transaction could see the row, even though in READ COMMITTED mode the
1659  * tuple will not be visible according to the current statement's
1660  * snapshot. This is in line with the way UPDATE deals with newer tuple
1661  * versions.
1662  */
1663  ExecCheckTupleVisible(estate, relation, existing);
1664 
1665  /*
1666  * Make tuple and any needed join variables available to ExecQual and
1667  * ExecProject. The EXCLUDED tuple is installed in ecxt_innertuple, while
1668  * the target's existing tuple is installed in the scantuple. EXCLUDED
1669  * has been made to reference INNER_VAR in setrefs.c, but there is no
1670  * other redirection.
1671  */
1672  econtext->ecxt_scantuple = existing;
1673  econtext->ecxt_innertuple = excludedSlot;
1674  econtext->ecxt_outertuple = NULL;
1675 
1676  if (!ExecQual(onConflictSetWhere, econtext))
1677  {
1678  ExecClearTuple(existing); /* see return below */
1679  InstrCountFiltered1(&mtstate->ps, 1);
1680  return true; /* done with the tuple */
1681  }
1682 
1683  if (resultRelInfo->ri_WithCheckOptions != NIL)
1684  {
1685  /*
1686  * Check target's existing tuple against UPDATE-applicable USING
1687  * security barrier quals (if any), enforced here as RLS checks/WCOs.
1688  *
1689  * The rewriter creates UPDATE RLS checks/WCOs for UPDATE security
1690  * quals, and stores them as WCOs of "kind" WCO_RLS_CONFLICT_CHECK,
1691  * but that's almost the extent of its special handling for ON
1692  * CONFLICT DO UPDATE.
1693  *
1694  * The rewriter will also have associated UPDATE applicable straight
1695  * RLS checks/WCOs for the benefit of the ExecUpdate() call that
1696  * follows. INSERTs and UPDATEs naturally have mutually exclusive WCO
1697  * kinds, so there is no danger of spurious over-enforcement in the
1698  * INSERT or UPDATE path.
1699  */
1701  existing,
1702  mtstate->ps.state);
1703  }
1704 
1705  /* Project the new tuple version */
1706  ExecProject(resultRelInfo->ri_onConflict->oc_ProjInfo);
1707 
1708  /*
1709  * Note that it is possible that the target tuple has been modified in
1710  * this session, after the above table_tuple_lock. We choose to not error
1711  * out in that case, in line with ExecUpdate's treatment of similar cases.
1712  * This can happen if an UPDATE is triggered from within ExecQual(),
1713  * ExecWithCheckOptions() or ExecProject() above, e.g. by selecting from a
1714  * wCTE in the ON CONFLICT's SET.
1715  */
1716 
1717  /* Execute UPDATE with projection */
1718  *returning = ExecUpdate(mtstate, conflictTid, NULL,
1719  resultRelInfo->ri_onConflict->oc_ProjSlot,
1720  planSlot,
1721  &mtstate->mt_epqstate, mtstate->ps.state,
1722  canSetTag);
1723 
1724  /*
1725  * Clear out existing tuple, as there might not be another conflict among
1726  * the next input rows. Don't want to hold resources till the end of the
1727  * query.
1728  */
1729  ExecClearTuple(existing);
1730  return true;
1731 }
#define NIL
Definition: pg_list.h:65
ItemPointerData ctid
Definition: tableam.h:125
Relation ri_RelationDesc
Definition: execnodes.h:413
LockTupleMode
Definition: lockoptions.h:49
int errhint(const char *fmt,...)
Definition: elog.c:1071
void ExecWithCheckOptions(WCOKind kind, ResultRelInfo *resultRelInfo, TupleTableSlot *slot, EState *estate)
Definition: execMain.c:2028
CommandId es_output_cid
Definition: execnodes.h:522
static void test(void)
static TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition: tuptable.h:425
uint32 TransactionId
Definition: c.h:520
bool TransactionIdIsCurrentTransactionId(TransactionId xid)
Definition: xact.c:869
static TupleTableSlot * ExecUpdate(ModifyTableState *mtstate, ItemPointer tupleid, HeapTuple oldtuple, TupleTableSlot *slot, TupleTableSlot *planSlot, EPQState *epqstate, EState *estate, bool canSetTag)
ExprContext * ps_ExprContext
Definition: execnodes.h:984
#define IsolationUsesXactSnapshot()
Definition: xact.h:51
int errcode(int sqlerrcode)
Definition: elog.c:610
Snapshot es_snapshot
Definition: execnodes.h:508
EState * state
Definition: execnodes.h:947
static void ExecCheckTupleVisible(EState *estate, Relation rel, TupleTableSlot *slot)
static bool ExecQual(ExprState *state, ExprContext *econtext)
Definition: executor.h:370
TupleTableSlot * oc_Existing
Definition: execnodes.h:385
#define ERROR
Definition: elog.h:43
PlanState ps
Definition: execnodes.h:1165
ProjectionInfo * oc_ProjInfo
Definition: execnodes.h:387
static TM_Result table_tuple_lock(Relation rel, ItemPointer tid, Snapshot snapshot, TupleTableSlot *slot, CommandId cid, LockTupleMode mode, LockWaitPolicy wait_policy, uint8 flags, TM_FailureData *tmfd)
Definition: tableam.h:1356
EPQState mt_epqstate
Definition: execnodes.h:1178
TupleTableSlot * ecxt_innertuple
Definition: execnodes.h:228
ExprState * oc_WhereClause
Definition: execnodes.h:388
#define InstrCountFiltered1(node, delta)
Definition: execnodes.h:1047
OnConflictSetState * ri_onConflict
Definition: execnodes.h:478
TM_Result
Definition: tableam.h:70
uintptr_t Datum
Definition: postgres.h:367
List * ri_WithCheckOptions
Definition: execnodes.h:451
#define ItemPointerIndicatesMovedPartitions(pointer)
Definition: itemptr.h:184
#define ereport(elevel,...)
Definition: elog.h:144
TupleTableSlot * oc_ProjSlot
Definition: execnodes.h:386
TupleTableSlot * ecxt_outertuple
Definition: execnodes.h:230
#define Assert(condition)
Definition: c.h:745
LockTupleMode ExecUpdateLockMode(EState *estate, ResultRelInfo *relinfo)
Definition: execMain.c:2313
Definition: tableam.h:76
TupleTableSlot * ecxt_scantuple
Definition: execnodes.h:226
#define DatumGetTransactionId(X)
Definition: postgres.h:514
int errmsg(const char *fmt,...)
Definition: elog.c:824
#define elog(elevel,...)
Definition: elog.h:214
static Datum slot_getsysattr(TupleTableSlot *slot, int attnum, bool *isnull)
Definition: tuptable.h:402
#define MinTransactionIdAttributeNumber
Definition: sysattr.h:22
static TupleTableSlot * ExecProject(ProjectionInfo *projInfo)
Definition: executor.h:333

◆ ExecPrepareTupleRouting()

static TupleTableSlot * ExecPrepareTupleRouting ( ModifyTableState mtstate,
EState estate,
PartitionTupleRouting proute,
ResultRelInfo targetRelInfo,
TupleTableSlot slot 
)
static

Definition at line 1883 of file nodeModifyTable.c.

References Assert, TupleConversionMap::attrMap, EState::es_result_relation_info, ExecFindPartition(), execute_attr_map_slot(), ModifyTableState::mt_oc_transition_capture, ModifyTableState::mt_transition_capture, PartitionRoutingInfo::pi_PartitionToRootMap, PartitionRoutingInfo::pi_PartitionTupleSlot, PartitionRoutingInfo::pi_RootToPartitionMap, ResultRelInfo::ri_PartitionInfo, ResultRelInfo::ri_TrigDesc, TransitionCaptureState::tcs_map, TransitionCaptureState::tcs_original_insert_tuple, and TriggerDesc::trig_insert_before_row.

Referenced by ExecModifyTable(), and ExecUpdate().

1888 {
1889  ResultRelInfo *partrel;
1890  PartitionRoutingInfo *partrouteinfo;
1891  TupleConversionMap *map;
1892 
1893  /*
1894  * Lookup the target partition's ResultRelInfo. If ExecFindPartition does
1895  * not find a valid partition for the tuple in 'slot' then an error is
1896  * raised. An error may also be raised if the found partition is not a
1897  * valid target for INSERTs. This is required since a partitioned table
1898  * UPDATE to another partition becomes a DELETE+INSERT.
1899  */
1900  partrel = ExecFindPartition(mtstate, targetRelInfo, proute, slot, estate);
1901  partrouteinfo = partrel->ri_PartitionInfo;
1902  Assert(partrouteinfo != NULL);
1903 
1904  /*
1905  * Make it look like we are inserting into the partition.
1906  */
1907  estate->es_result_relation_info = partrel;
1908 
1909  /*
1910  * If we're capturing transition tuples, we might need to convert from the
1911  * partition rowtype to root partitioned table's rowtype.
1912  */
1913  if (mtstate->mt_transition_capture != NULL)
1914  {
1915  if (partrel->ri_TrigDesc &&
1917  {
1918  /*
1919  * If there are any BEFORE triggers on the partition, we'll have
1920  * to be ready to convert their result back to tuplestore format.
1921  */
1923  mtstate->mt_transition_capture->tcs_map =
1924  partrouteinfo->pi_PartitionToRootMap;
1925  }
1926  else
1927  {
1928  /*
1929  * Otherwise, just remember the original unconverted tuple, to
1930  * avoid a needless round trip conversion.
1931  */
1933  mtstate->mt_transition_capture->tcs_map = NULL;
1934  }
1935  }
1936  if (mtstate->mt_oc_transition_capture != NULL)
1937  {
1938  mtstate->mt_oc_transition_capture->tcs_map =
1939  partrouteinfo->pi_PartitionToRootMap;
1940  }
1941 
1942  /*
1943  * Convert the tuple, if necessary.
1944  */
1945  map = partrouteinfo->pi_RootToPartitionMap;
1946  if (map != NULL)
1947  {
1948  TupleTableSlot *new_slot = partrouteinfo->pi_PartitionTupleSlot;
1949 
1950  slot = execute_attr_map_slot(map->attrMap, slot, new_slot);
1951  }
1952 
1953  return slot;
1954 }
struct TransitionCaptureState * mt_oc_transition_capture
Definition: execnodes.h:1194
struct PartitionRoutingInfo * ri_PartitionInfo
Definition: execnodes.h:490
TupleConversionMap * pi_RootToPartitionMap
Definition: execPartition.h:37
TupleConversionMap * tcs_map
Definition: trigger.h:74
struct TransitionCaptureState * mt_transition_capture
Definition: execnodes.h:1191
AttrMap * attrMap
Definition: tupconvert.h:27
TriggerDesc * ri_TrigDesc
Definition: execnodes.h:425
bool trig_insert_before_row
Definition: reltrigger.h:56
TupleConversionMap * pi_PartitionToRootMap
Definition: execPartition.h:43
TupleTableSlot * execute_attr_map_slot(AttrMap *attrMap, TupleTableSlot *in_slot, TupleTableSlot *out_slot)
Definition: tupconvert.c:177
#define Assert(condition)
Definition: c.h:745
ResultRelInfo * ExecFindPartition(ModifyTableState *mtstate, ResultRelInfo *rootResultRelInfo, PartitionTupleRouting *proute, TupleTableSlot *slot, EState *estate)
TupleTableSlot * pi_PartitionTupleSlot
Definition: execPartition.h:49
TupleTableSlot * tcs_original_insert_tuple
Definition: trigger.h:83
ResultRelInfo * es_result_relation_info
Definition: execnodes.h:527

◆ ExecProcessReturning()

static TupleTableSlot* ExecProcessReturning ( ResultRelInfo resultRelInfo,
TupleTableSlot tupleSlot,
TupleTableSlot planSlot 
)
static

Definition at line 162 of file nodeModifyTable.c.

References ExprContext::ecxt_outertuple, ExprContext::ecxt_scantuple, ExecProject(), ProjectionInfo::pi_exprContext, RelationGetRelid, ResultRelInfo::ri_projectReturning, ResultRelInfo::ri_RelationDesc, and TupleTableSlot::tts_tableOid.

Referenced by ExecDelete(), ExecInsert(), ExecModifyTable(), and ExecUpdate().

165 {
166  ProjectionInfo *projectReturning = resultRelInfo->ri_projectReturning;
167  ExprContext *econtext = projectReturning->pi_exprContext;
168 
169  /* Make tuple and any needed join variables available to ExecProject */
170  if (tupleSlot)
171  econtext->ecxt_scantuple = tupleSlot;
172  econtext->ecxt_outertuple = planSlot;
173 
174  /*
175  * RETURNING expressions might reference the tableoid column, so
176  * reinitialize tts_tableOid before evaluating them.
177  */
178  econtext->ecxt_scantuple->tts_tableOid =
179  RelationGetRelid(resultRelInfo->ri_RelationDesc);
180 
181  /* Compute the RETURNING expressions */
182  return ExecProject(projectReturning);
183 }
Oid tts_tableOid
Definition: tuptable.h:131
Relation ri_RelationDesc
Definition: execnodes.h:413
ProjectionInfo * ri_projectReturning
Definition: execnodes.h:472
TupleTableSlot * ecxt_outertuple
Definition: execnodes.h:230
TupleTableSlot * ecxt_scantuple
Definition: execnodes.h:226
ExprContext * pi_exprContext
Definition: execnodes.h:335
#define RelationGetRelid(relation)
Definition: rel.h:456
static TupleTableSlot * ExecProject(ProjectionInfo *projInfo)
Definition: executor.h:333

◆ ExecReScanModifyTable()

void ExecReScanModifyTable ( ModifyTableState node)

Definition at line 2815 of file nodeModifyTable.c.

References elog, and ERROR.

Referenced by ExecReScan().

2816 {
2817  /*
2818  * Currently, we don't need to support rescan on ModifyTable nodes. The
2819  * semantics of that would be a bit debatable anyway.
2820  */
2821  elog(ERROR, "ExecReScanModifyTable is not implemented");
2822 }
#define ERROR
Definition: elog.h:43
#define elog(elevel,...)
Definition: elog.h:214

◆ ExecSetupChildParentMapForSubplan()

static void ExecSetupChildParentMapForSubplan ( ModifyTableState mtstate)
static

Definition at line 1966 of file nodeModifyTable.c.

References convert_tuples_by_name(), getTargetResultRelInfo(), i, ModifyTableState::mt_nplans, ModifyTableState::mt_per_subplan_tupconv_maps, palloc(), RelationGetDescr, ModifyTableState::resultRelInfo, and ResultRelInfo::ri_RelationDesc.

Referenced by ExecInitModifyTable(), ExecSetupTransitionCaptureState(), and tupconv_map_for_subplan().

1967 {
1968  ResultRelInfo *targetRelInfo = getTargetResultRelInfo(mtstate);
1969  ResultRelInfo *resultRelInfos = mtstate->resultRelInfo;
1970  TupleDesc outdesc;
1971  int numResultRelInfos = mtstate->mt_nplans;
1972  int i;
1973 
1974  /*
1975  * Build array of conversion maps from each child's TupleDesc to the one
1976  * used in the target relation. The map pointers may be NULL when no
1977  * conversion is necessary, which is hopefully a common case.
1978  */
1979 
1980  /* Get tuple descriptor of the target rel. */
1981  outdesc = RelationGetDescr(targetRelInfo->ri_RelationDesc);
1982 
1984  palloc(sizeof(TupleConversionMap *) * numResultRelInfos);
1985 
1986  for (i = 0; i < numResultRelInfos; ++i)
1987  {
1988  mtstate->mt_per_subplan_tupconv_maps[i] =
1989  convert_tuples_by_name(RelationGetDescr(resultRelInfos[i].ri_RelationDesc),
1990  outdesc);
1991  }
1992 }
Relation ri_RelationDesc
Definition: execnodes.h:413
static ResultRelInfo * getTargetResultRelInfo(ModifyTableState *node)
#define RelationGetDescr(relation)
Definition: rel.h:482
ResultRelInfo * resultRelInfo
Definition: execnodes.h:1174
TupleConversionMap * convert_tuples_by_name(TupleDesc indesc, TupleDesc outdesc)
Definition: tupconvert.c:102
TupleConversionMap ** mt_per_subplan_tupconv_maps
Definition: execnodes.h:1197
void * palloc(Size size)
Definition: mcxt.c:949
int i

◆ ExecSetupTransitionCaptureState()

static void ExecSetupTransitionCaptureState ( ModifyTableState mtstate,
EState estate 
)
static

Definition at line 1831 of file nodeModifyTable.c.

References CMD_INSERT, CMD_UPDATE, ExecSetupChildParentMapForSubplan(), getTargetResultRelInfo(), MakeTransitionCaptureState(), ModifyTableState::mt_oc_transition_capture, ModifyTableState::mt_transition_capture, ONCONFLICT_UPDATE, ModifyTable::onConflictAction, ModifyTable::operation, ModifyTableState::operation, PlanState::plan, ModifyTableState::ps, RelationGetRelid, TransitionCaptureState::tcs_map, and tupconv_map_for_subplan().

Referenced by ExecInitModifyTable().

1832 {
1833  ModifyTable *plan = (ModifyTable *) mtstate->ps.plan;
1834  ResultRelInfo *targetRelInfo = getTargetResultRelInfo(mtstate);
1835 
1836  /* Check for transition tables on the directly targeted relation. */
1837  mtstate->mt_transition_capture =
1838  MakeTransitionCaptureState(targetRelInfo->ri_TrigDesc,
1839  RelationGetRelid(targetRelInfo->ri_RelationDesc),
1840  mtstate->operation);
1841  if (plan->operation == CMD_INSERT &&
1843  mtstate->mt_oc_transition_capture =
1844  MakeTransitionCaptureState(targetRelInfo->ri_TrigDesc,
1845  RelationGetRelid(targetRelInfo->ri_RelationDesc),
1846  CMD_UPDATE);
1847 
1848  /*
1849  * If we found that we need to collect transition tuples then we may also
1850  * need tuple conversion maps for any children that have TupleDescs that
1851  * aren't compatible with the tuplestores. (We can share these maps
1852  * between the regular and ON CONFLICT cases.)
1853  */
1854  if (mtstate->mt_transition_capture != NULL ||
1855  mtstate->mt_oc_transition_capture != NULL)
1856  {
1858 
1859  /*
1860  * Install the conversion map for the first plan for UPDATE and DELETE
1861  * operations. It will be advanced each time we switch to the next
1862  * plan. (INSERT operations set it every time, so we need not update
1863  * mtstate->mt_oc_transition_capture here.)
1864  */
1865  if (mtstate->mt_transition_capture && mtstate->operation != CMD_INSERT)
1866  mtstate->mt_transition_capture->tcs_map =
1867  tupconv_map_for_subplan(mtstate, 0);
1868  }
1869 }
struct TransitionCaptureState * mt_oc_transition_capture
Definition: execnodes.h:1194
static ResultRelInfo * getTargetResultRelInfo(ModifyTableState *node)
static TupleConversionMap * tupconv_map_for_subplan(ModifyTableState *node, int whichplan)
CmdType operation
Definition: execnodes.h:1166
static void ExecSetupChildParentMapForSubplan(ModifyTableState *mtstate)
PlanState ps
Definition: execnodes.h:1165
TupleConversionMap * tcs_map
Definition: trigger.h:74
struct TransitionCaptureState * mt_transition_capture
Definition: execnodes.h:1191
TransitionCaptureState * MakeTransitionCaptureState(TriggerDesc *trigdesc, Oid relid, CmdType cmdType)
Definition: trigger.c:4310
Plan * plan
Definition: execnodes.h:945
OnConflictAction onConflictAction
Definition: plannodes.h:236
CmdType operation
Definition: plannodes.h:221
#define RelationGetRelid(relation)
Definition: rel.h:456

◆ ExecUpdate()

static TupleTableSlot* ExecUpdate ( ModifyTableState mtstate,
ItemPointer  tupleid,
HeapTuple  oldtuple,
TupleTableSlot slot,
TupleTableSlot planSlot,
EPQState epqstate,
EState estate,
bool  canSetTag 
)
static

Definition at line 1069 of file nodeModifyTable.c.

References Assert, TupleConversionMap::attrMap, TM_FailureData::cmax, CMD_INSERT, CMD_UPDATE, TupleDescData::constr, elog, ereport, errcode(), errdetail(), errhint(), errmsg(), ERROR, EState::es_crosscheck_snapshot, EState::es_output_cid, EState::es_processed, EState::es_result_relation_info, EState::es_snapshot, EvalPlanQual(), EvalPlanQualSlot(), ExecARUpdateTriggers(), ExecBRUpdateTriggers(), ExecComputeStoredGenerated(), ExecConstraints(), ExecDelete(), ExecFilterJunk(), FdwRoutine::ExecForeignUpdate, ExecInsert(), ExecInsertIndexTuples(), ExecIRUpdateTriggers(), ExecMaterializeSlot(), ExecPartitionCheck(), ExecPartitionCheckEmitError(), ExecPrepareTupleRouting(), ExecProcessReturning(), execute_attr_map_slot(), ExecWithCheckOptions(), TupleConstr::has_generated_stored, IsBootstrapProcessingMode, IsolationUsesXactSnapshot, list_free(), LockWaitBlock, ModifyTableState::mt_oc_transition_capture, ModifyTableState::mt_partition_tuple_routing, ModifyTableState::mt_root_tuple_slot, ModifyTableState::mt_transition_capture, NIL, ONCONFLICT_UPDATE, ModifyTableState::operation, PlanState::plan, ModifyTableState::ps, RelationData::rd_att, RelationGetRelid, ModifyTableState::resultRelInfo, ResultRelInfo::ri_FdwRoutine, ResultRelInfo::ri_junkFilter, ResultRelInfo::ri_NumIndices, ResultRelInfo::ri_PartitionCheck, ResultRelInfo::ri_projectReturning, ResultRelInfo::ri_RangeTableIndex, ResultRelInfo::ri_RelationDesc, ResultRelInfo::ri_TrigDesc, ResultRelInfo::ri_WithCheckOptions, ModifyTableState::rootResultRelInfo, table_tuple_lock(), table_tuple_update(), TransitionCaptureState::tcs_map, TransitionCaptureState::tcs_original_insert_tuple, TM_Deleted, TM_Ok, TM_SelfModified, TM_Updated, TM_FailureData::traversed, TriggerDesc::trig_update_before_row, TriggerDesc::trig_update_instead_row, TupleTableSlot::tts_tableOid, tupconv_map_for_subplan(), TupIsNull, TUPLE_LOCK_FLAG_FIND_LAST_VERSION, WCO_RLS_UPDATE_CHECK, and WCO_VIEW_CHECK.

Referenced by ExecModifyTable(), and ExecOnConflictUpdate().

1077 {
1078  ResultRelInfo *resultRelInfo;
1079  Relation resultRelationDesc;
1080  TM_Result result;
1081  TM_FailureData tmfd;
1082  List *recheckIndexes = NIL;
1083  TupleConversionMap *saved_tcs_map = NULL;
1084 
1085  /*
1086  * abort the operation if not running transactions
1087  */
1089  elog(ERROR, "cannot UPDATE during bootstrap");
1090 
1091  ExecMaterializeSlot(slot);
1092 
1093  /*
1094  * get information on the (current) result relation
1095  */
1096  resultRelInfo = estate->es_result_relation_info;
1097  resultRelationDesc = resultRelInfo->ri_RelationDesc;
1098 
1099  /* BEFORE ROW UPDATE Triggers */
1100  if (resultRelInfo->ri_TrigDesc &&
1101  resultRelInfo->ri_TrigDesc->trig_update_before_row)
1102  {
1103  if (!ExecBRUpdateTriggers(estate, epqstate, resultRelInfo,
1104  tupleid, oldtuple, slot))
1105  return NULL; /* "do nothing" */
1106  }
1107 
1108  /* INSTEAD OF ROW UPDATE Triggers */
1109  if (resultRelInfo->ri_TrigDesc &&
1110  resultRelInfo->ri_TrigDesc->trig_update_instead_row)
1111  {
1112  if (!ExecIRUpdateTriggers(estate, resultRelInfo,
1113  oldtuple, slot))
1114  return NULL; /* "do nothing" */
1115  }
1116  else if (resultRelInfo->ri_FdwRoutine)
1117  {
1118  /*
1119  * Compute stored generated columns
1120  */
1121  if (resultRelationDesc->rd_att->constr &&
1122  resultRelationDesc->rd_att->constr->has_generated_stored)
1123  ExecComputeStoredGenerated(estate, slot, CMD_UPDATE);
1124 
1125  /*
1126  * update in foreign table: let the FDW do it
1127  */
1128  slot = resultRelInfo->ri_FdwRoutine->ExecForeignUpdate(estate,
1129  resultRelInfo,
1130  slot,
1131  planSlot);
1132 
1133  if (slot == NULL) /* "do nothing" */
1134  return NULL;
1135 
1136  /*
1137  * AFTER ROW Triggers or RETURNING expressions might reference the
1138  * tableoid column, so (re-)initialize tts_tableOid before evaluating
1139  * them.
1140  */
1141  slot->tts_tableOid = RelationGetRelid(resultRelationDesc);
1142  }
1143  else
1144  {
1145  LockTupleMode lockmode;
1146  bool partition_constraint_failed;
1147  bool update_indexes;
1148 
1149  /*
1150  * Constraints might reference the tableoid column, so (re-)initialize
1151  * tts_tableOid before evaluating them.
1152  */
1153  slot->tts_tableOid = RelationGetRelid(resultRelationDesc);
1154 
1155  /*
1156  * Compute stored generated columns
1157  */
1158  if (resultRelationDesc->rd_att->constr &&
1159  resultRelationDesc->rd_att->constr->has_generated_stored)
1160  ExecComputeStoredGenerated(estate, slot, CMD_UPDATE);
1161 
1162  /*
1163  * Check any RLS UPDATE WITH CHECK policies
1164  *
1165  * If we generate a new candidate tuple after EvalPlanQual testing, we
1166  * must loop back here and recheck any RLS policies and constraints.
1167  * (We don't need to redo triggers, however. If there are any BEFORE
1168  * triggers then trigger.c will have done table_tuple_lock to lock the
1169  * correct tuple, so there's no need to do them again.)
1170  */
1171 lreplace:;
1172 
1173  /* ensure slot is independent, consider e.g. EPQ */
1174  ExecMaterializeSlot(slot);
1175 
1176  /*
1177  * If partition constraint fails, this row might get moved to another
1178  * partition, in which case we should check the RLS CHECK policy just
1179  * before inserting into the new partition, rather than doing it here.
1180  * This is because a trigger on that partition might again change the
1181  * row. So skip the WCO checks if the partition constraint fails.
1182  */
1183  partition_constraint_failed =
1184  resultRelInfo->ri_PartitionCheck &&
1185  !ExecPartitionCheck(resultRelInfo, slot, estate, false);
1186 
1187  if (!partition_constraint_failed &&
1188  resultRelInfo->ri_WithCheckOptions != NIL)
1189  {
1190  /*
1191  * ExecWithCheckOptions() will skip any WCOs which are not of the
1192  * kind we are looking for at this point.
1193  */
1195  resultRelInfo, slot, estate);
1196  }
1197 
1198  /*
1199  * If a partition check failed, try to move the row into the right
1200  * partition.
1201  */
1202  if (partition_constraint_failed)
1203  {
1204  bool tuple_deleted;
1205  TupleTableSlot *ret_slot;
1206  TupleTableSlot *epqslot = NULL;
1208  int map_index;
1209  TupleConversionMap *tupconv_map;
1210 
1211  /*
1212  * Disallow an INSERT ON CONFLICT DO UPDATE that causes the
1213  * original row to migrate to a different partition. Maybe this
1214  * can be implemented some day, but it seems a fringe feature with
1215  * little redeeming value.
1216  */
1217  if (((ModifyTable *) mtstate->ps.plan)->onConflictAction == ONCONFLICT_UPDATE)
1218  ereport(ERROR,
1219  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1220  errmsg("invalid ON UPDATE specification"),
1221  errdetail("The result tuple would appear in a different partition than the original tuple.")));
1222 
1223  /*
1224  * When an UPDATE is run on a leaf partition, we will not have
1225  * partition tuple routing set up. In that case, fail with
1226  * partition constraint violation error.
1227  */
1228  if (proute == NULL)
1229  ExecPartitionCheckEmitError(resultRelInfo, slot, estate);
1230 
1231  /*
1232  * Row movement, part 1. Delete the tuple, but skip RETURNING
1233  * processing. We want to return rows from INSERT.
1234  */
1235  ExecDelete(mtstate, tupleid, oldtuple, planSlot, epqstate,
1236  estate, false, false /* canSetTag */ ,
1237  true /* changingPart */ , &tuple_deleted, &epqslot);
1238 
1239  /*
1240  * For some reason if DELETE didn't happen (e.g. trigger prevented
1241  * it, or it was already deleted by self, or it was concurrently
1242  * deleted by another transaction), then we should skip the insert
1243  * as well; otherwise, an UPDATE could cause an increase in the
1244  * total number of rows across all partitions, which is clearly
1245  * wrong.
1246  *
1247  * For a normal UPDATE, the case where the tuple has been the
1248  * subject of a concurrent UPDATE or DELETE would be handled by
1249  * the EvalPlanQual machinery, but for an UPDATE that we've
1250  * translated into a DELETE from this partition and an INSERT into
1251  * some other partition, that's not available, because CTID chains
1252  * can't span relation boundaries. We mimic the semantics to a
1253  * limited extent by skipping the INSERT if the DELETE fails to
1254  * find a tuple. This ensures that two concurrent attempts to
1255  * UPDATE the same tuple at the same time can't turn one tuple
1256  * into two, and that an UPDATE of a just-deleted tuple can't
1257  * resurrect it.
1258  */
1259  if (!tuple_deleted)
1260  {
1261  /*
1262  * epqslot will be typically NULL. But when ExecDelete()
1263  * finds that another transaction has concurrently updated the
1264  * same row, it re-fetches the row, skips the delete, and
1265  * epqslot is set to the re-fetched tuple slot. In that case,
1266  * we need to do all the checks again.
1267  */
1268  if (TupIsNull(epqslot))
1269  return NULL;
1270  else
1271  {
1272  slot = ExecFilterJunk(resultRelInfo->ri_junkFilter, epqslot);
1273  goto lreplace;
1274  }
1275  }
1276 
1277  /*
1278  * Updates set the transition capture map only when a new subplan
1279  * is chosen. But for inserts, it is set for each row. So after
1280  * INSERT, we need to revert back to the map created for UPDATE;
1281  * otherwise the next UPDATE will incorrectly use the one created
1282  * for INSERT. So first save the one created for UPDATE.
1283  */
1284  if (mtstate->mt_transition_capture)
1285  saved_tcs_map = mtstate->mt_transition_capture->tcs_map;
1286 
1287  /*
1288  * resultRelInfo is one of the per-subplan resultRelInfos. So we
1289  * should convert the tuple into root's tuple descriptor, since
1290  * ExecInsert() starts the search from root. The tuple conversion
1291  * map list is in the order of mtstate->resultRelInfo[], so to
1292  * retrieve the one for this resultRel, we need to know the
1293  * position of the resultRel in mtstate->resultRelInfo[].
1294  */
1295  map_index = resultRelInfo - mtstate->resultRelInfo;
1296  Assert(map_index >= 0 && map_index < mtstate->mt_nplans);
1297  tupconv_map = tupconv_map_for_subplan(mtstate, map_index);
1298  if (tupconv_map != NULL)
1299  slot = execute_attr_map_slot(tupconv_map->attrMap,
1300  slot,
1301  mtstate->mt_root_tuple_slot);
1302 
1303  /*
1304  * Prepare for tuple routing, making it look like we're inserting
1305  * into the root.
1306  */
1307  Assert(mtstate->rootResultRelInfo != NULL);
1308  slot = ExecPrepareTupleRouting(mtstate, estate, proute,
1309  mtstate->rootResultRelInfo, slot);
1310 
1311  ret_slot = ExecInsert(mtstate, slot, planSlot,
1312  estate, canSetTag);
1313 
1314  /* Revert ExecPrepareTupleRouting's node change. */
1315  estate->es_result_relation_info = resultRelInfo;
1316  if (mtstate->mt_transition_capture)
1317  {
1319  mtstate->mt_transition_capture->tcs_map = saved_tcs_map;
1320  }
1321 
1322  return ret_slot;
1323  }
1324 
1325  /*
1326  * Check the constraints of the tuple. We've already checked the
1327  * partition constraint above; however, we must still ensure the tuple
1328  * passes all other constraints, so we will call ExecConstraints() and
1329  * have it validate all remaining checks.
1330  */
1331  if (resultRelationDesc->rd_att->constr)
1332  ExecConstraints(resultRelInfo, slot, estate);
1333 
1334  /*
1335  * replace the heap tuple
1336  *
1337  * Note: if es_crosscheck_snapshot isn't InvalidSnapshot, we check
1338  * that the row to be updated is visible to that snapshot, and throw a
1339  * can't-serialize error if not. This is a special-case behavior
1340  * needed for referential integrity updates in transaction-snapshot
1341  * mode transactions.
1342  */
1343  result = table_tuple_update(resultRelationDesc, tupleid, slot,
1344  estate->es_output_cid,
1345  estate->es_snapshot,
1346  estate->es_crosscheck_snapshot,
1347  true /* wait for commit */ ,
1348  &tmfd, &lockmode, &update_indexes);
1349 
1350  switch (result)
1351  {
1352  case TM_SelfModified:
1353 
1354  /*
1355  * The target tuple was already updated or deleted by the
1356  * current command, or by a later command in the current
1357  * transaction. The former case is possible in a join UPDATE
1358  * where multiple tuples join to the same target tuple. This
1359  * is pretty questionable, but Postgres has always allowed it:
1360  * we just execute the first update action and ignore
1361  * additional update attempts.
1362  *
1363  * The latter case arises if the tuple is modified by a
1364  * command in a BEFORE trigger, or perhaps by a command in a
1365  * volatile function used in the query. In such situations we
1366  * should not ignore the update, but it is equally unsafe to
1367  * proceed. We don't want to discard the original UPDATE
1368  * while keeping the triggered actions based on it; and we
1369  * have no principled way to merge this update with the
1370  * previous ones. So throwing an error is the only safe
1371  * course.
1372  *
1373  * If a trigger actually intends this type of interaction, it
1374  * can re-execute the UPDATE (assuming it can figure out how)
1375  * and then return NULL to cancel the outer update.
1376  */
1377  if (tmfd.cmax != estate->es_output_cid)
1378  ereport(ERROR,
1379  (errcode(ERRCODE_TRIGGERED_DATA_CHANGE_VIOLATION),
1380  errmsg("tuple to be updated was already modified by an operation triggered by the current command"),
1381  errhint("Consider using an AFTER trigger instead of a BEFORE trigger to propagate changes to other rows.")));
1382 
1383  /* Else, already updated by self; nothing to do */
1384  return NULL;
1385 
1386  case TM_Ok:
1387  break;
1388 
1389  case TM_Updated:
1390  {
1391  TupleTableSlot *inputslot;
1392  TupleTableSlot *epqslot;
1393 
1395  ereport(ERROR,
1396  (errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
1397  errmsg("could not serialize access due to concurrent update")));
1398 
1399  /*
1400  * Already know that we're going to need to do EPQ, so
1401  * fetch tuple directly into the right slot.
1402  */
1403  inputslot = EvalPlanQualSlot(epqstate, resultRelationDesc,
1404  resultRelInfo->ri_RangeTableIndex);
1405 
1406  result = table_tuple_lock(resultRelationDesc, tupleid,
1407  estate->es_snapshot,
1408  inputslot, estate->es_output_cid,
1409  lockmode, LockWaitBlock,
1411  &tmfd);
1412 
1413  switch (result)
1414  {
1415  case TM_Ok:
1416  Assert(tmfd.traversed);
1417 
1418  epqslot = EvalPlanQual(epqstate,
1419  resultRelationDesc,
1420  resultRelInfo->ri_RangeTableIndex,
1421  inputslot);
1422  if (TupIsNull(epqslot))
1423  /* Tuple not passing quals anymore, exiting... */
1424  return NULL;
1425 
1426  slot = ExecFilterJunk(resultRelInfo->ri_junkFilter, epqslot);
1427  goto lreplace;
1428 
1429  case TM_Deleted:
1430  /* tuple already deleted; nothing to do */
1431  return NULL;
1432 
1433  case TM_SelfModified:
1434 
1435  /*
1436  * This can be reached when following an update
1437  * chain from a tuple updated by another session,
1438  * reaching a tuple that was already updated in
1439  * this transaction. If previously modified by
1440  * this command, ignore the redundant update,
1441  * otherwise error out.
1442  *
1443  * See also TM_SelfModified response to
1444  * table_tuple_update() above.
1445  */
1446  if (tmfd.cmax != estate->es_output_cid)
1447  ereport(ERROR,
1448  (errcode(ERRCODE_TRIGGERED_DATA_CHANGE_VIOLATION),
1449  errmsg("tuple to be updated was already modified by an operation triggered by the current command"),
1450  errhint("Consider using an AFTER trigger instead of a BEFORE trigger to propagate changes to other rows.")));
1451  return NULL;
1452 
1453  default:
1454  /* see table_tuple_lock call in ExecDelete() */
1455  elog(ERROR, "unexpected table_tuple_lock status: %u",
1456  result);
1457  return NULL;
1458  }
1459  }
1460 
1461  break;
1462 
1463  case TM_Deleted:
1465  ereport(ERROR,
1466  (errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
1467  errmsg("could not serialize access due to concurrent delete")));
1468  /* tuple already deleted; nothing to do */
1469  return NULL;
1470 
1471  default:
1472  elog(ERROR, "unrecognized table_tuple_update status: %u",
1473  result);
1474  return NULL;
1475  }
1476 
1477  /* insert index entries for tuple if necessary */
1478  if (resultRelInfo->ri_NumIndices > 0 && update_indexes)
1479  recheckIndexes = ExecInsertIndexTuples(slot, estate, false, NULL, NIL);
1480  }
1481 
1482  if (canSetTag)
1483  (estate->es_processed)++;
1484 
1485  /* AFTER ROW UPDATE Triggers */
1486  ExecARUpdateTriggers(estate, resultRelInfo, tupleid, oldtuple, slot,
1487  recheckIndexes,
1488  mtstate->operation == CMD_INSERT ?
1489  mtstate->mt_oc_transition_capture :
1490  mtstate->mt_transition_capture);
1491 
1492  list_free(recheckIndexes);
1493 
1494  /*
1495  * Check any WITH CHECK OPTION constraints from parent views. We are
1496  * required to do this after testing all constraints and uniqueness
1497  * violations per the SQL spec, so we do it after actually updating the
1498  * record in the heap and all indexes.
1499  *
1500  * ExecWithCheckOptions() will skip any WCOs which are not of the kind we
1501  * are looking for at this point.
1502  */
1503  if (resultRelInfo->ri_WithCheckOptions != NIL)
1504  ExecWithCheckOptions(WCO_VIEW_CHECK, resultRelInfo, slot, estate);
1505 
1506  /* Process RETURNING if present */
1507  if (resultRelInfo->ri_projectReturning)
1508  return ExecProcessReturning(resultRelInfo, slot, planSlot);
1509 
1510  return NULL;
1511 }
int ri_NumIndices
Definition: execnodes.h:416
#define NIL
Definition: pg_list.h:65
Oid tts_tableOid
Definition: tuptable.h:131
JunkFilter * ri_junkFilter
Definition: execnodes.h:466
struct TransitionCaptureState * mt_oc_transition_capture
Definition: execnodes.h:1194
static TupleTableSlot * ExecDelete(ModifyTableState *mtstate, ItemPointer tupleid, HeapTuple oldtuple, TupleTableSlot *planSlot, EPQState *epqstate, EState *estate, bool processReturning, bool canSetTag, bool changingPart, bool *tupleDeleted, TupleTableSlot **epqreturnslot)
Relation ri_RelationDesc
Definition: execnodes.h:413
LockTupleMode
Definition: lockoptions.h:49
int errhint(const char *fmt,...)
Definition: elog.c:1071
void ExecWithCheckOptions(WCOKind kind, ResultRelInfo *resultRelInfo, TupleTableSlot *slot, EState *estate)
Definition: execMain.c:2028
static TupleTableSlot * ExecInsert(ModifyTableState *mtstate, TupleTableSlot *slot, TupleTableSlot *planSlot, EState *estate, bool canSetTag)
CommandId es_output_cid
Definition: execnodes.h:522
struct PartitionTupleRouting * mt_partition_tuple_routing
Definition: execnodes.h:1188
ResultRelInfo * resultRelInfo
Definition: execnodes.h:1174
void ExecComputeStoredGenerated(EState *estate, TupleTableSlot *slot, CmdType cmdtype)
CommandId cmax
Definition: tableam.h:127
void ExecConstraints(ResultRelInfo *resultRelInfo, TupleTableSlot *slot, EState *estate)
Definition: execMain.c:1897
static TupleConversionMap * tupconv_map_for_subplan(ModifyTableState *node, int whichplan)
#define IsolationUsesXactSnapshot()
Definition: xact.h:51
Snapshot es_crosscheck_snapshot
Definition: execnodes.h:509
int errcode(int sqlerrcode)
Definition: elog.c:610
CmdType operation
Definition: execnodes.h:1166
Snapshot es_snapshot
Definition: execnodes.h:508
ResultRelInfo * rootResultRelInfo
Definition: execnodes.h:1175
Index ri_RangeTableIndex
Definition: execnodes.h:410
bool has_generated_stored
Definition: tupdesc.h:45
#define ERROR
Definition: elog.h:43
PlanState ps
Definition: execnodes.h:1165
TupleConversionMap * tcs_map
Definition: trigger.h:74
static TM_Result table_tuple_lock(Relation rel, ItemPointer tid, Snapshot snapshot, TupleTableSlot *slot, CommandId cid, LockTupleMode mode, LockWaitPolicy wait_policy, uint8 flags, TM_FailureData *tmfd)
Definition: tableam.h:1356
List * ExecInsertIndexTuples(TupleTableSlot *slot, EState *estate, bool noDupErr, bool *specConflict, List *arbiterIndexes)
Definition: execIndexing.c:273
TupleTableSlot * EvalPlanQualSlot(EPQState *epqstate, Relation relation, Index rti)
Definition: execMain.c:2541
struct TransitionCaptureState * mt_transition_capture
Definition: execnodes.h:1191
TupleConstr * constr
Definition: tupdesc.h:85
int errdetail(const char *fmt,...)
Definition: elog.c:957
void ExecPartitionCheckEmitError(ResultRelInfo *resultRelInfo, TupleTableSlot *slot, EState *estate)
Definition: execMain.c:1828
bool trig_update_before_row
Definition: reltrigger.h:61
TupleTableSlot * EvalPlanQual(EPQState *epqstate, Relation relation, Index rti, TupleTableSlot *inputslot)
Definition: execMain.c:2432
ProjectionInfo * ri_projectReturning
Definition: execnodes.h:472
#define TupIsNull(slot)
Definition: tuptable.h:292
struct FdwRoutine * ri_FdwRoutine
Definition: execnodes.h:442
AttrMap * attrMap
Definition: tupconvert.h:27
TriggerDesc * ri_TrigDesc
Definition: execnodes.h:425
bool trig_update_instead_row
Definition: reltrigger.h:63
static TupleTableSlot * ExecProcessReturning(ResultRelInfo *resultRelInfo, TupleTableSlot *tupleSlot, TupleTableSlot *planSlot)
void ExecARUpdateTriggers(EState *estate, ResultRelInfo *relinfo, ItemPointer tupleid, HeapTuple fdw_trigtuple, TupleTableSlot *newslot, List *recheckIndexes, TransitionCaptureState *transition_capture)
Definition: trigger.c:2783
static TupleTableSlot * ExecPrepareTupleRouting(ModifyTableState *mtstate, EState *estate, PartitionTupleRouting *proute, ResultRelInfo *targetRelInfo, TupleTableSlot *slot)
TM_Result
Definition: tableam.h:70
TupleTableSlot * ExecFilterJunk(JunkFilter *junkfilter, TupleTableSlot *slot)
Definition: execJunk.c:261
List * ri_WithCheckOptions
Definition: execnodes.h:451
List * ri_PartitionCheck
Definition: execnodes.h:481
TupleDesc rd_att
Definition: rel.h:110
static void ExecMaterializeSlot(TupleTableSlot *slot)
Definition: tuptable.h:443
Plan * plan
Definition: execnodes.h:945
#define ereport(elevel,...)
Definition: elog.h:144
ExecForeignUpdate_function ExecForeignUpdate
Definition: fdwapi.h:212
TupleTableSlot * execute_attr_map_slot(AttrMap *attrMap, TupleTableSlot *in_slot, TupleTableSlot *out_slot)
Definition: tupconvert.c:177
#define Assert(condition)
Definition: c.h:745
Definition: tableam.h:76
uint64 es_processed
Definition: execnodes.h:559
#define TUPLE_LOCK_FLAG_FIND_LAST_VERSION
Definition: tableam.h:141
TupleTableSlot * mt_root_tuple_slot
Definition: execnodes.h:1185
#define IsBootstrapProcessingMode()
Definition: miscadmin.h:393
int errmsg(const char *fmt,...)
Definition: elog.c:824
bool ExecIRUpdateTriggers(EState *estate, ResultRelInfo *relinfo, HeapTuple trigtuple, TupleTableSlot *newslot)
Definition: trigger.c:2825
void list_free(List *list)
Definition: list.c:1376
#define elog(elevel,...)
Definition: elog.h:214
bool ExecBRUpdateTriggers(EState *estate, EPQState *epqstate, ResultRelInfo *relinfo, ItemPointer tupleid, HeapTuple fdw_trigtuple, TupleTableSlot *newslot)
Definition: trigger.c:2643
bool ExecPartitionCheck(ResultRelInfo *resultRelInfo, TupleTableSlot *slot, EState *estate, bool emitError)
Definition: execMain.c:1783
static TM_Result table_tuple_update(Relation rel, ItemPointer otid, TupleTableSlot *slot, CommandId cid, Snapshot snapshot, Snapshot crosscheck, bool wait, TM_FailureData *tmfd, LockTupleMode *lockmode, bool *update_indexes)
Definition: tableam.h:1311
bool traversed
Definition: tableam.h:128
Definition: pg_list.h:50
#define RelationGetRelid(relation)
Definition: rel.h:456
TupleTableSlot * tcs_original_insert_tuple
Definition: trigger.h:83
ResultRelInfo * es_result_relation_info
Definition: execnodes.h:527

◆ fireASTriggers()

static void fireASTriggers ( ModifyTableState node)
static

Definition at line 1797 of file nodeModifyTable.c.

References CMD_DELETE, CMD_INSERT, CMD_UPDATE, elog, ERROR, ExecASDeleteTriggers(), ExecASInsertTriggers(), ExecASUpdateTriggers(), getTargetResultRelInfo(), ModifyTableState::mt_oc_transition_capture, ModifyTableState::mt_transition_capture, ONCONFLICT_UPDATE, ModifyTable::onConflictAction, ModifyTableState::operation, PlanState::plan, ModifyTableState::ps, and PlanState::state.

Referenced by ExecModifyTable().

1798 {
1799  ModifyTable *plan = (ModifyTable *) node->ps.plan;
1800  ResultRelInfo *resultRelInfo = getTargetResultRelInfo(node);
1801 
1802  switch (node->operation)
1803  {
1804  case CMD_INSERT:
1805  if (plan->onConflictAction == ONCONFLICT_UPDATE)
1807  resultRelInfo,
1808  node->mt_oc_transition_capture);
1809  ExecASInsertTriggers(node->ps.state, resultRelInfo,
1810  node->mt_transition_capture);
1811  break;
1812  case CMD_UPDATE:
1813  ExecASUpdateTriggers(node->ps.state, resultRelInfo,
1814  node->mt_transition_capture);
1815  break;
1816  case CMD_DELETE:
1817  ExecASDeleteTriggers(node->ps.state, resultRelInfo,
1818  node->mt_transition_capture);
1819  break;
1820  default:
1821  elog(ERROR, "unknown operation");
1822  break;
1823  }
1824 }
struct TransitionCaptureState * mt_oc_transition_capture
Definition: execnodes.h:1194
static ResultRelInfo * getTargetResultRelInfo(ModifyTableState *node)
CmdType operation
Definition: execnodes.h:1166
EState * state
Definition: execnodes.h:947
void ExecASDeleteTriggers(EState *estate, ResultRelInfo *relinfo, TransitionCaptureState *transition_capture)
Definition: trigger.c:2395
#define ERROR
Definition: elog.h:43
PlanState ps
Definition: execnodes.h:1165
struct TransitionCaptureState * mt_transition_capture
Definition: execnodes.h:1191
void ExecASUpdateTriggers(EState *estate, ResultRelInfo *relinfo, TransitionCaptureState *transition_capture)
Definition: trigger.c:2630
void ExecASInsertTriggers(EState *estate, ResultRelInfo *relinfo, TransitionCaptureState *transition_capture)
Definition: trigger.c:2181
Plan * plan
Definition: execnodes.h:945
OnConflictAction onConflictAction
Definition: plannodes.h:236
#define elog(elevel,...)
Definition: elog.h:214

◆ fireBSTriggers()

static void fireBSTriggers ( ModifyTableState node)
static

Definition at line 1738 of file nodeModifyTable.c.

References CMD_DELETE, CMD_INSERT, CMD_UPDATE, elog, ERROR, ExecBSDeleteTriggers(), ExecBSInsertTriggers(), ExecBSUpdateTriggers(), ONCONFLICT_UPDATE, ModifyTable::onConflictAction, ModifyTableState::operation, PlanState::plan, ModifyTableState::ps, ModifyTableState::resultRelInfo, ModifyTableState::rootResultRelInfo, and PlanState::state.

Referenced by ExecModifyTable().

1739 {
1740  ModifyTable *plan = (ModifyTable *) node->ps.plan;
1741  ResultRelInfo *resultRelInfo = node->resultRelInfo;
1742 
1743  /*
1744  * If the node modifies a partitioned table, we must fire its triggers.
1745  * Note that in that case, node->resultRelInfo points to the first leaf
1746  * partition, not the root table.
1747  */
1748  if (node->rootResultRelInfo != NULL)
1749  resultRelInfo = node->rootResultRelInfo;
1750 
1751  switch (node->operation)
1752  {
1753  case CMD_INSERT:
1754  ExecBSInsertTriggers(node->ps.state, resultRelInfo);
1755  if (plan->onConflictAction == ONCONFLICT_UPDATE)
1757  resultRelInfo);
1758  break;
1759  case CMD_UPDATE:
1760  ExecBSUpdateTriggers(node->ps.state, resultRelInfo);
1761  break;
1762  case CMD_DELETE:
1763  ExecBSDeleteTriggers(node->ps.state, resultRelInfo);
1764  break;
1765  default:
1766  elog(ERROR, "unknown operation");
1767  break;
1768  }
1769 }
void ExecBSDeleteTriggers(EState *estate, ResultRelInfo *relinfo)
Definition: trigger.c:2344
ResultRelInfo * resultRelInfo
Definition: execnodes.h:1174
CmdType operation
Definition: execnodes.h:1166
ResultRelInfo * rootResultRelInfo
Definition: execnodes.h:1175
EState * state
Definition: execnodes.h:947
#define ERROR
Definition: elog.h:43
PlanState ps
Definition: execnodes.h:1165
void ExecBSInsertTriggers(EState *estate, ResultRelInfo *relinfo)
Definition: trigger.c:2130
Plan * plan
Definition: execnodes.h:945
OnConflictAction onConflictAction
Definition: plannodes.h:236
void ExecBSUpdateTriggers(EState *estate, ResultRelInfo *relinfo)
Definition: trigger.c:2575
#define elog(elevel,...)
Definition: elog.h:214

◆ getTargetResultRelInfo()

static ResultRelInfo * getTargetResultRelInfo ( ModifyTableState node)
static

Definition at line 1781 of file nodeModifyTable.c.

References ModifyTableState::resultRelInfo, and ModifyTableState::rootResultRelInfo.

Referenced by ExecInitModifyTable(), ExecSetupChildParentMapForSubplan(), ExecSetupTransitionCaptureState(), and fireASTriggers().

1782 {
1783  /*
1784  * Note that if the node modifies a partitioned table, node->resultRelInfo
1785  * points to the first leaf partition, not the root table.
1786  */
1787  if (node->rootResultRelInfo != NULL)
1788  return node->rootResultRelInfo;
1789  else
1790  return node->resultRelInfo;
1791 }
ResultRelInfo * resultRelInfo
Definition: execnodes.h:1174
ResultRelInfo * rootResultRelInfo
Definition: execnodes.h:1175

◆ tupconv_map_for_subplan()

static TupleConversionMap * tupconv_map_for_subplan ( ModifyTableState node,
int  whichplan 
)
static

Definition at line 1998 of file nodeModifyTable.c.

References Assert, ExecSetupChildParentMapForSubplan(), and ModifyTableState::mt_per_subplan_tupconv_maps.

Referenced by ExecModifyTable(), ExecSetupTransitionCaptureState(), and ExecUpdate().

1999 {
2000  /* If nobody else set the per-subplan array of maps, do so ourselves. */
2001  if (mtstate->mt_per_subplan_tupconv_maps == NULL)
2003 
2004  Assert(whichplan >= 0 && whichplan < mtstate->mt_nplans);
2005  return mtstate->mt_per_subplan_tupconv_maps[whichplan];
2006 }
static void ExecSetupChildParentMapForSubplan(ModifyTableState *mtstate)
#define Assert(condition)
Definition: c.h:745