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