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