Coverage Report

Created: 2026-08-13 07:12

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