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