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 (ItemPointer tupleid, HeapTuple oldtuple, TupleTableSlot *planSlot, EPQState *epqstate, EState *estate, bool canSetTag)
 
static TupleTableSlotExecUpdate (ItemPointer tupleid, HeapTuple oldtuple, TupleTableSlot *slot, TupleTableSlot *planSlot, EPQState *epqstate, EState *estate, bool canSetTag)
 
static void fireBSTriggers (ModifyTableState *node)
 
static void fireASTriggers (ModifyTableState *node)
 
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:409
#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:207
#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:429
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:1374
#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:1367
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:374
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:207
#define elog
Definition: elog.h:219
int Buffer
Definition: buf.h:23
static TupleTableSlot* ExecDelete ( ItemPointer  tupleid,
HeapTuple  oldtuple,
TupleTableSlot planSlot,
EPQState epqstate,
EState estate,
bool  canSetTag 
)
static

Definition at line 622 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, 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().

628 {
629  ResultRelInfo *resultRelInfo;
630  Relation resultRelationDesc;
633  TupleTableSlot *slot = NULL;
634 
635  /*
636  * get information on the (current) result relation
637  */
638  resultRelInfo = estate->es_result_relation_info;
639  resultRelationDesc = resultRelInfo->ri_RelationDesc;
640 
641  /* BEFORE ROW DELETE Triggers */
642  if (resultRelInfo->ri_TrigDesc &&
643  resultRelInfo->ri_TrigDesc->trig_delete_before_row)
644  {
645  bool dodelete;
646 
647  dodelete = ExecBRDeleteTriggers(estate, epqstate, resultRelInfo,
648  tupleid, oldtuple);
649 
650  if (!dodelete) /* "do nothing" */
651  return NULL;
652  }
653 
654  /* INSTEAD OF ROW DELETE Triggers */
655  if (resultRelInfo->ri_TrigDesc &&
656  resultRelInfo->ri_TrigDesc->trig_delete_instead_row)
657  {
658  bool dodelete;
659 
660  Assert(oldtuple != NULL);
661  dodelete = ExecIRDeleteTriggers(estate, resultRelInfo, oldtuple);
662 
663  if (!dodelete) /* "do nothing" */
664  return NULL;
665  }
666  else if (resultRelInfo->ri_FdwRoutine)
667  {
668  HeapTuple tuple;
669 
670  /*
671  * delete from foreign table: let the FDW do it
672  *
673  * We offer the trigger tuple slot as a place to store RETURNING data,
674  * although the FDW can return some other slot if it wants. Set up
675  * the slot's tupdesc so the FDW doesn't need to do that for itself.
676  */
677  slot = estate->es_trig_tuple_slot;
678  if (slot->tts_tupleDescriptor != RelationGetDescr(resultRelationDesc))
679  ExecSetSlotDescriptor(slot, RelationGetDescr(resultRelationDesc));
680 
681  slot = resultRelInfo->ri_FdwRoutine->ExecForeignDelete(estate,
682  resultRelInfo,
683  slot,
684  planSlot);
685 
686  if (slot == NULL) /* "do nothing" */
687  return NULL;
688 
689  /*
690  * RETURNING expressions might reference the tableoid column, so
691  * initialize t_tableOid before evaluating them.
692  */
693  if (slot->tts_isempty)
694  ExecStoreAllNullTuple(slot);
695  tuple = ExecMaterializeSlot(slot);
696  tuple->t_tableOid = RelationGetRelid(resultRelationDesc);
697  }
698  else
699  {
700  /*
701  * delete the tuple
702  *
703  * Note: if es_crosscheck_snapshot isn't InvalidSnapshot, we check
704  * that the row to be deleted is visible to that snapshot, and throw a
705  * can't-serialize error if not. This is a special-case behavior
706  * needed for referential integrity updates in transaction-snapshot
707  * mode transactions.
708  */
709 ldelete:;
710  result = heap_delete(resultRelationDesc, tupleid,
711  estate->es_output_cid,
712  estate->es_crosscheck_snapshot,
713  true /* wait for commit */ ,
714  &hufd);
715  switch (result)
716  {
718 
719  /*
720  * The target tuple was already updated or deleted by the
721  * current command, or by a later command in the current
722  * transaction. The former case is possible in a join DELETE
723  * where multiple tuples join to the same target tuple. This
724  * is somewhat questionable, but Postgres has always allowed
725  * it: we just ignore additional deletion attempts.
726  *
727  * The latter case arises if the tuple is modified by a
728  * command in a BEFORE trigger, or perhaps by a command in a
729  * volatile function used in the query. In such situations we
730  * should not ignore the deletion, but it is equally unsafe to
731  * proceed. We don't want to discard the original DELETE
732  * while keeping the triggered actions based on its deletion;
733  * and it would be no better to allow the original DELETE
734  * while discarding updates that it triggered. The row update
735  * carries some information that might be important according
736  * to business rules; so throwing an error is the only safe
737  * course.
738  *
739  * If a trigger actually intends this type of interaction, it
740  * can re-execute the DELETE and then return NULL to cancel
741  * the outer delete.
742  */
743  if (hufd.cmax != estate->es_output_cid)
744  ereport(ERROR,
745  (errcode(ERRCODE_TRIGGERED_DATA_CHANGE_VIOLATION),
746  errmsg("tuple to be updated was already modified by an operation triggered by the current command"),
747  errhint("Consider using an AFTER trigger instead of a BEFORE trigger to propagate changes to other rows.")));
748 
749  /* Else, already deleted by self; nothing to do */
750  return NULL;
751 
753  break;
754 
755  case HeapTupleUpdated:
757  ereport(ERROR,
758  (errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
759  errmsg("could not serialize access due to concurrent update")));
760  if (!ItemPointerEquals(tupleid, &hufd.ctid))
761  {
762  TupleTableSlot *epqslot;
763 
764  epqslot = EvalPlanQual(estate,
765  epqstate,
766  resultRelationDesc,
767  resultRelInfo->ri_RangeTableIndex,
769  &hufd.ctid,
770  hufd.xmax);
771  if (!TupIsNull(epqslot))
772  {
773  *tupleid = hufd.ctid;
774  goto ldelete;
775  }
776  }
777  /* tuple already deleted; nothing to do */
778  return NULL;
779 
780  default:
781  elog(ERROR, "unrecognized heap_delete status: %u", result);
782  return NULL;
783  }
784 
785  /*
786  * Note: Normally one would think that we have to delete index tuples
787  * associated with the heap tuple now...
788  *
789  * ... but in POSTGRES, we have no need to do this because VACUUM will
790  * take care of it later. We can't delete index tuples immediately
791  * anyway, since the tuple is still visible to other transactions.
792  */
793  }
794 
795  if (canSetTag)
796  (estate->es_processed)++;
797 
798  /* AFTER ROW DELETE Triggers */
799  ExecARDeleteTriggers(estate, resultRelInfo, tupleid, oldtuple);
800 
801  /* Process RETURNING if present */
802  if (resultRelInfo->ri_projectReturning)
803  {
804  /*
805  * We have to put the target tuple into a slot, which means first we
806  * gotta fetch it. We can use the trigger tuple slot.
807  */
808  TupleTableSlot *rslot;
809  HeapTupleData deltuple;
810  Buffer delbuffer;
811 
812  if (resultRelInfo->ri_FdwRoutine)
813  {
814  /* FDW must have provided a slot containing the deleted row */
815  Assert(!TupIsNull(slot));
816  delbuffer = InvalidBuffer;
817  }
818  else
819  {
820  slot = estate->es_trig_tuple_slot;
821  if (oldtuple != NULL)
822  {
823  deltuple = *oldtuple;
824  delbuffer = InvalidBuffer;
825  }
826  else
827  {
828  deltuple.t_self = *tupleid;
829  if (!heap_fetch(resultRelationDesc, SnapshotAny,
830  &deltuple, &delbuffer, false, NULL))
831  elog(ERROR, "failed to fetch deleted tuple for DELETE RETURNING");
832  }
833 
834  if (slot->tts_tupleDescriptor != RelationGetDescr(resultRelationDesc))
835  ExecSetSlotDescriptor(slot, RelationGetDescr(resultRelationDesc));
836  ExecStoreTuple(&deltuple, slot, InvalidBuffer, false);
837  }
838 
839  rslot = ExecProcessReturning(resultRelInfo, slot, planSlot);
840 
841  /*
842  * Before releasing the target tuple again, make sure rslot has a
843  * local copy of any pass-by-reference values.
844  */
845  ExecMaterializeSlot(rslot);
846 
847  ExecClearTuple(slot);
848  if (BufferIsValid(delbuffer))
849  ReleaseBuffer(delbuffer);
850 
851  return rslot;
852  }
853 
854  return NULL;
855 }
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:374
bool tts_isempty
Definition: tuptable.h:116
bool ExecIRDeleteTriggers(EState *estate, ResultRelInfo *relinfo, HeapTuple trigtuple)
Definition: trigger.c:2485
int errhint(const char *fmt,...)
Definition: elog.c:987
CommandId es_output_cid
Definition: execnodes.h:418
TupleTableSlot * ExecStoreAllNullTuple(TupleTableSlot *slot)
Definition: execTuples.c:512
#define RelationGetDescr(relation)
Definition: rel.h:429
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:2380
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:410
int errcode(int sqlerrcode)
Definition: elog.c:575
return result
Definition: formatting.c:1618
void ReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3309
Index ri_RangeTableIndex
Definition: execnodes.h:373
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
CommandId cmax
Definition: heapam.h:72
HTSU_Result
Definition: snapshot.h:119
ProjectionInfo * ri_projectReturning
Definition: execnodes.h:389
#define TupIsNull(slot)
Definition: tuptable.h:138
struct FdwRoutine * ri_FdwRoutine
Definition: execnodes.h:382
Oid t_tableOid
Definition: htup.h:66
TupleTableSlot * es_trig_tuple_slot
Definition: execnodes.h:427
#define ereport(elevel, rest)
Definition: elog.h:122
TriggerDesc * ri_TrigDesc
Definition: execnodes.h:378
static TupleTableSlot * ExecProcessReturning(ResultRelInfo *resultRelInfo, TupleTableSlot *tupleSlot, TupleTableSlot *planSlot)
TransactionId xmax
Definition: heapam.h:71
TupleDesc tts_tupleDescriptor
Definition: tuptable.h:121
void ExecARDeleteTriggers(EState *estate, ResultRelInfo *relinfo, ItemPointer tupleid, HeapTuple fdw_trigtuple)
Definition: trigger.c:2455
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:2386
#define NULL
Definition: c.h:229
#define Assert(condition)
Definition: c.h:675
uint64 es_processed
Definition: execnodes.h:444
#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:417
bool trig_delete_before_row
Definition: reltrigger.h:65
ResultRelInfo * es_result_relation_info
Definition: execnodes.h:423
void ExecEndModifyTable ( ModifyTableState node)

Definition at line 2128 of file nodeModifyTable.c.

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

