PostgreSQL Source Code  git master
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
nodeModifyTable.c File Reference
#include "postgres.h"
#include "access/htup_details.h"
#include "access/xact.h"
#include "commands/trigger.h"
#include "executor/executor.h"
#include "executor/nodeModifyTable.h"
#include "foreign/fdwapi.h"
#include "miscadmin.h"
#include "nodes/nodeFuncs.h"
#include "parser/parsetree.h"
#include "storage/bufmgr.h"
#include "storage/lmgr.h"
#include "utils/builtins.h"
#include "utils/memutils.h"
#include "utils/rel.h"
#include "utils/tqual.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 void ExecCheckPlanOutput (Relation resultRel, List *targetList)
 
static TupleTableSlotExecProcessReturning (ResultRelInfo *resultRelInfo, TupleTableSlot *tupleSlot, TupleTableSlot *planSlot)
 
static void ExecCheckHeapTupleVisible (EState *estate, HeapTuple tuple, Buffer buffer)
 
static void ExecCheckTIDVisible (EState *estate, ResultRelInfo *relinfo, ItemPointer tid)
 
static TupleTableSlotExecInsert (ModifyTableState *mtstate, TupleTableSlot *slot, TupleTableSlot *planSlot, List *arbiterIndexes, OnConflictAction onconflict, EState *estate, bool canSetTag)
 
static TupleTableSlotExecDelete (ModifyTableState *mtstate, ItemPointer tupleid, HeapTuple oldtuple, TupleTableSlot *planSlot, EPQState *epqstate, EState *estate, bool canSetTag)
 
static TupleTableSlotExecUpdate (ModifyTableState *mtstate, ItemPointer tupleid, HeapTuple oldtuple, TupleTableSlot *slot, TupleTableSlot *planSlot, EPQState *epqstate, EState *estate, bool canSetTag)
 
static void fireBSTriggers (ModifyTableState *node)
 
static ResultRelInfogetASTriggerResultRelInfo (ModifyTableState *node)
 
static void fireASTriggers (ModifyTableState *node)
 
static void ExecSetupTransitionCaptureState (ModifyTableState *mtstate, EState *estate)
 
TupleTableSlotExecModifyTable (ModifyTableState *node)
 
ModifyTableStateExecInitModifyTable (ModifyTable *node, EState *estate, int eflags)
 
void ExecEndModifyTable (ModifyTableState *node)
 
void ExecReScanModifyTable (ModifyTableState *node)
 

Function Documentation

static void ExecCheckHeapTupleVisible ( EState estate,
HeapTuple  tuple,
Buffer  buffer 
)
static

Definition at line 191 of file nodeModifyTable.c.

References BUFFER_LOCK_SHARE, BUFFER_LOCK_UNLOCK, ereport, errcode(), errmsg(), ERROR, EState::es_snapshot, HeapTupleHeaderGetXmin, HeapTupleSatisfiesVisibility, IsolationUsesXactSnapshot, LockBuffer(), HeapTupleData::t_data, and TransactionIdIsCurrentTransactionId().

Referenced by ExecCheckTIDVisible(), and ExecOnConflictUpdate().

194 {
196  return;
197 
198  /*
199  * We need buffer pin and lock to call HeapTupleSatisfiesVisibility.
200  * Caller should be holding pin, but not lock.
201  */
203  if (!HeapTupleSatisfiesVisibility(tuple, estate->es_snapshot, buffer))
204  {
205  /*
206  * We should not raise a serialization failure if the conflict is
207  * against a tuple inserted by our own transaction, even if it's not
208  * visible to our snapshot. (This would happen, for example, if
209  * conflicting keys are proposed for insertion in a single command.)
210  */
212  ereport(ERROR,
213  (errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
214  errmsg("could not serialize access due to concurrent update")));
215  }
217 }
#define BUFFER_LOCK_UNLOCK
Definition: bufmgr.h:87
bool TransactionIdIsCurrentTransactionId(TransactionId xid)
Definition: xact.c:773
#define IsolationUsesXactSnapshot()
Definition: xact.h:43
int errcode(int sqlerrcode)
Definition: elog.c:575
Snapshot es_snapshot
Definition: execnodes.h:429
#define HeapTupleSatisfiesVisibility(tuple, snapshot, buffer)
Definition: tqual.h:45
HeapTupleHeader t_data
Definition: htup.h:67
#define ERROR
Definition: elog.h:43
#define ereport(elevel, rest)
Definition: elog.h:122
void LockBuffer(Buffer buffer, int mode)
Definition: bufmgr.c:3546
WalTimeSample buffer[LAG_TRACKER_BUFFER_SIZE]
Definition: walsender.c:214
#define HeapTupleHeaderGetXmin(tup)
Definition: htup_details.h:307
int errmsg(const char *fmt,...)
Definition: elog.c:797
#define BUFFER_LOCK_SHARE
Definition: bufmgr.h:88
static void ExecCheckPlanOutput ( Relation  resultRel,
List targetList 
)
static

Definition at line 79 of file nodeModifyTable.c.

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

Referenced by ExecInitModifyTable().

