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