2129 {
2130  int i;
2131 
2132  /*
2133  * Allow any FDWs to shut down
2134  */
2135  for (i = 0; i < node->mt_nplans; i++)
2136  {
2137  ResultRelInfo *resultRelInfo = node->resultRelInfo + i;
2138 
2139  if (!resultRelInfo->ri_usesFdwDirectModify &&
2140  resultRelInfo->ri_FdwRoutine != NULL &&
2141  resultRelInfo->ri_FdwRoutine->EndForeignModify != NULL)
2142  resultRelInfo->ri_FdwRoutine->EndForeignModify(node->ps.state,
2143  resultRelInfo);
2144  }
2145 
2146  /*
2147  * Close all the partitioned tables, leaf partitions, and their indices
2148  *
2149  * Remember node->mt_partition_dispatch_info[0] corresponds to the root
2150  * partitioned table, which we must not try to close, because it is the
2151  * main target table of the query that will be closed by ExecEndPlan().
2152  * Also, tupslot is NULL for the root partitioned table.
2153  */
2154  for (i = 1; i < node->mt_num_dispatch; i++)
2155  {
2157 
2158  heap_close(pd->reldesc, NoLock);
2160  }
2161  for (i = 0; i < node->mt_num_partitions; i++)
2162  {
2163  ResultRelInfo *resultRelInfo = node->mt_partitions + i;
2164 
2165  ExecCloseIndices(resultRelInfo);
2166  heap_close(resultRelInfo->ri_RelationDesc, NoLock);
2167  }
2168 
2169  /* Release the standalone partition tuple descriptor, if any */
2170  if (node->mt_partition_tuple_slot)
2172 
2173  /*
2174  * Free the exprcontext
2175  */
2176  ExecFreeExprContext(&node->ps);
2177 
2178  /*
2179  * clean out the tuple table
2180  */
2182 
2183  /*
2184  * Terminate EPQ execution if active
2185  */
2186  EvalPlanQualEnd(&node->mt_epqstate);
2187 
2188  /*
2189  * shut down subplans
2190  */
2191  for (i = 0; i < node->mt_nplans; i++)
2192  ExecEndNode(node->mt_plans[i]);
2193 }
Relation ri_RelationDesc
Definition: execnodes.h:374
ResultRelInfo * mt_partitions
Definition: execnodes.h:934
void ExecEndNode(PlanState *node)
Definition: execProcnode.c:654
ResultRelInfo * resultRelInfo
Definition: execnodes.h:916
TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition: execTuples.c:439
#define heap_close(r, l)
Definition: heapam.h:97
EState * state
Definition: execnodes.h:805
void ExecFreeExprContext(PlanState *planstate)
Definition: execUtils.c:516
void EvalPlanQualEnd(EPQState *epqstate)
Definition: execMain.c:3107
TupleTableSlot * ps_ResultTupleSlot
Definition: execnodes.h:832
PlanState ps
Definition: execnodes.h:909
bool ri_usesFdwDirectModify
Definition: execnodes.h:384
#define NoLock
Definition: lockdefs.h:34
void ExecDropSingleTupleTableSlot(TupleTableSlot *slot)
Definition: execTuples.c:216
EPQState mt_epqstate
Definition: execnodes.h:918
struct FdwRoutine * ri_FdwRoutine
Definition: execnodes.h:382
EndForeignModify_function EndForeignModify
Definition: fdwapi.h:200
PlanState ** mt_plans
Definition: execnodes.h:913
TupleTableSlot * tupslot
Definition: partition.h:66
TupleTableSlot * mt_partition_tuple_slot
Definition: execnodes.h:937
#define NULL
Definition: c.h:229
int i
struct PartitionDispatchData ** mt_partition_dispatch_info
Definition: execnodes.h:928
void ExecCloseIndices(ResultRelInfo *resultRelInfo)
Definition: execIndexing.c:224
ModifyTableState* ExecInitModifyTable ( ModifyTable node,
EState estate,
int  eflags 
)

Definition at line 1626 of file nodeModifyTable.c.

References ModifyTable::arbiterIndexes, Assert, AttributeNumberIsValid, FdwRoutine::BeginForeignModify, bms_is_member(), ModifyTable::canSetTag, ModifyTableState::canSetTag, CheckValidResultRel(), CMD_DELETE, CMD_INSERT, CMD_UPDATE, elog, ModifyTable::epqParam, ERROR, EState::es_auxmodifytables, EState::es_range_table, EState::es_result_relation_info, EState::es_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(), 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::rowMarks, PlanRowMark::rti, PlanState::state, Plan::targetlist, tupleDesc::tdhasoid, and ModifyTable::withCheckOptionLists.

Referenced by ExecInitNode().