80 {
81  TupleDesc resultDesc = RelationGetDescr(resultRel);
82  int attno = 0;
83  ListCell *lc;
84 
85  foreach(lc, targetList)
86  {
87  TargetEntry *tle = (TargetEntry *) lfirst(lc);
88  Form_pg_attribute attr;
89 
90  if (tle->resjunk)
91  continue; /* ignore junk tlist items */
92 
93  if (attno >= resultDesc->natts)
94  ereport(ERROR,
95  (errcode(ERRCODE_DATATYPE_MISMATCH),
96  errmsg("table row type and query-specified row type do not match"),
97  errdetail("Query has too many columns.")));
98  attr = resultDesc->attrs[attno++];
99 
100  if (!attr->attisdropped)
101  {
102  /* Normal case: demand type match */
103  if (exprType((Node *) tle->expr) != attr->atttypid)
104  ereport(ERROR,
105  (errcode(ERRCODE_DATATYPE_MISMATCH),
106  errmsg("table row type and query-specified row type do not match"),
107  errdetail("Table has type %s at ordinal position %d, but query expects %s.",
108  format_type_be(attr->atttypid),
109  attno,
110  format_type_be(exprType((Node *) tle->expr)))));
111  }
112  else
113  {
114  /*
115  * For a dropped column, we can't check atttypid (it's likely 0).
116  * In any case the planner has most likely inserted an INT4 null.
117  * What we insist on is just *some* NULL constant.
118  */
119  if (!IsA(tle->expr, Const) ||
120  !((Const *) tle->expr)->constisnull)
121  ereport(ERROR,
122  (errcode(ERRCODE_DATATYPE_MISMATCH),
123  errmsg("table row type and query-specified row type do not match"),
124  errdetail("Query provides a value for a dropped column at ordinal position %d.",
125  attno)));
126  }
127  }
128  if (attno != resultDesc->natts)
129  ereport(ERROR,
130  (errcode(ERRCODE_DATATYPE_MISMATCH),
131  errmsg("table row type and query-specified row type do not match"),
132  errdetail("Query has too few columns.")));
133 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:560
#define RelationGetDescr(relation)
Definition: rel.h:428
Form_pg_attribute * attrs
Definition: tupdesc.h:74
Definition: nodes.h:509
int errcode(int sqlerrcode)
Definition: elog.c:575
char * format_type_be(Oid type_oid)
Definition: format_type.c:94
int natts
Definition: tupdesc.h:73
bool resjunk
Definition: primnodes.h:1375
#define ERROR
Definition: elog.h:43
int errdetail(const char *fmt,...)
Definition: elog.c:873
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:187
#define ereport(elevel, rest)
Definition: elog.h:122
#define lfirst(lc)
Definition: pg_list.h:106
Expr * expr
Definition: primnodes.h:1368
Oid exprType(const Node *expr)
Definition: nodeFuncs.c:42
int errmsg(const char *fmt,...)
Definition: elog.c:797
static void ExecCheckTIDVisible ( EState estate,
ResultRelInfo relinfo,
ItemPointer  tid 
)
static

Definition at line 223 of file nodeModifyTable.c.

References buffer, elog, ERROR, ExecCheckHeapTupleVisible(), heap_fetch(), IsolationUsesXactSnapshot, NULL, ReleaseBuffer(), ResultRelInfo::ri_RelationDesc, SnapshotAny, and HeapTupleData::t_self.

Referenced by ExecInsert().

226 {
227  Relation rel = relinfo->ri_RelationDesc;
228  Buffer buffer;
229  HeapTupleData tuple;
230 
231  /* Redundantly check isolation level */
233  return;
234 
235  tuple.t_self = *tid;
236  if (!heap_fetch(rel, SnapshotAny, &tuple, &buffer, false, NULL))
237  elog(ERROR, "failed to fetch conflicting tuple for ON CONFLICT");
238  ExecCheckHeapTupleVisible(estate, &tuple, buffer);
239  ReleaseBuffer(buffer);
240 }
Relation ri_RelationDesc
Definition: execnodes.h:354
bool heap_fetch(Relation relation, Snapshot snapshot, HeapTuple tuple, Buffer *userbuf, bool keep_buf, Relation stats_relation)
Definition: heapam.c:1862
#define IsolationUsesXactSnapshot()
Definition: xact.h:43
void ReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3309
#define ERROR
Definition: elog.h:43
ItemPointerData t_self
Definition: htup.h:65
static void ExecCheckHeapTupleVisible(EState *estate, HeapTuple tuple, Buffer buffer)
#define SnapshotAny
Definition: tqual.h:28
#define NULL
Definition: c.h:229
WalTimeSample buffer[LAG_TRACKER_BUFFER_SIZE]
Definition: walsender.c:214
#define elog
Definition: elog.h:219
int Buffer
Definition: buf.h:23
static TupleTableSlot* ExecDelete ( ModifyTableState mtstate,
ItemPointer  tupleid,
HeapTuple  oldtuple,
TupleTableSlot planSlot,
EPQState epqstate,
EState estate,
bool  canSetTag 
)
static

Definition at line 670 of file nodeModifyTable.c.

References Assert, BufferIsValid, HeapUpdateFailureData::cmax, HeapUpdateFailureData::ctid, elog, ereport, errcode(), errhint(), errmsg(), ERROR, EState::es_crosscheck_snapshot, EState::es_output_cid, EState::es_processed, EState::es_result_relation_info, EState::es_trig_tuple_slot, EvalPlanQual(), ExecARDeleteTriggers(), ExecBRDeleteTriggers(), ExecClearTuple(), FdwRoutine::ExecForeignDelete, ExecIRDeleteTriggers(), ExecMaterializeSlot(), ExecProcessReturning(), ExecSetSlotDescriptor(), ExecStoreAllNullTuple(), ExecStoreTuple(), heap_delete(), heap_fetch(), HeapTupleMayBeUpdated, HeapTupleSelfUpdated, HeapTupleUpdated, InvalidBuffer, IsolationUsesXactSnapshot, ItemPointerEquals(), LockTupleExclusive, ModifyTableState::mt_transition_capture, NULL, RelationGetDescr, RelationGetRelid, ReleaseBuffer(), result, ResultRelInfo::ri_FdwRoutine, ResultRelInfo::ri_projectReturning, ResultRelInfo::ri_RangeTableIndex, ResultRelInfo::ri_RelationDesc, ResultRelInfo::ri_TrigDesc, SnapshotAny, HeapTupleData::t_self, HeapTupleData::t_tableOid, TriggerDesc::trig_delete_before_row, TriggerDesc::trig_delete_instead_row, TupleTableSlot::tts_isempty, TupleTableSlot::tts_tupleDescriptor, TupIsNull, and HeapUpdateFailureData::xmax.

Referenced by ExecModifyTable().

677 {
678  ResultRelInfo *resultRelInfo;
679  Relation resultRelationDesc;
682  TupleTableSlot *slot = NULL;
683 
684  /*
685  * get information on the (current) result relation
686  */
687  resultRelInfo = estate->es_result_relation_info;
688  resultRelationDesc = resultRelInfo->ri_RelationDesc;
689 
690  /* BEFORE ROW DELETE Triggers */
691  if (resultRelInfo->ri_TrigDesc &&
692  resultRelInfo->ri_TrigDesc->trig_delete_before_row)
693  {
694  bool dodelete;
695 
696  dodelete = ExecBRDeleteTriggers(estate, epqstate, resultRelInfo,
697  tupleid, oldtuple);
698 
699  if (!dodelete) /* "do nothing" */
700  return NULL;
701  }
702 
703  /* INSTEAD OF ROW DELETE Triggers */
704  if (resultRelInfo->ri_TrigDesc &&
705  resultRelInfo->ri_TrigDesc->trig_delete_instead_row)
706  {
707  bool dodelete;
708 
709  Assert(oldtuple != NULL);
710  dodelete = ExecIRDeleteTriggers(estate, resultRelInfo, oldtuple);
711 
712  if (!dodelete) /* "do nothing" */
713  return NULL;
714  }
715  else if (resultRelInfo->ri_FdwRoutine)
716  {
717  HeapTuple tuple;
718 
719  /*
720  * delete from foreign table: let the FDW do it
721  *
722  * We offer the trigger tuple slot as a place to store RETURNING data,
723  * although the FDW can return some other slot if it wants. Set up
724  * the slot's tupdesc so the FDW doesn't need to do that for itself.
725  */
726  slot = estate->es_trig_tuple_slot;
727  if (slot->tts_tupleDescriptor != RelationGetDescr(resultRelationDesc))
728  ExecSetSlotDescriptor(slot, RelationGetDescr(resultRelationDesc));
729 
730  slot = resultRelInfo->ri_FdwRoutine->ExecForeignDelete(estate,
731  resultRelInfo,
732  slot,
733  planSlot);
734 
735  if (slot == NULL) /* "do nothing" */
736  return NULL;
737 
738  /*
739  * RETURNING expressions might reference the tableoid column, so
740  * initialize t_tableOid before evaluating them.
741  */
742  if (slot->tts_isempty)
743  ExecStoreAllNullTuple(slot);
744  tuple = ExecMaterializeSlot(slot);
745  tuple->t_tableOid = RelationGetRelid(resultRelationDesc);
746  }
747  else
748  {
749  /*
750  * delete the tuple
751  *
752  * Note: if es_crosscheck_snapshot isn't InvalidSnapshot, we check
753  * that the row to be deleted is visible to that snapshot, and throw a
754  * can't-serialize error if not. This is a special-case behavior
755  * needed for referential integrity updates in transaction-snapshot
756  * mode transactions.
757  */
758 ldelete:;
759  result = heap_delete(resultRelationDesc, tupleid,
760  estate->es_output_cid,
761  estate->es_crosscheck_snapshot,
762  true /* wait for commit */ ,
763  &hufd);
764  switch (result)
765  {
767 
768  /*
769  * The target tuple was already updated or deleted by the
770  * current command, or by a later command in the current
771  * transaction. The former case is possible in a join DELETE
772  * where multiple tuples join to the same target tuple. This
773  * is somewhat questionable, but Postgres has always allowed
774  * it: we just ignore additional deletion attempts.
775  *
776  * The latter case arises if the tuple is modified by a
777  * command in a BEFORE trigger, or perhaps by a command in a
778  * volatile function used in the query. In such situations we
779  * should not ignore the deletion, but it is equally unsafe to
780  * proceed. We don't want to discard the original DELETE
781  * while keeping the triggered actions based on its deletion;
782  * and it would be no better to allow the original DELETE
783  * while discarding updates that it triggered. The row update
784  * carries some information that might be important according
785  * to business rules; so throwing an error is the only safe
786  * course.
787  *
788  * If a trigger actually intends this type of interaction, it
789  * can re-execute the DELETE and then return NULL to cancel
790  * the outer delete.
791  */
792  if (hufd.cmax != estate->es_output_cid)
793  ereport(ERROR,
794  (errcode(ERRCODE_TRIGGERED_DATA_CHANGE_VIOLATION),
795  errmsg("tuple to be updated was already modified by an operation triggered by the current command"),
796  errhint("Consider using an AFTER trigger instead of a BEFORE trigger to propagate changes to other rows.")));
797 
798  /* Else, already deleted by self; nothing to do */
799  return NULL;
800 
802  break;
803 
804  case HeapTupleUpdated:
806  ereport(ERROR,
807  (errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
808  errmsg("could not serialize access due to concurrent update")));
809  if (!ItemPointerEquals(tupleid, &hufd.ctid))
810  {
811  TupleTableSlot *epqslot;
812 
813  epqslot = EvalPlanQual(estate,
814  epqstate,
815  resultRelationDesc,
816  resultRelInfo->ri_RangeTableIndex,
818  &hufd.ctid,
819  hufd.xmax);
820  if (!TupIsNull(epqslot))
821  {
822  *tupleid = hufd.ctid;
823  goto ldelete;
824  }
825  }
826  /* tuple already deleted; nothing to do */
827  return NULL;
828 
829  default:
830  elog(ERROR, "unrecognized heap_delete status: %u", result);
831  return NULL;
832  }
833 
834  /*
835  * Note: Normally one would think that we have to delete index tuples
836  * associated with the heap tuple now...
837  *
838  * ... but in POSTGRES, we have no need to do this because VACUUM will
839  * take care of it later. We can't delete index tuples immediately
840  * anyway, since the tuple is still visible to other transactions.
841  */
842  }
843 
844  if (canSetTag)
845  (estate->es_processed)++;
846 
847  /* AFTER ROW DELETE Triggers */
848  ExecARDeleteTriggers(estate, resultRelInfo, tupleid, oldtuple,
849  mtstate->mt_transition_capture);
850 
851  /* Process RETURNING if present */
852  if (resultRelInfo->ri_projectReturning)
853  {
854  /*
855  * We have to put the target tuple into a slot, which means first we
856  * gotta fetch it. We can use the trigger tuple slot.
857  */
858  TupleTableSlot *rslot;
859  HeapTupleData deltuple;
860  Buffer delbuffer;
861 
862  if (resultRelInfo->ri_FdwRoutine)
863  {
864  /* FDW must have provided a slot containing the deleted row */
865  Assert(!TupIsNull(slot));
866  delbuffer = InvalidBuffer;
867  }
868  else
869  {
870  slot = estate->es_trig_tuple_slot;
871  if (oldtuple != NULL)
872  {
873  deltuple = *oldtuple;
874  delbuffer = InvalidBuffer;
875  }
876  else
877  {
878  deltuple.t_self = *tupleid;
879  if (!heap_fetch(resultRelationDesc, SnapshotAny,
880  &deltuple, &delbuffer, false, NULL))
881  elog(ERROR, "failed to fetch deleted tuple for DELETE RETURNING");
882  }
883 
884  if (slot->tts_tupleDescriptor != RelationGetDescr(resultRelationDesc))
885  ExecSetSlotDescriptor(slot, RelationGetDescr(resultRelationDesc));
886  ExecStoreTuple(&deltuple, slot, InvalidBuffer, false);
887  }
888 
889  rslot = ExecProcessReturning(resultRelInfo, slot, planSlot);
890 
891  /*
892  * Before releasing the target tuple again, make sure rslot has a
893  * local copy of any pass-by-reference values.
894  */
895  ExecMaterializeSlot(rslot);
896 
897  ExecClearTuple(slot);
898  if (BufferIsValid(delbuffer))
899  ReleaseBuffer(delbuffer);
900 
901  return rslot;
902  }
903 
904  return NULL;
905 }
ExecForeignDelete_function ExecForeignDelete
Definition: fdwapi.h:199
TupleTableSlot * ExecStoreTuple(HeapTuple tuple, TupleTableSlot *slot, Buffer buffer, bool shouldFree)
Definition: execTuples.c:320
Relation ri_RelationDesc
Definition: execnodes.h:354
bool tts_isempty
Definition: tuptable.h:116
bool ExecIRDeleteTriggers(EState *estate, ResultRelInfo *relinfo, HeapTuple trigtuple)
Definition: trigger.c:2658
int errhint(const char *fmt,...)
Definition: elog.c:987
CommandId es_output_cid
Definition: execnodes.h:438
TupleTableSlot * ExecStoreAllNullTuple(TupleTableSlot *slot)
Definition: execTuples.c:512
#define RelationGetDescr(relation)
Definition: rel.h:428
bool heap_fetch(Relation relation, Snapshot snapshot, HeapTuple tuple, Buffer *userbuf, bool keep_buf, Relation stats_relation)
Definition: heapam.c:1862
TupleTableSlot * EvalPlanQual(EState *estate, EPQState *epqstate, Relation relation, Index rti, int lockmode, ItemPointer tid, TransactionId priorXmax)
Definition: execMain.c:2445
TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition: execTuples.c:439
#define IsolationUsesXactSnapshot()
Definition: xact.h:43
#define InvalidBuffer
Definition: buf.h:25
Snapshot es_crosscheck_snapshot
Definition: execnodes.h:430
int errcode(int sqlerrcode)
Definition: elog.c:575
return result
Definition: formatting.c:1633
void ReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3309
Index ri_RangeTableIndex
Definition: execnodes.h:351
void ExecARDeleteTriggers(EState *estate, ResultRelInfo *relinfo, ItemPointer tupleid, HeapTuple fdw_trigtuple, TransitionCaptureState *transition_capture)
Definition: trigger.c:2626
HTSU_Result heap_delete(Relation relation, ItemPointer tid, CommandId cid, Snapshot crosscheck, bool wait, HeapUpdateFailureData *hufd)
Definition: heapam.c:3011
#define ERROR
Definition: elog.h:43
ItemPointerData t_self
Definition: htup.h:65
struct TransitionCaptureState * mt_transition_capture
Definition: execnodes.h:966
CommandId cmax
Definition: heapam.h:72
HTSU_Result
Definition: snapshot.h:119
ProjectionInfo * ri_projectReturning
Definition: execnodes.h:399
#define TupIsNull(slot)
Definition: tuptable.h:138
struct FdwRoutine * ri_FdwRoutine
Definition: execnodes.h:378
Oid t_tableOid
Definition: htup.h:66
TupleTableSlot * es_trig_tuple_slot
Definition: execnodes.h:457
#define ereport(elevel, rest)
Definition: elog.h:122
TriggerDesc * ri_TrigDesc
Definition: execnodes.h:366
static TupleTableSlot * ExecProcessReturning(ResultRelInfo *resultRelInfo, TupleTableSlot *tupleSlot, TupleTableSlot *planSlot)
TransactionId xmax
Definition: heapam.h:71
TupleDesc tts_tupleDescriptor
Definition: tuptable.h:121
bool trig_delete_instead_row
Definition: reltrigger.h:67
void ExecSetSlotDescriptor(TupleTableSlot *slot, TupleDesc tupdesc)
Definition: execTuples.c:247
#define SnapshotAny
Definition: tqual.h:28
bool ExecBRDeleteTriggers(EState *estate, EPQState *epqstate, ResultRelInfo *relinfo, ItemPointer tupleid, HeapTuple fdw_trigtuple)
Definition: trigger.c:2557
#define NULL
Definition: c.h:229
#define Assert(condition)
Definition: c.h:675
uint64 es_processed
Definition: execnodes.h:474
#define BufferIsValid(bufnum)
Definition: bufmgr.h:114
HeapTuple ExecMaterializeSlot(TupleTableSlot *slot)
Definition: execTuples.c:725
bool ItemPointerEquals(ItemPointer pointer1, ItemPointer pointer2)
Definition: itemptr.c:29
int errmsg(const char *fmt,...)
Definition: elog.c:797
ItemPointerData ctid
Definition: heapam.h:70
#define elog
Definition: elog.h:219
int Buffer
Definition: buf.h:23
#define RelationGetRelid(relation)
Definition: rel.h:416
bool trig_delete_before_row
Definition: reltrigger.h:65
ResultRelInfo * es_result_relation_info
Definition: execnodes.h:443
void ExecEndModifyTable ( ModifyTableState node)

Definition at line 2308 of file nodeModifyTable.c.

References DestroyTransitionCaptureState(), FdwRoutine::EndForeignModify, EvalPlanQualEnd(), ExecClearTuple(), ExecCloseIndices(), ExecDropSingleTupleTableSlot(), ExecEndNode(), ExecFreeExprContext(), heap_close, i, ModifyTableState::mt_epqstate, ModifyTableState::mt_nplans, ModifyTableState::mt_num_dispatch, ModifyTableState::mt_num_partitions, ModifyTableState::mt_partition_dispatch_info, ModifyTableState::mt_partition_tuple_slot, ModifyTableState::mt_partitions, ModifyTableState::mt_plans, ModifyTableState::mt_transition_capture, NoLock, NULL, ModifyTableState::ps, PlanState::ps_ResultTupleSlot, PartitionDispatchData::reldesc, ModifyTableState::resultRelInfo, ResultRelInfo::ri_FdwRoutine, ResultRelInfo::ri_RelationDesc, ResultRelInfo::ri_usesFdwDirectModify, PlanState::state, and PartitionDispatchData::tupslot.

Referenced by ExecEndNode().

2309 {
2310  int i;
2311 
2312  /* Free transition tables */
2313  if (node->mt_transition_capture != NULL)
2315 
2316  /*
2317  * Allow any FDWs to shut down
2318  */
2319  for (i = 0; i < node->mt_nplans; i++)
2320  {
2321  ResultRelInfo *resultRelInfo = node->resultRelInfo + i;
2322 
2323  if (!resultRelInfo->ri_usesFdwDirectModify &&
2324  resultRelInfo->ri_FdwRoutine != NULL &&
2325  resultRelInfo->ri_FdwRoutine->EndForeignModify != NULL)
2326  resultRelInfo->ri_FdwRoutine->EndForeignModify(node->ps.state,
2327  resultRelInfo);
2328  }
2329 
2330  /*
2331  * Close all the partitioned tables, leaf partitions, and their indices
2332  *
2333  * Remember node->mt_partition_dispatch_info[0] corresponds to the root
2334  * partitioned table, which we must not try to close, because it is the
2335  * main target table of the query that will be closed by ExecEndPlan().
2336  * Also, tupslot is NULL for the root partitioned table.
2337  */
2338  for (i = 1; i < node->mt_num_dispatch; i++)
2339  {
2341 
2342  heap_close(pd->reldesc, NoLock);
2344  }
2345  for (i = 0; i < node->mt_num_partitions; i++)
2346  {
2347  ResultRelInfo *resultRelInfo = node->mt_partitions + i;
2348 
2349  ExecCloseIndices(resultRelInfo);
2350  heap_close(resultRelInfo->ri_RelationDesc, NoLock);
2351  }
2352 
2353  /* Release the standalone partition tuple descriptor, if any */
2354  if (node->mt_partition_tuple_slot)
2356 
2357  /*
2358  * Free the exprcontext
2359  */
2360  ExecFreeExprContext(&node->ps);
2361 
2362  /*
2363  * clean out the tuple table
2364  */
2366 
2367  /*
2368  * Terminate EPQ execution if active
2369  */
2370  EvalPlanQualEnd(&node->mt_epqstate);
2371 
2372  /*
2373  * shut down subplans
2374  */
2375  for (i = 0; i < node->mt_nplans; i++)
2376  ExecEndNode(node->mt_plans[i]);
2377 }
Relation ri_RelationDesc
Definition: execnodes.h:354
ResultRelInfo * mt_partitions
Definition: execnodes.h:962
void ExecEndNode(PlanState *node)
Definition: execProcnode.c:654
ResultRelInfo * resultRelInfo
Definition: execnodes.h:945
TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition: execTuples.c:439
#define heap_close(r, l)
Definition: heapam.h:97
EState * state
Definition: execnodes.h:834
void ExecFreeExprContext(PlanState *planstate)
Definition: execUtils.c:516
void EvalPlanQualEnd(EPQState *epqstate)
Definition: execMain.c:3172
TupleTableSlot * ps_ResultTupleSlot
Definition: execnodes.h:861
PlanState ps
Definition: execnodes.h:938
bool ri_usesFdwDirectModify
Definition: execnodes.h:384
struct TransitionCaptureState * mt_transition_capture
Definition: execnodes.h:966
#define NoLock
Definition: lockdefs.h:34
void ExecDropSingleTupleTableSlot(TupleTableSlot *slot)
Definition: execTuples.c:216
EPQState mt_epqstate
Definition: execnodes.h:949
struct FdwRoutine * ri_FdwRoutine
Definition: execnodes.h:378
EndForeignModify_function EndForeignModify
Definition: fdwapi.h:200
PlanState ** mt_plans
Definition: execnodes.h:942
TupleTableSlot * tupslot
Definition: partition.h:66
TupleTableSlot * mt_partition_tuple_slot
Definition: execnodes.h:965
#define NULL
Definition: c.h:229
int i
struct PartitionDispatchData ** mt_partition_dispatch_info
Definition: execnodes.h:957
void DestroyTransitionCaptureState(TransitionCaptureState *tcs)
Definition: trigger.c:2167
void ExecCloseIndices(ResultRelInfo *resultRelInfo)
Definition: execIndexing.c:224
ModifyTableState* ExecInitModifyTable ( ModifyTable node,
EState estate,
int  eflags 
)

Definition at line 1785 of file nodeModifyTable.c.

References ModifyTable::arbiterIndexes, Assert, AttributeNumberIsValid, FdwRoutine::BeginForeignModify, bms_is_member(), ModifyTable::canSetTag, ModifyTableState::canSetTag, castNode, CheckValidResultRel(), CMD_DELETE, CMD_INSERT, CMD_UPDATE, elog, ModifyTable::epqParam, ERROR, EState::es_auxmodifytables, EState::es_range_table, EState::es_result_relation_info, EState::es_result_relations, EState::es_root_result_relations, EState::es_trig_tuple_slot, EvalPlanQualInit(), EvalPlanQualSetPlan(), ModifyTable::exclRelTlist, EXEC_FLAG_BACKWARD, EXEC_FLAG_MARK, ExecAssignExprContext(), ExecAssignResultType(), ExecBuildAuxRowMark(), ExecBuildProjectionInfo(), ExecCheckPlanOutput(), ExecFindJunkAttribute(), ExecFindRowMark(), ExecInitExtraTupleSlot(), ExecInitJunkFilter(), ExecInitNode(), ExecInitQual(), ExecInitResultTupleSlot(), ExecOpenIndices(), ExecSetSlotDescriptor(), ExecSetupPartitionTupleRouting(), ExecSetupTransitionCaptureState(), ExecTypeFromTL(), ModifyTable::fdwDirectModifyPlans, ModifyTable::fdwPrivLists, ModifyTableState::fireBSTriggers, getrelid, heap_close, heap_open(), i, PlanRowMark::isParent, JunkFilter::jf_junkAttNo, lappend(), lcons(), lfirst, lfirst_node, linitial, linitial_int, list_length(), list_nth(), makeNode, map_partition_varattnos(), ModifyTableState::mt_arbiterindexes, ModifyTableState::mt_arowmarks, ModifyTableState::mt_conflproj, ModifyTableState::mt_done, ModifyTableState::mt_epqstate, ModifyTableState::mt_excludedtlist, ModifyTableState::mt_existing, ModifyTableState::mt_nplans, ModifyTableState::mt_num_dispatch, ModifyTableState::mt_num_partitions, ModifyTableState::mt_onconflict, ModifyTableState::mt_partition_dispatch_info, ModifyTableState::mt_partition_tupconv_maps, ModifyTableState::mt_partition_tuple_slot, ModifyTableState::mt_partitions, ModifyTableState::mt_plans, ModifyTableState::mt_whichplan, NIL, NoLock, ModifyTable::nominalRelation, NULL, ONCONFLICT_NONE, ONCONFLICT_UPDATE, ModifyTable::onConflictAction, ModifyTable::onConflictSet, ModifyTable::onConflictWhere, ModifyTable::operation, ModifyTableState::operation, palloc0(), ModifyTable::partitioned_rels, PlanState::plan, ModifyTable::plans, ModifyTableState::ps, PlanState::ps_ExprContext, PlanState::ps_ResultTupleSlot, WithCheckOption::qual, RelationData::rd_att, RelationData::rd_rel, RELKIND_FOREIGN_TABLE, RELKIND_MATVIEW, RELKIND_PARTITIONED_TABLE, RELKIND_RELATION, TargetEntry::resjunk, ModifyTable::resultRelIndex, ModifyTableState::resultRelInfo, ModifyTable::returningLists, ResultRelInfo::ri_FdwRoutine, ResultRelInfo::ri_IndexRelationDescs, ResultRelInfo::ri_junkFilter, ResultRelInfo::ri_onConflictSetProj, ResultRelInfo::ri_onConflictSetWhere, ResultRelInfo::ri_projectReturning, ResultRelInfo::ri_RelationDesc, ResultRelInfo::ri_usesFdwDirectModify, ResultRelInfo::ri_WithCheckOptionExprs, ResultRelInfo::ri_WithCheckOptions, ModifyTable::rootResultRelIndex, ModifyTableState::rootResultRelInfo, ModifyTable::rowMarks, PlanRowMark::rti, PlanState::state, Plan::targetlist, tupleDesc::tdhasoid, and ModifyTable::withCheckOptionLists.

Referenced by ExecInitNode().

1786 {
1787  ModifyTableState *mtstate;
1788  CmdType operation = node->operation;
1789  int nplans = list_length(node->plans);
1790  ResultRelInfo *saved_resultRelInfo;
1791  ResultRelInfo *resultRelInfo;
1792  TupleDesc tupDesc;
1793  Plan *subplan;
1794  ListCell *l;
1795  int i;
1796  Relation rel;
1797 
1798  /* check for unsupported flags */
1799  Assert(!(eflags & (EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK)));
1800 
1801  /*
1802  * create state structure
1803  */
1804  mtstate = makeNode(ModifyTableState);
1805  mtstate->ps.plan = (Plan *) node;
1806  mtstate->ps.state = estate;
1807 
1808  mtstate->operation = operation;
1809  mtstate->canSetTag = node->canSetTag;
1810  mtstate->mt_done = false;
1811 
1812  mtstate->mt_plans = (PlanState **) palloc0(sizeof(PlanState *) * nplans);
1813  mtstate->resultRelInfo = estate->es_result_relations + node->resultRelIndex;
1814 
1815  /* If modifying a partitioned table, initialize the root table info */
1816  if (node->rootResultRelIndex >= 0)
1817  mtstate->rootResultRelInfo = estate->es_root_result_relations +
1818  node->rootResultRelIndex;
1819 
1820  mtstate->mt_arowmarks = (List **) palloc0(sizeof(List *) * nplans);
1821  mtstate->mt_nplans = nplans;
1822  mtstate->mt_onconflict = node->onConflictAction;
1823  mtstate->mt_arbiterindexes = node->arbiterIndexes;
1824 
1825  /* set up epqstate with dummy subplan data for the moment */
1826  EvalPlanQualInit(&mtstate->mt_epqstate, estate, NULL, NIL, node->epqParam);
1827  mtstate->fireBSTriggers = true;
1828 
1829  /*
1830  * call ExecInitNode on each of the plans to be executed and save the
1831  * results into the array "mt_plans". This is also a convenient place to
1832  * verify that the proposed target relations are valid and open their
1833  * indexes for insertion of new index entries. Note we *must* set
1834  * estate->es_result_relation_info correctly while we initialize each
1835  * sub-plan; ExecContextForcesOids depends on that!
1836  */
1837  saved_resultRelInfo = estate->es_result_relation_info;
1838 
1839  resultRelInfo = mtstate->resultRelInfo;
1840  i = 0;
1841  foreach(l, node->plans)
1842  {
1843  subplan = (Plan *) lfirst(l);
1844 
1845  /* Initialize the usesFdwDirectModify flag */
1846  resultRelInfo->ri_usesFdwDirectModify = bms_is_member(i,
1847  node->fdwDirectModifyPlans);
1848 
1849  /*
1850  * Verify result relation is a valid target for the current operation
1851  */
1852  CheckValidResultRel(resultRelInfo->ri_RelationDesc, operation);
1853 
1854  /*
1855  * If there are indices on the result relation, open them and save
1856  * descriptors in the result relation info, so that we can add new
1857  * index entries for the tuples we add/update. We need not do this
1858  * for a DELETE, however, since deletion doesn't affect indexes. Also,
1859  * inside an EvalPlanQual operation, the indexes might be open
1860  * already, since we share the resultrel state with the original
1861  * query.
1862  */
1863  if (resultRelInfo->ri_RelationDesc->rd_rel->relhasindex &&
1864  operation != CMD_DELETE &&
1865  resultRelInfo->ri_IndexRelationDescs == NULL)
1866  ExecOpenIndices(resultRelInfo, mtstate->mt_onconflict != ONCONFLICT_NONE);
1867 
1868  /* Now init the plan for this result rel */
1869  estate->es_result_relation_info = resultRelInfo;
1870  mtstate->mt_plans[i] = ExecInitNode(subplan, estate, eflags);
1871 
1872  /* Also let FDWs init themselves for foreign-table result rels */
1873  if (!resultRelInfo->ri_usesFdwDirectModify &&
1874  resultRelInfo->ri_FdwRoutine != NULL &&
1875  resultRelInfo->ri_FdwRoutine->BeginForeignModify != NULL)
1876  {
1877  List *fdw_private = (List *) list_nth(node->fdwPrivLists, i);
1878 
1879  resultRelInfo->ri_FdwRoutine->BeginForeignModify(mtstate,
1880  resultRelInfo,
1881  fdw_private,
1882  i,
1883  eflags);
1884  }
1885 
1886  resultRelInfo++;
1887  i++;
1888  }
1889 
1890  estate->es_result_relation_info = saved_resultRelInfo;
1891 
1892  /* The root table RT index is at the head of the partitioned_rels list */
1893  if (node->partitioned_rels)
1894  {
1895  Index root_rti;
1896  Oid root_oid;
1897 
1898  root_rti = linitial_int(node->partitioned_rels);
1899  root_oid = getrelid(root_rti, estate->es_range_table);
1900  rel = heap_open(root_oid, NoLock); /* locked by InitPlan */
1901  }
1902  else
1903  rel = mtstate->resultRelInfo->ri_RelationDesc;
1904 
1905  /* Build state for INSERT tuple routing */
1906  if (operation == CMD_INSERT &&
1907  rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
1908  {
1909  PartitionDispatch *partition_dispatch_info;
1910  ResultRelInfo *partitions;
1911  TupleConversionMap **partition_tupconv_maps;
1912  TupleTableSlot *partition_tuple_slot;
1913  int num_parted,
1914  num_partitions;
1915 
1917  node->nominalRelation,
1918  &partition_dispatch_info,
1919  &partitions,
1920  &partition_tupconv_maps,
1921  &partition_tuple_slot,
1922  &num_parted, &num_partitions);
1923  mtstate->mt_partition_dispatch_info = partition_dispatch_info;
1924  mtstate->mt_num_dispatch = num_parted;
1925  mtstate->mt_partitions = partitions;
1926  mtstate->mt_num_partitions = num_partitions;
1927  mtstate->mt_partition_tupconv_maps = partition_tupconv_maps;
1928  mtstate->mt_partition_tuple_slot = partition_tuple_slot;
1929  }
1930 
1931  /* Build state for collecting transition tuples */
1932  ExecSetupTransitionCaptureState(mtstate, estate);
1933 
1934  /*
1935  * Initialize any WITH CHECK OPTION constraints if needed.
1936  */
1937  resultRelInfo = mtstate->resultRelInfo;
1938  i = 0;
1939  foreach(l, node->withCheckOptionLists)
1940  {
1941  List *wcoList = (List *) lfirst(l);
1942  List *wcoExprs = NIL;
1943  ListCell *ll;
1944 
1945  foreach(ll, wcoList)
1946  {
1947  WithCheckOption *wco = (WithCheckOption *) lfirst(ll);
1948  ExprState *wcoExpr = ExecInitQual((List *) wco->qual,
1949  mtstate->mt_plans[i]);
1950 
1951  wcoExprs = lappend(wcoExprs, wcoExpr);
1952  }
1953 
1954  resultRelInfo->ri_WithCheckOptions = wcoList;
1955  resultRelInfo->ri_WithCheckOptionExprs = wcoExprs;
1956  resultRelInfo++;
1957  i++;
1958  }
1959 
1960  /*
1961  * Build WITH CHECK OPTION constraints for each leaf partition rel. Note
1962  * that we didn't build the withCheckOptionList for each partition within
1963  * the planner, but simple translation of the varattnos for each partition
1964  * will suffice. This only occurs for the INSERT case; UPDATE/DELETE
1965  * cases are handled above.
1966  */
1967  if (node->withCheckOptionLists != NIL && mtstate->mt_num_partitions > 0)
1968  {
1969  List *wcoList;
1970  PlanState *plan;
1971 
1972  /*
1973  * In case of INSERT on partitioned tables, there is only one plan.
1974  * Likewise, there is only one WITH CHECK OPTIONS list, not one per
1975  * partition. We make a copy of the WCO qual for each partition; note
1976  * that, if there are SubPlans in there, they all end up attached to
1977  * the one parent Plan node.
1978  */
1979  Assert(operation == CMD_INSERT &&
1980  list_length(node->withCheckOptionLists) == 1 &&
1981  mtstate->mt_nplans == 1);
1982  wcoList = linitial(node->withCheckOptionLists);
1983  plan = mtstate->mt_plans[0];
1984  resultRelInfo = mtstate->mt_partitions;
1985  for (i = 0; i < mtstate->mt_num_partitions; i++)
1986  {
1987  Relation partrel = resultRelInfo->ri_RelationDesc;
1988  List *mapped_wcoList;
1989  List *wcoExprs = NIL;
1990  ListCell *ll;
1991 
1992  /* varno = node->nominalRelation */
1993  mapped_wcoList = map_partition_varattnos(wcoList,
1994  node->nominalRelation,
1995  partrel, rel);
1996  foreach(ll, mapped_wcoList)
1997  {
1999  ExprState *wcoExpr = ExecInitQual(castNode(List, wco->qual),
2000  plan);
2001 
2002  wcoExprs = lappend(wcoExprs, wcoExpr);
2003  }
2004 
2005  resultRelInfo->ri_WithCheckOptions = mapped_wcoList;
2006  resultRelInfo->ri_WithCheckOptionExprs = wcoExprs;
2007  resultRelInfo++;
2008  }
2009  }
2010 
2011  /*
2012  * Initialize RETURNING projections if needed.
2013  */
2014  if (node->returningLists)
2015  {
2016  TupleTableSlot *slot;
2017  ExprContext *econtext;
2018  List *returningList;
2019 
2020  /*
2021  * Initialize result tuple slot and assign its rowtype using the first
2022  * RETURNING list. We assume the rest will look the same.
2023  */
2024  tupDesc = ExecTypeFromTL((List *) linitial(node->returningLists),
2025  false);
2026 
2027  /* Set up a slot for the output of the RETURNING projection(s) */
2028  ExecInitResultTupleSlot(estate, &mtstate->ps);
2029  ExecAssignResultType(&mtstate->ps, tupDesc);
2030  slot = mtstate->ps.ps_ResultTupleSlot;
2031 
2032  /* Need an econtext too */
2033  if (mtstate->ps.ps_ExprContext == NULL)
2034  ExecAssignExprContext(estate, &mtstate->ps);
2035  econtext = mtstate->ps.ps_ExprContext;
2036 
2037  /*
2038  * Build a projection for each result rel.
2039  */
2040  resultRelInfo = mtstate->resultRelInfo;
2041  foreach(l, node->returningLists)
2042  {
2043  List *rlist = (List *) lfirst(l);
2044 
2045  resultRelInfo->ri_projectReturning =
2046  ExecBuildProjectionInfo(rlist, econtext, slot, &mtstate->ps,
2047  resultRelInfo->ri_RelationDesc->rd_att);
2048  resultRelInfo++;
2049  }
2050 
2051  /*
2052  * Build a projection for each leaf partition rel. Note that we
2053  * didn't build the returningList for each partition within the
2054  * planner, but simple translation of the varattnos for each partition
2055  * will suffice. This only occurs for the INSERT case; UPDATE/DELETE
2056  * are handled above.
2057  */
2058  resultRelInfo = mtstate->mt_partitions;
2059  returningList = linitial(node->returningLists);
2060  for (i = 0; i < mtstate->mt_num_partitions; i++)
2061  {
2062  Relation partrel = resultRelInfo->ri_RelationDesc;
2063  List *rlist;
2064 
2065  /* varno = node->nominalRelation */
2066  rlist = map_partition_varattnos(returningList,
2067  node->nominalRelation,
2068  partrel, rel);
2069  resultRelInfo->ri_projectReturning =
2070  ExecBuildProjectionInfo(rlist, econtext, slot, &mtstate->ps,
2071  resultRelInfo->ri_RelationDesc->rd_att);
2072  resultRelInfo++;
2073  }
2074  }
2075  else
2076  {
2077  /*
2078  * We still must construct a dummy result tuple type, because InitPlan
2079  * expects one (maybe should change that?).
2080  */
2081  tupDesc = ExecTypeFromTL(NIL, false);
2082  ExecInitResultTupleSlot(estate, &mtstate->ps);
2083  ExecAssignResultType(&mtstate->ps, tupDesc);
2084 
2085  mtstate->ps.ps_ExprContext = NULL;
2086  }
2087 
2088  /* Close the root partitioned rel if we opened it above. */
2089  if (rel != mtstate->resultRelInfo->ri_RelationDesc)
2090  heap_close(rel, NoLock);
2091 
2092  /*
2093  * If needed, Initialize target list, projection and qual for ON CONFLICT
2094  * DO UPDATE.
2095  */
2096  resultRelInfo = mtstate->resultRelInfo;
2097  if (node->onConflictAction == ONCONFLICT_UPDATE)
2098  {
2099  ExprContext *econtext;
2100  TupleDesc tupDesc;
2101 
2102  /* insert may only have one plan, inheritance is not expanded */
2103  Assert(nplans == 1);
2104 
2105  /* already exists if created by RETURNING processing above */
2106  if (mtstate->ps.ps_ExprContext == NULL)
2107  ExecAssignExprContext(estate, &mtstate->ps);
2108 
2109  econtext = mtstate->ps.ps_ExprContext;
2110 
2111  /* initialize slot for the existing tuple */
2112  mtstate->mt_existing = ExecInitExtraTupleSlot(mtstate->ps.state);
2114  resultRelInfo->ri_RelationDesc->rd_att);
2115 
2116  /* carried forward solely for the benefit of explain */
2117  mtstate->mt_excludedtlist = node->exclRelTlist;
2118 
2119  /* create target slot for UPDATE SET projection */
2120  tupDesc = ExecTypeFromTL((List *) node->onConflictSet,
2121  resultRelInfo->ri_RelationDesc->rd_rel->relhasoids);
2122  mtstate->mt_conflproj = ExecInitExtraTupleSlot(mtstate->ps.state);
2123  ExecSetSlotDescriptor(mtstate->mt_conflproj, tupDesc);
2124 
2125  /* build UPDATE SET projection state */
2126  resultRelInfo->ri_onConflictSetProj =
2127  ExecBuildProjectionInfo(node->onConflictSet, econtext,
2128  mtstate->mt_conflproj, &mtstate->ps,
2129  resultRelInfo->ri_RelationDesc->rd_att);
2130 
2131  /* build DO UPDATE WHERE clause expression */
2132  if (node->onConflictWhere)
2133  {
2134  ExprState *qualexpr;
2135 
2136  qualexpr = ExecInitQual((List *) node->onConflictWhere,
2137  &mtstate->ps);
2138 
2139  resultRelInfo->ri_onConflictSetWhere = qualexpr;
2140  }
2141  }
2142 
2143  /*
2144  * If we have any secondary relations in an UPDATE or DELETE, they need to
2145  * be treated like non-locked relations in SELECT FOR UPDATE, ie, the
2146  * EvalPlanQual mechanism needs to be told about them. Locate the
2147  * relevant ExecRowMarks.
2148  */
2149  foreach(l, node->rowMarks)
2150  {
2152  ExecRowMark *erm;
2153 
2154  /* ignore "parent" rowmarks; they are irrelevant at runtime */
2155  if (rc->isParent)
2156  continue;
2157 
2158  /* find ExecRowMark (same for all subplans) */
2159  erm = ExecFindRowMark(estate, rc->rti, false);
2160 
2161  /* build ExecAuxRowMark for each subplan */
2162  for (i = 0; i < nplans; i++)
2163  {
2164  ExecAuxRowMark *aerm;
2165 
2166  subplan = mtstate->mt_plans[i]->plan;
2167  aerm = ExecBuildAuxRowMark(erm, subplan->targetlist);
2168  mtstate->mt_arowmarks[i] = lappend(mtstate->mt_arowmarks[i], aerm);
2169  }
2170  }
2171 
2172  /* select first subplan */
2173  mtstate->mt_whichplan = 0;
2174  subplan = (Plan *) linitial(node->plans);
2175  EvalPlanQualSetPlan(&mtstate->mt_epqstate, subplan,
2176  mtstate->mt_arowmarks[0]);
2177 
2178  /*
2179  * Initialize the junk filter(s) if needed. INSERT queries need a filter
2180  * if there are any junk attrs in the tlist. UPDATE and DELETE always
2181  * need a filter, since there's always a junk 'ctid' or 'wholerow'
2182  * attribute present --- no need to look first.
2183  *
2184  * If there are multiple result relations, each one needs its own junk
2185  * filter. Note multiple rels are only possible for UPDATE/DELETE, so we
2186  * can't be fooled by some needing a filter and some not.
2187  *
2188  * This section of code is also a convenient place to verify that the
2189  * output of an INSERT or UPDATE matches the target table(s).
2190  */
2191  {
2192  bool junk_filter_needed = false;
2193 
2194  switch (operation)
2195  {
2196  case CMD_INSERT:
2197  foreach(l, subplan->targetlist)
2198  {
2199  TargetEntry *tle = (TargetEntry *) lfirst(l);
2200 
2201  if (tle->resjunk)
2202  {
2203  junk_filter_needed = true;
2204  break;
2205  }
2206  }
2207  break;
2208  case CMD_UPDATE:
2209  case CMD_DELETE:
2210  junk_filter_needed = true;
2211  break;
2212  default:
2213  elog(ERROR, "unknown operation");
2214  break;
2215  }
2216 
2217  if (junk_filter_needed)
2218  {
2219  resultRelInfo = mtstate->resultRelInfo;
2220  for (i = 0; i < nplans; i++)
2221  {
2222  JunkFilter *j;
2223 
2224  subplan = mtstate->mt_plans[i]->plan;
2225  if (operation == CMD_INSERT || operation == CMD_UPDATE)
2226  ExecCheckPlanOutput(resultRelInfo->ri_RelationDesc,
2227  subplan->targetlist);
2228 
2229  j = ExecInitJunkFilter(subplan->targetlist,
2230  resultRelInfo->ri_RelationDesc->rd_att->tdhasoid,
2231  ExecInitExtraTupleSlot(estate));
2232 
2233  if (operation == CMD_UPDATE || operation == CMD_DELETE)
2234  {
2235  /* For UPDATE/DELETE, find the appropriate junk attr now */
2236  char relkind;
2237 
2238  relkind = resultRelInfo->ri_RelationDesc->rd_rel->relkind;
2239  if (relkind == RELKIND_RELATION ||
2240  relkind == RELKIND_MATVIEW ||
2241  relkind == RELKIND_PARTITIONED_TABLE)
2242  {
2243  j->jf_junkAttNo = ExecFindJunkAttribute(j, "ctid");
2245  elog(ERROR, "could not find junk ctid column");
2246  }
2247  else if (relkind == RELKIND_FOREIGN_TABLE)
2248  {
2249  /*
2250  * When there is an AFTER trigger, there should be a
2251  * wholerow attribute.
2252  */
2253  j->jf_junkAttNo = ExecFindJunkAttribute(j, "wholerow");
2254  }
2255  else
2256  {
2257  j->jf_junkAttNo = ExecFindJunkAttribute(j, "wholerow");
2259  elog(ERROR, "could not find junk wholerow column");
2260  }
2261  }
2262 
2263  resultRelInfo->ri_junkFilter = j;
2264  resultRelInfo++;
2265  }
2266  }
2267  else
2268  {
2269  if (operation == CMD_INSERT)
2271  subplan->targetlist);
2272  }
2273  }
2274 
2275  /*
2276  * Set up a tuple table slot for use for trigger output tuples. In a plan
2277  * containing multiple ModifyTable nodes, all can share one such slot, so
2278  * we keep it in the estate.
2279  */
2280  if (estate->es_trig_tuple_slot == NULL)
2281  estate->es_trig_tuple_slot = ExecInitExtraTupleSlot(estate);
2282 
2283  /*
2284  * Lastly, if this is not the primary (canSetTag) ModifyTable node, add it
2285  * to estate->es_auxmodifytables so that it will be run to completion by
2286  * ExecPostprocessPlan. (It'd actually work fine to add the primary
2287  * ModifyTable node too, but there's no need.) Note the use of lcons not
2288  * lappend: we need later-initialized ModifyTable nodes to be shut down
2289  * before earlier ones. This ensures that we don't throw away RETURNING
2290  * rows that need to be seen by a later CTE subplan.
2291  */
2292  if (!mtstate->canSetTag)
2293  estate->es_auxmodifytables = lcons(mtstate,
2294  estate->es_auxmodifytables);
2295 
2296  return mtstate;
2297 }
AttrNumber jf_junkAttNo
Definition: execnodes.h:336
#define NIL
Definition: pg_list.h:69
JunkFilter * ri_junkFilter
Definition: execnodes.h:396
List * arbiterIndexes
Definition: plannodes.h:233
Relation ri_RelationDesc
Definition: execnodes.h:354
Bitmapset * fdwDirectModifyPlans
Definition: plannodes.h:229
ExprState * ri_onConflictSetWhere
Definition: execnodes.h:405
TupleTableSlot * ExecInitExtraTupleSlot(EState *estate)
Definition: execTuples.c:852
Index nominalRelation
Definition: plannodes.h:219
bool tdhasoid
Definition: tupdesc.h:79
ProjectionInfo * ri_onConflictSetProj
Definition: execnodes.h:402
ResultRelInfo * mt_partitions
Definition: execnodes.h:962
List * withCheckOptionLists
Definition: plannodes.h:226
#define castNode(_type_, nodeptr)
Definition: nodes.h:578
int resultRelIndex
Definition: plannodes.h:223
ResultRelInfo * resultRelInfo
Definition: execnodes.h:945
AttrNumber ExecFindJunkAttribute(JunkFilter *junkfilter, const char *attrName)
Definition: execJunk.c:209
ExprContext * ps_ExprContext
Definition: execnodes.h:862
TupleTableSlot * mt_conflproj
Definition: execnodes.h:956
#define RELKIND_MATVIEW
Definition: pg_class.h:165
bool canSetTag
Definition: plannodes.h:218
CmdType operation
Definition: execnodes.h:939
ResultRelInfo * rootResultRelInfo
Definition: execnodes.h:946
void EvalPlanQualSetPlan(EPQState *epqstate, Plan *subplan, List *auxrowmarks)
Definition: execMain.c:2780
#define heap_close(r, l)
Definition: heapam.h:97
EState * state
Definition: execnodes.h:834
List * es_range_table
Definition: execnodes.h:431
Form_pg_class rd_rel
Definition: rel.h:114
unsigned int Oid
Definition: postgres_ext.h:31
List * plans
Definition: plannodes.h:225
void ExecAssignResultType(PlanState *planstate, TupleDesc tupDesc)
Definition: execUtils.c:428
ExprState * ExecInitQual(List *qual, PlanState *parent)
Definition: execExpr.c:160
List * onConflictSet
Definition: plannodes.h:234
int rootResultRelIndex
Definition: plannodes.h:224
void ExecOpenIndices(ResultRelInfo *resultRelInfo, bool speculative)
Definition: execIndexing.c:149
TupleTableSlot * mt_existing
Definition: execnodes.h:954
void ExecSetupPartitionTupleRouting(Relation rel, Index resultRTindex, PartitionDispatch **pd, ResultRelInfo **partitions, TupleConversionMap ***tup_conv_maps, TupleTableSlot **partition_tuple_slot, int *num_parted, int *num_partitions)
Definition: execMain.c:3234
List * ri_WithCheckOptionExprs
Definition: execnodes.h:390
#define linitial_int(l)
Definition: pg_list.h:112
OnConflictAction mt_onconflict
Definition: execnodes.h:951
TupleTableSlot * ps_ResultTupleSlot
Definition: execnodes.h:861
List * rowMarks
Definition: plannodes.h:230
bool resjunk
Definition: primnodes.h:1375
#define linitial(l)
Definition: pg_list.h:111
#define ERROR
Definition: elog.h:43
PlanState ps
Definition: execnodes.h:938
void ExecInitResultTupleSlot(EState *estate, PlanState *planstate)
Definition: execTuples.c:832
bool ri_usesFdwDirectModify
Definition: execnodes.h:384
static void ExecSetupTransitionCaptureState(ModifyTableState *mtstate, EState *estate)
#define EXEC_FLAG_BACKWARD
Definition: executor.h:60
#define lfirst_node(type, lc)
Definition: pg_list.h:109
void * list_nth(const List *list, int n)
Definition: list.c:410
#define NoLock
Definition: lockdefs.h:34
ResultRelInfo * es_result_relations
Definition: execnodes.h:441
JunkFilter * ExecInitJunkFilter(List *targetList, bool hasoid, TupleTableSlot *slot)
Definition: execJunk.c:61
List * fdwPrivLists
Definition: plannodes.h:228
EPQState mt_epqstate
Definition: execnodes.h:949
ProjectionInfo * ri_projectReturning
Definition: execnodes.h:399
void CheckValidResultRel(Relation resultRel, CmdType operation)
Definition: execMain.c:1099
struct FdwRoutine * ri_FdwRoutine
Definition: execnodes.h:378
#define RELKIND_FOREIGN_TABLE
Definition: pg_class.h:167
List * partitioned_rels
Definition: plannodes.h:221
TupleTableSlot * es_trig_tuple_slot
Definition: execnodes.h:457
TupleDesc ExecTypeFromTL(List *targetList, bool hasoid)
Definition: execTuples.c:888
List * lappend(List *list, void *datum)
Definition: list.c:128
PlanState ** mt_plans
Definition: execnodes.h:942
#define AttributeNumberIsValid(attributeNumber)
Definition: attnum.h:34
#define RELKIND_PARTITIONED_TABLE
Definition: pg_class.h:168
void * palloc0(Size size)
Definition: mcxt.c:878
List * es_auxmodifytables
Definition: execnodes.h:485
void ExecSetSlotDescriptor(TupleTableSlot *slot, TupleDesc tupdesc)
Definition: execTuples.c:247
List * ri_WithCheckOptions
Definition: execnodes.h:387
TupleTableSlot * mt_partition_tuple_slot
Definition: execnodes.h:965
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1284
unsigned int Index
Definition: c.h:365
TupleDesc rd_att
Definition: rel.h:115
void EvalPlanQualInit(EPQState *epqstate, EState *estate, Plan *subplan, List *auxrowmarks, int epqParam)
Definition: execMain.c:2761
Plan * plan
Definition: execnodes.h:832
List * lcons(void *datum, List *list)
Definition: list.c:259
#define makeNode(_type_)
Definition: nodes.h:557
static void ExecCheckPlanOutput(Relation resultRel, List *targetList)
#define NULL
Definition: c.h:229
#define Assert(condition)
Definition: c.h:675
#define lfirst(lc)
Definition: pg_list.h:106
#define EXEC_FLAG_MARK
Definition: executor.h:61
OnConflictAction onConflictAction
Definition: plannodes.h:232
void ExecAssignExprContext(EState *estate, PlanState *planstate)
Definition: execUtils.c:418
static int list_length(const List *l)
Definition: pg_list.h:89
List * targetlist
Definition: plannodes.h:144
List * mt_arbiterindexes
Definition: execnodes.h:952
List * mt_excludedtlist
Definition: execnodes.h:955
ProjectionInfo * ExecBuildProjectionInfo(List *targetList, ExprContext *econtext, TupleTableSlot *slot, PlanState *parent, TupleDesc inputDesc)
Definition: execExpr.c:301
#define getrelid(rangeindex, rangetable)
Definition: parsetree.h:41
CmdType operation
Definition: plannodes.h:217
ResultRelInfo * es_root_result_relations
Definition: execnodes.h:452
int i
struct PartitionDispatchData ** mt_partition_dispatch_info
Definition: execnodes.h:957
List * returningLists
Definition: plannodes.h:227
bool isParent
Definition: plannodes.h:1011
TupleConversionMap ** mt_partition_tupconv_maps
Definition: execnodes.h:963
#define elog
Definition: elog.h:219
BeginForeignModify_function BeginForeignModify
Definition: fdwapi.h:196
#define RELKIND_RELATION
Definition: pg_class.h:160
PlanState * ExecInitNode(Plan *node, EState *estate, int eflags)
Definition: execProcnode.c:140
Definition: pg_list.h:45
bool bms_is_member(int x, const Bitmapset *a)
Definition: bitmapset.c:420
CmdType
Definition: nodes.h:649
RelationPtr ri_IndexRelationDescs
Definition: execnodes.h:360
ExecAuxRowMark * ExecBuildAuxRowMark(ExecRowMark *erm, List *targetlist)
Definition: execMain.c:2374
List * exclRelTlist
Definition: plannodes.h:237
List ** mt_arowmarks
Definition: execnodes.h:948
int epqParam
Definition: plannodes.h:231
List * map_partition_varattnos(List *expr, int target_varno, Relation partrel, Relation parent)
Definition: partition.c:921
Node * onConflictWhere
Definition: plannodes.h:235
ExecRowMark * ExecFindRowMark(EState *estate, Index rti, bool missing_ok)
Definition: execMain.c:2350
ResultRelInfo * es_result_relation_info
Definition: execnodes.h:443
static TupleTableSlot* ExecInsert ( ModifyTableState mtstate,
TupleTableSlot slot,
TupleTableSlot planSlot,
List arbiterIndexes,
OnConflictAction  onconflict,
EState estate,
bool  canSetTag 
)
static

