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 if (!ExecUpdatePrologue(context, resultRelInfo, tupleid, oldtuple, slot, NULL))
2769 return NULL;
2770
2771 /* INSTEAD OF ROW UPDATE Triggers */
2772 if (resultRelInfo->ri_TrigDesc &&
2773 resultRelInfo->ri_TrigDesc->trig_update_instead_row)
2774 {
2775 if (!ExecIRUpdateTriggers(estate, resultRelInfo,
2776 oldtuple, slot))
2777 return NULL; /* "do nothing" */
2778 }
2779 else if (resultRelInfo->ri_FdwRoutine)
2780 {
2781 /* Fill in GENERATEd columns */
2782 ExecUpdatePrepareSlot(resultRelInfo, slot, estate);
2783
2784 /*
2785 * update in foreign table: let the FDW do it
2786 */
2787 slot = resultRelInfo->ri_FdwRoutine->ExecForeignUpdate(estate,
2788 resultRelInfo,
2789 slot,
2790 context->planSlot);
2791
2792 if (slot == NULL) /* "do nothing" */
2793 return NULL;
2794
2795 /*
2796 * AFTER ROW Triggers or RETURNING expressions might reference the
2797 * tableoid column, so (re-)initialize tts_tableOid before evaluating
2798 * them. (This covers the case where the FDW replaced the slot.)
2799 */
2801 }
2802 else
2803 {
2805
2806 /*
2807 * If we generate a new candidate tuple after EvalPlanQual testing, we
2808 * must loop back here to try again. (We don't need to redo triggers,
2809 * however. If there are any BEFORE triggers then trigger.c will have
2810 * done table_tuple_lock to lock the correct tuple, so there's no need
2811 * to do them again.)
2812 */
2813redo_act:
2814 lockedtid = *tupleid;
2815 result = ExecUpdateAct(context, resultRelInfo, tupleid, oldtuple, slot,
2816 canSetTag, &updateCxt);
2817
2818 /*
2819 * If ExecUpdateAct reports that a cross-partition update was done,
2820 * then the RETURNING tuple (if any) has been projected and there's
2821 * nothing else for us to do.
2822 */
2823 if (updateCxt.crossPartUpdate)
2824 return context->cpUpdateReturningSlot;
2825
2826 switch (result)
2827 {
2828 case TM_SelfModified:
2829
2830 /*
2831 * The target tuple was already updated or deleted by the
2832 * current command, or by a later command in the current
2833 * transaction. The former case is possible in a join UPDATE
2834 * where multiple tuples join to the same target tuple. This
2835 * is pretty questionable, but Postgres has always allowed it:
2836 * we just execute the first update action and ignore
2837 * additional update attempts.
2838 *
2839 * The latter case arises if the tuple is modified by a
2840 * command in a BEFORE trigger, or perhaps by a command in a
2841 * volatile function used in the query. In such situations we
2842 * should not ignore the update, but it is equally unsafe to
2843 * proceed. We don't want to discard the original UPDATE
2844 * while keeping the triggered actions based on it; and we
2845 * have no principled way to merge this update with the
2846 * previous ones. So throwing an error is the only safe
2847 * course.
2848 *
2849 * If a trigger actually intends this type of interaction, it
2850 * can re-execute the UPDATE (assuming it can figure out how)
2851 * and then return NULL to cancel the outer update.
2852 */
2853 if (context->tmfd.cmax != estate->es_output_cid)
2854 ereport(ERROR,
2856 errmsg("tuple to be updated was already modified by an operation triggered by the current command"),
2857 errhint("Consider using an AFTER trigger instead of a BEFORE trigger to propagate changes to other rows.")));
2858
2859 /* Else, already updated by self; nothing to do */
2860 return NULL;
2861
2862 case TM_Ok:
2863 break;
2864
2865 case TM_Updated:
2866 {
2867 TupleTableSlot *inputslot;
2869
2871 ereport(ERROR,
2873 errmsg("could not serialize access due to concurrent update")));
2874
2875 /*
2876 * Already know that we're going to need to do EPQ, so
2877 * fetch tuple directly into the right slot.
2878 */
2879 inputslot = EvalPlanQualSlot(context->epqstate, resultRelationDesc,
2880 resultRelInfo->ri_RangeTableIndex);
2881
2883 estate->es_snapshot,
2884 inputslot, estate->es_output_cid,
2885 updateCxt.lockmode, LockWaitBlock,
2887 &context->tmfd);
2888
2889 switch (result)
2890 {
2891 case TM_Ok:
2892 Assert(context->tmfd.traversed);
2893
2894 epqslot = EvalPlanQual(context->epqstate,
2896 resultRelInfo->ri_RangeTableIndex,
2897 inputslot);
2898 if (TupIsNull(epqslot))
2899 /* Tuple not passing quals anymore, exiting... */
2900 return NULL;
2901
2902 /* Make sure ri_oldTupleSlot is initialized. */
2903 if (unlikely(!resultRelInfo->ri_projectNewInfoValid))
2905 resultRelInfo);
2906
2907 if (resultRelInfo->ri_needLockTagTuple)
2908 {
2913 }
2914
2915 /* Fetch the most recent version of old tuple. */
2916 oldSlot = resultRelInfo->ri_oldTupleSlot;
2918 tupleid,
2920 oldSlot))
2921 elog(ERROR, "failed to fetch tuple being updated");
2922 slot = ExecGetUpdateNewTuple(resultRelInfo,
2923 epqslot, oldSlot);
2924 goto redo_act;
2925
2926 case TM_Deleted:
2927 /* tuple already deleted; nothing to do */
2928 return NULL;
2929
2930 case TM_SelfModified:
2931
2932 /*
2933 * This can be reached when following an update
2934 * chain from a tuple updated by another session,
2935 * reaching a tuple that was already updated in
2936 * this transaction. If previously modified by
2937 * this command, ignore the redundant update,
2938 * otherwise error out.
2939 *
2940 * See also TM_SelfModified response to
2941 * table_tuple_update() above.
2942 */
2943 if (context->tmfd.cmax != estate->es_output_cid)
2944 ereport(ERROR,
2946 errmsg("tuple to be updated was already modified by an operation triggered by the current command"),
2947 errhint("Consider using an AFTER trigger instead of a BEFORE trigger to propagate changes to other rows.")));
2948 return NULL;
2949
2950 default:
2951 /* see table_tuple_lock call in ExecDelete() */
2952 elog(ERROR, "unexpected table_tuple_lock status: %u",
2953 result);
2954 return NULL;
2955 }
2956 }
2957
2958 break;
2959
2960 case TM_Deleted:
2962 ereport(ERROR,
2964 errmsg("could not serialize access due to concurrent delete")));
2965 /* tuple already deleted; nothing to do */
2966 return NULL;
2967
2968 default:
2969 elog(ERROR, "unrecognized table_tuple_update status: %u",
2970 result);
2971 return NULL;
2972 }
2973 }
2974
2975 if (canSetTag)
2976 (estate->es_processed)++;
2977
2978 ExecUpdateEpilogue(context, &updateCxt, resultRelInfo, tupleid, oldtuple,
2979 slot);
2980
2981 /* Process RETURNING if present */
2982 if (resultRelInfo->ri_projectReturning)
2983 return ExecProcessReturning(context, resultRelInfo, false,
2984 oldSlot, slot, context->planSlot);
2985
2986 return NULL;
2987}
2988
2989/*
2990 * ExecOnConflictLockRow --- lock the row for ON CONFLICT DO SELECT/UPDATE
2991 *
2992 * Try to lock tuple for update as part of speculative insertion for ON
2993 * CONFLICT DO UPDATE or ON CONFLICT DO SELECT FOR UPDATE/SHARE.
2994 *
2995 * Returns true if the row is successfully locked, or false if the caller must
2996 * retry the INSERT from scratch.
2997 */
2998static bool
3002 Relation relation,
3003 LockTupleMode lockmode,
3004 bool isUpdate)
3005{
3006 TM_FailureData tmfd;
3009 TransactionId xmin;
3010 bool isnull;
3011
3012 /*
3013 * Lock tuple with lockmode. Don't follow updates when tuple cannot be
3014 * locked without doing so. A row locking conflict here means our
3015 * previous conclusion that the tuple is conclusively committed is not
3016 * true anymore.
3017 */
3018 test = table_tuple_lock(relation, conflictTid,
3019 context->estate->es_snapshot,
3020 existing, context->estate->es_output_cid,
3021 lockmode, LockWaitBlock, 0,
3022 &tmfd);
3023 switch (test)
3024 {
3025 case TM_Ok:
3026 /* success! */
3027 break;
3028
3029 case TM_Invisible:
3030
3031 /*
3032 * This can occur when a just inserted tuple is updated again in
3033 * the same command. E.g. because multiple rows with the same
3034 * conflicting key values are inserted.
3035 *
3036 * This is somewhat similar to the ExecUpdate() TM_SelfModified
3037 * case. We do not want to proceed because it would lead to the
3038 * same row being updated a second time in some unspecified order,
3039 * and in contrast to plain UPDATEs there's no historical behavior
3040 * to break.
3041 *
3042 * It is the user's responsibility to prevent this situation from
3043 * occurring. These problems are why the SQL standard similarly
3044 * specifies that for SQL MERGE, an exception must be raised in
3045 * the event of an attempt to update the same row twice.
3046 */
3049 &isnull);
3050 Assert(!isnull);
3052
3054 ereport(ERROR,
3056 /* translator: %s is a SQL command name */
3057 errmsg("%s command cannot affect row a second time",
3058 isUpdate ? "ON CONFLICT DO UPDATE" : "ON CONFLICT DO SELECT"),
3059 errhint("Ensure that no rows proposed for insertion within the same command have duplicate constrained values.")));
3060
3061 /* This shouldn't happen */
3062 elog(ERROR, "attempted to lock invisible tuple");
3063 break;
3064
3065 case TM_SelfModified:
3066
3067 /*
3068 * This state should never be reached. As a dirty snapshot is used
3069 * to find conflicting tuples, speculative insertion wouldn't have
3070 * seen this row to conflict with.
3071 */
3072 elog(ERROR, "unexpected self-updated tuple");
3073 break;
3074
3075 case TM_Updated:
3077 ereport(ERROR,
3079 errmsg("could not serialize access due to concurrent update")));
3080
3081 /*
3082 * Tell caller to try again from the very start.
3083 *
3084 * It does not make sense to use the usual EvalPlanQual() style
3085 * loop here, as the new version of the row might not conflict
3086 * anymore, or the conflicting tuple has actually been deleted.
3087 */
3089 return false;
3090
3091 case TM_Deleted:
3093 ereport(ERROR,
3095 errmsg("could not serialize access due to concurrent delete")));
3096
3097 /* see TM_Updated case */
3099 return false;
3100
3101 default:
3102 elog(ERROR, "unrecognized table_tuple_lock status: %u", test);
3103 }
3104
3105 /* Success, the tuple is locked. */
3106 return true;
3107}
3108
3109/*
3110 * ExecOnConflictUpdate --- execute UPDATE of INSERT ON CONFLICT DO UPDATE
3111 *
3112 * Try to lock tuple for update as part of speculative insertion. If
3113 * a qual originating from ON CONFLICT DO UPDATE is satisfied, update
3114 * (but still lock row, even though it may not satisfy estate's
3115 * snapshot).
3116 *
3117 * Returns true if we're done (with or without an update), or false if
3118 * the caller must retry the INSERT from scratch.
3119 */
3120static bool
3122 ResultRelInfo *resultRelInfo,
3125 bool canSetTag,
3126 TupleTableSlot **returning)
3127{
3128 ModifyTableState *mtstate = context->mtstate;
3129 ExprContext *econtext = mtstate->ps.ps_ExprContext;
3130 Relation relation = resultRelInfo->ri_RelationDesc;
3133 LockTupleMode lockmode;
3134
3135 /*
3136 * Parse analysis should have blocked ON CONFLICT for all system
3137 * relations, which includes these. There's no fundamental obstacle to
3138 * supporting this; we'd just need to handle LOCKTAG_TUPLE like the other
3139 * ExecUpdate() caller.
3140 */
3141 Assert(!resultRelInfo->ri_needLockTagTuple);
3142
3143 /* Determine lock mode to use */
3144 lockmode = ExecUpdateLockMode(context->estate, resultRelInfo);
3145
3146 /* Lock tuple for update */
3148 resultRelInfo->ri_RelationDesc, lockmode, true))
3149 return false;
3150
3151 /*
3152 * Verify that the tuple is visible to our MVCC snapshot if the current
3153 * isolation level mandates that.
3154 *
3155 * It's not sufficient to rely on the check within ExecUpdate() as e.g.
3156 * CONFLICT ... WHERE clause may prevent us from reaching that.
3157 *
3158 * This means we only ever continue when a new command in the current
3159 * transaction could see the row, even though in READ COMMITTED mode the
3160 * tuple will not be visible according to the current statement's
3161 * snapshot. This is in line with the way UPDATE deals with newer tuple
3162 * versions.
3163 */
3164 ExecCheckTupleVisible(context->estate, relation, existing);
3165
3166 /*
3167 * Make tuple and any needed join variables available to ExecQual and
3168 * ExecProject. The EXCLUDED tuple is installed in ecxt_innertuple, while
3169 * the target's existing tuple is installed in the scantuple. EXCLUDED
3170 * has been made to reference INNER_VAR in setrefs.c, but there is no
3171 * other redirection.
3172 */
3173 econtext->ecxt_scantuple = existing;
3174 econtext->ecxt_innertuple = excludedSlot;
3175 econtext->ecxt_outertuple = NULL;
3176
3177 if (!ExecQual(onConflictSetWhere, econtext))
3178 {
3179 ExecClearTuple(existing); /* see return below */
3180 InstrCountFiltered1(&mtstate->ps, 1);
3181 return true; /* done with the tuple */
3182 }
3183
3184 if (resultRelInfo->ri_WithCheckOptions != NIL)
3185 {
3186 /*
3187 * Check target's existing tuple against UPDATE-applicable USING
3188 * security barrier quals (if any), enforced here as RLS checks/WCOs.
3189 *
3190 * The rewriter creates UPDATE RLS checks/WCOs for UPDATE security
3191 * quals, and stores them as WCOs of "kind" WCO_RLS_CONFLICT_CHECK.
3192 * Since SELECT permission on the target table is always required for
3193 * INSERT ... ON CONFLICT DO UPDATE, the rewriter also adds SELECT RLS
3194 * checks/WCOs for SELECT security quals, using WCOs of the same kind,
3195 * and this check enforces them too.
3196 *
3197 * The rewriter will also have associated UPDATE-applicable straight
3198 * RLS checks/WCOs for the benefit of the ExecUpdate() call that
3199 * follows. INSERTs and UPDATEs naturally have mutually exclusive WCO
3200 * kinds, so there is no danger of spurious over-enforcement in the
3201 * INSERT or UPDATE path.
3202 */
3204 existing,
3205 mtstate->ps.state);
3206 }
3207
3208 /* Project the new tuple version */
3209 ExecProject(resultRelInfo->ri_onConflict->oc_ProjInfo);
3210
3211 /*
3212 * Note that it is possible that the target tuple has been modified in
3213 * this session, after the above table_tuple_lock. We choose to not error
3214 * out in that case, in line with ExecUpdate's treatment of similar cases.
3215 * This can happen if an UPDATE is triggered from within ExecQual(),
3216 * ExecWithCheckOptions() or ExecProject() above, e.g. by selecting from a
3217 * wCTE in the ON CONFLICT's SET.
3218 */
3219
3220 /* Execute UPDATE with projection */
3221 *returning = ExecUpdate(context, resultRelInfo,
3223 resultRelInfo->ri_onConflict->oc_ProjSlot,
3224 canSetTag);
3225
3226 /*
3227 * Clear out existing tuple, as there might not be another conflict among
3228 * the next input rows. Don't want to hold resources till the end of the
3229 * query. First though, make sure that the returning slot, if any, has a
3230 * local copy of any OLD pass-by-reference values, if it refers to any OLD
3231 * columns.
3232 */
3233 if (*returning != NULL &&
3235 ExecMaterializeSlot(*returning);
3236
3238
3239 return true;
3240}
3241
3242/*
3243 * ExecOnConflictSelect --- execute SELECT of INSERT ON CONFLICT DO SELECT
3244 *
3245 * If SELECT FOR UPDATE/SHARE is specified, try to lock tuple as part of
3246 * speculative insertion. If a qual originating from ON CONFLICT DO SELECT is
3247 * satisfied, select (but still lock row, even though it may not satisfy
3248 * estate's snapshot).
3249 *
3250 * Returns true if we're done (with or without a select), or false if the
3251 * caller must retry the INSERT from scratch.
3252 */
3253static bool
3255 ResultRelInfo *resultRelInfo,
3258 bool canSetTag,
3259 TupleTableSlot **returning)
3260{
3261 ModifyTableState *mtstate = context->mtstate;
3262 ExprContext *econtext = mtstate->ps.ps_ExprContext;
3263 Relation relation = resultRelInfo->ri_RelationDesc;
3266 LockClauseStrength lockStrength = resultRelInfo->ri_onConflict->oc_LockStrength;
3267
3268 /*
3269 * Parse analysis should have blocked ON CONFLICT for all system
3270 * relations, which includes these. There's no fundamental obstacle to
3271 * supporting this; we'd just need to handle LOCKTAG_TUPLE appropriately.
3272 */
3273 Assert(!resultRelInfo->ri_needLockTagTuple);
3274
3275 /* Fetch/lock existing tuple, according to the requested lock strength */
3276 if (lockStrength == LCS_NONE)
3277 {
3278 if (!table_tuple_fetch_row_version(relation,
3281 existing))
3282 elog(ERROR, "failed to fetch conflicting tuple for ON CONFLICT");
3283 }
3284 else
3285 {
3286 LockTupleMode lockmode;
3287
3288 switch (lockStrength)
3289 {
3290 case LCS_FORKEYSHARE:
3291 lockmode = LockTupleKeyShare;
3292 break;
3293 case LCS_FORSHARE:
3294 lockmode = LockTupleShare;
3295 break;
3296 case LCS_FORNOKEYUPDATE:
3297 lockmode = LockTupleNoKeyExclusive;
3298 break;
3299 case LCS_FORUPDATE:
3300 lockmode = LockTupleExclusive;
3301 break;
3302 default:
3303 elog(ERROR, "Unexpected lock strength %d", (int) lockStrength);
3304 }
3305
3307 resultRelInfo->ri_RelationDesc, lockmode, false))
3308 return false;
3309 }
3310
3311 /*
3312 * Verify that the tuple is visible to our MVCC snapshot if the current
3313 * isolation level mandates that. See comments in ExecOnConflictUpdate().
3314 */
3315 ExecCheckTupleVisible(context->estate, relation, existing);
3316
3317 /*
3318 * Make tuple and any needed join variables available to ExecQual. The
3319 * EXCLUDED tuple is installed in ecxt_innertuple, while the target's
3320 * existing tuple is installed in the scantuple. EXCLUDED has been made
3321 * to reference INNER_VAR in setrefs.c, but there is no other redirection.
3322 */
3323 econtext->ecxt_scantuple = existing;
3324 econtext->ecxt_innertuple = excludedSlot;
3325 econtext->ecxt_outertuple = NULL;
3326
3327 if (!ExecQual(onConflictSelectWhere, econtext))
3328 {
3329 ExecClearTuple(existing); /* see return below */
3330 InstrCountFiltered1(&mtstate->ps, 1);
3331 return true; /* done with the tuple */
3332 }
3333
3334 if (resultRelInfo->ri_WithCheckOptions != NIL)
3335 {
3336 /*
3337 * Check target's existing tuple against SELECT-applicable USING
3338 * security barrier quals (if any), enforced here as RLS checks/WCOs.
3339 *
3340 * The rewriter creates WCOs from the USING quals of SELECT policies,
3341 * and stores them as WCOs of "kind" WCO_RLS_CONFLICT_CHECK. If FOR
3342 * UPDATE/SHARE was specified, UPDATE permissions are required on the
3343 * target table, and the rewriter also adds WCOs built from the USING
3344 * quals of UPDATE policies, using WCOs of the same kind, and this
3345 * check enforces them too.
3346 */
3348 existing,
3349 mtstate->ps.state);
3350 }
3351
3352 /* RETURNING is required for DO SELECT */
3353 Assert(resultRelInfo->ri_projectReturning);
3354
3355 *returning = ExecProcessReturning(context, resultRelInfo, false,
3356 existing, existing, context->planSlot);
3357
3358 if (canSetTag)
3359 context->estate->es_processed++;
3360
3361 /*
3362 * Before releasing the existing tuple, make sure that the returning slot
3363 * has a local copy of any pass-by-reference values.
3364 */
3365 ExecMaterializeSlot(*returning);
3366
3367 /*
3368 * Clear out existing tuple, as there might not be another conflict among
3369 * the next input rows. Don't want to hold resources till the end of the
3370 * query.
3371 */
3373
3374 return true;
3375}
3376
3377/*
3378 * Perform MERGE.
3379 */
3380static TupleTableSlot *
3382 ItemPointer tupleid, HeapTuple oldtuple, bool canSetTag)
3383{
3385 bool matched;
3386
3387 /*-----
3388 * If we are dealing with a WHEN MATCHED case, tupleid or oldtuple is
3389 * valid, depending on whether the result relation is a table or a view.
3390 * We execute the first action for which the additional WHEN MATCHED AND
3391 * quals pass. If an action without quals is found, that action is
3392 * executed.
3393 *
3394 * Similarly, in the WHEN NOT MATCHED BY SOURCE case, tupleid or oldtuple
3395 * is valid, and we look at the given WHEN NOT MATCHED BY SOURCE actions
3396 * in sequence until one passes. This is almost identical to the WHEN
3397 * MATCHED case, and both cases are handled by ExecMergeMatched().
3398 *
3399 * Finally, in the WHEN NOT MATCHED [BY TARGET] case, both tupleid and
3400 * oldtuple are invalid, and we look at the given WHEN NOT MATCHED [BY
3401 * TARGET] actions in sequence until one passes.
3402 *
3403 * Things get interesting in case of concurrent update/delete of the
3404 * target tuple. Such concurrent update/delete is detected while we are
3405 * executing a WHEN MATCHED or WHEN NOT MATCHED BY SOURCE action.
3406 *
3407 * A concurrent update can:
3408 *
3409 * 1. modify the target tuple so that the results from checking any
3410 * additional quals attached to WHEN MATCHED or WHEN NOT MATCHED BY
3411 * SOURCE actions potentially change, but the result from the join
3412 * quals does not change.
3413 *
3414 * In this case, we are still dealing with the same kind of match
3415 * (MATCHED or NOT MATCHED BY SOURCE). We recheck the same list of
3416 * actions from the start and choose the first one that satisfies the
3417 * new target tuple.
3418 *
3419 * 2. modify the target tuple in the WHEN MATCHED case so that the join
3420 * quals no longer pass and hence the source and target tuples no
3421 * longer match.
3422 *
3423 * In this case, we are now dealing with a NOT MATCHED case, and we
3424 * process both WHEN NOT MATCHED BY SOURCE and WHEN NOT MATCHED [BY
3425 * TARGET] actions. First ExecMergeMatched() processes the list of
3426 * WHEN NOT MATCHED BY SOURCE actions in sequence until one passes,
3427 * then ExecMergeNotMatched() processes any WHEN NOT MATCHED [BY
3428 * TARGET] actions in sequence until one passes. Thus we may execute
3429 * two actions; one of each kind.
3430 *
3431 * Thus we support concurrent updates that turn MATCHED candidate rows
3432 * into NOT MATCHED rows. However, we do not attempt to support cases
3433 * that would turn NOT MATCHED rows into MATCHED rows, or which would
3434 * cause a target row to match a different source row.
3435 *
3436 * A concurrent delete changes a WHEN MATCHED case to WHEN NOT MATCHED
3437 * [BY TARGET].
3438 *
3439 * ExecMergeMatched() takes care of following the update chain and
3440 * re-finding the qualifying WHEN MATCHED or WHEN NOT MATCHED BY SOURCE
3441 * action, as long as the target tuple still exists. If the target tuple
3442 * gets deleted or a concurrent update causes the join quals to fail, it
3443 * returns a matched status of false and we call ExecMergeNotMatched().
3444 * Given that ExecMergeMatched() always makes progress by following the
3445 * update chain and we never switch from ExecMergeNotMatched() to
3446 * ExecMergeMatched(), there is no risk of a livelock.
3447 */
3448 matched = tupleid != NULL || oldtuple != NULL;
3449 if (matched)
3450 rslot = ExecMergeMatched(context, resultRelInfo, tupleid, oldtuple,
3451 canSetTag, &matched);
3452
3453 /*
3454 * Deal with the NOT MATCHED case (either a NOT MATCHED tuple from the
3455 * join, or a previously MATCHED tuple for which ExecMergeMatched() set
3456 * "matched" to false, indicating that it no longer matches).
3457 */
3458 if (!matched)
3459 {
3460 /*
3461 * If a concurrent update turned a MATCHED case into a NOT MATCHED
3462 * case, and we have both WHEN NOT MATCHED BY SOURCE and WHEN NOT
3463 * MATCHED [BY TARGET] actions, and there is a RETURNING clause,
3464 * ExecMergeMatched() may have already executed a WHEN NOT MATCHED BY
3465 * SOURCE action, and computed the row to return. If so, we cannot
3466 * execute a WHEN NOT MATCHED [BY TARGET] action now, so mark it as
3467 * pending (to be processed on the next call to ExecModifyTable()).
3468 * Otherwise, just process the action now.
3469 */
3470 if (rslot == NULL)
3471 rslot = ExecMergeNotMatched(context, resultRelInfo, canSetTag);
3472 else
3473 context->mtstate->mt_merge_pending_not_matched = context->planSlot;
3474 }
3475
3476 return rslot;
3477}
3478
3479/*
3480 * Check and execute the first qualifying MATCHED or NOT MATCHED BY SOURCE
3481 * action, depending on whether the join quals are satisfied. If the target
3482 * relation is a table, the current target tuple is identified by tupleid.
3483 * Otherwise, if the target relation is a view, oldtuple is the current target
3484 * tuple from the view.
3485 *
3486 * We start from the first WHEN MATCHED or WHEN NOT MATCHED BY SOURCE action
3487 * and check if the WHEN quals pass, if any. If the WHEN quals for the first
3488 * action do not pass, we check the second, then the third and so on. If we
3489 * reach the end without finding a qualifying action, we return NULL.
3490 * Otherwise, we execute the qualifying action and return its RETURNING
3491 * result, if any, or NULL.
3492 *
3493 * On entry, "*matched" is assumed to be true. If a concurrent update or
3494 * delete is detected that causes the join quals to no longer pass, we set it
3495 * to false, indicating that the caller should process any NOT MATCHED [BY
3496 * TARGET] actions.
3497 *
3498 * After a concurrent update, we restart from the first action to look for a
3499 * new qualifying action to execute. If the join quals originally passed, and
3500 * the concurrent update caused them to no longer pass, then we switch from
3501 * the MATCHED to the NOT MATCHED BY SOURCE list of actions before restarting
3502 * (and setting "*matched" to false). As a result we may execute a WHEN NOT
3503 * MATCHED BY SOURCE action, and set "*matched" to false, causing the caller
3504 * to also execute a WHEN NOT MATCHED [BY TARGET] action.
3505 */
3506static TupleTableSlot *
3508 ItemPointer tupleid, HeapTuple oldtuple, bool canSetTag,
3509 bool *matched)
3510{
3511 ModifyTableState *mtstate = context->mtstate;
3512 List **mergeActions = resultRelInfo->ri_MergeActions;
3517 EState *estate = context->estate;
3518 ExprContext *econtext = mtstate->ps.ps_ExprContext;
3519 bool isNull;
3520 EPQState *epqstate = &mtstate->mt_epqstate;
3521 ListCell *l;
3522
3523 /* Expect matched to be true on entry */
3524 Assert(*matched);
3525
3526 /*
3527 * If there are no WHEN MATCHED or WHEN NOT MATCHED BY SOURCE actions, we
3528 * are done.
3529 */
3532 return NULL;
3533
3534 /*
3535 * Make tuple and any needed join variables available to ExecQual and
3536 * ExecProject. The target's existing tuple is installed in the scantuple.
3537 * This target relation's slot is required only in the case of a MATCHED
3538 * or NOT MATCHED BY SOURCE tuple and UPDATE/DELETE actions.
3539 */
3540 econtext->ecxt_scantuple = resultRelInfo->ri_oldTupleSlot;
3541 econtext->ecxt_innertuple = context->planSlot;
3542 econtext->ecxt_outertuple = NULL;
3543
3544 /*
3545 * This routine is only invoked for matched target rows, so we should
3546 * either have the tupleid of the target row, or an old tuple from the
3547 * target wholerow junk attr.
3548 */
3549 Assert(tupleid != NULL || oldtuple != NULL);
3551 if (oldtuple != NULL)
3552 {
3553 Assert(!resultRelInfo->ri_needLockTagTuple);
3554 ExecForceStoreHeapTuple(oldtuple, resultRelInfo->ri_oldTupleSlot,
3555 false);
3556 }
3557 else
3558 {
3559 if (resultRelInfo->ri_needLockTagTuple)
3560 {
3561 /*
3562 * This locks even for CMD_DELETE, for CMD_NOTHING, and for tuples
3563 * that don't match mas_whenqual. MERGE on system catalogs is a
3564 * minor use case, so don't bother optimizing those.
3565 */
3566 LockTuple(resultRelInfo->ri_RelationDesc, tupleid,
3568 lockedtid = *tupleid;
3569 }
3571 tupleid,
3573 resultRelInfo->ri_oldTupleSlot))
3574 elog(ERROR, "failed to fetch the target tuple");
3575 }
3576
3577 /*
3578 * Test the join condition. If it's satisfied, perform a MATCHED action.
3579 * Otherwise, perform a NOT MATCHED BY SOURCE action.
3580 *
3581 * Note that this join condition will be NULL if there are no NOT MATCHED
3582 * BY SOURCE actions --- see transform_MERGE_to_join(). In that case, we
3583 * need only consider MATCHED actions here.
3584 */
3585 if (ExecQual(resultRelInfo->ri_MergeJoinCondition, econtext))
3587 else
3589
3591
3592 foreach(l, actionStates)
3593 {
3595 CmdType commandType = relaction->mas_action->commandType;
3598
3599 /*
3600 * Test condition, if any.
3601 *
3602 * In the absence of any condition, we perform the action
3603 * unconditionally (no need to check separately since ExecQual() will
3604 * return true if there are no conditions to evaluate).
3605 */
3606 if (!ExecQual(relaction->mas_whenqual, econtext))
3607 continue;
3608
3609 /*
3610 * Check if the existing target tuple meets the USING checks of
3611 * UPDATE/DELETE RLS policies. If those checks fail, we throw an
3612 * error.
3613 *
3614 * The WITH CHECK quals for UPDATE RLS policies are applied in
3615 * ExecUpdateAct() and hence we need not do anything special to handle
3616 * them.
3617 *
3618 * NOTE: We must do this after WHEN quals are evaluated, so that we
3619 * check policies only when they matter.
3620 */
3621 if (resultRelInfo->ri_WithCheckOptions && commandType != CMD_NOTHING)
3622 {
3623 ExecWithCheckOptions(commandType == CMD_UPDATE ?
3625 resultRelInfo,
3626 resultRelInfo->ri_oldTupleSlot,
3627 context->mtstate->ps.state);
3628 }
3629
3630 /* Perform stated action */
3631 switch (commandType)
3632 {
3633 case CMD_UPDATE:
3634
3635 /*
3636 * Project the output tuple, and use that to update the table.
3637 * We don't need to filter out junk attributes, because the
3638 * UPDATE action's targetlist doesn't have any.
3639 */
3640 newslot = ExecProject(relaction->mas_proj);
3641
3642 mtstate->mt_merge_action = relaction;
3643 if (!ExecUpdatePrologue(context, resultRelInfo,
3645 {
3646 if (result == TM_Ok)
3647 goto out; /* "do nothing" */
3648
3649 break; /* concurrent update/delete */
3650 }
3651
3652 /* INSTEAD OF ROW UPDATE Triggers */
3653 if (resultRelInfo->ri_TrigDesc &&
3654 resultRelInfo->ri_TrigDesc->trig_update_instead_row)
3655 {
3656 if (!ExecIRUpdateTriggers(estate, resultRelInfo,
3657 oldtuple, newslot))
3658 goto out; /* "do nothing" */
3659 }
3660 else
3661 {
3662 /* checked ri_needLockTagTuple above */
3663 Assert(oldtuple == NULL);
3664
3665 result = ExecUpdateAct(context, resultRelInfo, tupleid,
3666 NULL, newslot, canSetTag,
3667 &updateCxt);
3668
3669 /*
3670 * As in ExecUpdate(), if ExecUpdateAct() reports that a
3671 * cross-partition update was done, then there's nothing
3672 * else for us to do --- the UPDATE has been turned into a
3673 * DELETE and an INSERT, and we must not perform any of
3674 * the usual post-update tasks. Also, the RETURNING tuple
3675 * (if any) has been projected, so we can just return
3676 * that.
3677 */
3678 if (updateCxt.crossPartUpdate)
3679 {
3680 mtstate->mt_merge_updated += 1;
3681 rslot = context->cpUpdateReturningSlot;
3682 goto out;
3683 }
3684 }
3685
3686 if (result == TM_Ok)
3687 {
3688 ExecUpdateEpilogue(context, &updateCxt, resultRelInfo,
3689 tupleid, NULL, newslot);
3690 mtstate->mt_merge_updated += 1;
3691 }
3692 break;
3693
3694 case CMD_DELETE:
3695 mtstate->mt_merge_action = relaction;
3696 if (!ExecDeletePrologue(context, resultRelInfo, tupleid,
3697 NULL, NULL, &result))
3698 {
3699 if (result == TM_Ok)
3700 goto out; /* "do nothing" */
3701
3702 break; /* concurrent update/delete */
3703 }
3704
3705 /* INSTEAD OF ROW DELETE Triggers */
3706 if (resultRelInfo->ri_TrigDesc &&
3707 resultRelInfo->ri_TrigDesc->trig_delete_instead_row)
3708 {
3709 if (!ExecIRDeleteTriggers(estate, resultRelInfo,
3710 oldtuple))
3711 goto out; /* "do nothing" */
3712 }
3713 else
3714 {
3715 /* checked ri_needLockTagTuple above */
3716 Assert(oldtuple == NULL);
3717
3718 result = ExecDeleteAct(context, resultRelInfo, tupleid,
3719 false);
3720 }
3721
3722 if (result == TM_Ok)
3723 {
3724 ExecDeleteEpilogue(context, resultRelInfo, tupleid, NULL,
3725 false);
3726 mtstate->mt_merge_deleted += 1;
3727 }
3728 break;
3729
3730 case CMD_NOTHING:
3731 /* Doing nothing is always OK */
3732 result = TM_Ok;
3733 break;
3734
3735 default:
3736 elog(ERROR, "unknown action in MERGE WHEN clause");
3737 }
3738
3739 switch (result)
3740 {
3741 case TM_Ok:
3742 /* all good; perform final actions */
3743 if (canSetTag && commandType != CMD_NOTHING)
3744 (estate->es_processed)++;
3745
3746 break;
3747
3748 case TM_SelfModified:
3749
3750 /*
3751 * The target tuple was already updated or deleted by the
3752 * current command, or by a later command in the current
3753 * transaction. The former case is explicitly disallowed by
3754 * the SQL standard for MERGE, which insists that the MERGE
3755 * join condition should not join a target row to more than
3756 * one source row.
3757 *
3758 * The latter case arises if the tuple is modified by a
3759 * command in a BEFORE trigger, or perhaps by a command in a
3760 * volatile function used in the query. In such situations we
3761 * should not ignore the MERGE action, but it is equally
3762 * unsafe to proceed. We don't want to discard the original
3763 * MERGE action while keeping the triggered actions based on
3764 * it; and it would be no better to allow the original MERGE
3765 * action while discarding the updates that it triggered. So
3766 * throwing an error is the only safe course.
3767 */
3768 if (context->tmfd.cmax != estate->es_output_cid)
3769 ereport(ERROR,
3771 errmsg("tuple to be updated or deleted was already modified by an operation triggered by the current command"),
3772 errhint("Consider using an AFTER trigger instead of a BEFORE trigger to propagate changes to other rows.")));
3773
3775 ereport(ERROR,
3777 /* translator: %s is a SQL command name */
3778 errmsg("%s command cannot affect row a second time",
3779 "MERGE"),
3780 errhint("Ensure that not more than one source row matches any one target row.")));
3781
3782 /* This shouldn't happen */
3783 elog(ERROR, "attempted to update or delete invisible tuple");
3784 break;
3785
3786 case TM_Deleted:
3788 ereport(ERROR,
3790 errmsg("could not serialize access due to concurrent delete")));
3791
3792 /*
3793 * If the tuple was already deleted, set matched to false to
3794 * let caller handle it under NOT MATCHED [BY TARGET] clauses.
3795 */
3796 *matched = false;
3797 goto out;
3798
3799 case TM_Updated:
3800 {
3801 bool was_matched;
3804 *inputslot;
3805 LockTupleMode lockmode;
3806
3808 ereport(ERROR,
3810 errmsg("could not serialize access due to concurrent update")));
3811
3812 /*
3813 * The target tuple was concurrently updated by some other
3814 * transaction. If we are currently processing a MATCHED
3815 * action, use EvalPlanQual() with the new version of the
3816 * tuple and recheck the join qual, to detect a change
3817 * from the MATCHED to the NOT MATCHED cases. If we are
3818 * already processing a NOT MATCHED BY SOURCE action, we
3819 * skip this (cannot switch from NOT MATCHED BY SOURCE to
3820 * MATCHED).
3821 */
3822 was_matched = relaction->mas_action->matchKind == MERGE_WHEN_MATCHED;
3823 resultRelationDesc = resultRelInfo->ri_RelationDesc;
3824 lockmode = ExecUpdateLockMode(estate, resultRelInfo);
3825
3826 if (was_matched)
3827 inputslot = EvalPlanQualSlot(epqstate, resultRelationDesc,
3828 resultRelInfo->ri_RangeTableIndex);
3829 else
3830 inputslot = resultRelInfo->ri_oldTupleSlot;
3831
3833 estate->es_snapshot,
3834 inputslot, estate->es_output_cid,
3835 lockmode, LockWaitBlock,
3837 &context->tmfd);
3838 switch (result)
3839 {
3840 case TM_Ok:
3841
3842 /*
3843 * If the tuple was updated and migrated to
3844 * another partition concurrently, the current
3845 * MERGE implementation can't follow. There's
3846 * probably a better way to handle this case, but
3847 * it'd require recognizing the relation to which
3848 * the tuple moved, and setting our current
3849 * resultRelInfo to that.
3850 */
3852 ereport(ERROR,
3854 errmsg("tuple to be merged was already moved to another partition due to concurrent update")));
3855
3856 /*
3857 * If this was a MATCHED case, use EvalPlanQual()
3858 * to recheck the join condition.
3859 */
3860 if (was_matched)
3861 {
3862 epqslot = EvalPlanQual(epqstate,
3864 resultRelInfo->ri_RangeTableIndex,
3865 inputslot);
3866
3867 /*
3868 * If the subplan didn't return a tuple, then
3869 * we must be dealing with an inner join for
3870 * which the join condition no longer matches.
3871 * This can only happen if there are no NOT
3872 * MATCHED actions, and so there is nothing
3873 * more to do.
3874 */
3875 if (TupIsNull(epqslot))
3876 goto out;
3877
3878 /*
3879 * If we got a NULL ctid from the subplan, the
3880 * join quals no longer pass and we switch to
3881 * the NOT MATCHED BY SOURCE case.
3882 */
3884 resultRelInfo->ri_RowIdAttNo,
3885 &isNull);
3886 if (isNull)
3887 *matched = false;
3888
3889 /*
3890 * Otherwise, recheck the join quals to see if
3891 * we need to switch to the NOT MATCHED BY
3892 * SOURCE case.
3893 */
3894 if (resultRelInfo->ri_needLockTagTuple)
3895 {
3897 UnlockTuple(resultRelInfo->ri_RelationDesc, &lockedtid,
3899 LockTuple(resultRelInfo->ri_RelationDesc, tupleid,
3901 lockedtid = *tupleid;
3902 }
3903
3905 tupleid,
3907 resultRelInfo->ri_oldTupleSlot))
3908 elog(ERROR, "failed to fetch the target tuple");
3909
3910 if (*matched)
3911 *matched = ExecQual(resultRelInfo->ri_MergeJoinCondition,
3912 econtext);
3913
3914 /* Switch lists, if necessary */
3915 if (!*matched)
3916 {
3918
3919 /*
3920 * If we have both NOT MATCHED BY SOURCE
3921 * and NOT MATCHED BY TARGET actions (a
3922 * full join between the source and target
3923 * relations), the single previously
3924 * matched tuple from the outer plan node
3925 * is treated as two not matched tuples,
3926 * in the same way as if they had not
3927 * matched to start with. Therefore, we
3928 * must adjust the outer plan node's tuple
3929 * count, if we're instrumenting the
3930 * query, to get the correct "skipped" row
3931 * count --- see show_modifytable_info().
3932 */
3933 if (outerPlanState(mtstate)->instrument &&
3936 InstrUpdateTupleCount(outerPlanState(mtstate)->instrument, 1.0);
3937 }
3938 }
3939
3940 /*
3941 * Loop back and process the MATCHED or NOT
3942 * MATCHED BY SOURCE actions from the start.
3943 */
3944 goto lmerge_matched;
3945
3946 case TM_Deleted:
3947
3948 /*
3949 * tuple already deleted; tell caller to run NOT
3950 * MATCHED [BY TARGET] actions
3951 */
3952 *matched = false;
3953 goto out;
3954
3955 case TM_SelfModified:
3956
3957 /*
3958 * This can be reached when following an update
3959 * chain from a tuple updated by another session,
3960 * reaching a tuple that was already updated or
3961 * deleted by the current command, or by a later
3962 * command in the current transaction. As above,
3963 * this should always be treated as an error.
3964 */
3965 if (context->tmfd.cmax != estate->es_output_cid)
3966 ereport(ERROR,
3968 errmsg("tuple to be updated or deleted was already modified by an operation triggered by the current command"),
3969 errhint("Consider using an AFTER trigger instead of a BEFORE trigger to propagate changes to other rows.")));
3970
3972 ereport(ERROR,
3974 /* translator: %s is a SQL command name */
3975 errmsg("%s command cannot affect row a second time",
3976 "MERGE"),
3977 errhint("Ensure that not more than one source row matches any one target row.")));
3978
3979 /* This shouldn't happen */
3980 elog(ERROR, "attempted to update or delete invisible tuple");
3981 goto out;
3982
3983 default:
3984 /* see table_tuple_lock call in ExecDelete() */
3985 elog(ERROR, "unexpected table_tuple_lock status: %u",
3986 result);
3987 goto out;
3988 }
3989 }
3990
3991 case TM_Invisible:
3992 case TM_WouldBlock:
3993 case TM_BeingModified:
3994 /* these should not occur */
3995 elog(ERROR, "unexpected tuple operation result: %d", result);
3996 break;
3997 }
3998
3999 /* Process RETURNING if present */
4000 if (resultRelInfo->ri_projectReturning)
4001 {
4002 switch (commandType)
4003 {
4004 case CMD_UPDATE:
4005 rslot = ExecProcessReturning(context,
4006 resultRelInfo,
4007 false,
4008 resultRelInfo->ri_oldTupleSlot,
4009 newslot,
4010 context->planSlot);
4011 break;
4012
4013 case CMD_DELETE:
4014 rslot = ExecProcessReturning(context,
4015 resultRelInfo,
4016 true,
4017 resultRelInfo->ri_oldTupleSlot,
4018 NULL,
4019 context->planSlot);
4020 break;
4021
4022 case CMD_NOTHING:
4023 break;
4024
4025 default:
4026 elog(ERROR, "unrecognized commandType: %d",
4027 (int) commandType);
4028 }
4029 }
4030
4031 /*
4032 * We've activated one of the WHEN clauses, so we don't search
4033 * further. This is required behaviour, not an optimization.
4034 */
4035 break;
4036 }
4037
4038 /*
4039 * Successfully executed an action or no qualifying action was found.
4040 */
4041out:
4043 UnlockTuple(resultRelInfo->ri_RelationDesc, &lockedtid,
4045 return rslot;
4046}
4047
4048/*
4049 * Execute the first qualifying NOT MATCHED [BY TARGET] action.
4050 */
4051static TupleTableSlot *
4053 bool canSetTag)
4054{
4055 ModifyTableState *mtstate = context->mtstate;
4056 ExprContext *econtext = mtstate->ps.ps_ExprContext;
4059 ListCell *l;
4060
4061 /*
4062 * For INSERT actions, the root relation's merge action is OK since the
4063 * INSERT's targetlist and the WHEN conditions can only refer to the
4064 * source relation and hence it does not matter which result relation we
4065 * work with.
4066 *
4067 * XXX does this mean that we can avoid creating copies of actionStates on
4068 * partitioned tables, for not-matched actions?
4069 */
4071
4072 /*
4073 * Make source tuple available to ExecQual and ExecProject. We don't need
4074 * the target tuple, since the WHEN quals and targetlist can't refer to
4075 * the target columns.
4076 */
4077 econtext->ecxt_scantuple = NULL;
4078 econtext->ecxt_innertuple = context->planSlot;
4079 econtext->ecxt_outertuple = NULL;
4080
4081 foreach(l, actionStates)
4082 {
4083 MergeActionState *action = (MergeActionState *) lfirst(l);
4084 CmdType commandType = action->mas_action->commandType;
4086
4087 /*
4088 * Test condition, if any.
4089 *
4090 * In the absence of any condition, we perform the action
4091 * unconditionally (no need to check separately since ExecQual() will
4092 * return true if there are no conditions to evaluate).
4093 */
4094 if (!ExecQual(action->mas_whenqual, econtext))
4095 continue;
4096
4097 /* Perform stated action */
4098 switch (commandType)
4099 {
4100 case CMD_INSERT:
4101
4102 /*
4103 * Project the tuple. In case of a partitioned table, the
4104 * projection was already built to use the root's descriptor,
4105 * so we don't need to map the tuple here.
4106 */
4107 newslot = ExecProject(action->mas_proj);
4108 mtstate->mt_merge_action = action;
4109
4110 rslot = ExecInsert(context, mtstate->rootResultRelInfo,
4111 newslot, canSetTag, NULL, NULL);
4112 mtstate->mt_merge_inserted += 1;
4113 break;
4114 case CMD_NOTHING:
4115 /* Do nothing */
4116 break;
4117 default:
4118 elog(ERROR, "unknown action in MERGE WHEN NOT MATCHED clause");
4119 }
4120
4121 /*
4122 * We've activated one of the WHEN clauses, so we don't search
4123 * further. This is required behaviour, not an optimization.
4124 */
4125 break;
4126 }
4127
4128 return rslot;
4129}
4130
4131/*
4132 * Initialize state for execution of MERGE.
4133 */
4134void
4136{
4137 List *mergeActionLists = mtstate->mt_mergeActionLists;
4138 List *mergeJoinConditions = mtstate->mt_mergeJoinConditions;
4140 ResultRelInfo *resultRelInfo;
4141 ExprContext *econtext;
4142 ListCell *lc;
4143 int i;
4144
4145 if (mergeActionLists == NIL)
4146 return;
4147
4148 mtstate->mt_merge_subcommands = 0;
4149
4150 if (mtstate->ps.ps_ExprContext == NULL)
4151 ExecAssignExprContext(estate, &mtstate->ps);
4152 econtext = mtstate->ps.ps_ExprContext;
4153
4154 /*
4155 * Create a MergeActionState for each action on the mergeActionList and
4156 * add it to either a list of matched actions or not-matched actions.
4157 *
4158 * Similar logic appears in ExecInitPartitionInfo(), so if changing
4159 * anything here, do so there too.
4160 */
4161 i = 0;
4162 foreach(lc, mergeActionLists)
4163 {
4164 List *mergeActionList = lfirst(lc);
4165 Node *joinCondition;
4167 ListCell *l;
4168
4169 joinCondition = (Node *) list_nth(mergeJoinConditions, i);
4170 resultRelInfo = mtstate->resultRelInfo + i;
4171 i++;
4173
4174 /* initialize slots for MERGE fetches from this rel */
4175 if (unlikely(!resultRelInfo->ri_projectNewInfoValid))
4176 ExecInitMergeTupleSlots(mtstate, resultRelInfo);
4177
4178 /* initialize state for join condition checking */
4179 resultRelInfo->ri_MergeJoinCondition =
4180 ExecInitQual((List *) joinCondition, &mtstate->ps);
4181
4182 foreach(l, mergeActionList)
4183 {
4184 MergeAction *action = (MergeAction *) lfirst(l);
4185 MergeActionState *action_state;
4188
4189 /*
4190 * Build action merge state for this rel. (For partitions,
4191 * equivalent code exists in ExecInitPartitionInfo.)
4192 */
4193 action_state = makeNode(MergeActionState);
4194 action_state->mas_action = action;
4195 action_state->mas_whenqual = ExecInitQual((List *) action->qual,
4196 &mtstate->ps);
4197
4198 /*
4199 * We create three lists - one for each MergeMatchKind - and stick
4200 * the MergeActionState into the appropriate list.
4201 */
4202 resultRelInfo->ri_MergeActions[action->matchKind] =
4203 lappend(resultRelInfo->ri_MergeActions[action->matchKind],
4204 action_state);
4205
4206 switch (action->commandType)
4207 {
4208 case CMD_INSERT:
4209 /* INSERT actions always use rootRelInfo */
4210 ExecCheckPlanOutput(rootRelInfo->ri_RelationDesc,
4211 action->targetList);
4212
4213 /*
4214 * If the MERGE targets a partitioned table, any INSERT
4215 * actions must be routed through it, not the child
4216 * relations. Initialize the routing struct and the root
4217 * table's "new" tuple slot for that, if not already done.
4218 * The projection we prepare, for all relations, uses the
4219 * root relation descriptor, and targets the plan's root
4220 * slot. (This is consistent with the fact that we
4221 * checked the plan output to match the root relation,
4222 * above.)
4223 */
4224 if (rootRelInfo->ri_RelationDesc->rd_rel->relkind ==
4226 {
4227 if (mtstate->mt_partition_tuple_routing == NULL)
4228 {
4229 /*
4230 * Initialize planstate for routing if not already
4231 * done.
4232 *
4233 * Note that the slot is managed as a standalone
4234 * slot belonging to ModifyTableState, so we pass
4235 * NULL for the 2nd argument.
4236 */
4237 mtstate->mt_root_tuple_slot =
4238 table_slot_create(rootRelInfo->ri_RelationDesc,
4239 NULL);
4242 rootRelInfo->ri_RelationDesc);
4243 }
4244 tgtslot = mtstate->mt_root_tuple_slot;
4245 tgtdesc = RelationGetDescr(rootRelInfo->ri_RelationDesc);
4246 }
4247 else
4248 {
4249 /*
4250 * If the MERGE targets an inherited table, we insert
4251 * into the root table, so we must initialize its
4252 * "new" tuple slot, if not already done, and use its
4253 * relation descriptor for the projection.
4254 *
4255 * For non-inherited tables, rootRelInfo and
4256 * resultRelInfo are the same, and the "new" tuple
4257 * slot will already have been initialized.
4258 */
4259 if (rootRelInfo->ri_newTupleSlot == NULL)
4260 rootRelInfo->ri_newTupleSlot =
4261 table_slot_create(rootRelInfo->ri_RelationDesc,
4262 &estate->es_tupleTable);
4263
4264 tgtslot = rootRelInfo->ri_newTupleSlot;
4265 tgtdesc = RelationGetDescr(rootRelInfo->ri_RelationDesc);
4266 }
4267
4268 action_state->mas_proj =
4269 ExecBuildProjectionInfo(action->targetList, econtext,
4270 tgtslot,
4271 &mtstate->ps,
4272 tgtdesc);
4273
4275 break;
4276 case CMD_UPDATE:
4277 action_state->mas_proj =
4278 ExecBuildUpdateProjection(action->targetList,
4279 true,
4280 action->updateColnos,
4282 econtext,
4283 resultRelInfo->ri_newTupleSlot,
4284 &mtstate->ps);
4286 break;
4287 case CMD_DELETE:
4289 break;
4290 case CMD_NOTHING:
4291 break;
4292 default:
4293 elog(ERROR, "unknown action in MERGE WHEN clause");
4294 break;
4295 }
4296 }
4297 }
4298
4299 /*
4300 * If the MERGE targets an inherited table, any INSERT actions will use
4301 * rootRelInfo, and rootRelInfo will not be in the resultRelInfo array.
4302 * Therefore we must initialize its WITH CHECK OPTION constraints and
4303 * RETURNING projection, as ExecInitModifyTable did for the resultRelInfo
4304 * entries.
4305 *
4306 * Note that the planner does not build a withCheckOptionList or
4307 * returningList for the root relation, but as in ExecInitPartitionInfo,
4308 * we can use the first resultRelInfo entry as a reference to calculate
4309 * the attno's for the root table.
4310 */
4311 if (rootRelInfo != mtstate->resultRelInfo &&
4313 (mtstate->mt_merge_subcommands & MERGE_INSERT) != 0)
4314 {
4315 ModifyTable *node = (ModifyTable *) mtstate->ps.plan;
4316 Relation rootRelation = rootRelInfo->ri_RelationDesc;
4320 bool found_whole_row;
4321
4322 if (node->withCheckOptionLists != NIL)
4323 {
4324 List *wcoList;
4325 List *wcoExprs = NIL;
4326
4327 /* There should be as many WCO lists as result rels */
4330
4331 /*
4332 * Use the first WCO list as a reference. In the most common case,
4333 * this will be for the same relation as rootRelInfo, and so there
4334 * will be no need to adjust its attno's.
4335 */
4337 if (rootRelation != firstResultRel)
4338 {
4339 /* Convert any Vars in it to contain the root's attno's */
4340 part_attmap =
4343 false);
4344
4345 wcoList = (List *)
4347 firstVarno, 0,
4349 RelationGetForm(rootRelation)->reltype,
4350 &found_whole_row);
4351 }
4352
4353 foreach(lc, wcoList)
4354 {
4357 &mtstate->ps);
4358
4360 }
4361
4362 rootRelInfo->ri_WithCheckOptions = wcoList;
4363 rootRelInfo->ri_WithCheckOptionExprs = wcoExprs;
4364 }
4365
4366 if (node->returningLists != NIL)
4367 {
4368 List *returningList;
4369
4370 /* There should be as many returning lists as result rels */
4373
4374 /*
4375 * Use the first returning list as a reference. In the most common
4376 * case, this will be for the same relation as rootRelInfo, and so
4377 * there will be no need to adjust its attno's.
4378 */
4379 returningList = linitial(node->returningLists);
4380 if (rootRelation != firstResultRel)
4381 {
4382 /* Convert any Vars in it to contain the root's attno's */
4383 if (part_attmap == NULL)
4384 part_attmap =
4387 false);
4388
4389 returningList = (List *)
4390 map_variable_attnos((Node *) returningList,
4391 firstVarno, 0,
4393 RelationGetForm(rootRelation)->reltype,
4394 &found_whole_row);
4395 }
4396 rootRelInfo->ri_returningList = returningList;
4397
4398 /* Initialize the RETURNING projection */
4399 rootRelInfo->ri_projectReturning =
4400 ExecBuildProjectionInfo(returningList, econtext,
4401 mtstate->ps.ps_ResultTupleSlot,
4402 &mtstate->ps,
4403 RelationGetDescr(rootRelation));
4404 }
4405 }
4406}
4407
4408/*
4409 * Initializes the tuple slots in a ResultRelInfo for any MERGE action.
4410 *
4411 * We mark 'projectNewInfoValid' even though the projections themselves
4412 * are not initialized here.
4413 */
4414void
4416 ResultRelInfo *resultRelInfo)
4417{
4418 EState *estate = mtstate->ps.state;
4419
4420 Assert(!resultRelInfo->ri_projectNewInfoValid);
4421
4422 resultRelInfo->ri_oldTupleSlot =
4423 table_slot_create(resultRelInfo->ri_RelationDesc,
4424 &estate->es_tupleTable);
4425 resultRelInfo->ri_newTupleSlot =
4426 table_slot_create(resultRelInfo->ri_RelationDesc,
4427 &estate->es_tupleTable);
4428 resultRelInfo->ri_projectNewInfoValid = true;
4429}
4430
4431/*
4432 * Process BEFORE EACH STATEMENT triggers
4433 */
4434static void
4436{
4437 ModifyTable *plan = (ModifyTable *) node->ps.plan;
4438 ResultRelInfo *resultRelInfo = node->rootResultRelInfo;
4439
4440 switch (node->operation)
4441 {
4442 case CMD_INSERT:
4443 ExecBSInsertTriggers(node->ps.state, resultRelInfo);
4444 if (plan->onConflictAction == ONCONFLICT_UPDATE)
4446 resultRelInfo);
4447 break;
4448 case CMD_UPDATE:
4449 ExecBSUpdateTriggers(node->ps.state, resultRelInfo);
4450 break;
4451 case CMD_DELETE:
4452 ExecBSDeleteTriggers(node->ps.state, resultRelInfo);
4453 break;
4454 case CMD_MERGE:
4456 ExecBSInsertTriggers(node->ps.state, resultRelInfo);
4458 ExecBSUpdateTriggers(node->ps.state, resultRelInfo);
4460 ExecBSDeleteTriggers(node->ps.state, resultRelInfo);
4461 break;
4462 default:
4463 elog(ERROR, "unknown operation");
4464 break;
4465 }
4466}
4467
4468/*
4469 * Process AFTER EACH STATEMENT triggers
4470 */
4471static void
4473{
4474 ModifyTable *plan = (ModifyTable *) node->ps.plan;
4475 ResultRelInfo *resultRelInfo = node->rootResultRelInfo;
4476
4477 switch (node->operation)
4478 {
4479 case CMD_INSERT:
4480 if (plan->onConflictAction == ONCONFLICT_UPDATE)
4482 resultRelInfo,
4484 ExecASInsertTriggers(node->ps.state, resultRelInfo,
4485 node->mt_transition_capture);
4486 break;
4487 case CMD_UPDATE:
4488 ExecASUpdateTriggers(node->ps.state, resultRelInfo,
4489 node->mt_transition_capture);
4490 break;
4491 case CMD_DELETE:
4492 ExecASDeleteTriggers(node->ps.state, resultRelInfo,
4493 node->mt_transition_capture);
4494 break;
4495 case CMD_MERGE:
4497 ExecASDeleteTriggers(node->ps.state, resultRelInfo,
4498 node->mt_transition_capture);
4500 ExecASUpdateTriggers(node->ps.state, resultRelInfo,
4501 node->mt_transition_capture);
4503 ExecASInsertTriggers(node->ps.state, resultRelInfo,
4504 node->mt_transition_capture);
4505 break;
4506 default:
4507 elog(ERROR, "unknown operation");
4508 break;
4509 }
4510}
4511
4512/*
4513 * Set up the state needed for collecting transition tuples for AFTER
4514 * triggers.
4515 */
4516static void
4518{
4519 ModifyTable *plan = (ModifyTable *) mtstate->ps.plan;
4520 ResultRelInfo *targetRelInfo = mtstate->rootResultRelInfo;
4521
4522 /* Check for transition tables on the directly targeted relation. */
4523 mtstate->mt_transition_capture =
4525 RelationGetRelid(targetRelInfo->ri_RelationDesc),
4526 mtstate->operation);
4527 if (plan->operation == CMD_INSERT &&
4528 plan->onConflictAction == ONCONFLICT_UPDATE)
4529 mtstate->mt_oc_transition_capture =
4531 RelationGetRelid(targetRelInfo->ri_RelationDesc),
4532 CMD_UPDATE);
4533}
4534
4535/*
4536 * ExecPrepareTupleRouting --- prepare for routing one tuple
4537 *
4538 * Determine the partition in which the tuple in slot is to be inserted,
4539 * and return its ResultRelInfo in *partRelInfo. The return value is
4540 * a slot holding the tuple of the partition rowtype.
4541 *
4542 * This also sets the transition table information in mtstate based on the
4543 * selected partition.
4544 */
4545static TupleTableSlot *
4547 EState *estate,
4548 PartitionTupleRouting *proute,
4549 ResultRelInfo *targetRelInfo,
4550 TupleTableSlot *slot,
4552{
4553 ResultRelInfo *partrel;
4554 TupleConversionMap *map;
4555
4556 /*
4557 * Lookup the target partition's ResultRelInfo. If ExecFindPartition does
4558 * not find a valid partition for the tuple in 'slot' then an error is
4559 * raised. An error may also be raised if the found partition is not a
4560 * valid target for INSERTs. This is required since a partitioned table
4561 * UPDATE to another partition becomes a DELETE+INSERT.
4562 */
4563 partrel = ExecFindPartition(mtstate, targetRelInfo, proute, slot, estate);
4564
4565 /*
4566 * If we're capturing transition tuples, we might need to convert from the
4567 * partition rowtype to root partitioned table's rowtype. But if there
4568 * are no BEFORE triggers on the partition that could change the tuple, we
4569 * can just remember the original unconverted tuple to avoid a needless
4570 * round trip conversion.
4571 */
4572 if (mtstate->mt_transition_capture != NULL)
4573 {
4575
4578
4581 }
4582
4583 /*
4584 * Convert the tuple, if necessary.
4585 */
4586 map = ExecGetRootToChildMap(partrel, estate);
4587 if (map != NULL)
4588 {
4589 TupleTableSlot *new_slot = partrel->ri_PartitionTupleSlot;
4590
4591 slot = execute_attr_map_slot(map->attrMap, slot, new_slot);
4592 }
4593
4594 *partRelInfo = partrel;
4595 return slot;
4596}
4597
4598/* ----------------------------------------------------------------
4599 * ExecModifyTable
4600 *
4601 * Perform table modifications as required, and return RETURNING results
4602 * if needed.
4603 * ----------------------------------------------------------------
4604 */
4605static TupleTableSlot *
4607{
4609 ModifyTableContext context;
4610 EState *estate = node->ps.state;
4611 CmdType operation = node->operation;
4612 ResultRelInfo *resultRelInfo;
4614 TupleTableSlot *slot;
4618 HeapTuple oldtuple;
4620 bool tuplock;
4621
4623
4624 /*
4625 * This should NOT get called during EvalPlanQual; we should have passed a
4626 * subplan tree to EvalPlanQual, instead. Use a runtime test not just
4627 * Assert because this condition is easy to miss in testing. (Note:
4628 * although ModifyTable should not get executed within an EvalPlanQual
4629 * operation, we do have to allow it to be initialized and shut down in
4630 * case it is within a CTE subplan. Hence this test must be here, not in
4631 * ExecInitModifyTable.)
4632 */
4633 if (estate->es_epq_active != NULL)
4634 elog(ERROR, "ModifyTable should not be called during EvalPlanQual");
4635
4636 /*
4637 * If we've already completed processing, don't try to do more. We need
4638 * this test because ExecPostprocessPlan might call us an extra time, and
4639 * our subplan's nodes aren't necessarily robust against being called
4640 * extra times.
4641 */
4642 if (node->mt_done)
4643 return NULL;
4644
4645 /*
4646 * On first call, fire BEFORE STATEMENT triggers before proceeding.
4647 */
4648 if (node->fireBSTriggers)
4649 {
4650 fireBSTriggers(node);
4651 node->fireBSTriggers = false;
4652 }
4653
4654 /* Preload local variables */
4655 resultRelInfo = node->resultRelInfo + node->mt_lastResultIndex;
4657
4658 /* Set global context */
4659 context.mtstate = node;
4660 context.epqstate = &node->mt_epqstate;
4661 context.estate = estate;
4662
4663 /*
4664 * Fetch rows from subplan, and execute the required table modification
4665 * for each row.
4666 */
4667 for (;;)
4668 {
4669 /*
4670 * Reset the per-output-tuple exprcontext. This is needed because
4671 * triggers expect to use that context as workspace. It's a bit ugly
4672 * to do this below the top level of the plan, however. We might need
4673 * to rethink this later.
4674 */
4676
4677 /*
4678 * Reset per-tuple memory context used for processing on conflict and
4679 * returning clauses, to free any expression evaluation storage
4680 * allocated in the previous cycle.
4681 */
4682 if (pstate->ps_ExprContext)
4684
4685 /*
4686 * If there is a pending MERGE ... WHEN NOT MATCHED [BY TARGET] action
4687 * to execute, do so now --- see the comments in ExecMerge().
4688 */
4690 {
4691 context.planSlot = node->mt_merge_pending_not_matched;
4692 context.cpDeletedSlot = NULL;
4693
4694 slot = ExecMergeNotMatched(&context, node->resultRelInfo,
4695 node->canSetTag);
4696
4697 /* Clear the pending action */
4699
4700 /*
4701 * If we got a RETURNING result, return it to the caller. We'll
4702 * continue the work on next call.
4703 */
4704 if (slot)
4705 return slot;
4706
4707 continue; /* continue with the next tuple */
4708 }
4709
4710 /* Fetch the next row from subplan */
4712 context.cpDeletedSlot = NULL;
4713
4714 /* No more tuples to process? */
4715 if (TupIsNull(context.planSlot))
4716 break;
4717
4718 /*
4719 * When there are multiple result relations, each tuple contains a
4720 * junk column that gives the OID of the rel from which it came.
4721 * Extract it and select the correct result relation.
4722 */
4724 {
4725 Datum datum;
4726 bool isNull;
4727 Oid resultoid;
4728
4729 datum = ExecGetJunkAttribute(context.planSlot, node->mt_resultOidAttno,
4730 &isNull);
4731 if (isNull)
4732 {
4733 /*
4734 * For commands other than MERGE, any tuples having InvalidOid
4735 * for tableoid are errors. For MERGE, we may need to handle
4736 * them as WHEN NOT MATCHED clauses if any, so do that.
4737 *
4738 * Note that we use the node's toplevel resultRelInfo, not any
4739 * specific partition's.
4740 */
4741 if (operation == CMD_MERGE)
4742 {
4743 EvalPlanQualSetSlot(&node->mt_epqstate, context.planSlot);
4744
4745 slot = ExecMerge(&context, node->resultRelInfo,
4746 NULL, NULL, node->canSetTag);
4747
4748 /*
4749 * If we got a RETURNING result, return it to the caller.
4750 * We'll continue the work on next call.
4751 */
4752 if (slot)
4753 return slot;
4754
4755 continue; /* continue with the next tuple */
4756 }
4757
4758 elog(ERROR, "tableoid is NULL");
4759 }
4760 resultoid = DatumGetObjectId(datum);
4761
4762 /* If it's not the same as last time, we need to locate the rel */
4763 if (resultoid != node->mt_lastResultOid)
4764 resultRelInfo = ExecLookupResultRelByOid(node, resultoid,
4765 false, true);
4766 }
4767
4768 /*
4769 * If we don't have a ForPortionOfState yet, we must be a partition or
4770 * inheritance child being hit for the first time. Make a copy from
4771 * the root, with our own TupleTableSlot. We do this lazily so that we
4772 * don't pay the price of unused partitions.
4773 */
4774 if (((ModifyTable *) context.mtstate->ps.plan)->forPortionOf &&
4775 !resultRelInfo->ri_forPortionOf)
4776 ExecInitForPortionOf(context.mtstate, estate, resultRelInfo);
4777
4778 /*
4779 * If resultRelInfo->ri_usesFdwDirectModify is true, all we need to do
4780 * here is compute the RETURNING expressions.
4781 */
4782 if (resultRelInfo->ri_usesFdwDirectModify)
4783 {
4784 Assert(resultRelInfo->ri_projectReturning);
4785
4786 /*
4787 * A scan slot containing the data that was actually inserted,
4788 * updated or deleted has already been made available to
4789 * ExecProcessReturning by IterateDirectModify, so no need to
4790 * provide it here. The individual old and new slots are not
4791 * needed, since direct-modify is disabled if the RETURNING list
4792 * refers to OLD/NEW values.
4793 */
4794 Assert((resultRelInfo->ri_projectReturning->pi_state.flags & EEO_FLAG_HAS_OLD) == 0 &&
4795 (resultRelInfo->ri_projectReturning->pi_state.flags & EEO_FLAG_HAS_NEW) == 0);
4796
4797 slot = ExecProcessReturning(&context, resultRelInfo,
4799 NULL, NULL, context.planSlot);
4800
4801 return slot;
4802 }
4803
4804 EvalPlanQualSetSlot(&node->mt_epqstate, context.planSlot);
4805 slot = context.planSlot;
4806
4807 tupleid = NULL;
4808 oldtuple = NULL;
4809
4810 /*
4811 * For UPDATE/DELETE/MERGE, fetch the row identity info for the tuple
4812 * to be updated/deleted/merged. For a heap relation, that's a TID;
4813 * otherwise we may have a wholerow junk attr that carries the old
4814 * tuple in toto. Keep this in step with the part of
4815 * ExecInitModifyTable that sets up ri_RowIdAttNo.
4816 */
4819 {
4820 char relkind;
4821 Datum datum;
4822 bool isNull;
4823
4824 relkind = resultRelInfo->ri_RelationDesc->rd_rel->relkind;
4825 if (relkind == RELKIND_RELATION ||
4826 relkind == RELKIND_MATVIEW ||
4827 relkind == RELKIND_PARTITIONED_TABLE)
4828 {
4829 /*
4830 * ri_RowIdAttNo refers to a ctid attribute. See the comment
4831 * in ExecInitModifyTable().
4832 */
4834 relkind == RELKIND_PARTITIONED_TABLE);
4835 datum = ExecGetJunkAttribute(slot,
4836 resultRelInfo->ri_RowIdAttNo,
4837 &isNull);
4838
4839 /*
4840 * For commands other than MERGE, any tuples having a null row
4841 * identifier are errors. For MERGE, we may need to handle
4842 * them as WHEN NOT MATCHED clauses if any, so do that.
4843 *
4844 * Note that we use the node's toplevel resultRelInfo, not any
4845 * specific partition's.
4846 */
4847 if (isNull)
4848 {
4849 if (operation == CMD_MERGE)
4850 {
4851 EvalPlanQualSetSlot(&node->mt_epqstate, context.planSlot);
4852
4853 slot = ExecMerge(&context, node->resultRelInfo,
4854 NULL, NULL, node->canSetTag);
4855
4856 /*
4857 * If we got a RETURNING result, return it to the
4858 * caller. We'll continue the work on next call.
4859 */
4860 if (slot)
4861 return slot;
4862
4863 continue; /* continue with the next tuple */
4864 }
4865
4866 elog(ERROR, "ctid is NULL");
4867 }
4868
4870 tuple_ctid = *tupleid; /* be sure we don't free ctid!! */
4872 }
4873
4874 /*
4875 * Use the wholerow attribute, when available, to reconstruct the
4876 * old relation tuple. The old tuple serves one or both of two
4877 * purposes: 1) it serves as the OLD tuple for row triggers, 2) it
4878 * provides values for any unchanged columns for the NEW tuple of
4879 * an UPDATE, because the subplan does not produce all the columns
4880 * of the target table.
4881 *
4882 * Note that the wholerow attribute does not carry system columns,
4883 * so foreign table triggers miss seeing those, except that we
4884 * know enough here to set t_tableOid. Quite separately from
4885 * this, the FDW may fetch its own junk attrs to identify the row.
4886 *
4887 * Other relevant relkinds, currently limited to views, always
4888 * have a wholerow attribute.
4889 */
4890 else if (AttributeNumberIsValid(resultRelInfo->ri_RowIdAttNo))
4891 {
4892 datum = ExecGetJunkAttribute(slot,
4893 resultRelInfo->ri_RowIdAttNo,
4894 &isNull);
4895
4896 /*
4897 * For commands other than MERGE, any tuples having a null row
4898 * identifier are errors. For MERGE, we may need to handle
4899 * them as WHEN NOT MATCHED clauses if any, so do that.
4900 *
4901 * Note that we use the node's toplevel resultRelInfo, not any
4902 * specific partition's.
4903 */
4904 if (isNull)
4905 {
4906 if (operation == CMD_MERGE)
4907 {
4908 EvalPlanQualSetSlot(&node->mt_epqstate, context.planSlot);
4909
4910 slot = ExecMerge(&context, node->resultRelInfo,
4911 NULL, NULL, node->canSetTag);
4912
4913 /*
4914 * If we got a RETURNING result, return it to the
4915 * caller. We'll continue the work on next call.
4916 */
4917 if (slot)
4918 return slot;
4919
4920 continue; /* continue with the next tuple */
4921 }
4922
4923 elog(ERROR, "wholerow is NULL");
4924 }
4925
4926 oldtupdata.t_data = DatumGetHeapTupleHeader(datum);
4927 oldtupdata.t_len =
4930 /* Historically, view triggers see invalid t_tableOid. */
4931 oldtupdata.t_tableOid =
4932 (relkind == RELKIND_VIEW) ? InvalidOid :
4933 RelationGetRelid(resultRelInfo->ri_RelationDesc);
4934
4935 oldtuple = &oldtupdata;
4936 }
4937 else
4938 {
4939 /* Only foreign tables are allowed to omit a row-ID attr */
4940 Assert(relkind == RELKIND_FOREIGN_TABLE);
4941 }
4942 }
4943
4944 switch (operation)
4945 {
4946 case CMD_INSERT:
4947 /* Initialize projection info if first time for this table */
4948 if (unlikely(!resultRelInfo->ri_projectNewInfoValid))
4949 ExecInitInsertProjection(node, resultRelInfo);
4950 slot = ExecGetInsertNewTuple(resultRelInfo, context.planSlot);
4951 slot = ExecInsert(&context, resultRelInfo, slot,
4952 node->canSetTag, NULL, NULL);
4953 break;
4954
4955 case CMD_UPDATE:
4956 tuplock = false;
4957
4958 /* Initialize projection info if first time for this table */
4959 if (unlikely(!resultRelInfo->ri_projectNewInfoValid))
4960 ExecInitUpdateProjection(node, resultRelInfo);
4961
4962 /*
4963 * Make the new tuple by combining plan's output tuple with
4964 * the old tuple being updated.
4965 */
4966 oldSlot = resultRelInfo->ri_oldTupleSlot;
4967 if (oldtuple != NULL)
4968 {
4969 Assert(!resultRelInfo->ri_needLockTagTuple);
4970 /* Use the wholerow junk attr as the old tuple. */
4971 ExecForceStoreHeapTuple(oldtuple, oldSlot, false);
4972 }
4973 else
4974 {
4975 /* Fetch the most recent version of old tuple. */
4976 Relation relation = resultRelInfo->ri_RelationDesc;
4977
4978 if (resultRelInfo->ri_needLockTagTuple)
4979 {
4981 tuplock = true;
4982 }
4985 oldSlot))
4986 elog(ERROR, "failed to fetch tuple being updated");
4987 }
4988 slot = ExecGetUpdateNewTuple(resultRelInfo, context.planSlot,
4989 oldSlot);
4990
4991 /* Now apply the update. */
4992 slot = ExecUpdate(&context, resultRelInfo, tupleid, oldtuple,
4993 oldSlot, slot, node->canSetTag);
4994 if (tuplock)
4995 UnlockTuple(resultRelInfo->ri_RelationDesc, tupleid,
4997 break;
4998
4999 case CMD_DELETE:
5000 slot = ExecDelete(&context, resultRelInfo, tupleid, oldtuple,
5001 true, false, node->canSetTag, NULL, NULL, NULL);
5002 break;
5003
5004 case CMD_MERGE:
5005 slot = ExecMerge(&context, resultRelInfo, tupleid, oldtuple,
5006 node->canSetTag);
5007 break;
5008
5009 default:
5010 elog(ERROR, "unknown operation");
5011 break;
5012 }
5013
5014 /*
5015 * If we got a RETURNING result, return it to caller. We'll continue
5016 * the work on next call.
5017 */
5018 if (slot)
5019 return slot;
5020 }
5021
5022 /*
5023 * Insert remaining tuples for batch insert.
5024 */
5026 ExecPendingInserts(estate);
5027
5028 /*
5029 * We're done, but fire AFTER STATEMENT triggers before exiting.
5030 */
5031 fireASTriggers(node);
5032
5033 node->mt_done = true;
5034
5035 return NULL;
5036}
5037
5038/*
5039 * ExecLookupResultRelByOid
5040 * If the table with given OID is among the result relations to be
5041 * updated by the given ModifyTable node, return its ResultRelInfo.
5042 *
5043 * If not found, return NULL if missing_ok, else raise error.
5044 *
5045 * If update_cache is true, then upon successful lookup, update the node's
5046 * one-element cache. ONLY ExecModifyTable may pass true for this.
5047 */
5050 bool missing_ok, bool update_cache)
5051{
5052 if (node->mt_resultOidHash)
5053 {
5054 /* Use the pre-built hash table to locate the rel */
5056
5059 if (mtlookup)
5060 {
5061 if (update_cache)
5062 {
5064 node->mt_lastResultIndex = mtlookup->relationIndex;
5065 }
5066 return node->resultRelInfo + mtlookup->relationIndex;
5067 }
5068 }
5069 else
5070 {
5071 /* With few target rels, just search the ResultRelInfo array */
5072 for (int ndx = 0; ndx < node->mt_nrels; ndx++)
5073 {
5075
5076 if (RelationGetRelid(rInfo->ri_RelationDesc) == resultoid)
5077 {
5078 if (update_cache)
5079 {
5081 node->mt_lastResultIndex = ndx;
5082 }
5083 return rInfo;
5084 }
5085 }
5086 }
5087
5088 if (!missing_ok)
5089 elog(ERROR, "incorrect result relation OID %u", resultoid);
5090 return NULL;
5091}
5092
5093/* ----------------------------------------------------------------
5094 * ExecInitModifyTable
5095 * ----------------------------------------------------------------
5096 */
5098ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
5099{
5100 ModifyTableState *mtstate;
5101 Plan *subplan = outerPlan(node);
5102 CmdType operation = node->operation;
5104 int nrels;
5105 List *resultRelations = NIL;
5106 List *withCheckOptionLists = NIL;
5107 List *returningLists = NIL;
5108 List *updateColnosLists = NIL;
5109 List *mergeActionLists = NIL;
5110 List *mergeJoinConditions = NIL;
5111 ResultRelInfo *resultRelInfo;
5112 List *arowmarks;
5113 ListCell *l;
5114 int i;
5115 Relation rel;
5116
5117 /* check for unsupported flags */
5118 Assert(!(eflags & (EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK)));
5119
5120 /*
5121 * Only consider unpruned relations for initializing their ResultRelInfo
5122 * struct and other fields such as withCheckOptions, etc.
5123 *
5124 * Note: We must avoid pruning every result relation. This is important
5125 * for MERGE, since even if every result relation is pruned from the
5126 * subplan, there might still be NOT MATCHED rows, for which there may be
5127 * INSERT actions to perform. To allow these actions to be found, at
5128 * least one result relation must be kept. Also, when inserting into a
5129 * partitioned table, ExecInitPartitionInfo() needs a ResultRelInfo struct
5130 * as a reference for building the ResultRelInfo of the target partition.
5131 * In either case, it doesn't matter which result relation is kept, so we
5132 * just keep the first one, if all others have been pruned. See also,
5133 * ExecDoInitialPruning(), which ensures that this first result relation
5134 * has been locked.
5135 */
5136 i = 0;
5137 foreach(l, node->resultRelations)
5138 {
5139 Index rti = lfirst_int(l);
5140 bool keep_rel;
5141
5143 if (!keep_rel && i == total_nrels - 1 && resultRelations == NIL)
5144 {
5145 /* all result relations pruned; keep the first one */
5146 keep_rel = true;
5147 rti = linitial_int(node->resultRelations);
5148 i = 0;
5149 }
5150
5151 if (keep_rel)
5152 {
5153 resultRelations = lappend_int(resultRelations, rti);
5154 if (node->withCheckOptionLists)
5155 {
5158 i);
5159
5160 withCheckOptionLists = lappend(withCheckOptionLists, withCheckOptions);
5161 }
5162 if (node->returningLists)
5163 {
5164 List *returningList = list_nth_node(List,
5165 node->returningLists,
5166 i);
5167
5168 returningLists = lappend(returningLists, returningList);
5169 }
5170 if (node->updateColnosLists)
5171 {
5173
5174 updateColnosLists = lappend(updateColnosLists, updateColnosList);
5175 }
5176 if (node->mergeActionLists)
5177 {
5178 List *mergeActionList = list_nth(node->mergeActionLists, i);
5179
5180 mergeActionLists = lappend(mergeActionLists, mergeActionList);
5181 }
5182 if (node->mergeJoinConditions)
5183 {
5184 List *mergeJoinCondition = list_nth(node->mergeJoinConditions, i);
5185
5186 mergeJoinConditions = lappend(mergeJoinConditions, mergeJoinCondition);
5187 }
5188 }
5189 i++;
5190 }
5191 nrels = list_length(resultRelations);
5192 Assert(nrels > 0);
5193
5194 /*
5195 * create state structure
5196 */
5197 mtstate = makeNode(ModifyTableState);
5198 mtstate->ps.plan = (Plan *) node;
5199 mtstate->ps.state = estate;
5200 mtstate->ps.ExecProcNode = ExecModifyTable;
5201
5202 mtstate->operation = operation;
5203 mtstate->canSetTag = node->canSetTag;
5204 mtstate->mt_done = false;
5205
5206 mtstate->mt_nrels = nrels;
5207 mtstate->resultRelInfo = palloc_array(ResultRelInfo, nrels);
5208
5210 mtstate->mt_merge_inserted = 0;
5211 mtstate->mt_merge_updated = 0;
5212 mtstate->mt_merge_deleted = 0;
5213 mtstate->mt_updateColnosLists = updateColnosLists;
5214 mtstate->mt_mergeActionLists = mergeActionLists;
5215 mtstate->mt_mergeJoinConditions = mergeJoinConditions;
5216
5217 /*----------
5218 * Resolve the target relation. This is the same as:
5219 *
5220 * - the relation for which we will fire FOR STATEMENT triggers,
5221 * - the relation into whose tuple format all captured transition tuples
5222 * must be converted, and
5223 * - the root partitioned table used for tuple routing.
5224 *
5225 * If it's a partitioned or inherited table, the root partition or
5226 * appendrel RTE doesn't appear elsewhere in the plan and its RT index is
5227 * given explicitly in node->rootRelation. Otherwise, the target relation
5228 * is the sole relation in the node->resultRelations list and, since it can
5229 * never be pruned, also in the resultRelations list constructed above.
5230 *----------
5231 */
5232 if (node->rootRelation > 0)
5233 {
5237 node->rootRelation);
5238 }
5239 else
5240 {
5241 Assert(list_length(node->resultRelations) == 1);
5242 Assert(list_length(resultRelations) == 1);
5243 mtstate->rootResultRelInfo = mtstate->resultRelInfo;
5244 ExecInitResultRelation(estate, mtstate->resultRelInfo,
5245 linitial_int(resultRelations));
5246 }
5247
5248 /* set up epqstate with dummy subplan data for the moment */
5249 EvalPlanQualInit(&mtstate->mt_epqstate, estate, NULL, NIL,
5250 node->epqParam, resultRelations);
5251 mtstate->fireBSTriggers = true;
5252
5253 /*
5254 * Build state for collecting transition tuples. This requires having a
5255 * valid trigger query context, so skip it in explain-only mode.
5256 */
5257 if (!(eflags & EXEC_FLAG_EXPLAIN_ONLY))
5258 ExecSetupTransitionCaptureState(mtstate, estate);
5259
5260 /*
5261 * Open all the result relations and initialize the ResultRelInfo structs.
5262 * (But root relation was initialized above, if it's part of the array.)
5263 * We must do this before initializing the subplan, because direct-modify
5264 * FDWs expect their ResultRelInfos to be available.
5265 */
5266 resultRelInfo = mtstate->resultRelInfo;
5267 i = 0;
5268 foreach(l, resultRelations)
5269 {
5270 Index resultRelation = lfirst_int(l);
5272
5273 if (mergeActionLists)
5274 mergeActions = list_nth(mergeActionLists, i);
5275
5276 if (resultRelInfo != mtstate->rootResultRelInfo)
5277 {
5278 ExecInitResultRelation(estate, resultRelInfo, resultRelation);
5279
5280 /*
5281 * For child result relations, store the root result relation
5282 * pointer. We do so for the convenience of places that want to
5283 * look at the query's original target relation but don't have the
5284 * mtstate handy.
5285 */
5286 resultRelInfo->ri_RootResultRelInfo = mtstate->rootResultRelInfo;
5287 }
5288
5289 /* Initialize the usesFdwDirectModify flag */
5290 resultRelInfo->ri_usesFdwDirectModify =
5292
5293 /*
5294 * Verify result relation is a valid target for the current operation
5295 */
5296 CheckValidResultRel(resultRelInfo, operation, node->onConflictAction,
5297 mergeActions);
5298
5299 resultRelInfo++;
5300 i++;
5301 }
5302
5303 /*
5304 * Now we may initialize the subplan.
5305 */
5306 outerPlanState(mtstate) = ExecInitNode(subplan, estate, eflags);
5307
5308 /*
5309 * Do additional per-result-relation initialization.
5310 */
5311 for (i = 0; i < nrels; i++)
5312 {
5313 resultRelInfo = &mtstate->resultRelInfo[i];
5314
5315 /* Let FDWs init themselves for foreign-table result rels */
5316 if (!resultRelInfo->ri_usesFdwDirectModify &&
5317 resultRelInfo->ri_FdwRoutine != NULL &&
5318 resultRelInfo->ri_FdwRoutine->BeginForeignModify != NULL)
5319 {
5320 List *fdw_private = (List *) list_nth(node->fdwPrivLists, i);
5321
5322 resultRelInfo->ri_FdwRoutine->BeginForeignModify(mtstate,
5323 resultRelInfo,
5324 fdw_private,
5325 i,
5326 eflags);
5327 }
5328
5329 /*
5330 * For UPDATE/DELETE/MERGE, find the appropriate junk attr now, either
5331 * a 'ctid' or 'wholerow' attribute depending on relkind. For foreign
5332 * tables, the FDW might have created additional junk attr(s), but
5333 * those are no concern of ours.
5334 */
5337 {
5338 char relkind;
5339
5340 relkind = resultRelInfo->ri_RelationDesc->rd_rel->relkind;
5341 if (relkind == RELKIND_RELATION ||
5342 relkind == RELKIND_MATVIEW ||
5343 relkind == RELKIND_PARTITIONED_TABLE)
5344 {
5345 resultRelInfo->ri_RowIdAttNo =
5346 ExecFindJunkAttributeInTlist(subplan->targetlist, "ctid");
5347
5348 /*
5349 * For heap relations, a ctid junk attribute must be present.
5350 * Partitioned tables should only appear here when all leaf
5351 * partitions were pruned, in which case no rows can be
5352 * produced and ctid is not needed.
5353 */
5354 if (relkind == RELKIND_PARTITIONED_TABLE)
5355 Assert(nrels == 1);
5356 else if (!AttributeNumberIsValid(resultRelInfo->ri_RowIdAttNo))
5357 elog(ERROR, "could not find junk ctid column");
5358 }
5359 else if (relkind == RELKIND_FOREIGN_TABLE)
5360 {
5361 /*
5362 * We don't support MERGE with foreign tables for now. (It's
5363 * problematic because the implementation uses CTID.)
5364 */
5366
5367 /*
5368 * When there is a row-level trigger, there should be a
5369 * wholerow attribute. We also require it to be present in
5370 * UPDATE and MERGE, so we can get the values of unchanged
5371 * columns.
5372 */
5373 resultRelInfo->ri_RowIdAttNo =
5375 "wholerow");
5376 if ((mtstate->operation == CMD_UPDATE || mtstate->operation == CMD_MERGE) &&
5377 !AttributeNumberIsValid(resultRelInfo->ri_RowIdAttNo))
5378 elog(ERROR, "could not find junk wholerow column");
5379 }
5380 else
5381 {
5382 /* Other valid target relkinds must provide wholerow */
5383 resultRelInfo->ri_RowIdAttNo =
5385 "wholerow");
5386 if (!AttributeNumberIsValid(resultRelInfo->ri_RowIdAttNo))
5387 elog(ERROR, "could not find junk wholerow column");
5388 }
5389 }
5390 }
5391
5392 /*
5393 * If this is an inherited update/delete/merge, there will be a junk
5394 * attribute named "tableoid" present in the subplan's targetlist. It
5395 * will be used to identify the result relation for a given tuple to be
5396 * updated/deleted/merged.
5397 */
5398 mtstate->mt_resultOidAttno =
5399 ExecFindJunkAttributeInTlist(subplan->targetlist, "tableoid");
5401 mtstate->mt_lastResultOid = InvalidOid; /* force lookup at first tuple */
5402 mtstate->mt_lastResultIndex = 0; /* must be zero if no such attr */
5403
5404 /* Get the root target relation */
5405 rel = mtstate->rootResultRelInfo->ri_RelationDesc;
5406
5407 /*
5408 * Build state for tuple routing if it's a partitioned INSERT. An UPDATE
5409 * or MERGE might need this too, but only if it actually moves tuples
5410 * between partitions; in that case setup is done by
5411 * ExecCrossPartitionUpdate.
5412 */
5413 if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE &&
5416 ExecSetupPartitionTupleRouting(estate, rel);
5417
5418 /*
5419 * Initialize any WITH CHECK OPTION constraints if needed.
5420 */
5421 resultRelInfo = mtstate->resultRelInfo;
5422 foreach(l, withCheckOptionLists)
5423 {
5424 List *wcoList = (List *) lfirst(l);
5425 List *wcoExprs = NIL;
5426 ListCell *ll;
5427
5428 foreach(ll, wcoList)
5429 {
5431 ExprState *wcoExpr = ExecInitQual((List *) wco->qual,
5432 &mtstate->ps);
5433
5435 }
5436
5437 resultRelInfo->ri_WithCheckOptions = wcoList;
5438 resultRelInfo->ri_WithCheckOptionExprs = wcoExprs;
5439 resultRelInfo++;
5440 }
5441
5442 /*
5443 * Initialize RETURNING projections if needed.
5444 */
5445 if (returningLists)
5446 {
5447 TupleTableSlot *slot;
5448 ExprContext *econtext;
5449
5450 /*
5451 * Initialize result tuple slot and assign its rowtype using the plan
5452 * node's declared targetlist, which the planner set up to be the same
5453 * as the first (before runtime pruning) RETURNING list. We assume
5454 * all the result rels will produce compatible output.
5455 */
5457 slot = mtstate->ps.ps_ResultTupleSlot;
5458
5459 /* Need an econtext too */
5460 if (mtstate->ps.ps_ExprContext == NULL)
5461 ExecAssignExprContext(estate, &mtstate->ps);
5462 econtext = mtstate->ps.ps_ExprContext;
5463
5464 /*
5465 * Build a projection for each result rel.
5466 */
5467 resultRelInfo = mtstate->resultRelInfo;
5468 foreach(l, returningLists)
5469 {
5470 List *rlist = (List *) lfirst(l);
5471
5472 resultRelInfo->ri_returningList = rlist;
5473 resultRelInfo->ri_projectReturning =
5474 ExecBuildProjectionInfo(rlist, econtext, slot, &mtstate->ps,
5475 resultRelInfo->ri_RelationDesc->rd_att);
5476 resultRelInfo++;
5477 }
5478 }
5479 else
5480 {
5481 /*
5482 * We still must construct a dummy result tuple type, because InitPlan
5483 * expects one (maybe should change that?).
5484 */
5485 ExecInitResultTypeTL(&mtstate->ps);
5486
5487 mtstate->ps.ps_ExprContext = NULL;
5488 }
5489
5490 /* Set the list of arbiter indexes if needed for ON CONFLICT */
5491 resultRelInfo = mtstate->resultRelInfo;
5492 if (node->onConflictAction != ONCONFLICT_NONE)
5493 {
5494 /* insert may only have one relation, inheritance is not expanded */
5495 Assert(total_nrels == 1);
5496 resultRelInfo->ri_onConflictArbiterIndexes = node->arbiterIndexes;
5497 }
5498
5499 /*
5500 * For ON CONFLICT DO SELECT/UPDATE, initialize the ON CONFLICT action
5501 * state.
5502 */
5503 if (node->onConflictAction == ONCONFLICT_UPDATE ||
5505 {
5507
5508 /* already exists if created by RETURNING processing above */
5509 if (mtstate->ps.ps_ExprContext == NULL)
5510 ExecAssignExprContext(estate, &mtstate->ps);
5511
5512 /* action state for DO SELECT/UPDATE */
5513 resultRelInfo->ri_onConflict = onconfl;
5514
5515 /* lock strength for DO SELECT [FOR UPDATE/SHARE] */
5517
5518 /* initialize slot for the existing tuple */
5519 onconfl->oc_Existing =
5520 table_slot_create(resultRelInfo->ri_RelationDesc,
5521 &mtstate->ps.state->es_tupleTable);
5522
5523 /*
5524 * For ON CONFLICT DO UPDATE, initialize target list and projection.
5525 */
5527 {
5528 ExprContext *econtext;
5530
5531 econtext = mtstate->ps.ps_ExprContext;
5532 relationDesc = resultRelInfo->ri_RelationDesc->rd_att;
5533
5534 /*
5535 * Create the tuple slot for the UPDATE SET projection. We want a
5536 * slot of the table's type here, because the slot will be used to
5537 * insert into the table, and for RETURNING processing - which may
5538 * access system attributes.
5539 */
5540 onconfl->oc_ProjSlot =
5541 table_slot_create(resultRelInfo->ri_RelationDesc,
5542 &mtstate->ps.state->es_tupleTable);
5543
5544 /* build UPDATE SET projection state */
5545 onconfl->oc_ProjInfo =
5547 true,
5548 node->onConflictCols,
5550 econtext,
5551 onconfl->oc_ProjSlot,
5552 &mtstate->ps);
5553 }
5554
5555 /* initialize state to evaluate the WHERE clause, if any */
5556 if (node->onConflictWhere)
5557 {
5558 ExprState *qualexpr;
5559
5560 qualexpr = ExecInitQual((List *) node->onConflictWhere,
5561 &mtstate->ps);
5562 onconfl->oc_WhereClause = qualexpr;
5563 }
5564 }
5565
5566 /*
5567 * If needed, initialize the target range for FOR PORTION OF.
5568 */
5569 if (node->forPortionOf)
5570 {
5572 TupleDesc tupDesc;
5573 ForPortionOfExpr *forPortionOf;
5574 Datum targetRange;
5575 bool isNull;
5576 ExprContext *econtext;
5579
5580 rootRelInfo = mtstate->resultRelInfo;
5581 if (rootRelInfo->ri_RootResultRelInfo)
5583
5584 tupDesc = rootRelInfo->ri_RelationDesc->rd_att;
5585 forPortionOf = (ForPortionOfExpr *) node->forPortionOf;
5586
5587 /* Eval the FOR PORTION OF target */
5588 if (mtstate->ps.ps_ExprContext == NULL)
5589 ExecAssignExprContext(estate, &mtstate->ps);
5590 econtext = mtstate->ps.ps_ExprContext;
5591
5592 exprState = ExecPrepareExpr((Expr *) forPortionOf->targetRange, estate);
5593 targetRange = ExecEvalExpr(exprState, econtext, &isNull);
5594
5595 /*
5596 * FOR PORTION OF ... TO ... FROM should never give us a NULL target,
5597 * but FOR PORTION OF (...) could.
5598 */
5599 if (isNull)
5600 ereport(ERROR,
5601 (errmsg("FOR PORTION OF target was null")),
5602 executor_errposition(estate, forPortionOf->targetLocation));
5603
5604 /* Create state for FOR PORTION OF operation */
5605
5607 fpoState->fp_rangeName = forPortionOf->range_name;
5608 fpoState->fp_rangeType = forPortionOf->rangeType;
5609 fpoState->fp_rangeAttno = forPortionOf->rangeVar->varattno;
5610 fpoState->fp_targetRange = targetRange;
5611
5612 /* Initialize slot for the existing tuple */
5613
5614 fpoState->fp_Existing =
5615 table_slot_create(rootRelInfo->ri_RelationDesc,
5616 &mtstate->ps.state->es_tupleTable);
5617
5618 /* Create the tuple slot for INSERTing the temporal leftovers */
5619
5620 fpoState->fp_Leftover =
5621 ExecInitExtraTupleSlot(mtstate->ps.state, tupDesc, &TTSOpsVirtual);
5622
5623 rootRelInfo->ri_forPortionOf = fpoState;
5624
5625 /*
5626 * Make sure the root relation has the FOR PORTION OF clause too. Each
5627 * partition needs its own TupleTableSlot, since they can have
5628 * different descriptors, so they'll use the root fpoState to
5629 * initialize one if necessary.
5630 */
5631 if (node->rootRelation > 0)
5633
5634 if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE &&
5635 mtstate->mt_partition_tuple_routing == NULL)
5636 {
5637 /*
5638 * We will need tuple routing to insert temporal leftovers. Since
5639 * we are initializing things before ExecCrossPartitionUpdate
5640 * runs, we must do everything it needs as well.
5641 */
5644
5645 /* Things built here have to last for the query duration. */
5647
5650
5651 /*
5652 * Before a partition's tuple can be re-routed, it must first be
5653 * converted to the root's format, so we'll need a slot for
5654 * storing such tuples.
5655 */
5656 Assert(mtstate->mt_root_tuple_slot == NULL);
5658
5660 }
5661
5662 /*
5663 * Don't free the ExprContext here because the result must last for
5664 * the whole query.
5665 */
5666 }
5667
5668 /*
5669 * If we have any secondary relations in an UPDATE or DELETE, they need to
5670 * be treated like non-locked relations in SELECT FOR UPDATE, i.e., the
5671 * EvalPlanQual mechanism needs to be told about them. This also goes for
5672 * the source relations in a MERGE. Locate the relevant ExecRowMarks.
5673 */
5674 arowmarks = NIL;
5675 foreach(l, node->rowMarks)
5676 {
5678 RangeTblEntry *rte = exec_rt_fetch(rc->rti, estate);
5681
5682 /* ignore "parent" rowmarks; they are irrelevant at runtime */
5683 if (rc->isParent)
5684 continue;
5685
5686 /*
5687 * Also ignore rowmarks belonging to child tables that have been
5688 * pruned in ExecDoInitialPruning().
5689 */
5690 if (rte->rtekind == RTE_RELATION &&
5691 !bms_is_member(rc->rti, estate->es_unpruned_relids))
5692 continue;
5693
5694 /* Find ExecRowMark and build ExecAuxRowMark */
5695 erm = ExecFindRowMark(estate, rc->rti, false);
5698 }
5699
5700 /* For a MERGE command, initialize its state */
5701 if (mtstate->operation == CMD_MERGE)
5702 ExecInitMerge(mtstate, estate);
5703
5704 EvalPlanQualSetPlan(&mtstate->mt_epqstate, subplan, arowmarks);
5705
5706 /*
5707 * If there are a lot of result relations, use a hash table to speed the
5708 * lookups. If there are not a lot, a simple linear search is faster.
5709 *
5710 * It's not clear where the threshold is, but try 64 for starters. In a
5711 * debugging build, use a small threshold so that we get some test
5712 * coverage of both code paths.
5713 */
5714#ifdef USE_ASSERT_CHECKING
5715#define MT_NRELS_HASH 4
5716#else
5717#define MT_NRELS_HASH 64
5718#endif
5719 if (nrels >= MT_NRELS_HASH)
5720 {
5722
5723 hash_ctl.keysize = sizeof(Oid);
5724 hash_ctl.entrysize = sizeof(MTTargetRelLookup);
5726 mtstate->mt_resultOidHash =
5727 hash_create("ModifyTable target hash",
5728 nrels, &hash_ctl,
5730 for (i = 0; i < nrels; i++)
5731 {
5732 Oid hashkey;
5734 bool found;
5735
5736 resultRelInfo = &mtstate->resultRelInfo[i];
5737 hashkey = RelationGetRelid(resultRelInfo->ri_RelationDesc);
5740 HASH_ENTER, &found);
5741 Assert(!found);
5742 mtlookup->relationIndex = i;
5743 }
5744 }
5745 else
5746 mtstate->mt_resultOidHash = NULL;
5747
5748 /*
5749 * Determine if the FDW supports batch insert and determine the batch size
5750 * (a FDW may support batching, but it may be disabled for the
5751 * server/table).
5752 *
5753 * We only do this for INSERT, so that for UPDATE/DELETE the batch size
5754 * remains set to 0.
5755 */
5756 if (operation == CMD_INSERT)
5757 {
5758 /* insert may only have one relation, inheritance is not expanded */
5759 Assert(total_nrels == 1);
5760 resultRelInfo = mtstate->resultRelInfo;
5761 if (!resultRelInfo->ri_usesFdwDirectModify &&
5762 resultRelInfo->ri_FdwRoutine != NULL &&
5763 resultRelInfo->ri_FdwRoutine->GetForeignModifyBatchSize &&
5764 resultRelInfo->ri_FdwRoutine->ExecForeignBatchInsert)
5765 {
5766 resultRelInfo->ri_BatchSize =
5767 resultRelInfo->ri_FdwRoutine->GetForeignModifyBatchSize(resultRelInfo);
5768 Assert(resultRelInfo->ri_BatchSize >= 1);
5769 }
5770 else
5771 resultRelInfo->ri_BatchSize = 1;
5772 }
5773
5774 /*
5775 * Lastly, if this is not the primary (canSetTag) ModifyTable node, add it
5776 * to estate->es_auxmodifytables so that it will be run to completion by
5777 * ExecPostprocessPlan. (It'd actually work fine to add the primary
5778 * ModifyTable node too, but there's no need.) Note the use of lcons not
5779 * lappend: we need later-initialized ModifyTable nodes to be shut down
5780 * before earlier ones. This ensures that we don't throw away RETURNING
5781 * rows that need to be seen by a later CTE subplan.
5782 */
5783 if (!mtstate->canSetTag)
5784 estate->es_auxmodifytables = lcons(mtstate,
5785 estate->es_auxmodifytables);
5786
5787 return mtstate;
5788}
5789
5790/* ----------------------------------------------------------------
5791 * ExecEndModifyTable
5792 *
5793 * Shuts down the plan.
5794 *
5795 * Returns nothing of interest.
5796 * ----------------------------------------------------------------
5797 */
5798void
5800{
5801 int i;
5802
5803 /*
5804 * Allow any FDWs to shut down
5805 */
5806 for (i = 0; i < node->mt_nrels; i++)
5807 {
5808 int j;
5809 ResultRelInfo *resultRelInfo = node->resultRelInfo + i;
5810
5811 if (!resultRelInfo->ri_usesFdwDirectModify &&
5812 resultRelInfo->ri_FdwRoutine != NULL &&
5813 resultRelInfo->ri_FdwRoutine->EndForeignModify != NULL)
5814 resultRelInfo->ri_FdwRoutine->EndForeignModify(node->ps.state,
5815 resultRelInfo);
5816
5817 /*
5818 * Cleanup the initialized batch slots. This only matters for FDWs
5819 * with batching, but the other cases will have ri_NumSlotsInitialized
5820 * == 0.
5821 */
5822 for (j = 0; j < resultRelInfo->ri_NumSlotsInitialized; j++)
5823 {
5824 ExecDropSingleTupleTableSlot(resultRelInfo->ri_Slots[j]);
5826 }
5827 }
5828
5829 /*
5830 * Close all the partitioned tables, leaf partitions, and their indices
5831 * and release the slot used for tuple routing, if set.
5832 */
5834 {
5836
5837 if (node->mt_root_tuple_slot)
5839 }
5840
5841 /*
5842 * Terminate EPQ execution if active
5843 */
5845
5846 /*
5847 * shut down subplan
5848 */
5850}
5851
5852void
5854{
5855 /*
5856 * Currently, we don't need to support rescan on ModifyTable nodes. The
5857 * semantics of that would be a bit debatable anyway.
5858 */
5859 elog(ERROR, "ExecReScanModifyTable is not implemented");
5860}
5861
5862/* ----------------------------------------------------------------
5863 * ExecInitForPortionOf
5864 *
5865 * Initializes resultRelInfo->ri_forPortionOf for child tables.
5866 *
5867 * Partitions share the root leftover slot, since they must insert via
5868 * the root relation to get tuple routing. Plain inheritance children
5869 * must keep their own leftover slot and insert back into the child, or
5870 * else child-only column values and physical placement would be lost.
5871 * ----------------------------------------------------------------
5872 */
5873static void
5875 ResultRelInfo *resultRelInfo)
5876{
5881 TupleConversionMap *map;
5882
5883 if (!rootRelInfo)
5884 elog(ERROR, "no root relation but ri_forPortionOf is uninitialized");
5885
5886 fpoState = rootRelInfo->ri_forPortionOf;
5888
5889 /* Things built here have to last for the query duration. */
5891
5893
5894 leafState->fp_rangeName = fpoState->fp_rangeName;
5895 leafState->fp_rangeType = fpoState->fp_rangeType;
5896 leafState->fp_targetRange = fpoState->fp_targetRange;
5897 map = ExecGetChildToRootMap(resultRelInfo);
5898
5899 /*
5900 * fp_rangeAttno must match the tuple layout used for reading the old
5901 * range value. The query uses the target relation's attno, so translate
5902 * it to the child attno when the child has a different column layout.
5903 */
5904 if (map)
5905 leafState->fp_rangeAttno = map->attrMap->attnums[fpoState->fp_rangeAttno - 1];
5906 else
5907 leafState->fp_rangeAttno = fpoState->fp_rangeAttno;
5908
5909 /*
5910 * For partitioned tables we must read the leftovers using the child
5911 * table's tuple descriptor, but then insert them into the root table
5912 * (using its tuple descriptor) so we get tuple routing.
5913 *
5914 * For traditional table inheritance, we read and insert directly into
5915 * this resultRelInfo; no tuple routing via the parent is required.
5916 */
5917 if (rootRelInfo->ri_RelationDesc->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
5918 leafState->fp_Leftover = fpoState->fp_Leftover;
5919 else
5920 leafState->fp_Leftover =
5922 RelationGetDescr(resultRelInfo->ri_RelationDesc),
5923 &TTSOpsVirtual);
5924
5925 /* Each child relation needs a slot matching its tuple descriptor. */
5926 leafState->fp_Existing =
5927 table_slot_create(resultRelInfo->ri_RelationDesc,
5928 &mtstate->ps.state->es_tupleTable);
5929
5930 resultRelInfo->ri_forPortionOf = leafState;
5931
5933}
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:510
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition bitmapset.c:799
bool bms_overlap(const Bitmapset *a, const Bitmapset *b)
Definition bitmapset.c:575
static Datum values[MAXATTR]
Definition bootstrap.c:190
#define Assert(condition)
Definition c.h:943
#define unlikely(x)
Definition c.h:438
uint32_t uint32
Definition c.h:624
unsigned int Index
Definition c.h:698
uint32 TransactionId
Definition c.h:736
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:2559
ExecRowMark * ExecFindRowMark(EState *estate, Index rti, bool missing_ok)
Definition execMain.c:2585
ExecAuxRowMark * ExecBuildAuxRowMark(ExecRowMark *erm, List *targetlist)
Definition execMain.c:2608
TupleTableSlot * EvalPlanQualSlot(EPQState *epqstate, Relation relation, Index rti)
Definition execMain.c:2805
void CheckValidResultRel(ResultRelInfo *resultRelInfo, CmdType operation, OnConflictAction onConflictAction, List *mergeActions)
Definition execMain.c:1065
void EvalPlanQualBegin(EPQState *epqstate)
Definition execMain.c:2960
bool ExecPartitionCheck(ResultRelInfo *resultRelInfo, TupleTableSlot *slot, EState *estate, bool emitError)
Definition execMain.c:1885
void EvalPlanQualInit(EPQState *epqstate, EState *parentestate, Plan *subplan, List *auxrowmarks, int epqParam, List *resultRelations)
Definition execMain.c:2747
void ExecWithCheckOptions(WCOKind kind, ResultRelInfo *resultRelInfo, TupleTableSlot *slot, EState *estate)
Definition execMain.c:2257
void EvalPlanQualEnd(EPQState *epqstate)
Definition execMain.c:3208
void EvalPlanQualSetPlan(EPQState *epqstate, Plan *subplan, List *auxrowmarks)
Definition execMain.c:2788
TupleTableSlot * EvalPlanQual(EPQState *epqstate, Relation relation, Index rti, TupleTableSlot *inputslot)
Definition execMain.c:2678
void ExecPartitionCheckEmitError(ResultRelInfo *resultRelInfo, TupleTableSlot *slot, EState *estate)
Definition execMain.c:1938
void ExecConstraints(ResultRelInfo *resultRelInfo, TupleTableSlot *slot, EState *estate)
Definition execMain.c:2009
List * ExecGetAncestorResultRels(EState *estate, ResultRelInfo *resultRelInfo)
Definition execMain.c:1459
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:164
OnConflictAction
Definition nodes.h:427
@ ONCONFLICT_NONE
Definition nodes.h:428
@ ONCONFLICT_SELECT
Definition nodes.h:431
@ ONCONFLICT_UPDATE
Definition nodes.h:430
@ ONCONFLICT_NOTHING
Definition nodes.h:429
CmdType
Definition nodes.h:273
@ CMD_MERGE
Definition nodes.h:279
@ CMD_INSERT
Definition nodes.h:277
@ CMD_DELETE
Definition nodes.h:278
@ CMD_UPDATE
Definition nodes.h:276
@ CMD_NOTHING
Definition nodes.h:282
#define makeNode(_type_)
Definition nodes.h:161
#define castNode(_type_, nodeptr)
Definition nodes.h:182
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:2038
@ MERGE_WHEN_NOT_MATCHED_BY_SOURCE
Definition primnodes.h:2037
@ MERGE_WHEN_MATCHED
Definition primnodes.h:2036
#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:2464
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:2047
TM_FailureData tmfd
TupleTableSlot * planSlot
TupleTableSlot * cpDeletedSlot
TupleTableSlot * cpUpdateReturningSlot
ModifyTableState * mtstate
List * mt_mergeJoinConditions
Definition execnodes.h:1511
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:1509
double mt_merge_inserted
Definition execnodes.h:1500
TupleTableSlot * mt_root_tuple_slot
Definition execnodes.h:1475
EPQState mt_epqstate
Definition execnodes.h:1457
double mt_merge_updated
Definition execnodes.h:1501
List * mt_mergeActionLists
Definition execnodes.h:1510
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:135
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:2973
TransitionCaptureState * MakeTransitionCaptureState(TriggerDesc *trigdesc, Oid relid, CmdType cmdType)
Definition trigger.c:4980
void ExecARDeleteTriggers(EState *estate, ResultRelInfo *relinfo, ItemPointer tupleid, HeapTuple fdw_trigtuple, TransitionCaptureState *transition_capture, bool is_crosspart_update)
Definition trigger.c:2803
void ExecBSInsertTriggers(EState *estate, ResultRelInfo *relinfo)
Definition trigger.c:2403
bool ExecBRInsertTriggers(EState *estate, ResultRelInfo *relinfo, TupleTableSlot *slot)
Definition trigger.c:2467
bool ExecIRDeleteTriggers(EState *estate, ResultRelInfo *relinfo, HeapTuple trigtuple)
Definition trigger.c:2850
void ExecBSDeleteTriggers(EState *estate, ResultRelInfo *relinfo)
Definition trigger.c:2632
bool ExecIRInsertTriggers(EState *estate, ResultRelInfo *relinfo, TupleTableSlot *slot)
Definition trigger.c:2571
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:3146
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:2703
void ExecASUpdateTriggers(EState *estate, ResultRelInfo *relinfo, TransitionCaptureState *transition_capture)
Definition trigger.c:2955
void ExecASDeleteTriggers(EState *estate, ResultRelInfo *relinfo, TransitionCaptureState *transition_capture)
Definition trigger.c:2683
void ExecARInsertTriggers(EState *estate, ResultRelInfo *relinfo, TupleTableSlot *slot, List *recheckIndexes, TransitionCaptureState *transition_capture)
Definition trigger.c:2545
void ExecASInsertTriggers(EState *estate, ResultRelInfo *relinfo, TransitionCaptureState *transition_capture)
Definition trigger.c:2454
bool ExecIRUpdateTriggers(EState *estate, ResultRelInfo *relinfo, HeapTuple trigtuple, TupleTableSlot *newslot)
Definition trigger.c:3216
void AfterTriggerEndQuery(EState *estate)
Definition trigger.c:5161
void ExecBSUpdateTriggers(EState *estate, ResultRelInfo *relinfo)
Definition trigger.c:2897
void AfterTriggerBeginQuery(void)
Definition trigger.c:5141
#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