1627 {
1628  ModifyTableState *mtstate;
1629  CmdType operation = node->operation;
1630  int nplans = list_length(node->plans);
1631  ResultRelInfo *saved_resultRelInfo;
1632  ResultRelInfo *resultRelInfo;
1633  TupleDesc tupDesc;
1634  Plan *subplan;
1635  ListCell *l;
1636  int i;
1637  Relation rel;
1638 
1639  /* check for unsupported flags */
1640  Assert(!(eflags & (EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK)));
1641 
1642  /*
1643  * create state structure
1644  */
1645  mtstate = makeNode(ModifyTableState);
1646  mtstate->ps.plan = (Plan *) node;
1647  mtstate->ps.state = estate;
1648 
1649  mtstate->operation = operation;
1650  mtstate->canSetTag = node->canSetTag;
1651  mtstate->mt_done = false;
1652 
1653  mtstate->mt_plans = (PlanState **) palloc0(sizeof(PlanState *) * nplans);
1654  mtstate->resultRelInfo = estate->es_result_relations + node->resultRelIndex;
1655  mtstate->mt_arowmarks = (List **) palloc0(sizeof(List *) * nplans);
1656  mtstate->mt_nplans = nplans;
1657  mtstate->mt_onconflict = node->onConflictAction;
1658  mtstate->mt_arbiterindexes = node->arbiterIndexes;
1659 
1660  /* set up epqstate with dummy subplan data for the moment */
1661  EvalPlanQualInit(&mtstate->mt_epqstate, estate, NULL, NIL, node->epqParam);
1662  mtstate->fireBSTriggers = true;
1663 
1664  /*
1665  * call ExecInitNode on each of the plans to be executed and save the
1666  * results into the array "mt_plans". This is also a convenient place to
1667  * verify that the proposed target relations are valid and open their
1668  * indexes for insertion of new index entries. Note we *must* set
1669  * estate->es_result_relation_info correctly while we initialize each
1670  * sub-plan; ExecContextForcesOids depends on that!
1671  */
1672  saved_resultRelInfo = estate->es_result_relation_info;
1673 
1674  resultRelInfo = mtstate->resultRelInfo;
1675  i = 0;
1676  foreach(l, node->plans)
1677  {
1678  subplan = (Plan *) lfirst(l);
1679 
1680  /* Initialize the usesFdwDirectModify flag */
1681  resultRelInfo->ri_usesFdwDirectModify = bms_is_member(i,
1682  node->fdwDirectModifyPlans);
1683 
1684  /*
1685  * Verify result relation is a valid target for the current operation
1686  */
1687  CheckValidResultRel(resultRelInfo->ri_RelationDesc, operation);
1688 
1689  /*
1690  * If there are indices on the result relation, open them and save
1691  * descriptors in the result relation info, so that we can add new
1692  * index entries for the tuples we add/update. We need not do this
1693  * for a DELETE, however, since deletion doesn't affect indexes. Also,
1694  * inside an EvalPlanQual operation, the indexes might be open
1695  * already, since we share the resultrel state with the original
1696  * query.
1697  */
1698  if (resultRelInfo->ri_RelationDesc->rd_rel->relhasindex &&
1699  operation != CMD_DELETE &&
1700  resultRelInfo->ri_IndexRelationDescs == NULL)
1701  ExecOpenIndices(resultRelInfo, mtstate->mt_onconflict != ONCONFLICT_NONE);
1702 
1703  /* Now init the plan for this result rel */
1704  estate->es_result_relation_info = resultRelInfo;
1705  mtstate->mt_plans[i] = ExecInitNode(subplan, estate, eflags);
1706 
1707  /* Also let FDWs init themselves for foreign-table result rels */
1708  if (!resultRelInfo->ri_usesFdwDirectModify &&
1709  resultRelInfo->ri_FdwRoutine != NULL &&
1710  resultRelInfo->ri_FdwRoutine->BeginForeignModify != NULL)
1711  {
1712  List *fdw_private = (List *) list_nth(node->fdwPrivLists, i);
1713 
1714  resultRelInfo->ri_FdwRoutine->BeginForeignModify(mtstate,
1715  resultRelInfo,
1716  fdw_private,
1717  i,
1718  eflags);
1719  }
1720 
1721  resultRelInfo++;
1722  i++;
1723  }
1724 
1725  estate->es_result_relation_info = saved_resultRelInfo;
1726 
1727  /* The root table RT index is at the head of the partitioned_rels list */
1728  if (node->partitioned_rels)
1729  {
1730  Index root_rti;
1731  Oid root_oid;
1732 
1733  root_rti = linitial_int(node->partitioned_rels);
1734  root_oid = getrelid(root_rti, estate->es_range_table);
1735  rel = heap_open(root_oid, NoLock); /* locked by InitPlan */
1736  }
1737  else
1738  rel = mtstate->resultRelInfo->ri_RelationDesc;
1739 
1740  /* Build state for INSERT tuple routing */
1741  if (operation == CMD_INSERT &&
1742  rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
1743  {
1744  PartitionDispatch *partition_dispatch_info;
1745  ResultRelInfo *partitions;
1746  TupleConversionMap **partition_tupconv_maps;
1747  TupleTableSlot *partition_tuple_slot;
1748  int num_parted,
1749  num_partitions;
1750 
1752  &partition_dispatch_info,
1753  &partitions,
1754  &partition_tupconv_maps,
1755  &partition_tuple_slot,
1756  &num_parted, &num_partitions);
1757  mtstate->mt_partition_dispatch_info = partition_dispatch_info;
1758  mtstate->mt_num_dispatch = num_parted;
1759  mtstate->mt_partitions = partitions;
1760  mtstate->mt_num_partitions = num_partitions;
1761  mtstate->mt_partition_tupconv_maps = partition_tupconv_maps;
1762  mtstate->mt_partition_tuple_slot = partition_tuple_slot;
1763  }
1764 
1765  /*
1766  * Initialize any WITH CHECK OPTION constraints if needed.
1767  */
1768  resultRelInfo = mtstate->resultRelInfo;
1769  i = 0;
1770  foreach(l, node->withCheckOptionLists)
1771  {
1772  List *wcoList = (List *) lfirst(l);
1773  List *wcoExprs = NIL;
1774  ListCell *ll;
1775 
1776  foreach(ll, wcoList)
1777  {
1778  WithCheckOption *wco = (WithCheckOption *) lfirst(ll);
1779  ExprState *wcoExpr = ExecInitQual((List *) wco->qual,
1780  mtstate->mt_plans[i]);
1781 
1782  wcoExprs = lappend(wcoExprs, wcoExpr);
1783  }
1784 
1785  resultRelInfo->ri_WithCheckOptions = wcoList;
1786  resultRelInfo->ri_WithCheckOptionExprs = wcoExprs;
1787  resultRelInfo++;
1788  i++;
1789  }
1790 
1791  /*
1792  * Build WITH CHECK OPTION constraints for each leaf partition rel.
1793  * Note that we didn't build the withCheckOptionList for each partition
1794  * within the planner, but simple translation of the varattnos for each
1795  * partition will suffice. This only occurs for the INSERT case;
1796  * UPDATE/DELETE cases are handled above.
1797  */
1798  if (node->withCheckOptionLists != NIL && mtstate->mt_num_partitions > 0)
1799  {
1800  List *wcoList;
1801 
1802  Assert(operation == CMD_INSERT);
1803  resultRelInfo = mtstate->mt_partitions;
1804  wcoList = linitial(node->withCheckOptionLists);
1805  for (i = 0; i < mtstate->mt_num_partitions; i++)
1806  {
1807  Relation partrel = resultRelInfo->ri_RelationDesc;
1808  List *mapped_wcoList;
1809  List *wcoExprs = NIL;
1810  ListCell *ll;
1811 
1812  /* varno = node->nominalRelation */
1813  mapped_wcoList = map_partition_varattnos(wcoList,
1814  node->nominalRelation,
1815  partrel, rel);
1816  foreach(ll, mapped_wcoList)
1817  {
1818  WithCheckOption *wco = (WithCheckOption *) lfirst(ll);
1819  ExprState *wcoExpr = ExecInitQual((List *) wco->qual,
1820  mtstate->mt_plans[i]);
1821 
1822  wcoExprs = lappend(wcoExprs, wcoExpr);
1823  }
1824 
1825  resultRelInfo->ri_WithCheckOptions = mapped_wcoList;
1826  resultRelInfo->ri_WithCheckOptionExprs = wcoExprs;
1827  resultRelInfo++;
1828  }
1829  }
1830 
1831  /*
1832  * Initialize RETURNING projections if needed.
1833  */
1834  if (node->returningLists)
1835  {
1836  TupleTableSlot *slot;
1837  ExprContext *econtext;
1838  List *returningList;
1839 
1840  /*
1841  * Initialize result tuple slot and assign its rowtype using the first
1842  * RETURNING list. We assume the rest will look the same.
1843  */
1844  tupDesc = ExecTypeFromTL((List *) linitial(node->returningLists),
1845  false);
1846 
1847  /* Set up a slot for the output of the RETURNING projection(s) */
1848  ExecInitResultTupleSlot(estate, &mtstate->ps);
1849  ExecAssignResultType(&mtstate->ps, tupDesc);
1850  slot = mtstate->ps.ps_ResultTupleSlot;
1851 
1852  /* Need an econtext too */
1853  if (mtstate->ps.ps_ExprContext == NULL)
1854  ExecAssignExprContext(estate, &mtstate->ps);
1855  econtext = mtstate->ps.ps_ExprContext;
1856 
1857  /*
1858  * Build a projection for each result rel.
1859  */
1860  resultRelInfo = mtstate->resultRelInfo;
1861  foreach(l, node->returningLists)
1862  {
1863  List *rlist = (List *) lfirst(l);
1864 
1865  resultRelInfo->ri_projectReturning =
1866  ExecBuildProjectionInfo(rlist, econtext, slot, &mtstate->ps,
1867  resultRelInfo->ri_RelationDesc->rd_att);
1868  resultRelInfo++;
1869  }
1870 
1871  /*
1872  * Build a projection for each leaf partition rel. Note that we
1873  * didn't build the returningList for each partition within the
1874  * planner, but simple translation of the varattnos for each partition
1875  * will suffice. This only occurs for the INSERT case; UPDATE/DELETE
1876  * are handled above.
1877  */
1878  resultRelInfo = mtstate->mt_partitions;
1879  returningList = linitial(node->returningLists);
1880  for (i = 0; i < mtstate->mt_num_partitions; i++)
1881  {
1882  Relation partrel = resultRelInfo->ri_RelationDesc;
1883  List *rlist;
1884 
1885  /* varno = node->nominalRelation */
1886  rlist = map_partition_varattnos(returningList,
1887  node->nominalRelation,
1888  partrel, rel);
1889  resultRelInfo->ri_projectReturning =
1890  ExecBuildProjectionInfo(rlist, econtext, slot, &mtstate->ps,
1891  resultRelInfo->ri_RelationDesc->rd_att);
1892  resultRelInfo++;
1893  }
1894  }
1895  else
1896  {
1897  /*
1898  * We still must construct a dummy result tuple type, because InitPlan
1899  * expects one (maybe should change that?).
1900  */
1901  tupDesc = ExecTypeFromTL(NIL, false);
1902  ExecInitResultTupleSlot(estate, &mtstate->ps);
1903  ExecAssignResultType(&mtstate->ps, tupDesc);
1904 
1905  mtstate->ps.ps_ExprContext = NULL;
1906  }
1907 
1908  /* Close the root partitioned rel if we opened it above. */
1909  if (rel != mtstate->resultRelInfo->ri_RelationDesc)
1910  heap_close(rel, NoLock);
1911 
1912  /*
1913  * If needed, Initialize target list, projection and qual for ON CONFLICT
1914  * DO UPDATE.
1915  */
1916  resultRelInfo = mtstate->resultRelInfo;
1917  if (node->onConflictAction == ONCONFLICT_UPDATE)
1918  {
1919  ExprContext *econtext;
1920  TupleDesc tupDesc;
1921 
1922  /* insert may only have one plan, inheritance is not expanded */
1923  Assert(nplans == 1);
1924 
1925  /* already exists if created by RETURNING processing above */
1926  if (mtstate->ps.ps_ExprContext == NULL)
1927  ExecAssignExprContext(estate, &mtstate->ps);
1928 
1929  econtext = mtstate->ps.ps_ExprContext;
1930 
1931  /* initialize slot for the existing tuple */
1932  mtstate->mt_existing = ExecInitExtraTupleSlot(mtstate->ps.state);
1934  resultRelInfo->ri_RelationDesc->rd_att);
1935 
1936  /* carried forward solely for the benefit of explain */
1937  mtstate->mt_excludedtlist = node->exclRelTlist;
1938 
1939  /* create target slot for UPDATE SET projection */
1940  tupDesc = ExecTypeFromTL((List *) node->onConflictSet,
1941  resultRelInfo->ri_RelationDesc->rd_rel->relhasoids);
1942  mtstate->mt_conflproj = ExecInitExtraTupleSlot(mtstate->ps.state);
1943  ExecSetSlotDescriptor(mtstate->mt_conflproj, tupDesc);
1944 
1945  /* build UPDATE SET projection state */
1946  resultRelInfo->ri_onConflictSetProj =
1947  ExecBuildProjectionInfo(node->onConflictSet, econtext,
1948  mtstate->mt_conflproj, &mtstate->ps,
1949  resultRelInfo->ri_RelationDesc->rd_att);
1950 
1951  /* build DO UPDATE WHERE clause expression */
1952  if (node->onConflictWhere)
1953  {
1954  ExprState *qualexpr;
1955 
1956  qualexpr = ExecInitQual((List *) node->onConflictWhere,
1957  &mtstate->ps);
1958 
1959  resultRelInfo->ri_onConflictSetWhere = qualexpr;
1960  }
1961  }
1962 
1963  /*
1964  * If we have any secondary relations in an UPDATE or DELETE, they need to
1965  * be treated like non-locked relations in SELECT FOR UPDATE, ie, the
1966  * EvalPlanQual mechanism needs to be told about them. Locate the
1967  * relevant ExecRowMarks.
1968  */
1969  foreach(l, node->rowMarks)
1970  {
1972  ExecRowMark *erm;
1973 
1974  /* ignore "parent" rowmarks; they are irrelevant at runtime */
1975  if (rc->isParent)
1976  continue;
1977 
1978  /* find ExecRowMark (same for all subplans) */
1979  erm = ExecFindRowMark(estate, rc->rti, false);
1980 
1981  /* build ExecAuxRowMark for each subplan */
1982  for (i = 0; i < nplans; i++)
1983  {
1984  ExecAuxRowMark *aerm;
1985 
1986  subplan = mtstate->mt_plans[i]->plan;
1987  aerm = ExecBuildAuxRowMark(erm, subplan->targetlist);
1988  mtstate->mt_arowmarks[i] = lappend(mtstate->mt_arowmarks[i], aerm);
1989  }
1990  }
1991 
1992  /* select first subplan */
1993  mtstate->mt_whichplan = 0;
1994  subplan = (Plan *) linitial(node->plans);
1995  EvalPlanQualSetPlan(&mtstate->mt_epqstate, subplan,
1996  mtstate->mt_arowmarks[0]);
1997 
1998  /*
1999  * Initialize the junk filter(s) if needed. INSERT queries need a filter
2000  * if there are any junk attrs in the tlist. UPDATE and DELETE always
2001  * need a filter, since there's always a junk 'ctid' or 'wholerow'
2002  * attribute present --- no need to look first.
2003  *
2004  * If there are multiple result relations, each one needs its own junk
2005  * filter. Note multiple rels are only possible for UPDATE/DELETE, so we
2006  * can't be fooled by some needing a filter and some not.
2007  *
2008  * This section of code is also a convenient place to verify that the
2009  * output of an INSERT or UPDATE matches the target table(s).
2010  */
2011  {
2012  bool junk_filter_needed = false;
2013 
2014  switch (operation)
2015  {
2016  case CMD_INSERT:
2017  foreach(l, subplan->targetlist)
2018  {
2019  TargetEntry *tle = (TargetEntry *) lfirst(l);
2020 
2021  if (tle->resjunk)
2022  {
2023  junk_filter_needed = true;
2024  break;
2025  }
2026  }
2027  break;
2028  case CMD_UPDATE:
2029  case CMD_DELETE:
2030  junk_filter_needed = true;
2031  break;
2032  default:
2033  elog(ERROR, "unknown operation");
2034  break;
2035  }
2036 
2037  if (junk_filter_needed)
2038  {
2039  resultRelInfo = mtstate->resultRelInfo;
2040  for (i = 0; i < nplans; i++)
2041  {
2042  JunkFilter *j;
2043 
2044  subplan = mtstate->mt_plans[i]->plan;
2045  if (operation == CMD_INSERT || operation == CMD_UPDATE)
2046  ExecCheckPlanOutput(resultRelInfo->ri_RelationDesc,
2047  subplan->targetlist);
2048 
2049  j = ExecInitJunkFilter(subplan->targetlist,
2050  resultRelInfo->ri_RelationDesc->rd_att->tdhasoid,
2051  ExecInitExtraTupleSlot(estate));
2052 
2053  if (operation == CMD_UPDATE || operation == CMD_DELETE)
2054  {
2055  /* For UPDATE/DELETE, find the appropriate junk attr now */
2056  char relkind;
2057 
2058  relkind = resultRelInfo->ri_RelationDesc->rd_rel->relkind;
2059  if (relkind == RELKIND_RELATION ||
2060  relkind == RELKIND_MATVIEW ||
2061  relkind == RELKIND_PARTITIONED_TABLE)
2062  {
2063  j->jf_junkAttNo = ExecFindJunkAttribute(j, "ctid");
2065  elog(ERROR, "could not find junk ctid column");
2066  }
2067  else if (relkind == RELKIND_FOREIGN_TABLE)
2068  {
2069  /*
2070  * When there is an AFTER trigger, there should be a
2071  * wholerow attribute.
2072  */
2073  j->jf_junkAttNo = ExecFindJunkAttribute(j, "wholerow");
2074  }
2075  else
2076  {
2077  j->jf_junkAttNo = ExecFindJunkAttribute(j, "wholerow");
2079  elog(ERROR, "could not find junk wholerow column");
2080  }
2081  }
2082 
2083  resultRelInfo->ri_junkFilter = j;
2084  resultRelInfo++;
2085  }
2086  }
2087  else
2088  {
2089  if (operation == CMD_INSERT)
2091  subplan->targetlist);
2092  }
2093  }
2094 
2095  /*
2096  * Set up a tuple table slot for use for trigger output tuples. In a plan
2097  * containing multiple ModifyTable nodes, all can share one such slot, so
2098  * we keep it in the estate.
2099  */
2100  if (estate->es_trig_tuple_slot == NULL)
2101  estate->es_trig_tuple_slot = ExecInitExtraTupleSlot(estate);
2102 
2103  /*
2104  * Lastly, if this is not the primary (canSetTag) ModifyTable node, add it
2105  * to estate->es_auxmodifytables so that it will be run to completion by
2106  * ExecPostprocessPlan. (It'd actually work fine to add the primary
2107  * ModifyTable node too, but there's no need.) Note the use of lcons not
2108  * lappend: we need later-initialized ModifyTable nodes to be shut down
2109  * before earlier ones. This ensures that we don't throw away RETURNING
2110  * rows that need to be seen by a later CTE subplan.
2111  */
2112  if (!mtstate->canSetTag)
2113  estate->es_auxmodifytables = lcons(mtstate,
2114  estate->es_auxmodifytables);
2115 
2116  return mtstate;
2117 }
AttrNumber jf_junkAttNo
Definition: execnodes.h:336
#define NIL
Definition: pg_list.h:69
JunkFilter * ri_junkFilter
Definition: execnodes.h:388
List * arbiterIndexes
Definition: plannodes.h:222
Relation ri_RelationDesc
Definition: execnodes.h:374
Bitmapset * fdwDirectModifyPlans
Definition: plannodes.h:218
ExprState * ri_onConflictSetWhere
Definition: execnodes.h:391
TupleTableSlot * ExecInitExtraTupleSlot(EState *estate)
Definition: execTuples.c:852
Index nominalRelation
Definition: plannodes.h:209
bool tdhasoid
Definition: tupdesc.h:79
ProjectionInfo * ri_onConflictSetProj
Definition: execnodes.h:390
ResultRelInfo * mt_partitions
Definition: execnodes.h:934
List * withCheckOptionLists
Definition: plannodes.h:215
int resultRelIndex
Definition: plannodes.h:213
ResultRelInfo * resultRelInfo
Definition: execnodes.h:916
AttrNumber ExecFindJunkAttribute(JunkFilter *junkfilter, const char *attrName)
Definition: execJunk.c:209
ExprContext * ps_ExprContext
Definition: execnodes.h:833
TupleTableSlot * mt_conflproj
Definition: execnodes.h:926
#define RELKIND_MATVIEW
Definition: pg_class.h:165
bool canSetTag
Definition: plannodes.h:208
CmdType operation
Definition: execnodes.h:910
void EvalPlanQualSetPlan(EPQState *epqstate, Plan *subplan, List *auxrowmarks)
Definition: execMain.c:2715
#define heap_close(r, l)
Definition: heapam.h:97
EState * state
Definition: execnodes.h:805
List * es_range_table
Definition: execnodes.h:411
Form_pg_class rd_rel
Definition: rel.h:114
unsigned int Oid
Definition: postgres_ext.h:31
List * plans
Definition: plannodes.h:214
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:223
void ExecOpenIndices(ResultRelInfo *resultRelInfo, bool speculative)
Definition: execIndexing.c:149
TupleTableSlot * mt_existing
Definition: execnodes.h:923
List * ri_WithCheckOptionExprs
Definition: execnodes.h:386
#define linitial_int(l)
Definition: pg_list.h:112
OnConflictAction mt_onconflict
Definition: execnodes.h:920
TupleTableSlot * ps_ResultTupleSlot
Definition: execnodes.h:832
List * rowMarks
Definition: plannodes.h:219
void ExecSetupPartitionTupleRouting(Relation rel, PartitionDispatch **pd, ResultRelInfo **partitions, TupleConversionMap ***tup_conv_maps, TupleTableSlot **partition_tuple_slot, int *num_parted, int *num_partitions)
Definition: execMain.c:3176
bool resjunk
Definition: primnodes.h:1374
#define linitial(l)
Definition: pg_list.h:111
#define ERROR
Definition: elog.h:43
PlanState ps
Definition: execnodes.h:909
void ExecInitResultTupleSlot(EState *estate, PlanState *planstate)
Definition: execTuples.c:832
bool ri_usesFdwDirectModify
Definition: execnodes.h:384
#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:421
JunkFilter * ExecInitJunkFilter(List *targetList, bool hasoid, TupleTableSlot *slot)
Definition: execJunk.c:61
List * fdwPrivLists
Definition: plannodes.h:217
EPQState mt_epqstate
Definition: execnodes.h:918
ProjectionInfo * ri_projectReturning
Definition: execnodes.h:389
void CheckValidResultRel(Relation resultRel, CmdType operation)
Definition: execMain.c:1060
struct FdwRoutine * ri_FdwRoutine
Definition: execnodes.h:382
#define RELKIND_FOREIGN_TABLE
Definition: pg_class.h:167
List * partitioned_rels
Definition: plannodes.h:211
TupleTableSlot * es_trig_tuple_slot
Definition: execnodes.h:427
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:913
#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:455
void ExecSetSlotDescriptor(TupleTableSlot *slot, TupleDesc tupdesc)
Definition: execTuples.c:247
List * ri_WithCheckOptions
Definition: execnodes.h:385
TupleTableSlot * mt_partition_tuple_slot
Definition: execnodes.h:937
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:2696
Plan * plan
Definition: execnodes.h:803
Index rti
Definition: plannodes.h:998
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:221
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:134
List * mt_arbiterindexes
Definition: execnodes.h:921
List * mt_excludedtlist
Definition: execnodes.h:924
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:207
int i
struct PartitionDispatchData ** mt_partition_dispatch_info
Definition: execnodes.h:928
List * returningLists
Definition: plannodes.h:216
bool isParent
Definition: plannodes.h:1005
TupleConversionMap ** mt_partition_tupconv_maps
Definition: execnodes.h:935
#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:648
RelationPtr ri_IndexRelationDescs
Definition: execnodes.h:376
ExecAuxRowMark * ExecBuildAuxRowMark(ExecRowMark *erm, List *targetlist)
Definition: execMain.c:2309
List * exclRelTlist
Definition: plannodes.h:226
List ** mt_arowmarks
Definition: execnodes.h:917
int epqParam
Definition: plannodes.h:220
List * map_partition_varattnos(List *expr, int target_varno, Relation partrel, Relation parent)
Definition: partition.c:932
Node * onConflictWhere
Definition: plannodes.h:224
ExecRowMark * ExecFindRowMark(EState *estate, Index rti, bool missing_ok)
Definition: execMain.c:2285
ResultRelInfo * es_result_relation_info
Definition: execnodes.h:423
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, 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, 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  * We might need to convert from the parent rowtype to the partition
318  * rowtype.
319  */
320  map = mtstate->mt_partition_tupconv_maps[leaf_part_index];
321  if (map)
322  {
323  Relation partrel = resultRelInfo->ri_RelationDesc;
324 
325  tuple = do_convert_tuple(tuple, map);
326 
327  /*
328  * We must use the partition's tuple descriptor from this point
329  * on, until we're finished dealing with the partition. Use the
330  * dedicated slot for that.
331  */
332  slot = mtstate->mt_partition_tuple_slot;
333  Assert(slot != NULL);
334  ExecSetSlotDescriptor(slot, RelationGetDescr(partrel));
335  ExecStoreTuple(tuple, slot, InvalidBuffer, true);
336  }
337  }
338 
339  resultRelationDesc = resultRelInfo->ri_RelationDesc;
340 
341  /*
342  * If the result relation has OIDs, force the tuple's OID to zero so that
343  * heap_insert will assign a fresh OID. Usually the OID already will be
344  * zero at this point, but there are corner cases where the plan tree can
345  * return a tuple extracted literally from some table with the same
346  * rowtype.
347  *
348  * XXX if we ever wanted to allow users to assign their own OIDs to new
349  * rows, this'd be the place to do it. For the moment, we make a point of
350  * doing this before calling triggers, so that a user-supplied trigger
351  * could hack the OID if desired.
352  */
353  if (resultRelationDesc->rd_rel->relhasoids)
354  HeapTupleSetOid(tuple, InvalidOid);
355 
356  /*
357  * BEFORE ROW INSERT Triggers.
358  *
359  * Note: We fire BEFORE ROW TRIGGERS for every attempted insertion in an
360  * INSERT ... ON CONFLICT statement. We cannot check for constraint
361  * violations before firing these triggers, because they can change the
362  * values to insert. Also, they can run arbitrary user-defined code with
363  * side-effects that we can't cancel by just not inserting the tuple.
364  */
365  if (resultRelInfo->ri_TrigDesc &&
366  resultRelInfo->ri_TrigDesc->trig_insert_before_row)
367  {
368  slot = ExecBRInsertTriggers(estate, resultRelInfo, slot);
369 
370  if (slot == NULL) /* "do nothing" */
371  return NULL;
372 
373  /* trigger might have changed tuple */
374  tuple = ExecMaterializeSlot(slot);
375  }
376 
377  /* INSTEAD OF ROW INSERT Triggers */
378  if (resultRelInfo->ri_TrigDesc &&
379  resultRelInfo->ri_TrigDesc->trig_insert_instead_row)
380  {
381  slot = ExecIRInsertTriggers(estate, resultRelInfo, slot);
382 
383  if (slot == NULL) /* "do nothing" */
384  return NULL;
385 
386  /* trigger might have changed tuple */
387  tuple = ExecMaterializeSlot(slot);
388 
389  newId = InvalidOid;
390  }
391  else if (resultRelInfo->ri_FdwRoutine)
392  {
393  /*
394  * insert into foreign table: let the FDW do it
395  */
396  slot = resultRelInfo->ri_FdwRoutine->ExecForeignInsert(estate,
397  resultRelInfo,
398  slot,
399  planSlot);
400 
401  if (slot == NULL) /* "do nothing" */
402  return NULL;
403 
404  /* FDW might have changed tuple */
405  tuple = ExecMaterializeSlot(slot);
406 
407  /*
408  * AFTER ROW Triggers or RETURNING expressions might reference the
409  * tableoid column, so initialize t_tableOid before evaluating them.
410  */
411  tuple->t_tableOid = RelationGetRelid(resultRelationDesc);
412 
413  newId = InvalidOid;
414  }
415  else
416  {
417  /*
418  * Constraints might reference the tableoid column, so initialize
419  * t_tableOid before evaluating them.
420  */
421  tuple->t_tableOid = RelationGetRelid(resultRelationDesc);
422 
423  /*
424  * Check any RLS INSERT WITH CHECK policies
425  *
426  * ExecWithCheckOptions() will skip any WCOs which are not of the kind
427  * we are looking for at this point.
428  */
429  if (resultRelInfo->ri_WithCheckOptions != NIL)
431  resultRelInfo, slot, estate);
432 
433  /*
434  * Check the constraints of the tuple
435  */
436  if (resultRelationDesc->rd_att->constr || resultRelInfo->ri_PartitionCheck)
437  ExecConstraints(resultRelInfo, slot, estate);
438 
439  if (onconflict != ONCONFLICT_NONE && resultRelInfo->ri_NumIndices > 0)
440  {
441  /* Perform a speculative insertion. */
442  uint32 specToken;
443  ItemPointerData conflictTid;
444  bool specConflict;
445 
446  /*
447  * Do a non-conclusive check for conflicts first.
448  *
449  * We're not holding any locks yet, so this doesn't guarantee that
450  * the later insert won't conflict. But it avoids leaving behind
451  * a lot of canceled speculative insertions, if you run a lot of
452  * INSERT ON CONFLICT statements that do conflict.
453  *
454  * We loop back here if we find a conflict below, either during
455  * the pre-check, or when we re-check after inserting the tuple
456  * speculatively.
457  */
458  vlock:
459  specConflict = false;
460  if (!ExecCheckIndexConstraints(slot, estate, &conflictTid,
461  arbiterIndexes))
462  {
463  /* committed conflict tuple found */
464  if (onconflict == ONCONFLICT_UPDATE)
465  {
466  /*
467  * In case of ON CONFLICT DO UPDATE, execute the UPDATE
468  * part. Be prepared to retry if the UPDATE fails because
469  * of another concurrent UPDATE/DELETE to the conflict
470  * tuple.
471  */
472  TupleTableSlot *returning = NULL;
473 
474  if (ExecOnConflictUpdate(mtstate, resultRelInfo,
475  &conflictTid, planSlot, slot,
476  estate, canSetTag, &returning))
477  {
478  InstrCountFiltered2(&mtstate->ps, 1);
479  return returning;
480  }
481  else
482  goto vlock;
483  }
484  else
485  {
486  /*
487  * In case of ON CONFLICT DO NOTHING, do nothing. However,
488  * verify that the tuple is visible to the executor's MVCC
489  * snapshot at higher isolation levels.
490  */
491  Assert(onconflict == ONCONFLICT_NOTHING);
492  ExecCheckTIDVisible(estate, resultRelInfo, &conflictTid);
493  InstrCountFiltered2(&mtstate->ps, 1);
494  return NULL;
495  }
496  }
497 
498  /*
499  * Before we start insertion proper, acquire our "speculative
500  * insertion lock". Others can use that to wait for us to decide
501  * if we're going to go ahead with the insertion, instead of
502  * waiting for the whole transaction to complete.
503  */
505  HeapTupleHeaderSetSpeculativeToken(tuple->t_data, specToken);
506 
507  /* insert the tuple, with the speculative token */
508  newId = heap_insert(resultRelationDesc, tuple,
509  estate->es_output_cid,
511  NULL);
512 
513  /* insert index entries for tuple */
514  recheckIndexes = ExecInsertIndexTuples(slot, &(tuple->t_self),
515  estate, true, &specConflict,
516  arbiterIndexes);
517 
518  /* adjust the tuple's state accordingly */
519  if (!specConflict)
520  heap_finish_speculative(resultRelationDesc, tuple);
521  else
522  heap_abort_speculative(resultRelationDesc, tuple);
523 
524  /*
525  * Wake up anyone waiting for our decision. They will re-check
526  * the tuple, see that it's no longer speculative, and wait on our
527  * XID as if this was a regularly inserted tuple all along. Or if
528  * we killed the tuple, they will see it's dead, and proceed as if
529  * the tuple never existed.
530  */
532 
533  /*
534  * If there was a conflict, start from the beginning. We'll do
535  * the pre-check again, which will now find the conflicting tuple
536  * (unless it aborts before we get there).
537  */
538  if (specConflict)
539  {
540  list_free(recheckIndexes);
541  goto vlock;
542  }
543 
544  /* Since there was no insertion conflict, we're done */
545  }
546  else
547  {
548  /*
549  * insert the tuple normally.
550  *
551  * Note: heap_insert returns the tid (location) of the new tuple
552  * in the t_self field.
553  */
554  newId = heap_insert(resultRelationDesc, tuple,
555  estate->es_output_cid,
556  0, NULL);
557 
558  /* insert index entries for tuple */
559  if (resultRelInfo->ri_NumIndices > 0)
560  recheckIndexes = ExecInsertIndexTuples(slot, &(tuple->t_self),
561  estate, false, NULL,
562  arbiterIndexes);
563  }
564  }
565 
566  if (canSetTag)
567  {
568  (estate->es_processed)++;
569  estate->es_lastoid = newId;
570  setLastTid(&(tuple->t_self));
571  }
572 
573  /* AFTER ROW INSERT Triggers */
574  ExecARInsertTriggers(estate, resultRelInfo, tuple, recheckIndexes);
575 
576  list_free(recheckIndexes);
577 
578  /*
579  * Check any WITH CHECK OPTION constraints from parent views. We are
580  * required to do this after testing all constraints and uniqueness
581  * violations per the SQL spec, so we do it after actually inserting the
582  * record into the heap and all indexes.
583  *
584  * ExecWithCheckOptions will elog(ERROR) if a violation is found, so the
585  * tuple will never be seen, if it violates the WITH CHECK OPTION.
586  *
587  * ExecWithCheckOptions() will skip any WCOs which are not of the kind we
588  * are looking for at this point.
589  */
590  if (resultRelInfo->ri_WithCheckOptions != NIL)
591  ExecWithCheckOptions(WCO_VIEW_CHECK, resultRelInfo, slot, estate);
592 
593  /* Process RETURNING if present */
594  if (resultRelInfo->ri_projectReturning)
595  result = ExecProcessReturning(resultRelInfo, slot, planSlot);
596 
597  if (saved_resultRelInfo)
598  estate->es_result_relation_info = saved_resultRelInfo;
599 
600  return result;
601 }
int ri_NumIndices
Definition: execnodes.h:375
#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:374
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:1996
void heap_abort_speculative(Relation relation, HeapTuple tuple)
Definition: heapam.c:6053
CommandId es_output_cid
Definition: execnodes.h:418
List * ExecInsertIndexTuples(TupleTableSlot *slot, ItemPointer tupleid, EState *estate, bool noDupErr, bool *specConflict, List *arbiterIndexes)
Definition: execIndexing.c:271
ResultRelInfo * mt_partitions
Definition: execnodes.h:934
#define RelationGetDescr(relation)
Definition: rel.h:429
Oid es_lastoid
Definition: execnodes.h:445
ExecForeignInsert_function ExecForeignInsert
Definition: fdwapi.h:197
TupleTableSlot * ExecIRInsertTriggers(EState *estate, ResultRelInfo *relinfo, TupleTableSlot *slot)
Definition: trigger.c:2258
void ExecConstraints(ResultRelInfo *resultRelInfo, TupleTableSlot *slot, EState *estate)
Definition: execMain.c:1831
#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
return result
Definition: formatting.c:1618
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
#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:909
static void ExecCheckTIDVisible(EState *estate, ResultRelInfo *relinfo, ItemPointer tid)
ItemPointerData t_self
Definition: htup.h:65
TransactionId GetCurrentTransactionId(void)
Definition: xact.c:417
ProjectionInfo * ri_projectReturning
Definition: execnodes.h:389
struct FdwRoutine * ri_FdwRoutine
Definition: execnodes.h:382
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:378
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:385
int ExecFindPartition(ResultRelInfo *resultRelInfo, PartitionDispatch *pd, TupleTableSlot *slot, EState *estate)
Definition: execMain.c:3265
TupleTableSlot * mt_partition_tuple_slot
Definition: execnodes.h:937
List * ri_PartitionCheck
Definition: execnodes.h:392
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:853
void heap_finish_speculative(Relation relation, HeapTuple tuple)
Definition: heapam.c:5962
uint64 es_processed
Definition: execnodes.h:444
TupleConstr * constr
Definition: tupdesc.h:76
HeapTuple ExecMaterializeSlot(TupleTableSlot *slot)
Definition: execTuples.c:725
void ExecARInsertTriggers(EState *estate, ResultRelInfo *relinfo, HeapTuple trigtuple, List *recheckIndexes)
Definition: trigger.c:2246
HeapTuple do_convert_tuple(HeapTuple tuple, TupleConversionMap *map)
Definition: tupconvert.c:343
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:928
TupleTableSlot * ExecBRInsertTriggers(EState *estate, ResultRelInfo *relinfo, TupleTableSlot *slot)
Definition: trigger.c:2180
TupleConversionMap ** mt_partition_tupconv_maps
Definition: execnodes.h:935
Definition: pg_list.h:45
#define RelationGetRelid(relation)
Definition: rel.h:417
ResultRelInfo * es_result_relation_info
Definition: execnodes.h:423
TupleTableSlot* ExecModifyTable ( ModifyTableState node)