Definition at line 252 of file nodeModifyTable.c.

References Assert, tupleDesc::constr, do_convert_tuple(), ereport, errcode(), errmsg(), ERROR, EState::es_lastoid, EState::es_output_cid, EState::es_processed, EState::es_result_relation_info, ExecARInsertTriggers(), ExecBRInsertTriggers(), ExecCheckIndexConstraints(), ExecCheckTIDVisible(), ExecConstraints(), ExecFindPartition(), FdwRoutine::ExecForeignInsert, ExecInsertIndexTuples(), ExecIRInsertTriggers(), ExecMaterializeSlot(), ExecOnConflictUpdate(), ExecProcessReturning(), ExecSetSlotDescriptor(), ExecStoreTuple(), ExecWithCheckOptions(), GetCurrentTransactionId(), heap_abort_speculative(), heap_finish_speculative(), heap_insert(), HEAP_INSERT_SPECULATIVE, HeapTupleHeaderSetSpeculativeToken, HeapTupleSetOid, InstrCountFiltered2, InvalidBuffer, InvalidOid, list_free(), ModifyTableState::mt_partition_dispatch_info, ModifyTableState::mt_partition_tupconv_maps, ModifyTableState::mt_partition_tuple_slot, ModifyTableState::mt_partitions, ModifyTableState::mt_transition_capture, ModifyTableState::mt_transition_tupconv_maps, NIL, NULL, ONCONFLICT_NONE, ONCONFLICT_NOTHING, ONCONFLICT_UPDATE, ModifyTableState::ps, RelationData::rd_att, RelationData::rd_rel, RelationGetDescr, RelationGetRelid, result, ResultRelInfo::ri_FdwRoutine, ResultRelInfo::ri_NumIndices, ResultRelInfo::ri_PartitionCheck, ResultRelInfo::ri_projectReturning, ResultRelInfo::ri_RelationDesc, ResultRelInfo::ri_TrigDesc, ResultRelInfo::ri_WithCheckOptions, setLastTid(), SpeculativeInsertionLockAcquire(), SpeculativeInsertionLockRelease(), HeapTupleData::t_data, HeapTupleData::t_self, HeapTupleData::t_tableOid, TransitionCaptureState::tcs_map, TransitionCaptureState::tcs_original_insert_tuple, TriggerDesc::trig_insert_before_row, TriggerDesc::trig_insert_instead_row, WCO_RLS_INSERT_CHECK, and WCO_VIEW_CHECK.

