1 /*-------------------------------------------------------------------------
2  *
3  * nodeModifyTable.c
4  *	  routines to handle ModifyTable nodes.
5  *
6  * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group
7  * Portions Copyright (c) 1994, Regents of the University of California
8  *
9  *
10  * IDENTIFICATION
11  *	  src/backend/executor/nodeModifyTable.c
12  *
13  *-------------------------------------------------------------------------
14  */
15 /* INTERFACE ROUTINES
16  *		ExecInitModifyTable - initialize the ModifyTable node
17  *		ExecModifyTable		- retrieve the next tuple from the node
18  *		ExecEndModifyTable	- shut down the ModifyTable node
19  *		ExecReScanModifyTable - rescan the ModifyTable node
20  *
21  *	 NOTES
22  *		Each ModifyTable node contains a list of one or more subplans,
23  *		much like an Append node.  There is one subplan per result relation.
24  *		The key reason for this is that in an inherited UPDATE command, each
25  *		result relation could have a different schema (more or different
26  *		columns) requiring a different plan tree to produce it.  In an
27  *		inherited DELETE, all the subplans should produce the same output
28  *		rowtype, but we might still find that different plans are appropriate
29  *		for different child relations.
30  *
31  *		If the query specifies RETURNING, then the ModifyTable returns a
32  *		RETURNING tuple after completing each row insert, update, or delete.
33  *		It must be called again to continue the operation.  Without RETURNING,
34  *		we just loop within the node until all the work is done, then
35  *		return NULL.  This avoids useless call/return overhead.
36  */
37 
38 #include "postgres.h"
39 
40 #include "access/htup_details.h"
41 #include "access/xact.h"
42 #include "commands/trigger.h"
43 #include "executor/executor.h"
44 #include "executor/nodeModifyTable.h"
45 #include "foreign/fdwapi.h"
46 #include "miscadmin.h"
47 #include "nodes/nodeFuncs.h"
48 #include "parser/parsetree.h"
49 #include "storage/bufmgr.h"
50 #include "storage/lmgr.h"
51 #include "utils/builtins.h"
52 #include "utils/memutils.h"
53 #include "utils/rel.h"
54 #include "utils/tqual.h"
55 
56 
57 static bool ExecOnConflictUpdate(ModifyTableState *mtstate,
58 					 ResultRelInfo *resultRelInfo,
59 					 ItemPointer conflictTid,
60 					 TupleTableSlot *planSlot,
61 					 TupleTableSlot *excludedSlot,
62 					 EState *estate,
63 					 bool canSetTag,
64 					 TupleTableSlot **returning);
65 static TupleTableSlot *ExecPrepareTupleRouting(ModifyTableState *mtstate,
66 						EState *estate,
67 						ResultRelInfo *targetRelInfo,
68 						TupleTableSlot *slot);
69 
70 /*
71  * Verify that the tuples to be produced by INSERT or UPDATE match the
72  * target relation's rowtype
73  *
74  * We do this to guard against stale plans.  If plan invalidation is
75  * functioning properly then we should never get a failure here, but better
76  * safe than sorry.  Note that this is called after we have obtained lock
77  * on the target rel, so the rowtype can't change underneath us.
78  *
79  * The plan output is represented by its targetlist, because that makes
80  * handling the dropped-column case easier.
81  */
82 static void
ExecCheckPlanOutput(Relation resultRel,List * targetList)83 ExecCheckPlanOutput(Relation resultRel, List *targetList)
84 {
85 	TupleDesc	resultDesc = RelationGetDescr(resultRel);
86 	int			attno = 0;
87 	ListCell   *lc;
88 
89 	foreach(lc, targetList)
90 	{
91 		TargetEntry *tle = (TargetEntry *) lfirst(lc);
92 		Form_pg_attribute attr;
93 
94 		if (tle->resjunk)
95 			continue;			/* ignore junk tlist items */
96 
97 		if (attno >= resultDesc->natts)
98 			ereport(ERROR,
99 					(errcode(ERRCODE_DATATYPE_MISMATCH),
100 					 errmsg("table row type and query-specified row type do not match"),
101 					 errdetail("Query has too many columns.")));
102 		attr = resultDesc->attrs[attno++];
103 
104 		if (!attr->attisdropped)
105 		{
106 			/* Normal case: demand type match */
107 			if (exprType((Node *) tle->expr) != attr->atttypid)
108 				ereport(ERROR,
109 						(errcode(ERRCODE_DATATYPE_MISMATCH),
110 						 errmsg("table row type and query-specified row type do not match"),
111 						 errdetail("Table has type %s at ordinal position %d, but query expects %s.",
112 								   format_type_be(attr->atttypid),
113 								   attno,
114 								   format_type_be(exprType((Node *) tle->expr)))));
115 		}
116 		else
117 		{
118 			/*
119 			 * For a dropped column, we can't check atttypid (it's likely 0).
120 			 * In any case the planner has most likely inserted an INT4 null.
121 			 * What we insist on is just *some* NULL constant.
122 			 */
123 			if (!IsA(tle->expr, Const) ||
124 				!((Const *) tle->expr)->constisnull)
125 				ereport(ERROR,
126 						(errcode(ERRCODE_DATATYPE_MISMATCH),
127 						 errmsg("table row type and query-specified row type do not match"),
128 						 errdetail("Query provides a value for a dropped column at ordinal position %d.",
129 								   attno)));
130 		}
131 	}
132 	if (attno != resultDesc->natts)
133 		ereport(ERROR,
134 				(errcode(ERRCODE_DATATYPE_MISMATCH),
135 				 errmsg("table row type and query-specified row type do not match"),
136 				 errdetail("Query has too few columns.")));
137 }
138 
139 /*
140  * ExecProcessReturning --- evaluate a RETURNING list
141  *
142  * projectReturning: RETURNING projection info for current result rel
143  * tupleSlot: slot holding tuple actually inserted/updated/deleted
144  * planSlot: slot holding tuple returned by top subplan node
145  *
146  * Note: If tupleSlot is NULL, the FDW should have already provided econtext's
147  * scan tuple.
148  *
149  * Returns a slot holding the result tuple
150  */
151 static TupleTableSlot *
ExecProcessReturning(ResultRelInfo * resultRelInfo,TupleTableSlot * tupleSlot,TupleTableSlot * planSlot)152 ExecProcessReturning(ResultRelInfo *resultRelInfo,
153 					 TupleTableSlot *tupleSlot,
154 					 TupleTableSlot *planSlot)
155 {
156 	ProjectionInfo *projectReturning = resultRelInfo->ri_projectReturning;
157 	ExprContext *econtext = projectReturning->pi_exprContext;
158 
159 	/*
160 	 * Reset per-tuple memory context to free any expression evaluation
161 	 * storage allocated in the previous cycle.
162 	 */
163 	ResetExprContext(econtext);
164 
165 	/* Make tuple and any needed join variables available to ExecProject */
166 	if (tupleSlot)
167 		econtext->ecxt_scantuple = tupleSlot;
168 	else
169 	{
170 		HeapTuple	tuple;
171 
172 		/*
173 		 * RETURNING expressions might reference the tableoid column, so
174 		 * initialize t_tableOid before evaluating them.
175 		 */
176 		Assert(!TupIsNull(econtext->ecxt_scantuple));
177 		tuple = ExecMaterializeSlot(econtext->ecxt_scantuple);
178 		tuple->t_tableOid = RelationGetRelid(resultRelInfo->ri_RelationDesc);
179 	}
180 	econtext->ecxt_outertuple = planSlot;
181 
182 	/* Compute the RETURNING expressions */
183 	return ExecProject(projectReturning);
184 }
185 
186 /*
187  * ExecCheckHeapTupleVisible -- verify heap tuple is visible
188  *
189  * It would not be consistent with guarantees of the higher isolation levels to
190  * proceed with avoiding insertion (taking speculative insertion's alternative
191  * path) on the basis of another tuple that is not visible to MVCC snapshot.
192  * Check for the need to raise a serialization failure, and do so as necessary.
193  */
194 static void
ExecCheckHeapTupleVisible(EState * estate,HeapTuple tuple,Buffer buffer)195 ExecCheckHeapTupleVisible(EState *estate,
196 						  HeapTuple tuple,
197 						  Buffer buffer)
198 {
199 	if (!IsolationUsesXactSnapshot())
200 		return;
201 
202 	/*
203 	 * We need buffer pin and lock to call HeapTupleSatisfiesVisibility.
204 	 * Caller should be holding pin, but not lock.
205 	 */
206 	LockBuffer(buffer, BUFFER_LOCK_SHARE);
207 	if (!HeapTupleSatisfiesVisibility(tuple, estate->es_snapshot, buffer))
208 	{
209 		/*
210 		 * We should not raise a serialization failure if the conflict is
211 		 * against a tuple inserted by our own transaction, even if it's not
212 		 * visible to our snapshot.  (This would happen, for example, if
213 		 * conflicting keys are proposed for insertion in a single command.)
214 		 */
215 		if (!TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmin(tuple->t_data)))
216 			ereport(ERROR,
217 					(errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
218 					 errmsg("could not serialize access due to concurrent update")));
219 	}
220 	LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
221 }
222 
223 /*
224  * ExecCheckTIDVisible -- convenience variant of ExecCheckHeapTupleVisible()
225  */
226 static void
ExecCheckTIDVisible(EState * estate,ResultRelInfo * relinfo,ItemPointer tid)227 ExecCheckTIDVisible(EState *estate,
228 					ResultRelInfo *relinfo,
229 					ItemPointer tid)
230 {
231 	Relation	rel = relinfo->ri_RelationDesc;
232 	Buffer		buffer;
233 	HeapTupleData tuple;
234 
235 	/* Redundantly check isolation level */
236 	if (!IsolationUsesXactSnapshot())
237 		return;
238 
239 	tuple.t_self = *tid;
240 	if (!heap_fetch(rel, SnapshotAny, &tuple, &buffer, false, NULL))
241 		elog(ERROR, "failed to fetch conflicting tuple for ON CONFLICT");
242 	ExecCheckHeapTupleVisible(estate, &tuple, buffer);
243 	ReleaseBuffer(buffer);
244 }
245 
246 /* ----------------------------------------------------------------
247  *		ExecInsert
248  *
249  *		For INSERT, we have to insert the tuple into the target relation
250  *		and insert appropriate tuples into the index relations.
251  *
252  *		Returns RETURNING result if any, otherwise NULL.
253  * ----------------------------------------------------------------
254  */
255 static TupleTableSlot *
ExecInsert(ModifyTableState * mtstate,TupleTableSlot * slot,TupleTableSlot * planSlot,List * arbiterIndexes,OnConflictAction onconflict,EState * estate,bool canSetTag)256 ExecInsert(ModifyTableState *mtstate,
257 		   TupleTableSlot *slot,
258 		   TupleTableSlot *planSlot,
259 		   List *arbiterIndexes,
260 		   OnConflictAction onconflict,
261 		   EState *estate,
262 		   bool canSetTag)
263 {
264 	HeapTuple	tuple;
265 	ResultRelInfo *resultRelInfo;
266 	Relation	resultRelationDesc;
267 	Oid			newId;
268 	List	   *recheckIndexes = NIL;
269 	TupleTableSlot *result = NULL;
270 
271 	/*
272 	 * get the heap tuple out of the tuple table slot, making sure we have a
273 	 * writable copy
274 	 */
275 	tuple = ExecMaterializeSlot(slot);
276 
277 	/*
278 	 * get information on the (current) result relation
279 	 */
280 	resultRelInfo = estate->es_result_relation_info;
281 	resultRelationDesc = resultRelInfo->ri_RelationDesc;
282 
283 	/*
284 	 * If the result relation has OIDs, force the tuple's OID to zero so that
285 	 * heap_insert will assign a fresh OID.  Usually the OID already will be
286 	 * zero at this point, but there are corner cases where the plan tree can
287 	 * return a tuple extracted literally from some table with the same
288 	 * rowtype.
289 	 *
290 	 * XXX if we ever wanted to allow users to assign their own OIDs to new
291 	 * rows, this'd be the place to do it.  For the moment, we make a point of
292 	 * doing this before calling triggers, so that a user-supplied trigger
293 	 * could hack the OID if desired.
294 	 */
295 	if (resultRelationDesc->rd_rel->relhasoids)
296 		HeapTupleSetOid(tuple, InvalidOid);
297 
298 	/*
299 	 * BEFORE ROW INSERT Triggers.
300 	 *
301 	 * Note: We fire BEFORE ROW TRIGGERS for every attempted insertion in an
302 	 * INSERT ... ON CONFLICT statement.  We cannot check for constraint
303 	 * violations before firing these triggers, because they can change the
304 	 * values to insert.  Also, they can run arbitrary user-defined code with
305 	 * side-effects that we can't cancel by just not inserting the tuple.
306 	 */
307 	if (resultRelInfo->ri_TrigDesc &&
308 		resultRelInfo->ri_TrigDesc->trig_insert_before_row)
309 	{
310 		slot = ExecBRInsertTriggers(estate, resultRelInfo, slot);
311 
312 		if (slot == NULL)		/* "do nothing" */
313 			return NULL;
314 
315 		/* trigger might have changed tuple */
316 		tuple = ExecMaterializeSlot(slot);
317 	}
318 
319 	/* INSTEAD OF ROW INSERT Triggers */
320 	if (resultRelInfo->ri_TrigDesc &&
321 		resultRelInfo->ri_TrigDesc->trig_insert_instead_row)
322 	{
323 		slot = ExecIRInsertTriggers(estate, resultRelInfo, slot);
324 
325 		if (slot == NULL)		/* "do nothing" */
326 			return NULL;
327 
328 		/* trigger might have changed tuple */
329 		tuple = ExecMaterializeSlot(slot);
330 
331 		newId = InvalidOid;
332 	}
333 	else if (resultRelInfo->ri_FdwRoutine)
334 	{
335 		/*
336 		 * insert into foreign table: let the FDW do it
337 		 */
338 		slot = resultRelInfo->ri_FdwRoutine->ExecForeignInsert(estate,
339 															   resultRelInfo,
340 															   slot,
341 															   planSlot);
342 
343 		if (slot == NULL)		/* "do nothing" */
344 			return NULL;
345 
346 		/* FDW might have changed tuple */
347 		tuple = ExecMaterializeSlot(slot);
348 
349 		/*
350 		 * AFTER ROW Triggers or RETURNING expressions might reference the
351 		 * tableoid column, so initialize t_tableOid before evaluating them.
352 		 */
353 		tuple->t_tableOid = RelationGetRelid(resultRelationDesc);
354 
355 		newId = InvalidOid;
356 	}
357 	else
358 	{
359 		/*
360 		 * We always check the partition constraint, including when the tuple
361 		 * got here via tuple-routing.  However we don't need to in the latter
362 		 * case if no BR trigger is defined on the partition.  Note that a BR
363 		 * trigger might modify the tuple such that the partition constraint
364 		 * is no longer satisfied, so we need to check in that case.
365 		 */
366 		bool		check_partition_constr =
367 		(resultRelInfo->ri_PartitionCheck != NIL);
368 
369 		/*
370 		 * Constraints might reference the tableoid column, so initialize
371 		 * t_tableOid before evaluating them.
372 		 */
373 		tuple->t_tableOid = RelationGetRelid(resultRelationDesc);
374 
375 		/*
376 		 * Check any RLS INSERT WITH CHECK policies
377 		 *
378 		 * ExecWithCheckOptions() will skip any WCOs which are not of the kind
379 		 * we are looking for at this point.
380 		 */
381 		if (resultRelInfo->ri_WithCheckOptions != NIL)
382 			ExecWithCheckOptions(WCO_RLS_INSERT_CHECK,
383 								 resultRelInfo, slot, estate);
384 
385 		/*
386 		 * No need though if the tuple has been routed, and a BR trigger
387 		 * doesn't exist.
388 		 */
389 		if (resultRelInfo->ri_PartitionRoot != NULL &&
390 			!(resultRelInfo->ri_TrigDesc &&
391 			  resultRelInfo->ri_TrigDesc->trig_insert_before_row))
392 			check_partition_constr = false;
393 
394 		/* Check the constraints of the tuple */
395 		if (resultRelationDesc->rd_att->constr || check_partition_constr)
396 			ExecConstraints(resultRelInfo, slot, estate);
397 
398 		if (onconflict != ONCONFLICT_NONE && resultRelInfo->ri_NumIndices > 0)
399 		{
400 			/* Perform a speculative insertion. */
401 			uint32		specToken;
402 			ItemPointerData conflictTid;
403 			bool		specConflict;
404 
405 			/*
406 			 * Do a non-conclusive check for conflicts first.
407 			 *
408 			 * We're not holding any locks yet, so this doesn't guarantee that
409 			 * the later insert won't conflict.  But it avoids leaving behind
410 			 * a lot of canceled speculative insertions, if you run a lot of
411 			 * INSERT ON CONFLICT statements that do conflict.
412 			 *
413 			 * We loop back here if we find a conflict below, either during
414 			 * the pre-check, or when we re-check after inserting the tuple
415 			 * speculatively.
416 			 */
417 	vlock:
418 			specConflict = false;
419 			if (!ExecCheckIndexConstraints(slot, estate, &conflictTid,
420 										   arbiterIndexes))
421 			{
422 				/* committed conflict tuple found */
423 				if (onconflict == ONCONFLICT_UPDATE)
424 				{
425 					/*
426 					 * In case of ON CONFLICT DO UPDATE, execute the UPDATE
427 					 * part.  Be prepared to retry if the UPDATE fails because
428 					 * of another concurrent UPDATE/DELETE to the conflict
429 					 * tuple.
430 					 */
431 					TupleTableSlot *returning = NULL;
432 
433 					if (ExecOnConflictUpdate(mtstate, resultRelInfo,
434 											 &conflictTid, planSlot, slot,
435 											 estate, canSetTag, &returning))
436 					{
437 						InstrCountFiltered2(&mtstate->ps, 1);
438 						return returning;
439 					}
440 					else
441 						goto vlock;
442 				}
443 				else
444 				{
445 					/*
446 					 * In case of ON CONFLICT DO NOTHING, do nothing. However,
447 					 * verify that the tuple is visible to the executor's MVCC
448 					 * snapshot at higher isolation levels.
449 					 */
450 					Assert(onconflict == ONCONFLICT_NOTHING);
451 					ExecCheckTIDVisible(estate, resultRelInfo, &conflictTid);
452 					InstrCountFiltered2(&mtstate->ps, 1);
453 					return NULL;
454 				}
455 			}
456 
457 			/*
458 			 * Before we start insertion proper, acquire our "speculative
459 			 * insertion lock".  Others can use that to wait for us to decide
460 			 * if we're going to go ahead with the insertion, instead of
461 			 * waiting for the whole transaction to complete.
462 			 */
463 			specToken = SpeculativeInsertionLockAcquire(GetCurrentTransactionId());
464 			HeapTupleHeaderSetSpeculativeToken(tuple->t_data, specToken);
465 
466 			/* insert the tuple, with the speculative token */
467 			newId = heap_insert(resultRelationDesc, tuple,
468 								estate->es_output_cid,
469 								HEAP_INSERT_SPECULATIVE,
470 								NULL);
471 
472 			/* insert index entries for tuple */
473 			recheckIndexes = ExecInsertIndexTuples(slot, &(tuple->t_self),
474 												   estate, true, &specConflict,
475 												   arbiterIndexes);
476 
477 			/* adjust the tuple's state accordingly */
478 			if (!specConflict)
479 				heap_finish_speculative(resultRelationDesc, tuple);
480 			else
481 				heap_abort_speculative(resultRelationDesc, tuple);
482 
483 			/*
484 			 * Wake up anyone waiting for our decision.  They will re-check
485 			 * the tuple, see that it's no longer speculative, and wait on our
486 			 * XID as if this was a regularly inserted tuple all along.  Or if
487 			 * we killed the tuple, they will see it's dead, and proceed as if
488 			 * the tuple never existed.
489 			 */
490 			SpeculativeInsertionLockRelease(GetCurrentTransactionId());
491 
492 			/*
493 			 * If there was a conflict, start from the beginning.  We'll do
494 			 * the pre-check again, which will now find the conflicting tuple
495 			 * (unless it aborts before we get there).
496 			 */
497 			if (specConflict)
498 			{
499 				list_free(recheckIndexes);
500 				goto vlock;
501 			}
502 
503 			/* Since there was no insertion conflict, we're done */
504 		}
505 		else
506 		{
507 			/*
508 			 * insert the tuple normally.
509 			 *
510 			 * Note: heap_insert returns the tid (location) of the new tuple
511 			 * in the t_self field.
512 			 */
513 			newId = heap_insert(resultRelationDesc, tuple,
514 								estate->es_output_cid,
515 								0, NULL);
516 
517 			/* insert index entries for tuple */
518 			if (resultRelInfo->ri_NumIndices > 0)
519 				recheckIndexes = ExecInsertIndexTuples(slot, &(tuple->t_self),
520 													   estate, false, NULL,
521 													   arbiterIndexes);
522 		}
523 	}
524 
525 	if (canSetTag)
526 	{
527 		(estate->es_processed)++;
528 		estate->es_lastoid = newId;
529 		setLastTid(&(tuple->t_self));
530 	}
531 
532 	/* AFTER ROW INSERT Triggers */
533 	ExecARInsertTriggers(estate, resultRelInfo, tuple, recheckIndexes,
534 						 mtstate->mt_transition_capture);
535 
536 	list_free(recheckIndexes);
537 
538 	/*
539 	 * Check any WITH CHECK OPTION constraints from parent views.  We are
540 	 * required to do this after testing all constraints and uniqueness
541 	 * violations per the SQL spec, so we do it after actually inserting the
542 	 * record into the heap and all indexes.
543 	 *
544 	 * ExecWithCheckOptions will elog(ERROR) if a violation is found, so the
545 	 * tuple will never be seen, if it violates the WITH CHECK OPTION.
546 	 *
547 	 * ExecWithCheckOptions() will skip any WCOs which are not of the kind we
548 	 * are looking for at this point.
549 	 */
550 	if (resultRelInfo->ri_WithCheckOptions != NIL)
551 		ExecWithCheckOptions(WCO_VIEW_CHECK, resultRelInfo, slot, estate);
552 
553 	/* Process RETURNING if present */
554 	if (resultRelInfo->ri_projectReturning)
555 		result = ExecProcessReturning(resultRelInfo, slot, planSlot);
556 
557 	return result;
558 }
559 
560 /* ----------------------------------------------------------------
561  *		ExecDelete
562  *
563  *		DELETE is like UPDATE, except that we delete the tuple and no
564  *		index modifications are needed.
565  *
566  *		When deleting from a table, tupleid identifies the tuple to
567  *		delete and oldtuple is NULL.  When deleting from a view,
568  *		oldtuple is passed to the INSTEAD OF triggers and identifies
569  *		what to delete, and tupleid is invalid.  When deleting from a
570  *		foreign table, tupleid is invalid; the FDW has to figure out
571  *		which row to delete using data from the planSlot.  oldtuple is
572  *		passed to foreign table triggers; it is NULL when the foreign
573  *		table has no relevant triggers.
574  *
575  *		Returns RETURNING result if any, otherwise NULL.
576  * ----------------------------------------------------------------
577  */
578 static TupleTableSlot *
ExecDelete(ModifyTableState * mtstate,ItemPointer tupleid,HeapTuple oldtuple,TupleTableSlot * planSlot,EPQState * epqstate,EState * estate,bool canSetTag)579 ExecDelete(ModifyTableState *mtstate,
580 		   ItemPointer tupleid,
581 		   HeapTuple oldtuple,
582 		   TupleTableSlot *planSlot,
583 		   EPQState *epqstate,
584 		   EState *estate,
585 		   bool canSetTag)
586 {
587 	ResultRelInfo *resultRelInfo;
588 	Relation	resultRelationDesc;
589 	HTSU_Result result;
590 	HeapUpdateFailureData hufd;
591 	TupleTableSlot *slot = NULL;
592 
593 	/*
594 	 * get information on the (current) result relation
595 	 */
596 	resultRelInfo = estate->es_result_relation_info;
597 	resultRelationDesc = resultRelInfo->ri_RelationDesc;
598 
599 	/* BEFORE ROW DELETE Triggers */
600 	if (resultRelInfo->ri_TrigDesc &&
601 		resultRelInfo->ri_TrigDesc->trig_delete_before_row)
602 	{
603 		bool		dodelete;
604 
605 		dodelete = ExecBRDeleteTriggers(estate, epqstate, resultRelInfo,
606 										tupleid, oldtuple);
607 
608 		if (!dodelete)			/* "do nothing" */
609 			return NULL;
610 	}
611 
612 	/* INSTEAD OF ROW DELETE Triggers */
613 	if (resultRelInfo->ri_TrigDesc &&
614 		resultRelInfo->ri_TrigDesc->trig_delete_instead_row)
615 	{
616 		bool		dodelete;
617 
618 		Assert(oldtuple != NULL);
619 		dodelete = ExecIRDeleteTriggers(estate, resultRelInfo, oldtuple);
620 
621 		if (!dodelete)			/* "do nothing" */
622 			return NULL;
623 	}
624 	else if (resultRelInfo->ri_FdwRoutine)
625 	{
626 		HeapTuple	tuple;
627 
628 		/*
629 		 * delete from foreign table: let the FDW do it
630 		 *
631 		 * We offer the trigger tuple slot as a place to store RETURNING data,
632 		 * although the FDW can return some other slot if it wants.  Set up
633 		 * the slot's tupdesc so the FDW doesn't need to do that for itself.
634 		 */
635 		slot = estate->es_trig_tuple_slot;
636 		if (slot->tts_tupleDescriptor != RelationGetDescr(resultRelationDesc))
637 			ExecSetSlotDescriptor(slot, RelationGetDescr(resultRelationDesc));
638 
639 		slot = resultRelInfo->ri_FdwRoutine->ExecForeignDelete(estate,
640 															   resultRelInfo,
641 															   slot,
642 															   planSlot);
643 
644 		if (slot == NULL)		/* "do nothing" */
645 			return NULL;
646 
647 		/*
648 		 * RETURNING expressions might reference the tableoid column, so
649 		 * initialize t_tableOid before evaluating them.
650 		 */
651 		if (slot->tts_isempty)
652 			ExecStoreAllNullTuple(slot);
653 		tuple = ExecMaterializeSlot(slot);
654 		tuple->t_tableOid = RelationGetRelid(resultRelationDesc);
655 	}
656 	else
657 	{
658 		/*
659 		 * delete the tuple
660 		 *
661 		 * Note: if es_crosscheck_snapshot isn't InvalidSnapshot, we check
662 		 * that the row to be deleted is visible to that snapshot, and throw a
663 		 * can't-serialize error if not. This is a special-case behavior
664 		 * needed for referential integrity updates in transaction-snapshot
665 		 * mode transactions.
666 		 */
667 ldelete:;
668 		result = heap_delete(resultRelationDesc, tupleid,
669 							 estate->es_output_cid,
670 							 estate->es_crosscheck_snapshot,
671 							 true /* wait for commit */ ,
672 							 &hufd);
673 		switch (result)
674 		{
675 			case HeapTupleSelfUpdated:
676 
677 				/*
678 				 * The target tuple was already updated or deleted by the
679 				 * current command, or by a later command in the current
680 				 * transaction.  The former case is possible in a join DELETE
681 				 * where multiple tuples join to the same target tuple. This
682 				 * is somewhat questionable, but Postgres has always allowed
683 				 * it: we just ignore additional deletion attempts.
684 				 *
685 				 * The latter case arises if the tuple is modified by a
686 				 * command in a BEFORE trigger, or perhaps by a command in a
687 				 * volatile function used in the query.  In such situations we
688 				 * should not ignore the deletion, but it is equally unsafe to
689 				 * proceed.  We don't want to discard the original DELETE
690 				 * while keeping the triggered actions based on its deletion;
691 				 * and it would be no better to allow the original DELETE
692 				 * while discarding updates that it triggered.  The row update
693 				 * carries some information that might be important according
694 				 * to business rules; so throwing an error is the only safe
695 				 * course.
696 				 *
697 				 * If a trigger actually intends this type of interaction, it
698 				 * can re-execute the DELETE and then return NULL to cancel
699 				 * the outer delete.
700 				 */
701 				if (hufd.cmax != estate->es_output_cid)
702 					ereport(ERROR,
703 							(errcode(ERRCODE_TRIGGERED_DATA_CHANGE_VIOLATION),
704 							 errmsg("tuple to be updated was already modified by an operation triggered by the current command"),
705 							 errhint("Consider using an AFTER trigger instead of a BEFORE trigger to propagate changes to other rows.")));
706 
707 				/* Else, already deleted by self; nothing to do */
708 				return NULL;
709 
710 			case HeapTupleMayBeUpdated:
711 				break;
712 
713 			case HeapTupleUpdated:
714 				if (IsolationUsesXactSnapshot())
715 					ereport(ERROR,
716 							(errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
717 							 errmsg("could not serialize access due to concurrent update")));
718 				if (!ItemPointerEquals(tupleid, &hufd.ctid))
719 				{
720 					TupleTableSlot *epqslot;
721 
722 					epqslot = EvalPlanQual(estate,
723 										   epqstate,
724 										   resultRelationDesc,
725 										   resultRelInfo->ri_RangeTableIndex,
726 										   LockTupleExclusive,
727 										   &hufd.ctid,
728 										   hufd.xmax);
729 					if (!TupIsNull(epqslot))
730 					{
731 						*tupleid = hufd.ctid;
732 						goto ldelete;
733 					}
734 				}
735 				/* tuple already deleted; nothing to do */
736 				return NULL;
737 
738 			default:
739 				elog(ERROR, "unrecognized heap_delete status: %u", result);
740 				return NULL;
741 		}
742 
743 		/*
744 		 * Note: Normally one would think that we have to delete index tuples
745 		 * associated with the heap tuple now...
746 		 *
747 		 * ... but in POSTGRES, we have no need to do this because VACUUM will
748 		 * take care of it later.  We can't delete index tuples immediately
749 		 * anyway, since the tuple is still visible to other transactions.
750 		 */
751 	}
752 
753 	if (canSetTag)
754 		(estate->es_processed)++;
755 
756 	/* AFTER ROW DELETE Triggers */
757 	ExecARDeleteTriggers(estate, resultRelInfo, tupleid, oldtuple,
758 						 mtstate->mt_transition_capture);
759 
760 	/* Process RETURNING if present */
761 	if (resultRelInfo->ri_projectReturning)
762 	{
763 		/*
764 		 * We have to put the target tuple into a slot, which means first we
765 		 * gotta fetch it.  We can use the trigger tuple slot.
766 		 */
767 		TupleTableSlot *rslot;
768 		HeapTupleData deltuple;
769 		Buffer		delbuffer;
770 
771 		if (resultRelInfo->ri_FdwRoutine)
772 		{
773 			/* FDW must have provided a slot containing the deleted row */
774 			Assert(!TupIsNull(slot));
775 			delbuffer = InvalidBuffer;
776 		}
777 		else
778 		{
779 			slot = estate->es_trig_tuple_slot;
780 			if (oldtuple != NULL)
781 			{
782 				deltuple = *oldtuple;
783 				delbuffer = InvalidBuffer;
784 			}
785 			else
786 			{
787 				deltuple.t_self = *tupleid;
788 				if (!heap_fetch(resultRelationDesc, SnapshotAny,
789 								&deltuple, &delbuffer, false, NULL))
790 					elog(ERROR, "failed to fetch deleted tuple for DELETE RETURNING");
791 			}
792 
793 			if (slot->tts_tupleDescriptor != RelationGetDescr(resultRelationDesc))
794 				ExecSetSlotDescriptor(slot, RelationGetDescr(resultRelationDesc));
795 			ExecStoreTuple(&deltuple, slot, InvalidBuffer, false);
796 		}
797 
798 		rslot = ExecProcessReturning(resultRelInfo, slot, planSlot);
799 
800 		/*
801 		 * Before releasing the target tuple again, make sure rslot has a
802 		 * local copy of any pass-by-reference values.
803 		 */
804 		ExecMaterializeSlot(rslot);
805 
806 		ExecClearTuple(slot);
807 		if (BufferIsValid(delbuffer))
808 			ReleaseBuffer(delbuffer);
809 
810 		return rslot;
811 	}
812 
813 	return NULL;
814 }
815 
816 /* ----------------------------------------------------------------
817  *		ExecUpdate
818  *
819  *		note: we can't run UPDATE queries with transactions
820  *		off because UPDATEs are actually INSERTs and our
821  *		scan will mistakenly loop forever, updating the tuple
822  *		it just inserted..  This should be fixed but until it
823  *		is, we don't want to get stuck in an infinite loop
824  *		which corrupts your database..
825  *
826  *		When updating a table, tupleid identifies the tuple to
827  *		update and oldtuple is NULL.  When updating a view, oldtuple
828  *		is passed to the INSTEAD OF triggers and identifies what to
829  *		update, and tupleid is invalid.  When updating a foreign table,
830  *		tupleid is invalid; the FDW has to figure out which row to
831  *		update using data from the planSlot.  oldtuple is passed to
832  *		foreign table triggers; it is NULL when the foreign table has
833  *		no relevant triggers.
834  *
835  *		Returns RETURNING result if any, otherwise NULL.
836  * ----------------------------------------------------------------
837  */
838 static TupleTableSlot *
ExecUpdate(ModifyTableState * mtstate,ItemPointer tupleid,HeapTuple oldtuple,TupleTableSlot * slot,TupleTableSlot * planSlot,EPQState * epqstate,EState * estate,bool canSetTag)839 ExecUpdate(ModifyTableState *mtstate,
840 		   ItemPointer tupleid,
841 		   HeapTuple oldtuple,
842 		   TupleTableSlot *slot,
843 		   TupleTableSlot *planSlot,
844 		   EPQState *epqstate,
845 		   EState *estate,
846 		   bool canSetTag)
847 {
848 	HeapTuple	tuple;
849 	ResultRelInfo *resultRelInfo;
850 	Relation	resultRelationDesc;
851 	HTSU_Result result;
852 	HeapUpdateFailureData hufd;
853 	List	   *recheckIndexes = NIL;
854 
855 	/*
856 	 * abort the operation if not running transactions
857 	 */
858 	if (IsBootstrapProcessingMode())
859 		elog(ERROR, "cannot UPDATE during bootstrap");
860 
861 	/*
862 	 * get the heap tuple out of the tuple table slot, making sure we have a
863 	 * writable copy
864 	 */
865 	tuple = ExecMaterializeSlot(slot);
866 
867 	/*
868 	 * get information on the (current) result relation
869 	 */
870 	resultRelInfo = estate->es_result_relation_info;
871 	resultRelationDesc = resultRelInfo->ri_RelationDesc;
872 
873 	/* BEFORE ROW UPDATE Triggers */
874 	if (resultRelInfo->ri_TrigDesc &&
875 		resultRelInfo->ri_TrigDesc->trig_update_before_row)
876 	{
877 		slot = ExecBRUpdateTriggers(estate, epqstate, resultRelInfo,
878 									tupleid, oldtuple, slot);
879 
880 		if (slot == NULL)		/* "do nothing" */
881 			return NULL;
882 
883 		/* trigger might have changed tuple */
884 		tuple = ExecMaterializeSlot(slot);
885 	}
886 
887 	/* INSTEAD OF ROW UPDATE Triggers */
888 	if (resultRelInfo->ri_TrigDesc &&
889 		resultRelInfo->ri_TrigDesc->trig_update_instead_row)
890 	{
891 		slot = ExecIRUpdateTriggers(estate, resultRelInfo,
892 									oldtuple, slot);
893 
894 		if (slot == NULL)		/* "do nothing" */
895 			return NULL;
896 
897 		/* trigger might have changed tuple */
898 		tuple = ExecMaterializeSlot(slot);
899 	}
900 	else if (resultRelInfo->ri_FdwRoutine)
901 	{
902 		/*
903 		 * update in foreign table: let the FDW do it
904 		 */
905 		slot = resultRelInfo->ri_FdwRoutine->ExecForeignUpdate(estate,
906 															   resultRelInfo,
907 															   slot,
908 															   planSlot);
909 
910 		if (slot == NULL)		/* "do nothing" */
911 			return NULL;
912 
913 		/* FDW might have changed tuple */
914 		tuple = ExecMaterializeSlot(slot);
915 
916 		/*
917 		 * AFTER ROW Triggers or RETURNING expressions might reference the
918 		 * tableoid column, so initialize t_tableOid before evaluating them.
919 		 */
920 		tuple->t_tableOid = RelationGetRelid(resultRelationDesc);
921 	}
922 	else
923 	{
924 		LockTupleMode lockmode;
925 
926 		/*
927 		 * Constraints might reference the tableoid column, so initialize
928 		 * t_tableOid before evaluating them.
929 		 */
930 		tuple->t_tableOid = RelationGetRelid(resultRelationDesc);
931 
932 		/*
933 		 * Check any RLS UPDATE WITH CHECK policies
934 		 *
935 		 * If we generate a new candidate tuple after EvalPlanQual testing, we
936 		 * must loop back here and recheck any RLS policies and constraints.
937 		 * (We don't need to redo triggers, however.  If there are any BEFORE
938 		 * triggers then trigger.c will have done heap_lock_tuple to lock the
939 		 * correct tuple, so there's no need to do them again.)
940 		 *
941 		 * ExecWithCheckOptions() will skip any WCOs which are not of the kind
942 		 * we are looking for at this point.
943 		 */
944 lreplace:;
945 		if (resultRelInfo->ri_WithCheckOptions != NIL)
946 			ExecWithCheckOptions(WCO_RLS_UPDATE_CHECK,
947 								 resultRelInfo, slot, estate);
948 
949 		/*
950 		 * Check the constraints of the tuple
951 		 */
952 		if (resultRelationDesc->rd_att->constr || resultRelInfo->ri_PartitionCheck)
953 			ExecConstraints(resultRelInfo, slot, estate);
954 
955 		/*
956 		 * replace the heap tuple
957 		 *
958 		 * Note: if es_crosscheck_snapshot isn't InvalidSnapshot, we check
959 		 * that the row to be updated is visible to that snapshot, and throw a
960 		 * can't-serialize error if not. This is a special-case behavior
961 		 * needed for referential integrity updates in transaction-snapshot
962 		 * mode transactions.
963 		 */
964 		result = heap_update(resultRelationDesc, tupleid, tuple,
965 							 estate->es_output_cid,
966 							 estate->es_crosscheck_snapshot,
967 							 true /* wait for commit */ ,
968 							 &hufd, &lockmode);
969 		switch (result)
970 		{
971 			case HeapTupleSelfUpdated:
972 
973 				/*
974 				 * The target tuple was already updated or deleted by the
975 				 * current command, or by a later command in the current
976 				 * transaction.  The former case is possible in a join UPDATE
977 				 * where multiple tuples join to the same target tuple. This
978 				 * is pretty questionable, but Postgres has always allowed it:
979 				 * we just execute the first update action and ignore
980 				 * additional update attempts.
981 				 *
982 				 * The latter case arises if the tuple is modified by a
983 				 * command in a BEFORE trigger, or perhaps by a command in a
984 				 * volatile function used in the query.  In such situations we
985 				 * should not ignore the update, but it is equally unsafe to
986 				 * proceed.  We don't want to discard the original UPDATE
987 				 * while keeping the triggered actions based on it; and we
988 				 * have no principled way to merge this update with the
989 				 * previous ones.  So throwing an error is the only safe
990 				 * course.
991 				 *
992 				 * If a trigger actually intends this type of interaction, it
993 				 * can re-execute the UPDATE (assuming it can figure out how)
994 				 * and then return NULL to cancel the outer update.
995 				 */
996 				if (hufd.cmax != estate->es_output_cid)
997 					ereport(ERROR,
998 							(errcode(ERRCODE_TRIGGERED_DATA_CHANGE_VIOLATION),
999 							 errmsg("tuple to be updated was already modified by an operation triggered by the current command"),
1000 							 errhint("Consider using an AFTER trigger instead of a BEFORE trigger to propagate changes to other rows.")));
1001 
1002 				/* Else, already updated by self; nothing to do */
1003 				return NULL;
1004 
1005 			case HeapTupleMayBeUpdated:
1006 				break;
1007 
1008 			case HeapTupleUpdated:
1009 				if (IsolationUsesXactSnapshot())
1010 					ereport(ERROR,
1011 							(errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
1012 							 errmsg("could not serialize access due to concurrent update")));
1013 				if (!ItemPointerEquals(tupleid, &hufd.ctid))
1014 				{
1015 					TupleTableSlot *epqslot;
1016 
1017 					epqslot = EvalPlanQual(estate,
1018 										   epqstate,
1019 										   resultRelationDesc,
1020 										   resultRelInfo->ri_RangeTableIndex,
1021 										   lockmode,
1022 										   &hufd.ctid,
1023 										   hufd.xmax);
1024 					if (!TupIsNull(epqslot))
1025 					{
1026 						*tupleid = hufd.ctid;
1027 						slot = ExecFilterJunk(resultRelInfo->ri_junkFilter, epqslot);
1028 						tuple = ExecMaterializeSlot(slot);
1029 						goto lreplace;
1030 					}
1031 				}
1032 				/* tuple already deleted; nothing to do */
1033 				return NULL;
1034 
1035 			default:
1036 				elog(ERROR, "unrecognized heap_update status: %u", result);
1037 				return NULL;
1038 		}
1039 
1040 		/*
1041 		 * Note: instead of having to update the old index tuples associated
1042 		 * with the heap tuple, all we do is form and insert new index tuples.
1043 		 * This is because UPDATEs are actually DELETEs and INSERTs, and index
1044 		 * tuple deletion is done later by VACUUM (see notes in ExecDelete).
1045 		 * All we do here is insert new index tuples.  -cim 9/27/89
1046 		 */
1047 
1048 		/*
1049 		 * insert index entries for tuple
1050 		 *
1051 		 * Note: heap_update returns the tid (location) of the new tuple in
1052 		 * the t_self field.
1053 		 *
1054 		 * If it's a HOT update, we mustn't insert new index entries.
1055 		 */
1056 		if (resultRelInfo->ri_NumIndices > 0 && !HeapTupleIsHeapOnly(tuple))
1057 			recheckIndexes = ExecInsertIndexTuples(slot, &(tuple->t_self),
1058 												   estate, false, NULL, NIL);
1059 	}
1060 
1061 	if (canSetTag)
1062 		(estate->es_processed)++;
1063 
1064 	/* AFTER ROW UPDATE Triggers */
1065 	ExecARUpdateTriggers(estate, resultRelInfo, tupleid, oldtuple, tuple,
1066 						 recheckIndexes,
1067 						 mtstate->operation == CMD_INSERT ?
1068 						 mtstate->mt_oc_transition_capture :
1069 						 mtstate->mt_transition_capture);
1070 
1071 	list_free(recheckIndexes);
1072 
1073 	/*
1074 	 * Check any WITH CHECK OPTION constraints from parent views.  We are
1075 	 * required to do this after testing all constraints and uniqueness
1076 	 * violations per the SQL spec, so we do it after actually updating the
1077 	 * record in the heap and all indexes.
1078 	 *
1079 	 * ExecWithCheckOptions() will skip any WCOs which are not of the kind we
1080 	 * are looking for at this point.
1081 	 */
1082 	if (resultRelInfo->ri_WithCheckOptions != NIL)
1083 		ExecWithCheckOptions(WCO_VIEW_CHECK, resultRelInfo, slot, estate);
1084 
1085 	/* Process RETURNING if present */
1086 	if (resultRelInfo->ri_projectReturning)
1087 		return ExecProcessReturning(resultRelInfo, slot, planSlot);
1088 
1089 	return NULL;
1090 }
1091 
1092 /*
1093  * ExecOnConflictUpdate --- execute UPDATE of INSERT ON CONFLICT DO UPDATE
1094  *
1095  * Try to lock tuple for update as part of speculative insertion.  If
1096  * a qual originating from ON CONFLICT DO UPDATE is satisfied, update
1097  * (but still lock row, even though it may not satisfy estate's
1098  * snapshot).
1099  *
1100  * Returns true if we're done (with or without an update), or false if
1101  * the caller must retry the INSERT from scratch.
1102  */
1103 static bool
ExecOnConflictUpdate(ModifyTableState * mtstate,ResultRelInfo * resultRelInfo,ItemPointer conflictTid,TupleTableSlot * planSlot,TupleTableSlot * excludedSlot,EState * estate,bool canSetTag,TupleTableSlot ** returning)1104 ExecOnConflictUpdate(ModifyTableState *mtstate,
1105 					 ResultRelInfo *resultRelInfo,
1106 					 ItemPointer conflictTid,
1107 					 TupleTableSlot *planSlot,
1108 					 TupleTableSlot *excludedSlot,
1109 					 EState *estate,
1110 					 bool canSetTag,
1111 					 TupleTableSlot **returning)
1112 {
1113 	ExprContext *econtext = mtstate->ps.ps_ExprContext;
1114 	Relation	relation = resultRelInfo->ri_RelationDesc;
1115 	ExprState  *onConflictSetWhere = resultRelInfo->ri_onConflictSetWhere;
1116 	HeapTupleData tuple;
1117 	HeapUpdateFailureData hufd;
1118 	LockTupleMode lockmode;
1119 	HTSU_Result test;
1120 	Buffer		buffer;
1121 
1122 	/* Determine lock mode to use */
1123 	lockmode = ExecUpdateLockMode(estate, resultRelInfo);
1124 
1125 	/*
1126 	 * Lock tuple for update.  Don't follow updates when tuple cannot be
1127 	 * locked without doing so.  A row locking conflict here means our
1128 	 * previous conclusion that the tuple is conclusively committed is not
1129 	 * true anymore.
1130 	 */
1131 	tuple.t_self = *conflictTid;
1132 	test = heap_lock_tuple(relation, &tuple, estate->es_output_cid,
1133 						   lockmode, LockWaitBlock, false, &buffer,
1134 						   &hufd);
1135 	switch (test)
1136 	{
1137 		case HeapTupleMayBeUpdated:
1138 			/* success! */
1139 			break;
1140 
1141 		case HeapTupleInvisible:
1142 
1143 			/*
1144 			 * This can occur when a just inserted tuple is updated again in
1145 			 * the same command. E.g. because multiple rows with the same
1146 			 * conflicting key values are inserted.
1147 			 *
1148 			 * This is somewhat similar to the ExecUpdate()
1149 			 * HeapTupleSelfUpdated case.  We do not want to proceed because
1150 			 * it would lead to the same row being updated a second time in
1151 			 * some unspecified order, and in contrast to plain UPDATEs
1152 			 * there's no historical behavior to break.
1153 			 *
1154 			 * It is the user's responsibility to prevent this situation from
1155 			 * occurring.  These problems are why SQL-2003 similarly specifies
1156 			 * that for SQL MERGE, an exception must be raised in the event of
1157 			 * an attempt to update the same row twice.
1158 			 */
1159 			if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmin(tuple.t_data)))
1160 				ereport(ERROR,
1161 						(errcode(ERRCODE_CARDINALITY_VIOLATION),
1162 						 errmsg("ON CONFLICT DO UPDATE command cannot affect row a second time"),
1163 						 errhint("Ensure that no rows proposed for insertion within the same command have duplicate constrained values.")));
1164 
1165 			/* This shouldn't happen */
1166 			elog(ERROR, "attempted to lock invisible tuple");
1167 
1168 		case HeapTupleSelfUpdated:
1169 
1170 			/*
1171 			 * This state should never be reached. As a dirty snapshot is used
1172 			 * to find conflicting tuples, speculative insertion wouldn't have
1173 			 * seen this row to conflict with.
1174 			 */
1175 			elog(ERROR, "unexpected self-updated tuple");
1176 
1177 		case HeapTupleUpdated:
1178 			if (IsolationUsesXactSnapshot())
1179 				ereport(ERROR,
1180 						(errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
1181 						 errmsg("could not serialize access due to concurrent update")));
1182 
1183 			/*
1184 			 * Tell caller to try again from the very start.
1185 			 *
1186 			 * It does not make sense to use the usual EvalPlanQual() style
1187 			 * loop here, as the new version of the row might not conflict
1188 			 * anymore, or the conflicting tuple has actually been deleted.
1189 			 */
1190 			ReleaseBuffer(buffer);
1191 			return false;
1192 
1193 		default:
1194 			elog(ERROR, "unrecognized heap_lock_tuple status: %u", test);
1195 	}
1196 
1197 	/*
1198 	 * Success, the tuple is locked.
1199 	 *
1200 	 * Reset per-tuple memory context to free any expression evaluation
1201 	 * storage allocated in the previous cycle.
1202 	 */
1203 	ResetExprContext(econtext);
1204 
1205 	/*
1206 	 * Verify that the tuple is visible to our MVCC snapshot if the current
1207 	 * isolation level mandates that.
1208 	 *
1209 	 * It's not sufficient to rely on the check within ExecUpdate() as e.g.
1210 	 * CONFLICT ... WHERE clause may prevent us from reaching that.
1211 	 *
1212 	 * This means we only ever continue when a new command in the current
1213 	 * transaction could see the row, even though in READ COMMITTED mode the
1214 	 * tuple will not be visible according to the current statement's
1215 	 * snapshot.  This is in line with the way UPDATE deals with newer tuple
1216 	 * versions.
1217 	 */
1218 	ExecCheckHeapTupleVisible(estate, &tuple, buffer);
1219 
1220 	/* Store target's existing tuple in the state's dedicated slot */
1221 	ExecStoreTuple(&tuple, mtstate->mt_existing, buffer, false);
1222 
1223 	/*
1224 	 * Make tuple and any needed join variables available to ExecQual and
1225 	 * ExecProject.  The EXCLUDED tuple is installed in ecxt_innertuple, while
1226 	 * the target's existing tuple is installed in the scantuple.  EXCLUDED
1227 	 * has been made to reference INNER_VAR in setrefs.c, but there is no
1228 	 * other redirection.
1229 	 */
1230 	econtext->ecxt_scantuple = mtstate->mt_existing;
1231 	econtext->ecxt_innertuple = excludedSlot;
1232 	econtext->ecxt_outertuple = NULL;
1233 
1234 	if (!ExecQual(onConflictSetWhere, econtext))
1235 	{
1236 		ReleaseBuffer(buffer);
1237 		InstrCountFiltered1(&mtstate->ps, 1);
1238 		return true;			/* done with the tuple */
1239 	}
1240 
1241 	if (resultRelInfo->ri_WithCheckOptions != NIL)
1242 	{
1243 		/*
1244 		 * Check target's existing tuple against UPDATE-applicable USING
1245 		 * security barrier quals (if any), enforced here as RLS checks/WCOs.
1246 		 *
1247 		 * The rewriter creates UPDATE RLS checks/WCOs for UPDATE security
1248 		 * quals, and stores them as WCOs of "kind" WCO_RLS_CONFLICT_CHECK,
1249 		 * but that's almost the extent of its special handling for ON
1250 		 * CONFLICT DO UPDATE.
1251 		 *
1252 		 * The rewriter will also have associated UPDATE applicable straight
1253 		 * RLS checks/WCOs for the benefit of the ExecUpdate() call that
1254 		 * follows.  INSERTs and UPDATEs naturally have mutually exclusive WCO
1255 		 * kinds, so there is no danger of spurious over-enforcement in the
1256 		 * INSERT or UPDATE path.
1257 		 */
1258 		ExecWithCheckOptions(WCO_RLS_CONFLICT_CHECK, resultRelInfo,
1259 							 mtstate->mt_existing,
1260 							 mtstate->ps.state);
1261 	}
1262 
1263 	/* Project the new tuple version */
1264 	ExecProject(resultRelInfo->ri_onConflictSetProj);
1265 
1266 	/*
1267 	 * Note that it is possible that the target tuple has been modified in
1268 	 * this session, after the above heap_lock_tuple. We choose to not error
1269 	 * out in that case, in line with ExecUpdate's treatment of similar cases.
1270 	 * This can happen if an UPDATE is triggered from within ExecQual(),
1271 	 * ExecWithCheckOptions() or ExecProject() above, e.g. by selecting from a
1272 	 * wCTE in the ON CONFLICT's SET.
1273 	 */
1274 
1275 	/* Execute UPDATE with projection */
1276 	*returning = ExecUpdate(mtstate, &tuple.t_self, NULL,
1277 							mtstate->mt_conflproj, planSlot,
1278 							&mtstate->mt_epqstate, mtstate->ps.state,
1279 							canSetTag);
1280 
1281 	ReleaseBuffer(buffer);
1282 	return true;
1283 }
1284 
1285 
1286 /*
1287  * Process BEFORE EACH STATEMENT triggers
1288  */
1289 static void
fireBSTriggers(ModifyTableState * node)1290 fireBSTriggers(ModifyTableState *node)
1291 {
1292 	ResultRelInfo *resultRelInfo = node->resultRelInfo;
1293 
1294 	/*
1295 	 * If the node modifies a partitioned table, we must fire its triggers.
1296 	 * Note that in that case, node->resultRelInfo points to the first leaf
1297 	 * partition, not the root table.
1298 	 */
1299 	if (node->rootResultRelInfo != NULL)
1300 		resultRelInfo = node->rootResultRelInfo;
1301 
1302 	switch (node->operation)
1303 	{
1304 		case CMD_INSERT:
1305 			ExecBSInsertTriggers(node->ps.state, resultRelInfo);
1306 			if (node->mt_onconflict == ONCONFLICT_UPDATE)
1307 				ExecBSUpdateTriggers(node->ps.state,
1308 									 resultRelInfo);
1309 			break;
1310 		case CMD_UPDATE:
1311 			ExecBSUpdateTriggers(node->ps.state, resultRelInfo);
1312 			break;
1313 		case CMD_DELETE:
1314 			ExecBSDeleteTriggers(node->ps.state, resultRelInfo);
1315 			break;
1316 		default:
1317 			elog(ERROR, "unknown operation");
1318 			break;
1319 	}
1320 }
1321 
1322 /*
1323  * Return the ResultRelInfo for which we will fire AFTER STATEMENT triggers.
1324  * This is also the relation into whose tuple format all captured transition
1325  * tuples must be converted.
1326  */
1327 static ResultRelInfo *
getASTriggerResultRelInfo(ModifyTableState * node)1328 getASTriggerResultRelInfo(ModifyTableState *node)
1329 {
1330 	/*
1331 	 * If the node modifies a partitioned table, we must fire its triggers.
1332 	 * Note that in that case, node->resultRelInfo points to the first leaf
1333 	 * partition, not the root table.
1334 	 */
1335 	if (node->rootResultRelInfo != NULL)
1336 		return node->rootResultRelInfo;
1337 	else
1338 		return node->resultRelInfo;
1339 }
1340 
1341 /*
1342  * Process AFTER EACH STATEMENT triggers
1343  */
1344 static void
fireASTriggers(ModifyTableState * node)1345 fireASTriggers(ModifyTableState *node)
1346 {
1347 	ResultRelInfo *resultRelInfo = getASTriggerResultRelInfo(node);
1348 
1349 	switch (node->operation)
1350 	{
1351 		case CMD_INSERT:
1352 			if (node->mt_onconflict == ONCONFLICT_UPDATE)
1353 				ExecASUpdateTriggers(node->ps.state,
1354 									 resultRelInfo,
1355 									 node->mt_oc_transition_capture);
1356 			ExecASInsertTriggers(node->ps.state, resultRelInfo,
1357 								 node->mt_transition_capture);
1358 			break;
1359 		case CMD_UPDATE:
1360 			ExecASUpdateTriggers(node->ps.state, resultRelInfo,
1361 								 node->mt_transition_capture);
1362 			break;
1363 		case CMD_DELETE:
1364 			ExecASDeleteTriggers(node->ps.state, resultRelInfo,
1365 								 node->mt_transition_capture);
1366 			break;
1367 		default:
1368 			elog(ERROR, "unknown operation");
1369 			break;
1370 	}
1371 }
1372 
1373 /*
1374  * Set up the state needed for collecting transition tuples for AFTER
1375  * triggers.
1376  */
1377 static void
ExecSetupTransitionCaptureState(ModifyTableState * mtstate,EState * estate)1378 ExecSetupTransitionCaptureState(ModifyTableState *mtstate, EState *estate)
1379 {
1380 	ResultRelInfo *targetRelInfo = getASTriggerResultRelInfo(mtstate);
1381 	int			i;
1382 
1383 	/* Check for transition tables on the directly targeted relation. */
1384 	mtstate->mt_transition_capture =
1385 		MakeTransitionCaptureState(targetRelInfo->ri_TrigDesc,
1386 								   RelationGetRelid(targetRelInfo->ri_RelationDesc),
1387 								   mtstate->operation);
1388 	if (mtstate->operation == CMD_INSERT &&
1389 		mtstate->mt_onconflict == ONCONFLICT_UPDATE)
1390 		mtstate->mt_oc_transition_capture =
1391 			MakeTransitionCaptureState(targetRelInfo->ri_TrigDesc,
1392 									   RelationGetRelid(targetRelInfo->ri_RelationDesc),
1393 									   CMD_UPDATE);
1394 
1395 	/*
1396 	 * If we found that we need to collect transition tuples then we may also
1397 	 * need tuple conversion maps for any children that have TupleDescs that
1398 	 * aren't compatible with the tuplestores.  (We can share these maps
1399 	 * between the regular and ON CONFLICT cases.)
1400 	 */
1401 	if (mtstate->mt_transition_capture != NULL ||
1402 		mtstate->mt_oc_transition_capture != NULL)
1403 	{
1404 		ResultRelInfo *resultRelInfos;
1405 		int			numResultRelInfos;
1406 
1407 		/* Find the set of partitions so that we can find their TupleDescs. */
1408 		if (mtstate->mt_partition_dispatch_info != NULL)
1409 		{
1410 			/*
1411 			 * For INSERT via partitioned table, so we need TupleDescs based
1412 			 * on the partition routing table.
1413 			 */
1414 			resultRelInfos = mtstate->mt_partitions;
1415 			numResultRelInfos = mtstate->mt_num_partitions;
1416 		}
1417 		else
1418 		{
1419 			/* Otherwise we need the ResultRelInfo for each subplan. */
1420 			resultRelInfos = mtstate->resultRelInfo;
1421 			numResultRelInfos = mtstate->mt_nplans;
1422 		}
1423 
1424 		/*
1425 		 * Build array of conversion maps from each child's TupleDesc to the
1426 		 * one used in the tuplestore.  The map pointers may be NULL when no
1427 		 * conversion is necessary, which is hopefully a common case for
1428 		 * partitions.
1429 		 */
1430 		mtstate->mt_transition_tupconv_maps = (TupleConversionMap **)
1431 			palloc0(sizeof(TupleConversionMap *) * numResultRelInfos);
1432 		for (i = 0; i < numResultRelInfos; ++i)
1433 		{
1434 			mtstate->mt_transition_tupconv_maps[i] =
1435 				convert_tuples_by_name(RelationGetDescr(resultRelInfos[i].ri_RelationDesc),
1436 									   RelationGetDescr(targetRelInfo->ri_RelationDesc),
1437 									   gettext_noop("could not convert row type"));
1438 		}
1439 
1440 		/*
1441 		 * Install the conversion map for the first plan for UPDATE and DELETE
1442 		 * operations.  It will be advanced each time we switch to the next
1443 		 * plan.  (INSERT operations set it every time, so we need not update
1444 		 * mtstate->mt_oc_transition_capture here.)
1445 		 */
1446 		if (mtstate->mt_transition_capture)
1447 			mtstate->mt_transition_capture->tcs_map =
1448 				mtstate->mt_transition_tupconv_maps[0];
1449 	}
1450 }
1451 
1452 /*
1453  * ExecPrepareTupleRouting --- prepare for routing one tuple
1454  *
1455  * Determine the partition in which the tuple in slot is to be inserted,
1456  * and modify mtstate and estate to prepare for it.
1457  *
1458  * Caller must revert the estate changes after executing the insertion!
1459  * In mtstate, transition capture changes may also need to be reverted.
1460  *
1461  * Returns a slot holding the tuple of the partition rowtype.
1462  */
1463 static TupleTableSlot *
ExecPrepareTupleRouting(ModifyTableState * mtstate,EState * estate,ResultRelInfo * targetRelInfo,TupleTableSlot * slot)1464 ExecPrepareTupleRouting(ModifyTableState *mtstate,
1465 						EState *estate,
1466 						ResultRelInfo *targetRelInfo,
1467 						TupleTableSlot *slot)
1468 {
1469 	int			partidx;
1470 	ResultRelInfo *partrel;
1471 	HeapTuple	tuple;
1472 	TupleConversionMap *map;
1473 
1474 	/*
1475 	 * Determine the target partition.  If ExecFindPartition does not find
1476 	 * a partition after all, it doesn't return here; otherwise, the returned
1477 	 * value is to be used as an index into the arrays for the resultRelInfo
1478 	 * and TupleConversionMap for the partition.
1479 	 */
1480 	partidx = ExecFindPartition(targetRelInfo,
1481 								mtstate->mt_partition_dispatch_info,
1482 								slot,
1483 								estate);
1484 	Assert(partidx >= 0 && partidx < mtstate->mt_num_partitions);
1485 
1486 	/* Get the ResultRelInfo corresponding to the selected partition. */
1487 	partrel = &mtstate->mt_partitions[partidx];
1488 
1489 	/* We do not yet have a way to insert into a foreign partition */
1490 	if (partrel->ri_FdwRoutine)
1491 		ereport(ERROR,
1492 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1493 				 errmsg("cannot route inserted tuples to a foreign table")));
1494 
1495 	/*
1496 	 * Make it look like we are inserting into the partition.
1497 	 */
1498 	estate->es_result_relation_info = partrel;
1499 
1500 	/* Get the heap tuple out of the given slot. */
1501 	tuple = ExecMaterializeSlot(slot);
1502 
1503 	/*
1504 	 * If we're capturing transition tuples, we might need to convert from the
1505 	 * partition rowtype to parent rowtype.
1506 	 */
1507 	if (mtstate->mt_transition_capture != NULL)
1508 	{
1509 		if (partrel->ri_TrigDesc &&
1510 			partrel->ri_TrigDesc->trig_insert_before_row)
1511 		{
1512 			/*
1513 			 * If there are any BEFORE triggers on the partition, we'll have
1514 			 * to be ready to convert their result back to tuplestore format.
1515 			 */
1516 			mtstate->mt_transition_capture->tcs_original_insert_tuple = NULL;
1517 			mtstate->mt_transition_capture->tcs_map =
1518 				mtstate->mt_transition_tupconv_maps[partidx];
1519 		}
1520 		else
1521 		{
1522 			/*
1523 			 * Otherwise, just remember the original unconverted tuple, to
1524 			 * avoid a needless round trip conversion.
1525 			 */
1526 			mtstate->mt_transition_capture->tcs_original_insert_tuple = tuple;
1527 			mtstate->mt_transition_capture->tcs_map = NULL;
1528 		}
1529 	}
1530 	if (mtstate->mt_oc_transition_capture != NULL)
1531 	{
1532 		mtstate->mt_oc_transition_capture->tcs_map =
1533 			mtstate->mt_transition_tupconv_maps[partidx];
1534 	}
1535 
1536 	/*
1537 	 * Convert the tuple, if necessary.
1538 	 */
1539 	map = mtstate->mt_partition_tupconv_maps[partidx];
1540 	if (map)
1541 	{
1542 		tuple = do_convert_tuple(tuple, map);
1543 
1544 		/*
1545 		 * We must use the partition's tuple descriptor from this point on,
1546 		 * until we're finished dealing with the partition.  Use the
1547 		 * dedicated slot for that.
1548 		 */
1549 		slot = mtstate->mt_partition_tuple_slot;
1550 		ExecSetSlotDescriptor(slot, RelationGetDescr(partrel->ri_RelationDesc));
1551 		ExecStoreTuple(tuple, slot, InvalidBuffer, true);
1552 	}
1553 
1554 	return slot;
1555 }
1556 
1557 /* ----------------------------------------------------------------
1558  *	   ExecModifyTable
1559  *
1560  *		Perform table modifications as required, and return RETURNING results
1561  *		if needed.
1562  * ----------------------------------------------------------------
1563  */
1564 static TupleTableSlot *
ExecModifyTable(PlanState * pstate)1565 ExecModifyTable(PlanState *pstate)
1566 {
1567 	ModifyTableState *node = castNode(ModifyTableState, pstate);
1568 	EState	   *estate = node->ps.state;
1569 	CmdType		operation = node->operation;
1570 	ResultRelInfo *saved_resultRelInfo;
1571 	ResultRelInfo *resultRelInfo;
1572 	PlanState  *subplanstate;
1573 	JunkFilter *junkfilter;
1574 	TupleTableSlot *slot;
1575 	TupleTableSlot *planSlot;
1576 	ItemPointer tupleid;
1577 	ItemPointerData tuple_ctid;
1578 	HeapTupleData oldtupdata;
1579 	HeapTuple	oldtuple;
1580 
1581 	CHECK_FOR_INTERRUPTS();
1582 
1583 	/*
1584 	 * This should NOT get called during EvalPlanQual; we should have passed a
1585 	 * subplan tree to EvalPlanQual, instead.  Use a runtime test not just
1586 	 * Assert because this condition is easy to miss in testing.  (Note:
1587 	 * although ModifyTable should not get executed within an EvalPlanQual
1588 	 * operation, we do have to allow it to be initialized and shut down in
1589 	 * case it is within a CTE subplan.  Hence this test must be here, not in
1590 	 * ExecInitModifyTable.)
1591 	 */
1592 	if (estate->es_epqTuple != NULL)
1593 		elog(ERROR, "ModifyTable should not be called during EvalPlanQual");
1594 
1595 	/*
1596 	 * If we've already completed processing, don't try to do more.  We need
1597 	 * this test because ExecPostprocessPlan might call us an extra time, and
1598 	 * our subplan's nodes aren't necessarily robust against being called
1599 	 * extra times.
1600 	 */
1601 	if (node->mt_done)
1602 		return NULL;
1603 
1604 	/*
1605 	 * On first call, fire BEFORE STATEMENT triggers before proceeding.
1606 	 */
1607 	if (node->fireBSTriggers)
1608 	{
1609 		fireBSTriggers(node);
1610 		node->fireBSTriggers = false;
1611 	}
1612 
1613 	/* Preload local variables */
1614 	resultRelInfo = node->resultRelInfo + node->mt_whichplan;
1615 	subplanstate = node->mt_plans[node->mt_whichplan];
1616 	junkfilter = resultRelInfo->ri_junkFilter;
1617 
1618 	/*
1619 	 * es_result_relation_info must point to the currently active result
1620 	 * relation while we are within this ModifyTable node.  Even though
1621 	 * ModifyTable nodes can't be nested statically, they can be nested
1622 	 * dynamically (since our subplan could include a reference to a modifying
1623 	 * CTE).  So we have to save and restore the caller's value.
1624 	 */
1625 	saved_resultRelInfo = estate->es_result_relation_info;
1626 
1627 	estate->es_result_relation_info = resultRelInfo;
1628 
1629 	/*
1630 	 * Fetch rows from subplan(s), and execute the required table modification
1631 	 * for each row.
1632 	 */
1633 	for (;;)
1634 	{
1635 		/*
1636 		 * Reset the per-output-tuple exprcontext.  This is needed because
1637 		 * triggers expect to use that context as workspace.  It's a bit ugly
1638 		 * to do this below the top level of the plan, however.  We might need
1639 		 * to rethink this later.
1640 		 */
1641 		ResetPerTupleExprContext(estate);
1642 
1643 		planSlot = ExecProcNode(subplanstate);
1644 
1645 		if (TupIsNull(planSlot))
1646 		{
1647 			/* advance to next subplan if any */
1648 			node->mt_whichplan++;
1649 			if (node->mt_whichplan < node->mt_nplans)
1650 			{
1651 				resultRelInfo++;
1652 				subplanstate = node->mt_plans[node->mt_whichplan];
1653 				junkfilter = resultRelInfo->ri_junkFilter;
1654 				estate->es_result_relation_info = resultRelInfo;
1655 				EvalPlanQualSetPlan(&node->mt_epqstate, subplanstate->plan,
1656 									node->mt_arowmarks[node->mt_whichplan]);
1657 				/* Prepare to convert transition tuples from this child. */
1658 				if (node->mt_transition_capture != NULL)
1659 				{
1660 					Assert(node->mt_transition_tupconv_maps != NULL);
1661 					node->mt_transition_capture->tcs_map =
1662 						node->mt_transition_tupconv_maps[node->mt_whichplan];
1663 				}
1664 				if (node->mt_oc_transition_capture != NULL)
1665 				{
1666 					Assert(node->mt_transition_tupconv_maps != NULL);
1667 					node->mt_oc_transition_capture->tcs_map =
1668 						node->mt_transition_tupconv_maps[node->mt_whichplan];
1669 				}
1670 				continue;
1671 			}
1672 			else
1673 				break;
1674 		}
1675 
1676 		/*
1677 		 * If resultRelInfo->ri_usesFdwDirectModify is true, all we need to do
1678 		 * here is compute the RETURNING expressions.
1679 		 */
1680 		if (resultRelInfo->ri_usesFdwDirectModify)
1681 		{
1682 			Assert(resultRelInfo->ri_projectReturning);
1683 
1684 			/*
1685 			 * A scan slot containing the data that was actually inserted,
1686 			 * updated or deleted has already been made available to
1687 			 * ExecProcessReturning by IterateDirectModify, so no need to
1688 			 * provide it here.
1689 			 */
1690 			slot = ExecProcessReturning(resultRelInfo, NULL, planSlot);
1691 
1692 			estate->es_result_relation_info = saved_resultRelInfo;
1693 			return slot;
1694 		}
1695 
1696 		EvalPlanQualSetSlot(&node->mt_epqstate, planSlot);
1697 		slot = planSlot;
1698 
1699 		tupleid = NULL;
1700 		oldtuple = NULL;
1701 		if (junkfilter != NULL)
1702 		{
1703 			/*
1704 			 * extract the 'ctid' or 'wholerow' junk attribute.
1705 			 */
1706 			if (operation == CMD_UPDATE || operation == CMD_DELETE)
1707 			{
1708 				char		relkind;
1709 				Datum		datum;
1710 				bool		isNull;
1711 
1712 				relkind = resultRelInfo->ri_RelationDesc->rd_rel->relkind;
1713 				if (relkind == RELKIND_RELATION || relkind == RELKIND_MATVIEW)
1714 				{
1715 					datum = ExecGetJunkAttribute(slot,
1716 												 junkfilter->jf_junkAttNo,
1717 												 &isNull);
1718 					/* shouldn't ever get a null result... */
1719 					if (isNull)
1720 						elog(ERROR, "ctid is NULL");
1721 
1722 					tupleid = (ItemPointer) DatumGetPointer(datum);
1723 					tuple_ctid = *tupleid;	/* be sure we don't free ctid!! */
1724 					tupleid = &tuple_ctid;
1725 				}
1726 
1727 				/*
1728 				 * Use the wholerow attribute, when available, to reconstruct
1729 				 * the old relation tuple.
1730 				 *
1731 				 * Foreign table updates have a wholerow attribute when the
1732 				 * relation has a row-level trigger.  Note that the wholerow
1733 				 * attribute does not carry system columns.  Foreign table
1734 				 * triggers miss seeing those, except that we know enough here
1735 				 * to set t_tableOid.  Quite separately from this, the FDW may
1736 				 * fetch its own junk attrs to identify the row.
1737 				 *
1738 				 * Other relevant relkinds, currently limited to views, always
1739 				 * have a wholerow attribute.
1740 				 */
1741 				else if (AttributeNumberIsValid(junkfilter->jf_junkAttNo))
1742 				{
1743 					datum = ExecGetJunkAttribute(slot,
1744 												 junkfilter->jf_junkAttNo,
1745 												 &isNull);
1746 					/* shouldn't ever get a null result... */
1747 					if (isNull)
1748 						elog(ERROR, "wholerow is NULL");
1749 
1750 					oldtupdata.t_data = DatumGetHeapTupleHeader(datum);
1751 					oldtupdata.t_len =
1752 						HeapTupleHeaderGetDatumLength(oldtupdata.t_data);
1753 					ItemPointerSetInvalid(&(oldtupdata.t_self));
1754 					/* Historically, view triggers see invalid t_tableOid. */
1755 					oldtupdata.t_tableOid =
1756 						(relkind == RELKIND_VIEW) ? InvalidOid :
1757 						RelationGetRelid(resultRelInfo->ri_RelationDesc);
1758 
1759 					oldtuple = &oldtupdata;
1760 				}
1761 				else
1762 					Assert(relkind == RELKIND_FOREIGN_TABLE);
1763 			}
1764 
1765 			/*
1766 			 * apply the junkfilter if needed.
1767 			 */
1768 			if (operation != CMD_DELETE)
1769 				slot = ExecFilterJunk(junkfilter, slot);
1770 		}
1771 
1772 		switch (operation)
1773 		{
1774 			case CMD_INSERT:
1775 				/* Prepare for tuple routing, if needed. */
1776 				if (node->mt_partition_dispatch_info)
1777 					slot = ExecPrepareTupleRouting(node, estate,
1778 												   resultRelInfo, slot);
1779 				slot = ExecInsert(node, slot, planSlot,
1780 								  node->mt_arbiterindexes, node->mt_onconflict,
1781 								  estate, node->canSetTag);
1782 				/* Revert ExecPrepareTupleRouting's node change. */
1783 				if (node->mt_partition_dispatch_info)
1784 					estate->es_result_relation_info = resultRelInfo;
1785 				break;
1786 			case CMD_UPDATE:
1787 				slot = ExecUpdate(node, tupleid, oldtuple, slot, planSlot,
1788 								  &node->mt_epqstate, estate, node->canSetTag);
1789 				break;
1790 			case CMD_DELETE:
1791 				slot = ExecDelete(node, tupleid, oldtuple, planSlot,
1792 								  &node->mt_epqstate, estate, node->canSetTag);
1793 				break;
1794 			default:
1795 				elog(ERROR, "unknown operation");
1796 				break;
1797 		}
1798 
1799 		/*
1800 		 * If we got a RETURNING result, return it to caller.  We'll continue
1801 		 * the work on next call.
1802 		 */
1803 		if (slot)
1804 		{
1805 			estate->es_result_relation_info = saved_resultRelInfo;
1806 			return slot;
1807 		}
1808 	}
1809 
1810 	/* Restore es_result_relation_info before exiting */
1811 	estate->es_result_relation_info = saved_resultRelInfo;
1812 
1813 	/*
1814 	 * We're done, but fire AFTER STATEMENT triggers before exiting.
1815 	 */
1816 	fireASTriggers(node);
1817 
1818 	node->mt_done = true;
1819 
1820 	return NULL;
1821 }
1822 
1823 /* ----------------------------------------------------------------
1824  *		ExecInitModifyTable
1825  * ----------------------------------------------------------------
1826  */
1827 ModifyTableState *
ExecInitModifyTable(ModifyTable * node,EState * estate,int eflags)1828 ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
1829 {
1830 	ModifyTableState *mtstate;
1831 	CmdType		operation = node->operation;
1832 	int			nplans = list_length(node->plans);
1833 	ResultRelInfo *saved_resultRelInfo;
1834 	ResultRelInfo *resultRelInfo;
1835 	TupleDesc	tupDesc;
1836 	Plan	   *subplan;
1837 	ListCell   *l;
1838 	int			i;
1839 	Relation	rel;
1840 
1841 	/* check for unsupported flags */
1842 	Assert(!(eflags & (EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK)));
1843 
1844 	/*
1845 	 * create state structure
1846 	 */
1847 	mtstate = makeNode(ModifyTableState);
1848 	mtstate->ps.plan = (Plan *) node;
1849 	mtstate->ps.state = estate;
1850 	mtstate->ps.ExecProcNode = ExecModifyTable;
1851 
1852 	mtstate->operation = operation;
1853 	mtstate->canSetTag = node->canSetTag;
1854 	mtstate->mt_done = false;
1855 
1856 	mtstate->mt_plans = (PlanState **) palloc0(sizeof(PlanState *) * nplans);
1857 	mtstate->resultRelInfo = estate->es_result_relations + node->resultRelIndex;
1858 
1859 	/* If modifying a partitioned table, initialize the root table info */
1860 	if (node->rootResultRelIndex >= 0)
1861 		mtstate->rootResultRelInfo = estate->es_root_result_relations +
1862 			node->rootResultRelIndex;
1863 
1864 	mtstate->mt_arowmarks = (List **) palloc0(sizeof(List *) * nplans);
1865 	mtstate->mt_nplans = nplans;
1866 	mtstate->mt_onconflict = node->onConflictAction;
1867 	mtstate->mt_arbiterindexes = node->arbiterIndexes;
1868 
1869 	/* set up epqstate with dummy subplan data for the moment */
1870 	EvalPlanQualInit(&mtstate->mt_epqstate, estate, NULL, NIL, node->epqParam);
1871 	mtstate->fireBSTriggers = true;
1872 
1873 	/*
1874 	 * call ExecInitNode on each of the plans to be executed and save the
1875 	 * results into the array "mt_plans".  This is also a convenient place to
1876 	 * verify that the proposed target relations are valid and open their
1877 	 * indexes for insertion of new index entries.  Note we *must* set
1878 	 * estate->es_result_relation_info correctly while we initialize each
1879 	 * sub-plan; ExecContextForcesOids depends on that!
1880 	 */
1881 	saved_resultRelInfo = estate->es_result_relation_info;
1882 
1883 	resultRelInfo = mtstate->resultRelInfo;
1884 	i = 0;
1885 	foreach(l, node->plans)
1886 	{
1887 		subplan = (Plan *) lfirst(l);
1888 
1889 		/* Initialize the usesFdwDirectModify flag */
1890 		resultRelInfo->ri_usesFdwDirectModify = bms_is_member(i,
1891 															  node->fdwDirectModifyPlans);
1892 
1893 		/*
1894 		 * Verify result relation is a valid target for the current operation
1895 		 */
1896 		CheckValidResultRel(resultRelInfo, operation);
1897 
1898 		/*
1899 		 * If there are indices on the result relation, open them and save
1900 		 * descriptors in the result relation info, so that we can add new
1901 		 * index entries for the tuples we add/update.  We need not do this
1902 		 * for a DELETE, however, since deletion doesn't affect indexes. Also,
1903 		 * inside an EvalPlanQual operation, the indexes might be open
1904 		 * already, since we share the resultrel state with the original
1905 		 * query.
1906 		 */
1907 		if (resultRelInfo->ri_RelationDesc->rd_rel->relhasindex &&
1908 			operation != CMD_DELETE &&
1909 			resultRelInfo->ri_IndexRelationDescs == NULL)
1910 			ExecOpenIndices(resultRelInfo, mtstate->mt_onconflict != ONCONFLICT_NONE);
1911 
1912 		/* Now init the plan for this result rel */
1913 		estate->es_result_relation_info = resultRelInfo;
1914 		mtstate->mt_plans[i] = ExecInitNode(subplan, estate, eflags);
1915 
1916 		/* Also let FDWs init themselves for foreign-table result rels */
1917 		if (!resultRelInfo->ri_usesFdwDirectModify &&
1918 			resultRelInfo->ri_FdwRoutine != NULL &&
1919 			resultRelInfo->ri_FdwRoutine->BeginForeignModify != NULL)
1920 		{
1921 			List	   *fdw_private = (List *) list_nth(node->fdwPrivLists, i);
1922 
1923 			resultRelInfo->ri_FdwRoutine->BeginForeignModify(mtstate,
1924 															 resultRelInfo,
1925 															 fdw_private,
1926 															 i,
1927 															 eflags);
1928 		}
1929 
1930 		resultRelInfo++;
1931 		i++;
1932 	}
1933 
1934 	estate->es_result_relation_info = saved_resultRelInfo;
1935 
1936 	/* Examine the root partition if we have one, else target table */
1937 	if (mtstate->rootResultRelInfo)
1938 		rel = mtstate->rootResultRelInfo->ri_RelationDesc;
1939 	else
1940 		rel = mtstate->resultRelInfo->ri_RelationDesc;
1941 
1942 	/* Build state for INSERT tuple routing */
1943 	if (operation == CMD_INSERT &&
1944 		rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
1945 	{
1946 		PartitionDispatch *partition_dispatch_info;
1947 		ResultRelInfo *partitions;
1948 		TupleConversionMap **partition_tupconv_maps;
1949 		TupleTableSlot *partition_tuple_slot;
1950 		int			num_parted,
1951 					num_partitions;
1952 
1953 		ExecSetupPartitionTupleRouting(rel,
1954 									   node->nominalRelation,
1955 									   estate,
1956 									   &partition_dispatch_info,
1957 									   &partitions,
1958 									   &partition_tupconv_maps,
1959 									   &partition_tuple_slot,
1960 									   &num_parted, &num_partitions);
1961 		mtstate->mt_partition_dispatch_info = partition_dispatch_info;
1962 		mtstate->mt_num_dispatch = num_parted;
1963 		mtstate->mt_partitions = partitions;
1964 		mtstate->mt_num_partitions = num_partitions;
1965 		mtstate->mt_partition_tupconv_maps = partition_tupconv_maps;
1966 		mtstate->mt_partition_tuple_slot = partition_tuple_slot;
1967 	}
1968 
1969 	/*
1970 	 * Build state for collecting transition tuples.  This requires having a
1971 	 * valid trigger query context, so skip it in explain-only mode.
1972 	 */
1973 	if (!(eflags & EXEC_FLAG_EXPLAIN_ONLY))
1974 		ExecSetupTransitionCaptureState(mtstate, estate);
1975 
1976 	/*
1977 	 * Initialize any WITH CHECK OPTION constraints if needed.
1978 	 */
1979 	resultRelInfo = mtstate->resultRelInfo;
1980 	i = 0;
1981 	foreach(l, node->withCheckOptionLists)
1982 	{
1983 		List	   *wcoList = (List *) lfirst(l);
1984 		List	   *wcoExprs = NIL;
1985 		ListCell   *ll;
1986 
1987 		foreach(ll, wcoList)
1988 		{
1989 			WithCheckOption *wco = (WithCheckOption *) lfirst(ll);
1990 			ExprState  *wcoExpr = ExecInitQual((List *) wco->qual,
1991 											   &mtstate->ps);
1992 
1993 			wcoExprs = lappend(wcoExprs, wcoExpr);
1994 		}
1995 
1996 		resultRelInfo->ri_WithCheckOptions = wcoList;
1997 		resultRelInfo->ri_WithCheckOptionExprs = wcoExprs;
1998 		resultRelInfo++;
1999 		i++;
2000 	}
2001 
2002 	/*
2003 	 * Build WITH CHECK OPTION constraints for each leaf partition rel. Note
2004 	 * that we didn't build the withCheckOptionList for each partition within
2005 	 * the planner, but simple translation of the varattnos for each partition
2006 	 * will suffice.  This only occurs for the INSERT case; UPDATE/DELETE
2007 	 * cases are handled above.
2008 	 */
2009 	if (node->withCheckOptionLists != NIL && mtstate->mt_num_partitions > 0)
2010 	{
2011 		List	   *wcoList;
2012 		PlanState  *plan;
2013 
2014 		/*
2015 		 * In case of INSERT on partitioned tables, there is only one plan.
2016 		 * Likewise, there is only one WITH CHECK OPTIONS list, not one per
2017 		 * partition.  We make a copy of the WCO qual for each partition; note
2018 		 * that, if there are SubPlans in there, they all end up attached to
2019 		 * the one parent Plan node.
2020 		 */
2021 		Assert(operation == CMD_INSERT &&
2022 			   list_length(node->withCheckOptionLists) == 1 &&
2023 			   mtstate->mt_nplans == 1);
2024 		wcoList = linitial(node->withCheckOptionLists);
2025 		plan = mtstate->mt_plans[0];
2026 		resultRelInfo = mtstate->mt_partitions;
2027 		for (i = 0; i < mtstate->mt_num_partitions; i++)
2028 		{
2029 			Relation	partrel = resultRelInfo->ri_RelationDesc;
2030 			List	   *mapped_wcoList;
2031 			List	   *wcoExprs = NIL;
2032 			ListCell   *ll;
2033 
2034 			/* varno = node->nominalRelation */
2035 			mapped_wcoList = map_partition_varattnos(wcoList,
2036 													 node->nominalRelation,
2037 													 partrel, rel, NULL);
2038 			foreach(ll, mapped_wcoList)
2039 			{
2040 				WithCheckOption *wco = castNode(WithCheckOption, lfirst(ll));
2041 				ExprState  *wcoExpr = ExecInitQual(castNode(List, wco->qual),
2042 												   plan);
2043 
2044 				wcoExprs = lappend(wcoExprs, wcoExpr);
2045 			}
2046 
2047 			resultRelInfo->ri_WithCheckOptions = mapped_wcoList;
2048 			resultRelInfo->ri_WithCheckOptionExprs = wcoExprs;
2049 			resultRelInfo++;
2050 		}
2051 	}
2052 
2053 	/*
2054 	 * Initialize RETURNING projections if needed.
2055 	 */
2056 	if (node->returningLists)
2057 	{
2058 		TupleTableSlot *slot;
2059 		ExprContext *econtext;
2060 		List	   *returningList;
2061 
2062 		/*
2063 		 * Initialize result tuple slot and assign its rowtype using the first
2064 		 * RETURNING list.  We assume the rest will look the same.
2065 		 */
2066 		tupDesc = ExecTypeFromTL((List *) linitial(node->returningLists),
2067 								 false);
2068 
2069 		/* Set up a slot for the output of the RETURNING projection(s) */
2070 		ExecInitResultTupleSlot(estate, &mtstate->ps);
2071 		ExecAssignResultType(&mtstate->ps, tupDesc);
2072 		slot = mtstate->ps.ps_ResultTupleSlot;
2073 
2074 		/* Need an econtext too */
2075 		if (mtstate->ps.ps_ExprContext == NULL)
2076 			ExecAssignExprContext(estate, &mtstate->ps);
2077 		econtext = mtstate->ps.ps_ExprContext;
2078 
2079 		/*
2080 		 * Build a projection for each result rel.
2081 		 */
2082 		resultRelInfo = mtstate->resultRelInfo;
2083 		foreach(l, node->returningLists)
2084 		{
2085 			List	   *rlist = (List *) lfirst(l);
2086 
2087 			resultRelInfo->ri_projectReturning =
2088 				ExecBuildProjectionInfo(rlist, econtext, slot, &mtstate->ps,
2089 										resultRelInfo->ri_RelationDesc->rd_att);
2090 			resultRelInfo++;
2091 		}
2092 
2093 		/*
2094 		 * Build a projection for each leaf partition rel.  Note that we
2095 		 * didn't build the returningList for each partition within the
2096 		 * planner, but simple translation of the varattnos for each partition
2097 		 * will suffice.  This only occurs for the INSERT case; UPDATE/DELETE
2098 		 * are handled above.
2099 		 */
2100 		resultRelInfo = mtstate->mt_partitions;
2101 		returningList = linitial(node->returningLists);
2102 		for (i = 0; i < mtstate->mt_num_partitions; i++)
2103 		{
2104 			Relation	partrel = resultRelInfo->ri_RelationDesc;
2105 			List	   *rlist;
2106 
2107 			/* varno = node->nominalRelation */
2108 			rlist = map_partition_varattnos(returningList,
2109 											node->nominalRelation,
2110 											partrel, rel, NULL);
2111 			resultRelInfo->ri_projectReturning =
2112 				ExecBuildProjectionInfo(rlist, econtext, slot, &mtstate->ps,
2113 										resultRelInfo->ri_RelationDesc->rd_att);
2114 			resultRelInfo++;
2115 		}
2116 	}
2117 	else
2118 	{
2119 		/*
2120 		 * We still must construct a dummy result tuple type, because InitPlan
2121 		 * expects one (maybe should change that?).
2122 		 */
2123 		tupDesc = ExecTypeFromTL(NIL, false);
2124 		ExecInitResultTupleSlot(estate, &mtstate->ps);
2125 		ExecAssignResultType(&mtstate->ps, tupDesc);
2126 
2127 		mtstate->ps.ps_ExprContext = NULL;
2128 	}
2129 
2130 	/*
2131 	 * If needed, Initialize target list, projection and qual for ON CONFLICT
2132 	 * DO UPDATE.
2133 	 */
2134 	resultRelInfo = mtstate->resultRelInfo;
2135 	if (node->onConflictAction == ONCONFLICT_UPDATE)
2136 	{
2137 		ExprContext *econtext;
2138 
2139 		/* insert may only have one plan, inheritance is not expanded */
2140 		Assert(nplans == 1);
2141 
2142 		/* already exists if created by RETURNING processing above */
2143 		if (mtstate->ps.ps_ExprContext == NULL)
2144 			ExecAssignExprContext(estate, &mtstate->ps);
2145 
2146 		econtext = mtstate->ps.ps_ExprContext;
2147 
2148 		/* initialize slot for the existing tuple */
2149 		mtstate->mt_existing = ExecInitExtraTupleSlot(mtstate->ps.state);
2150 		ExecSetSlotDescriptor(mtstate->mt_existing,
2151 							  resultRelInfo->ri_RelationDesc->rd_att);
2152 
2153 		/* carried forward solely for the benefit of explain */
2154 		mtstate->mt_excludedtlist = node->exclRelTlist;
2155 
2156 		/* create target slot for UPDATE SET projection */
2157 		mtstate->mt_conflproj = ExecInitExtraTupleSlot(mtstate->ps.state);
2158 		ExecSetSlotDescriptor(mtstate->mt_conflproj,
2159 							  resultRelInfo->ri_RelationDesc->rd_att);
2160 
2161 		/*
2162 		 * The onConflictSet tlist should already have been adjusted to emit
2163 		 * the table's exact column list.  It could also contain resjunk
2164 		 * columns, which should be evaluated but not included in the
2165 		 * projection result.
2166 		 */
2167 		ExecCheckPlanOutput(resultRelInfo->ri_RelationDesc,
2168 							node->onConflictSet);
2169 
2170 		/* build UPDATE SET projection state */
2171 		resultRelInfo->ri_onConflictSetProj =
2172 			ExecBuildProjectionInfoExt(node->onConflictSet, econtext,
2173 									   mtstate->mt_conflproj, false,
2174 									   &mtstate->ps,
2175 									   resultRelInfo->ri_RelationDesc->rd_att);
2176 
2177 		/* build DO UPDATE WHERE clause expression */
2178 		if (node->onConflictWhere)
2179 		{
2180 			ExprState  *qualexpr;
2181 
2182 			qualexpr = ExecInitQual((List *) node->onConflictWhere,
2183 									&mtstate->ps);
2184 
2185 			resultRelInfo->ri_onConflictSetWhere = qualexpr;
2186 		}
2187 	}
2188 
2189 	/*
2190 	 * If we have any secondary relations in an UPDATE or DELETE, they need to
2191 	 * be treated like non-locked relations in SELECT FOR UPDATE, ie, the
2192 	 * EvalPlanQual mechanism needs to be told about them.  Locate the
2193 	 * relevant ExecRowMarks.
2194 	 */
2195 	foreach(l, node->rowMarks)
2196 	{
2197 		PlanRowMark *rc = lfirst_node(PlanRowMark, l);
2198 		ExecRowMark *erm;
2199 
2200 		/* ignore "parent" rowmarks; they are irrelevant at runtime */
2201 		if (rc->isParent)
2202 			continue;
2203 
2204 		/* find ExecRowMark (same for all subplans) */
2205 		erm = ExecFindRowMark(estate, rc->rti, false);
2206 
2207 		/* build ExecAuxRowMark for each subplan */
2208 		for (i = 0; i < nplans; i++)
2209 		{
2210 			ExecAuxRowMark *aerm;
2211 
2212 			subplan = mtstate->mt_plans[i]->plan;
2213 			aerm = ExecBuildAuxRowMark(erm, subplan->targetlist);
2214 			mtstate->mt_arowmarks[i] = lappend(mtstate->mt_arowmarks[i], aerm);
2215 		}
2216 	}
2217 
2218 	/* select first subplan */
2219 	mtstate->mt_whichplan = 0;
2220 	subplan = (Plan *) linitial(node->plans);
2221 	EvalPlanQualSetPlan(&mtstate->mt_epqstate, subplan,
2222 						mtstate->mt_arowmarks[0]);
2223 
2224 	/*
2225 	 * Initialize the junk filter(s) if needed.  INSERT queries need a filter
2226 	 * if there are any junk attrs in the tlist.  UPDATE and DELETE always
2227 	 * need a filter, since there's always at least one junk attribute present
2228 	 * --- no need to look first.  Typically, this will be a 'ctid' or
2229 	 * 'wholerow' attribute, but in the case of a foreign data wrapper it
2230 	 * might be a set of junk attributes sufficient to identify the remote
2231 	 * row.
2232 	 *
2233 	 * If there are multiple result relations, each one needs its own junk
2234 	 * filter.  Note multiple rels are only possible for UPDATE/DELETE, so we
2235 	 * can't be fooled by some needing a filter and some not.
2236 	 *
2237 	 * This section of code is also a convenient place to verify that the
2238 	 * output of an INSERT or UPDATE matches the target table(s).
2239 	 */
2240 	{
2241 		bool		junk_filter_needed = false;
2242 
2243 		switch (operation)
2244 		{
2245 			case CMD_INSERT:
2246 				foreach(l, subplan->targetlist)
2247 				{
2248 					TargetEntry *tle = (TargetEntry *) lfirst(l);
2249 
2250 					if (tle->resjunk)
2251 					{
2252 						junk_filter_needed = true;
2253 						break;
2254 					}
2255 				}
2256 				break;
2257 			case CMD_UPDATE:
2258 			case CMD_DELETE:
2259 				junk_filter_needed = true;
2260 				break;
2261 			default:
2262 				elog(ERROR, "unknown operation");
2263 				break;
2264 		}
2265 
2266 		if (junk_filter_needed)
2267 		{
2268 			resultRelInfo = mtstate->resultRelInfo;
2269 			for (i = 0; i < nplans; i++)
2270 			{
2271 				JunkFilter *j;
2272 
2273 				subplan = mtstate->mt_plans[i]->plan;
2274 				if (operation == CMD_INSERT || operation == CMD_UPDATE)
2275 					ExecCheckPlanOutput(resultRelInfo->ri_RelationDesc,
2276 										subplan->targetlist);
2277 
2278 				j = ExecInitJunkFilter(subplan->targetlist,
2279 									   resultRelInfo->ri_RelationDesc->rd_att->tdhasoid,
2280 									   ExecInitExtraTupleSlot(estate));
2281 
2282 				if (operation == CMD_UPDATE || operation == CMD_DELETE)
2283 				{
2284 					/* For UPDATE/DELETE, find the appropriate junk attr now */
2285 					char		relkind;
2286 
2287 					relkind = resultRelInfo->ri_RelationDesc->rd_rel->relkind;
2288 					if (relkind == RELKIND_RELATION ||
2289 						relkind == RELKIND_MATVIEW ||
2290 						relkind == RELKIND_PARTITIONED_TABLE)
2291 					{
2292 						j->jf_junkAttNo = ExecFindJunkAttribute(j, "ctid");
2293 						if (!AttributeNumberIsValid(j->jf_junkAttNo))
2294 							elog(ERROR, "could not find junk ctid column");
2295 					}
2296 					else if (relkind == RELKIND_FOREIGN_TABLE)
2297 					{
2298 						/*
2299 						 * When there is a row-level trigger, there should be
2300 						 * a wholerow attribute.
2301 						 */
2302 						j->jf_junkAttNo = ExecFindJunkAttribute(j, "wholerow");
2303 					}
2304 					else
2305 					{
2306 						j->jf_junkAttNo = ExecFindJunkAttribute(j, "wholerow");
2307 						if (!AttributeNumberIsValid(j->jf_junkAttNo))
2308 							elog(ERROR, "could not find junk wholerow column");
2309 					}
2310 				}
2311 
2312 				resultRelInfo->ri_junkFilter = j;
2313 				resultRelInfo++;
2314 			}
2315 		}
2316 		else
2317 		{
2318 			if (operation == CMD_INSERT)
2319 				ExecCheckPlanOutput(mtstate->resultRelInfo->ri_RelationDesc,
2320 									subplan->targetlist);
2321 		}
2322 	}
2323 
2324 	/*
2325 	 * Set up a tuple table slot for use for trigger output tuples. In a plan
2326 	 * containing multiple ModifyTable nodes, all can share one such slot, so
2327 	 * we keep it in the estate.
2328 	 */
2329 	if (estate->es_trig_tuple_slot == NULL)
2330 		estate->es_trig_tuple_slot = ExecInitExtraTupleSlot(estate);
2331 
2332 	/*
2333 	 * Lastly, if this is not the primary (canSetTag) ModifyTable node, add it
2334 	 * to estate->es_auxmodifytables so that it will be run to completion by
2335 	 * ExecPostprocessPlan.  (It'd actually work fine to add the primary
2336 	 * ModifyTable node too, but there's no need.)  Note the use of lcons not
2337 	 * lappend: we need later-initialized ModifyTable nodes to be shut down
2338 	 * before earlier ones.  This ensures that we don't throw away RETURNING
2339 	 * rows that need to be seen by a later CTE subplan.
2340 	 */
2341 	if (!mtstate->canSetTag)
2342 		estate->es_auxmodifytables = lcons(mtstate,
2343 										   estate->es_auxmodifytables);
2344 
2345 	return mtstate;
2346 }
2347 
2348 /* ----------------------------------------------------------------
2349  *		ExecEndModifyTable
2350  *
2351  *		Shuts down the plan.
2352  *
2353  *		Returns nothing of interest.
2354  * ----------------------------------------------------------------
2355  */
2356 void
ExecEndModifyTable(ModifyTableState * node)2357 ExecEndModifyTable(ModifyTableState *node)
2358 {
2359 	int			i;
2360 
2361 	/*
2362 	 * Allow any FDWs to shut down
2363 	 */
2364 	for (i = 0; i < node->mt_nplans; i++)
2365 	{
2366 		ResultRelInfo *resultRelInfo = node->resultRelInfo + i;
2367 
2368 		if (!resultRelInfo->ri_usesFdwDirectModify &&
2369 			resultRelInfo->ri_FdwRoutine != NULL &&
2370 			resultRelInfo->ri_FdwRoutine->EndForeignModify != NULL)
2371 			resultRelInfo->ri_FdwRoutine->EndForeignModify(node->ps.state,
2372 														   resultRelInfo);
2373 	}
2374 
2375 	/*
2376 	 * Close all the partitioned tables, leaf partitions, and their indices
2377 	 *
2378 	 * Remember node->mt_partition_dispatch_info[0] corresponds to the root
2379 	 * partitioned table, which we must not try to close, because it is the
2380 	 * main target table of the query that will be closed by ExecEndPlan().
2381 	 * Also, tupslot is NULL for the root partitioned table.
2382 	 */
2383 	for (i = 1; i < node->mt_num_dispatch; i++)
2384 	{
2385 		PartitionDispatch pd = node->mt_partition_dispatch_info[i];
2386 
2387 		heap_close(pd->reldesc, NoLock);
2388 		ExecDropSingleTupleTableSlot(pd->tupslot);
2389 	}
2390 	for (i = 0; i < node->mt_num_partitions; i++)
2391 	{
2392 		ResultRelInfo *resultRelInfo = node->mt_partitions + i;
2393 
2394 		ExecCloseIndices(resultRelInfo);
2395 		heap_close(resultRelInfo->ri_RelationDesc, NoLock);
2396 	}
2397 
2398 	/* Release the standalone partition tuple descriptor, if any */
2399 	if (node->mt_partition_tuple_slot)
2400 		ExecDropSingleTupleTableSlot(node->mt_partition_tuple_slot);
2401 
2402 	/*
2403 	 * Free the exprcontext
2404 	 */
2405 	ExecFreeExprContext(&node->ps);
2406 
2407 	/*
2408 	 * clean out the tuple table
2409 	 */
2410 	ExecClearTuple(node->ps.ps_ResultTupleSlot);
2411 
2412 	/*
2413 	 * Terminate EPQ execution if active
2414 	 */
2415 	EvalPlanQualEnd(&node->mt_epqstate);
2416 
2417 	/*
2418 	 * shut down subplans
2419 	 */
2420 	for (i = 0; i < node->mt_nplans; i++)
2421 		ExecEndNode(node->mt_plans[i]);
2422 }
2423 
2424 void
ExecReScanModifyTable(ModifyTableState * node)2425 ExecReScanModifyTable(ModifyTableState *node)
2426 {
2427 	/*
2428 	 * Currently, we don't need to support rescan on ModifyTable nodes. The
2429 	 * semantics of that would be a bit debatable anyway.
2430 	 */
2431 	elog(ERROR, "ExecReScanModifyTable is not implemented");
2432 }
2433