Definition at line 1386 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_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, and TupIsNull.

Referenced by ExecProcNode().

1387 {
1388  EState *estate = node->ps.state;
1389  CmdType operation = node->operation;
1390  ResultRelInfo *saved_resultRelInfo;
1391  ResultRelInfo *resultRelInfo;
1392  PlanState *subplanstate;
1393  JunkFilter *junkfilter;
1394  TupleTableSlot *slot;
1395  TupleTableSlot *planSlot;
1396  ItemPointer tupleid = NULL;
1397  ItemPointerData tuple_ctid;
1398  HeapTupleData oldtupdata;
1399  HeapTuple oldtuple;
1400 
1401  /*
1402  * This should NOT get called during EvalPlanQual; we should have passed a
1403  * subplan tree to EvalPlanQual, instead. Use a runtime test not just
1404  * Assert because this condition is easy to miss in testing. (Note:
1405  * although ModifyTable should not get executed within an EvalPlanQual
1406  * operation, we do have to allow it to be initialized and shut down in
1407  * case it is within a CTE subplan. Hence this test must be here, not in
1408  * ExecInitModifyTable.)
1409  */
1410  if (estate->es_epqTuple != NULL)
1411  elog(ERROR, "ModifyTable should not be called during EvalPlanQual");
1412 
1413  /*
1414  * If we've already completed processing, don't try to do more. We need
1415  * this test because ExecPostprocessPlan might call us an extra time, and
1416  * our subplan's nodes aren't necessarily robust against being called
1417  * extra times.
1418  */
1419  if (node->mt_done)
1420  return NULL;
1421 
1422  /*
1423  * On first call, fire BEFORE STATEMENT triggers before proceeding.
1424  */
1425  if (node->fireBSTriggers)
1426  {
1427  fireBSTriggers(node);
1428  node->fireBSTriggers = false;
1429  }
1430 
1431  /* Preload local variables */
1432  resultRelInfo = node->resultRelInfo + node->mt_whichplan;
1433  subplanstate = node->mt_plans[node->mt_whichplan];
1434  junkfilter = resultRelInfo->ri_junkFilter;
1435 
1436  /*
1437  * es_result_relation_info must point to the currently active result
1438  * relation while we are within this ModifyTable node. Even though
1439  * ModifyTable nodes can't be nested statically, they can be nested
1440  * dynamically (since our subplan could include a reference to a modifying
1441  * CTE). So we have to save and restore the caller's value.
1442  */
1443  saved_resultRelInfo = estate->es_result_relation_info;
1444 
1445  estate->es_result_relation_info = resultRelInfo;
1446 
1447  /*
1448  * Fetch rows from subplan(s), and execute the required table modification
1449  * for each row.
1450  */
1451  for (;;)
1452  {
1453  /*
1454  * Reset the per-output-tuple exprcontext. This is needed because
1455  * triggers expect to use that context as workspace. It's a bit ugly
1456  * to do this below the top level of the plan, however. We might need
1457  * to rethink this later.
1458  */
1459  ResetPerTupleExprContext(estate);
1460 
1461  planSlot = ExecProcNode(subplanstate);
1462 
1463  if (TupIsNull(planSlot))
1464  {
1465  /* advance to next subplan if any */
1466  node->mt_whichplan++;
1467  if (node->mt_whichplan < node->mt_nplans)
1468  {
1469  resultRelInfo++;
1470  subplanstate = node->mt_plans[node->mt_whichplan];
1471  junkfilter = resultRelInfo->ri_junkFilter;
1472  estate->es_result_relation_info = resultRelInfo;
1473  EvalPlanQualSetPlan(&node->mt_epqstate, subplanstate->plan,
1474  node->mt_arowmarks[node->mt_whichplan]);
1475  continue;
1476  }
1477  else
1478  break;
1479  }
1480 
1481  /*
1482  * If resultRelInfo->ri_usesFdwDirectModify is true, all we need to do
1483  * here is compute the RETURNING expressions.
1484  */
1485  if (resultRelInfo->ri_usesFdwDirectModify)
1486  {
1487  Assert(resultRelInfo->ri_projectReturning);
1488 
1489  /*
1490  * A scan slot containing the data that was actually inserted,
1491  * updated or deleted has already been made available to
1492  * ExecProcessReturning by IterateDirectModify, so no need to
1493  * provide it here.
1494  */
1495  slot = ExecProcessReturning(resultRelInfo, NULL, planSlot);
1496 
1497  estate->es_result_relation_info = saved_resultRelInfo;
1498  return slot;
1499  }
1500 
1501  EvalPlanQualSetSlot(&node->mt_epqstate, planSlot);
1502  slot = planSlot;
1503 
1504  oldtuple = NULL;
1505  if (junkfilter != NULL)
1506  {
1507  /*
1508  * extract the 'ctid' or 'wholerow' junk attribute.
1509  */
1510  if (operation == CMD_UPDATE || operation == CMD_DELETE)
1511  {
1512  char relkind;
1513  Datum datum;
1514  bool isNull;
1515 
1516  relkind = resultRelInfo->ri_RelationDesc->rd_rel->relkind;
1517  if (relkind == RELKIND_RELATION || relkind == RELKIND_MATVIEW)
1518  {
1519  datum = ExecGetJunkAttribute(slot,
1520  junkfilter->jf_junkAttNo,
1521  &isNull);
1522  /* shouldn't ever get a null result... */
1523  if (isNull)
1524  elog(ERROR, "ctid is NULL");
1525 
1526  tupleid = (ItemPointer) DatumGetPointer(datum);
1527  tuple_ctid = *tupleid; /* be sure we don't free
1528  * ctid!! */
1529  tupleid = &tuple_ctid;
1530  }
1531 
1532  /*
1533  * Use the wholerow attribute, when available, to reconstruct
1534  * the old relation tuple.
1535  *
1536  * Foreign table updates have a wholerow attribute when the
1537  * relation has an AFTER ROW trigger. Note that the wholerow
1538  * attribute does not carry system columns. Foreign table
1539  * triggers miss seeing those, except that we know enough here
1540  * to set t_tableOid. Quite separately from this, the FDW may
1541  * fetch its own junk attrs to identify the row.
1542  *
1543  * Other relevant relkinds, currently limited to views, always
1544  * have a wholerow attribute.
1545  */
1546  else if (AttributeNumberIsValid(junkfilter->jf_junkAttNo))
1547  {
1548  datum = ExecGetJunkAttribute(slot,
1549  junkfilter->jf_junkAttNo,
1550  &isNull);
1551  /* shouldn't ever get a null result... */
1552  if (isNull)
1553  elog(ERROR, "wholerow is NULL");
1554 
1555  oldtupdata.t_data = DatumGetHeapTupleHeader(datum);
1556  oldtupdata.t_len =
1558  ItemPointerSetInvalid(&(oldtupdata.t_self));
1559  /* Historically, view triggers see invalid t_tableOid. */
1560  oldtupdata.t_tableOid =
1561  (relkind == RELKIND_VIEW) ? InvalidOid :
1562  RelationGetRelid(resultRelInfo->ri_RelationDesc);
1563 
1564  oldtuple = &oldtupdata;
1565  }
1566  else
1567  Assert(relkind == RELKIND_FOREIGN_TABLE);
1568  }
1569 
1570  /*
1571  * apply the junkfilter if needed.
1572  */
1573  if (operation != CMD_DELETE)
1574  slot = ExecFilterJunk(junkfilter, slot);
1575  }
1576 
1577  switch (operation)
1578  {
1579  case CMD_INSERT:
1580  slot = ExecInsert(node, slot, planSlot,
1581  node->mt_arbiterindexes, node->mt_onconflict,
1582  estate, node->canSetTag);
1583  break;
1584  case CMD_UPDATE:
1585  slot = ExecUpdate(tupleid, oldtuple, slot, planSlot,
1586  &node->mt_epqstate, estate, node->canSetTag);
1587  break;
1588  case CMD_DELETE:
1589  slot = ExecDelete(tupleid, oldtuple, planSlot,
1590  &node->mt_epqstate, estate, node->canSetTag);
1591  break;
1592  default:
1593  elog(ERROR, "unknown operation");
1594  break;
1595  }
1596 
1597  /*
1598  * If we got a RETURNING result, return it to caller. We'll continue
1599  * the work on next call.
1600  */
1601  if (slot)
1602  {
1603  estate->es_result_relation_info = saved_resultRelInfo;
1604  return slot;
1605  }
1606  }
1607 
1608  /* Restore es_result_relation_info before exiting */
1609  estate->es_result_relation_info = saved_resultRelInfo;
1610 
1611  /*
1612  * We're done, but fire AFTER STATEMENT triggers before exiting.
1613  */
1614  fireASTriggers(node);
1615 
1616  node->mt_done = true;
1617 
1618  return NULL;
1619 }
AttrNumber jf_junkAttNo
Definition: execnodes.h:336
JunkFilter * ri_junkFilter
Definition: execnodes.h:388
HeapTuple * es_epqTuple
Definition: execnodes.h:473
Relation ri_RelationDesc
Definition: execnodes.h:374
TupleTableSlot * ExecProcNode(PlanState *node)
Definition: execProcnode.c:398
#define ResetPerTupleExprContext(estate)
Definition: executor.h:464
static TupleTableSlot * ExecUpdate(ItemPointer tupleid, HeapTuple oldtuple, TupleTableSlot *slot, TupleTableSlot *planSlot, EPQState *epqstate, EState *estate, bool canSetTag)
ResultRelInfo * resultRelInfo
Definition: execnodes.h:916
static void fireBSTriggers(ModifyTableState *node)
#define RELKIND_MATVIEW
Definition: pg_class.h:165
CmdType operation
Definition: execnodes.h:910
void EvalPlanQualSetPlan(EPQState *epqstate, Plan *subplan, List *auxrowmarks)
Definition: execMain.c:2715
EState * state
Definition: execnodes.h:805
Form_pg_class rd_rel
Definition: rel.h:114
#define DatumGetHeapTupleHeader(X)
Definition: fmgr.h:259
ItemPointerData * ItemPointer
Definition: itemptr.h:48
HeapTupleHeader t_data
Definition: htup.h:67
static TupleTableSlot * ExecDelete(ItemPointer tupleid, HeapTuple oldtuple, TupleTableSlot *planSlot, EPQState *epqstate, EState *estate, bool canSetTag)
OnConflictAction mt_onconflict
Definition: execnodes.h:920
#define ERROR
Definition: elog.h:43
PlanState ps
Definition: execnodes.h:909
ItemPointerData t_self
Definition: htup.h:65
bool ri_usesFdwDirectModify
Definition: execnodes.h:384
uint32 t_len
Definition: htup.h:64
EPQState mt_epqstate
Definition: execnodes.h:918
ProjectionInfo * ri_projectReturning
Definition: execnodes.h:389
#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:913
#define AttributeNumberIsValid(attributeNumber)
Definition: attnum.h:34
static void fireASTriggers(ModifyTableState *node)
uintptr_t Datum
Definition: postgres.h:372
TupleTableSlot * ExecFilterJunk(JunkFilter *junkfilter, TupleTableSlot *slot)
Definition: execJunk.c:262
Plan * plan
Definition: execnodes.h:803
#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
List * mt_arbiterindexes
Definition: execnodes.h:921
#define ItemPointerSetInvalid(pointer)
Definition: itemptr.h:149
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:417
CmdType
Definition: nodes.h:648
List ** mt_arowmarks
Definition: execnodes.h:917
#define EvalPlanQualSetSlot(epqstate, slot)
Definition: executor.h:219
#define HeapTupleHeaderGetDatumLength(tup)
Definition: htup_details.h:439
ResultRelInfo * es_result_relation_info
Definition: execnodes.h:423
static bool ExecOnConflictUpdate ( ModifyTableState mtstate,
ResultRelInfo resultRelInfo,
ItemPointer  conflictTid,
TupleTableSlot planSlot,
TupleTableSlot excludedSlot,
EState estate,
bool  canSetTag,
TupleTableSlot **  returning 
)
static