Referenced by ExecModifyTable().

259 {
260  HeapTuple tuple;
261  ResultRelInfo *resultRelInfo;
262  ResultRelInfo *saved_resultRelInfo = NULL;
263  Relation resultRelationDesc;
264  Oid newId;
265  List *recheckIndexes = NIL;
267 
268  /*
269  * get the heap tuple out of the tuple table slot, making sure we have a
270  * writable copy
271  */
272  tuple = ExecMaterializeSlot(slot);
273 
274  /*
275  * get information on the (current) result relation
276  */
277  resultRelInfo = estate->es_result_relation_info;
278 
279  /* Determine the partition to heap_insert the tuple into */
280  if (mtstate->mt_partition_dispatch_info)
281  {
282  int leaf_part_index;
283  TupleConversionMap *map;
284 
285  /*
286  * Away we go ... If we end up not finding a partition after all,
287  * ExecFindPartition() does not return and errors out instead.
288  * Otherwise, the returned value is to be used as an index into arrays
289  * mt_partitions[] and mt_partition_tupconv_maps[] that will get us
290  * the ResultRelInfo and TupleConversionMap for the partition,
291  * respectively.
292  */
293  leaf_part_index = ExecFindPartition(resultRelInfo,
295  slot,
296  estate);
297  Assert(leaf_part_index >= 0 &&
298  leaf_part_index < mtstate->mt_num_partitions);
299 
300  /*
301  * Save the old ResultRelInfo and switch to the one corresponding to
302  * the selected partition.
303  */
304  saved_resultRelInfo = resultRelInfo;
305  resultRelInfo = mtstate->mt_partitions + leaf_part_index;
306 
307  /* We do not yet have a way to insert into a foreign partition */
308  if (resultRelInfo->ri_FdwRoutine)
309  ereport(ERROR,
310  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
311  errmsg("cannot route inserted tuples to a foreign table")));
312 
313  /* For ExecInsertIndexTuples() to work on the partition's indexes */
314  estate->es_result_relation_info = resultRelInfo;
315 
316  /*
317  * If we're capturing transition tuples, we might need to convert from
318  * the partition rowtype to parent rowtype.
319  */
320  if (mtstate->mt_transition_capture != NULL)
321  {
322  if (resultRelInfo->ri_TrigDesc &&
323  (resultRelInfo->ri_TrigDesc->trig_insert_before_row ||
324  resultRelInfo->ri_TrigDesc->trig_insert_instead_row))
325  {
326  /*
327  * If there are any BEFORE or INSTEAD triggers on the
328  * partition, we'll have to be ready to convert their result
329  * back to tuplestore format.
330  */
332  mtstate->mt_transition_capture->tcs_map =
333  mtstate->mt_transition_tupconv_maps[leaf_part_index];
334  }
335  else
336  {
337  /*
338  * Otherwise, just remember the original unconverted tuple, to
339  * avoid a needless round trip conversion.
340  */
342  mtstate->mt_transition_capture->tcs_map = NULL;
343  }
344  }
345 
346  /*
347  * We might need to convert from the parent rowtype to the partition
348  * rowtype.
349  */
350  map = mtstate->mt_partition_tupconv_maps[leaf_part_index];
351  if (map)
352  {
353  Relation partrel = resultRelInfo->ri_RelationDesc;
354 
355  tuple = do_convert_tuple(tuple, map);
356 
357  /*
358  * We must use the partition's tuple descriptor from this point
359  * on, until we're finished dealing with the partition. Use the
360  * dedicated slot for that.
361  */
362  slot = mtstate->mt_partition_tuple_slot;
363  Assert(slot != NULL);
364  ExecSetSlotDescriptor(slot, RelationGetDescr(partrel));
365  ExecStoreTuple(tuple, slot, InvalidBuffer, true);
366  }
367  }
368 
369  resultRelationDesc = resultRelInfo->ri_RelationDesc;
370 
371  /*
372  * If the result relation has OIDs, force the tuple's OID to zero so that
373  * heap_insert will assign a fresh OID. Usually the OID already will be
374  * zero at this point, but there are corner cases where the plan tree can
375  * return a tuple extracted literally from some table with the same
376  * rowtype.
377  *
378  * XXX if we ever wanted to allow users to assign their own OIDs to new
379  * rows, this'd be the place to do it. For the moment, we make a point of
380  * doing this before calling triggers, so that a user-supplied trigger
381  * could hack the OID if desired.
382  */
383  if (resultRelationDesc->rd_rel->relhasoids)
384  HeapTupleSetOid(tuple, InvalidOid);
385 
386  /*
387  * BEFORE ROW INSERT Triggers.
388  *
389  * Note: We fire BEFORE ROW TRIGGERS for every attempted insertion in an
390  * INSERT ... ON CONFLICT statement. We cannot check for constraint
391  * violations before firing these triggers, because they can change the
392  * values to insert. Also, they can run arbitrary user-defined code with
393  * side-effects that we can't cancel by just not inserting the tuple.
394  */
395  if (resultRelInfo->ri_TrigDesc &&
396  resultRelInfo->ri_TrigDesc->trig_insert_before_row)
397  {
398  slot = ExecBRInsertTriggers(estate, resultRelInfo, slot);
399 
400  if (slot == NULL) /* "do nothing" */
401  return NULL;
402 
403  /* trigger might have changed tuple */
404  tuple = ExecMaterializeSlot(slot);
405  }
406 
407  /* INSTEAD OF ROW INSERT Triggers */
408  if (resultRelInfo->ri_TrigDesc &&
409  resultRelInfo->ri_TrigDesc->trig_insert_instead_row)
410  {
411  slot = ExecIRInsertTriggers(estate, resultRelInfo, slot);
412 
413  if (slot == NULL) /* "do nothing" */
414  return NULL;
415 
416  /* trigger might have changed tuple */
417  tuple = ExecMaterializeSlot(slot);
418 
419  newId = InvalidOid;
420  }
421  else if (resultRelInfo->ri_FdwRoutine)
422  {
423  /*
424  * insert into foreign table: let the FDW do it
425  */
426  slot = resultRelInfo->ri_FdwRoutine->ExecForeignInsert(estate,
427  resultRelInfo,
428  slot,
429  planSlot);
430 
431  if (slot == NULL) /* "do nothing" */
432  return NULL;
433 
434  /* FDW might have changed tuple */
435  tuple = ExecMaterializeSlot(slot);
436 
437  /*
438  * AFTER ROW Triggers or RETURNING expressions might reference the
439  * tableoid column, so initialize t_tableOid before evaluating them.
440  */
441  tuple->t_tableOid = RelationGetRelid(resultRelationDesc);
442 
443  newId = InvalidOid;
444  }
445  else
446  {
447  /*
448  * We always check the partition constraint, including when the tuple
449  * got here via tuple-routing. However we don't need to in the latter
450  * case if no BR trigger is defined on the partition. Note that a BR
451  * trigger might modify the tuple such that the partition constraint
452  * is no longer satisfied, so we need to check in that case.
453  */
454  bool check_partition_constr =
455  (resultRelInfo->ri_PartitionCheck != NIL);
456 
457  /*
458  * Constraints might reference the tableoid column, so initialize
459  * t_tableOid before evaluating them.
460  */
461  tuple->t_tableOid = RelationGetRelid(resultRelationDesc);
462 
463  /*
464  * Check any RLS INSERT WITH CHECK policies
465  *
466  * ExecWithCheckOptions() will skip any WCOs which are not of the kind
467  * we are looking for at this point.
468  */
469  if (resultRelInfo->ri_WithCheckOptions != NIL)
471  resultRelInfo, slot, estate);
472 
473  /*
474  * No need though if the tuple has been routed, and a BR trigger
475  * doesn't exist.
476  */
477  if (saved_resultRelInfo != NULL &&
478  !(resultRelInfo->ri_TrigDesc &&
479  resultRelInfo->ri_TrigDesc->trig_insert_before_row))
480  check_partition_constr = false;
481 
482  /* Check the constraints of the tuple */
483  if (resultRelationDesc->rd_att->constr || check_partition_constr)
484  ExecConstraints(resultRelInfo, slot, estate);
485 
486  if (onconflict != ONCONFLICT_NONE && resultRelInfo->ri_NumIndices > 0)
487  {
488  /* Perform a speculative insertion. */
489  uint32 specToken;
490  ItemPointerData conflictTid;
491  bool specConflict;
492 
493  /*
494  * Do a non-conclusive check for conflicts first.
495  *
496  * We're not holding any locks yet, so this doesn't guarantee that
497  * the later insert won't conflict. But it avoids leaving behind
498  * a lot of canceled speculative insertions, if you run a lot of
499  * INSERT ON CONFLICT statements that do conflict.
500  *
501  * We loop back here if we find a conflict below, either during
502  * the pre-check, or when we re-check after inserting the tuple
503  * speculatively.
504  */
505  vlock:
506  specConflict = false;
507  if (!ExecCheckIndexConstraints(slot, estate, &conflictTid,
508  arbiterIndexes))
509  {
510  /* committed conflict tuple found */
511  if (onconflict == ONCONFLICT_UPDATE)
512  {
513  /*
514  * In case of ON CONFLICT DO UPDATE, execute the UPDATE
515  * part. Be prepared to retry if the UPDATE fails because
516  * of another concurrent UPDATE/DELETE to the conflict
517  * tuple.
518  */
519  TupleTableSlot *returning = NULL;
520 
521  if (ExecOnConflictUpdate(mtstate, resultRelInfo,
522  &conflictTid, planSlot, slot,
523  estate, canSetTag, &returning))
524  {
525  InstrCountFiltered2(&mtstate->ps, 1);
526  return returning;
527  }
528  else
529  goto vlock;
530  }
531  else
532  {
533  /*
534  * In case of ON CONFLICT DO NOTHING, do nothing. However,
535  * verify that the tuple is visible to the executor's MVCC
536  * snapshot at higher isolation levels.
537  */
538  Assert(onconflict == ONCONFLICT_NOTHING);
539  ExecCheckTIDVisible(estate, resultRelInfo, &conflictTid);
540  InstrCountFiltered2(&mtstate->ps, 1);
541  return NULL;
542  }
543  }
544 
545  /*
546  * Before we start insertion proper, acquire our "speculative
547  * insertion lock". Others can use that to wait for us to decide
548  * if we're going to go ahead with the insertion, instead of
549  * waiting for the whole transaction to complete.
550  */
552  HeapTupleHeaderSetSpeculativeToken(tuple->t_data, specToken);
553 
554  /* insert the tuple, with the speculative token */
555  newId = heap_insert(resultRelationDesc, tuple,
556  estate->es_output_cid,
558  NULL);
559 
560  /* insert index entries for tuple */
561  recheckIndexes = ExecInsertIndexTuples(slot, &(tuple->t_self),
562  estate, true, &specConflict,
563  arbiterIndexes);
564 
565  /* adjust the tuple's state accordingly */
566  if (!specConflict)
567  heap_finish_speculative(resultRelationDesc, tuple);
568  else
569  heap_abort_speculative(resultRelationDesc, tuple);
570 
571  /*
572  * Wake up anyone waiting for our decision. They will re-check
573  * the tuple, see that it's no longer speculative, and wait on our
574  * XID as if this was a regularly inserted tuple all along. Or if
575  * we killed the tuple, they will see it's dead, and proceed as if
576  * the tuple never existed.
577  */
579 
580  /*
581  * If there was a conflict, start from the beginning. We'll do
582  * the pre-check again, which will now find the conflicting tuple
583  * (unless it aborts before we get there).
584  */
585  if (specConflict)
586  {
587  list_free(recheckIndexes);
588  goto vlock;
589  }
590 
591  /* Since there was no insertion conflict, we're done */
592  }
593  else
594  {
595  /*
596  * insert the tuple normally.
597  *
598  * Note: heap_insert returns the tid (location) of the new tuple
599  * in the t_self field.
600  */
601  newId = heap_insert(resultRelationDesc, tuple,
602  estate->es_output_cid,
603  0, NULL);
604 
605  /* insert index entries for tuple */
606  if (resultRelInfo->ri_NumIndices > 0)
607  recheckIndexes = ExecInsertIndexTuples(slot, &(tuple->t_self),
608  estate, false, NULL,
609  arbiterIndexes);
610  }
611  }
612 
613  if (canSetTag)
614  {
615  (estate->es_processed)++;
616  estate->es_lastoid = newId;
617  setLastTid(&(tuple->t_self));
618  }
619 
620  /* AFTER ROW INSERT Triggers */
621  ExecARInsertTriggers(estate, resultRelInfo, tuple, recheckIndexes,
622  mtstate->mt_transition_capture);
623 
624  list_free(recheckIndexes);
625 
626  /*
627  * Check any WITH CHECK OPTION constraints from parent views. We are
628  * required to do this after testing all constraints and uniqueness
629  * violations per the SQL spec, so we do it after actually inserting the
630  * record into the heap and all indexes.
631  *
632  * ExecWithCheckOptions will elog(ERROR) if a violation is found, so the
633  * tuple will never be seen, if it violates the WITH CHECK OPTION.
634  *
635  * ExecWithCheckOptions() will skip any WCOs which are not of the kind we
636  * are looking for at this point.
637  */
638  if (resultRelInfo->ri_WithCheckOptions != NIL)
639  ExecWithCheckOptions(WCO_VIEW_CHECK, resultRelInfo, slot, estate);
640 
641  /* Process RETURNING if present */
642  if (resultRelInfo->ri_projectReturning)
643  result = ExecProcessReturning(resultRelInfo, slot, planSlot);
644 
645  if (saved_resultRelInfo)
646  estate->es_result_relation_info = saved_resultRelInfo;
647 
648  return result;
649 }
int ri_NumIndices
Definition: execnodes.h:357
#define NIL
Definition: pg_list.h:69
TupleTableSlot * ExecStoreTuple(HeapTuple tuple, TupleTableSlot *slot, Buffer buffer, bool shouldFree)
Definition: execTuples.c:320
Relation ri_RelationDesc
Definition: execnodes.h:354
void SpeculativeInsertionLockRelease(TransactionId xid)
Definition: lmgr.c:669
static bool ExecOnConflictUpdate(ModifyTableState *mtstate, ResultRelInfo *resultRelInfo, ItemPointer conflictTid, TupleTableSlot *planSlot, TupleTableSlot *excludedSlot, EState *estate, bool canSetTag, TupleTableSlot **returning)
void ExecWithCheckOptions(WCOKind kind, ResultRelInfo *resultRelInfo, TupleTableSlot *slot, EState *estate)
Definition: execMain.c:2042
void heap_abort_speculative(Relation relation, HeapTuple tuple)
Definition: heapam.c:6054
CommandId es_output_cid
Definition: execnodes.h:438
List * ExecInsertIndexTuples(TupleTableSlot *slot, ItemPointer tupleid, EState *estate, bool noDupErr, bool *specConflict, List *arbiterIndexes)
Definition: execIndexing.c:271
ResultRelInfo * mt_partitions
Definition: execnodes.h:962
#define RelationGetDescr(relation)
Definition: rel.h:428
Oid es_lastoid
Definition: execnodes.h:475
ExecForeignInsert_function ExecForeignInsert
Definition: fdwapi.h:197
TupleTableSlot * ExecIRInsertTriggers(EState *estate, ResultRelInfo *relinfo, TupleTableSlot *slot)
Definition: trigger.c:2428
void ExecConstraints(ResultRelInfo *resultRelInfo, TupleTableSlot *slot, EState *estate)
Definition: execMain.c:1913
#define HeapTupleHeaderSetSpeculativeToken(tup, token)
Definition: htup_details.h:434
#define InvalidBuffer
Definition: buf.h:25
int errcode(int sqlerrcode)
Definition: elog.c:575
uint32 SpeculativeInsertionLockAcquire(TransactionId xid)
Definition: lmgr.c:643
void ExecARInsertTriggers(EState *estate, ResultRelInfo *relinfo, HeapTuple trigtuple, List *recheckIndexes, TransitionCaptureState *transition_capture)
Definition: trigger.c:2413
return result
Definition: formatting.c:1633
Form_pg_class rd_rel
Definition: rel.h:114
unsigned int Oid
Definition: postgres_ext.h:31
bool ExecCheckIndexConstraints(TupleTableSlot *slot, EState *estate, ItemPointer conflictTid, List *arbiterIndexes)
Definition: execIndexing.c:475
HeapTuple tcs_original_insert_tuple
Definition: trigger.h:74
#define HEAP_INSERT_SPECULATIVE
Definition: heapam.h:31
HeapTupleHeader t_data
Definition: htup.h:67
#define HeapTupleSetOid(tuple, oid)
Definition: htup_details.h:698
bool trig_insert_instead_row
Definition: reltrigger.h:57
#define ERROR
Definition: elog.h:43
PlanState ps
Definition: execnodes.h:938
static void ExecCheckTIDVisible(EState *estate, ResultRelInfo *relinfo, ItemPointer tid)
TupleConversionMap * tcs_map
Definition: trigger.h:65
ItemPointerData t_self
Definition: htup.h:65
TransactionId GetCurrentTransactionId(void)
Definition: xact.c:417
struct TransitionCaptureState * mt_transition_capture
Definition: execnodes.h:966
ProjectionInfo * ri_projectReturning
Definition: execnodes.h:399
struct FdwRoutine * ri_FdwRoutine
Definition: execnodes.h:378
unsigned int uint32
Definition: c.h:268
Oid t_tableOid
Definition: htup.h:66
void setLastTid(const ItemPointer tid)
Definition: tid.c:254
#define ereport(elevel, rest)
Definition: elog.h:122
Oid heap_insert(Relation relation, HeapTuple tup, CommandId cid, int options, BulkInsertState bistate)
Definition: heapam.c:2396
TriggerDesc * ri_TrigDesc
Definition: execnodes.h:366
static TupleTableSlot * ExecProcessReturning(ResultRelInfo *resultRelInfo, TupleTableSlot *tupleSlot, TupleTableSlot *planSlot)
bool trig_insert_before_row
Definition: reltrigger.h:55
void ExecSetSlotDescriptor(TupleTableSlot *slot, TupleDesc tupdesc)
Definition: execTuples.c:247
List * ri_WithCheckOptions
Definition: execnodes.h:387
int ExecFindPartition(ResultRelInfo *resultRelInfo, PartitionDispatch *pd, TupleTableSlot *slot, EState *estate)
Definition: execMain.c:3324
TupleTableSlot * mt_partition_tuple_slot
Definition: execnodes.h:965
List * ri_PartitionCheck
Definition: execnodes.h:408
TupleDesc rd_att
Definition: rel.h:115
#define InvalidOid
Definition: postgres_ext.h:36
#define NULL
Definition: c.h:229
#define Assert(condition)
Definition: c.h:675
#define InstrCountFiltered2(node, delta)
Definition: execnodes.h:882
void heap_finish_speculative(Relation relation, HeapTuple tuple)
Definition: heapam.c:5963
uint64 es_processed
Definition: execnodes.h:474
TupleConstr * constr
Definition: tupdesc.h:76
HeapTuple ExecMaterializeSlot(TupleTableSlot *slot)
Definition: execTuples.c:725
HeapTuple do_convert_tuple(HeapTuple tuple, TupleConversionMap *map)
Definition: tupconvert.c:343
TupleConversionMap ** mt_transition_tupconv_maps
Definition: execnodes.h:968
int errmsg(const char *fmt,...)
Definition: elog.c:797
void list_free(List *list)
Definition: list.c:1133
struct PartitionDispatchData ** mt_partition_dispatch_info
Definition: execnodes.h:957
TupleTableSlot * ExecBRInsertTriggers(EState *estate, ResultRelInfo *relinfo, TupleTableSlot *slot)
Definition: trigger.c:2347
TupleConversionMap ** mt_partition_tupconv_maps
Definition: execnodes.h:963
Definition: pg_list.h:45
#define RelationGetRelid(relation)
Definition: rel.h:416
ResultRelInfo * es_result_relation_info
Definition: execnodes.h:443
TupleTableSlot* ExecModifyTable ( ModifyTableState node)

