PostgreSQL Source Code git master
Loading...
Searching...
No Matches
nodeModifyTable.c
Go to the documentation of this file.
1/*-------------------------------------------------------------------------
2 *
3 * nodeModifyTable.c
4 * routines to handle ModifyTable nodes.
5 *
6 * Portions Copyright (c) 1996-2026, 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/*
16 * INTERFACE ROUTINES
17 * ExecInitModifyTable - initialize the ModifyTable node
18 * ExecModifyTable - retrieve the next tuple from the node
19 * ExecEndModifyTable - shut down the ModifyTable node
20 * ExecReScanModifyTable - rescan the ModifyTable node
21 *
22 * NOTES
23 * The ModifyTable node receives input from its outerPlan, which is
24 * the data to insert for INSERT cases, the changed columns' new
25 * values plus row-locating info for UPDATE and MERGE cases, or just the
26 * row-locating info for DELETE cases.
27 *
28 * The relation to modify can be an ordinary table, a foreign table, or a
29 * view. If it's a view, either it has sufficient INSTEAD OF triggers or
30 * this node executes only MERGE ... DO NOTHING. If the original MERGE
31 * targeted a view not in one of those two categories, earlier processing
32 * already pointed the ModifyTable result relation to an underlying
33 * relation of that other view. This node does process
34 * ri_WithCheckOptions, which may have expressions from those other,
35 * automatically updatable views.
36 *
37 * MERGE runs a join between the source relation and the target table.
38 * If any WHEN NOT MATCHED [BY TARGET] clauses are present, then the join
39 * is an outer join that might output tuples without a matching target
40 * tuple. In this case, any unmatched target tuples will have NULL
41 * row-locating info, and only INSERT can be run. But for matched target
42 * tuples, the row-locating info is used to determine the tuple to UPDATE
43 * or DELETE. When all clauses are WHEN MATCHED or WHEN NOT MATCHED BY
44 * SOURCE, all tuples produced by the join will include a matching target
45 * tuple, so all tuples contain row-locating info.
46 *
47 * If the query specifies RETURNING, then the ModifyTable returns a
48 * RETURNING tuple after completing each row insert, update, or delete.
49 * It must be called again to continue the operation. Without RETURNING,
50 * we just loop within the node until all the work is done, then
51 * return NULL. This avoids useless call/return overhead.
52 */
53
54#include "postgres.h"
55
56#include "access/htup_details.h"
57#include "access/tableam.h"
58#include "access/tupconvert.h"
59#include "access/xact.h"
60#include "commands/trigger.h"
62#include "executor/executor.h"
63#include "executor/instrument.h"
65#include "foreign/fdwapi.h"
66#include "miscadmin.h"
67#include "nodes/nodeFuncs.h"
68#include "optimizer/optimizer.h"
69#include "pgstat.h"
72#include "storage/lmgr.h"
73#include "utils/builtins.h"
74#include "utils/datum.h"
76#include "utils/rangetypes.h"
77#include "utils/rel.h"
78#include "utils/snapmgr.h"
79
80
81typedef struct MTTargetRelLookup
82{
83 Oid relationOid; /* hash key, must be first */
84 int relationIndex; /* rel's index in resultRelInfo[] array */
86
87/*
88 * Context struct for a ModifyTable operation, containing basic execution
89 * state and some output variables populated by ExecUpdateAct() and
90 * ExecDeleteAct() to report the result of their actions to callers.
91 */
92typedef struct ModifyTableContext
93{
94 /* Operation state */
98
99 /*
100 * Slot containing tuple obtained from ModifyTable's subplan. Used to
101 * access "junk" columns that are not going to be stored.
102 */
104
105 /*
106 * Information about the changes that were made concurrently to a tuple
107 * being updated or deleted
108 */
110
111 /*
112 * The tuple deleted when doing a cross-partition UPDATE with a RETURNING
113 * clause that refers to OLD columns (converted to the root's tuple
114 * descriptor).
115 */
117
118 /*
119 * The tuple projected by the INSERT's RETURNING clause, when doing a
120 * cross-partition UPDATE
121 */
124
125/*
126 * Context struct containing output data specific to UPDATE operations.
127 */
128typedef struct UpdateContext
129{
130 bool crossPartUpdate; /* was it a cross-partition update? */
131 TU_UpdateIndexes updateIndexes; /* Which index updates are required? */
132
133 /*
134 * Lock mode to acquire on the latest tuple version before performing
135 * EvalPlanQual on it
136 */
139
140
141static void ExecBatchInsert(ModifyTableState *mtstate,
142 ResultRelInfo *resultRelInfo,
143 TupleTableSlot **slots,
145 int numSlots,
146 EState *estate,
147 bool canSetTag);
148static void ExecPendingInserts(EState *estate);
155static bool ExecOnConflictLockRow(ModifyTableContext *context,
158 Relation relation,
159 LockTupleMode lockmode,
160 bool isUpdate);
161static bool ExecOnConflictUpdate(ModifyTableContext *context,
162 ResultRelInfo *resultRelInfo,
165 bool canSetTag,
166 TupleTableSlot **returning);
167static bool ExecOnConflictSelect(ModifyTableContext *context,
168 ResultRelInfo *resultRelInfo,
171 bool canSetTag,
172 TupleTableSlot **returning);
174 EState *estate,
175 ResultRelInfo *resultRelInfo,
178 EState *estate,
179 PartitionTupleRouting *proute,
180 ResultRelInfo *targetRelInfo,
181 TupleTableSlot *slot,
183
185 ResultRelInfo *resultRelInfo,
187 HeapTuple oldtuple,
188 bool canSetTag);
189static void ExecInitMerge(ModifyTableState *mtstate, EState *estate);
191 ResultRelInfo *resultRelInfo,
193 HeapTuple oldtuple,
194 bool canSetTag,
195 bool *matched);
197 ResultRelInfo *resultRelInfo,
198 bool canSetTag);
199static void ExecSetupTransitionCaptureState(ModifyTableState *mtstate, EState *estate);
200static void fireBSTriggers(ModifyTableState *node);
201static void fireASTriggers(ModifyTableState *node);
202static void ExecInitForPortionOf(ModifyTableState *mtstate, EState *estate,
203 ResultRelInfo *resultRelInfo);
204
205
206/*
207 * Verify that the tuples to be produced by INSERT match the
208 * target relation's rowtype
209 *
210 * We do this to guard against stale plans. If plan invalidation is
211 * functioning properly then we should never get a failure here, but better
212 * safe than sorry. Note that this is called after we have obtained lock
213 * on the target rel, so the rowtype can't change underneath us.
214 *
215 * The plan output is represented by its targetlist, because that makes
216 * handling the dropped-column case easier.
217 *
218 * We used to use this for UPDATE as well, but now the equivalent checks
219 * are done in ExecBuildUpdateProjection.
220 */
221static void
222ExecCheckPlanOutput(Relation resultRel, List *targetList)
223{
224 TupleDesc resultDesc = RelationGetDescr(resultRel);
225 int attno = 0;
226 ListCell *lc;
227
228 foreach(lc, targetList)
229 {
232
233 Assert(!tle->resjunk); /* caller removed junk items already */
234
235 if (attno >= resultDesc->natts)
238 errmsg("table row type and query-specified row type do not match"),
239 errdetail("Query has too many columns.")));
240 attr = TupleDescAttr(resultDesc, attno);
241 attno++;
242
243 /*
244 * Special cases here should match planner's expand_insert_targetlist.
245 */
246 if (attr->attisdropped)
247 {
248 /*
249 * For a dropped column, we can't check atttypid (it's likely 0).
250 * In any case the planner has most likely inserted an INT4 null.
251 * What we insist on is just *some* NULL constant.
252 */
253 if (!IsA(tle->expr, Const) ||
254 !((Const *) tle->expr)->constisnull)
257 errmsg("table row type and query-specified row type do not match"),
258 errdetail("Query provides a value for a dropped column at ordinal position %d.",
259 attno)));
260 }
261 else if (attr->attgenerated)
262 {
263 /*
264 * For a generated column, the planner will have inserted a null
265 * of the column's base type (to avoid possibly failing on domain
266 * not-null constraints). It doesn't seem worth insisting on that
267 * exact type though, since a null value is type-independent. As
268 * above, just insist on *some* NULL constant.
269 */
270 if (!IsA(tle->expr, Const) ||
271 !((Const *) tle->expr)->constisnull)
274 errmsg("table row type and query-specified row type do not match"),
275 errdetail("Query provides a value for a generated column at ordinal position %d.",
276 attno)));
277 }
278 else
279 {
280 /* Normal case: demand type match */
281 if (exprType((Node *) tle->expr) != attr->atttypid)
284 errmsg("table row type and query-specified row type do not match"),
285 errdetail("Table has type %s at ordinal position %d, but query expects %s.",
286 format_type_be(attr->atttypid),
287 attno,
288 format_type_be(exprType((Node *) tle->expr)))));
289 }
290 }
291 if (attno != resultDesc->natts)
294 errmsg("table row type and query-specified row type do not match"),
295 errdetail("Query has too few columns.")));
296}
297
298/*
299 * ExecProcessReturning --- evaluate a RETURNING list
300 *
301 * context: context for the ModifyTable operation
302 * resultRelInfo: current result rel
303 * isDelete: true if the operation/merge action is a DELETE
304 * oldSlot: slot holding old tuple deleted or updated
305 * newSlot: slot holding new tuple inserted or updated
306 * planSlot: slot holding tuple returned by top subplan node
307 *
308 * Note: If oldSlot and newSlot are NULL, the FDW should have already provided
309 * econtext's scan tuple and its old & new tuples are not needed (FDW direct-
310 * modify is disabled if the RETURNING list refers to any OLD/NEW values).
311 *
312 * Note: For the SELECT path of INSERT ... ON CONFLICT DO SELECT, oldSlot and
313 * newSlot are both the existing tuple, since it's not changed.
314 *
315 * Returns a slot holding the result tuple
316 */
317static TupleTableSlot *
319 ResultRelInfo *resultRelInfo,
320 bool isDelete,
323 TupleTableSlot *planSlot)
324{
325 EState *estate = context->estate;
327 ExprContext *econtext = projectReturning->pi_exprContext;
328
329 /* Make tuple and any needed join variables available to ExecProject */
330 if (isDelete)
331 {
332 /* return old tuple by default */
333 if (oldSlot)
334 econtext->ecxt_scantuple = oldSlot;
335 }
336 else
337 {
338 /* return new tuple by default */
339 if (newSlot)
340 econtext->ecxt_scantuple = newSlot;
341 }
342 econtext->ecxt_outertuple = planSlot;
343
344 /* Make old/new tuples available to ExecProject, if required */
345 if (oldSlot)
346 econtext->ecxt_oldtuple = oldSlot;
347 else if (projectReturning->pi_state.flags & EEO_FLAG_HAS_OLD)
348 econtext->ecxt_oldtuple = ExecGetAllNullSlot(estate, resultRelInfo);
349 else
350 econtext->ecxt_oldtuple = NULL; /* No references to OLD columns */
351
352 if (newSlot)
353 econtext->ecxt_newtuple = newSlot;
354 else if (projectReturning->pi_state.flags & EEO_FLAG_HAS_NEW)
355 econtext->ecxt_newtuple = ExecGetAllNullSlot(estate, resultRelInfo);
356 else
357 econtext->ecxt_newtuple = NULL; /* No references to NEW columns */
358
359 /*
360 * Tell ExecProject whether or not the OLD/NEW rows actually exist. This
361 * information is required to evaluate ReturningExpr nodes and also in
362 * ExecEvalSysVar() and ExecEvalWholeRowVar().
363 */
364 if (oldSlot == NULL)
365 projectReturning->pi_state.flags |= EEO_FLAG_OLD_IS_NULL;
366 else
367 projectReturning->pi_state.flags &= ~EEO_FLAG_OLD_IS_NULL;
368
369 if (newSlot == NULL)
370 projectReturning->pi_state.flags |= EEO_FLAG_NEW_IS_NULL;
371 else
372 projectReturning->pi_state.flags &= ~EEO_FLAG_NEW_IS_NULL;
373
374 /* Compute the RETURNING expressions */
376}
377
378/*
379 * ExecCheckTupleVisible -- verify tuple is visible
380 *
381 * It would not be consistent with guarantees of the higher isolation levels to
382 * proceed with avoiding insertion (taking speculative insertion's alternative
383 * path) on the basis of another tuple that is not visible to MVCC snapshot.
384 * Check for the need to raise a serialization failure, and do so as necessary.
385 */
386static void
388 Relation rel,
389 TupleTableSlot *slot)
390{
392 return;
393
394 if (!table_tuple_satisfies_snapshot(rel, slot, estate->es_snapshot))
395 {
397 TransactionId xmin;
398 bool isnull;
399
401 Assert(!isnull);
403
404 /*
405 * We should not raise a serialization failure if the conflict is
406 * against a tuple inserted by our own transaction, even if it's not
407 * visible to our snapshot. (This would happen, for example, if
408 * conflicting keys are proposed for insertion in a single command.)
409 */
413 errmsg("could not serialize access due to concurrent update")));
414 }
415}
416
417/*
418 * ExecCheckTIDVisible -- convenience variant of ExecCheckTupleVisible()
419 */
420static void
423 ItemPointer tid,
425{
426 Relation rel = relinfo->ri_RelationDesc;
427
428 /* Redundantly check isolation level */
430 return;
431
433 elog(ERROR, "failed to fetch conflicting tuple for ON CONFLICT");
434 ExecCheckTupleVisible(estate, rel, tempSlot);
436}
437
438/*
439 * Initialize generated columns handling for a tuple
440 *
441 * This fills the resultRelInfo's ri_GeneratedExprsI/ri_NumGeneratedNeededI or
442 * ri_GeneratedExprsU/ri_NumGeneratedNeededU fields, depending on cmdtype.
443 * This is used only for stored generated columns.
444 *
445 * If cmdType == CMD_UPDATE, the ri_extraUpdatedCols field is filled too.
446 * This is used by both stored and virtual generated columns.
447 *
448 * Note: usually, a given query would need only one of ri_GeneratedExprsI and
449 * ri_GeneratedExprsU per result rel; but MERGE can need both, and so can
450 * cross-partition UPDATEs, since a partition might be the target of both
451 * UPDATE and INSERT actions.
452 */
453void
455 EState *estate,
456 CmdType cmdtype)
457{
458 Relation rel = resultRelInfo->ri_RelationDesc;
459 TupleDesc tupdesc = RelationGetDescr(rel);
460 int natts = tupdesc->natts;
463 Bitmapset *updatedCols;
465
466 /* Nothing to do if no generated columns */
467 if (!(tupdesc->constr && (tupdesc->constr->has_generated_stored || tupdesc->constr->has_generated_virtual)))
468 return;
469
470 /*
471 * In an UPDATE, we can skip computing any generated columns that do not
472 * depend on any UPDATE target column. But if there is a BEFORE ROW
473 * UPDATE trigger, we cannot skip because the trigger might change more
474 * columns.
475 */
476 if (cmdtype == CMD_UPDATE &&
478 updatedCols = ExecGetUpdatedCols(resultRelInfo, estate);
479 else
480 updatedCols = NULL;
481
482 /*
483 * Make sure these data structures are built in the per-query memory
484 * context so they'll survive throughout the query.
485 */
487
488 ri_GeneratedExprs = (ExprState **) palloc0(natts * sizeof(ExprState *));
490
491 for (int i = 0; i < natts; i++)
492 {
493 char attgenerated = TupleDescAttr(tupdesc, i)->attgenerated;
494
495 if (attgenerated)
496 {
497 Expr *expr;
498
499 /* Fetch the GENERATED AS expression tree */
500 expr = (Expr *) build_column_default(rel, i + 1);
501 if (expr == NULL)
502 elog(ERROR, "no generation expression found for column number %d of table \"%s\"",
503 i + 1, RelationGetRelationName(rel));
504
505 /*
506 * If it's an update with a known set of update target columns,
507 * see if we can skip the computation.
508 */
509 if (updatedCols)
510 {
511 Bitmapset *attrs_used = NULL;
512
513 pull_varattnos((Node *) expr, 1, &attrs_used);
514
515 if (!bms_overlap(updatedCols, attrs_used))
516 continue; /* need not update this column */
517 }
518
519 /* No luck, so prepare the expression for execution */
520 if (attgenerated == ATTRIBUTE_GENERATED_STORED)
521 {
522 ri_GeneratedExprs[i] = ExecPrepareExpr(expr, estate);
524 }
525
526 /* If UPDATE, mark column in resultRelInfo->ri_extraUpdatedCols */
527 if (cmdtype == CMD_UPDATE)
528 resultRelInfo->ri_extraUpdatedCols =
529 bms_add_member(resultRelInfo->ri_extraUpdatedCols,
531 }
532 }
533
534 if (ri_NumGeneratedNeeded == 0)
535 {
536 /* didn't need it after all */
539 }
540
541 /* Save in appropriate set of fields */
542 if (cmdtype == CMD_UPDATE)
543 {
544 /* Don't call twice */
545 Assert(resultRelInfo->ri_GeneratedExprsU == NULL);
546
547 resultRelInfo->ri_GeneratedExprsU = ri_GeneratedExprs;
549
550 resultRelInfo->ri_extraUpdatedCols_valid = true;
551 }
552 else
553 {
554 /* Don't call twice */
555 Assert(resultRelInfo->ri_GeneratedExprsI == NULL);
556
557 resultRelInfo->ri_GeneratedExprsI = ri_GeneratedExprs;
559 }
560
562}
563
564/*
565 * Compute stored generated columns for a tuple
566 */
567void
569 EState *estate, TupleTableSlot *slot,
570 CmdType cmdtype)
571{
572 Relation rel = resultRelInfo->ri_RelationDesc;
573 TupleDesc tupdesc = RelationGetDescr(rel);
574 int natts = tupdesc->natts;
575 ExprContext *econtext = GetPerTupleExprContext(estate);
578 Datum *values;
579 bool *nulls;
580
581 /* We should not be called unless this is true */
582 Assert(tupdesc->constr && tupdesc->constr->has_generated_stored);
583
584 /*
585 * Initialize the expressions if we didn't already, and check whether we
586 * can exit early because nothing needs to be computed.
587 */
588 if (cmdtype == CMD_UPDATE)
589 {
590 if (resultRelInfo->ri_GeneratedExprsU == NULL)
591 ExecInitGenerated(resultRelInfo, estate, cmdtype);
592 if (resultRelInfo->ri_NumGeneratedNeededU == 0)
593 return;
594 ri_GeneratedExprs = resultRelInfo->ri_GeneratedExprsU;
595 }
596 else
597 {
598 if (resultRelInfo->ri_GeneratedExprsI == NULL)
599 ExecInitGenerated(resultRelInfo, estate, cmdtype);
600 /* Early exit is impossible given the prior Assert */
601 Assert(resultRelInfo->ri_NumGeneratedNeededI > 0);
602 ri_GeneratedExprs = resultRelInfo->ri_GeneratedExprsI;
603 }
604
606
607 values = palloc_array(Datum, natts);
608 nulls = palloc_array(bool, natts);
609
610 slot_getallattrs(slot);
611 memcpy(nulls, slot->tts_isnull, sizeof(*nulls) * natts);
612
613 for (int i = 0; i < natts; i++)
614 {
615 CompactAttribute *attr = TupleDescCompactAttr(tupdesc, i);
616
617 if (ri_GeneratedExprs[i])
618 {
619 Datum val;
620 bool isnull;
621
622 Assert(TupleDescAttr(tupdesc, i)->attgenerated == ATTRIBUTE_GENERATED_STORED);
623
624 econtext->ecxt_scantuple = slot;
625
626 val = ExecEvalExpr(ri_GeneratedExprs[i], econtext, &isnull);
627
628 /*
629 * We must make a copy of val as we have no guarantees about where
630 * memory for a pass-by-reference Datum is located.
631 */
632 if (!isnull)
633 val = datumCopy(val, attr->attbyval, attr->attlen);
634
635 values[i] = val;
636 nulls[i] = isnull;
637 }
638 else
639 {
640 if (!nulls[i])
641 values[i] = datumCopy(slot->tts_values[i], attr->attbyval, attr->attlen);
642 }
643 }
644
645 ExecClearTuple(slot);
646 memcpy(slot->tts_values, values, sizeof(*values) * natts);
647 memcpy(slot->tts_isnull, nulls, sizeof(*nulls) * natts);
650
652}
653
654/*
655 * ExecInitInsertProjection
656 * Do one-time initialization of projection data for INSERT tuples.
657 *
658 * INSERT queries may need a projection to filter out junk attrs in the tlist.
659 *
660 * This is also a convenient place to verify that the
661 * output of an INSERT matches the target table.
662 */
663static void
665 ResultRelInfo *resultRelInfo)
666{
667 ModifyTable *node = (ModifyTable *) mtstate->ps.plan;
668 Plan *subplan = outerPlan(node);
669 EState *estate = mtstate->ps.state;
671 bool need_projection = false;
672 ListCell *l;
673
674 /* Extract non-junk columns of the subplan's result tlist. */
675 foreach(l, subplan->targetlist)
676 {
678
679 if (!tle->resjunk)
681 else
682 need_projection = true;
683 }
684
685 /*
686 * The junk-free list must produce a tuple suitable for the result
687 * relation.
688 */
690
691 /* We'll need a slot matching the table's format. */
692 resultRelInfo->ri_newTupleSlot =
693 table_slot_create(resultRelInfo->ri_RelationDesc,
694 &estate->es_tupleTable);
695
696 /* Build ProjectionInfo if needed (it probably isn't). */
697 if (need_projection)
698 {
700
701 /* need an expression context to do the projection */
702 if (mtstate->ps.ps_ExprContext == NULL)
703 ExecAssignExprContext(estate, &mtstate->ps);
704
705 resultRelInfo->ri_projectNew =
707 mtstate->ps.ps_ExprContext,
708 resultRelInfo->ri_newTupleSlot,
709 &mtstate->ps,
710 relDesc);
711 }
712
713 resultRelInfo->ri_projectNewInfoValid = true;
714}
715
716/*
717 * ExecInitUpdateProjection
718 * Do one-time initialization of projection data for UPDATE tuples.
719 *
720 * UPDATE always needs a projection, because (1) there's always some junk
721 * attrs, and (2) we may need to merge values of not-updated columns from
722 * the old tuple into the final tuple. In UPDATE, the tuple arriving from
723 * the subplan contains only new values for the changed columns, plus row
724 * identity info in the junk attrs.
725 *
726 * This is "one-time" for any given result rel, but we might touch more than
727 * one result rel in the course of an inherited UPDATE, and each one needs
728 * its own projection due to possible column order variation.
729 *
730 * This is also a convenient place to verify that the output of an UPDATE
731 * matches the target table (ExecBuildUpdateProjection does that).
732 */
733static void
735 ResultRelInfo *resultRelInfo)
736{
737 ModifyTable *node = (ModifyTable *) mtstate->ps.plan;
738 Plan *subplan = outerPlan(node);
739 EState *estate = mtstate->ps.state;
741 int whichrel;
743
744 /*
745 * Usually, mt_lastResultIndex matches the target rel. If it happens not
746 * to, we can get the index the hard way with an integer division.
747 */
748 whichrel = mtstate->mt_lastResultIndex;
749 if (resultRelInfo != mtstate->resultRelInfo + whichrel)
750 {
751 whichrel = resultRelInfo - mtstate->resultRelInfo;
752 Assert(whichrel >= 0 && whichrel < mtstate->mt_nrels);
753 }
754
756
757 /*
758 * For UPDATE, we use the old tuple to fill up missing values in the tuple
759 * produced by the subplan to get the new tuple. We need two slots, both
760 * matching the table's desired format.
761 */
762 resultRelInfo->ri_oldTupleSlot =
763 table_slot_create(resultRelInfo->ri_RelationDesc,
764 &estate->es_tupleTable);
765 resultRelInfo->ri_newTupleSlot =
766 table_slot_create(resultRelInfo->ri_RelationDesc,
767 &estate->es_tupleTable);
768
769 /* need an expression context to do the projection */
770 if (mtstate->ps.ps_ExprContext == NULL)
771 ExecAssignExprContext(estate, &mtstate->ps);
772
773 resultRelInfo->ri_projectNew =
775 false, /* subplan did the evaluation */
777 relDesc,
778 mtstate->ps.ps_ExprContext,
779 resultRelInfo->ri_newTupleSlot,
780 &mtstate->ps);
781
782 resultRelInfo->ri_projectNewInfoValid = true;
783}
784
785/*
786 * ExecGetInsertNewTuple
787 * This prepares a "new" tuple ready to be inserted into given result
788 * relation, by removing any junk columns of the plan's output tuple
789 * and (if necessary) coercing the tuple to the right tuple format.
790 */
791static TupleTableSlot *
793 TupleTableSlot *planSlot)
794{
795 ProjectionInfo *newProj = relinfo->ri_projectNew;
796 ExprContext *econtext;
797
798 /*
799 * If there's no projection to be done, just make sure the slot is of the
800 * right type for the target rel. If the planSlot is the right type we
801 * can use it as-is, else copy the data into ri_newTupleSlot.
802 */
803 if (newProj == NULL)
804 {
805 if (relinfo->ri_newTupleSlot->tts_ops != planSlot->tts_ops)
806 {
807 ExecCopySlot(relinfo->ri_newTupleSlot, planSlot);
808 return relinfo->ri_newTupleSlot;
809 }
810 else
811 return planSlot;
812 }
813
814 /*
815 * Else project; since the projection output slot is ri_newTupleSlot, this
816 * will also fix any slot-type problem.
817 *
818 * Note: currently, this is dead code, because INSERT cases don't receive
819 * any junk columns so there's never a projection to be done.
820 */
821 econtext = newProj->pi_exprContext;
822 econtext->ecxt_outertuple = planSlot;
823 return ExecProject(newProj);
824}
825
826/*
827 * ExecGetUpdateNewTuple
828 * This prepares a "new" tuple by combining an UPDATE subplan's output
829 * tuple (which contains values of changed columns) with unchanged
830 * columns taken from the old tuple.
831 *
832 * The subplan tuple might also contain junk columns, which are ignored.
833 * Note that the projection also ensures we have a slot of the right type.
834 */
837 TupleTableSlot *planSlot,
839{
840 ProjectionInfo *newProj = relinfo->ri_projectNew;
841 ExprContext *econtext;
842
843 /* Use a few extra Asserts to protect against outside callers */
844 Assert(relinfo->ri_projectNewInfoValid);
845 Assert(planSlot != NULL && !TTS_EMPTY(planSlot));
847
848 econtext = newProj->pi_exprContext;
849 econtext->ecxt_outertuple = planSlot;
850 econtext->ecxt_scantuple = oldSlot;
851 return ExecProject(newProj);
852}
853
854/* ----------------------------------------------------------------
855 * ExecInsert
856 *
857 * For INSERT, we have to insert the tuple into the target relation
858 * (or partition thereof) and insert appropriate tuples into the index
859 * relations.
860 *
861 * slot contains the new tuple value to be stored.
862 *
863 * Returns RETURNING result if any, otherwise NULL.
864 * *inserted_tuple is the tuple that's effectively inserted;
865 * *insert_destrel is the relation where it was inserted.
866 * These are only set on success.
867 *
868 * This may change the currently active tuple conversion map in
869 * mtstate->mt_transition_capture, so the callers must take care to
870 * save the previous value to avoid losing track of it.
871 * ----------------------------------------------------------------
872 */
873static TupleTableSlot *
875 ResultRelInfo *resultRelInfo,
876 TupleTableSlot *slot,
877 bool canSetTag,
880{
881 ModifyTableState *mtstate = context->mtstate;
882 EState *estate = context->estate;
885 TupleTableSlot *planSlot = context->planSlot;
888 ModifyTable *node = (ModifyTable *) mtstate->ps.plan;
889 OnConflictAction onconflict = node->onConflictAction;
892
893 /*
894 * If the input result relation is a partitioned table, find the leaf
895 * partition to insert the tuple into.
896 */
897 if (proute)
898 {
900
901 slot = ExecPrepareTupleRouting(mtstate, estate, proute,
902 resultRelInfo, slot,
903 &partRelInfo);
904 resultRelInfo = partRelInfo;
905 }
906
908
909 resultRelationDesc = resultRelInfo->ri_RelationDesc;
910
911 /*
912 * Open the table's indexes, if we have not done so already, so that we
913 * can add new index entries for the inserted tuple.
914 */
915 if (resultRelationDesc->rd_rel->relhasindex &&
916 resultRelInfo->ri_IndexRelationDescs == NULL)
917 ExecOpenIndices(resultRelInfo, onconflict != ONCONFLICT_NONE);
918
919 /*
920 * BEFORE ROW INSERT Triggers.
921 *
922 * Note: We fire BEFORE ROW TRIGGERS for every attempted insertion in an
923 * INSERT ... ON CONFLICT statement. We cannot check for constraint
924 * violations before firing these triggers, because they can change the
925 * values to insert. Also, they can run arbitrary user-defined code with
926 * side-effects that we can't cancel by just not inserting the tuple.
927 */
928 if (resultRelInfo->ri_TrigDesc &&
929 resultRelInfo->ri_TrigDesc->trig_insert_before_row)
930 {
931 /* Flush any pending inserts, so rows are visible to the triggers */
933 ExecPendingInserts(estate);
934
935 if (!ExecBRInsertTriggers(estate, resultRelInfo, slot))
936 return NULL; /* "do nothing" */
937 }
938
939 /* INSTEAD OF ROW INSERT Triggers */
940 if (resultRelInfo->ri_TrigDesc &&
941 resultRelInfo->ri_TrigDesc->trig_insert_instead_row)
942 {
943 if (!ExecIRInsertTriggers(estate, resultRelInfo, slot))
944 return NULL; /* "do nothing" */
945 }
946 else if (resultRelInfo->ri_FdwRoutine)
947 {
948 /*
949 * GENERATED expressions might reference the tableoid column, so
950 * (re-)initialize tts_tableOid before evaluating them.
951 */
952 slot->tts_tableOid = RelationGetRelid(resultRelInfo->ri_RelationDesc);
953
954 /*
955 * Compute stored generated columns
956 */
957 if (resultRelationDesc->rd_att->constr &&
958 resultRelationDesc->rd_att->constr->has_generated_stored)
959 ExecComputeStoredGenerated(resultRelInfo, estate, slot,
960 CMD_INSERT);
961
962 /*
963 * If the FDW supports batching, and batching is requested, accumulate
964 * rows and insert them in batches. Otherwise use the per-row inserts.
965 */
966 if (resultRelInfo->ri_BatchSize > 1)
967 {
968 bool flushed = false;
969
970 /*
971 * When we've reached the desired batch size, perform the
972 * insertion.
973 */
974 if (resultRelInfo->ri_NumSlots == resultRelInfo->ri_BatchSize)
975 {
976 ExecBatchInsert(mtstate, resultRelInfo,
977 resultRelInfo->ri_Slots,
978 resultRelInfo->ri_PlanSlots,
979 resultRelInfo->ri_NumSlots,
980 estate, canSetTag);
981 flushed = true;
982 }
983
985
986 if (resultRelInfo->ri_Slots == NULL)
987 {
988 resultRelInfo->ri_Slots = palloc_array(TupleTableSlot *, resultRelInfo->ri_BatchSize);
989 resultRelInfo->ri_PlanSlots = palloc_array(TupleTableSlot *, resultRelInfo->ri_BatchSize);
990 }
991
992 /*
993 * Initialize the batch slots. We don't know how many slots will
994 * be needed, so we initialize them as the batch grows, and we
995 * keep them across batches. To mitigate an inefficiency in how
996 * resource owner handles objects with many references (as with
997 * many slots all referencing the same tuple descriptor) we copy
998 * the appropriate tuple descriptor for each slot.
999 */
1000 if (resultRelInfo->ri_NumSlots >= resultRelInfo->ri_NumSlotsInitialized)
1001 {
1005
1006 resultRelInfo->ri_Slots[resultRelInfo->ri_NumSlots] =
1008
1009 resultRelInfo->ri_PlanSlots[resultRelInfo->ri_NumSlots] =
1011
1012 /* remember how many batch slots we initialized */
1013 resultRelInfo->ri_NumSlotsInitialized++;
1014 }
1015
1016 ExecCopySlot(resultRelInfo->ri_Slots[resultRelInfo->ri_NumSlots],
1017 slot);
1018
1019 ExecCopySlot(resultRelInfo->ri_PlanSlots[resultRelInfo->ri_NumSlots],
1020 planSlot);
1021
1022 /*
1023 * If these are the first tuples stored in the buffers, add the
1024 * target rel and the mtstate to the
1025 * es_insert_pending_result_relations and
1026 * es_insert_pending_modifytables lists respectively, except in
1027 * the case where flushing was done above, in which case they
1028 * would already have been added to the lists, so no need to do
1029 * this.
1030 */
1031 if (resultRelInfo->ri_NumSlots == 0 && !flushed)
1032 {
1034 resultRelInfo));
1037 resultRelInfo);
1039 lappend(estate->es_insert_pending_modifytables, mtstate);
1040 }
1042 resultRelInfo));
1043
1044 resultRelInfo->ri_NumSlots++;
1045
1047
1048 return NULL;
1049 }
1050
1051 /*
1052 * insert into foreign table: let the FDW do it
1053 */
1054 slot = resultRelInfo->ri_FdwRoutine->ExecForeignInsert(estate,
1055 resultRelInfo,
1056 slot,
1057 planSlot);
1058
1059 if (slot == NULL) /* "do nothing" */
1060 return NULL;
1061
1062 /*
1063 * AFTER ROW Triggers or RETURNING expressions might reference the
1064 * tableoid column, so (re-)initialize tts_tableOid before evaluating
1065 * them. (This covers the case where the FDW replaced the slot.)
1066 */
1067 slot->tts_tableOid = RelationGetRelid(resultRelInfo->ri_RelationDesc);
1068 }
1069 else
1070 {
1072
1073 /*
1074 * Constraints and GENERATED expressions might reference the tableoid
1075 * column, so (re-)initialize tts_tableOid before evaluating them.
1076 */
1078
1079 /*
1080 * Compute stored generated columns
1081 */
1082 if (resultRelationDesc->rd_att->constr &&
1083 resultRelationDesc->rd_att->constr->has_generated_stored)
1084 ExecComputeStoredGenerated(resultRelInfo, estate, slot,
1085 CMD_INSERT);
1086
1087 /*
1088 * Check any RLS WITH CHECK policies.
1089 *
1090 * Normally we should check INSERT policies. But if the insert is the
1091 * result of a partition key update that moved the tuple to a new
1092 * partition, we should instead check UPDATE policies, because we are
1093 * executing policies defined on the target table, and not those
1094 * defined on the child partitions.
1095 *
1096 * If we're running MERGE, we refer to the action that we're executing
1097 * to know if we're doing an INSERT or UPDATE to a partition table.
1098 */
1099 if (mtstate->operation == CMD_UPDATE)
1101 else if (mtstate->operation == CMD_MERGE)
1104 else
1106
1107 /*
1108 * ExecWithCheckOptions() will skip any WCOs which are not of the kind
1109 * we are looking for at this point.
1110 */
1111 if (resultRelInfo->ri_WithCheckOptions != NIL)
1112 ExecWithCheckOptions(wco_kind, resultRelInfo, slot, estate);
1113
1114 /*
1115 * Check the constraints of the tuple.
1116 */
1117 if (resultRelationDesc->rd_att->constr)
1118 ExecConstraints(resultRelInfo, slot, estate);
1119
1120 /*
1121 * Also check the tuple against the partition constraint, if there is
1122 * one; except that if we got here via tuple-routing, we don't need to
1123 * if there's no BR trigger defined on the partition.
1124 */
1125 if (resultRelationDesc->rd_rel->relispartition &&
1126 (resultRelInfo->ri_RootResultRelInfo == NULL ||
1127 (resultRelInfo->ri_TrigDesc &&
1128 resultRelInfo->ri_TrigDesc->trig_insert_before_row)))
1129 ExecPartitionCheck(resultRelInfo, slot, estate, true);
1130
1131 if (onconflict != ONCONFLICT_NONE && resultRelInfo->ri_NumIndices > 0)
1132 {
1133 /* Perform a speculative insertion. */
1137 bool specConflict;
1138 List *arbiterIndexes;
1139
1141 arbiterIndexes = resultRelInfo->ri_onConflictArbiterIndexes;
1142
1143 /*
1144 * Do a non-conclusive check for conflicts first.
1145 *
1146 * We're not holding any locks yet, so this doesn't guarantee that
1147 * the later insert won't conflict. But it avoids leaving behind
1148 * a lot of canceled speculative insertions, if you run a lot of
1149 * INSERT ON CONFLICT statements that do conflict.
1150 *
1151 * We loop back here if we find a conflict below, either during
1152 * the pre-check, or when we re-check after inserting the tuple
1153 * speculatively. Better allow interrupts in case some bug makes
1154 * this an infinite loop.
1155 */
1156 vlock:
1158 specConflict = false;
1159 if (!ExecCheckIndexConstraints(resultRelInfo, slot, estate,
1161 arbiterIndexes))
1162 {
1163 /* committed conflict tuple found */
1164 if (onconflict == ONCONFLICT_UPDATE)
1165 {
1166 /*
1167 * In case of ON CONFLICT DO UPDATE, execute the UPDATE
1168 * part. Be prepared to retry if the UPDATE fails because
1169 * of another concurrent UPDATE/DELETE to the conflict
1170 * tuple.
1171 */
1172 TupleTableSlot *returning = NULL;
1173
1174 if (ExecOnConflictUpdate(context, resultRelInfo,
1175 &conflictTid, slot, canSetTag,
1176 &returning))
1177 {
1178 InstrCountTuples2(&mtstate->ps, 1);
1179 return returning;
1180 }
1181 else
1182 goto vlock;
1183 }
1184 else if (onconflict == ONCONFLICT_SELECT)
1185 {
1186 /*
1187 * In case of ON CONFLICT DO SELECT, optionally lock the
1188 * conflicting tuple, fetch it and project RETURNING on
1189 * it. Be prepared to retry if locking fails because of a
1190 * concurrent UPDATE/DELETE to the conflict tuple.
1191 */
1192 TupleTableSlot *returning = NULL;
1193
1194 if (ExecOnConflictSelect(context, resultRelInfo,
1195 &conflictTid, slot, canSetTag,
1196 &returning))
1197 {
1198 InstrCountTuples2(&mtstate->ps, 1);
1199 return returning;
1200 }
1201 else
1202 goto vlock;
1203 }
1204 else
1205 {
1206 /*
1207 * In case of ON CONFLICT DO NOTHING, do nothing. However,
1208 * verify that the tuple is visible to the executor's MVCC
1209 * snapshot at higher isolation levels.
1210 *
1211 * Using ExecGetReturningSlot() to store the tuple for the
1212 * recheck isn't that pretty, but we can't trivially use
1213 * the input slot, because it might not be of a compatible
1214 * type. As there's no conflicting usage of
1215 * ExecGetReturningSlot() in the DO NOTHING case...
1216 */
1217 Assert(onconflict == ONCONFLICT_NOTHING);
1218 ExecCheckTIDVisible(estate, resultRelInfo, &conflictTid,
1219 ExecGetReturningSlot(estate, resultRelInfo));
1220 InstrCountTuples2(&mtstate->ps, 1);
1221 return NULL;
1222 }
1223 }
1224
1225 /*
1226 * Before we start insertion proper, acquire our "speculative
1227 * insertion lock". Others can use that to wait for us to decide
1228 * if we're going to go ahead with the insertion, instead of
1229 * waiting for the whole transaction to complete.
1230 */
1231 INJECTION_POINT("exec-insert-before-insert-speculative", NULL);
1233
1234 /* insert the tuple, with the speculative token */
1236 estate->es_output_cid,
1237 0,
1238 NULL,
1239 specToken);
1240
1241 /* insert index entries for tuple */
1242 recheckIndexes = ExecInsertIndexTuples(resultRelInfo,
1243 estate, EIIT_NO_DUPE_ERROR,
1244 slot, arbiterIndexes,
1245 &specConflict);
1246
1247 /* adjust the tuple's state accordingly */
1250
1251 /*
1252 * Wake up anyone waiting for our decision. They will re-check
1253 * the tuple, see that it's no longer speculative, and wait on our
1254 * XID as if this was a regularly inserted tuple all along. Or if
1255 * we killed the tuple, they will see it's dead, and proceed as if
1256 * the tuple never existed.
1257 */
1259
1260 /*
1261 * If there was a conflict, start from the beginning. We'll do
1262 * the pre-check again, which will now find the conflicting tuple
1263 * (unless it aborts before we get there).
1264 */
1265 if (specConflict)
1266 {
1268 goto vlock;
1269 }
1270
1271 /* Since there was no insertion conflict, we're done */
1272 }
1273 else
1274 {
1275 /* insert the tuple normally */
1277 estate->es_output_cid,
1278 0, NULL);
1279
1280 /* insert index entries for tuple */
1281 if (resultRelInfo->ri_NumIndices > 0)
1282 recheckIndexes = ExecInsertIndexTuples(resultRelInfo, estate,
1283 0, slot, NIL,
1284 NULL);
1285 }
1286 }
1287
1288 if (canSetTag)
1289 (estate->es_processed)++;
1290
1291 /*
1292 * If this insert is the result of a partition key update that moved the
1293 * tuple to a new partition, put this row into the transition NEW TABLE,
1294 * if there is one. We need to do this separately for DELETE and INSERT
1295 * because they happen on different tables.
1296 */
1298 if (mtstate->operation == CMD_UPDATE && mtstate->mt_transition_capture
1300 {
1301 ExecARUpdateTriggers(estate, resultRelInfo,
1302 NULL, NULL,
1303 NULL,
1304 NULL,
1305 slot,
1306 NULL,
1307 mtstate->mt_transition_capture,
1308 false);
1309
1310 /*
1311 * We've already captured the NEW TABLE row, so make sure any AR
1312 * INSERT trigger fired below doesn't capture it again.
1313 */
1315 }
1316
1317 /* AFTER ROW INSERT Triggers */
1318 ExecARInsertTriggers(estate, resultRelInfo, slot, recheckIndexes,
1320
1322
1323 /*
1324 * Check any WITH CHECK OPTION constraints from parent views. We are
1325 * required to do this after testing all constraints and uniqueness
1326 * violations per the SQL spec, so we do it after actually inserting the
1327 * record into the heap and all indexes.
1328 *
1329 * ExecWithCheckOptions will elog(ERROR) if a violation is found, so the
1330 * tuple will never be seen, if it violates the WITH CHECK OPTION.
1331 *
1332 * ExecWithCheckOptions() will skip any WCOs which are not of the kind we
1333 * are looking for at this point.
1334 */
1335 if (resultRelInfo->ri_WithCheckOptions != NIL)
1336 ExecWithCheckOptions(WCO_VIEW_CHECK, resultRelInfo, slot, estate);
1337
1338 /* Process RETURNING if present */
1339 if (resultRelInfo->ri_projectReturning)
1340 {
1342
1343 /*
1344 * If this is part of a cross-partition UPDATE, and the RETURNING list
1345 * refers to any OLD columns, ExecDelete() will have saved the tuple
1346 * deleted from the original partition, which we must use here to
1347 * compute the OLD column values. Otherwise, all OLD column values
1348 * will be NULL.
1349 */
1350 if (context->cpDeletedSlot)
1351 {
1353
1354 /*
1355 * Convert the OLD tuple to the new partition's format/slot, if
1356 * needed. Note that ExecDelete() already converted it to the
1357 * root's partition's format/slot.
1358 */
1359 oldSlot = context->cpDeletedSlot;
1360 tupconv_map = ExecGetRootToChildMap(resultRelInfo, estate);
1361 if (tupconv_map != NULL)
1362 {
1364 oldSlot,
1365 ExecGetReturningSlot(estate,
1366 resultRelInfo));
1367
1368 oldSlot->tts_tableOid = context->cpDeletedSlot->tts_tableOid;
1369 ItemPointerCopy(&context->cpDeletedSlot->tts_tid, &oldSlot->tts_tid);
1370 }
1371 }
1372
1373 result = ExecProcessReturning(context, resultRelInfo, false,
1374 oldSlot, slot, planSlot);
1375
1376 /*
1377 * For a cross-partition UPDATE, release the old tuple, first making
1378 * sure that the result slot has a local copy of any pass-by-reference
1379 * values.
1380 */
1381 if (context->cpDeletedSlot)
1382 {
1385 if (context->cpDeletedSlot != oldSlot)
1386 ExecClearTuple(context->cpDeletedSlot);
1387 context->cpDeletedSlot = NULL;
1388 }
1389 }
1390
1391 if (inserted_tuple)
1392 *inserted_tuple = slot;
1393 if (insert_destrel)
1394 *insert_destrel = resultRelInfo;
1395
1396 return result;
1397}
1398
1399/* ----------------------------------------------------------------
1400 * ExecForPortionOfLeftovers
1401 *
1402 * Insert tuples for the untouched portion of a row in a FOR
1403 * PORTION OF UPDATE/DELETE
1404 * ----------------------------------------------------------------
1405 */
1406static void
1408 EState *estate,
1409 ResultRelInfo *resultRelInfo,
1411{
1412 ModifyTableState *mtstate = context->mtstate;
1413 ModifyTable *node = (ModifyTable *) mtstate->ps.plan;
1414 ForPortionOfExpr *forPortionOf = (ForPortionOfExpr *) node->forPortionOf;
1416 TypeCacheEntry *typcache;
1420 TupleConversionMap *map = NULL;
1421 HeapTuple oldtuple = NULL;
1424 FmgrInfo flinfo;
1426 ReturnSetInfo rsi;
1427 bool didInit = false;
1428 bool shouldFree = false;
1430 bool partitionRouting =
1431 rootRelInfo &&
1433
1434 LOCAL_FCINFO(fcinfo, 2);
1435
1436 fpoState = resultRelInfo->ri_forPortionOf;
1438 leftoverSlot = fpoState->fp_Leftover;
1439
1440 /*
1441 * Get the old pre-UPDATE/DELETE tuple. We will use its range to compute
1442 * untouched parts of history, and if necessary we will insert copies with
1443 * truncated start/end times.
1444 *
1445 * We have already locked the tuple in ExecUpdate/ExecDelete, and it has
1446 * passed EvalPlanQual. This ensures that concurrent updates in READ
1447 * COMMITTED can't insert conflicting temporal leftovers.
1448 *
1449 * It does *not* protect against concurrent update/deletes overlooking
1450 * each others' leftovers though. See our isolation tests for details
1451 * about that and a viable workaround.
1452 */
1454 elog(ERROR, "failed to fetch tuple for FOR PORTION OF");
1455
1457
1458 /* Get the old range of the record being updated/deleted. */
1459 if (oldtupleSlot->tts_isnull[fpoState->fp_rangeAttno - 1])
1460 elog(ERROR, "found a NULL range in a temporal table");
1461 oldRange = oldtupleSlot->tts_values[fpoState->fp_rangeAttno - 1];
1462
1463 /*
1464 * Get the range's type cache entry. This is worth caching for the whole
1465 * UPDATE/DELETE as range functions do.
1466 */
1467
1468 typcache = fpoState->fp_leftoverstypcache;
1469 if (typcache == NULL)
1470 {
1471 typcache = lookup_type_cache(forPortionOf->rangeType, 0);
1472 fpoState->fp_leftoverstypcache = typcache;
1473 }
1474
1475 /*
1476 * Get the ranges to the left/right of the targeted range. We call a SETOF
1477 * support function and insert as many temporal leftovers as it gives us.
1478 * Although rangetypes have 0/1/2 leftovers, multiranges have 0/1, and
1479 * other types may have more.
1480 */
1481
1482 fmgr_info(forPortionOf->withoutPortionProc, &flinfo);
1483 rsi.type = T_ReturnSetInfo;
1484 rsi.econtext = mtstate->ps.ps_ExprContext;
1485 rsi.expectedDesc = NULL;
1488 /* isDone is filled below */
1489 rsi.setResult = NULL;
1490 rsi.setDesc = NULL;
1491
1492 InitFunctionCallInfoData(*fcinfo, &flinfo, 2, InvalidOid, NULL, (Node *) &rsi);
1493 fcinfo->args[0].value = oldRange;
1494 fcinfo->args[0].isnull = false;
1495 fcinfo->args[1].value = fpoState->fp_targetRange;
1496 fcinfo->args[1].isnull = false;
1497
1498 /*
1499 * For partitioned tables, we must read leftovers with the tuple
1500 * descriptor of the child table, but insert into the root table to enable
1501 * tuple routing. So leftoverSlot is configured with the root's tuple
1502 * descriptor. But for traditional table inheritance, we don't need tuple
1503 * routing and just insert directly into the child table to preserve
1504 * child-specific columns. In that case, leftoverSlot uses the child's
1505 * (resultRelInfo) tuple descriptor.
1506 */
1507 if (partitionRouting)
1508 {
1509 map = ExecGetChildToRootMap(resultRelInfo);
1510 resultRelInfo = resultRelInfo->ri_RootResultRelInfo;
1511 }
1512
1513 /*
1514 * Insert a leftover for each value returned by the without_portion helper
1515 * function
1516 */
1517 while (true)
1518 {
1520
1521 /* Call the function one time */
1523
1524 fcinfo->isnull = false;
1526 leftover = FunctionCallInvoke(fcinfo);
1527
1529 rsi.isDone != ExprMultipleResult);
1530
1531 if (rsi.returnMode != SFRM_ValuePerCall)
1532 elog(ERROR, "without_portion function violated function call protocol");
1533
1534 /* Are we done? */
1535 if (rsi.isDone == ExprEndResult)
1536 break;
1537
1538 if (fcinfo->isnull)
1539 elog(ERROR, "got a null from without_portion function");
1540
1541 /*
1542 * Does the new Datum violate domain checks? Row-level CHECK
1543 * constraints are validated by ExecInsert, so we don't need to do
1544 * anything here for those.
1545 */
1546 if (forPortionOf->isDomain)
1547 domain_check(leftover, false, forPortionOf->rangeVar->vartype, NULL, NULL);
1548
1549 if (!didInit)
1550 {
1551 /*
1552 * Make a copy of the pre-UPDATE row. Then we'll overwrite the
1553 * range column below. Only partitioned targets need conversion to
1554 * the root table's format, because they reinsert through the root
1555 * relation for tuple routing.
1556 */
1557 if (map != NULL)
1558 {
1561 leftoverSlot);
1562 }
1563 else
1564 {
1565 oldtuple = ExecFetchSlotHeapTuple(oldtupleSlot, false, &shouldFree);
1566 ExecForceStoreHeapTuple(oldtuple, leftoverSlot, false);
1567 }
1568
1569 /*
1570 * Save some mtstate things so we can restore them below. XXX:
1571 * Should we create our own ModifyTableState instead?
1572 */
1573 oldOperation = mtstate->operation;
1574 mtstate->operation = CMD_INSERT;
1575 oldTcs = mtstate->mt_transition_capture;
1576
1577 didInit = true;
1578 }
1579 else
1580 {
1581 /*
1582 * Re-copy the original row into leftoverSlot because ExecInsert
1583 * might pass leftoverSlot to BEFORE ROW INSERT triggers, which
1584 * can modify the slot contents.
1585 */
1586 if (map != NULL)
1588 else
1589 ExecForceStoreHeapTuple(oldtuple, leftoverSlot, false);
1590 }
1591
1592 leftoverSlot->tts_values[resultRelInfo->ri_forPortionOf->fp_rangeAttno - 1] = leftover;
1593 leftoverSlot->tts_isnull[resultRelInfo->ri_forPortionOf->fp_rangeAttno - 1] = false;
1595
1596 /*
1597 * The standard says that each temporal leftover should execute its
1598 * own INSERT statement, firing all statement and row triggers, but
1599 * skipping insert permission checks. Therefore we give each insert
1600 * its own transition table. If we just push & pop a new trigger level
1601 * for each insert, we get exactly what we need.
1602 *
1603 * We have to make sure that the inserts don't add to the ROW_COUNT
1604 * diagnostic or the command tag, so we pass false for canSetTag.
1605 */
1607 ExecSetupTransitionCaptureState(mtstate, estate);
1608 fireBSTriggers(mtstate);
1609 ExecInsert(context, resultRelInfo, leftoverSlot, false, NULL, NULL);
1610 fireASTriggers(mtstate);
1611 AfterTriggerEndQuery(estate);
1612 }
1613
1614 if (didInit)
1615 {
1616 mtstate->operation = oldOperation;
1617 mtstate->mt_transition_capture = oldTcs;
1618
1619 if (shouldFree)
1620 heap_freetuple(oldtuple);
1621 }
1622}
1623
1624/* ----------------------------------------------------------------
1625 * ExecBatchInsert
1626 *
1627 * Insert multiple tuples in an efficient way.
1628 * Currently, this handles inserting into a foreign table without
1629 * RETURNING clause.
1630 * ----------------------------------------------------------------
1631 */
1632static void
1634 ResultRelInfo *resultRelInfo,
1635 TupleTableSlot **slots,
1637 int numSlots,
1638 EState *estate,
1639 bool canSetTag)
1640{
1641 int i;
1642 int numInserted = numSlots;
1643 TupleTableSlot *slot = NULL;
1645
1646 /*
1647 * insert into foreign table: let the FDW do it
1648 */
1649 rslots = resultRelInfo->ri_FdwRoutine->ExecForeignBatchInsert(estate,
1650 resultRelInfo,
1651 slots,
1652 planSlots,
1653 &numInserted);
1654
1655 for (i = 0; i < numInserted; i++)
1656 {
1657 slot = rslots[i];
1658
1659 /*
1660 * AFTER ROW Triggers might reference the tableoid column, so
1661 * (re-)initialize tts_tableOid before evaluating them.
1662 */
1663 slot->tts_tableOid = RelationGetRelid(resultRelInfo->ri_RelationDesc);
1664
1665 /* AFTER ROW INSERT Triggers */
1666 ExecARInsertTriggers(estate, resultRelInfo, slot, NIL,
1667 mtstate->mt_transition_capture);
1668
1669 /*
1670 * Check any WITH CHECK OPTION constraints from parent views. See the
1671 * comment in ExecInsert.
1672 */
1673 if (resultRelInfo->ri_WithCheckOptions != NIL)
1674 ExecWithCheckOptions(WCO_VIEW_CHECK, resultRelInfo, slot, estate);
1675 }
1676
1677 if (canSetTag && numInserted > 0)
1678 estate->es_processed += numInserted;
1679
1680 /* Clean up all the slots, ready for the next batch */
1681 for (i = 0; i < numSlots; i++)
1682 {
1683 ExecClearTuple(slots[i]);
1685 }
1686 resultRelInfo->ri_NumSlots = 0;
1687}
1688
1689/*
1690 * ExecPendingInserts -- flushes all pending inserts to the foreign tables
1691 */
1692static void
1694{
1695 ListCell *l1,
1696 *l2;
1697
1700 {
1701 ResultRelInfo *resultRelInfo = (ResultRelInfo *) lfirst(l1);
1702 ModifyTableState *mtstate = (ModifyTableState *) lfirst(l2);
1703
1704 Assert(mtstate);
1705 ExecBatchInsert(mtstate, resultRelInfo,
1706 resultRelInfo->ri_Slots,
1707 resultRelInfo->ri_PlanSlots,
1708 resultRelInfo->ri_NumSlots,
1709 estate, mtstate->canSetTag);
1710 }
1711
1716}
1717
1718/*
1719 * ExecDeletePrologue -- subroutine for ExecDelete
1720 *
1721 * Prepare executor state for DELETE. Actually, the only thing we have to do
1722 * here is execute BEFORE ROW triggers. We return false if one of them makes
1723 * the delete a no-op; otherwise, return true.
1724 */
1725static bool
1727 ItemPointer tupleid, HeapTuple oldtuple,
1729{
1730 if (result)
1731 *result = TM_Ok;
1732
1733 /* BEFORE ROW DELETE triggers */
1734 if (resultRelInfo->ri_TrigDesc &&
1735 resultRelInfo->ri_TrigDesc->trig_delete_before_row)
1736 {
1737 /* Flush any pending inserts, so rows are visible to the triggers */
1739 ExecPendingInserts(context->estate);
1740
1741 return ExecBRDeleteTriggers(context->estate, context->epqstate,
1742 resultRelInfo, tupleid, oldtuple,
1743 epqreturnslot, result, &context->tmfd,
1744 context->mtstate->operation == CMD_MERGE);
1745 }
1746
1747 return true;
1748}
1749
1750/*
1751 * ExecDeleteAct -- subroutine for ExecDelete
1752 *
1753 * Actually delete the tuple from a plain table.
1754 *
1755 * Caller is in charge of doing EvalPlanQual as necessary
1756 */
1757static TM_Result
1760{
1761 EState *estate = context->estate;
1762 uint32 options = 0;
1763
1764 if (changingPart)
1766
1767 return table_tuple_delete(resultRelInfo->ri_RelationDesc, tupleid,
1768 estate->es_output_cid,
1769 options,
1770 estate->es_snapshot,
1771 estate->es_crosscheck_snapshot,
1772 true /* wait for commit */ ,
1773 &context->tmfd);
1774}
1775
1776/*
1777 * ExecDeleteEpilogue -- subroutine for ExecDelete
1778 *
1779 * Closing steps of tuple deletion; this invokes AFTER FOR EACH ROW triggers,
1780 * including the UPDATE triggers if the deletion is being done as part of a
1781 * cross-partition tuple move. It also inserts temporal leftovers from a
1782 * DELETE FOR PORTION OF.
1783 */
1784static void
1786 ItemPointer tupleid, HeapTuple oldtuple, bool changingPart)
1787{
1788 ModifyTableState *mtstate = context->mtstate;
1789 EState *estate = context->estate;
1791
1792 /*
1793 * If this delete is the result of a partition key update that moved the
1794 * tuple to a new partition, put this row into the transition OLD TABLE,
1795 * if there is one. We need to do this separately for DELETE and INSERT
1796 * because they happen on different tables.
1797 */
1799 if (mtstate->operation == CMD_UPDATE && mtstate->mt_transition_capture &&
1801 {
1802 ExecARUpdateTriggers(estate, resultRelInfo,
1803 NULL, NULL,
1804 tupleid, oldtuple,
1805 NULL, NULL, mtstate->mt_transition_capture,
1806 false);
1807
1808 /*
1809 * We've already captured the OLD TABLE row, so make sure any AR
1810 * DELETE trigger fired below doesn't capture it again.
1811 */
1813 }
1814
1815 /* Compute temporal leftovers in FOR PORTION OF */
1816 if (((ModifyTable *) context->mtstate->ps.plan)->forPortionOf)
1817 ExecForPortionOfLeftovers(context, estate, resultRelInfo, tupleid);
1818
1819 /* AFTER ROW DELETE Triggers */
1820 ExecARDeleteTriggers(estate, resultRelInfo, tupleid, oldtuple,
1822}
1823
1824/* ----------------------------------------------------------------
1825 * ExecDelete
1826 *
1827 * DELETE is like UPDATE, except that we delete the tuple and no
1828 * index modifications are needed.
1829 *
1830 * When deleting from a table, tupleid identifies the tuple to delete and
1831 * oldtuple is NULL. When deleting through a view INSTEAD OF trigger,
1832 * oldtuple is passed to the triggers and identifies what to delete, and
1833 * tupleid is invalid. When deleting from a foreign table, tupleid is
1834 * invalid; the FDW has to figure out which row to delete using data from
1835 * the planSlot. oldtuple is passed to foreign table triggers; it is
1836 * NULL when the foreign table has no relevant triggers. We use
1837 * tupleDeleted to indicate whether the tuple is actually deleted,
1838 * callers can use it to decide whether to continue the operation. When
1839 * this DELETE is a part of an UPDATE of partition-key, then the slot
1840 * returned by EvalPlanQual() is passed back using output parameter
1841 * epqreturnslot.
1842 *
1843 * Returns RETURNING result if any, otherwise NULL.
1844 * ----------------------------------------------------------------
1845 */
1846static TupleTableSlot *
1848 ResultRelInfo *resultRelInfo,
1850 HeapTuple oldtuple,
1851 bool processReturning,
1852 bool changingPart,
1853 bool canSetTag,
1855 bool *tupleDeleted,
1857{
1858 EState *estate = context->estate;
1860 TupleTableSlot *slot = NULL;
1862 bool saveOld;
1863
1864 if (tupleDeleted)
1865 *tupleDeleted = false;
1866
1867 /*
1868 * Prepare for the delete. This includes BEFORE ROW triggers, so we're
1869 * done if it says we are.
1870 */
1871 if (!ExecDeletePrologue(context, resultRelInfo, tupleid, oldtuple,
1873 return NULL;
1874
1875 /* INSTEAD OF ROW DELETE Triggers */
1876 if (resultRelInfo->ri_TrigDesc &&
1877 resultRelInfo->ri_TrigDesc->trig_delete_instead_row)
1878 {
1879 bool dodelete;
1880
1881 Assert(oldtuple != NULL);
1882 dodelete = ExecIRDeleteTriggers(estate, resultRelInfo, oldtuple);
1883
1884 if (!dodelete) /* "do nothing" */
1885 return NULL;
1886 }
1887 else if (resultRelInfo->ri_FdwRoutine)
1888 {
1889 /*
1890 * delete from foreign table: let the FDW do it
1891 *
1892 * We offer the returning slot as a place to store RETURNING data,
1893 * although the FDW can return some other slot if it wants.
1894 */
1895 slot = ExecGetReturningSlot(estate, resultRelInfo);
1896 slot = resultRelInfo->ri_FdwRoutine->ExecForeignDelete(estate,
1897 resultRelInfo,
1898 slot,
1899 context->planSlot);
1900
1901 if (slot == NULL) /* "do nothing" */
1902 return NULL;
1903
1904 /*
1905 * RETURNING expressions might reference the tableoid column, so
1906 * (re)initialize tts_tableOid before evaluating them.
1907 */
1908 if (TTS_EMPTY(slot))
1910
1912 }
1913 else
1914 {
1915 /*
1916 * delete the tuple
1917 *
1918 * Note: if context->estate->es_crosscheck_snapshot isn't
1919 * InvalidSnapshot, we check that the row to be deleted is visible to
1920 * that snapshot, and throw a can't-serialize error if not. This is a
1921 * special-case behavior needed for referential integrity updates in
1922 * transaction-snapshot mode transactions.
1923 */
1924ldelete:
1925 result = ExecDeleteAct(context, resultRelInfo, tupleid, changingPart);
1926
1927 if (tmresult)
1928 *tmresult = result;
1929
1930 switch (result)
1931 {
1932 case TM_SelfModified:
1933
1934 /*
1935 * The target tuple was already updated or deleted by the
1936 * current command, or by a later command in the current
1937 * transaction. The former case is possible in a join DELETE
1938 * where multiple tuples join to the same target tuple. This
1939 * is somewhat questionable, but Postgres has always allowed
1940 * it: we just ignore additional deletion attempts.
1941 *
1942 * The latter case arises if the tuple is modified by a
1943 * command in a BEFORE trigger, or perhaps by a command in a
1944 * volatile function used in the query. In such situations we
1945 * should not ignore the deletion, but it is equally unsafe to
1946 * proceed. We don't want to discard the original DELETE
1947 * while keeping the triggered actions based on its deletion;
1948 * and it would be no better to allow the original DELETE
1949 * while discarding updates that it triggered. The row update
1950 * carries some information that might be important according
1951 * to business rules; so throwing an error is the only safe
1952 * course.
1953 *
1954 * If a trigger actually intends this type of interaction, it
1955 * can re-execute the DELETE and then return NULL to cancel
1956 * the outer delete.
1957 */
1958 if (context->tmfd.cmax != estate->es_output_cid)
1959 ereport(ERROR,
1961 errmsg("tuple to be deleted was already modified by an operation triggered by the current command"),
1962 errhint("Consider using an AFTER trigger instead of a BEFORE trigger to propagate changes to other rows.")));
1963
1964 /* Else, already deleted by self; nothing to do */
1965 return NULL;
1966
1967 case TM_Ok:
1968 break;
1969
1970 case TM_Updated:
1971 {
1972 TupleTableSlot *inputslot;
1974
1976 ereport(ERROR,
1978 errmsg("could not serialize access due to concurrent update")));
1979
1980 /*
1981 * Already know that we're going to need to do EPQ, so
1982 * fetch tuple directly into the right slot.
1983 */
1984 EvalPlanQualBegin(context->epqstate);
1985 inputslot = EvalPlanQualSlot(context->epqstate, resultRelationDesc,
1986 resultRelInfo->ri_RangeTableIndex);
1987
1989 estate->es_snapshot,
1990 inputslot, estate->es_output_cid,
1993 &context->tmfd);
1994
1995 switch (result)
1996 {
1997 case TM_Ok:
1998 Assert(context->tmfd.traversed);
1999 epqslot = EvalPlanQual(context->epqstate,
2001 resultRelInfo->ri_RangeTableIndex,
2002 inputslot);
2003 if (TupIsNull(epqslot))
2004 /* Tuple not passing quals anymore, exiting... */
2005 return NULL;
2006
2007 /*
2008 * If requested, skip delete and pass back the
2009 * updated row.
2010 */
2011 if (epqreturnslot)
2012 {
2014 return NULL;
2015 }
2016 else
2017 goto ldelete;
2018
2019 case TM_SelfModified:
2020
2021 /*
2022 * This can be reached when following an update
2023 * chain from a tuple updated by another session,
2024 * reaching a tuple that was already updated in
2025 * this transaction. If previously updated by this
2026 * command, ignore the delete, otherwise error
2027 * out.
2028 *
2029 * See also TM_SelfModified response to
2030 * table_tuple_delete() above.
2031 */
2032 if (context->tmfd.cmax != estate->es_output_cid)
2033 ereport(ERROR,
2035 errmsg("tuple to be deleted was already modified by an operation triggered by the current command"),
2036 errhint("Consider using an AFTER trigger instead of a BEFORE trigger to propagate changes to other rows.")));
2037 return NULL;
2038
2039 case TM_Deleted:
2040 /* tuple already deleted; nothing to do */
2041 return NULL;
2042
2043 default:
2044
2045 /*
2046 * TM_Invisible should be impossible because we're
2047 * waiting for updated row versions, and would
2048 * already have errored out if the first version
2049 * is invisible.
2050 *
2051 * TM_Updated should be impossible, because we're
2052 * locking the latest version via
2053 * TUPLE_LOCK_FLAG_FIND_LAST_VERSION.
2054 */
2055 elog(ERROR, "unexpected table_tuple_lock status: %u",
2056 result);
2057 return NULL;
2058 }
2059
2060 Assert(false);
2061 break;
2062 }
2063
2064 case TM_Deleted:
2066 ereport(ERROR,
2068 errmsg("could not serialize access due to concurrent delete")));
2069 /* tuple already deleted; nothing to do */
2070 return NULL;
2071
2072 default:
2073 elog(ERROR, "unrecognized table_tuple_delete status: %u",
2074 result);
2075 return NULL;
2076 }
2077
2078 /*
2079 * Note: Normally one would think that we have to delete index tuples
2080 * associated with the heap tuple now...
2081 *
2082 * ... but in POSTGRES, we have no need to do this because VACUUM will
2083 * take care of it later. We can't delete index tuples immediately
2084 * anyway, since the tuple is still visible to other transactions.
2085 */
2086 }
2087
2088 if (canSetTag)
2089 (estate->es_processed)++;
2090
2091 /* Tell caller that the delete actually happened. */
2092 if (tupleDeleted)
2093 *tupleDeleted = true;
2094
2095 ExecDeleteEpilogue(context, resultRelInfo, tupleid, oldtuple, changingPart);
2096
2097 /*
2098 * Process RETURNING if present and if requested.
2099 *
2100 * If this is part of a cross-partition UPDATE, and the RETURNING list
2101 * refers to any OLD column values, save the old tuple here for later
2102 * processing of the RETURNING list by ExecInsert().
2103 */
2104 saveOld = changingPart && resultRelInfo->ri_projectReturning &&
2106
2107 if (resultRelInfo->ri_projectReturning && (processReturning || saveOld))
2108 {
2109 /*
2110 * We have to put the target tuple into a slot, which means first we
2111 * gotta fetch it. We can use the trigger tuple slot.
2112 */
2114
2115 if (resultRelInfo->ri_FdwRoutine)
2116 {
2117 /* FDW must have provided a slot containing the deleted row */
2118 Assert(!TupIsNull(slot));
2119 }
2120 else
2121 {
2122 slot = ExecGetReturningSlot(estate, resultRelInfo);
2123 if (oldtuple != NULL)
2124 {
2125 ExecForceStoreHeapTuple(oldtuple, slot, false);
2126 }
2127 else
2128 {
2130 SnapshotAny, slot))
2131 elog(ERROR, "failed to fetch deleted tuple for DELETE RETURNING");
2132 }
2133 }
2134
2135 /*
2136 * If required, save the old tuple for later processing of the
2137 * RETURNING list by ExecInsert().
2138 */
2139 if (saveOld)
2140 {
2142
2143 /*
2144 * Convert the tuple into the root partition's format/slot, if
2145 * needed. ExecInsert() will then convert it to the new
2146 * partition's format/slot, if necessary.
2147 */
2148 tupconv_map = ExecGetChildToRootMap(resultRelInfo);
2149 if (tupconv_map != NULL)
2150 {
2152 TupleTableSlot *oldSlot = slot;
2153
2154 slot = execute_attr_map_slot(tupconv_map->attrMap,
2155 slot,
2156 ExecGetReturningSlot(estate,
2157 rootRelInfo));
2158
2159 slot->tts_tableOid = oldSlot->tts_tableOid;
2160 ItemPointerCopy(&oldSlot->tts_tid, &slot->tts_tid);
2161 }
2162
2163 context->cpDeletedSlot = slot;
2164
2165 return NULL;
2166 }
2167
2168 rslot = ExecProcessReturning(context, resultRelInfo, true,
2169 slot, NULL, context->planSlot);
2170
2171 /*
2172 * Before releasing the target tuple again, make sure rslot has a
2173 * local copy of any pass-by-reference values.
2174 */
2176
2177 ExecClearTuple(slot);
2178
2179 return rslot;
2180 }
2181
2182 return NULL;
2183}
2184
2185/*
2186 * ExecCrossPartitionUpdate --- Move an updated tuple to another partition.
2187 *
2188 * This works by first deleting the old tuple from the current partition,
2189 * followed by inserting the new tuple into the root parent table, that is,
2190 * mtstate->rootResultRelInfo. It will be re-routed from there to the
2191 * correct partition.
2192 *
2193 * Returns true if the tuple has been successfully moved, or if it's found
2194 * that the tuple was concurrently deleted so there's nothing more to do
2195 * for the caller.
2196 *
2197 * False is returned if the tuple we're trying to move is found to have been
2198 * concurrently updated. In that case, the caller must check if the updated
2199 * tuple that's returned in *retry_slot still needs to be re-routed, and call
2200 * this function again or perform a regular update accordingly. For MERGE,
2201 * the updated tuple is not returned in *retry_slot; it has its own retry
2202 * logic.
2203 */
2204static bool
2206 ResultRelInfo *resultRelInfo,
2207 ItemPointer tupleid, HeapTuple oldtuple,
2208 TupleTableSlot *slot,
2209 bool canSetTag,
2215{
2216 ModifyTableState *mtstate = context->mtstate;
2217 EState *estate = mtstate->ps.state;
2219 bool tuple_deleted;
2221
2222 context->cpDeletedSlot = NULL;
2223 context->cpUpdateReturningSlot = NULL;
2224 *retry_slot = NULL;
2225
2226 /*
2227 * Disallow an INSERT ON CONFLICT DO UPDATE that causes the original row
2228 * to migrate to a different partition. Maybe this can be implemented
2229 * some day, but it seems a fringe feature with little redeeming value.
2230 */
2231 if (((ModifyTable *) mtstate->ps.plan)->onConflictAction == ONCONFLICT_UPDATE)
2232 ereport(ERROR,
2234 errmsg("invalid ON UPDATE specification"),
2235 errdetail("The result tuple would appear in a different partition than the original tuple.")));
2236
2237 /*
2238 * When an UPDATE is run directly on a leaf partition, simply fail with a
2239 * partition constraint violation error.
2240 */
2241 if (resultRelInfo == mtstate->rootResultRelInfo)
2242 ExecPartitionCheckEmitError(resultRelInfo, slot, estate);
2243
2244 /*
2245 * Initialize tuple routing info if not already done. Note whatever we do
2246 * here must be done in ExecInitModifyTable for FOR PORTION OF as well.
2247 */
2248 if (mtstate->mt_partition_tuple_routing == NULL)
2249 {
2252
2253 /* Things built here have to last for the query duration. */
2255
2258
2259 /*
2260 * Before a partition's tuple can be re-routed, it must first be
2261 * converted to the root's format, so we'll need a slot for storing
2262 * such tuples.
2263 */
2264 Assert(mtstate->mt_root_tuple_slot == NULL);
2266
2268 }
2269
2270 /*
2271 * Row movement, part 1. Delete the tuple, but skip RETURNING processing.
2272 * We want to return rows from INSERT.
2273 */
2274 ExecDelete(context, resultRelInfo,
2275 tupleid, oldtuple,
2276 false, /* processReturning */
2277 true, /* changingPart */
2278 false, /* canSetTag */
2280
2281 /*
2282 * For some reason if DELETE didn't happen (e.g. trigger prevented it, or
2283 * it was already deleted by self, or it was concurrently deleted by
2284 * another transaction), then we should skip the insert as well;
2285 * otherwise, an UPDATE could cause an increase in the total number of
2286 * rows across all partitions, which is clearly wrong.
2287 *
2288 * For a normal UPDATE, the case where the tuple has been the subject of a
2289 * concurrent UPDATE or DELETE would be handled by the EvalPlanQual
2290 * machinery, but for an UPDATE that we've translated into a DELETE from
2291 * this partition and an INSERT into some other partition, that's not
2292 * available, because CTID chains can't span relation boundaries. We
2293 * mimic the semantics to a limited extent by skipping the INSERT if the
2294 * DELETE fails to find a tuple. This ensures that two concurrent
2295 * attempts to UPDATE the same tuple at the same time can't turn one tuple
2296 * into two, and that an UPDATE of a just-deleted tuple can't resurrect
2297 * it.
2298 */
2299 if (!tuple_deleted)
2300 {
2301 /*
2302 * epqslot will be typically NULL. But when ExecDelete() finds that
2303 * another transaction has concurrently updated the same row, it
2304 * re-fetches the row, skips the delete, and epqslot is set to the
2305 * re-fetched tuple slot. In that case, we need to do all the checks
2306 * again. For MERGE, we leave everything to the caller (it must do
2307 * additional rechecking, and might end up executing a different
2308 * action entirely).
2309 */
2310 if (mtstate->operation == CMD_MERGE)
2311 return *tmresult == TM_Ok;
2312 else if (TupIsNull(epqslot))
2313 return true;
2314 else
2315 {
2316 /* Fetch the most recent version of old tuple. */
2318
2319 /* ... but first, make sure ri_oldTupleSlot is initialized. */
2320 if (unlikely(!resultRelInfo->ri_projectNewInfoValid))
2321 ExecInitUpdateProjection(mtstate, resultRelInfo);
2322 oldSlot = resultRelInfo->ri_oldTupleSlot;
2324 tupleid,
2326 oldSlot))
2327 elog(ERROR, "failed to fetch tuple being updated");
2328 /* and project the new tuple to retry the UPDATE with */
2329 *retry_slot = ExecGetUpdateNewTuple(resultRelInfo, epqslot,
2330 oldSlot);
2331 return false;
2332 }
2333 }
2334
2335 /*
2336 * resultRelInfo is one of the per-relation resultRelInfos. So we should
2337 * convert the tuple into root's tuple descriptor if needed, since
2338 * ExecInsert() starts the search from root.
2339 */
2340 tupconv_map = ExecGetChildToRootMap(resultRelInfo);
2341 if (tupconv_map != NULL)
2342 slot = execute_attr_map_slot(tupconv_map->attrMap,
2343 slot,
2344 mtstate->mt_root_tuple_slot);
2345
2346 /* Tuple routing starts from the root table. */
2347 context->cpUpdateReturningSlot =
2348 ExecInsert(context, mtstate->rootResultRelInfo, slot, canSetTag,
2350
2351 /*
2352 * Reset the transition state that may possibly have been written by
2353 * INSERT.
2354 */
2355 if (mtstate->mt_transition_capture)
2357
2358 /* We're done moving. */
2359 return true;
2360}
2361
2362/*
2363 * ExecUpdatePrologue -- subroutine for ExecUpdate
2364 *
2365 * Prepare executor state for UPDATE. This includes running BEFORE ROW
2366 * triggers. We return false if one of them makes the update a no-op;
2367 * otherwise, return true.
2368 */
2369static bool
2373{
2375
2376 if (result)
2377 *result = TM_Ok;
2378
2379 ExecMaterializeSlot(slot);
2380
2381 /*
2382 * Open the table's indexes, if we have not done so already, so that we
2383 * can add new index entries for the updated tuple.
2384 */
2385 if (resultRelationDesc->rd_rel->relhasindex &&
2386 resultRelInfo->ri_IndexRelationDescs == NULL)
2387 ExecOpenIndices(resultRelInfo, false);
2388
2389 /* BEFORE ROW UPDATE triggers */
2390 if (resultRelInfo->ri_TrigDesc &&
2391 resultRelInfo->ri_TrigDesc->trig_update_before_row)
2392 {
2393 /* Flush any pending inserts, so rows are visible to the triggers */
2395 ExecPendingInserts(context->estate);
2396
2397 return ExecBRUpdateTriggers(context->estate, context->epqstate,
2398 resultRelInfo, tupleid, oldtuple, slot,
2399 result, &context->tmfd,
2400 context->mtstate->operation == CMD_MERGE);
2401 }
2402
2403 return true;
2404}
2405
2406/*
2407 * ExecUpdatePrepareSlot -- subroutine for ExecUpdateAct
2408 *
2409 * Apply the final modifications to the tuple slot before the update.
2410 * (This is split out because we also need it in the foreign-table code path.)
2411 */
2412static void
2414 TupleTableSlot *slot,
2415 EState *estate)
2416{
2418
2419 /*
2420 * Constraints and GENERATED expressions might reference the tableoid
2421 * column, so (re-)initialize tts_tableOid before evaluating them.
2422 */
2424
2425 /*
2426 * Compute stored generated columns
2427 */
2428 if (resultRelationDesc->rd_att->constr &&
2429 resultRelationDesc->rd_att->constr->has_generated_stored)
2430 ExecComputeStoredGenerated(resultRelInfo, estate, slot,
2431 CMD_UPDATE);
2432}
2433
2434/*
2435 * ExecUpdateAct -- subroutine for ExecUpdate
2436 *
2437 * Actually update the tuple, when operating on a plain table. If the
2438 * table is a partition, and the command was called referencing an ancestor
2439 * partitioned table, this routine migrates the resulting tuple to another
2440 * partition.
2441 *
2442 * The caller is in charge of keeping indexes current as necessary. The
2443 * caller is also in charge of doing EvalPlanQual if the tuple is found to
2444 * be concurrently updated. However, in case of a cross-partition update,
2445 * this routine does it.
2446 */
2447static TM_Result
2450 bool canSetTag, UpdateContext *updateCxt)
2451{
2452 EState *estate = context->estate;
2456
2457 updateCxt->crossPartUpdate = false;
2458
2459 /*
2460 * If we move the tuple to a new partition, we loop back here to recompute
2461 * GENERATED values (which are allowed to be different across partitions)
2462 * and recheck any RLS policies and constraints. We do not fire any
2463 * BEFORE triggers of the new partition, however.
2464 */
2465lreplace:
2466 /* Fill in GENERATEd columns */
2467 ExecUpdatePrepareSlot(resultRelInfo, slot, estate);
2468
2469 /* ensure slot is independent, consider e.g. EPQ */
2470 ExecMaterializeSlot(slot);
2471
2472 /*
2473 * If partition constraint fails, this row might get moved to another
2474 * partition, in which case we should check the RLS CHECK policy just
2475 * before inserting into the new partition, rather than doing it here.
2476 * This is because a trigger on that partition might again change the row.
2477 * So skip the WCO checks if the partition constraint fails.
2478 */
2480 resultRelationDesc->rd_rel->relispartition &&
2481 !ExecPartitionCheck(resultRelInfo, slot, estate, false);
2482
2483 /* Check any RLS UPDATE WITH CHECK policies */
2485 resultRelInfo->ri_WithCheckOptions != NIL)
2486 {
2487 /*
2488 * ExecWithCheckOptions() will skip any WCOs which are not of the kind
2489 * we are looking for at this point.
2490 */
2492 resultRelInfo, slot, estate);
2493 }
2494
2495 /*
2496 * If a partition check failed, try to move the row into the right
2497 * partition.
2498 */
2500 {
2502 *retry_slot;
2504
2505 /*
2506 * ExecCrossPartitionUpdate will first DELETE the row from the
2507 * partition it's currently in and then insert it back into the root
2508 * table, which will re-route it to the correct partition. However,
2509 * if the tuple has been concurrently updated, a retry is needed.
2510 */
2511 if (ExecCrossPartitionUpdate(context, resultRelInfo,
2512 tupleid, oldtuple, slot,
2513 canSetTag, updateCxt,
2514 &result,
2515 &retry_slot,
2518 {
2519 /* success! */
2520 updateCxt->crossPartUpdate = true;
2521
2522 /*
2523 * If the partitioned table being updated is referenced in foreign
2524 * keys, queue up trigger events to check that none of them were
2525 * violated. No special treatment is needed in
2526 * non-cross-partition update situations, because the leaf
2527 * partition's AR update triggers will take care of that. During
2528 * cross-partition updates implemented as delete on the source
2529 * partition followed by insert on the destination partition,
2530 * AR-UPDATE triggers of the root table (that is, the table
2531 * mentioned in the query) must be fired.
2532 *
2533 * NULL insert_destrel means that the move failed to occur, that
2534 * is, the update failed, so no need to anything in that case.
2535 */
2536 if (insert_destrel &&
2537 resultRelInfo->ri_TrigDesc &&
2538 resultRelInfo->ri_TrigDesc->trig_update_after_row)
2540 resultRelInfo,
2542 tupleid, slot,
2544
2545 return TM_Ok;
2546 }
2547
2548 /*
2549 * No luck, a retry is needed. If running MERGE, we do not do so
2550 * here; instead let it handle that on its own rules.
2551 */
2552 if (context->mtstate->operation == CMD_MERGE)
2553 return result;
2554
2555 /*
2556 * ExecCrossPartitionUpdate installed an updated version of the new
2557 * tuple in the retry slot; start over.
2558 */
2559 slot = retry_slot;
2560 goto lreplace;
2561 }
2562
2563 /*
2564 * Check the constraints of the tuple. We've already checked the
2565 * partition constraint above; however, we must still ensure the tuple
2566 * passes all other constraints, so we will call ExecConstraints() and
2567 * have it validate all remaining checks.
2568 */
2569 if (resultRelationDesc->rd_att->constr)
2570 ExecConstraints(resultRelInfo, slot, estate);
2571
2572 /*
2573 * replace the heap tuple
2574 *
2575 * Note: if es_crosscheck_snapshot isn't InvalidSnapshot, we check that
2576 * the row to be updated is visible to that snapshot, and throw a
2577 * can't-serialize error if not. This is a special-case behavior needed
2578 * for referential integrity updates in transaction-snapshot mode
2579 * transactions.
2580 */
2582 estate->es_output_cid,
2583 0,
2584 estate->es_snapshot,
2585 estate->es_crosscheck_snapshot,
2586 true /* wait for commit */ ,
2587 &context->tmfd, &updateCxt->lockmode,
2588 &updateCxt->updateIndexes);
2589
2590 return result;
2591}
2592
2593/*
2594 * ExecUpdateEpilogue -- subroutine for ExecUpdate
2595 *
2596 * Closing steps of updating a tuple. Must be called if ExecUpdateAct
2597 * returns indicating that the tuple was updated. It also inserts temporal
2598 * leftovers from an UPDATE FOR PORTION OF.
2599 */
2600static void
2602 ResultRelInfo *resultRelInfo, ItemPointer tupleid,
2603 HeapTuple oldtuple, TupleTableSlot *slot)
2604{
2605 ModifyTableState *mtstate = context->mtstate;
2607
2608 /* insert index entries for tuple if necessary */
2609 if (resultRelInfo->ri_NumIndices > 0 && (updateCxt->updateIndexes != TU_None))
2610 {
2611 uint32 flags = EIIT_IS_UPDATE;
2612
2613 if (updateCxt->updateIndexes == TU_Summarizing)
2614 flags |= EIIT_ONLY_SUMMARIZING;
2615 recheckIndexes = ExecInsertIndexTuples(resultRelInfo, context->estate,
2616 flags, slot, NIL,
2617 NULL);
2618 }
2619
2620 /* Compute temporal leftovers in FOR PORTION OF */
2621 if (((ModifyTable *) context->mtstate->ps.plan)->forPortionOf)
2622 ExecForPortionOfLeftovers(context, context->estate, resultRelInfo, tupleid);
2623
2624 /* AFTER ROW UPDATE Triggers */
2625 ExecARUpdateTriggers(context->estate, resultRelInfo,
2626 NULL, NULL,
2627 tupleid, oldtuple, slot,
2629 mtstate->operation == CMD_INSERT ?
2630 mtstate->mt_oc_transition_capture :
2631 mtstate->mt_transition_capture,
2632 false);
2633
2635
2636 /*
2637 * Check any WITH CHECK OPTION constraints from parent views. We are
2638 * required to do this after testing all constraints and uniqueness
2639 * violations per the SQL spec, so we do it after actually updating the
2640 * record in the heap and all indexes.
2641 *
2642 * ExecWithCheckOptions() will skip any WCOs which are not of the kind we
2643 * are looking for at this point.
2644 */
2645 if (resultRelInfo->ri_WithCheckOptions != NIL)
2646 ExecWithCheckOptions(WCO_VIEW_CHECK, resultRelInfo,
2647 slot, context->estate);
2648}
2649
2650/*
2651 * Queues up an update event using the target root partitioned table's
2652 * trigger to check that a cross-partition update hasn't broken any foreign
2653 * keys pointing into it.
2654 */
2655static void
2662{
2663 ListCell *lc;
2666
2667 rootRelInfo = sourcePartInfo->ri_RootResultRelInfo;
2669
2670 /*
2671 * For any foreign keys that point directly into a non-root ancestors of
2672 * the source partition, we can in theory fire an update event to enforce
2673 * those constraints using their triggers, if we could tell that both the
2674 * source and the destination partitions are under the same ancestor. But
2675 * for now, we simply report an error that those cannot be enforced.
2676 */
2677 foreach(lc, ancestorRels)
2678 {
2680 TriggerDesc *trigdesc = rInfo->ri_TrigDesc;
2681 bool has_noncloned_fkey = false;
2682
2683 /* Root ancestor's triggers will be processed. */
2684 if (rInfo == rootRelInfo)
2685 continue;
2686
2687 if (trigdesc && trigdesc->trig_update_after_row)
2688 {
2689 for (int i = 0; i < trigdesc->numtriggers; i++)
2690 {
2691 Trigger *trig = &trigdesc->triggers[i];
2692
2693 if (!trig->tgisclone &&
2695 {
2696 has_noncloned_fkey = true;
2697 break;
2698 }
2699 }
2700 }
2701
2703 ereport(ERROR,
2705 errmsg("cannot move tuple across partitions when a non-root ancestor of the source partition is directly referenced in a foreign key"),
2706 errdetail("A foreign key points to ancestor \"%s\" but not the root ancestor \"%s\".",
2707 RelationGetRelationName(rInfo->ri_RelationDesc),
2708 RelationGetRelationName(rootRelInfo->ri_RelationDesc)),
2709 errhint("Consider defining the foreign key on table \"%s\".",
2710 RelationGetRelationName(rootRelInfo->ri_RelationDesc))));
2711 }
2712
2713 /* Perform the root table's triggers. */
2716 tupleid, NULL, newslot, NIL, NULL, true);
2717}
2718
2719/* ----------------------------------------------------------------
2720 * ExecUpdate
2721 *
2722 * note: we can't run UPDATE queries with transactions
2723 * off because UPDATEs are actually INSERTs and our
2724 * scan will mistakenly loop forever, updating the tuple
2725 * it just inserted.. This should be fixed but until it
2726 * is, we don't want to get stuck in an infinite loop
2727 * which corrupts your database..
2728 *
2729 * When updating a table, tupleid identifies the tuple to update and
2730 * oldtuple is NULL. When updating through a view INSTEAD OF trigger,
2731 * oldtuple is passed to the triggers and identifies what to update, and
2732 * tupleid is invalid. When updating a foreign table, tupleid is
2733 * invalid; the FDW has to figure out which row to update using data from
2734 * the planSlot. oldtuple is passed to foreign table triggers; it is
2735 * NULL when the foreign table has no relevant triggers.
2736 *
2737 * oldSlot contains the old tuple value.
2738 * slot contains the new tuple value to be stored.
2739 * planSlot is the output of the ModifyTable's subplan; we use it
2740 * to access values from other input tables (for RETURNING),
2741 * row-ID junk columns, etc.
2742 *
2743 * Returns RETURNING result if any, otherwise NULL. On exit, if tupleid
2744 * had identified the tuple to update, it will identify the tuple
2745 * actually updated after EvalPlanQual.
2746 * ----------------------------------------------------------------
2747 */
2748static TupleTableSlot *
2751 TupleTableSlot *slot, bool canSetTag)
2752{
2753 EState *estate = context->estate;
2757
2758 /*
2759 * abort the operation if not running transactions
2760 */
2762 elog(ERROR, "cannot UPDATE during bootstrap");
2763
2764 /*
2765 * Prepare for the update. This includes BEFORE ROW triggers, so we're
2766 * done if it says we are.
2767 */
2768 context->tmfd.traversed = false;
2769 if (!ExecUpdatePrologue(context, resultRelInfo, tupleid, oldtuple, slot, NULL))
2770 return NULL;
2771
2772 /*
2773 * If the target tuple was concurrently updated, the trigger code will
2774 * have done EPQ and updated tupleid, following the update chain. In this
2775 * case, we must fetch the most recent version of old tuple for the
2776 * benefit of RETURNING. Technically, we could get away with not doing
2777 * this, if there is no RETURNING clause, or it doesn't refer to OLD, but
2778 * it seems preferable to always ensure that the contents of oldSlot are
2779 * correct.
2780 */
2781 if (context->tmfd.traversed)
2782 {
2784 tupleid,
2786 oldSlot))
2787 elog(ERROR, "failed to re-fetch tuple updated during trigger execution");
2788 }
2789
2790 /* INSTEAD OF ROW UPDATE Triggers */
2791 if (resultRelInfo->ri_TrigDesc &&
2792 resultRelInfo->ri_TrigDesc->trig_update_instead_row)
2793 {
2794 if (!ExecIRUpdateTriggers(estate, resultRelInfo,
2795 oldtuple, slot))
2796 return NULL; /* "do nothing" */
2797 }
2798 else if (resultRelInfo->ri_FdwRoutine)
2799 {
2800 /* Fill in GENERATEd columns */
2801 ExecUpdatePrepareSlot(resultRelInfo, slot, estate);
2802
2803 /*
2804 * update in foreign table: let the FDW do it
2805 */
2806 slot = resultRelInfo->ri_FdwRoutine->ExecForeignUpdate(estate,
2807 resultRelInfo,
2808 slot,
2809 context->planSlot);
2810
2811 if (slot == NULL) /* "do nothing" */
2812 return NULL;
2813
2814 /*
2815 * AFTER ROW Triggers or RETURNING expressions might reference the
2816 * tableoid column, so (re-)initialize tts_tableOid before evaluating
2817 * them. (This covers the case where the FDW replaced the slot.)
2818 */
2820 }
2821 else
2822 {
2824
2825 /*
2826 * If we generate a new candidate tuple after EvalPlanQual testing, we
2827 * must loop back here to try again. (We don't need to redo triggers,
2828 * however. If there are any BEFORE triggers then trigger.c will have
2829 * done table_tuple_lock to lock the correct tuple, so there's no need
2830 * to do them again.)
2831 */
2832redo_act:
2833 lockedtid = *tupleid;
2834 result = ExecUpdateAct(context, resultRelInfo, tupleid, oldtuple, slot,
2835 canSetTag, &updateCxt);
2836
2837 /*
2838 * If ExecUpdateAct reports that a cross-partition update was done,
2839 * then the RETURNING tuple (if any) has been projected and there's
2840 * nothing else for us to do.
2841 */
2842 if (updateCxt.crossPartUpdate)
2843 return context->cpUpdateReturningSlot;
2844
2845 switch (result)
2846 {
2847 case TM_SelfModified:
2848
2849 /*
2850 * The target tuple was already updated or deleted by the
2851 * current command, or by a later command in the current
2852 * transaction. The former case is possible in a join UPDATE
2853 * where multiple tuples join to the same target tuple. This
2854 * is pretty questionable, but Postgres has always allowed it:
2855 * we just execute the first update action and ignore
2856 * additional update attempts.
2857 *
2858 * The latter case arises if the tuple is modified by a
2859 * command in a BEFORE trigger, or perhaps by a command in a
2860 * volatile function used in the query. In such situations we
2861 * should not ignore the update, but it is equally unsafe to
2862 * proceed. We don't want to discard the original UPDATE
2863 * while keeping the triggered actions based on it; and we
2864 * have no principled way to merge this update with the
2865 * previous ones. So throwing an error is the only safe
2866 * course.
2867 *
2868 * If a trigger actually intends this type of interaction, it
2869 * can re-execute the UPDATE (assuming it can figure out how)
2870 * and then return NULL to cancel the outer update.
2871 */
2872 if (context->tmfd.cmax != estate->es_output_cid)
2873 ereport(ERROR,
2875 errmsg("tuple to be updated was already modified by an operation triggered by the current command"),
2876 errhint("Consider using an AFTER trigger instead of a BEFORE trigger to propagate changes to other rows.")));
2877
2878 /* Else, already updated by self; nothing to do */
2879 return NULL;
2880
2881 case TM_Ok:
2882 break;
2883
2884 case TM_Updated:
2885 {
2886 TupleTableSlot *inputslot;
2888
2890 ereport(ERROR,
2892 errmsg("could not serialize access due to concurrent update")));
2893
2894 /*
2895 * Already know that we're going to need to do EPQ, so
2896 * fetch tuple directly into the right slot.
2897 */
2898 inputslot = EvalPlanQualSlot(context->epqstate, resultRelationDesc,
2899 resultRelInfo->ri_RangeTableIndex);
2900
2902 estate->es_snapshot,
2903 inputslot, estate->es_output_cid,
2904 updateCxt.lockmode, LockWaitBlock,
2906 &context->tmfd);
2907
2908 switch (result)
2909 {
2910 case TM_Ok:
2911 Assert(context->tmfd.traversed);
2912
2913 epqslot = EvalPlanQual(context->epqstate,
2915 resultRelInfo->ri_RangeTableIndex,
2916 inputslot);
2917 if (TupIsNull(epqslot))
2918 /* Tuple not passing quals anymore, exiting... */
2919 return NULL;
2920
2921 /* Make sure ri_oldTupleSlot is initialized. */
2922 if (unlikely(!resultRelInfo->ri_projectNewInfoValid))
2924 resultRelInfo);
2925
2926 if (resultRelInfo->ri_needLockTagTuple)
2927 {
2932 }
2933
2934 /* Fetch the most recent version of old tuple. */
2935 oldSlot = resultRelInfo->ri_oldTupleSlot;
2937 tupleid,
2939 oldSlot))
2940 elog(ERROR, "failed to fetch tuple being updated");
2941 slot = ExecGetUpdateNewTuple(resultRelInfo,
2942 epqslot, oldSlot);
2943 goto redo_act;
2944
2945 case TM_Deleted:
2946 /* tuple already deleted; nothing to do */
2947 return NULL;
2948
2949 case TM_SelfModified:
2950
2951 /*
2952 * This can be reached when following an update
2953 * chain from a tuple updated by another session,
2954 * reaching a tuple that was already updated in
2955 * this transaction. If previously modified by
2956 * this command, ignore the redundant update,
2957 * otherwise error out.
2958 *
2959 * See also TM_SelfModified response to
2960 * table_tuple_update() above.
2961 */
2962 if (context->tmfd.cmax != estate->es_output_cid)
2963 ereport(ERROR,
2965 errmsg("tuple to be updated was already modified by an operation triggered by the current command"),
2966 errhint("Consider using an AFTER trigger instead of a BEFORE trigger to propagate changes to other rows.")));
2967 return NULL;
2968
2969 default:
2970 /* see table_tuple_lock call in ExecDelete() */
2971 elog(ERROR, "unexpected table_tuple_lock status: %u",
2972 result);
2973 return NULL;
2974 }
2975 }
2976
2977 break;
2978
2979 case TM_Deleted:
2981 ereport(ERROR,
2983 errmsg("could not serialize access due to concurrent delete")));
2984 /* tuple already deleted; nothing to do */
2985 return NULL;
2986
2987 default:
2988 elog(ERROR, "unrecognized table_tuple_update status: %u",
2989 result);
2990 return NULL;
2991 }
2992 }
2993
2994 if (canSetTag)
2995 (estate->es_processed)++;
2996
2997 ExecUpdateEpilogue(context, &updateCxt, resultRelInfo, tupleid, oldtuple,
2998 slot);
2999
3000 /* Process RETURNING if present */
3001 if (resultRelInfo->ri_projectReturning)
3002 return ExecProcessReturning(context, resultRelInfo, false,
3003 oldSlot, slot, context->planSlot);
3004
3005 return NULL;
3006}
3007
3008/*
3009 * ExecOnConflictLockRow --- lock the row for ON CONFLICT DO SELECT/UPDATE
3010 *
3011 * Try to lock tuple for update as part of speculative insertion for ON
3012 * CONFLICT DO UPDATE or ON CONFLICT DO SELECT FOR UPDATE/SHARE.
3013 *
3014 * Returns true if the row is successfully locked, or false if the caller must
3015 * retry the INSERT from scratch.
3016 */
3017static bool
3021 Relation relation,
3022 LockTupleMode lockmode,
3023 bool isUpdate)
3024{
3025 TM_FailureData tmfd;
3028 TransactionId xmin;
3029 bool isnull;
3030
3031 /*
3032 * Lock tuple with lockmode. Don't follow updates when tuple cannot be
3033 * locked without doing so. A row locking conflict here means our
3034 * previous conclusion that the tuple is conclusively committed is not
3035 * true anymore.
3036 */
3037 test = table_tuple_lock(relation, conflictTid,
3038 context->estate->es_snapshot,
3039 existing, context->estate->es_output_cid,
3040 lockmode, LockWaitBlock, 0,
3041 &tmfd);
3042 switch (test)
3043 {
3044 case TM_Ok:
3045 /* success! */
3046 break;
3047
3048 case TM_Invisible:
3049
3050 /*
3051 * This can occur when a just inserted tuple is updated again in
3052 * the same command. E.g. because multiple rows with the same
3053 * conflicting key values are inserted.
3054 *
3055 * This is somewhat similar to the ExecUpdate() TM_SelfModified
3056 * case. We do not want to proceed because it would lead to the
3057 * same row being updated a second time in some unspecified order,
3058 * and in contrast to plain UPDATEs there's no historical behavior
3059 * to break.
3060 *
3061 * It is the user's responsibility to prevent this situation from
3062 * occurring. These problems are why the SQL standard similarly
3063 * specifies that for SQL MERGE, an exception must be raised in
3064 * the event of an attempt to update the same row twice.
3065 */
3068 &isnull);
3069 Assert(!isnull);
3071
3073 ereport(ERROR,
3075 /* translator: %s is a SQL command name */
3076 errmsg("%s command cannot affect row a second time",
3077 isUpdate ? "ON CONFLICT DO UPDATE" : "ON CONFLICT DO SELECT"),
3078 errhint("Ensure that no rows proposed for insertion within the same command have duplicate constrained values.")));
3079
3080 /* This shouldn't happen */
3081 elog(ERROR, "attempted to lock invisible tuple");
3082 break;
3083
3084 case TM_SelfModified:
3085
3086 /*
3087 * This state should never be reached. As a dirty snapshot is used
3088 * to find conflicting tuples, speculative insertion wouldn't have
3089 * seen this row to conflict with.
3090 */
3091 elog(ERROR, "unexpected self-updated tuple");
3092 break;
3093
3094 case TM_Updated:
3096 ereport(ERROR,
3098 errmsg("could not serialize access due to concurrent update")));
3099
3100 /*
3101 * Tell caller to try again from the very start.
3102 *
3103 * It does not make sense to use the usual EvalPlanQual() style
3104 * loop here, as the new version of the row might not conflict
3105 * anymore, or the conflicting tuple has actually been deleted.
3106 */
3108 return false;
3109
3110 case TM_Deleted:
3112 ereport(ERROR,
3114 errmsg("could not serialize access due to concurrent delete")));
3115
3116 /* see TM_Updated case */
3118 return false;
3119
3120 default:
3121 elog(ERROR, "unrecognized table_tuple_lock status: %u", test);
3122 }
3123
3124 /* Success, the tuple is locked. */
3125 return true;
3126}
3127
3128/*
3129 * ExecOnConflictUpdate --- execute UPDATE of INSERT ON CONFLICT DO UPDATE
3130 *
3131 * Try to lock tuple for update as part of speculative insertion. If
3132 * a qual originating from ON CONFLICT DO UPDATE is satisfied, update
3133 * (but still lock row, even though it may not satisfy estate's
3134 * snapshot).
3135 *
3136 * Returns true if we're done (with or without an update), or false if
3137 * the caller must retry the INSERT from scratch.
3138 */
3139static bool
3141 ResultRelInfo *resultRelInfo,
3144 bool canSetTag,
3145 TupleTableSlot **returning)
3146{
3147 ModifyTableState *mtstate = context->mtstate;
3148 ExprContext *econtext = mtstate->ps.ps_ExprContext;
3149 Relation relation = resultRelInfo->ri_RelationDesc;
3152 LockTupleMode lockmode;
3153
3154 /*
3155 * Parse analysis should have blocked ON CONFLICT for all system
3156 * relations, which includes these. There's no fundamental obstacle to
3157 * supporting this; we'd just need to handle LOCKTAG_TUPLE like the other
3158 * ExecUpdate() caller.
3159 */
3160 Assert(!resultRelInfo->ri_needLockTagTuple);
3161
3162 /* Determine lock mode to use */
3163 lockmode = ExecUpdateLockMode(context->estate, resultRelInfo);
3164
3165 /* Lock tuple for update */
3167 resultRelInfo->ri_RelationDesc, lockmode, true))
3168 return false;
3169
3170 /*
3171 * Verify that the tuple is visible to our MVCC snapshot if the current
3172 * isolation level mandates that.
3173 *
3174 * It's not sufficient to rely on the check within ExecUpdate() as e.g.
3175 * CONFLICT ... WHERE clause may prevent us from reaching that.
3176 *
3177 * This means we only ever continue when a new command in the current
3178 * transaction could see the row, even though in READ COMMITTED mode the
3179 * tuple will not be visible according to the current statement's
3180 * snapshot. This is in line with the way UPDATE deals with newer tuple
3181 * versions.
3182 */
3183 ExecCheckTupleVisible(context->estate, relation, existing);
3184
3185 /*
3186 * Make tuple and any needed join variables available to ExecQual and
3187 * ExecProject. The EXCLUDED tuple is installed in ecxt_innertuple, while
3188 * the target's existing tuple is installed in the scantuple. EXCLUDED
3189 * has been made to reference INNER_VAR in setrefs.c, but there is no
3190 * other redirection.
3191 */
3192 econtext->ecxt_scantuple = existing;
3193 econtext->ecxt_innertuple = excludedSlot;
3194 econtext->ecxt_outertuple = NULL;
3195
3196 if (!ExecQual(onConflictSetWhere, econtext))
3197 {
3198 ExecClearTuple(existing); /* see return below */
3199 InstrCountFiltered1(&mtstate->ps, 1);
3200 return true; /* done with the tuple */
3201 }
3202
3203 if (resultRelInfo->ri_WithCheckOptions != NIL)
3204 {
3205 /*
3206 * Check target's existing tuple against UPDATE-applicable USING
3207 * security barrier quals (if any), enforced here as RLS checks/WCOs.
3208 *
3209 * The rewriter creates UPDATE RLS checks/WCOs for UPDATE security
3210 * quals, and stores them as WCOs of "kind" WCO_RLS_CONFLICT_CHECK.
3211 * Since SELECT permission on the target table is always required for
3212 * INSERT ... ON CONFLICT DO UPDATE, the rewriter also adds SELECT RLS
3213 * checks/WCOs for SELECT security quals, using WCOs of the same kind,
3214 * and this check enforces them too.
3215 *
3216 * The rewriter will also have associated UPDATE-applicable straight
3217 * RLS checks/WCOs for the benefit of the ExecUpdate() call that
3218 * follows. INSERTs and UPDATEs naturally have mutually exclusive WCO
3219 * kinds, so there is no danger of spurious over-enforcement in the
3220 * INSERT or UPDATE path.
3221 */
3223 existing,
3224 mtstate->ps.state);
3225 }
3226
3227 /* Project the new tuple version */
3228 ExecProject(resultRelInfo->ri_onConflict->oc_ProjInfo);
3229
3230 /*
3231 * Note that it is possible that the target tuple has been modified in
3232 * this session, after the above table_tuple_lock. We choose to not error
3233 * out in that case, in line with ExecUpdate's treatment of similar cases.
3234 * This can happen if an UPDATE is triggered from within ExecQual(),
3235 * ExecWithCheckOptions() or ExecProject() above, e.g. by selecting from a
3236 * wCTE in the ON CONFLICT's SET.
3237 */
3238
3239 /* Execute UPDATE with projection */
3240 *returning = ExecUpdate(context, resultRelInfo,
3242 resultRelInfo->ri_onConflict->oc_ProjSlot,
3243 canSetTag);
3244
3245 /*
3246 * Clear out existing tuple, as there might not be another conflict among
3247 * the next input rows. Don't want to hold resources till the end of the
3248 * query. First though, make sure that the returning slot, if any, has a
3249 * local copy of any OLD pass-by-reference values, if it refers to any OLD
3250 * columns.
3251 */
3252 if (*returning != NULL &&
3254 ExecMaterializeSlot(*returning);
3255
3257
3258 return true;
3259}
3260
3261/*
3262 * ExecOnConflictSelect --- execute SELECT of INSERT ON CONFLICT DO SELECT
3263 *
3264 * If SELECT FOR UPDATE/SHARE is specified, try to lock tuple as part of
3265 * speculative insertion. If a qual originating from ON CONFLICT DO SELECT is
3266 * satisfied, select (but still lock row, even though it may not satisfy
3267 * estate's snapshot).
3268 *
3269 * Returns true if we're done (with or without a select), or false if the
3270 * caller must retry the INSERT from scratch.
3271 */
3272static bool
3274 ResultRelInfo *resultRelInfo,
3277 bool canSetTag,
3278 TupleTableSlot **returning)
3279{
3280 ModifyTableState *mtstate = context->mtstate;
3281 ExprContext *econtext = mtstate->ps.ps_ExprContext;
3282 Relation relation = resultRelInfo->ri_RelationDesc;
3285 LockClauseStrength lockStrength = resultRelInfo->ri_onConflict->oc_LockStrength;
3286
3287 /*
3288 * Parse analysis should have blocked ON CONFLICT for all system
3289 * relations, which includes these. There's no fundamental obstacle to
3290 * supporting this; we'd just need to handle LOCKTAG_TUPLE appropriately.
3291 */
3292 Assert(!resultRelInfo->ri_needLockTagTuple);
3293
3294 /* Fetch/lock existing tuple, according to the requested lock strength */
3295 if (lockStrength == LCS_NONE)
3296 {
3297 if (!table_tuple_fetch_row_version(relation,
3300 existing))
3301 elog(ERROR, "failed to fetch conflicting tuple for ON CONFLICT");
3302 }
3303 else
3304 {
3305 LockTupleMode lockmode;
3306
3307 switch (lockStrength)
3308 {
3309 case LCS_FORKEYSHARE:
3310 lockmode = LockTupleKeyShare;
3311 break;
3312 case LCS_FORSHARE:
3313 lockmode = LockTupleShare;
3314 break;
3315 case LCS_FORNOKEYUPDATE:
3316 lockmode = LockTupleNoKeyExclusive;
3317 break;
3318 case LCS_FORUPDATE:
3319 lockmode = LockTupleExclusive;
3320 break;
3321 default:
3322 elog(ERROR, "Unexpected lock strength %d", (int) lockStrength);
3323 }
3324
3326 resultRelInfo->ri_RelationDesc, lockmode, false))
3327 return false;
3328 }
3329
3330 /*
3331 * Verify that the tuple is visible to our MVCC snapshot if the current
3332 * isolation level mandates that. See comments in ExecOnConflictUpdate().
3333 */
3334 ExecCheckTupleVisible(context->estate, relation, existing);
3335
3336 /*
3337 * Make tuple and any needed join variables available to ExecQual. The
3338 * EXCLUDED tuple is installed in ecxt_innertuple, while the target's
3339 * existing tuple is installed in the scantuple. EXCLUDED has been made
3340 * to reference INNER_VAR in setrefs.c, but there is no other redirection.
3341 */
3342 econtext->ecxt_scantuple = existing;
3343 econtext->ecxt_innertuple = excludedSlot;
3344 econtext->ecxt_outertuple = NULL;
3345
3346 if (!ExecQual(onConflictSelectWhere, econtext))
3347 {
3348 ExecClearTuple(existing); /* see return below */
3349 InstrCountFiltered1(&mtstate->ps, 1);
3350 return true; /* done with the tuple */
3351 }
3352
3353 if (resultRelInfo->ri_WithCheckOptions != NIL)
3354 {
3355 /*
3356 * Check target's existing tuple against SELECT-applicable USING
3357 * security barrier quals (if any), enforced here as RLS checks/WCOs.
3358 *
3359 * The rewriter creates WCOs from the USING quals of SELECT policies,
3360 * and stores them as WCOs of "kind" WCO_RLS_CONFLICT_CHECK. If FOR
3361 * UPDATE/SHARE was specified, UPDATE permissions are required on the
3362 * target table, and the rewriter also adds WCOs built from the USING
3363 * quals of UPDATE policies, using WCOs of the same kind, and this
3364 * check enforces them too.
3365 */
3367 existing,
3368 mtstate->ps.state);
3369 }
3370
3371 /* RETURNING is required for DO SELECT */
3372 Assert(resultRelInfo->ri_projectReturning);
3373
3374 *returning = ExecProcessReturning(context, resultRelInfo, false,
3375 existing, existing, context->planSlot);
3376
3377 if (canSetTag)
3378 context->estate->es_processed++;
3379
3380 /*
3381 * Before releasing the existing tuple, make sure that the returning slot
3382 * has a local copy of any pass-by-reference values.
3383 */
3384 ExecMaterializeSlot(*returning);
3385
3386 /*
3387 * Clear out existing tuple, as there might not be another conflict among
3388 * the next input rows. Don't want to hold resources till the end of the
3389 * query.
3390 */
3392
3393 return true;
3394}
3395
3396/*
3397 * Perform MERGE.
3398 */
3399static TupleTableSlot *
3401 ItemPointer tupleid, HeapTuple oldtuple, bool canSetTag)
3402{
3404 bool matched;
3405
3406 /*-----
3407 * If we are dealing with a WHEN MATCHED case, tupleid or oldtuple is
3408 * valid, depending on whether the result relation is a table or a view.
3409 * We execute the first action for which the additional WHEN MATCHED AND
3410 * quals pass. If an action without quals is found, that action is
3411 * executed.
3412 *
3413 * Similarly, in the WHEN NOT MATCHED BY SOURCE case, tupleid or oldtuple
3414 * is valid, and we look at the given WHEN NOT MATCHED BY SOURCE actions
3415 * in sequence until one passes. This is almost identical to the WHEN
3416 * MATCHED case, and both cases are handled by ExecMergeMatched().
3417 *
3418 * Finally, in the WHEN NOT MATCHED [BY TARGET] case, both tupleid and
3419 * oldtuple are invalid, and we look at the given WHEN NOT MATCHED [BY
3420 * TARGET] actions in sequence until one passes.
3421 *
3422 * Things get interesting in case of concurrent update/delete of the
3423 * target tuple. Such concurrent update/delete is detected while we are
3424 * executing a WHEN MATCHED or WHEN NOT MATCHED BY SOURCE action.
3425 *
3426 * A concurrent update can:
3427 *
3428 * 1. modify the target tuple so that the results from checking any
3429 * additional quals attached to WHEN MATCHED or WHEN NOT MATCHED BY
3430 * SOURCE actions potentially change, but the result from the join
3431 * quals does not change.
3432 *
3433 * In this case, we are still dealing with the same kind of match
3434 * (MATCHED or NOT MATCHED BY SOURCE). We recheck the same list of
3435 * actions from the start and choose the first one that satisfies the
3436 * new target tuple.
3437 *
3438 * 2. modify the target tuple in the WHEN MATCHED case so that the join
3439 * quals no longer pass and hence the source and target tuples no
3440 * longer match.
3441 *
3442 * In this case, we are now dealing with a NOT MATCHED case, and we
3443 * process both WHEN NOT MATCHED BY SOURCE and WHEN NOT MATCHED [BY
3444 * TARGET] actions. First ExecMergeMatched() processes the list of
3445 * WHEN NOT MATCHED BY SOURCE actions in sequence until one passes,
3446 * then ExecMergeNotMatched() processes any WHEN NOT MATCHED [BY
3447 * TARGET] actions in sequence until one passes. Thus we may execute
3448 * two actions; one of each kind.
3449 *
3450 * Thus we support concurrent updates that turn MATCHED candidate rows
3451 * into NOT MATCHED rows. However, we do not attempt to support cases
3452 * that would turn NOT MATCHED rows into MATCHED rows, or which would
3453 * cause a target row to match a different source row.
3454 *
3455 * A concurrent delete changes a WHEN MATCHED case to WHEN NOT MATCHED
3456 * [BY TARGET].
3457 *
3458 * ExecMergeMatched() takes care of following the update chain and
3459 * re-finding the qualifying WHEN MATCHED or WHEN NOT MATCHED BY SOURCE
3460 * action, as long as the target tuple still exists. If the target tuple
3461 * gets deleted or a concurrent update causes the join quals to fail, it
3462 * returns a matched status of false and we call ExecMergeNotMatched().
3463 * Given that ExecMergeMatched() always makes progress by following the
3464 * update chain and we never switch from ExecMergeNotMatched() to
3465 * ExecMergeMatched(), there is no risk of a livelock.
3466 */
3467 matched = tupleid != NULL || oldtuple != NULL;
3468 if (matched)
3469 rslot = ExecMergeMatched(context, resultRelInfo, tupleid, oldtuple,
3470 canSetTag, &matched);
3471
3472 /*
3473 * Deal with the NOT MATCHED case (either a NOT MATCHED tuple from the
3474 * join, or a previously MATCHED tuple for which ExecMergeMatched() set
3475 * "matched" to false, indicating that it no longer matches).
3476 */
3477 if (!matched)
3478 {
3479 /*
3480 * If a concurrent update turned a MATCHED case into a NOT MATCHED
3481 * case, and we have both WHEN NOT MATCHED BY SOURCE and WHEN NOT
3482 * MATCHED [BY TARGET] actions, and there is a RETURNING clause,
3483 * ExecMergeMatched() may have already executed a WHEN NOT MATCHED BY
3484 * SOURCE action, and computed the row to return. If so, we cannot
3485 * execute a WHEN NOT MATCHED [BY TARGET] action now, so mark it as
3486 * pending (to be processed on the next call to ExecModifyTable()).
3487 * Otherwise, just process the action now.
3488 */
3489 if (rslot == NULL)
3490 rslot = ExecMergeNotMatched(context, resultRelInfo, canSetTag);
3491 else
3492 context->mtstate->mt_merge_pending_not_matched = context->planSlot;
3493 }
3494
3495 return rslot;
3496}
3497
3498/*
3499 * Check and execute the first qualifying MATCHED or NOT MATCHED BY SOURCE
3500 * action, depending on whether the join quals are satisfied. If the target
3501 * relation is a table, the current target tuple is identified by tupleid.
3502 * Otherwise, if the target relation is a view, oldtuple is the current target
3503 * tuple from the view.
3504 *
3505 * We start from the first WHEN MATCHED or WHEN NOT MATCHED BY SOURCE action
3506 * and check if the WHEN quals pass, if any. If the WHEN quals for the first
3507 * action do not pass, we check the second, then the third and so on. If we
3508 * reach the end without finding a qualifying action, we return NULL.
3509 * Otherwise, we execute the qualifying action and return its RETURNING
3510 * result, if any, or NULL.
3511 *
3512 * On entry, "*matched" is assumed to be true. If a concurrent update or
3513 * delete is detected that causes the join quals to no longer pass, we set it
3514 * to false, indicating that the caller should process any NOT MATCHED [BY
3515 * TARGET] actions.
3516 *
3517 * After a concurrent update, we restart from the first action to look for a
3518 * new qualifying action to execute. If the join quals originally passed, and
3519 * the concurrent update caused them to no longer pass, then we switch from
3520 * the MATCHED to the NOT MATCHED BY SOURCE list of actions before restarting
3521 * (and setting "*matched" to false). As a result we may execute a WHEN NOT
3522 * MATCHED BY SOURCE action, and set "*matched" to false, causing the caller
3523 * to also execute a WHEN NOT MATCHED [BY TARGET] action.
3524 */
3525static TupleTableSlot *
3527 ItemPointer tupleid, HeapTuple oldtuple, bool canSetTag,
3528 bool *matched)
3529{
3530 ModifyTableState *mtstate = context->mtstate;
3531 List **mergeActions = resultRelInfo->ri_MergeActions;
3536 EState *estate = context->estate;
3537 ExprContext *econtext = mtstate->ps.ps_ExprContext;
3538 bool isNull;
3539 EPQState *epqstate = &mtstate->mt_epqstate;
3540 ListCell *l;
3541
3542 /* Expect matched to be true on entry */
3543 Assert(*matched);
3544
3545 /*
3546 * If there are no WHEN MATCHED or WHEN NOT MATCHED BY SOURCE actions, we
3547 * are done.
3548 */
3551 return NULL;
3552
3553 /*
3554 * Make tuple and any needed join variables available to ExecQual and
3555 * ExecProject. The target's existing tuple is installed in the scantuple.
3556 * This target relation's slot is required only in the case of a MATCHED
3557 * or NOT MATCHED BY SOURCE tuple and UPDATE/DELETE actions.
3558 */
3559 econtext->ecxt_scantuple = resultRelInfo->ri_oldTupleSlot;
3560 econtext->ecxt_innertuple = context->planSlot;
3561 econtext->ecxt_outertuple = NULL;
3562
3563 /*
3564 * This routine is only invoked for matched target rows, so we should
3565 * either have the tupleid of the target row, or an old tuple from the
3566 * target wholerow junk attr.
3567 */
3568 Assert(tupleid != NULL || oldtuple != NULL);
3570 if (oldtuple != NULL)
3571 {
3572 Assert(!resultRelInfo->ri_needLockTagTuple);
3573 ExecForceStoreHeapTuple(oldtuple, resultRelInfo->ri_oldTupleSlot,
3574 false);
3575 }
3576 else
3577 {
3578 if (resultRelInfo->ri_needLockTagTuple)
3579 {
3580 /*
3581 * This locks even for CMD_DELETE, for CMD_NOTHING, and for tuples
3582 * that don't match mas_whenqual. MERGE on system catalogs is a
3583 * minor use case, so don't bother optimizing those.
3584 */
3585 LockTuple(resultRelInfo->ri_RelationDesc, tupleid,
3587 lockedtid = *tupleid;
3588 }
3590 tupleid,
3592 resultRelInfo->ri_oldTupleSlot))
3593 elog(ERROR, "failed to fetch the target tuple");
3594 }
3595
3596 /*
3597 * Test the join condition. If it's satisfied, perform a MATCHED action.
3598 * Otherwise, perform a NOT MATCHED BY SOURCE action.
3599 *
3600 * Note that this join condition will be NULL if there are no NOT MATCHED
3601 * BY SOURCE actions --- see transform_MERGE_to_join(). In that case, we
3602 * need only consider MATCHED actions here.
3603 */
3604 if (ExecQual(resultRelInfo->ri_MergeJoinCondition, econtext))
3606 else
3608
3610
3611 foreach(l, actionStates)
3612 {
3614 CmdType commandType = relaction->mas_action->commandType;
3617
3618 /*
3619 * Test condition, if any.
3620 *
3621 * In the absence of any condition, we perform the action
3622 * unconditionally (no need to check separately since ExecQual() will
3623 * return true if there are no conditions to evaluate).
3624 */
3625 if (!ExecQual(relaction->mas_whenqual, econtext))
3626 continue;
3627
3628 /*
3629 * Check if the existing target tuple meets the USING checks of
3630 * UPDATE/DELETE RLS policies. If those checks fail, we throw an
3631 * error.
3632 *
3633 * The WITH CHECK quals for UPDATE RLS policies are applied in
3634 * ExecUpdateAct() and hence we need not do anything special to handle
3635 * them.
3636 *
3637 * NOTE: We must do this after WHEN quals are evaluated, so that we
3638 * check policies only when they matter.
3639 */
3640 if (resultRelInfo->ri_WithCheckOptions && commandType != CMD_NOTHING)
3641 {
3642 ExecWithCheckOptions(commandType == CMD_UPDATE ?
3644 resultRelInfo,
3645 resultRelInfo->ri_oldTupleSlot,
3646 context->mtstate->ps.state);
3647 }
3648
3649 /* Perform stated action */
3650 switch (commandType)
3651 {
3652 case CMD_UPDATE:
3653
3654 /*
3655 * Project the output tuple, and use that to update the table.
3656 * We don't need to filter out junk attributes, because the
3657 * UPDATE action's targetlist doesn't have any.
3658 */
3659 newslot = ExecProject(relaction->mas_proj);
3660
3661 mtstate->mt_merge_action = relaction;
3662 if (!ExecUpdatePrologue(context, resultRelInfo,
3664 {
3665 if (result == TM_Ok)
3666 goto out; /* "do nothing" */
3667
3668 break; /* concurrent update/delete */
3669 }
3670
3671 /* INSTEAD OF ROW UPDATE Triggers */
3672 if (resultRelInfo->ri_TrigDesc &&
3673 resultRelInfo->ri_TrigDesc->trig_update_instead_row)
3674 {
3675 if (!ExecIRUpdateTriggers(estate, resultRelInfo,
3676 oldtuple, newslot))
3677 goto out; /* "do nothing" */
3678 }
3679 else
3680 {
3681 /* checked ri_needLockTagTuple above */
3682 Assert(oldtuple == NULL);
3683
3684 result = ExecUpdateAct(context, resultRelInfo, tupleid,
3685 NULL, newslot, canSetTag,
3686 &updateCxt);
3687
3688 /*
3689 * As in ExecUpdate(), if ExecUpdateAct() reports that a
3690 * cross-partition update was done, then there's nothing
3691 * else for us to do --- the UPDATE has been turned into a
3692 * DELETE and an INSERT, and we must not perform any of
3693 * the usual post-update tasks. Also, the RETURNING tuple
3694 * (if any) has been projected, so we can just return
3695 * that.
3696 */
3697 if (updateCxt.crossPartUpdate)
3698 {
3699 mtstate->mt_merge_updated += 1;
3700 rslot = context->cpUpdateReturningSlot;
3701 goto out;
3702 }
3703 }
3704
3705 if (result == TM_Ok)
3706 {
3707 ExecUpdateEpilogue(context, &updateCxt, resultRelInfo,
3708 tupleid, NULL, newslot);
3709 mtstate->mt_merge_updated += 1;
3710 }
3711 break;
3712
3713 case CMD_DELETE:
3714 mtstate->mt_merge_action = relaction;
3715 if (!ExecDeletePrologue(context, resultRelInfo, tupleid,
3716 NULL, NULL, &result))
3717 {
3718 if (result == TM_Ok)
3719 goto out; /* "do nothing" */
3720
3721 break; /* concurrent update/delete */
3722 }
3723
3724 /* INSTEAD OF ROW DELETE Triggers */
3725 if (resultRelInfo->ri_TrigDesc &&
3726 resultRelInfo->ri_TrigDesc->trig_delete_instead_row)
3727 {
3728 if (!ExecIRDeleteTriggers(estate, resultRelInfo,
3729 oldtuple))
3730 goto out; /* "do nothing" */
3731 }
3732 else
3733 {
3734 /* checked ri_needLockTagTuple above */
3735 Assert(oldtuple == NULL);
3736
3737 result = ExecDeleteAct(context, resultRelInfo, tupleid,
3738 false);
3739 }
3740
3741 if (result == TM_Ok)
3742 {
3743 ExecDeleteEpilogue(context, resultRelInfo, tupleid, NULL,
3744 false);
3745 mtstate->mt_merge_deleted += 1;
3746 }
3747 break;
3748
3749 case CMD_NOTHING:
3750 /* Doing nothing is always OK */
3751 result = TM_Ok;
3752 break;
3753
3754 default:
3755 elog(ERROR, "unknown action in MERGE WHEN clause");
3756 }
3757
3758 switch (result)
3759 {
3760 case TM_Ok:
3761 /* all good; perform final actions */
3762 if (canSetTag && commandType != CMD_NOTHING)
3763 (estate->es_processed)++;
3764
3765 break;
3766
3767 case TM_SelfModified:
3768
3769 /*
3770 * The target tuple was already updated or deleted by the
3771 * current command, or by a later command in the current
3772 * transaction. The former case is explicitly disallowed by
3773 * the SQL standard for MERGE, which insists that the MERGE
3774 * join condition should not join a target row to more than
3775 * one source row.
3776 *
3777 * The latter case arises if the tuple is modified by a
3778 * command in a BEFORE trigger, or perhaps by a command in a
3779 * volatile function used in the query. In such situations we
3780 * should not ignore the MERGE action, but it is equally
3781 * unsafe to proceed. We don't want to discard the original
3782 * MERGE action while keeping the triggered actions based on
3783 * it; and it would be no better to allow the original MERGE
3784 * action while discarding the updates that it triggered. So
3785 * throwing an error is the only safe course.
3786 */
3787 if (context->tmfd.cmax != estate->es_output_cid)
3788 ereport(ERROR,
3790 errmsg("tuple to be updated or deleted was already modified by an operation triggered by the current command"),
3791 errhint("Consider using an AFTER trigger instead of a BEFORE trigger to propagate changes to other rows.")));
3792
3794 ereport(ERROR,
3796 /* translator: %s is a SQL command name */
3797 errmsg("%s command cannot affect row a second time",
3798 "MERGE"),
3799 errhint("Ensure that not more than one source row matches any one target row.")));
3800
3801 /* This shouldn't happen */
3802 elog(ERROR, "attempted to update or delete invisible tuple");
3803 break;
3804
3805 case TM_Deleted:
3807 ereport(ERROR,
3809 errmsg("could not serialize access due to concurrent delete")));
3810
3811 /*
3812 * If the tuple was already deleted, set matched to false to
3813 * let caller handle it under NOT MATCHED [BY TARGET] clauses.
3814 */
3815 *matched = false;
3816 goto out;
3817
3818 case TM_Updated:
3819 {
3820 bool was_matched;
3823 *inputslot;
3824 LockTupleMode lockmode;
3825
3827 ereport(ERROR,
3829 errmsg("could not serialize access due to concurrent update")));
3830
3831 /*
3832 * The target tuple was concurrently updated by some other
3833 * transaction. If we are currently processing a MATCHED
3834 * action, use EvalPlanQual() with the new version of the
3835 * tuple and recheck the join qual, to detect a change
3836 * from the MATCHED to the NOT MATCHED cases. If we are
3837 * already processing a NOT MATCHED BY SOURCE action, we
3838 * skip this (cannot switch from NOT MATCHED BY SOURCE to
3839 * MATCHED).
3840 */
3841 was_matched = relaction->mas_action->matchKind == MERGE_WHEN_MATCHED;
3842 resultRelationDesc = resultRelInfo->ri_RelationDesc;
3843 lockmode = ExecUpdateLockMode(estate, resultRelInfo);
3844
3845 if (was_matched)
3846 inputslot = EvalPlanQualSlot(epqstate, resultRelationDesc,
3847 resultRelInfo->ri_RangeTableIndex);
3848 else
3849 inputslot = resultRelInfo->ri_oldTupleSlot;
3850
3852 estate->es_snapshot,
3853 inputslot, estate->es_output_cid,
3854 lockmode, LockWaitBlock,
3856 &context->tmfd);
3857 switch (result)
3858 {
3859 case TM_Ok:
3860
3861 /*
3862 * If the tuple was updated and migrated to
3863 * another partition concurrently, the current
3864 * MERGE implementation can't follow. There's
3865 * probably a better way to handle this case, but
3866 * it'd require recognizing the relation to which
3867 * the tuple moved, and setting our current
3868 * resultRelInfo to that.
3869 */
3871 ereport(ERROR,
3873 errmsg("tuple to be merged was already moved to another partition due to concurrent update")));
3874
3875 /*
3876 * If this was a MATCHED case, use EvalPlanQual()
3877 * to recheck the join condition.
3878 */
3879 if (was_matched)
3880 {
3881 epqslot = EvalPlanQual(epqstate,
3883 resultRelInfo->ri_RangeTableIndex,
3884 inputslot);
3885
3886 /*
3887 * If the subplan didn't return a tuple, then
3888 * we must be dealing with an inner join for
3889 * which the join condition no longer matches.
3890 * This can only happen if there are no NOT
3891 * MATCHED actions, and so there is nothing
3892 * more to do.
3893 */
3894 if (TupIsNull(epqslot))
3895 goto out;
3896
3897 /*
3898 * If we got a NULL ctid from the subplan, the
3899 * join quals no longer pass and we switch to
3900 * the NOT MATCHED BY SOURCE case.
3901 */
3903 resultRelInfo->ri_RowIdAttNo,
3904 &isNull);
3905 if (isNull)
3906 *matched = false;
3907
3908 /*
3909 * Otherwise, recheck the join quals to see if
3910 * we need to switch to the NOT MATCHED BY
3911 * SOURCE case.
3912 */
3913 if (resultRelInfo->ri_needLockTagTuple)
3914 {
3916 UnlockTuple(resultRelInfo->ri_RelationDesc, &lockedtid,
3918 LockTuple(resultRelInfo->ri_RelationDesc, tupleid,
3920 lockedtid = *tupleid;
3921 }
3922
3924 tupleid,
3926 resultRelInfo->ri_oldTupleSlot))
3927 elog(ERROR, "failed to fetch the target tuple");
3928
3929 if (*matched)
3930 *matched = ExecQual(resultRelInfo->ri_MergeJoinCondition,
3931 econtext);
3932
3933 /* Switch lists, if necessary */
3934 if (!*matched)
3935 {
3937
3938 /*
3939 * If we have both NOT MATCHED BY SOURCE
3940 * and NOT MATCHED BY TARGET actions (a
3941 * full join between the source and target
3942 * relations), the single previously
3943 * matched tuple from the outer plan node
3944 * is treated as two not matched tuples,
3945 * in the same way as if they had not
3946 * matched to start with. Therefore, we
3947 * must adjust the outer plan node's tuple
3948 * count, if we're instrumenting the
3949 * query, to get the correct "skipped" row
3950 * count --- see show_modifytable_info().
3951 */
3952 if (outerPlanState(mtstate)->instrument &&
3955 InstrUpdateTupleCount(outerPlanState(mtstate)->instrument, 1.0);
3956 }
3957 }
3958
3959 /*
3960 * Loop back and process the MATCHED or NOT
3961 * MATCHED BY SOURCE actions from the start.
3962 */
3963 goto lmerge_matched;
3964
3965 case TM_Deleted:
3966
3967 /*
3968 * tuple already deleted; tell caller to run NOT
3969 * MATCHED [BY TARGET] actions
3970 */
3971 *matched = false;
3972 goto out;
3973
3974 case TM_SelfModified:
3975
3976 /*
3977 * This can be reached when following an update
3978 * chain from a tuple updated by another session,
3979 * reaching a tuple that was already updated or
3980 * deleted by the current command, or by a later
3981 * command in the current transaction. As above,
3982 * this should always be treated as an error.
3983 */
3984 if (context->tmfd.cmax != estate->es_output_cid)
3985 ereport(ERROR,
3987 errmsg("tuple to be updated or deleted was already modified by an operation triggered by the current command"),
3988 errhint("Consider using an AFTER trigger instead of a BEFORE trigger to propagate changes to other rows.")));
3989
3991 ereport(ERROR,
3993 /* translator: %s is a SQL command name */
3994 errmsg("%s command cannot affect row a second time",
3995 "MERGE"),
3996 errhint("Ensure that not more than one source row matches any one target row.")));
3997
3998 /* This shouldn't happen */
3999 elog(ERROR, "attempted to update or delete invisible tuple");
4000 goto out;
4001
4002 default:
4003 /* see table_tuple_lock call in ExecDelete() */
4004 elog(ERROR, "unexpected table_tuple_lock status: %u",
4005 result);
4006 goto out;
4007 }
4008 }
4009
4010 case TM_Invisible:
4011 case TM_WouldBlock:
4012 case TM_BeingModified:
4013 /* these should not occur */
4014 elog(ERROR, "unexpected tuple operation result: %d", result);
4015 break;
4016 }
4017
4018 /* Process RETURNING if present */
4019 if (resultRelInfo->ri_projectReturning)
4020 {
4021 switch (commandType)
4022 {
4023 case CMD_UPDATE:
4024 rslot = ExecProcessReturning(context,
4025 resultRelInfo,
4026 false,
4027 resultRelInfo->ri_oldTupleSlot,
4028 newslot,
4029 context->planSlot);
4030 break;
4031
4032 case CMD_DELETE:
4033 rslot = ExecProcessReturning(context,
4034 resultRelInfo,
4035 true,
4036 resultRelInfo->ri_oldTupleSlot,
4037 NULL,
4038 context->planSlot);
4039 break;
4040
4041 case CMD_NOTHING:
4042 break;
4043
4044 default:
4045 elog(ERROR, "unrecognized commandType: %d",
4046 (int) commandType);
4047 }
4048 }
4049
4050 /*
4051 * We've activated one of the WHEN clauses, so we don't search
4052 * further. This is required behaviour, not an optimization.
4053 */
4054 break;
4055 }
4056
4057 /*
4058 * Successfully executed an action or no qualifying action was found.
4059 */
4060out:
4062 UnlockTuple(resultRelInfo->ri_RelationDesc, &lockedtid,
4064 return rslot;
4065}
4066
4067/*
4068 * Execute the first qualifying NOT MATCHED [BY TARGET] action.
4069 */
4070static TupleTableSlot *
4072 bool canSetTag)
4073{
4074 ModifyTableState *mtstate = context->mtstate;
4075 ExprContext *econtext = mtstate->ps.ps_ExprContext;
4078 ListCell *l;
4079
4080 /*
4081 * For INSERT actions, the root relation's merge action is OK since the
4082 * INSERT's targetlist and the WHEN conditions can only refer to the
4083 * source relation and hence it does not matter which result relation we
4084 * work with.
4085 *
4086 * XXX does this mean that we can avoid creating copies of actionStates on
4087 * partitioned tables, for not-matched actions?
4088 */
4090
4091 /*
4092 * Make source tuple available to ExecQual and ExecProject. We don't need
4093 * the target tuple, since the WHEN quals and targetlist can't refer to
4094 * the target columns.
4095 */
4096 econtext->ecxt_scantuple = NULL;
4097 econtext->ecxt_innertuple = context->planSlot;
4098 econtext->ecxt_outertuple = NULL;
4099
4100 foreach(l, actionStates)
4101 {
4102 MergeActionState *action = (MergeActionState *) lfirst(l);
4103 CmdType commandType = action->mas_action->commandType;
4105
4106 /*
4107 * Test condition, if any.
4108 *
4109 * In the absence of any condition, we perform the action
4110 * unconditionally (no need to check separately since ExecQual() will
4111 * return true if there are no conditions to evaluate).
4112 */
4113 if (!ExecQual(action->mas_whenqual, econtext))
4114 continue;
4115
4116 /* Perform stated action */
4117 switch (commandType)
4118 {
4119 case CMD_INSERT:
4120
4121 /*
4122 * Project the tuple. In case of a partitioned table, the
4123 * projection was already built to use the root's descriptor,
4124 * so we don't need to map the tuple here.
4125 */
4126 newslot = ExecProject(action->mas_proj);
4127 mtstate->mt_merge_action = action;
4128
4129 rslot = ExecInsert(context, mtstate->rootResultRelInfo,
4130 newslot, canSetTag, NULL, NULL);
4131 mtstate->mt_merge_inserted += 1;
4132 break;
4133 case CMD_NOTHING:
4134 /* Do nothing */
4135 break;
4136 default:
4137 elog(ERROR, "unknown action in MERGE WHEN NOT MATCHED clause");
4138 }
4139
4140 /*
4141 * We've activated one of the WHEN clauses, so we don't search
4142 * further. This is required behaviour, not an optimization.
4143 */
4144 break;
4145 }
4146
4147 return rslot;
4148}
4149
4150/*
4151 * Initialize state for execution of MERGE.
4152 */
4153void
4155{
4156 List *mergeActionLists = mtstate->mt_mergeActionLists;
4157 List *mergeJoinConditions = mtstate->mt_mergeJoinConditions;
4159 ResultRelInfo *resultRelInfo;
4160 ExprContext *econtext;
4161 ListCell *lc;
4162 int i;
4163
4164 if (mergeActionLists == NIL)
4165 return;
4166
4167 mtstate->mt_merge_subcommands = 0;
4168
4169 if (mtstate->ps.ps_ExprContext == NULL)
4170 ExecAssignExprContext(estate, &mtstate->ps);
4171 econtext = mtstate->ps.ps_ExprContext;
4172
4173 /*
4174 * Create a MergeActionState for each action on the mergeActionList and
4175 * add it to either a list of matched actions or not-matched actions.
4176 *
4177 * Similar logic appears in ExecInitPartitionInfo(), so if changing
4178 * anything here, do so there too.
4179 */
4180 i = 0;
4181 foreach(lc, mergeActionLists)
4182 {
4183 List *mergeActionList = lfirst(lc);
4184 Node *joinCondition;
4186 ListCell *l;
4187
4188 joinCondition = (Node *) list_nth(mergeJoinConditions, i);
4189 resultRelInfo = mtstate->resultRelInfo + i;
4190 i++;
4192
4193 /* initialize slots for MERGE fetches from this rel */
4194 if (unlikely(!resultRelInfo->ri_projectNewInfoValid))
4195 ExecInitMergeTupleSlots(mtstate, resultRelInfo);
4196
4197 /* initialize state for join condition checking */
4198 resultRelInfo->ri_MergeJoinCondition =
4199 ExecInitQual((List *) joinCondition, &mtstate->ps);
4200
4201 foreach(l, mergeActionList)
4202 {
4203 MergeAction *action = (MergeAction *) lfirst(l);
4204 MergeActionState *action_state;
4207
4208 /*
4209 * Build action merge state for this rel. (For partitions,
4210 * equivalent code exists in ExecInitPartitionInfo.)
4211 */
4212 action_state = makeNode(MergeActionState);
4213 action_state->mas_action = action;
4214 action_state->mas_whenqual = ExecInitQual((List *) action->qual,
4215 &mtstate->ps);
4216
4217 /*
4218 * We create three lists - one for each MergeMatchKind - and stick
4219 * the MergeActionState into the appropriate list.
4220 */
4221 resultRelInfo->ri_MergeActions[action->matchKind] =
4222 lappend(resultRelInfo->ri_MergeActions[action->matchKind],
4223 action_state);
4224
4225 switch (action->commandType)
4226 {
4227 case CMD_INSERT:
4228 /* INSERT actions always use rootRelInfo */
4229 ExecCheckPlanOutput(rootRelInfo->ri_RelationDesc,
4230 action->targetList);
4231
4232 /*
4233 * If the MERGE targets a partitioned table, any INSERT
4234 * actions must be routed through it, not the child
4235 * relations. Initialize the routing struct and the root
4236 * table's "new" tuple slot for that, if not already done.
4237 * The projection we prepare, for all relations, uses the
4238 * root relation descriptor, and targets the plan's root
4239 * slot. (This is consistent with the fact that we
4240 * checked the plan output to match the root relation,
4241 * above.)
4242 */
4243 if (rootRelInfo->ri_RelationDesc->rd_rel->relkind ==
4245 {
4246 if (mtstate->mt_partition_tuple_routing == NULL)
4247 {
4248 /*
4249 * Initialize planstate for routing if not already
4250 * done.
4251 *
4252 * Note that the slot is managed as a standalone
4253 * slot belonging to ModifyTableState, so we pass
4254 * NULL for the 2nd argument.
4255 */
4256 mtstate->mt_root_tuple_slot =
4257 table_slot_create(rootRelInfo->ri_RelationDesc,
4258 NULL);
4261 rootRelInfo->ri_RelationDesc);
4262 }
4263 tgtslot = mtstate->mt_root_tuple_slot;
4264 tgtdesc = RelationGetDescr(rootRelInfo->ri_RelationDesc);
4265 }
4266 else
4267 {
4268 /*
4269 * If the MERGE targets an inherited table, we insert
4270 * into the root table, so we must initialize its
4271 * "new" tuple slot, if not already done, and use its
4272 * relation descriptor for the projection.
4273 *
4274 * For non-inherited tables, rootRelInfo and
4275 * resultRelInfo are the same, and the "new" tuple
4276 * slot will already have been initialized.
4277 */
4278 if (rootRelInfo->ri_newTupleSlot == NULL)
4279 rootRelInfo->ri_newTupleSlot =
4280 table_slot_create(rootRelInfo->ri_RelationDesc,
4281 &estate->es_tupleTable);
4282
4283 tgtslot = rootRelInfo->ri_newTupleSlot;
4284 tgtdesc = RelationGetDescr(rootRelInfo->ri_RelationDesc);
4285 }
4286
4287 action_state->mas_proj =
4288 ExecBuildProjectionInfo(action->targetList, econtext,
4289 tgtslot,
4290 &mtstate->ps,
4291 tgtdesc);
4292
4294 break;
4295 case CMD_UPDATE:
4296 action_state->mas_proj =
4297 ExecBuildUpdateProjection(action->targetList,
4298 true,
4299 action->updateColnos,
4301 econtext,
4302 resultRelInfo->ri_newTupleSlot,
4303 &mtstate->ps);
4305 break;
4306 case CMD_DELETE:
4308 break;
4309 case CMD_NOTHING:
4310 break;
4311 default:
4312 elog(ERROR, "unknown action in MERGE WHEN clause");
4313 break;
4314 }
4315 }
4316 }
4317
4318 /*
4319 * If the MERGE targets an inherited table, any INSERT actions will use
4320 * rootRelInfo, and rootRelInfo will not be in the resultRelInfo array.
4321 * Therefore we must initialize its WITH CHECK OPTION constraints and
4322 * RETURNING projection, as ExecInitModifyTable did for the resultRelInfo
4323 * entries.
4324 *
4325 * Note that the planner does not build a withCheckOptionList or
4326 * returningList for the root relation, but as in ExecInitPartitionInfo,
4327 * we can use the first resultRelInfo entry as a reference to calculate
4328 * the attno's for the root table.
4329 */
4330 if (rootRelInfo != mtstate->resultRelInfo &&
4332 (mtstate->mt_merge_subcommands & MERGE_INSERT) != 0)
4333 {
4334 ModifyTable *node = (ModifyTable *) mtstate->ps.plan;
4335 Relation rootRelation = rootRelInfo->ri_RelationDesc;
4339 bool found_whole_row;
4340
4341 if (node->withCheckOptionLists != NIL)
4342 {
4343 List *wcoList;
4344 List *wcoExprs = NIL;
4345
4346 /* There should be as many WCO lists as result rels */
4349
4350 /*
4351 * Use the first WCO list as a reference. In the most common case,
4352 * this will be for the same relation as rootRelInfo, and so there
4353 * will be no need to adjust its attno's.
4354 */
4356 if (rootRelation != firstResultRel)
4357 {
4358 /* Convert any Vars in it to contain the root's attno's */
4359 part_attmap =
4362 false);
4363
4364 wcoList = (List *)
4366 firstVarno, 0,
4368 RelationGetForm(rootRelation)->reltype,
4369 &found_whole_row);
4370 }
4371
4372 foreach(lc, wcoList)
4373 {
4376 &mtstate->ps);
4377
4379 }
4380
4381 rootRelInfo->ri_WithCheckOptions = wcoList;
4382 rootRelInfo->ri_WithCheckOptionExprs = wcoExprs;
4383 }
4384
4385 if (node->returningLists != NIL)
4386 {
4387 List *returningList;
4388
4389 /* There should be as many returning lists as result rels */
4392
4393 /*
4394 * Use the first returning list as a reference. In the most common
4395 * case, this will be for the same relation as rootRelInfo, and so
4396 * there will be no need to adjust its attno's.
4397 */
4398 returningList = linitial(node->returningLists);
4399 if (rootRelation != firstResultRel)
4400 {
4401 /* Convert any Vars in it to contain the root's attno's */
4402 if (part_attmap == NULL)
4403 part_attmap =
4406 false);
4407
4408 returningList = (List *)
4409 map_variable_attnos((Node *) returningList,
4410 firstVarno, 0,
4412 RelationGetForm(rootRelation)->reltype,
4413 &found_whole_row);
4414 }
4415 rootRelInfo->ri_returningList = returningList;
4416
4417 /* Initialize the RETURNING projection */
4418 rootRelInfo->ri_projectReturning =
4419 ExecBuildProjectionInfo(returningList, econtext,
4420 mtstate->ps.ps_ResultTupleSlot,
4421 &mtstate->ps,
4422 RelationGetDescr(rootRelation));
4423 }
4424 }
4425}
4426
4427/*
4428 * Initializes the tuple slots in a ResultRelInfo for any MERGE action.
4429 *
4430 * We mark 'projectNewInfoValid' even though the projections themselves
4431 * are not initialized here.
4432 */
4433void
4435 ResultRelInfo *resultRelInfo)
4436{
4437 EState *estate = mtstate->ps.state;
4438
4439 Assert(!resultRelInfo->ri_projectNewInfoValid);
4440
4441 resultRelInfo->ri_oldTupleSlot =
4442 table_slot_create(resultRelInfo->ri_RelationDesc,
4443 &estate->es_tupleTable);
4444 resultRelInfo->ri_newTupleSlot =
4445 table_slot_create(resultRelInfo->ri_RelationDesc,
4446 &estate->es_tupleTable);
4447 resultRelInfo->ri_projectNewInfoValid = true;
4448}
4449
4450/*
4451 * Process BEFORE EACH STATEMENT triggers
4452 */
4453static void
4455{
4456 ModifyTable *plan = (ModifyTable *) node->ps.plan;
4457 ResultRelInfo *resultRelInfo = node->rootResultRelInfo;
4458
4459 switch (node->operation)
4460 {
4461 case CMD_INSERT:
4462 ExecBSInsertTriggers(node->ps.state, resultRelInfo);
4463 if (plan->onConflictAction == ONCONFLICT_UPDATE)
4465 resultRelInfo);
4466 break;
4467 case CMD_UPDATE:
4468 ExecBSUpdateTriggers(node->ps.state, resultRelInfo);
4469 break;
4470 case CMD_DELETE:
4471 ExecBSDeleteTriggers(node->ps.state, resultRelInfo);
4472 break;
4473 case CMD_MERGE:
4475 ExecBSInsertTriggers(node->ps.state, resultRelInfo);
4477 ExecBSUpdateTriggers(node->ps.state, resultRelInfo);
4479 ExecBSDeleteTriggers(node->ps.state, resultRelInfo);
4480 break;
4481 default:
4482 elog(ERROR, "unknown operation");
4483 break;
4484 }
4485}
4486
4487/*
4488 * Process AFTER EACH STATEMENT triggers
4489 */
4490static void
4492{
4493 ModifyTable *plan = (ModifyTable *) node->ps.plan;
4494 ResultRelInfo *resultRelInfo = node->rootResultRelInfo;
4495
4496 switch (node->operation)
4497 {
4498 case CMD_INSERT:
4499 if (plan->onConflictAction == ONCONFLICT_UPDATE)
4501 resultRelInfo,
4503 ExecASInsertTriggers(node->ps.state, resultRelInfo,
4504 node->mt_transition_capture);
4505 break;
4506 case CMD_UPDATE:
4507 ExecASUpdateTriggers(node->ps.state, resultRelInfo,
4508 node->mt_transition_capture);
4509 break;
4510 case CMD_DELETE:
4511 ExecASDeleteTriggers(node->ps.state, resultRelInfo,
4512 node->mt_transition_capture);
4513 break;
4514 case CMD_MERGE:
4516 ExecASDeleteTriggers(node->ps.state, resultRelInfo,
4517 node->mt_transition_capture);
4519 ExecASUpdateTriggers(node->ps.state, resultRelInfo,
4520 node->mt_transition_capture);
4522 ExecASInsertTriggers(node->ps.state, resultRelInfo,
4523 node->mt_transition_capture);
4524 break;
4525 default:
4526 elog(ERROR, "unknown operation");
4527 break;
4528 }
4529}
4530
4531/*
4532 * Set up the state needed for collecting transition tuples for AFTER
4533 * triggers.
4534 */
4535static void
4537{
4538 ModifyTable *plan = (ModifyTable *) mtstate->ps.plan;
4539 ResultRelInfo *targetRelInfo = mtstate->rootResultRelInfo;
4540
4541 /* Check for transition tables on the directly targeted relation. */
4542 mtstate->mt_transition_capture =
4544 RelationGetRelid(targetRelInfo->ri_RelationDesc),
4545 mtstate->operation);
4546 if (plan->operation == CMD_INSERT &&
4547 plan->onConflictAction == ONCONFLICT_UPDATE)
4548 mtstate->mt_oc_transition_capture =
4550 RelationGetRelid(targetRelInfo->ri_RelationDesc),
4551 CMD_UPDATE);
4552}
4553
4554/*
4555 * ExecPrepareTupleRouting --- prepare for routing one tuple
4556 *
4557 * Determine the partition in which the tuple in slot is to be inserted,
4558 * and return its ResultRelInfo in *partRelInfo. The return value is
4559 * a slot holding the tuple of the partition rowtype.
4560 *
4561 * This also sets the transition table information in mtstate based on the
4562 * selected partition.
4563 */
4564static TupleTableSlot *
4566 EState *estate,
4567 PartitionTupleRouting *proute,
4568 ResultRelInfo *targetRelInfo,
4569 TupleTableSlot *slot,
4571{
4572 ResultRelInfo *partrel;
4573 TupleConversionMap *map;
4574
4575 /*
4576 * Lookup the target partition's ResultRelInfo. If ExecFindPartition does
4577 * not find a valid partition for the tuple in 'slot' then an error is
4578 * raised. An error may also be raised if the found partition is not a
4579 * valid target for INSERTs. This is required since a partitioned table
4580 * UPDATE to another partition becomes a DELETE+INSERT.
4581 */
4582 partrel = ExecFindPartition(mtstate, targetRelInfo, proute, slot, estate);
4583
4584 /*
4585 * If we're capturing transition tuples, we might need to convert from the
4586 * partition rowtype to root partitioned table's rowtype. But if there
4587 * are no BEFORE triggers on the partition that could change the tuple, we
4588 * can just remember the original unconverted tuple to avoid a needless
4589 * round trip conversion.
4590 */
4591 if (mtstate->mt_transition_capture != NULL)
4592 {
4594
4597
4600 }
4601
4602 /*
4603 * Convert the tuple, if necessary.
4604 */
4605 map = ExecGetRootToChildMap(partrel, estate);
4606 if (map != NULL)
4607 {
4608 TupleTableSlot *new_slot = partrel->ri_PartitionTupleSlot;
4609
4610 slot = execute_attr_map_slot(map->attrMap, slot, new_slot);
4611 }
4612
4613 *partRelInfo = partrel;
4614 return slot;
4615}
4616
4617/* ----------------------------------------------------------------
4618 * ExecModifyTable
4619 *
4620 * Perform table modifications as required, and return RETURNING results
4621 * if needed.
4622 * ----------------------------------------------------------------
4623 */
4624static TupleTableSlot *
4626{
4628 ModifyTableContext context;
4629 EState *estate = node->ps.state;
4630 CmdType operation = node->operation;
4631 ResultRelInfo *resultRelInfo;
4633 TupleTableSlot *slot;
4637 HeapTuple oldtuple;
4639 bool tuplock;
4640
4642
4643 /*
4644 * This should NOT get called during EvalPlanQual; we should have passed a
4645 * subplan tree to EvalPlanQual, instead. Use a runtime test not just
4646 * Assert because this condition is easy to miss in testing. (Note:
4647 * although ModifyTable should not get executed within an EvalPlanQual
4648 * operation, we do have to allow it to be initialized and shut down in
4649 * case it is within a CTE subplan. Hence this test must be here, not in
4650 * ExecInitModifyTable.)
4651 */
4652 if (estate->es_epq_active != NULL)
4653 elog(ERROR, "ModifyTable should not be called during EvalPlanQual");
4654
4655 /*
4656 * If we've already completed processing, don't try to do more. We need
4657 * this test because ExecPostprocessPlan might call us an extra time, and
4658 * our subplan's nodes aren't necessarily robust against being called
4659 * extra times.
4660 */
4661 if (node->mt_done)
4662 return NULL;
4663
4664 /*
4665 * On first call, fire BEFORE STATEMENT triggers before proceeding.
4666 */
4667 if (node->fireBSTriggers)
4668 {
4669 fireBSTriggers(node);
4670 node->fireBSTriggers = false;
4671 }
4672
4673 /* Preload local variables */
4674 resultRelInfo = node->resultRelInfo + node->mt_lastResultIndex;
4676
4677 /* Set global context */
4678 context.mtstate = node;
4679 context.epqstate = &node->mt_epqstate;
4680 context.estate = estate;
4681
4682 /*
4683 * Fetch rows from subplan, and execute the required table modification
4684 * for each row.
4685 */
4686 for (;;)
4687 {
4688 /*
4689 * Reset the per-output-tuple exprcontext. This is needed because
4690 * triggers expect to use that context as workspace. It's a bit ugly
4691 * to do this below the top level of the plan, however. We might need
4692 * to rethink this later.
4693 */
4695
4696 /*
4697 * Reset per-tuple memory context used for processing on conflict and
4698 * returning clauses, to free any expression evaluation storage
4699 * allocated in the previous cycle.
4700 */
4701 if (pstate->ps_ExprContext)
4703
4704 /*
4705 * If there is a pending MERGE ... WHEN NOT MATCHED [BY TARGET] action
4706 * to execute, do so now --- see the comments in ExecMerge().
4707 */
4709 {
4710 context.planSlot = node->mt_merge_pending_not_matched;
4711 context.cpDeletedSlot = NULL;
4712
4713 slot = ExecMergeNotMatched(&context, node->resultRelInfo,
4714 node->canSetTag);
4715
4716 /* Clear the pending action */
4718
4719 /*
4720 * If we got a RETURNING result, return it to the caller. We'll
4721 * continue the work on next call.
4722 */
4723 if (slot)
4724 return slot;
4725
4726 continue; /* continue with the next tuple */
4727 }
4728
4729 /* Fetch the next row from subplan */
4731 context.cpDeletedSlot = NULL;
4732
4733 /* No more tuples to process? */
4734 if (TupIsNull(context.planSlot))
4735 break;
4736
4737 /*
4738 * When there are multiple result relations, each tuple contains a
4739 * junk column that gives the OID of the rel from which it came.
4740 * Extract it and select the correct result relation.
4741 */
4743 {
4744 Datum datum;
4745 bool isNull;
4746 Oid resultoid;
4747
4748 datum = ExecGetJunkAttribute(context.planSlot, node->mt_resultOidAttno,
4749 &isNull);
4750 if (isNull)
4751 {
4752 /*
4753 * For commands other than MERGE, any tuples having InvalidOid
4754 * for tableoid are errors. For MERGE, we may need to handle
4755 * them as WHEN NOT MATCHED clauses if any, so do that.
4756 *
4757 * Note that we use the node's toplevel resultRelInfo, not any
4758 * specific partition's.
4759 */
4760 if (operation == CMD_MERGE)
4761 {
4762 EvalPlanQualSetSlot(&node->mt_epqstate, context.planSlot);
4763
4764 slot = ExecMerge(&context, node->resultRelInfo,
4765 NULL, NULL, node->canSetTag);
4766
4767 /*
4768 * If we got a RETURNING result, return it to the caller.
4769 * We'll continue the work on next call.
4770 */
4771 if (slot)
4772 return slot;
4773
4774 continue; /* continue with the next tuple */
4775 }
4776
4777 elog(ERROR, "tableoid is NULL");
4778 }
4779 resultoid = DatumGetObjectId(datum);
4780
4781 /* If it's not the same as last time, we need to locate the rel */
4782 if (resultoid != node->mt_lastResultOid)
4783 resultRelInfo = ExecLookupResultRelByOid(node, resultoid,
4784 false, true);
4785 }
4786
4787 /*
4788 * If we don't have a ForPortionOfState yet, we must be a partition or
4789 * inheritance child being hit for the first time. Make a copy from
4790 * the root, with our own TupleTableSlot. We do this lazily so that we
4791 * don't pay the price of unused partitions.
4792 */
4793 if (((ModifyTable *) context.mtstate->ps.plan)->forPortionOf &&
4794 !resultRelInfo->ri_forPortionOf)
4795 ExecInitForPortionOf(context.mtstate, estate, resultRelInfo);
4796
4797 /*
4798 * If resultRelInfo->ri_usesFdwDirectModify is true, all we need to do
4799 * here is compute the RETURNING expressions.
4800 */
4801 if (resultRelInfo->ri_usesFdwDirectModify)
4802 {
4803 Assert(resultRelInfo->ri_projectReturning);
4804
4805 /*
4806 * A scan slot containing the data that was actually inserted,
4807 * updated or deleted has already been made available to
4808 * ExecProcessReturning by IterateDirectModify, so no need to
4809 * provide it here. The individual old and new slots are not
4810 * needed, since direct-modify is disabled if the RETURNING list
4811 * refers to OLD/NEW values.
4812 */
4813 Assert((resultRelInfo->ri_projectReturning->pi_state.flags & EEO_FLAG_HAS_OLD) == 0 &&
4814 (resultRelInfo->ri_projectReturning->pi_state.flags & EEO_FLAG_HAS_NEW) == 0);
4815
4816 slot = ExecProcessReturning(&context, resultRelInfo,
4818 NULL, NULL, context.planSlot);
4819
4820 return slot;
4821 }
4822
4823 EvalPlanQualSetSlot(&node->mt_epqstate, context.planSlot);
4824 slot = context.planSlot;
4825
4826 tupleid = NULL;
4827 oldtuple = NULL;
4828
4829 /*
4830 * For UPDATE/DELETE/MERGE, fetch the row identity info for the tuple
4831 * to be updated/deleted/merged. For a heap relation, that's a TID;
4832 * otherwise we may have a wholerow junk attr that carries the old
4833 * tuple in toto. Keep this in step with the part of
4834 * ExecInitModifyTable that sets up ri_RowIdAttNo.
4835 */
4838 {
4839 char relkind;
4840 Datum datum;
4841 bool isNull;
4842
4843 relkind = resultRelInfo->ri_RelationDesc->rd_rel->relkind;
4844 if (relkind == RELKIND_RELATION ||
4845 relkind == RELKIND_MATVIEW ||
4846 relkind == RELKIND_PARTITIONED_TABLE)
4847 {
4848 /*
4849 * ri_RowIdAttNo refers to a ctid attribute. See the comment
4850 * in ExecInitModifyTable().
4851 */
4853 relkind == RELKIND_PARTITIONED_TABLE);
4854 datum = ExecGetJunkAttribute(slot,
4855 resultRelInfo->ri_RowIdAttNo,
4856 &isNull);
4857
4858 /*
4859 * For commands other than MERGE, any tuples having a null row
4860 * identifier are errors. For MERGE, we may need to handle
4861 * them as WHEN NOT MATCHED clauses if any, so do that.
4862 *
4863 * Note that we use the node's toplevel resultRelInfo, not any
4864 * specific partition's.
4865 */
4866 if (isNull)
4867 {
4868 if (operation == CMD_MERGE)
4869 {
4870 EvalPlanQualSetSlot(&node->mt_epqstate, context.planSlot);
4871
4872 slot = ExecMerge(&context, node->resultRelInfo,
4873 NULL, NULL, node->canSetTag);
4874
4875 /*
4876 * If we got a RETURNING result, return it to the
4877 * caller. We'll continue the work on next call.
4878 */
4879 if (slot)
4880 return slot;
4881
4882 continue; /* continue with the next tuple */
4883 }
4884
4885 elog(ERROR, "ctid is NULL");
4886 }
4887
4889 tuple_ctid = *tupleid; /* be sure we don't free ctid!! */
4891 }
4892
4893 /*
4894 * Use the wholerow attribute, when available, to reconstruct the
4895 * old relation tuple. The old tuple serves one or both of two
4896 * purposes: 1) it serves as the OLD tuple for row triggers, 2) it
4897 * provides values for any unchanged columns for the NEW tuple of
4898 * an UPDATE, because the subplan does not produce all the columns
4899 * of the target table.
4900 *
4901 * Note that the wholerow attribute does not carry system columns,
4902 * so foreign table triggers miss seeing those, except that we
4903 * know enough here to set t_tableOid. Quite separately from
4904 * this, the FDW may fetch its own junk attrs to identify the row.
4905 *
4906 * Other relevant relkinds, currently limited to views, always
4907 * have a wholerow attribute.
4908 */
4909 else if (AttributeNumberIsValid(resultRelInfo->ri_RowIdAttNo))
4910 {
4911 datum = ExecGetJunkAttribute(slot,
4912 resultRelInfo->ri_RowIdAttNo,
4913 &isNull);
4914
4915 /*
4916 * For commands other than MERGE, any tuples having a null row
4917 * identifier are errors. For MERGE, we may need to handle
4918 * them as WHEN NOT MATCHED clauses if any, so do that.
4919 *
4920 * Note that we use the node's toplevel resultRelInfo, not any
4921 * specific partition's.
4922 */
4923 if (isNull)
4924 {
4925 if (operation == CMD_MERGE)
4926 {
4927 EvalPlanQualSetSlot(&node->mt_epqstate, context.planSlot);
4928
4929 slot = ExecMerge(&context, node->resultRelInfo,
4930 NULL, NULL, node->canSetTag);
4931
4932 /*
4933 * If we got a RETURNING result, return it to the
4934 * caller. We'll continue the work on next call.
4935 */
4936 if (slot)
4937 return slot;
4938
4939 continue; /* continue with the next tuple */
4940 }
4941
4942 elog(ERROR, "wholerow is NULL");
4943 }
4944
4945 oldtupdata.t_data = DatumGetHeapTupleHeader(datum);
4946 oldtupdata.t_len =
4949 /* Historically, view triggers see invalid t_tableOid. */
4950 oldtupdata.t_tableOid =
4951 (relkind == RELKIND_VIEW) ? InvalidOid :
4952 RelationGetRelid(resultRelInfo->ri_RelationDesc);
4953
4954 oldtuple = &oldtupdata;
4955 }
4956 else
4957 {
4958 /* Only foreign tables are allowed to omit a row-ID attr */
4959 Assert(relkind == RELKIND_FOREIGN_TABLE);
4960 }
4961 }
4962
4963 switch (operation)
4964 {
4965 case CMD_INSERT:
4966 /* Initialize projection info if first time for this table */
4967 if (unlikely(!resultRelInfo->ri_projectNewInfoValid))
4968 ExecInitInsertProjection(node, resultRelInfo);
4969 slot = ExecGetInsertNewTuple(resultRelInfo, context.planSlot);
4970 slot = ExecInsert(&context, resultRelInfo, slot,
4971 node->canSetTag, NULL, NULL);
4972 break;
4973
4974 case CMD_UPDATE:
4975 tuplock = false;
4976
4977 /* Initialize projection info if first time for this table */
4978 if (unlikely(!resultRelInfo->ri_projectNewInfoValid))
4979 ExecInitUpdateProjection(node, resultRelInfo);
4980
4981 /*
4982 * Make the new tuple by combining plan's output tuple with
4983 * the old tuple being updated.
4984 */
4985 oldSlot = resultRelInfo->ri_oldTupleSlot;
4986 if (oldtuple != NULL)
4987 {
4988 Assert(!resultRelInfo->ri_needLockTagTuple);
4989 /* Use the wholerow junk attr as the old tuple. */
4990 ExecForceStoreHeapTuple(oldtuple, oldSlot, false);
4991 }
4992 else
4993 {
4994 /* Fetch the most recent version of old tuple. */
4995 Relation relation = resultRelInfo->ri_RelationDesc;
4996
4997 if (resultRelInfo->ri_needLockTagTuple)
4998 {
5000 tuplock = true;
5001 }
5004 oldSlot))
5005 elog(ERROR, "failed to fetch tuple being updated");
5006 }
5007 slot = ExecGetUpdateNewTuple(resultRelInfo, context.planSlot,
5008 oldSlot);
5009
5010 /* Now apply the update. */
5011 slot = ExecUpdate(&context, resultRelInfo, tupleid, oldtuple,
5012 oldSlot, slot, node->canSetTag);
5013 if (tuplock)
5014 UnlockTuple(resultRelInfo->ri_RelationDesc, tupleid,
5016 break;
5017
5018 case CMD_DELETE:
5019 slot = ExecDelete(&context, resultRelInfo, tupleid, oldtuple,
5020 true, false, node->canSetTag, NULL, NULL, NULL);
5021 break;
5022
5023 case CMD_MERGE:
5024 slot = ExecMerge(&context, resultRelInfo, tupleid, oldtuple,
5025 node->canSetTag);
5026 break;
5027
5028 default:
5029 elog(ERROR, "unknown operation");
5030 break;
5031 }
5032
5033 /*
5034 * If we got a RETURNING result, return it to caller. We'll continue
5035 * the work on next call.
5036 */
5037 if (slot)
5038 return slot;
5039 }
5040
5041 /*
5042 * Insert remaining tuples for batch insert.
5043 */
5045 ExecPendingInserts(estate);
5046
5047 /*
5048 * We're done, but fire AFTER STATEMENT triggers before exiting.
5049 */
5050 fireASTriggers(node);
5051
5052 node->mt_done = true;
5053
5054 return NULL;
5055}
5056
5057/*
5058 * ExecLookupResultRelByOid
5059 * If the table with given OID is among the result relations to be
5060 * updated by the given ModifyTable node, return its ResultRelInfo.
5061 *
5062 * If not found, return NULL if missing_ok, else raise error.
5063 *
5064 * If update_cache is true, then upon successful lookup, update the node's
5065 * one-element cache. ONLY ExecModifyTable may pass true for this.
5066 */
5069 bool missing_ok, bool update_cache)
5070{
5071 if (node->mt_resultOidHash)
5072 {
5073 /* Use the pre-built hash table to locate the rel */
5075
5078 if (mtlookup)
5079 {
5080 if (update_cache)
5081 {
5083 node->mt_lastResultIndex = mtlookup->relationIndex;
5084 }
5085 return node->resultRelInfo + mtlookup->relationIndex;
5086 }
5087 }
5088 else
5089 {
5090 /* With few target rels, just search the ResultRelInfo array */
5091 for (int ndx = 0; ndx < node->mt_nrels; ndx++)
5092 {
5094
5095 if (RelationGetRelid(rInfo->ri_RelationDesc) == resultoid)
5096 {
5097 if (update_cache)
5098 {
5100 node->mt_lastResultIndex = ndx;
5101 }
5102 return rInfo;
5103 }
5104 }
5105 }
5106
5107 if (!missing_ok)
5108 elog(ERROR, "incorrect result relation OID %u", resultoid);
5109 return NULL;
5110}
5111
5112/* ----------------------------------------------------------------
5113 * ExecInitModifyTable
5114 * ----------------------------------------------------------------
5115 */
5117ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
5118{
5119 ModifyTableState *mtstate;
5120 Plan *subplan = outerPlan(node);
5121 CmdType operation = node->operation;
5123 int nrels;
5124 List *resultRelations = NIL;
5125 List *withCheckOptionLists = NIL;
5126 List *returningLists = NIL;
5127 List *updateColnosLists = NIL;
5128 List *mergeActionLists = NIL;
5129 List *mergeJoinConditions = NIL;
5130 List *fdwPrivLists = NIL;
5131 Bitmapset *fdwDirectModifyPlans = NULL;
5132 ResultRelInfo *resultRelInfo;
5133 List *arowmarks;
5134 ListCell *l;
5135 int i;
5136 Relation rel;
5137
5138 /* check for unsupported flags */
5139 Assert(!(eflags & (EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK)));
5140
5141 /*
5142 * Only consider unpruned relations for initializing their ResultRelInfo
5143 * struct and other fields such as withCheckOptions, etc.
5144 *
5145 * Note: We must avoid pruning every result relation. This is important
5146 * for MERGE, since even if every result relation is pruned from the
5147 * subplan, there might still be NOT MATCHED rows, for which there may be
5148 * INSERT actions to perform. To allow these actions to be found, at
5149 * least one result relation must be kept. Also, when inserting into a
5150 * partitioned table, ExecInitPartitionInfo() needs a ResultRelInfo struct
5151 * as a reference for building the ResultRelInfo of the target partition.
5152 * In either case, it doesn't matter which result relation is kept, so we
5153 * just keep the first one, if all others have been pruned. See also,
5154 * ExecDoInitialPruning(), which ensures that this first result relation
5155 * has been locked.
5156 */
5157 i = 0;
5158 foreach(l, node->resultRelations)
5159 {
5160 Index rti = lfirst_int(l);
5161 bool keep_rel;
5162
5164 if (!keep_rel && i == total_nrels - 1 && resultRelations == NIL)
5165 {
5166 /* all result relations pruned; keep the first one */
5167 keep_rel = true;
5168 rti = linitial_int(node->resultRelations);
5169 i = 0;
5170 }
5171
5172 if (keep_rel)
5173 {
5174 List *fdwPrivList = (List *) list_nth(node->fdwPrivLists, i);
5175
5176 resultRelations = lappend_int(resultRelations, rti);
5177 if (node->withCheckOptionLists)
5178 {
5181 i);
5182
5183 withCheckOptionLists = lappend(withCheckOptionLists, withCheckOptions);
5184 }
5185 if (node->returningLists)
5186 {
5187 List *returningList = list_nth_node(List,
5188 node->returningLists,
5189 i);
5190
5191 returningLists = lappend(returningLists, returningList);
5192 }
5193 if (node->updateColnosLists)
5194 {
5196
5197 updateColnosLists = lappend(updateColnosLists, updateColnosList);
5198 }
5199 if (node->mergeActionLists)
5200 {
5201 List *mergeActionList = list_nth(node->mergeActionLists, i);
5202
5203 mergeActionLists = lappend(mergeActionLists, mergeActionList);
5204 }
5205 if (node->mergeJoinConditions)
5206 {
5207 List *mergeJoinCondition = list_nth(node->mergeJoinConditions, i);
5208
5209 mergeJoinConditions = lappend(mergeJoinConditions, mergeJoinCondition);
5210 }
5211
5212 /*
5213 * fdwPrivLists/fdwDirectModifyPlans are re-indexed to match
5214 * resultRelations
5215 */
5216 fdwPrivLists = lappend(fdwPrivLists, fdwPrivList);
5218 {
5219 int new_index = list_length(resultRelations) - 1;
5220
5221 fdwDirectModifyPlans = bms_add_member(fdwDirectModifyPlans,
5222 new_index);
5223 }
5224 }
5225 i++;
5226 }
5227 nrels = list_length(resultRelations);
5228 Assert(nrels > 0);
5229
5230 /*
5231 * create state structure
5232 */
5233 mtstate = makeNode(ModifyTableState);
5234 mtstate->ps.plan = (Plan *) node;
5235 mtstate->ps.state = estate;
5236 mtstate->ps.ExecProcNode = ExecModifyTable;
5237
5238 mtstate->operation = operation;
5239 mtstate->canSetTag = node->canSetTag;
5240 mtstate->mt_done = false;
5241
5242 mtstate->mt_nrels = nrels;
5243 mtstate->resultRelInfo = palloc_array(ResultRelInfo, nrels);
5244
5246 mtstate->mt_merge_inserted = 0;
5247 mtstate->mt_merge_updated = 0;
5248 mtstate->mt_merge_deleted = 0;
5249 mtstate->mt_updateColnosLists = updateColnosLists;
5250 mtstate->mt_mergeActionLists = mergeActionLists;
5251 mtstate->mt_mergeJoinConditions = mergeJoinConditions;
5252 mtstate->mt_fdwPrivLists = fdwPrivLists;
5253
5254 /*----------
5255 * Resolve the target relation. This is the same as:
5256 *
5257 * - the relation for which we will fire FOR STATEMENT triggers,
5258 * - the relation into whose tuple format all captured transition tuples
5259 * must be converted, and
5260 * - the root partitioned table used for tuple routing.
5261 *
5262 * If it's a partitioned or inherited table, the root partition or
5263 * appendrel RTE doesn't appear elsewhere in the plan and its RT index is
5264 * given explicitly in node->rootRelation. Otherwise, the target relation
5265 * is the sole relation in the node->resultRelations list and, since it can
5266 * never be pruned, also in the resultRelations list constructed above.
5267 *----------
5268 */
5269 if (node->rootRelation > 0)
5270 {
5274 node->rootRelation);
5275 }
5276 else
5277 {
5278 Assert(list_length(node->resultRelations) == 1);
5279 Assert(list_length(resultRelations) == 1);
5280 mtstate->rootResultRelInfo = mtstate->resultRelInfo;
5281 ExecInitResultRelation(estate, mtstate->resultRelInfo,
5282 linitial_int(resultRelations));
5283 }
5284
5285 /* set up epqstate with dummy subplan data for the moment */
5286 EvalPlanQualInit(&mtstate->mt_epqstate, estate, NULL, NIL,
5287 node->epqParam, resultRelations);
5288 mtstate->fireBSTriggers = true;
5289
5290 /*
5291 * Build state for collecting transition tuples. This requires having a
5292 * valid trigger query context, so skip it in explain-only mode.
5293 */
5294 if (!(eflags & EXEC_FLAG_EXPLAIN_ONLY))
5295 ExecSetupTransitionCaptureState(mtstate, estate);
5296
5297 /*
5298 * Open all the result relations and initialize the ResultRelInfo structs.
5299 * (But root relation was initialized above, if it's part of the array.)
5300 * We must do this before initializing the subplan, because direct-modify
5301 * FDWs expect their ResultRelInfos to be available.
5302 */
5303 resultRelInfo = mtstate->resultRelInfo;
5304 i = 0;
5305 foreach(l, resultRelations)
5306 {
5307 Index resultRelation = lfirst_int(l);
5309
5310 if (mergeActionLists)
5311 mergeActions = list_nth(mergeActionLists, i);
5312
5313 if (resultRelInfo != mtstate->rootResultRelInfo)
5314 {
5315 ExecInitResultRelation(estate, resultRelInfo, resultRelation);
5316
5317 /*
5318 * For child result relations, store the root result relation
5319 * pointer. We do so for the convenience of places that want to
5320 * look at the query's original target relation but don't have the
5321 * mtstate handy.
5322 */
5323 resultRelInfo->ri_RootResultRelInfo = mtstate->rootResultRelInfo;
5324 }
5325
5326 /* Initialize the usesFdwDirectModify flag */
5327 resultRelInfo->ri_usesFdwDirectModify =
5328 bms_is_member(i, fdwDirectModifyPlans);
5329
5330 /*
5331 * Verify result relation is a valid target for the current operation
5332 */
5333 CheckValidResultRel(resultRelInfo, operation, node->onConflictAction,
5334 mergeActions, node);
5335
5336 resultRelInfo++;
5337 i++;
5338 }
5339
5340 /*
5341 * Now we may initialize the subplan.
5342 */
5343 outerPlanState(mtstate) = ExecInitNode(subplan, estate, eflags);
5344
5345 /*
5346 * Do additional per-result-relation initialization.
5347 */
5348 for (i = 0; i < nrels; i++)
5349 {
5350 resultRelInfo = &mtstate->resultRelInfo[i];
5351
5352 /* Let FDWs init themselves for foreign-table result rels */
5353 if (!resultRelInfo->ri_usesFdwDirectModify &&
5354 resultRelInfo->ri_FdwRoutine != NULL &&
5355 resultRelInfo->ri_FdwRoutine->BeginForeignModify != NULL)
5356 {
5357 List *fdw_private = (List *) list_nth(fdwPrivLists, i);
5358
5359 resultRelInfo->ri_FdwRoutine->BeginForeignModify(mtstate,
5360 resultRelInfo,
5361 fdw_private,
5362 i,
5363 eflags);
5364 }
5365
5366 /*
5367 * For UPDATE/DELETE/MERGE, find the appropriate junk attr now, either
5368 * a 'ctid' or 'wholerow' attribute depending on relkind. For foreign
5369 * tables, the FDW might have created additional junk attr(s), but
5370 * those are no concern of ours.
5371 */
5374 {
5375 char relkind;
5376
5377 relkind = resultRelInfo->ri_RelationDesc->rd_rel->relkind;
5378 if (relkind == RELKIND_RELATION ||
5379 relkind == RELKIND_MATVIEW ||
5380 relkind == RELKIND_PARTITIONED_TABLE)
5381 {
5382 resultRelInfo->ri_RowIdAttNo =
5383 ExecFindJunkAttributeInTlist(subplan->targetlist, "ctid");
5384
5385 /*
5386 * For heap relations, a ctid junk attribute must be present.
5387 * Partitioned tables should only appear here when all leaf
5388 * partitions were pruned, in which case no rows can be
5389 * produced and ctid is not needed.
5390 */
5391 if (relkind == RELKIND_PARTITIONED_TABLE)
5392 Assert(nrels == 1);
5393 else if (!AttributeNumberIsValid(resultRelInfo->ri_RowIdAttNo))
5394 elog(ERROR, "could not find junk ctid column");
5395 }
5396 else if (relkind == RELKIND_FOREIGN_TABLE)
5397 {
5398 /*
5399 * We don't support MERGE with foreign tables for now. (It's
5400 * problematic because the implementation uses CTID.)
5401 */
5403
5404 /*
5405 * When there is a row-level trigger, there should be a
5406 * wholerow attribute. We also require it to be present in
5407 * UPDATE and MERGE, so we can get the values of unchanged
5408 * columns.
5409 */
5410 resultRelInfo->ri_RowIdAttNo =
5412 "wholerow");
5413 if ((mtstate->operation == CMD_UPDATE || mtstate->operation == CMD_MERGE) &&
5414 !AttributeNumberIsValid(resultRelInfo->ri_RowIdAttNo))
5415 elog(ERROR, "could not find junk wholerow column");
5416 }
5417 else
5418 {
5419 /* Other valid target relkinds must provide wholerow */
5420 resultRelInfo->ri_RowIdAttNo =
5422 "wholerow");
5423 if (!AttributeNumberIsValid(resultRelInfo->ri_RowIdAttNo))
5424 elog(ERROR, "could not find junk wholerow column");
5425 }
5426 }
5427 }
5428
5429 /*
5430 * If this is an inherited update/delete/merge, there will be a junk
5431 * attribute named "tableoid" present in the subplan's targetlist. It
5432 * will be used to identify the result relation for a given tuple to be
5433 * updated/deleted/merged.
5434 */
5435 mtstate->mt_resultOidAttno =
5436 ExecFindJunkAttributeInTlist(subplan->targetlist, "tableoid");
5438 mtstate->mt_lastResultOid = InvalidOid; /* force lookup at first tuple */
5439 mtstate->mt_lastResultIndex = 0; /* must be zero if no such attr */
5440
5441 /* Get the root target relation */
5442 rel = mtstate->rootResultRelInfo->ri_RelationDesc;
5443
5444 /*
5445 * Build state for tuple routing if it's a partitioned INSERT. An UPDATE
5446 * or MERGE might need this too, but only if it actually moves tuples
5447 * between partitions; in that case setup is done by
5448 * ExecCrossPartitionUpdate.
5449 */
5450 if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE &&
5453 ExecSetupPartitionTupleRouting(estate, rel);
5454
5455 /*
5456 * Initialize any WITH CHECK OPTION constraints if needed.
5457 */
5458 resultRelInfo = mtstate->resultRelInfo;
5459 foreach(l, withCheckOptionLists)
5460 {
5461 List *wcoList = (List *) lfirst(l);
5462 List *wcoExprs = NIL;
5463 ListCell *ll;
5464
5465 foreach(ll, wcoList)
5466 {
5468 ExprState *wcoExpr = ExecInitQual((List *) wco->qual,
5469 &mtstate->ps);
5470
5472 }
5473
5474 resultRelInfo->ri_WithCheckOptions = wcoList;
5475 resultRelInfo->ri_WithCheckOptionExprs = wcoExprs;
5476 resultRelInfo++;
5477 }
5478
5479 /*
5480 * Initialize RETURNING projections if needed.
5481 */
5482 if (returningLists)
5483 {
5484 TupleTableSlot *slot;
5485 ExprContext *econtext;
5486
5487 /*
5488 * Initialize result tuple slot and assign its rowtype using the plan
5489 * node's declared targetlist, which the planner set up to be the same
5490 * as the first (before runtime pruning) RETURNING list. We assume
5491 * all the result rels will produce compatible output.
5492 */
5494 slot = mtstate->ps.ps_ResultTupleSlot;
5495
5496 /* Need an econtext too */
5497 if (mtstate->ps.ps_ExprContext == NULL)
5498 ExecAssignExprContext(estate, &mtstate->ps);
5499 econtext = mtstate->ps.ps_ExprContext;
5500
5501 /*
5502 * Build a projection for each result rel.
5503 */
5504 resultRelInfo = mtstate->resultRelInfo;
5505 foreach(l, returningLists)
5506 {
5507 List *rlist = (List *) lfirst(l);
5508
5509 resultRelInfo->ri_returningList = rlist;
5510 resultRelInfo->ri_projectReturning =
5511 ExecBuildProjectionInfo(rlist, econtext, slot, &mtstate->ps,
5512 resultRelInfo->ri_RelationDesc->rd_att);
5513 resultRelInfo++;
5514 }
5515 }
5516 else
5517 {
5518 /*
5519 * We still must construct a dummy result tuple type, because InitPlan
5520 * expects one (maybe should change that?).
5521 */
5522 ExecInitResultTypeTL(&mtstate->ps);
5523
5524 mtstate->ps.ps_ExprContext = NULL;
5525 }
5526
5527 /* Set the list of arbiter indexes if needed for ON CONFLICT */
5528 resultRelInfo = mtstate->resultRelInfo;
5529 if (node->onConflictAction != ONCONFLICT_NONE)
5530 {
5531 /* insert may only have one relation, inheritance is not expanded */
5532 Assert(total_nrels == 1);
5533 resultRelInfo->ri_onConflictArbiterIndexes = node->arbiterIndexes;
5534 }
5535
5536 /*
5537 * For ON CONFLICT DO SELECT/UPDATE, initialize the ON CONFLICT action
5538 * state.
5539 */
5540 if (node->onConflictAction == ONCONFLICT_UPDATE ||
5542 {
5544
5545 /* already exists if created by RETURNING processing above */
5546 if (mtstate->ps.ps_ExprContext == NULL)
5547 ExecAssignExprContext(estate, &mtstate->ps);
5548
5549 /* action state for DO SELECT/UPDATE */
5550 resultRelInfo->ri_onConflict = onconfl;
5551
5552 /* lock strength for DO SELECT [FOR UPDATE/SHARE] */
5554
5555 /* initialize slot for the existing tuple */
5556 onconfl->oc_Existing =
5557 table_slot_create(resultRelInfo->ri_RelationDesc,
5558 &mtstate->ps.state->es_tupleTable);
5559
5560 /*
5561 * For ON CONFLICT DO UPDATE, initialize target list and projection.
5562 */
5564 {
5565 ExprContext *econtext;
5567
5568 econtext = mtstate->ps.ps_ExprContext;
5569 relationDesc = resultRelInfo->ri_RelationDesc->rd_att;
5570
5571 /*
5572 * Create the tuple slot for the UPDATE SET projection. We want a
5573 * slot of the table's type here, because the slot will be used to
5574 * insert into the table, and for RETURNING processing - which may
5575 * access system attributes.
5576 */
5577 onconfl->oc_ProjSlot =
5578 table_slot_create(resultRelInfo->ri_RelationDesc,
5579 &mtstate->ps.state->es_tupleTable);
5580
5581 /* build UPDATE SET projection state */
5582 onconfl->oc_ProjInfo =
5584 true,
5585 node->onConflictCols,
5587 econtext,
5588 onconfl->oc_ProjSlot,
5589 &mtstate->ps);
5590 }
5591
5592 /* initialize state to evaluate the WHERE clause, if any */
5593 if (node->onConflictWhere)
5594 {
5595 ExprState *qualexpr;
5596
5597 qualexpr = ExecInitQual((List *) node->onConflictWhere,
5598 &mtstate->ps);
5599 onconfl->oc_WhereClause = qualexpr;
5600 }
5601 }
5602
5603 /*
5604 * If needed, initialize the target range for FOR PORTION OF.
5605 */
5606 if (node->forPortionOf)
5607 {
5609 TupleDesc tupDesc;
5610 ForPortionOfExpr *forPortionOf;
5611 Datum targetRange;
5612 bool isNull;
5613 ExprContext *econtext;
5616
5617 rootRelInfo = mtstate->resultRelInfo;
5618 if (rootRelInfo->ri_RootResultRelInfo)
5620
5621 tupDesc = rootRelInfo->ri_RelationDesc->rd_att;
5622 forPortionOf = (ForPortionOfExpr *) node->forPortionOf;
5623
5624 /* Eval the FOR PORTION OF target */
5625 if (mtstate->ps.ps_ExprContext == NULL)
5626 ExecAssignExprContext(estate, &mtstate->ps);
5627 econtext = mtstate->ps.ps_ExprContext;
5628
5629 exprState = ExecPrepareExpr((Expr *) forPortionOf->targetRange, estate);
5630 targetRange = ExecEvalExpr(exprState, econtext, &isNull);
5631
5632 /*
5633 * FOR PORTION OF ... TO ... FROM should never give us a NULL target,
5634 * but FOR PORTION OF (...) could.
5635 */
5636 if (isNull)
5637 ereport(ERROR,
5638 (errmsg("FOR PORTION OF target was null")),
5639 executor_errposition(estate, forPortionOf->targetLocation));
5640
5641 /* Create state for FOR PORTION OF operation */
5642
5644 fpoState->fp_rangeName = forPortionOf->range_name;
5645 fpoState->fp_rangeType = forPortionOf->rangeType;
5646 fpoState->fp_rangeAttno = forPortionOf->rangeVar->varattno;
5647 fpoState->fp_targetRange = targetRange;
5648
5649 /* Initialize slot for the existing tuple */
5650
5651 fpoState->fp_Existing =
5652 table_slot_create(rootRelInfo->ri_RelationDesc,
5653 &mtstate->ps.state->es_tupleTable);
5654
5655 /* Create the tuple slot for INSERTing the temporal leftovers */
5656
5657 fpoState->fp_Leftover =
5658 ExecInitExtraTupleSlot(mtstate->ps.state, tupDesc, &TTSOpsVirtual);
5659
5660 rootRelInfo->ri_forPortionOf = fpoState;
5661
5662 /*
5663 * Make sure the root relation has the FOR PORTION OF clause too. Each
5664 * partition needs its own TupleTableSlot, since they can have
5665 * different descriptors, so they'll use the root fpoState to
5666 * initialize one if necessary.
5667 */
5668 if (node->rootRelation > 0)
5670
5671 if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE &&
5672 mtstate->mt_partition_tuple_routing == NULL)
5673 {
5674 /*
5675 * We will need tuple routing to insert temporal leftovers. Since
5676 * we are initializing things before ExecCrossPartitionUpdate
5677 * runs, we must do everything it needs as well.
5678 */
5681
5682 /* Things built here have to last for the query duration. */
5684
5687
5688 /*
5689 * Before a partition's tuple can be re-routed, it must first be
5690 * converted to the root's format, so we'll need a slot for
5691 * storing such tuples.
5692 */
5693 Assert(mtstate->mt_root_tuple_slot == NULL);
5695
5697 }
5698
5699 /*
5700 * Don't free the ExprContext here because the result must last for
5701 * the whole query.
5702 */
5703 }
5704
5705 /*
5706 * If we have any secondary relations in an UPDATE or DELETE, they need to
5707 * be treated like non-locked relations in SELECT FOR UPDATE, i.e., the
5708 * EvalPlanQual mechanism needs to be told about them. This also goes for
5709 * the source relations in a MERGE. Locate the relevant ExecRowMarks.
5710 */
5711 arowmarks = NIL;
5712 foreach(l, node->rowMarks)
5713 {
5715 RangeTblEntry *rte = exec_rt_fetch(rc->rti, estate);
5718
5719 /* ignore "parent" rowmarks; they are irrelevant at runtime */
5720 if (rc->isParent)
5721 continue;
5722
5723 /*
5724 * Also ignore rowmarks belonging to child tables that have been
5725 * pruned in ExecDoInitialPruning().
5726 */
5727 if (rte->rtekind == RTE_RELATION &&
5728 !bms_is_member(rc->rti, estate->es_unpruned_relids))
5729 continue;
5730
5731 /* Find ExecRowMark and build ExecAuxRowMark */
5732 erm = ExecFindRowMark(estate, rc->rti, false);
5735 }
5736
5737 /* For a MERGE command, initialize its state */
5738 if (mtstate->operation == CMD_MERGE)
5739 ExecInitMerge(mtstate, estate);
5740
5741 EvalPlanQualSetPlan(&mtstate->mt_epqstate, subplan, arowmarks);
5742
5743 /*
5744 * If there are a lot of result relations, use a hash table to speed the
5745 * lookups. If there are not a lot, a simple linear search is faster.
5746 *
5747 * It's not clear where the threshold is, but try 64 for starters. In a
5748 * debugging build, use a small threshold so that we get some test
5749 * coverage of both code paths.
5750 */
5751#ifdef USE_ASSERT_CHECKING
5752#define MT_NRELS_HASH 4
5753#else
5754#define MT_NRELS_HASH 64
5755#endif
5756 if (nrels >= MT_NRELS_HASH)
5757 {
5759
5760 hash_ctl.keysize = sizeof(Oid);
5761 hash_ctl.entrysize = sizeof(MTTargetRelLookup);
5763 mtstate->mt_resultOidHash =
5764 hash_create("ModifyTable target hash",
5765 nrels, &hash_ctl,
5767 for (i = 0; i < nrels; i++)
5768 {
5769 Oid hashkey;
5771 bool found;
5772
5773 resultRelInfo = &mtstate->resultRelInfo[i];
5774 hashkey = RelationGetRelid(resultRelInfo->ri_RelationDesc);
5777 HASH_ENTER, &found);
5778 Assert(!found);
5779 mtlookup->relationIndex = i;
5780 }
5781 }
5782 else
5783 mtstate->mt_resultOidHash = NULL;
5784
5785 /*
5786 * Determine if the FDW supports batch insert and determine the batch size
5787 * (a FDW may support batching, but it may be disabled for the
5788 * server/table).
5789 *
5790 * We only do this for INSERT, so that for UPDATE/DELETE the batch size
5791 * remains set to 0.
5792 */
5793 if (operation == CMD_INSERT)
5794 {
5795 /* insert may only have one relation, inheritance is not expanded */
5796 Assert(total_nrels == 1);
5797 resultRelInfo = mtstate->resultRelInfo;
5798 if (!resultRelInfo->ri_usesFdwDirectModify &&
5799 resultRelInfo->ri_FdwRoutine != NULL &&
5800 resultRelInfo->ri_FdwRoutine->GetForeignModifyBatchSize &&
5801 resultRelInfo->ri_FdwRoutine->ExecForeignBatchInsert)
5802 {
5803 resultRelInfo->ri_BatchSize =
5804 resultRelInfo->ri_FdwRoutine->GetForeignModifyBatchSize(resultRelInfo);
5805 Assert(resultRelInfo->ri_BatchSize >= 1);
5806 }
5807 else
5808 resultRelInfo->ri_BatchSize = 1;
5809 }
5810
5811 /*
5812 * Lastly, if this is not the primary (canSetTag) ModifyTable node, add it
5813 * to estate->es_auxmodifytables so that it will be run to completion by
5814 * ExecPostprocessPlan. (It'd actually work fine to add the primary
5815 * ModifyTable node too, but there's no need.) Note the use of lcons not
5816 * lappend: we need later-initialized ModifyTable nodes to be shut down
5817 * before earlier ones. This ensures that we don't throw away RETURNING
5818 * rows that need to be seen by a later CTE subplan.
5819 */
5820 if (!mtstate->canSetTag)
5821 estate->es_auxmodifytables = lcons(mtstate,
5822 estate->es_auxmodifytables);
5823
5824 return mtstate;
5825}
5826
5827/* ----------------------------------------------------------------
5828 * ExecEndModifyTable
5829 *
5830 * Shuts down the plan.
5831 *
5832 * Returns nothing of interest.
5833 * ----------------------------------------------------------------
5834 */
5835void
5837{
5838 int i;
5839
5840 /*
5841 * Allow any FDWs to shut down
5842 */
5843 for (i = 0; i < node->mt_nrels; i++)
5844 {
5845 int j;
5846 ResultRelInfo *resultRelInfo = node->resultRelInfo + i;
5847
5848 if (!resultRelInfo->ri_usesFdwDirectModify &&
5849 resultRelInfo->ri_FdwRoutine != NULL &&
5850 resultRelInfo->ri_FdwRoutine->EndForeignModify != NULL)
5851 resultRelInfo->ri_FdwRoutine->EndForeignModify(node->ps.state,
5852 resultRelInfo);
5853
5854 /*
5855 * Cleanup the initialized batch slots. This only matters for FDWs
5856 * with batching, but the other cases will have ri_NumSlotsInitialized
5857 * == 0.
5858 */
5859 for (j = 0; j < resultRelInfo->ri_NumSlotsInitialized; j++)
5860 {
5861 ExecDropSingleTupleTableSlot(resultRelInfo->ri_Slots[j]);
5863 }
5864 }
5865
5866 /*
5867 * Close all the partitioned tables, leaf partitions, and their indices
5868 * and release the slot used for tuple routing, if set.
5869 */
5871 {
5873
5874 if (node->mt_root_tuple_slot)
5876 }
5877
5878 /*
5879 * Terminate EPQ execution if active
5880 */
5882
5883 /*
5884 * shut down subplan
5885 */
5887}
5888
5889void
5891{
5892 /*
5893 * Currently, we don't need to support rescan on ModifyTable nodes. The
5894 * semantics of that would be a bit debatable anyway.
5895 */
5896 elog(ERROR, "ExecReScanModifyTable is not implemented");
5897}
5898
5899/* ----------------------------------------------------------------
5900 * ExecInitForPortionOf
5901 *
5902 * Initializes resultRelInfo->ri_forPortionOf for child tables.
5903 *
5904 * Partitions share the root leftover slot, since they must insert via
5905 * the root relation to get tuple routing. Plain inheritance children
5906 * must keep their own leftover slot and insert back into the child, or
5907 * else child-only column values and physical placement would be lost.
5908 * ----------------------------------------------------------------
5909 */
5910static void
5912 ResultRelInfo *resultRelInfo)
5913{
5918 TupleConversionMap *map;
5919
5920 if (!rootRelInfo)
5921 elog(ERROR, "no root relation but ri_forPortionOf is uninitialized");
5922
5923 fpoState = rootRelInfo->ri_forPortionOf;
5925
5926 /* Things built here have to last for the query duration. */
5928
5930
5931 leafState->fp_rangeName = fpoState->fp_rangeName;
5932 leafState->fp_rangeType = fpoState->fp_rangeType;
5933 leafState->fp_targetRange = fpoState->fp_targetRange;
5934 map = ExecGetChildToRootMap(resultRelInfo);
5935
5936 /*
5937 * fp_rangeAttno must match the tuple layout used for reading the old
5938 * range value. The query uses the target relation's attno, so translate
5939 * it to the child attno when the child has a different column layout.
5940 */
5941 if (map)
5942 leafState->fp_rangeAttno = map->attrMap->attnums[fpoState->fp_rangeAttno - 1];
5943 else
5944 leafState->fp_rangeAttno = fpoState->fp_rangeAttno;
5945
5946 /*
5947 * For partitioned tables we must read the leftovers using the child
5948 * table's tuple descriptor, but then insert them into the root table
5949 * (using its tuple descriptor) so we get tuple routing.
5950 *
5951 * For traditional table inheritance, we read and insert directly into
5952 * this resultRelInfo; no tuple routing via the parent is required.
5953 */
5954 if (rootRelInfo->ri_RelationDesc->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
5955 leafState->fp_Leftover = fpoState->fp_Leftover;
5956 else
5957 leafState->fp_Leftover =
5959 RelationGetDescr(resultRelInfo->ri_RelationDesc),
5960 &TTSOpsVirtual);
5961
5962 /* Each child relation needs a slot matching its tuple descriptor. */
5963 leafState->fp_Existing =
5964 table_slot_create(resultRelInfo->ri_RelationDesc,
5965 &mtstate->ps.state->es_tupleTable);
5966
5967 resultRelInfo->ri_forPortionOf = leafState;
5968
5970}
AttrMap * build_attrmap_by_name(TupleDesc indesc, TupleDesc outdesc, bool missing_ok)
Definition attmap.c:175
#define AttributeNumberIsValid(attributeNumber)
Definition attnum.h:34
bool bms_is_member(int x, const Bitmapset *a)
Definition bitmapset.c:645
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition bitmapset.c:934
bool bms_overlap(const Bitmapset *a, const Bitmapset *b)
Definition bitmapset.c:710
static Datum values[MAXATTR]
Definition bootstrap.c:190
#define Assert(condition)
Definition c.h:1002
#define unlikely(x)
Definition c.h:497
uint32_t uint32
Definition c.h:683
unsigned int Index
Definition c.h:757
uint32 TransactionId
Definition c.h:795
uint32 result
memcpy(sums, checksumBaseOffsets, sizeof(checksumBaseOffsets))
static DataChecksumsWorkerOperation operation
Datum datumCopy(Datum value, bool typByVal, int typLen)
Definition datum.c:132
void domain_check(Datum value, bool isnull, Oid domainType, void **extra, MemoryContext mcxt)
Definition domains.c:346
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition dynahash.c:889
HTAB * hash_create(const char *tabname, int64 nelem, const HASHCTL *info, int flags)
Definition dynahash.c:360
int errcode(int sqlerrcode)
Definition elog.c:875
int errhint(const char *fmt,...) pg_attribute_printf(1
int errdetail(const char *fmt,...) pg_attribute_printf(1
#define ERROR
Definition elog.h:40
#define elog(elevel,...)
Definition elog.h:228
#define ereport(elevel,...)
Definition elog.h:152
ExprState * ExecPrepareExpr(Expr *node, EState *estate)
Definition execExpr.c:765
ProjectionInfo * ExecBuildProjectionInfo(List *targetList, ExprContext *econtext, TupleTableSlot *slot, PlanState *parent, TupleDesc inputDesc)
Definition execExpr.c:370
ExprState * ExecInitQual(List *qual, PlanState *parent)
Definition execExpr.c:229
ProjectionInfo * ExecBuildUpdateProjection(List *targetList, bool evalTargetList, List *targetColnos, TupleDesc relDesc, ExprContext *econtext, TupleTableSlot *slot, PlanState *parent)
Definition execExpr.c:547
List * ExecInsertIndexTuples(ResultRelInfo *resultRelInfo, EState *estate, uint32 flags, TupleTableSlot *slot, List *arbiterIndexes, bool *specConflict)
void ExecOpenIndices(ResultRelInfo *resultRelInfo, bool speculative)
bool ExecCheckIndexConstraints(ResultRelInfo *resultRelInfo, TupleTableSlot *slot, EState *estate, ItemPointer conflictTid, const ItemPointerData *tupleid, List *arbiterIndexes)
AttrNumber ExecFindJunkAttributeInTlist(List *targetlist, const char *attrName)
Definition execJunk.c:222
LockTupleMode ExecUpdateLockMode(EState *estate, ResultRelInfo *relinfo)
Definition execMain.c:2596
ExecRowMark * ExecFindRowMark(EState *estate, Index rti, bool missing_ok)
Definition execMain.c:2622
ExecAuxRowMark * ExecBuildAuxRowMark(ExecRowMark *erm, List *targetlist)
Definition execMain.c:2645
TupleTableSlot * EvalPlanQualSlot(EPQState *epqstate, Relation relation, Index rti)
Definition execMain.c:2842
void EvalPlanQualBegin(EPQState *epqstate)
Definition execMain.c:2997
bool ExecPartitionCheck(ResultRelInfo *resultRelInfo, TupleTableSlot *slot, EState *estate, bool emitError)
Definition execMain.c:1922
void CheckValidResultRel(ResultRelInfo *resultRelInfo, CmdType operation, OnConflictAction onConflictAction, List *mergeActions, ModifyTable *mtnode)
Definition execMain.c:1065
void EvalPlanQualInit(EPQState *epqstate, EState *parentestate, Plan *subplan, List *auxrowmarks, int epqParam, List *resultRelations)
Definition execMain.c:2784
void ExecWithCheckOptions(WCOKind kind, ResultRelInfo *resultRelInfo, TupleTableSlot *slot, EState *estate)
Definition execMain.c:2294
void EvalPlanQualEnd(EPQState *epqstate)
Definition execMain.c:3245
void EvalPlanQualSetPlan(EPQState *epqstate, Plan *subplan, List *auxrowmarks)
Definition execMain.c:2825
TupleTableSlot * EvalPlanQual(EPQState *epqstate, Relation relation, Index rti, TupleTableSlot *inputslot)
Definition execMain.c:2715
void ExecPartitionCheckEmitError(ResultRelInfo *resultRelInfo, TupleTableSlot *slot, EState *estate)
Definition execMain.c:1975
void ExecConstraints(ResultRelInfo *resultRelInfo, TupleTableSlot *slot, EState *estate)
Definition execMain.c:2046
List * ExecGetAncestorResultRels(EState *estate, ResultRelInfo *resultRelInfo)
Definition execMain.c:1496
PartitionTupleRouting * ExecSetupPartitionTupleRouting(EState *estate, Relation rel)
ResultRelInfo * ExecFindPartition(ModifyTableState *mtstate, ResultRelInfo *rootResultRelInfo, PartitionTupleRouting *proute, TupleTableSlot *slot, EState *estate)
void ExecCleanupTupleRouting(ModifyTableState *mtstate, PartitionTupleRouting *proute)
void ExecEndNode(PlanState *node)
PlanState * ExecInitNode(Plan *node, EState *estate, int eflags)
TupleTableSlot * MakeSingleTupleTableSlot(TupleDesc tupdesc, const TupleTableSlotOps *tts_ops)
const TupleTableSlotOps TTSOpsVirtual
Definition execTuples.c:84
void ExecDropSingleTupleTableSlot(TupleTableSlot *slot)
TupleTableSlot * ExecStoreVirtualTuple(TupleTableSlot *slot)
void ExecInitResultTypeTL(PlanState *planstate)
HeapTuple ExecFetchSlotHeapTuple(TupleTableSlot *slot, bool materialize, bool *shouldFree)
TupleTableSlot * ExecInitExtraTupleSlot(EState *estate, TupleDesc tupledesc, const TupleTableSlotOps *tts_ops)
void ExecInitResultTupleSlotTL(PlanState *planstate, const TupleTableSlotOps *tts_ops)
TupleTableSlot * ExecStoreAllNullTuple(TupleTableSlot *slot)
void ExecForceStoreHeapTuple(HeapTuple tuple, TupleTableSlot *slot, bool shouldFree)
TupleConversionMap * ExecGetRootToChildMap(ResultRelInfo *resultRelInfo, EState *estate)
Definition execUtils.c:1352
TupleConversionMap * ExecGetChildToRootMap(ResultRelInfo *resultRelInfo)
Definition execUtils.c:1326
int executor_errposition(EState *estate, int location)
Definition execUtils.c:962
Bitmapset * ExecGetUpdatedCols(ResultRelInfo *relinfo, EState *estate)
Definition execUtils.c:1408
void ExecInitResultRelation(EState *estate, ResultRelInfo *resultRelInfo, Index rti)
Definition execUtils.c:906
void ExecAssignExprContext(EState *estate, PlanState *planstate)
Definition execUtils.c:490
TupleTableSlot * ExecGetAllNullSlot(EState *estate, ResultRelInfo *relInfo)
Definition execUtils.c:1299
TupleTableSlot * ExecGetReturningSlot(EState *estate, ResultRelInfo *relInfo)
Definition execUtils.c:1274
#define MERGE_UPDATE
Definition execnodes.h:1433
#define InstrCountFiltered1(node, delta)
Definition execnodes.h:1308
#define EEO_FLAG_HAS_OLD
Definition execnodes.h:90
#define outerPlanState(node)
Definition execnodes.h:1300
#define InstrCountTuples2(node, delta)
Definition execnodes.h:1303
#define MERGE_INSERT
Definition execnodes.h:1432
#define EEO_FLAG_NEW_IS_NULL
Definition execnodes.h:96
@ ExprSingleResult
Definition execnodes.h:341
@ ExprMultipleResult
Definition execnodes.h:342
@ ExprEndResult
Definition execnodes.h:343
#define EEO_FLAG_OLD_IS_NULL
Definition execnodes.h:94
#define EEO_FLAG_HAS_NEW
Definition execnodes.h:92
@ SFRM_ValuePerCall
Definition execnodes.h:354
#define MERGE_DELETE
Definition execnodes.h:1434
#define EXEC_FLAG_BACKWARD
Definition executor.h:70
#define ResetPerTupleExprContext(estate)
Definition executor.h:674
static TupleTableSlot * ExecProject(ProjectionInfo *projInfo)
Definition executor.h:491
#define GetPerTupleExprContext(estate)
Definition executor.h:665
#define EIIT_IS_UPDATE
Definition executor.h:755
static RangeTblEntry * exec_rt_fetch(Index rti, EState *estate)
Definition executor.h:708
#define ResetExprContext(econtext)
Definition executor.h:659
#define GetPerTupleMemoryContext(estate)
Definition executor.h:670
#define EIIT_ONLY_SUMMARIZING
Definition executor.h:757
static bool ExecQual(ExprState *state, ExprContext *econtext)
Definition executor.h:527
static TupleTableSlot * ExecProcNode(PlanState *node)
Definition executor.h:322
#define EvalPlanQualSetSlot(epqstate, slot)
Definition executor.h:290
static Datum ExecEvalExpr(ExprState *state, ExprContext *econtext, bool *isNull)
Definition executor.h:401
#define EXEC_FLAG_EXPLAIN_ONLY
Definition executor.h:67
static Datum ExecGetJunkAttribute(TupleTableSlot *slot, AttrNumber attno, bool *isNull)
Definition executor.h:226
#define EXEC_FLAG_MARK
Definition executor.h:71
#define EIIT_NO_DUPE_ERROR
Definition executor.h:756
#define palloc_array(type, count)
Definition fe_memutils.h:91
void fmgr_info(Oid functionId, FmgrInfo *finfo)
Definition fmgr.c:129
#define DatumGetHeapTupleHeader(X)
Definition fmgr.h:296
#define InitFunctionCallInfoData(Fcinfo, Flinfo, Nargs, Collation, Context, Resultinfo)
Definition fmgr.h:150
#define LOCAL_FCINFO(name, nargs)
Definition fmgr.h:110
#define FunctionCallInvoke(fcinfo)
Definition fmgr.h:172
char * format_type_be(Oid type_oid)
void heap_freetuple(HeapTuple htup)
Definition heaptuple.c:1372
@ HASH_FIND
Definition hsearch.h:108
@ HASH_ENTER
Definition hsearch.h:109
#define HASH_CONTEXT
Definition hsearch.h:97
#define HASH_ELEM
Definition hsearch.h:90
#define HASH_BLOBS
Definition hsearch.h:92
static uint32 HeapTupleHeaderGetDatumLength(const HeapTupleHeaderData *tup)
long val
Definition informix.c:689
#define INJECTION_POINT(name, arg)
void InstrUpdateTupleCount(NodeInstrumentation *instr, double nTuples)
Definition instrument.c:196
int j
Definition isn.c:78
int i
Definition isn.c:77
static void ItemPointerSetInvalid(ItemPointerData *pointer)
Definition itemptr.h:184
static bool ItemPointerIndicatesMovedPartitions(const ItemPointerData *pointer)
Definition itemptr.h:197
ItemPointerData * ItemPointer
Definition itemptr.h:49
static void ItemPointerCopy(const ItemPointerData *fromPointer, ItemPointerData *toPointer)
Definition itemptr.h:172
static bool ItemPointerIsValid(const ItemPointerData *pointer)
Definition itemptr.h:83
List * lappend(List *list, void *datum)
Definition list.c:339
List * lappend_int(List *list, int datum)
Definition list.c:357
List * lcons(void *datum, List *list)
Definition list.c:495
bool list_member_ptr(const List *list, const void *datum)
Definition list.c:682
void list_free(List *list)
Definition list.c:1546
void UnlockTuple(Relation relation, const ItemPointerData *tid, LOCKMODE lockmode)
Definition lmgr.c:601
uint32 SpeculativeInsertionLockAcquire(TransactionId xid)
Definition lmgr.c:786
void SpeculativeInsertionLockRelease(TransactionId xid)
Definition lmgr.c:812
void LockTuple(Relation relation, const ItemPointerData *tid, LOCKMODE lockmode)
Definition lmgr.c:562
#define InplaceUpdateTupleLock
Definition lockdefs.h:48
@ LockWaitBlock
Definition lockoptions.h:40
LockTupleMode
Definition lockoptions.h:51
@ LockTupleExclusive
Definition lockoptions.h:59
@ LockTupleNoKeyExclusive
Definition lockoptions.h:57
@ LockTupleShare
Definition lockoptions.h:55
@ LockTupleKeyShare
Definition lockoptions.h:53
LockClauseStrength
Definition lockoptions.h:22
@ LCS_FORUPDATE
Definition lockoptions.h:28
@ LCS_NONE
Definition lockoptions.h:23
@ LCS_FORSHARE
Definition lockoptions.h:26
@ LCS_FORKEYSHARE
Definition lockoptions.h:25
@ LCS_FORNOKEYUPDATE
Definition lockoptions.h:27
void pfree(void *pointer)
Definition mcxt.c:1619
void * palloc0(Size size)
Definition mcxt.c:1420
MemoryContext CurrentMemoryContext
Definition mcxt.c:161
#define IsBootstrapProcessingMode()
Definition miscadmin.h:486
#define CHECK_FOR_INTERRUPTS()
Definition miscadmin.h:125
Oid exprType(const Node *expr)
Definition nodeFuncs.c:42
static bool ExecOnConflictSelect(ModifyTableContext *context, ResultRelInfo *resultRelInfo, ItemPointer conflictTid, TupleTableSlot *excludedSlot, bool canSetTag, TupleTableSlot **returning)
static void ExecInitInsertProjection(ModifyTableState *mtstate, ResultRelInfo *resultRelInfo)
ResultRelInfo * ExecLookupResultRelByOid(ModifyTableState *node, Oid resultoid, bool missing_ok, bool update_cache)
static void ExecPendingInserts(EState *estate)
static void ExecSetupTransitionCaptureState(ModifyTableState *mtstate, EState *estate)
static void ExecForPortionOfLeftovers(ModifyTableContext *context, EState *estate, ResultRelInfo *resultRelInfo, ItemPointer tupleid)
void ExecInitMergeTupleSlots(ModifyTableState *mtstate, ResultRelInfo *resultRelInfo)
static void ExecInitForPortionOf(ModifyTableState *mtstate, EState *estate, ResultRelInfo *resultRelInfo)
static void ExecUpdatePrepareSlot(ResultRelInfo *resultRelInfo, TupleTableSlot *slot, EState *estate)
static TupleTableSlot * ExecInsert(ModifyTableContext *context, ResultRelInfo *resultRelInfo, TupleTableSlot *slot, bool canSetTag, TupleTableSlot **inserted_tuple, ResultRelInfo **insert_destrel)
ModifyTableState * ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
static TupleTableSlot * ExecMergeMatched(ModifyTableContext *context, ResultRelInfo *resultRelInfo, ItemPointer tupleid, HeapTuple oldtuple, bool canSetTag, bool *matched)
static TupleTableSlot * ExecModifyTable(PlanState *pstate)
static bool ExecDeletePrologue(ModifyTableContext *context, ResultRelInfo *resultRelInfo, ItemPointer tupleid, HeapTuple oldtuple, TupleTableSlot **epqreturnslot, TM_Result *result)
static void ExecCheckPlanOutput(Relation resultRel, List *targetList)
TupleTableSlot * ExecGetUpdateNewTuple(ResultRelInfo *relinfo, TupleTableSlot *planSlot, TupleTableSlot *oldSlot)
static void ExecCrossPartitionUpdateForeignKey(ModifyTableContext *context, ResultRelInfo *sourcePartInfo, ResultRelInfo *destPartInfo, ItemPointer tupleid, TupleTableSlot *oldslot, TupleTableSlot *newslot)
static void ExecInitUpdateProjection(ModifyTableState *mtstate, ResultRelInfo *resultRelInfo)
static void ExecCheckTIDVisible(EState *estate, ResultRelInfo *relinfo, ItemPointer tid, TupleTableSlot *tempSlot)
static TM_Result ExecDeleteAct(ModifyTableContext *context, ResultRelInfo *resultRelInfo, ItemPointer tupleid, bool changingPart)
static void ExecCheckTupleVisible(EState *estate, Relation rel, TupleTableSlot *slot)
static TupleTableSlot * ExecUpdate(ModifyTableContext *context, ResultRelInfo *resultRelInfo, ItemPointer tupleid, HeapTuple oldtuple, TupleTableSlot *oldSlot, TupleTableSlot *slot, bool canSetTag)
void ExecComputeStoredGenerated(ResultRelInfo *resultRelInfo, EState *estate, TupleTableSlot *slot, CmdType cmdtype)
static TupleTableSlot * ExecPrepareTupleRouting(ModifyTableState *mtstate, EState *estate, PartitionTupleRouting *proute, ResultRelInfo *targetRelInfo, TupleTableSlot *slot, ResultRelInfo **partRelInfo)
static TupleTableSlot * ExecGetInsertNewTuple(ResultRelInfo *relinfo, TupleTableSlot *planSlot)
#define MT_NRELS_HASH
static TM_Result ExecUpdateAct(ModifyTableContext *context, ResultRelInfo *resultRelInfo, ItemPointer tupleid, HeapTuple oldtuple, TupleTableSlot *slot, bool canSetTag, UpdateContext *updateCxt)
static void ExecUpdateEpilogue(ModifyTableContext *context, UpdateContext *updateCxt, ResultRelInfo *resultRelInfo, ItemPointer tupleid, HeapTuple oldtuple, TupleTableSlot *slot)
void ExecInitGenerated(ResultRelInfo *resultRelInfo, EState *estate, CmdType cmdtype)
static bool ExecOnConflictLockRow(ModifyTableContext *context, TupleTableSlot *existing, ItemPointer conflictTid, Relation relation, LockTupleMode lockmode, bool isUpdate)
static void fireBSTriggers(ModifyTableState *node)
void ExecReScanModifyTable(ModifyTableState *node)
static TupleTableSlot * ExecDelete(ModifyTableContext *context, ResultRelInfo *resultRelInfo, ItemPointer tupleid, HeapTuple oldtuple, bool processReturning, bool changingPart, bool canSetTag, TM_Result *tmresult, bool *tupleDeleted, TupleTableSlot **epqreturnslot)
void ExecEndModifyTable(ModifyTableState *node)
static void fireASTriggers(ModifyTableState *node)
static bool ExecOnConflictUpdate(ModifyTableContext *context, ResultRelInfo *resultRelInfo, ItemPointer conflictTid, TupleTableSlot *excludedSlot, bool canSetTag, TupleTableSlot **returning)
static void ExecBatchInsert(ModifyTableState *mtstate, ResultRelInfo *resultRelInfo, TupleTableSlot **slots, TupleTableSlot **planSlots, int numSlots, EState *estate, bool canSetTag)
static bool ExecUpdatePrologue(ModifyTableContext *context, ResultRelInfo *resultRelInfo, ItemPointer tupleid, HeapTuple oldtuple, TupleTableSlot *slot, TM_Result *result)
static void ExecDeleteEpilogue(ModifyTableContext *context, ResultRelInfo *resultRelInfo, ItemPointer tupleid, HeapTuple oldtuple, bool changingPart)
static TupleTableSlot * ExecMergeNotMatched(ModifyTableContext *context, ResultRelInfo *resultRelInfo, bool canSetTag)
static TupleTableSlot * ExecMerge(ModifyTableContext *context, ResultRelInfo *resultRelInfo, ItemPointer tupleid, HeapTuple oldtuple, bool canSetTag)
static TupleTableSlot * ExecProcessReturning(ModifyTableContext *context, ResultRelInfo *resultRelInfo, bool isDelete, TupleTableSlot *oldSlot, TupleTableSlot *newSlot, TupleTableSlot *planSlot)
static bool ExecCrossPartitionUpdate(ModifyTableContext *context, ResultRelInfo *resultRelInfo, ItemPointer tupleid, HeapTuple oldtuple, TupleTableSlot *slot, bool canSetTag, UpdateContext *updateCxt, TM_Result *tmresult, TupleTableSlot **retry_slot, TupleTableSlot **inserted_tuple, ResultRelInfo **insert_destrel)
static void ExecInitMerge(ModifyTableState *mtstate, EState *estate)
#define IsA(nodeptr, _type_)
Definition nodes.h:162
OnConflictAction
Definition nodes.h:425
@ ONCONFLICT_NONE
Definition nodes.h:426
@ ONCONFLICT_SELECT
Definition nodes.h:429
@ ONCONFLICT_UPDATE
Definition nodes.h:428
@ ONCONFLICT_NOTHING
Definition nodes.h:427
CmdType
Definition nodes.h:271
@ CMD_MERGE
Definition nodes.h:277
@ CMD_INSERT
Definition nodes.h:275
@ CMD_DELETE
Definition nodes.h:276
@ CMD_UPDATE
Definition nodes.h:274
@ CMD_NOTHING
Definition nodes.h:280
#define makeNode(_type_)
Definition nodes.h:159
#define castNode(_type_, nodeptr)
Definition nodes.h:180
static char * errmsg
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition palloc.h:138
WCOKind
@ WCO_RLS_MERGE_UPDATE_CHECK
@ WCO_RLS_CONFLICT_CHECK
@ WCO_RLS_INSERT_CHECK
@ WCO_VIEW_CHECK
@ WCO_RLS_UPDATE_CHECK
@ WCO_RLS_MERGE_DELETE_CHECK
@ RTE_RELATION
FormData_pg_attribute * Form_pg_attribute
#define lfirst(lc)
Definition pg_list.h:172
#define lfirst_node(type, lc)
Definition pg_list.h:176
static int list_length(const List *l)
Definition pg_list.h:152
#define NIL
Definition pg_list.h:68
#define forboth(cell1, list1, cell2, list2)
Definition pg_list.h:550
#define lfirst_int(lc)
Definition pg_list.h:173
#define linitial_int(l)
Definition pg_list.h:179
static void * list_nth(const List *list, int n)
Definition pg_list.h:331
#define linitial(l)
Definition pg_list.h:178
#define list_nth_node(type, list, n)
Definition pg_list.h:359
#define plan(x)
Definition pg_regress.c:164
#define ERRCODE_T_R_SERIALIZATION_FAILURE
Definition pgbench.c:77
void pgstat_init_function_usage(FunctionCallInfo fcinfo, PgStat_FunctionCallUsage *fcu)
void pgstat_end_function_usage(PgStat_FunctionCallUsage *fcu, bool finalize)
#define outerPlan(node)
Definition plannodes.h:267
static Oid DatumGetObjectId(Datum X)
Definition postgres.h:242
uint64_t Datum
Definition postgres.h:70
static Pointer DatumGetPointer(Datum X)
Definition postgres.h:332
static TransactionId DatumGetTransactionId(Datum X)
Definition postgres.h:282
#define InvalidOid
unsigned int Oid
static void test(void)
static int fb(int x)
@ MERGE_WHEN_NOT_MATCHED_BY_TARGET
Definition primnodes.h:2021
@ MERGE_WHEN_NOT_MATCHED_BY_SOURCE
Definition primnodes.h:2020
@ MERGE_WHEN_MATCHED
Definition primnodes.h:2019
#define RelationGetForm(relation)
Definition rel.h:510
#define RelationGetRelid(relation)
Definition rel.h:516
#define RelationGetDescr(relation)
Definition rel.h:542
#define RelationGetRelationName(relation)
Definition rel.h:550
Node * build_column_default(Relation rel, int attrno)
Node * map_variable_attnos(Node *node, int target_varno, int sublevels_up, const AttrMap *attno_map, Oid to_rowtype, bool *found_whole_row)
int RI_FKey_trigger_type(Oid tgfoid)
#define SnapshotAny
Definition snapmgr.h:33
AttrNumber * attnums
Definition attmap.h:36
uint64 es_processed
Definition execnodes.h:751
Bitmapset * es_unpruned_relids
Definition execnodes.h:710
List * es_insert_pending_result_relations
Definition execnodes.h:808
MemoryContext es_query_cxt
Definition execnodes.h:747
List * es_tupleTable
Definition execnodes.h:749
struct EPQState * es_epq_active
Definition execnodes.h:779
CommandId es_output_cid
Definition execnodes.h:719
List * es_insert_pending_modifytables
Definition execnodes.h:809
Snapshot es_snapshot
Definition execnodes.h:697
List * es_auxmodifytables
Definition execnodes.h:764
Snapshot es_crosscheck_snapshot
Definition execnodes.h:698
TupleTableSlot * ecxt_innertuple
Definition execnodes.h:289
TupleTableSlot * ecxt_newtuple
Definition execnodes.h:326
TupleTableSlot * ecxt_scantuple
Definition execnodes.h:287
TupleTableSlot * ecxt_oldtuple
Definition execnodes.h:324
TupleTableSlot * ecxt_outertuple
Definition execnodes.h:291
uint8 flags
Definition execnodes.h:103
BeginForeignModify_function BeginForeignModify
Definition fdwapi.h:235
EndForeignModify_function EndForeignModify
Definition fdwapi.h:241
ExecForeignInsert_function ExecForeignInsert
Definition fdwapi.h:236
ExecForeignUpdate_function ExecForeignUpdate
Definition fdwapi.h:239
ExecForeignBatchInsert_function ExecForeignBatchInsert
Definition fdwapi.h:237
GetForeignModifyBatchSize_function GetForeignModifyBatchSize
Definition fdwapi.h:238
ExecForeignDelete_function ExecForeignDelete
Definition fdwapi.h:240
ParseLoc targetLocation
Definition primnodes.h:2447
TupleTableSlot * fp_Existing
Definition execnodes.h:485
Size keysize
Definition hsearch.h:69
Definition pg_list.h:54
MergeAction * mas_action
Definition execnodes.h:464
ProjectionInfo * mas_proj
Definition execnodes.h:465
ExprState * mas_whenqual
Definition execnodes.h:467
CmdType commandType
Definition primnodes.h:2030
TM_FailureData tmfd
TupleTableSlot * planSlot
TupleTableSlot * cpDeletedSlot
TupleTableSlot * cpUpdateReturningSlot
ModifyTableState * mtstate
List * mt_mergeJoinConditions
Definition execnodes.h:1512
TupleTableSlot * mt_merge_pending_not_matched
Definition execnodes.h:1497
ResultRelInfo * resultRelInfo
Definition execnodes.h:1447
double mt_merge_deleted
Definition execnodes.h:1502
struct PartitionTupleRouting * mt_partition_tuple_routing
Definition execnodes.h:1478
List * mt_updateColnosLists
Definition execnodes.h:1510
double mt_merge_inserted
Definition execnodes.h:1500
TupleTableSlot * mt_root_tuple_slot
Definition execnodes.h:1475
List * mt_fdwPrivLists
Definition execnodes.h:1513
EPQState mt_epqstate
Definition execnodes.h:1457
double mt_merge_updated
Definition execnodes.h:1501
List * mt_mergeActionLists
Definition execnodes.h:1511
HTAB * mt_resultOidHash
Definition execnodes.h:1469
ResultRelInfo * rootResultRelInfo
Definition execnodes.h:1455
struct TransitionCaptureState * mt_transition_capture
Definition execnodes.h:1481
struct TransitionCaptureState * mt_oc_transition_capture
Definition execnodes.h:1484
MergeActionState * mt_merge_action
Definition execnodes.h:1490
List * updateColnosLists
Definition plannodes.h:350
List * arbiterIndexes
Definition plannodes.h:370
List * onConflictCols
Definition plannodes.h:376
List * mergeJoinConditions
Definition plannodes.h:388
CmdType operation
Definition plannodes.h:340
Node * forPortionOf
Definition plannodes.h:380
List * resultRelations
Definition plannodes.h:348
Bitmapset * fdwDirectModifyPlans
Definition plannodes.h:362
List * onConflictSet
Definition plannodes.h:374
List * mergeActionLists
Definition plannodes.h:386
bool canSetTag
Definition plannodes.h:342
List * fdwPrivLists
Definition plannodes.h:360
List * returningLists
Definition plannodes.h:358
List * withCheckOptionLists
Definition plannodes.h:352
LockClauseStrength onConflictLockStrength
Definition plannodes.h:372
Index rootRelation
Definition plannodes.h:346
Node * onConflictWhere
Definition plannodes.h:378
List * rowMarks
Definition plannodes.h:364
OnConflictAction onConflictAction
Definition plannodes.h:368
Definition nodes.h:133
ExprState * oc_WhereClause
Definition execnodes.h:451
ProjectionInfo * oc_ProjInfo
Definition execnodes.h:449
TupleTableSlot * oc_ProjSlot
Definition execnodes.h:448
TupleTableSlot * oc_Existing
Definition execnodes.h:447
LockClauseStrength oc_LockStrength
Definition execnodes.h:450
Plan * plan
Definition execnodes.h:1202
EState * state
Definition execnodes.h:1204
ExprContext * ps_ExprContext
Definition execnodes.h:1243
TupleTableSlot * ps_ResultTupleSlot
Definition execnodes.h:1242
ExecProcNodeMtd ExecProcNode
Definition execnodes.h:1208
List * targetlist
Definition plannodes.h:235
ExprState pi_state
Definition execnodes.h:400
TriggerDesc * trigdesc
Definition rel.h:117
TupleDesc rd_att
Definition rel.h:112
Form_pg_class rd_rel
Definition rel.h:111
OnConflictActionState * ri_onConflict
Definition execnodes.h:617
TupleTableSlot * ri_PartitionTupleSlot
Definition execnodes.h:656
bool ri_projectNewInfoValid
Definition execnodes.h:543
List * ri_onConflictArbiterIndexes
Definition execnodes.h:614
struct ResultRelInfo * ri_RootResultRelInfo
Definition execnodes.h:655
TupleTableSlot ** ri_Slots
Definition execnodes.h:579
ExprState * ri_MergeJoinCondition
Definition execnodes.h:623
bool ri_needLockTagTuple
Definition execnodes.h:546
Relation ri_RelationDesc
Definition execnodes.h:514
RelationPtr ri_IndexRelationDescs
Definition execnodes.h:520
int ri_NumSlotsInitialized
Definition execnodes.h:577
List * ri_WithCheckOptions
Definition execnodes.h:583
TupleTableSlot * ri_oldTupleSlot
Definition execnodes.h:541
bool ri_extraUpdatedCols_valid
Definition execnodes.h:534
TriggerDesc * ri_TrigDesc
Definition execnodes.h:549
ForPortionOfState * ri_forPortionOf
Definition execnodes.h:626
Bitmapset * ri_extraUpdatedCols
Definition execnodes.h:532
Index ri_RangeTableIndex
Definition execnodes.h:511
ExprState ** ri_GeneratedExprsI
Definition execnodes.h:600
int ri_NumGeneratedNeededU
Definition execnodes.h:605
List * ri_MergeActions[NUM_MERGE_MATCH_KINDS]
Definition execnodes.h:620
TupleTableSlot * ri_newTupleSlot
Definition execnodes.h:539
List * ri_WithCheckOptionExprs
Definition execnodes.h:586
ProjectionInfo * ri_projectNew
Definition execnodes.h:537
ProjectionInfo * ri_projectReturning
Definition execnodes.h:611
ExprState ** ri_GeneratedExprsU
Definition execnodes.h:601
struct FdwRoutine * ri_FdwRoutine
Definition execnodes.h:567
List * ri_returningList
Definition execnodes.h:608
TupleTableSlot ** ri_PlanSlots
Definition execnodes.h:580
bool ri_usesFdwDirectModify
Definition execnodes.h:573
AttrNumber ri_RowIdAttNo
Definition execnodes.h:529
int ri_NumGeneratedNeededI
Definition execnodes.h:604
NodeTag type
Definition execnodes.h:368
SetFunctionReturnMode returnMode
Definition execnodes.h:374
ExprContext * econtext
Definition execnodes.h:370
TupleDesc setDesc
Definition execnodes.h:378
Tuplestorestate * setResult
Definition execnodes.h:377
TupleDesc expectedDesc
Definition execnodes.h:371
ExprDoneCond isDone
Definition execnodes.h:375
TransactionId xmax
Definition tableam.h:172
CommandId cmax
Definition tableam.h:173
TupleTableSlot * tcs_original_insert_tuple
Definition trigger.h:76
int numtriggers
Definition reltrigger.h:50
bool trig_delete_before_row
Definition reltrigger.h:66
bool trig_update_instead_row
Definition reltrigger.h:63
Trigger * triggers
Definition reltrigger.h:49
bool trig_delete_instead_row
Definition reltrigger.h:68
bool trig_update_after_row
Definition reltrigger.h:62
bool trig_insert_instead_row
Definition reltrigger.h:58
bool trig_update_before_row
Definition reltrigger.h:61
bool trig_insert_before_row
Definition reltrigger.h:56
bool has_generated_virtual
Definition tupdesc.h:47
bool has_generated_stored
Definition tupdesc.h:46
AttrMap * attrMap
Definition tupconvert.h:28
TupleConstr * constr
Definition tupdesc.h:159
TupleDesc tts_tupleDescriptor
Definition tuptable.h:129
const TupleTableSlotOps *const tts_ops
Definition tuptable.h:127
bool * tts_isnull
Definition tuptable.h:133
ItemPointerData tts_tid
Definition tuptable.h:142
Datum * tts_values
Definition tuptable.h:131
TU_UpdateIndexes updateIndexes
LockTupleMode lockmode
AttrNumber varattno
Definition primnodes.h:275
#define MinTransactionIdAttributeNumber
Definition sysattr.h:22
#define FirstLowInvalidHeapAttributeNumber
Definition sysattr.h:27
TupleTableSlot * table_slot_create(Relation relation, List **reglist)
Definition tableam.c:92
TU_UpdateIndexes
Definition tableam.h:133
@ TU_Summarizing
Definition tableam.h:141
@ TU_None
Definition tableam.h:135
TM_Result
Definition tableam.h:95
@ TM_Ok
Definition tableam.h:100
@ TM_BeingModified
Definition tableam.h:122
@ TM_Deleted
Definition tableam.h:115
@ TM_WouldBlock
Definition tableam.h:125
@ TM_Updated
Definition tableam.h:112
@ TM_SelfModified
Definition tableam.h:106
@ TM_Invisible
Definition tableam.h:103
static TM_Result table_tuple_lock(Relation rel, ItemPointer tid, Snapshot snapshot, TupleTableSlot *slot, CommandId cid, LockTupleMode mode, LockWaitPolicy wait_policy, uint8 flags, TM_FailureData *tmfd)
Definition tableam.h:1646
static void table_tuple_insert_speculative(Relation rel, TupleTableSlot *slot, CommandId cid, uint32 options, BulkInsertStateData *bistate, uint32 specToken)
Definition tableam.h:1477
static void table_tuple_complete_speculative(Relation rel, TupleTableSlot *slot, uint32 specToken, bool succeeded)
Definition tableam.h:1491
#define TUPLE_LOCK_FLAG_FIND_LAST_VERSION
Definition tableam.h:299
#define TABLE_DELETE_CHANGING_PARTITION
Definition tableam.h:289
static void table_tuple_insert(Relation rel, TupleTableSlot *slot, CommandId cid, uint32 options, BulkInsertStateData *bistate)
Definition tableam.h:1458
static TM_Result table_tuple_update(Relation rel, ItemPointer otid, TupleTableSlot *slot, CommandId cid, uint32 options, Snapshot snapshot, Snapshot crosscheck, bool wait, TM_FailureData *tmfd, LockTupleMode *lockmode, TU_UpdateIndexes *update_indexes)
Definition tableam.h:1598
static TM_Result table_tuple_delete(Relation rel, ItemPointer tid, CommandId cid, uint32 options, Snapshot snapshot, Snapshot crosscheck, bool wait, TM_FailureData *tmfd)
Definition tableam.h:1549
static bool table_tuple_satisfies_snapshot(Relation rel, TupleTableSlot *slot, Snapshot snapshot)
Definition tableam.h:1391
static bool table_tuple_fetch_row_version(Relation rel, ItemPointer tid, Snapshot snapshot, TupleTableSlot *slot)
Definition tableam.h:1344
bool ExecBRUpdateTriggers(EState *estate, EPQState *epqstate, ResultRelInfo *relinfo, ItemPointer tupleid, HeapTuple fdw_trigtuple, TupleTableSlot *newslot, TM_Result *tmresult, TM_FailureData *tmfd, bool is_merge_update)
Definition trigger.c:2998
TransitionCaptureState * MakeTransitionCaptureState(TriggerDesc *trigdesc, Oid relid, CmdType cmdType)
Definition trigger.c:5005
void ExecARDeleteTriggers(EState *estate, ResultRelInfo *relinfo, ItemPointer tupleid, HeapTuple fdw_trigtuple, TransitionCaptureState *transition_capture, bool is_crosspart_update)
Definition trigger.c:2828
void ExecBSInsertTriggers(EState *estate, ResultRelInfo *relinfo)
Definition trigger.c:2428
bool ExecBRInsertTriggers(EState *estate, ResultRelInfo *relinfo, TupleTableSlot *slot)
Definition trigger.c:2492
bool ExecIRDeleteTriggers(EState *estate, ResultRelInfo *relinfo, HeapTuple trigtuple)
Definition trigger.c:2875
void ExecBSDeleteTriggers(EState *estate, ResultRelInfo *relinfo)
Definition trigger.c:2657
bool ExecIRInsertTriggers(EState *estate, ResultRelInfo *relinfo, TupleTableSlot *slot)
Definition trigger.c:2596
void ExecARUpdateTriggers(EState *estate, ResultRelInfo *relinfo, ResultRelInfo *src_partinfo, ResultRelInfo *dst_partinfo, ItemPointer tupleid, HeapTuple fdw_trigtuple, TupleTableSlot *newslot, List *recheckIndexes, TransitionCaptureState *transition_capture, bool is_crosspart_update)
Definition trigger.c:3171
bool ExecBRDeleteTriggers(EState *estate, EPQState *epqstate, ResultRelInfo *relinfo, ItemPointer tupleid, HeapTuple fdw_trigtuple, TupleTableSlot **epqslot, TM_Result *tmresult, TM_FailureData *tmfd, bool is_merge_delete)
Definition trigger.c:2728
void ExecASUpdateTriggers(EState *estate, ResultRelInfo *relinfo, TransitionCaptureState *transition_capture)
Definition trigger.c:2980
void ExecASDeleteTriggers(EState *estate, ResultRelInfo *relinfo, TransitionCaptureState *transition_capture)
Definition trigger.c:2708
void ExecARInsertTriggers(EState *estate, ResultRelInfo *relinfo, TupleTableSlot *slot, List *recheckIndexes, TransitionCaptureState *transition_capture)
Definition trigger.c:2570
void ExecASInsertTriggers(EState *estate, ResultRelInfo *relinfo, TransitionCaptureState *transition_capture)
Definition trigger.c:2479
bool ExecIRUpdateTriggers(EState *estate, ResultRelInfo *relinfo, HeapTuple trigtuple, TupleTableSlot *newslot)
Definition trigger.c:3241
void AfterTriggerEndQuery(EState *estate)
Definition trigger.c:5186
void ExecBSUpdateTriggers(EState *estate, ResultRelInfo *relinfo)
Definition trigger.c:2922
void AfterTriggerBeginQuery(void)
Definition trigger.c:5166
#define RI_TRIGGER_PK
Definition trigger.h:286
TupleTableSlot * execute_attr_map_slot(AttrMap *attrMap, TupleTableSlot *in_slot, TupleTableSlot *out_slot)
Definition tupconvert.c:193
TupleDesc CreateTupleDescCopy(TupleDesc tupdesc)
Definition tupdesc.c:242
static FormData_pg_attribute * TupleDescAttr(TupleDesc tupdesc, int i)
Definition tupdesc.h:178
static CompactAttribute * TupleDescCompactAttr(TupleDesc tupdesc, int i)
Definition tupdesc.h:195
#define TTS_EMPTY(slot)
Definition tuptable.h:92
static Datum slot_getsysattr(TupleTableSlot *slot, int attnum, bool *isnull)
Definition tuptable.h:438
static TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition tuptable.h:476
#define TupIsNull(slot)
Definition tuptable.h:325
static void slot_getallattrs(TupleTableSlot *slot)
Definition tuptable.h:390
static TupleTableSlot * ExecCopySlot(TupleTableSlot *dstslot, TupleTableSlot *srcslot)
Definition tuptable.h:544
static void ExecMaterializeSlot(TupleTableSlot *slot)
Definition tuptable.h:495
TypeCacheEntry * lookup_type_cache(Oid type_id, int flags)
Definition typcache.c:389
void pull_varattnos(Node *node, Index varno, Bitmapset **varattnos)
Definition var.c:296
bool TransactionIdIsCurrentTransactionId(TransactionId xid)
Definition xact.c:943
TransactionId GetCurrentTransactionId(void)
Definition xact.c:456
#define IsolationUsesXactSnapshot()
Definition xact.h:52