Definition at line 1143 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().

1151 {
1152  ExprContext *econtext = mtstate->ps.ps_ExprContext;
1153  Relation relation = resultRelInfo->ri_RelationDesc;
1154  ExprState *onConflictSetWhere = resultRelInfo->ri_onConflictSetWhere;
1155  HeapTupleData tuple;
1156  HeapUpdateFailureData hufd;
1157  LockTupleMode lockmode;
1158  HTSU_Result test;
1159  Buffer buffer;
1160 
1161  /* Determine lock mode to use */
1162  lockmode = ExecUpdateLockMode(estate, resultRelInfo);
1163 
1164  /*
1165  * Lock tuple for update. Don't follow updates when tuple cannot be
1166  * locked without doing so. A row locking conflict here means our
1167  * previous conclusion that the tuple is conclusively committed is not
1168  * true anymore.
1169  */
1170  tuple.t_self = *conflictTid;
1171  test = heap_lock_tuple(relation, &tuple, estate->es_output_cid,
1172  lockmode, LockWaitBlock, false, &buffer,
1173  &hufd);
1174  switch (test)
1175  {
1176  case HeapTupleMayBeUpdated:
1177  /* success! */
1178  break;
1179 
1180  case HeapTupleInvisible:
1181 
1182  /*
1183  * This can occur when a just inserted tuple is updated again in
1184  * the same command. E.g. because multiple rows with the same
1185  * conflicting key values are inserted.
1186  *
1187  * This is somewhat similar to the ExecUpdate()
1188  * HeapTupleSelfUpdated case. We do not want to proceed because
1189  * it would lead to the same row being updated a second time in
1190  * some unspecified order, and in contrast to plain UPDATEs
1191  * there's no historical behavior to break.
1192  *
1193  * It is the user's responsibility to prevent this situation from
1194  * occurring. These problems are why SQL-2003 similarly specifies
1195  * that for SQL MERGE, an exception must be raised in the event of
1196  * an attempt to update the same row twice.
1197  */
1199  ereport(ERROR,
1200  (errcode(ERRCODE_CARDINALITY_VIOLATION),
1201  errmsg("ON CONFLICT DO UPDATE command cannot affect row a second time"),
1202  errhint("Ensure that no rows proposed for insertion within the same command have duplicate constrained values.")));
1203 
1204  /* This shouldn't happen */
1205  elog(ERROR, "attempted to lock invisible tuple");
1206 
1207  case HeapTupleSelfUpdated:
1208 
1209  /*
1210  * This state should never be reached. As a dirty snapshot is used
1211  * to find conflicting tuples, speculative insertion wouldn't have
1212  * seen this row to conflict with.
1213  */
1214  elog(ERROR, "unexpected self-updated tuple");
1215 
1216  case HeapTupleUpdated:
1218  ereport(ERROR,
1219  (errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
1220  errmsg("could not serialize access due to concurrent update")));
1221 
1222  /*
1223  * Tell caller to try again from the very start.
1224  *
1225  * It does not make sense to use the usual EvalPlanQual() style
1226  * loop here, as the new version of the row might not conflict
1227  * anymore, or the conflicting tuple has actually been deleted.
1228  */
1229  ReleaseBuffer(buffer);
1230  return false;
1231 
1232  default:
1233  elog(ERROR, "unrecognized heap_lock_tuple status: %u", test);
1234  }
1235 
1236  /*
1237  * Success, the tuple is locked.
1238  *
1239  * Reset per-tuple memory context to free any expression evaluation
1240  * storage allocated in the previous cycle.
1241  */
1242  ResetExprContext(econtext);
1243 
1244  /*
1245  * Verify that the tuple is visible to our MVCC snapshot if the current
1246  * isolation level mandates that.
1247  *
1248  * It's not sufficient to rely on the check within ExecUpdate() as e.g.
1249  * CONFLICT ... WHERE clause may prevent us from reaching that.
1250  *
1251  * This means we only ever continue when a new command in the current
1252  * transaction could see the row, even though in READ COMMITTED mode the
1253  * tuple will not be visible according to the current statement's
1254  * snapshot. This is in line with the way UPDATE deals with newer tuple
1255  * versions.
1256  */
1257  ExecCheckHeapTupleVisible(estate, &tuple, buffer);
1258 
1259  /* Store target's existing tuple in the state's dedicated slot */
1260  ExecStoreTuple(&tuple, mtstate->mt_existing, buffer, false);
1261 
1262  /*
1263  * Make tuple and any needed join variables available to ExecQual and
1264  * ExecProject. The EXCLUDED tuple is installed in ecxt_innertuple, while
1265  * the target's existing tuple is installed in the scantuple. EXCLUDED
1266  * has been made to reference INNER_VAR in setrefs.c, but there is no
1267  * other redirection.
1268  */
1269  econtext->ecxt_scantuple = mtstate->mt_existing;
1270  econtext->ecxt_innertuple = excludedSlot;
1271  econtext->ecxt_outertuple = NULL;
1272 
1273  if (!ExecQual(onConflictSetWhere, econtext))
1274  {
1275  ReleaseBuffer(buffer);
1276  InstrCountFiltered1(&mtstate->ps, 1);
1277  return true; /* done with the tuple */
1278  }
1279 
1280  if (resultRelInfo->ri_WithCheckOptions != NIL)
1281  {
1282  /*
1283  * Check target's existing tuple against UPDATE-applicable USING
1284  * security barrier quals (if any), enforced here as RLS checks/WCOs.
1285  *
1286  * The rewriter creates UPDATE RLS checks/WCOs for UPDATE security
1287  * quals, and stores them as WCOs of "kind" WCO_RLS_CONFLICT_CHECK,
1288  * but that's almost the extent of its special handling for ON
1289  * CONFLICT DO UPDATE.
1290  *
1291  * The rewriter will also have associated UPDATE applicable straight
1292  * RLS checks/WCOs for the benefit of the ExecUpdate() call that
1293  * follows. INSERTs and UPDATEs naturally have mutually exclusive WCO
1294  * kinds, so there is no danger of spurious over-enforcement in the
1295  * INSERT or UPDATE path.
1296  */
1298  mtstate->mt_existing,
1299  mtstate->ps.state);
1300  }
1301 
1302  /* Project the new tuple version */
1303  ExecProject(resultRelInfo->ri_onConflictSetProj);
1304 
1305  /*
1306  * Note that it is possible that the target tuple has been modified in
1307  * this session, after the above heap_lock_tuple. We choose to not error
1308  * out in that case, in line with ExecUpdate's treatment of similar cases.
1309  * This can happen if an UPDATE is triggered from within ExecQual(),
1310  * ExecWithCheckOptions() or ExecProject() above, e.g. by selecting from a
1311  * wCTE in the ON CONFLICT's SET.
1312  */
1313 
1314  /* Execute UPDATE with projection */
1315  *returning = ExecUpdate(&tuple.t_self, NULL,
1316  mtstate->mt_conflproj, planSlot,
1317  &mtstate->mt_epqstate, mtstate->ps.state,
1318  canSetTag);
1319 
1320  ReleaseBuffer(buffer);
1321  return true;
1322 }
#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:374
ExprState * ri_onConflictSetWhere
Definition: execnodes.h:391
int errhint(const char *fmt,...)
Definition: elog.c:987
void ExecWithCheckOptions(WCOKind kind, ResultRelInfo *resultRelInfo, TupleTableSlot *slot, EState *estate)
Definition: execMain.c:1996
CommandId es_output_cid
Definition: execnodes.h:418
ProjectionInfo * ri_onConflictSetProj
Definition: execnodes.h:390
static void test(void)
static TupleTableSlot * ExecUpdate(ItemPointer tupleid, HeapTuple oldtuple, TupleTableSlot *slot, TupleTableSlot *planSlot, EPQState *epqstate, EState *estate, bool canSetTag)
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:4539
ExprContext * ps_ExprContext
Definition: execnodes.h:833
TupleTableSlot * mt_conflproj
Definition: execnodes.h:926
#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:805
static bool ExecQual(ExprState *state, ExprContext *econtext)
Definition: executor.h:345
TupleTableSlot * mt_existing
Definition: execnodes.h:923
HeapTupleHeader t_data
Definition: htup.h:67
LockTupleMode
Definition: heapam.h:38
#define ERROR
Definition: elog.h:43
PlanState ps
Definition: execnodes.h:909
ItemPointerData t_self
Definition: htup.h:65
static void ExecCheckHeapTupleVisible(EState *estate, HeapTuple tuple, Buffer buffer)
EPQState mt_epqstate
Definition: execnodes.h:918
TupleTableSlot * ecxt_innertuple
Definition: execnodes.h:198
HTSU_Result
Definition: snapshot.h:119
#define InstrCountFiltered1(node, delta)
Definition: execnodes.h:848
#define ereport(elevel, rest)
Definition: elog.h:122
List * ri_WithCheckOptions
Definition: execnodes.h:385
TupleTableSlot * ecxt_outertuple
Definition: execnodes.h:199
#define NULL
Definition: c.h:229
LockTupleMode ExecUpdateLockMode(EState *estate, ResultRelInfo *relinfo)
Definition: execMain.c:2259
WalTimeSample buffer[LAG_TRACKER_BUFFER_SIZE]
Definition: walsender.c:207
#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:308
#define ResetExprContext(econtext)
Definition: executor.h:449
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:374
ProjectionInfo * ri_projectReturning
Definition: execnodes.h:389
#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:417
static TupleTableSlot * ExecProject(ProjectionInfo *projInfo)
Definition: executor.h:308
#define ResetExprContext(econtext)
Definition: executor.h:449
void ExecReScanModifyTable ( ModifyTableState node)