Definition at line 1539 of file nodeModifyTable.c.

References Assert, AttributeNumberIsValid, ModifyTableState::canSetTag, CMD_DELETE, CMD_INSERT, CMD_UPDATE, DatumGetHeapTupleHeader, DatumGetPointer, elog, ERROR, EState::es_epqTuple, EState::es_result_relation_info, EvalPlanQualSetPlan(), EvalPlanQualSetSlot, ExecDelete(), ExecFilterJunk(), ExecGetJunkAttribute(), ExecInsert(), ExecProcessReturning(), ExecProcNode(), ExecUpdate(), fireASTriggers(), ModifyTableState::fireBSTriggers, fireBSTriggers(), HeapTupleHeaderGetDatumLength, InvalidOid, ItemPointerSetInvalid, JunkFilter::jf_junkAttNo, ModifyTableState::mt_arbiterindexes, ModifyTableState::mt_arowmarks, ModifyTableState::mt_done, ModifyTableState::mt_epqstate, ModifyTableState::mt_nplans, ModifyTableState::mt_onconflict, ModifyTableState::mt_plans, ModifyTableState::mt_transition_capture, ModifyTableState::mt_transition_tupconv_maps, ModifyTableState::mt_whichplan, NULL, ModifyTableState::operation, PlanState::plan, ModifyTableState::ps, RelationData::rd_rel, RelationGetRelid, RELKIND_FOREIGN_TABLE, RELKIND_MATVIEW, RELKIND_RELATION, RELKIND_VIEW, 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, and TupIsNull.

Referenced by ExecProcNode().

1540 {
1541  EState *estate = node->ps.state;
1542  CmdType operation = node->operation;
1543  ResultRelInfo *saved_resultRelInfo;
1544  ResultRelInfo *resultRelInfo;
1545  PlanState *subplanstate;
1546  JunkFilter *junkfilter;
1547  TupleTableSlot *slot;
1548  TupleTableSlot *planSlot;
1549  ItemPointer tupleid = NULL;
1550  ItemPointerData tuple_ctid;
1551  HeapTupleData oldtupdata;
1552  HeapTuple oldtuple;
1553 
1554  /*
1555  * This should NOT get called during EvalPlanQual; we should have passed a
1556  * subplan tree to EvalPlanQual, instead. Use a runtime test not just
1557  * Assert because this condition is easy to miss in testing. (Note:
1558  * although ModifyTable should not get executed within an EvalPlanQual
1559  * operation, we do have to allow it to be initialized and shut down in
1560  * case it is within a CTE subplan. Hence this test must be here, not in
1561  * ExecInitModifyTable.)
1562  */
1563  if (estate->es_epqTuple != NULL)
1564  elog(ERROR, "ModifyTable should not be called during EvalPlanQual");
1565 
1566  /*
1567  * If we've already completed processing, don't try to do more. We need
1568  * this test because ExecPostprocessPlan might call us an extra time, and
1569  * our subplan's nodes aren't necessarily robust against being called
1570  * extra times.
1571  */
1572  if (node->mt_done)
1573  return NULL;
1574 
1575  /*
1576  * On first call, fire BEFORE STATEMENT triggers before proceeding.
1577  */
1578  if (node->fireBSTriggers)
1579  {
1580  fireBSTriggers(node);
1581  node->fireBSTriggers = false;
1582  }
1583 
1584  /* Preload local variables */
1585  resultRelInfo = node->resultRelInfo + node->mt_whichplan;
1586  subplanstate = node->mt_plans[node->mt_whichplan];
1587  junkfilter = resultRelInfo->ri_junkFilter;
1588 
1589  /*
1590  * es_result_relation_info must point to the currently active result
1591  * relation while we are within this ModifyTable node. Even though
1592  * ModifyTable nodes can't be nested statically, they can be nested
1593  * dynamically (since our subplan could include a reference to a modifying
1594  * CTE). So we have to save and restore the caller's value.
1595  */
1596  saved_resultRelInfo = estate->es_result_relation_info;
1597 
1598  estate->es_result_relation_info = resultRelInfo;
1599 
1600  /*
1601  * Fetch rows from subplan(s), and execute the required table modification
1602  * for each row.
1603  */
1604  for (;;)
1605  {
1606  /*
1607  * Reset the per-output-tuple exprcontext. This is needed because
1608  * triggers expect to use that context as workspace. It's a bit ugly
1609  * to do this below the top level of the plan, however. We might need
1610  * to rethink this later.
1611  */
1612  ResetPerTupleExprContext(estate);
1613 
1614  planSlot = ExecProcNode(subplanstate);
1615 
1616  if (TupIsNull(planSlot))
1617  {
1618  /* advance to next subplan if any */
1619  node->mt_whichplan++;
1620  if (node->mt_whichplan < node->mt_nplans)
1621  {
1622  resultRelInfo++;
1623  subplanstate = node->mt_plans[node->mt_whichplan];
1624  junkfilter = resultRelInfo->ri_junkFilter;
1625  estate->es_result_relation_info = resultRelInfo;
1626  EvalPlanQualSetPlan(&node->mt_epqstate, subplanstate->plan,
1627  node->mt_arowmarks[node->mt_whichplan]);
1628  if (node->mt_transition_capture != NULL)
1629  {
1630  /* Prepare to convert transition tuples from this child. */
1634  }
1635  continue;
1636  }
1637  else
1638  break;
1639  }
1640 
1641  /*
1642  * If resultRelInfo->ri_usesFdwDirectModify is true, all we need to do
1643  * here is compute the RETURNING expressions.
1644  */
1645  if (resultRelInfo->ri_usesFdwDirectModify)
1646  {
1647  Assert(resultRelInfo->ri_projectReturning);
1648 
1649  /*
1650  * A scan slot containing the data that was actually inserted,
1651  * updated or deleted has already been made available to
1652  * ExecProcessReturning by IterateDirectModify, so no need to
1653  * provide it here.
1654  */
1655  slot = ExecProcessReturning(resultRelInfo, NULL, planSlot);
1656 
1657  estate->es_result_relation_info = saved_resultRelInfo;
1658  return slot;
1659  }
1660 
1661  EvalPlanQualSetSlot(&node->mt_epqstate, planSlot);
1662  slot = planSlot;
1663 
1664  oldtuple = NULL;
1665  if (junkfilter != NULL)
1666  {
1667  /*
1668  * extract the 'ctid' or 'wholerow' junk attribute.
1669  */
1670  if (operation == CMD_UPDATE || operation == CMD_DELETE)
1671  {
1672  char relkind;
1673  Datum datum;
1674  bool isNull;
1675 
1676  relkind = resultRelInfo->ri_RelationDesc->rd_rel->relkind;
1677  if (relkind == RELKIND_RELATION || relkind == RELKIND_MATVIEW)
1678  {
1679  datum = ExecGetJunkAttribute(slot,
1680  junkfilter->jf_junkAttNo,
1681  &isNull);
1682  /* shouldn't ever get a null result... */
1683  if (isNull)
1684  elog(ERROR, "ctid is NULL");
1685 
1686  tupleid = (ItemPointer) DatumGetPointer(datum);
1687  tuple_ctid = *tupleid; /* be sure we don't free ctid!! */
1688  tupleid = &tuple_ctid;
1689  }
1690 
1691  /*
1692  * Use the wholerow attribute, when available, to reconstruct
1693  * the old relation tuple.
1694  *
1695  * Foreign table updates have a wholerow attribute when the
1696  * relation has an AFTER ROW trigger. Note that the wholerow
1697  * attribute does not carry system columns. Foreign table
1698  * triggers miss seeing those, except that we know enough here
1699  * to set t_tableOid. Quite separately from this, the FDW may
1700  * fetch its own junk attrs to identify the row.
1701  *
1702  * Other relevant relkinds, currently limited to views, always
1703  * have a wholerow attribute.
1704  */
1705  else if (AttributeNumberIsValid(junkfilter->jf_junkAttNo))
1706  {
1707  datum = ExecGetJunkAttribute(slot,
1708  junkfilter->jf_junkAttNo,
1709  &isNull);
1710  /* shouldn't ever get a null result... */
1711  if (isNull)
1712  elog(ERROR, "wholerow is NULL");
1713 
1714  oldtupdata.t_data = DatumGetHeapTupleHeader(datum);
1715  oldtupdata.t_len =
1717  ItemPointerSetInvalid(&(oldtupdata.t_self));
1718  /* Historically, view triggers see invalid t_tableOid. */
1719  oldtupdata.t_tableOid =
1720  (relkind == RELKIND_VIEW) ? InvalidOid :
1721  RelationGetRelid(resultRelInfo->ri_RelationDesc);
1722 
1723  oldtuple = &oldtupdata;
1724  }
1725  else
1726  Assert(relkind == RELKIND_FOREIGN_TABLE);
1727  }
1728 
1729  /*
1730  * apply the junkfilter if needed.
1731  */
1732  if (operation != CMD_DELETE)
1733  slot = ExecFilterJunk(junkfilter, slot);
1734  }
1735 
1736  switch (operation)
1737  {
1738  case CMD_INSERT:
1739  slot = ExecInsert(node, slot, planSlot,
1740  node->mt_arbiterindexes, node->mt_onconflict,
1741  estate, node->canSetTag);
1742  break;
1743  case CMD_UPDATE:
1744  slot = ExecUpdate(node, tupleid, oldtuple, slot, planSlot,
1745  &node->mt_epqstate, estate, node->canSetTag);
1746  break;
1747  case CMD_DELETE:
1748  slot = ExecDelete(node, tupleid, oldtuple, planSlot,
1749  &node->mt_epqstate, estate, node->canSetTag);
1750  break;
1751  default:
1752  elog(ERROR, "unknown operation");
1753  break;
1754  }
1755 
1756  /*
1757  * If we got a RETURNING result, return it to caller. We'll continue
1758  * the work on next call.
1759  */
1760  if (slot)
1761  {
1762  estate->es_result_relation_info = saved_resultRelInfo;
1763  return slot;
1764  }
1765  }
1766 
1767  /* Restore es_result_relation_info before exiting */
1768  estate->es_result_relation_info = saved_resultRelInfo;
1769 
1770  /*
1771  * We're done, but fire AFTER STATEMENT triggers before exiting.
1772  */
1773  fireASTriggers(node);
1774 
1775  node->mt_done = true;
1776 
1777  return NULL;
1778 }
AttrNumber jf_junkAttNo
Definition: execnodes.h:336
JunkFilter * ri_junkFilter
Definition: execnodes.h:396
HeapTuple * es_epqTuple
Definition: execnodes.h:503
Relation ri_RelationDesc
Definition: execnodes.h:354
TupleTableSlot * ExecProcNode(PlanState *node)
Definition: execProcnode.c:398
#define ResetPerTupleExprContext(estate)
Definition: executor.h:466
ResultRelInfo * resultRelInfo
Definition: execnodes.h:945
static TupleTableSlot * ExecUpdate(ModifyTableState *mtstate, ItemPointer tupleid, HeapTuple oldtuple, TupleTableSlot *slot, TupleTableSlot *planSlot, EPQState *epqstate, EState *estate, bool canSetTag)
static void fireBSTriggers(ModifyTableState *node)
#define RELKIND_MATVIEW
Definition: pg_class.h:165
CmdType operation
Definition: execnodes.h:939
void EvalPlanQualSetPlan(EPQState *epqstate, Plan *subplan, List *auxrowmarks)
Definition: execMain.c:2780
EState * state
Definition: execnodes.h:834
Form_pg_class rd_rel
Definition: rel.h:114
#define DatumGetHeapTupleHeader(X)
Definition: fmgr.h:259
ItemPointerData * ItemPointer
Definition: itemptr.h:49
HeapTupleHeader t_data
Definition: htup.h:67
OnConflictAction mt_onconflict
Definition: execnodes.h:951
#define ERROR
Definition: elog.h:43
PlanState ps
Definition: execnodes.h:938
TupleConversionMap * tcs_map
Definition: trigger.h:65
ItemPointerData t_self
Definition: htup.h:65
bool ri_usesFdwDirectModify
Definition: execnodes.h:384
uint32 t_len
Definition: htup.h:64
struct TransitionCaptureState * mt_transition_capture
Definition: execnodes.h:966
EPQState mt_epqstate
Definition: execnodes.h:949
ProjectionInfo * ri_projectReturning
Definition: execnodes.h:399
#define TupIsNull(slot)
Definition: tuptable.h:138
Oid t_tableOid
Definition: htup.h:66
#define RELKIND_FOREIGN_TABLE
Definition: pg_class.h:167
static TupleTableSlot * ExecProcessReturning(ResultRelInfo *resultRelInfo, TupleTableSlot *tupleSlot, TupleTableSlot *planSlot)
PlanState ** mt_plans
Definition: execnodes.h:942
#define AttributeNumberIsValid(attributeNumber)
Definition: attnum.h:34
static void fireASTriggers(ModifyTableState *node)
static TupleTableSlot * ExecDelete(ModifyTableState *mtstate, ItemPointer tupleid, HeapTuple oldtuple, TupleTableSlot *planSlot, EPQState *epqstate, EState *estate, bool canSetTag)
uintptr_t Datum
Definition: postgres.h:372
TupleTableSlot * ExecFilterJunk(JunkFilter *junkfilter, TupleTableSlot *slot)
Definition: execJunk.c:262
Plan * plan
Definition: execnodes.h:832
#define InvalidOid
Definition: postgres_ext.h:36
#define NULL
Definition: c.h:229
#define Assert(condition)
Definition: c.h:675
static TupleTableSlot * ExecInsert(ModifyTableState *mtstate, TupleTableSlot *slot, TupleTableSlot *planSlot, List *arbiterIndexes, OnConflictAction onconflict, EState *estate, bool canSetTag)
#define DatumGetPointer(X)
Definition: postgres.h:555
TupleConversionMap ** mt_transition_tupconv_maps
Definition: execnodes.h:968
List * mt_arbiterindexes
Definition: execnodes.h:952
#define ItemPointerSetInvalid(pointer)
Definition: itemptr.h:150
Datum ExecGetJunkAttribute(TupleTableSlot *slot, AttrNumber attno, bool *isNull)
Definition: execJunk.c:248
#define RELKIND_VIEW
Definition: pg_class.h:164
#define elog
Definition: elog.h:219
#define RELKIND_RELATION
Definition: pg_class.h:160
#define RelationGetRelid(relation)
Definition: rel.h:416
CmdType
Definition: nodes.h:649
List ** mt_arowmarks
Definition: execnodes.h:948
#define EvalPlanQualSetSlot(epqstate, slot)
Definition: executor.h:221
#define HeapTupleHeaderGetDatumLength(tup)
Definition: htup_details.h:439
ResultRelInfo * es_result_relation_info
Definition: execnodes.h:443
static bool ExecOnConflictUpdate ( ModifyTableState mtstate,
ResultRelInfo resultRelInfo,
ItemPointer  conflictTid,
TupleTableSlot planSlot,
TupleTableSlot excludedSlot,
EState estate,
bool  canSetTag,
TupleTableSlot **  returning 
)
static

Definition at line 1195 of file nodeModifyTable.c.

References buffer, ExprContext::ecxt_innertuple, ExprContext::ecxt_outertuple, ExprContext::ecxt_scantuple, elog, ereport, errcode(), errhint(), errmsg(), ERROR, EState::es_output_cid, ExecCheckHeapTupleVisible(), ExecProject(), ExecQual(), ExecStoreTuple(), ExecUpdate(), ExecUpdateLockMode(), ExecWithCheckOptions(), heap_lock_tuple(), HeapTupleHeaderGetXmin, HeapTupleInvisible, HeapTupleMayBeUpdated, HeapTupleSelfUpdated, HeapTupleUpdated, InstrCountFiltered1, IsolationUsesXactSnapshot, LockWaitBlock, ModifyTableState::mt_conflproj, ModifyTableState::mt_epqstate, ModifyTableState::mt_existing, NIL, NULL, ModifyTableState::ps, PlanState::ps_ExprContext, ReleaseBuffer(), ResetExprContext, ResultRelInfo::ri_onConflictSetProj, ResultRelInfo::ri_onConflictSetWhere, ResultRelInfo::ri_RelationDesc, ResultRelInfo::ri_WithCheckOptions, PlanState::state, HeapTupleData::t_data, HeapTupleData::t_self, test(), TransactionIdIsCurrentTransactionId(), and WCO_RLS_CONFLICT_CHECK.

Referenced by ExecInsert().