Definition at line 2196 of file nodeModifyTable.c.

References elog, and ERROR.

Referenced by ExecReScan().

2197 {
2198  /*
2199  * Currently, we don't need to support rescan on ModifyTable nodes. The
2200  * semantics of that would be a bit debatable anyway.
2201  */
2202  elog(ERROR, "ExecReScanModifyTable is not implemented");
2203 }
#define ERROR
Definition: elog.h:43
#define elog
Definition: elog.h:219
static TupleTableSlot* ExecUpdate ( ItemPointer  tupleid,
HeapTuple  oldtuple,
TupleTableSlot slot,
TupleTableSlot planSlot,
EPQState epqstate,
EState estate,
bool  canSetTag 
)
static

Definition at line 880 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(), 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().

887 {
888  HeapTuple tuple;
889  ResultRelInfo *resultRelInfo;
890  Relation resultRelationDesc;
893  List *recheckIndexes = NIL;
894 
895  /*
896  * abort the operation if not running transactions
897  */
899  elog(ERROR, "cannot UPDATE during bootstrap");
900 
901  /*
902  * get the heap tuple out of the tuple table slot, making sure we have a
903  * writable copy
904  */
905  tuple = ExecMaterializeSlot(slot);
906 
907  /*
908  * get information on the (current) result relation
909  */
910  resultRelInfo = estate->es_result_relation_info;
911  resultRelationDesc = resultRelInfo->ri_RelationDesc;
912 
913  /* BEFORE ROW UPDATE Triggers */
914  if (resultRelInfo->ri_TrigDesc &&
915  resultRelInfo->ri_TrigDesc->trig_update_before_row)
916  {
917  slot = ExecBRUpdateTriggers(estate, epqstate, resultRelInfo,
918  tupleid, oldtuple, slot);
919 
920  if (slot == NULL) /* "do nothing" */
921  return NULL;
922 
923  /* trigger might have changed tuple */
924  tuple = ExecMaterializeSlot(slot);
925  }
926 
927  /* INSTEAD OF ROW UPDATE Triggers */
928  if (resultRelInfo->ri_TrigDesc &&
929  resultRelInfo->ri_TrigDesc->trig_update_instead_row)
930  {
931  slot = ExecIRUpdateTriggers(estate, resultRelInfo,
932  oldtuple, slot);
933 
934  if (slot == NULL) /* "do nothing" */
935  return NULL;
936 
937  /* trigger might have changed tuple */
938  tuple = ExecMaterializeSlot(slot);
939  }
940  else if (resultRelInfo->ri_FdwRoutine)
941  {
942  /*
943  * update in foreign table: let the FDW do it
944  */
945  slot = resultRelInfo->ri_FdwRoutine->ExecForeignUpdate(estate,
946  resultRelInfo,
947  slot,
948  planSlot);
949 
950  if (slot == NULL) /* "do nothing" */
951  return NULL;
952 
953  /* FDW might have changed tuple */
954  tuple = ExecMaterializeSlot(slot);
955 
956  /*
957  * AFTER ROW Triggers or RETURNING expressions might reference the
958  * tableoid column, so initialize t_tableOid before evaluating them.
959  */
960  tuple->t_tableOid = RelationGetRelid(resultRelationDesc);
961  }
962  else
963  {
964  LockTupleMode lockmode;
965 
966  /*
967  * Constraints might reference the tableoid column, so initialize
968  * t_tableOid before evaluating them.
969  */
970  tuple->t_tableOid = RelationGetRelid(resultRelationDesc);
971 
972  /*
973  * Check any RLS UPDATE WITH CHECK policies
974  *
975  * If we generate a new candidate tuple after EvalPlanQual testing, we
976  * must loop back here and recheck any RLS policies and constraints.
977  * (We don't need to redo triggers, however. If there are any BEFORE
978  * triggers then trigger.c will have done heap_lock_tuple to lock the
979  * correct tuple, so there's no need to do them again.)
980  *
981  * ExecWithCheckOptions() will skip any WCOs which are not of the kind
982  * we are looking for at this point.
983  */
984 lreplace:;
985  if (resultRelInfo->ri_WithCheckOptions != NIL)
987  resultRelInfo, slot, estate);
988 
989  /*
990  * Check the constraints of the tuple. Note that we pass the same
991  * slot for the orig_slot argument, because unlike ExecInsert(), no
992  * tuple-routing is performed here, hence the slot remains unchanged.
993  */
994  if (resultRelationDesc->rd_att->constr || resultRelInfo->ri_PartitionCheck)
995  ExecConstraints(resultRelInfo, slot, estate);
996 
997  /*
998  * replace the heap tuple
999  *
1000  * Note: if es_crosscheck_snapshot isn't InvalidSnapshot, we check
1001  * that the row to be updated is visible to that snapshot, and throw a
1002  * can't-serialize error if not. This is a special-case behavior
1003  * needed for referential integrity updates in transaction-snapshot
1004  * mode transactions.
1005  */
1006  result = heap_update(resultRelationDesc, tupleid, tuple,
1007  estate->es_output_cid,
1008  estate->es_crosscheck_snapshot,
1009  true /* wait for commit */ ,
1010  &hufd, &lockmode);
1011  switch (result)
1012  {
1013  case HeapTupleSelfUpdated:
1014 
1015  /*
1016  * The target tuple was already updated or deleted by the
1017  * current command, or by a later command in the current
1018  * transaction. The former case is possible in a join UPDATE
1019  * where multiple tuples join to the same target tuple. This
1020  * is pretty questionable, but Postgres has always allowed it:
1021  * we just execute the first update action and ignore
1022  * additional update attempts.
1023  *
1024  * The latter case arises if the tuple is modified by a
1025  * command in a BEFORE trigger, or perhaps by a command in a
1026  * volatile function used in the query. In such situations we
1027  * should not ignore the update, but it is equally unsafe to
1028  * proceed. We don't want to discard the original UPDATE
1029  * while keeping the triggered actions based on it; and we
1030  * have no principled way to merge this update with the
1031  * previous ones. So throwing an error is the only safe
1032  * course.
1033  *
1034  * If a trigger actually intends this type of interaction, it
1035  * can re-execute the UPDATE (assuming it can figure out how)
1036  * and then return NULL to cancel the outer update.
1037  */
1038  if (hufd.cmax != estate->es_output_cid)
1039  ereport(ERROR,
1040  (errcode(ERRCODE_TRIGGERED_DATA_CHANGE_VIOLATION),
1041  errmsg("tuple to be updated was already modified by an operation triggered by the current command"),
1042  errhint("Consider using an AFTER trigger instead of a BEFORE trigger to propagate changes to other rows.")));
1043 
1044  /* Else, already updated by self; nothing to do */
1045  return NULL;
1046 
1047  case HeapTupleMayBeUpdated:
1048  break;
1049 
1050  case HeapTupleUpdated:
1052  ereport(ERROR,
1053  (errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
1054  errmsg("could not serialize access due to concurrent update")));
1055  if (!ItemPointerEquals(tupleid, &hufd.ctid))
1056  {
1057  TupleTableSlot *epqslot;
1058 
1059  epqslot = EvalPlanQual(estate,
1060  epqstate,
1061  resultRelationDesc,
1062  resultRelInfo->ri_RangeTableIndex,
1063  lockmode,
1064  &hufd.ctid,
1065  hufd.xmax);
1066  if (!TupIsNull(epqslot))
1067  {
1068  *tupleid = hufd.ctid;
1069  slot = ExecFilterJunk(resultRelInfo->ri_junkFilter, epqslot);
1070  tuple = ExecMaterializeSlot(slot);
1071  goto lreplace;
1072  }
1073  }
1074  /* tuple already deleted; nothing to do */
1075  return NULL;
1076 
1077  default:
1078  elog(ERROR, "unrecognized heap_update status: %u", result);
1079  return NULL;
1080  }
1081 
1082  /*
1083  * Note: instead of having to update the old index tuples associated
1084  * with the heap tuple, all we do is form and insert new index tuples.
1085  * This is because UPDATEs are actually DELETEs and INSERTs, and index
1086  * tuple deletion is done later by VACUUM (see notes in ExecDelete).
1087  * All we do here is insert new index tuples. -cim 9/27/89
1088  */
1089 
1090  /*
1091  * insert index entries for tuple
1092  *
1093  * Note: heap_update returns the tid (location) of the new tuple in
1094  * the t_self field.
1095  *
1096  * If it's a HOT update, we mustn't insert new index entries.
1097  */
1098  if (resultRelInfo->ri_NumIndices > 0 && !HeapTupleIsHeapOnly(tuple))
1099  recheckIndexes = ExecInsertIndexTuples(slot, &(tuple->t_self),
1100  estate, false, NULL, NIL);
1101  }
1102 
1103  if (canSetTag)
1104  (estate->es_processed)++;
1105 
1106  /* AFTER ROW UPDATE Triggers */
1107  ExecARUpdateTriggers(estate, resultRelInfo, tupleid, oldtuple, tuple,
1108  recheckIndexes);
1109 
1110  list_free(recheckIndexes);
1111 
1112  /*
1113  * Check any WITH CHECK OPTION constraints from parent views. We are
1114  * required to do this after testing all constraints and uniqueness
1115  * violations per the SQL spec, so we do it after actually updating the
1116  * record in the heap and all indexes.
1117  *
1118  * ExecWithCheckOptions() will skip any WCOs which are not of the kind we
1119  * are looking for at this point.
1120  */
1121  if (resultRelInfo->ri_WithCheckOptions != NIL)
1122  ExecWithCheckOptions(WCO_VIEW_CHECK, resultRelInfo, slot, estate);
1123 
1124  /* Process RETURNING if present */
1125  if (resultRelInfo->ri_projectReturning)
1126  return ExecProcessReturning(resultRelInfo, slot, planSlot);
1127 
1128  return NULL;
1129 }
int ri_NumIndices
Definition: execnodes.h:375
#define NIL
Definition: pg_list.h:69
JunkFilter * ri_junkFilter
Definition: execnodes.h:388
Relation ri_RelationDesc
Definition: execnodes.h:374
int errhint(const char *fmt,...)
Definition: elog.c:987
void ExecWithCheckOptions(WCOKind kind, ResultRelInfo *resultRelInfo, TupleTableSlot *slot, EState *estate)
Definition: execMain.c:1996
CommandId es_output_cid
Definition: execnodes.h:418
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:2380
TupleTableSlot * ExecBRUpdateTriggers(EState *estate, EPQState *epqstate, ResultRelInfo *relinfo, ItemPointer tupleid, HeapTuple fdw_trigtuple, TupleTableSlot *slot)
Definition: trigger.c:2598
void ExecConstraints(ResultRelInfo *resultRelInfo, TupleTableSlot *slot, EState *estate)
Definition: execMain.c:1831
#define IsolationUsesXactSnapshot()
Definition: xact.h:43
Snapshot es_crosscheck_snapshot
Definition: execnodes.h:410
int errcode(int sqlerrcode)
Definition: elog.c:575
return result
Definition: formatting.c:1618
Index ri_RangeTableIndex
Definition: execnodes.h:373
TupleTableSlot * ExecIRUpdateTriggers(EState *estate, ResultRelInfo *relinfo, HeapTuple trigtuple, TupleTableSlot *slot)
Definition: trigger.c:2748
LockTupleMode
Definition: heapam.h:38
#define ERROR
Definition: elog.h:43
ItemPointerData t_self
Definition: htup.h:65
void ExecARUpdateTriggers(EState *estate, ResultRelInfo *relinfo, ItemPointer tupleid, HeapTuple fdw_trigtuple, HeapTuple newtuple, List *recheckIndexes)
Definition: trigger.c:2715
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:389
#define TupIsNull(slot)
Definition: tuptable.h:138
struct FdwRoutine * ri_FdwRoutine
Definition: execnodes.h:382
Oid t_tableOid
Definition: htup.h:66
#define ereport(elevel, rest)
Definition: elog.h:122
TriggerDesc * ri_TrigDesc
Definition: execnodes.h:378
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:385
List * ri_PartitionCheck
Definition: execnodes.h:392
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:444
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:365
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:417
ResultRelInfo * es_result_relation_info
Definition: execnodes.h:423
static void fireASTriggers ( ModifyTableState node)
static