1203 {
1204  ExprContext *econtext = mtstate->ps.ps_ExprContext;
1205  Relation relation = resultRelInfo->ri_RelationDesc;
1206  ExprState *onConflictSetWhere = resultRelInfo->ri_onConflictSetWhere;
1207  HeapTupleData tuple;
1208  HeapUpdateFailureData hufd;
1209  LockTupleMode lockmode;
1210  HTSU_Result test;
1211  Buffer buffer;
1212 
1213  /* Determine lock mode to use */
1214  lockmode = ExecUpdateLockMode(estate, resultRelInfo);
1215 
1216  /*
1217  * Lock tuple for update. Don't follow updates when tuple cannot be
1218  * locked without doing so. A row locking conflict here means our
1219  * previous conclusion that the tuple is conclusively committed is not
1220  * true anymore.
1221  */
1222  tuple.t_self = *conflictTid;
1223  test = heap_lock_tuple(relation, &tuple, estate->es_output_cid,
1224  lockmode, LockWaitBlock, false, &buffer,
1225  &hufd);
1226  switch (test)
1227  {
1228  case HeapTupleMayBeUpdated:
1229  /* success! */
1230  break;
1231 
1232  case HeapTupleInvisible:
1233 
1234  /*
1235  * This can occur when a just inserted tuple is updated again in
1236  * the same command. E.g. because multiple rows with the same
1237  * conflicting key values are inserted.
1238  *
1239  * This is somewhat similar to the ExecUpdate()
1240  * HeapTupleSelfUpdated case. We do not want to proceed because
1241  * it would lead to the same row being updated a second time in
1242  * some unspecified order, and in contrast to plain UPDATEs
1243  * there's no historical behavior to break.
1244  *
1245  * It is the user's responsibility to prevent this situation from
1246  * occurring. These problems are why SQL-2003 similarly specifies
1247  * that for SQL MERGE, an exception must be raised in the event of
1248  * an attempt to update the same row twice.
1249  */
1251  ereport(ERROR,
1252  (errcode(ERRCODE_CARDINALITY_VIOLATION),
1253  errmsg("ON CONFLICT DO UPDATE command cannot affect row a second time"),
1254  errhint("Ensure that no rows proposed for insertion within the same command have duplicate constrained values.")));
1255 
1256  /* This shouldn't happen */
1257  elog(ERROR, "attempted to lock invisible tuple");
1258 
1259  case HeapTupleSelfUpdated:
1260 
1261  /*
1262  * This state should never be reached. As a dirty snapshot is used
1263  * to find conflicting tuples, speculative insertion wouldn't have
1264  * seen this row to conflict with.
1265  */
1266  elog(ERROR, "unexpected self-updated tuple");
1267 
1268  case HeapTupleUpdated:
1270  ereport(ERROR,
1271  (errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
1272  errmsg("could not serialize access due to concurrent update")));
1273 
1274  /*
1275  * Tell caller to try again from the very start.
1276  *
1277  * It does not make sense to use the usual EvalPlanQual() style
1278  * loop here, as the new version of the row might not conflict
1279  * anymore, or the conflicting tuple has actually been deleted.
1280  */
1281  ReleaseBuffer(buffer);
1282  return false;
1283 
1284  default:
1285  elog(ERROR, "unrecognized heap_lock_tuple status: %u", test);
1286  }
1287 
1288  /*
1289  * Success, the tuple is locked.
1290  *
1291  * Reset per-tuple memory context to free any expression evaluation
1292  * storage allocated in the previous cycle.
1293  */
1294  ResetExprContext(econtext);
1295 
1296  /*
1297  * Verify that the tuple is visible to our MVCC snapshot if the current
1298  * isolation level mandates that.
1299  *
1300  * It's not sufficient to rely on the check within ExecUpdate() as e.g.
1301  * CONFLICT ... WHERE clause may prevent us from reaching that.
1302  *
1303  * This means we only ever continue when a new command in the current
1304  * transaction could see the row, even though in READ COMMITTED mode the
1305  * tuple will not be visible according to the current statement's
1306  * snapshot. This is in line with the way UPDATE deals with newer tuple
1307  * versions.
1308  */
1309  ExecCheckHeapTupleVisible(estate, &tuple, buffer);
1310 
1311  /* Store target's existing tuple in the state's dedicated slot */
1312  ExecStoreTuple(&tuple, mtstate->mt_existing, buffer, false);
1313 
1314  /*
1315  * Make tuple and any needed join variables available to ExecQual and
1316  * ExecProject. The EXCLUDED tuple is installed in ecxt_innertuple, while
1317  * the target's existing tuple is installed in the scantuple. EXCLUDED
1318  * has been made to reference INNER_VAR in setrefs.c, but there is no
1319  * other redirection.
1320  */
1321  econtext->ecxt_scantuple = mtstate->mt_existing;
1322  econtext->ecxt_innertuple = excludedSlot;
1323  econtext->ecxt_outertuple = NULL;
1324 
1325  if (!ExecQual(onConflictSetWhere, econtext))
1326  {
1327  ReleaseBuffer(buffer);
1328  InstrCountFiltered1(&mtstate->ps, 1);
1329  return true; /* done with the tuple */
1330  }
1331 
1332  if (resultRelInfo->ri_WithCheckOptions != NIL)
1333  {
1334  /*
1335  * Check target's existing tuple against UPDATE-applicable USING
1336  * security barrier quals (if any), enforced here as RLS checks/WCOs.
1337  *
1338  * The rewriter creates UPDATE RLS checks/WCOs for UPDATE security
1339  * quals, and stores them as WCOs of "kind" WCO_RLS_CONFLICT_CHECK,
1340  * but that's almost the extent of its special handling for ON
1341  * CONFLICT DO UPDATE.
1342  *
1343  * The rewriter will also have associated UPDATE applicable straight
1344  * RLS checks/WCOs for the benefit of the ExecUpdate() call that
1345  * follows. INSERTs and UPDATEs naturally have mutually exclusive WCO
1346  * kinds, so there is no danger of spurious over-enforcement in the
1347  * INSERT or UPDATE path.
1348  */
1350  mtstate->mt_existing,
1351  mtstate->ps.state);
1352  }
1353 
1354  /* Project the new tuple version */
1355  ExecProject(resultRelInfo->ri_onConflictSetProj);
1356 
1357  /*
1358  * Note that it is possible that the target tuple has been modified in
1359  * this session, after the above heap_lock_tuple. We choose to not error
1360  * out in that case, in line with ExecUpdate's treatment of similar cases.
1361  * This can happen if an UPDATE is triggered from within ExecQual(),
1362  * ExecWithCheckOptions() or ExecProject() above, e.g. by selecting from a
1363  * wCTE in the ON CONFLICT's SET.
1364  */
1365 
1366  /* Execute UPDATE with projection */
1367  *returning = ExecUpdate(mtstate, &tuple.t_self, NULL,
1368  mtstate->mt_conflproj, planSlot,
1369  &mtstate->mt_epqstate, mtstate->ps.state,
1370  canSetTag);
1371 
1372  ReleaseBuffer(buffer);
1373  return true;
1374 }
#define NIL
Definition: pg_list.h:69
TupleTableSlot * ExecStoreTuple(HeapTuple tuple, TupleTableSlot *slot, Buffer buffer, bool shouldFree)
Definition: execTuples.c:320
Relation ri_RelationDesc
Definition: execnodes.h:354
ExprState * ri_onConflictSetWhere
Definition: execnodes.h:405
int errhint(const char *fmt,...)
Definition: elog.c:987
void ExecWithCheckOptions(WCOKind kind, ResultRelInfo *resultRelInfo, TupleTableSlot *slot, EState *estate)
Definition: execMain.c:2042
CommandId es_output_cid
Definition: execnodes.h:438
ProjectionInfo * ri_onConflictSetProj
Definition: execnodes.h:402
static void test(void)
bool TransactionIdIsCurrentTransactionId(TransactionId xid)
Definition: xact.c:773
HTSU_Result heap_lock_tuple(Relation relation, HeapTuple tuple, CommandId cid, LockTupleMode mode, LockWaitPolicy wait_policy, bool follow_updates, Buffer *buffer, HeapUpdateFailureData *hufd)
Definition: heapam.c:4540
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:862
TupleTableSlot * mt_conflproj
Definition: execnodes.h:956
#define IsolationUsesXactSnapshot()
Definition: xact.h:43
int errcode(int sqlerrcode)
Definition: elog.c:575
void ReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3309
EState * state
Definition: execnodes.h:834
static bool ExecQual(ExprState *state, ExprContext *econtext)
Definition: executor.h:347
TupleTableSlot * mt_existing
Definition: execnodes.h:954
HeapTupleHeader t_data
Definition: htup.h:67
LockTupleMode
Definition: heapam.h:38
#define ERROR
Definition: elog.h:43
PlanState ps
Definition: execnodes.h:938
ItemPointerData t_self
Definition: htup.h:65
static void ExecCheckHeapTupleVisible(EState *estate, HeapTuple tuple, Buffer buffer)
EPQState mt_epqstate
Definition: execnodes.h:949
TupleTableSlot * ecxt_innertuple
Definition: execnodes.h:198
HTSU_Result
Definition: snapshot.h:119
#define InstrCountFiltered1(node, delta)
Definition: execnodes.h:877
#define ereport(elevel, rest)
Definition: elog.h:122
List * ri_WithCheckOptions
Definition: execnodes.h:387
TupleTableSlot * ecxt_outertuple
Definition: execnodes.h:199
#define NULL
Definition: c.h:229
LockTupleMode ExecUpdateLockMode(EState *estate, ResultRelInfo *relinfo)
Definition: execMain.c:2324
WalTimeSample buffer[LAG_TRACKER_BUFFER_SIZE]
Definition: walsender.c:214
#define HeapTupleHeaderGetXmin(tup)
Definition: htup_details.h:307
TupleTableSlot * ecxt_scantuple
Definition: execnodes.h:197
int errmsg(const char *fmt,...)
Definition: elog.c:797
#define elog
Definition: elog.h:219
int Buffer
Definition: buf.h:23
static TupleTableSlot * ExecProject(ProjectionInfo *projInfo)
Definition: executor.h:310
#define ResetExprContext(econtext)
Definition: executor.h:451
static TupleTableSlot* ExecProcessReturning ( ResultRelInfo resultRelInfo,
TupleTableSlot tupleSlot,
TupleTableSlot planSlot 
)
static

Definition at line 148 of file nodeModifyTable.c.

References Assert, ExprContext::ecxt_outertuple, ExprContext::ecxt_scantuple, ExecMaterializeSlot(), ExecProject(), ProjectionInfo::pi_exprContext, RelationGetRelid, ResetExprContext, ResultRelInfo::ri_projectReturning, ResultRelInfo::ri_RelationDesc, HeapTupleData::t_tableOid, and TupIsNull.

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

151 {
152  ProjectionInfo *projectReturning = resultRelInfo->ri_projectReturning;
153  ExprContext *econtext = projectReturning->pi_exprContext;
154 
155  /*
156  * Reset per-tuple memory context to free any expression evaluation
157  * storage allocated in the previous cycle.
158  */
159  ResetExprContext(econtext);
160 
161  /* Make tuple and any needed join variables available to ExecProject */
162  if (tupleSlot)
163  econtext->ecxt_scantuple = tupleSlot;
164  else
165  {
166  HeapTuple tuple;
167 
168  /*
169  * RETURNING expressions might reference the tableoid column, so
170  * initialize t_tableOid before evaluating them.
171  */
172  Assert(!TupIsNull(econtext->ecxt_scantuple));
173  tuple = ExecMaterializeSlot(econtext->ecxt_scantuple);
174  tuple->t_tableOid = RelationGetRelid(resultRelInfo->ri_RelationDesc);
175  }
176  econtext->ecxt_outertuple = planSlot;
177 
178  /* Compute the RETURNING expressions */
179  return ExecProject(projectReturning);
180 }
Relation ri_RelationDesc
Definition: execnodes.h:354
ProjectionInfo * ri_projectReturning
Definition: execnodes.h:399
#define TupIsNull(slot)
Definition: tuptable.h:138
Oid t_tableOid
Definition: htup.h:66
TupleTableSlot * ecxt_outertuple
Definition: execnodes.h:199
#define Assert(condition)
Definition: c.h:675
TupleTableSlot * ecxt_scantuple
Definition: execnodes.h:197
HeapTuple ExecMaterializeSlot(TupleTableSlot *slot)
Definition: execTuples.c:725
ExprContext * pi_exprContext
Definition: execnodes.h:298
#define RelationGetRelid(relation)
Definition: rel.h:416
static TupleTableSlot * ExecProject(ProjectionInfo *projInfo)
Definition: executor.h:310
#define ResetExprContext(econtext)
Definition: executor.h:451
void ExecReScanModifyTable ( ModifyTableState node)

Definition at line 2380 of file nodeModifyTable.c.

References elog, and ERROR.

Referenced by ExecReScan().

2381 {
2382  /*
2383  * Currently, we don't need to support rescan on ModifyTable nodes. The
2384  * semantics of that would be a bit debatable anyway.
2385  */
2386  elog(ERROR, "ExecReScanModifyTable is not implemented");
2387 }
#define ERROR
Definition: elog.h:43
#define elog
Definition: elog.h:219
static void ExecSetupTransitionCaptureState ( ModifyTableState mtstate,
EState estate 
)
static

Definition at line 1469 of file nodeModifyTable.c.

References convert_tuples_by_name(), getASTriggerResultRelInfo(), gettext_noop, i, MakeTransitionCaptureState(), ModifyTableState::mt_nplans, ModifyTableState::mt_num_partitions, ModifyTableState::mt_partition_dispatch_info, ModifyTableState::mt_partitions, ModifyTableState::mt_transition_capture, ModifyTableState::mt_transition_tupconv_maps, NULL, palloc0(), RelationGetDescr, ModifyTableState::resultRelInfo, ResultRelInfo::ri_RelationDesc, ResultRelInfo::ri_TrigDesc, and TransitionCaptureState::tcs_map.

Referenced by ExecInitModifyTable().

1470 {
1471  ResultRelInfo *targetRelInfo = getASTriggerResultRelInfo(mtstate);
1472  int i;
1473 
1474  /* Check for transition tables on the directly targeted relation. */
1475  mtstate->mt_transition_capture =
1476  MakeTransitionCaptureState(targetRelInfo->ri_TrigDesc);
1477 
1478  /*
1479  * If we found that we need to collect transition tuples then we may also
1480  * need tuple conversion maps for any children that have TupleDescs that
1481  * aren't compatible with the tuplestores.
1482  */
1483  if (mtstate->mt_transition_capture != NULL)
1484  {
1485  ResultRelInfo *resultRelInfos;
1486  int numResultRelInfos;
1487 
1488  /* Find the set of partitions so that we can find their TupleDescs. */
1489  if (mtstate->mt_partition_dispatch_info != NULL)
1490  {
1491  /*
1492  * For INSERT via partitioned table, so we need TupleDescs based
1493  * on the partition routing table.
1494  */
1495  resultRelInfos = mtstate->mt_partitions;
1496  numResultRelInfos = mtstate->mt_num_partitions;
1497  }
1498  else
1499  {
1500  /* Otherwise we need the ResultRelInfo for each subplan. */
1501  resultRelInfos = mtstate->resultRelInfo;
1502  numResultRelInfos = mtstate->mt_nplans;
1503  }
1504 
1505  /*
1506  * Build array of conversion maps from each child's TupleDesc to the
1507  * one used in the tuplestore. The map pointers may be NULL when no
1508  * conversion is necessary, which is hopefully a common case for
1509  * partitions.
1510  */
1512  palloc0(sizeof(TupleConversionMap *) * numResultRelInfos);
1513  for (i = 0; i < numResultRelInfos; ++i)
1514  {
1515  mtstate->mt_transition_tupconv_maps[i] =
1516  convert_tuples_by_name(RelationGetDescr(resultRelInfos[i].ri_RelationDesc),
1517  RelationGetDescr(targetRelInfo->ri_RelationDesc),
1518  gettext_noop("could not convert row type"));
1519  }
1520 
1521  /*
1522  * Install the conversion map for the first plan for UPDATE and DELETE
1523  * operations. It will be advanced each time we switch to the next
1524  * plan. (INSERT operations set it every time.)
1525  */
1526  mtstate->mt_transition_capture->tcs_map =
1527  mtstate->mt_transition_tupconv_maps[0];
1528  }
1529 }
static ResultRelInfo * getASTriggerResultRelInfo(ModifyTableState *node)
Relation ri_RelationDesc
Definition: execnodes.h:354
TransitionCaptureState * MakeTransitionCaptureState(TriggerDesc *trigdesc)
Definition: trigger.c:2104
ResultRelInfo * mt_partitions
Definition: execnodes.h:962
#define RelationGetDescr(relation)
Definition: rel.h:428
ResultRelInfo * resultRelInfo
Definition: execnodes.h:945
#define gettext_noop(x)
Definition: c.h:139
TupleConversionMap * tcs_map
Definition: trigger.h:65
struct TransitionCaptureState * mt_transition_capture
Definition: execnodes.h:966
TriggerDesc * ri_TrigDesc
Definition: execnodes.h:366
TupleConversionMap * convert_tuples_by_name(TupleDesc indesc, TupleDesc outdesc, const char *msg)
Definition: tupconvert.c:205
void * palloc0(Size size)
Definition: mcxt.c:878
#define NULL
Definition: c.h:229
TupleConversionMap ** mt_transition_tupconv_maps
Definition: execnodes.h:968
int i
struct PartitionDispatchData ** mt_partition_dispatch_info
Definition: execnodes.h:957
static TupleTableSlot* ExecUpdate ( ModifyTableState mtstate,
ItemPointer  tupleid,
HeapTuple  oldtuple,
TupleTableSlot slot,
TupleTableSlot planSlot,
EPQState epqstate,
EState estate,
bool  canSetTag 
)
static

Definition at line 930 of file nodeModifyTable.c.

References HeapUpdateFailureData::cmax, tupleDesc::constr, HeapUpdateFailureData::ctid, elog, ereport, errcode(), errhint(), errmsg(), ERROR, EState::es_crosscheck_snapshot, EState::es_output_cid, EState::es_processed, EState::es_result_relation_info, EvalPlanQual(), ExecARUpdateTriggers(), ExecBRUpdateTriggers(), ExecConstraints(), ExecFilterJunk(), FdwRoutine::ExecForeignUpdate, ExecInsertIndexTuples(), ExecIRUpdateTriggers(), ExecMaterializeSlot(), ExecProcessReturning(), ExecWithCheckOptions(), heap_update(), HeapTupleIsHeapOnly, HeapTupleMayBeUpdated, HeapTupleSelfUpdated, HeapTupleUpdated, IsBootstrapProcessingMode, IsolationUsesXactSnapshot, ItemPointerEquals(), list_free(), ModifyTableState::mt_transition_capture, NIL, NULL, RelationData::rd_att, RelationGetRelid, result, 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, HeapTupleData::t_self, HeapTupleData::t_tableOid, TriggerDesc::trig_update_before_row, TriggerDesc::trig_update_instead_row, TupIsNull, WCO_RLS_UPDATE_CHECK, WCO_VIEW_CHECK, and HeapUpdateFailureData::xmax.

Referenced by ExecModifyTable(), and ExecOnConflictUpdate().

938 {
939  HeapTuple tuple;
940  ResultRelInfo *resultRelInfo;
941  Relation resultRelationDesc;
944  List *recheckIndexes = NIL;
945 
946  /*
947  * abort the operation if not running transactions
948  */
950  elog(ERROR, "cannot UPDATE during bootstrap");
951 
952  /*
953  * get the heap tuple out of the tuple table slot, making sure we have a
954  * writable copy
955  */
956  tuple = ExecMaterializeSlot(slot);
957 
958  /*
959  * get information on the (current) result relation
960  */
961  resultRelInfo = estate->es_result_relation_info;
962  resultRelationDesc = resultRelInfo->ri_RelationDesc;
963 
964  /* BEFORE ROW UPDATE Triggers */
965  if (resultRelInfo->ri_TrigDesc &&
966  resultRelInfo->ri_TrigDesc->trig_update_before_row)
967  {
968  slot = ExecBRUpdateTriggers(estate, epqstate, resultRelInfo,
969  tupleid, oldtuple, slot);
970 
971  if (slot == NULL) /* "do nothing" */
972  return NULL;
973 
974  /* trigger might have changed tuple */
975  tuple = ExecMaterializeSlot(slot);
976  }
977 
978  /* INSTEAD OF ROW UPDATE Triggers */
979  if (resultRelInfo->ri_TrigDesc &&
980  resultRelInfo->ri_TrigDesc->trig_update_instead_row)
981  {
982  slot = ExecIRUpdateTriggers(estate, resultRelInfo,
983  oldtuple, slot);
984 
985  if (slot == NULL) /* "do nothing" */
986  return NULL;
987 
988  /* trigger might have changed tuple */
989  tuple = ExecMaterializeSlot(slot);
990  }
991  else if (resultRelInfo->ri_FdwRoutine)
992  {
993  /*
994  * update in foreign table: let the FDW do it
995  */
996  slot = resultRelInfo->ri_FdwRoutine->ExecForeignUpdate(estate,
997  resultRelInfo,
998  slot,
999  planSlot);
1000 
1001  if (slot == NULL) /* "do nothing" */
1002  return NULL;
1003 
1004  /* FDW might have changed tuple */
1005  tuple = ExecMaterializeSlot(slot);
1006 
1007  /*
1008  * AFTER ROW Triggers or RETURNING expressions might reference the
1009  * tableoid column, so initialize t_tableOid before evaluating them.
1010  */
1011  tuple->t_tableOid = RelationGetRelid(resultRelationDesc);
1012  }
1013  else
1014  {
1015  LockTupleMode lockmode;
1016 
1017  /*
1018  * Constraints might reference the tableoid column, so initialize
1019  * t_tableOid before evaluating them.
1020  */
1021  tuple->t_tableOid = RelationGetRelid(resultRelationDesc);
1022 
1023  /*
1024  * Check any RLS UPDATE WITH CHECK policies
1025  *
1026  * If we generate a new candidate tuple after EvalPlanQual testing, we
1027  * must loop back here and recheck any RLS policies and constraints.
1028  * (We don't need to redo triggers, however. If there are any BEFORE
1029  * triggers then trigger.c will have done heap_lock_tuple to lock the
1030  * correct tuple, so there's no need to do them again.)
1031  *
1032  * ExecWithCheckOptions() will skip any WCOs which are not of the kind
1033  * we are looking for at this point.
1034  */
1035 lreplace:;
1036  if (resultRelInfo->ri_WithCheckOptions != NIL)
1038  resultRelInfo, slot, estate);
1039 
1040  /*
1041  * Check the constraints of the tuple. Note that we pass the same
1042  * slot for the orig_slot argument, because unlike ExecInsert(), no
1043  * tuple-routing is performed here, hence the slot remains unchanged.
1044  */
1045  if (resultRelationDesc->rd_att->constr || resultRelInfo->ri_PartitionCheck)
1046  ExecConstraints(resultRelInfo, slot, estate);
1047 
1048  /*
1049  * replace the heap tuple
1050  *
1051  * Note: if es_crosscheck_snapshot isn't InvalidSnapshot, we check
1052  * that the row to be updated is visible to that snapshot, and throw a
1053  * can't-serialize error if not. This is a special-case behavior
1054  * needed for referential integrity updates in transaction-snapshot
1055  * mode transactions.
1056  */
1057  result = heap_update(resultRelationDesc, tupleid, tuple,
1058  estate->es_output_cid,
1059  estate->es_crosscheck_snapshot,
1060  true /* wait for commit */ ,
1061  &hufd, &lockmode);
1062  switch (result)
1063  {
1064  case HeapTupleSelfUpdated:
1065 
1066  /*
1067  * The target tuple was already updated or deleted by the
1068  * current command, or by a later command in the current
1069  * transaction. The former case is possible in a join UPDATE
1070  * where multiple tuples join to the same target tuple. This
1071  * is pretty questionable, but Postgres has always allowed it:
1072  * we just execute the first update action and ignore
1073  * additional update attempts.
1074  *
1075  * The latter case arises if the tuple is modified by a
1076  * command in a BEFORE trigger, or perhaps by a command in a
1077  * volatile function used in the query. In such situations we
1078  * should not ignore the update, but it is equally unsafe to
1079  * proceed. We don't want to discard the original UPDATE
1080  * while keeping the triggered actions based on it; and we
1081  * have no principled way to merge this update with the
1082  * previous ones. So throwing an error is the only safe
1083  * course.
1084  *
1085  * If a trigger actually intends this type of interaction, it
1086  * can re-execute the UPDATE (assuming it can figure out how)
1087  * and then return NULL to cancel the outer update.
1088  */
1089  if (hufd.cmax != estate->es_output_cid)
1090  ereport(ERROR,
1091  (errcode(ERRCODE_TRIGGERED_DATA_CHANGE_VIOLATION),
1092  errmsg("tuple to be updated was already modified by an operation triggered by the current command"),
1093  errhint("Consider using an AFTER trigger instead of a BEFORE trigger to propagate changes to other rows.")));
1094 
1095  /* Else, already updated by self; nothing to do */
1096  return NULL;
1097 
1098  case HeapTupleMayBeUpdated:
1099  break;
1100 
1101  case HeapTupleUpdated:
1103  ereport(ERROR,
1104  (errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
1105  errmsg("could not serialize access due to concurrent update")));
1106  if (!ItemPointerEquals(tupleid, &hufd.ctid))
1107  {
1108  TupleTableSlot *epqslot;
1109 
1110  epqslot = EvalPlanQual(estate,
1111  epqstate,
1112  resultRelationDesc,
1113  resultRelInfo->ri_RangeTableIndex,
1114  lockmode,
1115  &hufd.ctid,
1116  hufd.xmax);
1117  if (!TupIsNull(epqslot))
1118  {
1119  *tupleid = hufd.ctid;
1120  slot = ExecFilterJunk(resultRelInfo->ri_junkFilter, epqslot);
1121  tuple = ExecMaterializeSlot(slot);
1122  goto lreplace;
1123  }
1124  }
1125  /* tuple already deleted; nothing to do */
1126  return NULL;
1127 
1128  default:
1129  elog(ERROR, "unrecognized heap_update status: %u", result);
1130  return NULL;
1131  }
1132 
1133  /*
1134  * Note: instead of having to update the old index tuples associated
1135  * with the heap tuple, all we do is form and insert new index tuples.
1136  * This is because UPDATEs are actually DELETEs and INSERTs, and index
1137  * tuple deletion is done later by VACUUM (see notes in ExecDelete).
1138  * All we do here is insert new index tuples. -cim 9/27/89
1139  */
1140 
1141  /*
1142  * insert index entries for tuple
1143  *
1144  * Note: heap_update returns the tid (location) of the new tuple in
1145  * the t_self field.
1146  *
1147  * If it's a HOT update, we mustn't insert new index entries.
1148  */
1149  if (resultRelInfo->ri_NumIndices > 0 && !HeapTupleIsHeapOnly(tuple))
1150  recheckIndexes = ExecInsertIndexTuples(slot, &(tuple->t_self),
1151  estate, false, NULL, NIL);
1152  }
1153 
1154  if (canSetTag)
1155  (estate->es_processed)++;
1156 
1157  /* AFTER ROW UPDATE Triggers */
1158  ExecARUpdateTriggers(estate, resultRelInfo, tupleid, oldtuple, tuple,
1159  recheckIndexes,
1160  mtstate->mt_transition_capture);
1161 
1162  list_free(recheckIndexes);
1163 
1164  /*
1165  * Check any WITH CHECK OPTION constraints from parent views. We are
1166  * required to do this after testing all constraints and uniqueness
1167  * violations per the SQL spec, so we do it after actually updating the
1168  * record in the heap and all indexes.
1169  *
1170  * ExecWithCheckOptions() will skip any WCOs which are not of the kind we
1171  * are looking for at this point.
1172  */
1173  if (resultRelInfo->ri_WithCheckOptions != NIL)
1174  ExecWithCheckOptions(WCO_VIEW_CHECK, resultRelInfo, slot, estate);
1175 
1176  /* Process RETURNING if present */
1177  if (resultRelInfo->ri_projectReturning)
1178  return ExecProcessReturning(resultRelInfo, slot, planSlot);
1179 
1180  return NULL;
1181 }
int ri_NumIndices
Definition: execnodes.h:357
#define NIL
Definition: pg_list.h:69
JunkFilter * ri_junkFilter
Definition: execnodes.h:396
Relation ri_RelationDesc
Definition: execnodes.h:354
int errhint(const char *fmt,...)
Definition: elog.c:987
void ExecWithCheckOptions(WCOKind kind, ResultRelInfo *resultRelInfo, TupleTableSlot *slot, EState *estate)
Definition: execMain.c:2042
CommandId es_output_cid
Definition: execnodes.h:438
List * ExecInsertIndexTuples(TupleTableSlot *slot, ItemPointer tupleid, EState *estate, bool noDupErr, bool *specConflict, List *arbiterIndexes)
Definition: execIndexing.c:271
TupleTableSlot * EvalPlanQual(EState *estate, EPQState *epqstate, Relation relation, Index rti, int lockmode, ItemPointer tid, TransactionId priorXmax)
Definition: execMain.c:2445
TupleTableSlot * ExecBRUpdateTriggers(EState *estate, EPQState *epqstate, ResultRelInfo *relinfo, ItemPointer tupleid, HeapTuple fdw_trigtuple, TupleTableSlot *slot)
Definition: trigger.c:2773
void ExecConstraints(ResultRelInfo *resultRelInfo, TupleTableSlot *slot, EState *estate)
Definition: execMain.c:1913
#define IsolationUsesXactSnapshot()
Definition: xact.h:43
Snapshot es_crosscheck_snapshot
Definition: execnodes.h:430
int errcode(int sqlerrcode)
Definition: elog.c:575
return result
Definition: formatting.c:1633
Index ri_RangeTableIndex
Definition: execnodes.h:351
TupleTableSlot * ExecIRUpdateTriggers(EState *estate, ResultRelInfo *relinfo, HeapTuple trigtuple, TupleTableSlot *slot)
Definition: trigger.c:2927
LockTupleMode
Definition: heapam.h:38
#define ERROR
Definition: elog.h:43
ItemPointerData t_self
Definition: htup.h:65
struct TransitionCaptureState * mt_transition_capture
Definition: execnodes.h:966
CommandId cmax
Definition: heapam.h:72
bool trig_update_before_row
Definition: reltrigger.h:60
HTSU_Result
Definition: snapshot.h:119
ProjectionInfo * ri_projectReturning
Definition: execnodes.h:399
#define TupIsNull(slot)
Definition: tuptable.h:138
struct FdwRoutine * ri_FdwRoutine
Definition: execnodes.h:378
Oid t_tableOid
Definition: htup.h:66
#define ereport(elevel, rest)
Definition: elog.h:122
TriggerDesc * ri_TrigDesc
Definition: execnodes.h:366
void ExecARUpdateTriggers(EState *estate, ResultRelInfo *relinfo, ItemPointer tupleid, HeapTuple fdw_trigtuple, HeapTuple newtuple, List *recheckIndexes, TransitionCaptureState *transition_capture)
Definition: trigger.c:2890
bool trig_update_instead_row
Definition: reltrigger.h:62
static TupleTableSlot * ExecProcessReturning(ResultRelInfo *resultRelInfo, TupleTableSlot *tupleSlot, TupleTableSlot *planSlot)
TransactionId xmax
Definition: heapam.h:71
TupleTableSlot * ExecFilterJunk(JunkFilter *junkfilter, TupleTableSlot *slot)
Definition: execJunk.c:262
List * ri_WithCheckOptions
Definition: execnodes.h:387
List * ri_PartitionCheck
Definition: execnodes.h:408
TupleDesc rd_att
Definition: rel.h:115
HTSU_Result heap_update(Relation relation, ItemPointer otid, HeapTuple newtup, CommandId cid, Snapshot crosscheck, bool wait, HeapUpdateFailureData *hufd, LockTupleMode *lockmode)
Definition: heapam.c:3462
ExecForeignUpdate_function ExecForeignUpdate
Definition: fdwapi.h:198
#define NULL
Definition: c.h:229
#define HeapTupleIsHeapOnly(tuple)
Definition: htup_details.h:686
uint64 es_processed
Definition: execnodes.h:474
TupleConstr * constr
Definition: tupdesc.h:76
HeapTuple ExecMaterializeSlot(TupleTableSlot *slot)
Definition: execTuples.c:725
bool ItemPointerEquals(ItemPointer pointer1, ItemPointer pointer2)
Definition: itemptr.c:29
#define IsBootstrapProcessingMode()
Definition: miscadmin.h:368
int errmsg(const char *fmt,...)
Definition: elog.c:797
void list_free(List *list)
Definition: list.c:1133
ItemPointerData ctid
Definition: heapam.h:70
#define elog
Definition: elog.h:219
Definition: pg_list.h:45
#define RelationGetRelid(relation)
Definition: rel.h:416
ResultRelInfo * es_result_relation_info
Definition: execnodes.h:443
static void fireASTriggers ( ModifyTableState node)
static

Definition at line 1436 of file nodeModifyTable.c.

References CMD_DELETE, CMD_INSERT, CMD_UPDATE, elog, ERROR, ExecASDeleteTriggers(), ExecASInsertTriggers(), ExecASUpdateTriggers(), getASTriggerResultRelInfo(), ModifyTableState::mt_onconflict, ModifyTableState::mt_transition_capture, ONCONFLICT_UPDATE, ModifyTableState::operation, ModifyTableState::ps, and PlanState::state.

Referenced by ExecModifyTable().

1437 {
1438  ResultRelInfo *resultRelInfo = getASTriggerResultRelInfo(node);
1439 
1440  switch (node->operation)
1441  {
1442  case CMD_INSERT:
1443  if (node->mt_onconflict == ONCONFLICT_UPDATE)
1445  resultRelInfo,
1446  node->mt_transition_capture);
1447  ExecASInsertTriggers(node->ps.state, resultRelInfo,
1448  node->mt_transition_capture);
1449  break;
1450  case CMD_UPDATE:
1451  ExecASUpdateTriggers(node->ps.state, resultRelInfo,
1452  node->mt_transition_capture);
1453  break;
1454  case CMD_DELETE:
1455  ExecASDeleteTriggers(node->ps.state, resultRelInfo,
1456  node->mt_transition_capture);
1457  break;
1458  default:
1459  elog(ERROR, "unknown operation");
1460  break;
1461  }
1462 }
static ResultRelInfo * getASTriggerResultRelInfo(ModifyTableState *node)
CmdType operation
Definition: execnodes.h:939
EState * state
Definition: execnodes.h:834
void ExecASDeleteTriggers(EState *estate, ResultRelInfo *relinfo, TransitionCaptureState *transition_capture)
Definition: trigger.c:2546
OnConflictAction mt_onconflict
Definition: execnodes.h:951
#define ERROR
Definition: elog.h:43
PlanState ps
Definition: execnodes.h:938
struct TransitionCaptureState * mt_transition_capture
Definition: execnodes.h:966
void ExecASUpdateTriggers(EState *estate, ResultRelInfo *relinfo, TransitionCaptureState *transition_capture)
Definition: trigger.c:2760
void ExecASInsertTriggers(EState *estate, ResultRelInfo *relinfo, TransitionCaptureState *transition_capture)
Definition: trigger.c:2336
#define elog
Definition: elog.h:219
static void fireBSTriggers ( ModifyTableState node)
static

Definition at line 1381 of file nodeModifyTable.c.

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

Referenced by ExecModifyTable().

1382 {
1383  ResultRelInfo *resultRelInfo = node->resultRelInfo;
1384 
1385  /*
1386  * If the node modifies a partitioned table, we must fire its triggers.
1387  * Note that in that case, node->resultRelInfo points to the first leaf
1388  * partition, not the root table.
1389  */
1390  if (node->rootResultRelInfo != NULL)
1391  resultRelInfo = node->rootResultRelInfo;
1392 
1393  switch (node->operation)
1394  {
1395  case CMD_INSERT:
1396  ExecBSInsertTriggers(node->ps.state, resultRelInfo);
1397  if (node->mt_onconflict == ONCONFLICT_UPDATE)
1399  resultRelInfo);
1400  break;
1401  case CMD_UPDATE:
1402  ExecBSUpdateTriggers(node->ps.state, resultRelInfo);
1403  break;
1404  case CMD_DELETE:
1405  ExecBSDeleteTriggers(node->ps.state, resultRelInfo);
1406  break;
1407  default:
1408  elog(ERROR, "unknown operation");
1409  break;
1410  }
1411 }
void ExecBSDeleteTriggers(EState *estate, ResultRelInfo *relinfo)
Definition: trigger.c:2494
ResultRelInfo * resultRelInfo
Definition: execnodes.h:945
CmdType operation
Definition: execnodes.h:939
ResultRelInfo * rootResultRelInfo
Definition: execnodes.h:946
EState * state
Definition: execnodes.h:834
OnConflictAction mt_onconflict
Definition: execnodes.h:951
#define ERROR
Definition: elog.h:43
PlanState ps
Definition: execnodes.h:938
void ExecBSInsertTriggers(EState *estate, ResultRelInfo *relinfo)
Definition: trigger.c:2284
#define NULL
Definition: c.h:229
void ExecBSUpdateTriggers(EState *estate, ResultRelInfo *relinfo)
Definition: trigger.c:2705
#define elog
Definition: elog.h:219
static ResultRelInfo* getASTriggerResultRelInfo ( ModifyTableState node)
static

Definition at line 1419 of file nodeModifyTable.c.

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

Referenced by ExecSetupTransitionCaptureState(), and fireASTriggers().

1420 {
1421  /*
1422  * If the node modifies a partitioned table, we must fire its triggers.
1423  * Note that in that case, node->resultRelInfo points to the first leaf
1424  * partition, not the root table.
1425  */
1426  if (node->rootResultRelInfo != NULL)
1427  return node->rootResultRelInfo;
1428  else
1429  return node->resultRelInfo;
1430 }
ResultRelInfo * resultRelInfo
Definition: execnodes.h:945
ResultRelInfo * rootResultRelInfo
Definition: execnodes.h:946
#define NULL
Definition: c.h:229