Definition at line 1355 of file nodeModifyTable.c.

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

Referenced by ExecModifyTable().

1356 {
1357  switch (node->operation)
1358  {
1359  case CMD_INSERT:
1360  if (node->mt_onconflict == ONCONFLICT_UPDATE)
1362  node->resultRelInfo);
1364  break;
1365  case CMD_UPDATE:
1367  break;
1368  case CMD_DELETE:
1370  break;
1371  default:
1372  elog(ERROR, "unknown operation");
1373  break;
1374  }
1375 }
void ExecASDeleteTriggers(EState *estate, ResultRelInfo *relinfo)
Definition: trigger.c:2376
void ExecASUpdateTriggers(EState *estate, ResultRelInfo *relinfo)
Definition: trigger.c:2587
ResultRelInfo * resultRelInfo
Definition: execnodes.h:916
CmdType operation
Definition: execnodes.h:910
EState * state
Definition: execnodes.h:805
OnConflictAction mt_onconflict
Definition: execnodes.h:920
#define ERROR
Definition: elog.h:43
PlanState ps
Definition: execnodes.h:909
void ExecASInsertTriggers(EState *estate, ResultRelInfo *relinfo)
Definition: trigger.c:2170
#define elog
Definition: elog.h:219
static void fireBSTriggers ( ModifyTableState node)
static

Definition at line 1329 of file nodeModifyTable.c.

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

Referenced by ExecModifyTable().

1330 {
1331  switch (node->operation)
1332  {
1333  case CMD_INSERT:
1335  if (node->mt_onconflict == ONCONFLICT_UPDATE)
1337  node->resultRelInfo);
1338  break;
1339  case CMD_UPDATE:
1341  break;
1342  case CMD_DELETE:
1344  break;
1345  default:
1346  elog(ERROR, "unknown operation");
1347  break;
1348  }
1349 }
void ExecBSDeleteTriggers(EState *estate, ResultRelInfo *relinfo)
Definition: trigger.c:2324
ResultRelInfo * resultRelInfo
Definition: execnodes.h:916
CmdType operation
Definition: execnodes.h:910
EState * state
Definition: execnodes.h:805
OnConflictAction mt_onconflict
Definition: execnodes.h:920
#define ERROR
Definition: elog.h:43
PlanState ps
Definition: execnodes.h:909
void ExecBSInsertTriggers(EState *estate, ResultRelInfo *relinfo)
Definition: trigger.c:2118
void ExecBSUpdateTriggers(EState *estate, ResultRelInfo *relinfo)
Definition: trigger.c:2532
#define elog
Definition: elog.h:219