PostgreSQL Source Code git master
nodeModifyTable.h File Reference
#include "nodes/execnodes.h"
Include dependency graph for nodeModifyTable.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Functions

void ExecInitGenerated (ResultRelInfo *resultRelInfo, EState *estate, CmdType cmdtype)
 
void ExecComputeStoredGenerated (ResultRelInfo *resultRelInfo, EState *estate, TupleTableSlot *slot, CmdType cmdtype)
 
ModifyTableStateExecInitModifyTable (ModifyTable *node, EState *estate, int eflags)
 
void ExecEndModifyTable (ModifyTableState *node)
 
void ExecReScanModifyTable (ModifyTableState *node)
 
void ExecInitMergeTupleSlots (ModifyTableState *mtstate, ResultRelInfo *resultRelInfo)
 

Function Documentation

◆ ExecComputeStoredGenerated()

void ExecComputeStoredGenerated ( ResultRelInfo resultRelInfo,
EState estate,
TupleTableSlot slot,
CmdType  cmdtype 
)

Definition at line 543 of file nodeModifyTable.c.

546{
547 Relation rel = resultRelInfo->ri_RelationDesc;
548 TupleDesc tupdesc = RelationGetDescr(rel);
549 int natts = tupdesc->natts;
550 ExprContext *econtext = GetPerTupleExprContext(estate);
551 ExprState **ri_GeneratedExprs;
552 MemoryContext oldContext;
553 Datum *values;
554 bool *nulls;
555
556 /* We should not be called unless this is true */
557 Assert(tupdesc->constr && tupdesc->constr->has_generated_stored);
558
559 /*
560 * Initialize the expressions if we didn't already, and check whether we
561 * can exit early because nothing needs to be computed.
562 */
563 if (cmdtype == CMD_UPDATE)
564 {
565 if (resultRelInfo->ri_GeneratedExprsU == NULL)
566 ExecInitGenerated(resultRelInfo, estate, cmdtype);
567 if (resultRelInfo->ri_NumGeneratedNeededU == 0)
568 return;
569 ri_GeneratedExprs = resultRelInfo->ri_GeneratedExprsU;
570 }
571 else
572 {
573 if (resultRelInfo->ri_GeneratedExprsI == NULL)
574 ExecInitGenerated(resultRelInfo, estate, cmdtype);
575 /* Early exit is impossible given the prior Assert */
576 Assert(resultRelInfo->ri_NumGeneratedNeededI > 0);
577 ri_GeneratedExprs = resultRelInfo->ri_GeneratedExprsI;
578 }
579
581
582 values = palloc(sizeof(*values) * natts);
583 nulls = palloc(sizeof(*nulls) * natts);
584
585 slot_getallattrs(slot);
586 memcpy(nulls, slot->tts_isnull, sizeof(*nulls) * natts);
587
588 for (int i = 0; i < natts; i++)
589 {
590 CompactAttribute *attr = TupleDescCompactAttr(tupdesc, i);
591
592 if (ri_GeneratedExprs[i])
593 {
594 Datum val;
595 bool isnull;
596
597 Assert(TupleDescAttr(tupdesc, i)->attgenerated == ATTRIBUTE_GENERATED_STORED);
598
599 econtext->ecxt_scantuple = slot;
600
601 val = ExecEvalExpr(ri_GeneratedExprs[i], econtext, &isnull);
602
603 /*
604 * We must make a copy of val as we have no guarantees about where
605 * memory for a pass-by-reference Datum is located.
606 */
607 if (!isnull)
608 val = datumCopy(val, attr->attbyval, attr->attlen);
609
610 values[i] = val;
611 nulls[i] = isnull;
612 }
613 else
614 {
615 if (!nulls[i])
616 values[i] = datumCopy(slot->tts_values[i], attr->attbyval, attr->attlen);
617 }
618 }
619
620 ExecClearTuple(slot);
621 memcpy(slot->tts_values, values, sizeof(*values) * natts);
622 memcpy(slot->tts_isnull, nulls, sizeof(*nulls) * natts);
625
626 MemoryContextSwitchTo(oldContext);
627}
static Datum values[MAXATTR]
Definition: bootstrap.c:151
Datum datumCopy(Datum value, bool typByVal, int typLen)
Definition: datum.c:132
TupleTableSlot * ExecStoreVirtualTuple(TupleTableSlot *slot)
Definition: execTuples.c:1741
#define GetPerTupleExprContext(estate)
Definition: executor.h:678
#define GetPerTupleMemoryContext(estate)
Definition: executor.h:683
static Datum ExecEvalExpr(ExprState *state, ExprContext *econtext, bool *isNull)
Definition: executor.h:415
Assert(PointerIsAligned(start, uint64))
long val
Definition: informix.c:689
int i
Definition: isn.c:77
void * palloc(Size size)
Definition: mcxt.c:1945
void ExecInitGenerated(ResultRelInfo *resultRelInfo, EState *estate, CmdType cmdtype)
@ CMD_UPDATE
Definition: nodes.h:272
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:124
uintptr_t Datum
Definition: postgres.h:69
#define RelationGetDescr(relation)
Definition: rel.h:542
int16 attlen
Definition: tupdesc.h:71
TupleTableSlot * ecxt_scantuple
Definition: execnodes.h:268
Relation ri_RelationDesc
Definition: execnodes.h:475
ExprState ** ri_GeneratedExprsI
Definition: execnodes.h:561
int ri_NumGeneratedNeededU
Definition: execnodes.h:566
ExprState ** ri_GeneratedExprsU
Definition: execnodes.h:562
int ri_NumGeneratedNeededI
Definition: execnodes.h:565
bool has_generated_stored
Definition: tupdesc.h:46
TupleConstr * constr
Definition: tupdesc.h:141
bool * tts_isnull
Definition: tuptable.h:127
Datum * tts_values
Definition: tuptable.h:125
static FormData_pg_attribute * TupleDescAttr(TupleDesc tupdesc, int i)
Definition: tupdesc.h:160
static CompactAttribute * TupleDescCompactAttr(TupleDesc tupdesc, int i)
Definition: tupdesc.h:175
static TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition: tuptable.h:458
static void slot_getallattrs(TupleTableSlot *slot)
Definition: tuptable.h:372
static void ExecMaterializeSlot(TupleTableSlot *slot)
Definition: tuptable.h:476

References Assert(), CompactAttribute::attbyval, CompactAttribute::attlen, CMD_UPDATE, TupleDescData::constr, datumCopy(), ExprContext::ecxt_scantuple, ExecClearTuple(), ExecEvalExpr(), ExecInitGenerated(), ExecMaterializeSlot(), ExecStoreVirtualTuple(), GetPerTupleExprContext, GetPerTupleMemoryContext, TupleConstr::has_generated_stored, i, MemoryContextSwitchTo(), TupleDescData::natts, palloc(), RelationGetDescr, ResultRelInfo::ri_GeneratedExprsI, ResultRelInfo::ri_GeneratedExprsU, ResultRelInfo::ri_NumGeneratedNeededI, ResultRelInfo::ri_NumGeneratedNeededU, ResultRelInfo::ri_RelationDesc, slot_getallattrs(), TupleTableSlot::tts_isnull, TupleTableSlot::tts_values, TupleDescAttr(), TupleDescCompactAttr(), val, and values.

Referenced by CopyFrom(), ExecInsert(), ExecSimpleRelationInsert(), ExecSimpleRelationUpdate(), and ExecUpdatePrepareSlot().

◆ ExecEndModifyTable()

void ExecEndModifyTable ( ModifyTableState node)

Definition at line 5066 of file nodeModifyTable.c.

5067{
5068 int i;
5069
5070 /*
5071 * Allow any FDWs to shut down
5072 */
5073 for (i = 0; i < node->mt_nrels; i++)
5074 {
5075 int j;
5076 ResultRelInfo *resultRelInfo = node->resultRelInfo + i;
5077
5078 if (!resultRelInfo->ri_usesFdwDirectModify &&
5079 resultRelInfo->ri_FdwRoutine != NULL &&
5080 resultRelInfo->ri_FdwRoutine->EndForeignModify != NULL)
5081 resultRelInfo->ri_FdwRoutine->EndForeignModify(node->ps.state,
5082 resultRelInfo);
5083
5084 /*
5085 * Cleanup the initialized batch slots. This only matters for FDWs
5086 * with batching, but the other cases will have ri_NumSlotsInitialized
5087 * == 0.
5088 */
5089 for (j = 0; j < resultRelInfo->ri_NumSlotsInitialized; j++)
5090 {
5091 ExecDropSingleTupleTableSlot(resultRelInfo->ri_Slots[j]);
5093 }
5094 }
5095
5096 /*
5097 * Close all the partitioned tables, leaf partitions, and their indices
5098 * and release the slot used for tuple routing, if set.
5099 */
5101 {
5103
5104 if (node->mt_root_tuple_slot)
5106 }
5107
5108 /*
5109 * Terminate EPQ execution if active
5110 */
5112
5113 /*
5114 * shut down subplan
5115 */
5117}
void EvalPlanQualEnd(EPQState *epqstate)
Definition: execMain.c:3249
void ExecCleanupTupleRouting(ModifyTableState *mtstate, PartitionTupleRouting *proute)
void ExecEndNode(PlanState *node)
Definition: execProcnode.c:562
void ExecDropSingleTupleTableSlot(TupleTableSlot *slot)
Definition: execTuples.c:1443
#define outerPlanState(node)
Definition: execnodes.h:1255
int j
Definition: isn.c:78
EndForeignModify_function EndForeignModify
Definition: fdwapi.h:237
ResultRelInfo * resultRelInfo
Definition: execnodes.h:1402
struct PartitionTupleRouting * mt_partition_tuple_routing
Definition: execnodes.h:1433
TupleTableSlot * mt_root_tuple_slot
Definition: execnodes.h:1430
EPQState mt_epqstate
Definition: execnodes.h:1412
PlanState ps
Definition: execnodes.h:1397
EState * state
Definition: execnodes.h:1161
TupleTableSlot ** ri_Slots
Definition: execnodes.h:540
int ri_NumSlotsInitialized
Definition: execnodes.h:538
struct FdwRoutine * ri_FdwRoutine
Definition: execnodes.h:528
TupleTableSlot ** ri_PlanSlots
Definition: execnodes.h:541
bool ri_usesFdwDirectModify
Definition: execnodes.h:534

References FdwRoutine::EndForeignModify, EvalPlanQualEnd(), ExecCleanupTupleRouting(), ExecDropSingleTupleTableSlot(), ExecEndNode(), i, j, ModifyTableState::mt_epqstate, ModifyTableState::mt_nrels, ModifyTableState::mt_partition_tuple_routing, ModifyTableState::mt_root_tuple_slot, outerPlanState, ModifyTableState::ps, ModifyTableState::resultRelInfo, ResultRelInfo::ri_FdwRoutine, ResultRelInfo::ri_NumSlotsInitialized, ResultRelInfo::ri_PlanSlots, ResultRelInfo::ri_Slots, ResultRelInfo::ri_usesFdwDirectModify, and PlanState::state.

Referenced by ExecEndNode().

◆ ExecInitGenerated()

void ExecInitGenerated ( ResultRelInfo resultRelInfo,
EState estate,
CmdType  cmdtype 
)

Definition at line 429 of file nodeModifyTable.c.

432{
433 Relation rel = resultRelInfo->ri_RelationDesc;
434 TupleDesc tupdesc = RelationGetDescr(rel);
435 int natts = tupdesc->natts;
436 ExprState **ri_GeneratedExprs;
437 int ri_NumGeneratedNeeded;
438 Bitmapset *updatedCols;
439 MemoryContext oldContext;
440
441 /* Nothing to do if no generated columns */
442 if (!(tupdesc->constr && (tupdesc->constr->has_generated_stored || tupdesc->constr->has_generated_virtual)))
443 return;
444
445 /*
446 * In an UPDATE, we can skip computing any generated columns that do not
447 * depend on any UPDATE target column. But if there is a BEFORE ROW
448 * UPDATE trigger, we cannot skip because the trigger might change more
449 * columns.
450 */
451 if (cmdtype == CMD_UPDATE &&
453 updatedCols = ExecGetUpdatedCols(resultRelInfo, estate);
454 else
455 updatedCols = NULL;
456
457 /*
458 * Make sure these data structures are built in the per-query memory
459 * context so they'll survive throughout the query.
460 */
461 oldContext = MemoryContextSwitchTo(estate->es_query_cxt);
462
463 ri_GeneratedExprs = (ExprState **) palloc0(natts * sizeof(ExprState *));
464 ri_NumGeneratedNeeded = 0;
465
466 for (int i = 0; i < natts; i++)
467 {
468 char attgenerated = TupleDescAttr(tupdesc, i)->attgenerated;
469
470 if (attgenerated)
471 {
472 Expr *expr;
473
474 /* Fetch the GENERATED AS expression tree */
475 expr = (Expr *) build_column_default(rel, i + 1);
476 if (expr == NULL)
477 elog(ERROR, "no generation expression found for column number %d of table \"%s\"",
478 i + 1, RelationGetRelationName(rel));
479
480 /*
481 * If it's an update with a known set of update target columns,
482 * see if we can skip the computation.
483 */
484 if (updatedCols)
485 {
486 Bitmapset *attrs_used = NULL;
487
488 pull_varattnos((Node *) expr, 1, &attrs_used);
489
490 if (!bms_overlap(updatedCols, attrs_used))
491 continue; /* need not update this column */
492 }
493
494 /* No luck, so prepare the expression for execution */
495 if (attgenerated == ATTRIBUTE_GENERATED_STORED)
496 {
497 ri_GeneratedExprs[i] = ExecPrepareExpr(expr, estate);
498 ri_NumGeneratedNeeded++;
499 }
500
501 /* If UPDATE, mark column in resultRelInfo->ri_extraUpdatedCols */
502 if (cmdtype == CMD_UPDATE)
503 resultRelInfo->ri_extraUpdatedCols =
504 bms_add_member(resultRelInfo->ri_extraUpdatedCols,
506 }
507 }
508
509 if (ri_NumGeneratedNeeded == 0)
510 {
511 /* didn't need it after all */
512 pfree(ri_GeneratedExprs);
513 ri_GeneratedExprs = NULL;
514 }
515
516 /* Save in appropriate set of fields */
517 if (cmdtype == CMD_UPDATE)
518 {
519 /* Don't call twice */
520 Assert(resultRelInfo->ri_GeneratedExprsU == NULL);
521
522 resultRelInfo->ri_GeneratedExprsU = ri_GeneratedExprs;
523 resultRelInfo->ri_NumGeneratedNeededU = ri_NumGeneratedNeeded;
524
525 resultRelInfo->ri_extraUpdatedCols_valid = true;
526 }
527 else
528 {
529 /* Don't call twice */
530 Assert(resultRelInfo->ri_GeneratedExprsI == NULL);
531
532 resultRelInfo->ri_GeneratedExprsI = ri_GeneratedExprs;
533 resultRelInfo->ri_NumGeneratedNeededI = ri_NumGeneratedNeeded;
534 }
535
536 MemoryContextSwitchTo(oldContext);
537}
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition: bitmapset.c:815
bool bms_overlap(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:582
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:225
ExprState * ExecPrepareExpr(Expr *node, EState *estate)
Definition: execExpr.c:765
Bitmapset * ExecGetUpdatedCols(ResultRelInfo *relinfo, EState *estate)
Definition: execUtils.c:1383
void pfree(void *pointer)
Definition: mcxt.c:2152
void * palloc0(Size size)
Definition: mcxt.c:1975
#define RelationGetRelationName(relation)
Definition: rel.h:550
Node * build_column_default(Relation rel, int attrno)
MemoryContext es_query_cxt
Definition: execnodes.h:708
Definition: nodes.h:135
TriggerDesc * trigdesc
Definition: rel.h:117
bool ri_extraUpdatedCols_valid
Definition: execnodes.h:495
Bitmapset * ri_extraUpdatedCols
Definition: execnodes.h:493
bool trig_update_before_row
Definition: reltrigger.h:61
bool has_generated_virtual
Definition: tupdesc.h:47
#define FirstLowInvalidHeapAttributeNumber
Definition: sysattr.h:27
void pull_varattnos(Node *node, Index varno, Bitmapset **varattnos)
Definition: var.c:296

References Assert(), bms_add_member(), bms_overlap(), build_column_default(), CMD_UPDATE, TupleDescData::constr, elog, ERROR, EState::es_query_cxt, ExecGetUpdatedCols(), ExecPrepareExpr(), FirstLowInvalidHeapAttributeNumber, TupleConstr::has_generated_stored, TupleConstr::has_generated_virtual, i, MemoryContextSwitchTo(), TupleDescData::natts, palloc0(), pfree(), pull_varattnos(), RelationGetDescr, RelationGetRelationName, ResultRelInfo::ri_extraUpdatedCols, ResultRelInfo::ri_extraUpdatedCols_valid, ResultRelInfo::ri_GeneratedExprsI, ResultRelInfo::ri_GeneratedExprsU, ResultRelInfo::ri_NumGeneratedNeededI, ResultRelInfo::ri_NumGeneratedNeededU, ResultRelInfo::ri_RelationDesc, TriggerDesc::trig_update_before_row, RelationData::trigdesc, and TupleDescAttr().

Referenced by ExecComputeStoredGenerated(), and ExecGetExtraUpdatedCols().

◆ ExecInitMergeTupleSlots()

void ExecInitMergeTupleSlots ( ModifyTableState mtstate,
ResultRelInfo resultRelInfo 
)

Definition at line 3821 of file nodeModifyTable.c.

3823{
3824 EState *estate = mtstate->ps.state;
3825
3826 Assert(!resultRelInfo->ri_projectNewInfoValid);
3827
3828 resultRelInfo->ri_oldTupleSlot =
3829 table_slot_create(resultRelInfo->ri_RelationDesc,
3830 &estate->es_tupleTable);
3831 resultRelInfo->ri_newTupleSlot =
3832 table_slot_create(resultRelInfo->ri_RelationDesc,
3833 &estate->es_tupleTable);
3834 resultRelInfo->ri_projectNewInfoValid = true;
3835}
List * es_tupleTable
Definition: execnodes.h:710
bool ri_projectNewInfoValid
Definition: execnodes.h:504
TupleTableSlot * ri_oldTupleSlot
Definition: execnodes.h:502
TupleTableSlot * ri_newTupleSlot
Definition: execnodes.h:500
TupleTableSlot * table_slot_create(Relation relation, List **reglist)
Definition: tableam.c:92

References Assert(), EState::es_tupleTable, ModifyTableState::ps, ResultRelInfo::ri_newTupleSlot, ResultRelInfo::ri_oldTupleSlot, ResultRelInfo::ri_projectNewInfoValid, ResultRelInfo::ri_RelationDesc, PlanState::state, and table_slot_create().

Referenced by ExecInitMerge(), and ExecInitPartitionInfo().

◆ ExecInitModifyTable()

ModifyTableState * ExecInitModifyTable ( ModifyTable node,
EState estate,
int  eflags 
)

Definition at line 4489 of file nodeModifyTable.c.

4490{
4491 ModifyTableState *mtstate;
4492 Plan *subplan = outerPlan(node);
4493 CmdType operation = node->operation;
4494 int total_nrels = list_length(node->resultRelations);
4495 int nrels;
4496 List *resultRelations = NIL;
4497 List *withCheckOptionLists = NIL;
4498 List *returningLists = NIL;
4499 List *updateColnosLists = NIL;
4500 List *mergeActionLists = NIL;
4501 List *mergeJoinConditions = NIL;
4502 ResultRelInfo *resultRelInfo;
4503 List *arowmarks;
4504 ListCell *l;
4505 int i;
4506 Relation rel;
4507
4508 /* check for unsupported flags */
4509 Assert(!(eflags & (EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK)));
4510
4511 /*
4512 * Only consider unpruned relations for initializing their ResultRelInfo
4513 * struct and other fields such as withCheckOptions, etc.
4514 *
4515 * Note: We must avoid pruning every result relation. This is important
4516 * for MERGE, since even if every result relation is pruned from the
4517 * subplan, there might still be NOT MATCHED rows, for which there may be
4518 * INSERT actions to perform. To allow these actions to be found, at
4519 * least one result relation must be kept. Also, when inserting into a
4520 * partitioned table, ExecInitPartitionInfo() needs a ResultRelInfo struct
4521 * as a reference for building the ResultRelInfo of the target partition.
4522 * In either case, it doesn't matter which result relation is kept, so we
4523 * just keep the first one, if all others have been pruned. See also,
4524 * ExecDoInitialPruning(), which ensures that this first result relation
4525 * has been locked.
4526 */
4527 i = 0;
4528 foreach(l, node->resultRelations)
4529 {
4530 Index rti = lfirst_int(l);
4531 bool keep_rel;
4532
4533 keep_rel = bms_is_member(rti, estate->es_unpruned_relids);
4534 if (!keep_rel && i == total_nrels - 1 && resultRelations == NIL)
4535 {
4536 /* all result relations pruned; keep the first one */
4537 keep_rel = true;
4538 rti = linitial_int(node->resultRelations);
4539 i = 0;
4540 }
4541
4542 if (keep_rel)
4543 {
4544 resultRelations = lappend_int(resultRelations, rti);
4545 if (node->withCheckOptionLists)
4546 {
4547 List *withCheckOptions = list_nth_node(List,
4549 i);
4550
4551 withCheckOptionLists = lappend(withCheckOptionLists, withCheckOptions);
4552 }
4553 if (node->returningLists)
4554 {
4555 List *returningList = list_nth_node(List,
4556 node->returningLists,
4557 i);
4558
4559 returningLists = lappend(returningLists, returningList);
4560 }
4561 if (node->updateColnosLists)
4562 {
4563 List *updateColnosList = list_nth(node->updateColnosLists, i);
4564
4565 updateColnosLists = lappend(updateColnosLists, updateColnosList);
4566 }
4567 if (node->mergeActionLists)
4568 {
4569 List *mergeActionList = list_nth(node->mergeActionLists, i);
4570
4571 mergeActionLists = lappend(mergeActionLists, mergeActionList);
4572 }
4573 if (node->mergeJoinConditions)
4574 {
4575 List *mergeJoinCondition = list_nth(node->mergeJoinConditions, i);
4576
4577 mergeJoinConditions = lappend(mergeJoinConditions, mergeJoinCondition);
4578 }
4579 }
4580 i++;
4581 }
4582 nrels = list_length(resultRelations);
4583 Assert(nrels > 0);
4584
4585 /*
4586 * create state structure
4587 */
4588 mtstate = makeNode(ModifyTableState);
4589 mtstate->ps.plan = (Plan *) node;
4590 mtstate->ps.state = estate;
4591 mtstate->ps.ExecProcNode = ExecModifyTable;
4592
4593 mtstate->operation = operation;
4594 mtstate->canSetTag = node->canSetTag;
4595 mtstate->mt_done = false;
4596
4597 mtstate->mt_nrels = nrels;
4598 mtstate->resultRelInfo = (ResultRelInfo *)
4599 palloc(nrels * sizeof(ResultRelInfo));
4600
4601 mtstate->mt_merge_pending_not_matched = NULL;
4602 mtstate->mt_merge_inserted = 0;
4603 mtstate->mt_merge_updated = 0;
4604 mtstate->mt_merge_deleted = 0;
4605 mtstate->mt_updateColnosLists = updateColnosLists;
4606 mtstate->mt_mergeActionLists = mergeActionLists;
4607 mtstate->mt_mergeJoinConditions = mergeJoinConditions;
4608
4609 /*----------
4610 * Resolve the target relation. This is the same as:
4611 *
4612 * - the relation for which we will fire FOR STATEMENT triggers,
4613 * - the relation into whose tuple format all captured transition tuples
4614 * must be converted, and
4615 * - the root partitioned table used for tuple routing.
4616 *
4617 * If it's a partitioned or inherited table, the root partition or
4618 * appendrel RTE doesn't appear elsewhere in the plan and its RT index is
4619 * given explicitly in node->rootRelation. Otherwise, the target relation
4620 * is the sole relation in the node->resultRelations list and, since it can
4621 * never be pruned, also in the resultRelations list constructed above.
4622 *----------
4623 */
4624 if (node->rootRelation > 0)
4625 {
4629 node->rootRelation);
4630 }
4631 else
4632 {
4633 Assert(list_length(node->resultRelations) == 1);
4634 Assert(list_length(resultRelations) == 1);
4635 mtstate->rootResultRelInfo = mtstate->resultRelInfo;
4636 ExecInitResultRelation(estate, mtstate->resultRelInfo,
4637 linitial_int(resultRelations));
4638 }
4639
4640 /* set up epqstate with dummy subplan data for the moment */
4641 EvalPlanQualInit(&mtstate->mt_epqstate, estate, NULL, NIL,
4642 node->epqParam, resultRelations);
4643 mtstate->fireBSTriggers = true;
4644
4645 /*
4646 * Build state for collecting transition tuples. This requires having a
4647 * valid trigger query context, so skip it in explain-only mode.
4648 */
4649 if (!(eflags & EXEC_FLAG_EXPLAIN_ONLY))
4650 ExecSetupTransitionCaptureState(mtstate, estate);
4651
4652 /*
4653 * Open all the result relations and initialize the ResultRelInfo structs.
4654 * (But root relation was initialized above, if it's part of the array.)
4655 * We must do this before initializing the subplan, because direct-modify
4656 * FDWs expect their ResultRelInfos to be available.
4657 */
4658 resultRelInfo = mtstate->resultRelInfo;
4659 i = 0;
4660 foreach(l, resultRelations)
4661 {
4662 Index resultRelation = lfirst_int(l);
4663 List *mergeActions = NIL;
4664
4665 if (mergeActionLists)
4666 mergeActions = list_nth(mergeActionLists, i);
4667
4668 if (resultRelInfo != mtstate->rootResultRelInfo)
4669 {
4670 ExecInitResultRelation(estate, resultRelInfo, resultRelation);
4671
4672 /*
4673 * For child result relations, store the root result relation
4674 * pointer. We do so for the convenience of places that want to
4675 * look at the query's original target relation but don't have the
4676 * mtstate handy.
4677 */
4678 resultRelInfo->ri_RootResultRelInfo = mtstate->rootResultRelInfo;
4679 }
4680
4681 /* Initialize the usesFdwDirectModify flag */
4682 resultRelInfo->ri_usesFdwDirectModify =
4684
4685 /*
4686 * Verify result relation is a valid target for the current operation
4687 */
4688 CheckValidResultRel(resultRelInfo, operation, mergeActions);
4689
4690 resultRelInfo++;
4691 i++;
4692 }
4693
4694 /*
4695 * Now we may initialize the subplan.
4696 */
4697 outerPlanState(mtstate) = ExecInitNode(subplan, estate, eflags);
4698
4699 /*
4700 * Do additional per-result-relation initialization.
4701 */
4702 for (i = 0; i < nrels; i++)
4703 {
4704 resultRelInfo = &mtstate->resultRelInfo[i];
4705
4706 /* Let FDWs init themselves for foreign-table result rels */
4707 if (!resultRelInfo->ri_usesFdwDirectModify &&
4708 resultRelInfo->ri_FdwRoutine != NULL &&
4709 resultRelInfo->ri_FdwRoutine->BeginForeignModify != NULL)
4710 {
4711 List *fdw_private = (List *) list_nth(node->fdwPrivLists, i);
4712
4713 resultRelInfo->ri_FdwRoutine->BeginForeignModify(mtstate,
4714 resultRelInfo,
4715 fdw_private,
4716 i,
4717 eflags);
4718 }
4719
4720 /*
4721 * For UPDATE/DELETE/MERGE, find the appropriate junk attr now, either
4722 * a 'ctid' or 'wholerow' attribute depending on relkind. For foreign
4723 * tables, the FDW might have created additional junk attr(s), but
4724 * those are no concern of ours.
4725 */
4726 if (operation == CMD_UPDATE || operation == CMD_DELETE ||
4727 operation == CMD_MERGE)
4728 {
4729 char relkind;
4730
4731 relkind = resultRelInfo->ri_RelationDesc->rd_rel->relkind;
4732 if (relkind == RELKIND_RELATION ||
4733 relkind == RELKIND_MATVIEW ||
4734 relkind == RELKIND_PARTITIONED_TABLE)
4735 {
4736 resultRelInfo->ri_RowIdAttNo =
4737 ExecFindJunkAttributeInTlist(subplan->targetlist, "ctid");
4738 if (!AttributeNumberIsValid(resultRelInfo->ri_RowIdAttNo))
4739 elog(ERROR, "could not find junk ctid column");
4740 }
4741 else if (relkind == RELKIND_FOREIGN_TABLE)
4742 {
4743 /*
4744 * We don't support MERGE with foreign tables for now. (It's
4745 * problematic because the implementation uses CTID.)
4746 */
4747 Assert(operation != CMD_MERGE);
4748
4749 /*
4750 * When there is a row-level trigger, there should be a
4751 * wholerow attribute. We also require it to be present in
4752 * UPDATE and MERGE, so we can get the values of unchanged
4753 * columns.
4754 */
4755 resultRelInfo->ri_RowIdAttNo =
4757 "wholerow");
4758 if ((mtstate->operation == CMD_UPDATE || mtstate->operation == CMD_MERGE) &&
4759 !AttributeNumberIsValid(resultRelInfo->ri_RowIdAttNo))
4760 elog(ERROR, "could not find junk wholerow column");
4761 }
4762 else
4763 {
4764 /* Other valid target relkinds must provide wholerow */
4765 resultRelInfo->ri_RowIdAttNo =
4767 "wholerow");
4768 if (!AttributeNumberIsValid(resultRelInfo->ri_RowIdAttNo))
4769 elog(ERROR, "could not find junk wholerow column");
4770 }
4771 }
4772 }
4773
4774 /*
4775 * If this is an inherited update/delete/merge, there will be a junk
4776 * attribute named "tableoid" present in the subplan's targetlist. It
4777 * will be used to identify the result relation for a given tuple to be
4778 * updated/deleted/merged.
4779 */
4780 mtstate->mt_resultOidAttno =
4781 ExecFindJunkAttributeInTlist(subplan->targetlist, "tableoid");
4782 Assert(AttributeNumberIsValid(mtstate->mt_resultOidAttno) || total_nrels == 1);
4783 mtstate->mt_lastResultOid = InvalidOid; /* force lookup at first tuple */
4784 mtstate->mt_lastResultIndex = 0; /* must be zero if no such attr */
4785
4786 /* Get the root target relation */
4787 rel = mtstate->rootResultRelInfo->ri_RelationDesc;
4788
4789 /*
4790 * Build state for tuple routing if it's a partitioned INSERT. An UPDATE
4791 * or MERGE might need this too, but only if it actually moves tuples
4792 * between partitions; in that case setup is done by
4793 * ExecCrossPartitionUpdate.
4794 */
4795 if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE &&
4796 operation == CMD_INSERT)
4798 ExecSetupPartitionTupleRouting(estate, rel);
4799
4800 /*
4801 * Initialize any WITH CHECK OPTION constraints if needed.
4802 */
4803 resultRelInfo = mtstate->resultRelInfo;
4804 foreach(l, withCheckOptionLists)
4805 {
4806 List *wcoList = (List *) lfirst(l);
4807 List *wcoExprs = NIL;
4808 ListCell *ll;
4809
4810 foreach(ll, wcoList)
4811 {
4812 WithCheckOption *wco = (WithCheckOption *) lfirst(ll);
4813 ExprState *wcoExpr = ExecInitQual((List *) wco->qual,
4814 &mtstate->ps);
4815
4816 wcoExprs = lappend(wcoExprs, wcoExpr);
4817 }
4818
4819 resultRelInfo->ri_WithCheckOptions = wcoList;
4820 resultRelInfo->ri_WithCheckOptionExprs = wcoExprs;
4821 resultRelInfo++;
4822 }
4823
4824 /*
4825 * Initialize RETURNING projections if needed.
4826 */
4827 if (returningLists)
4828 {
4829 TupleTableSlot *slot;
4830 ExprContext *econtext;
4831
4832 /*
4833 * Initialize result tuple slot and assign its rowtype using the first
4834 * RETURNING list. We assume the rest will look the same.
4835 */
4836 mtstate->ps.plan->targetlist = (List *) linitial(returningLists);
4837
4838 /* Set up a slot for the output of the RETURNING projection(s) */
4840 slot = mtstate->ps.ps_ResultTupleSlot;
4841
4842 /* Need an econtext too */
4843 if (mtstate->ps.ps_ExprContext == NULL)
4844 ExecAssignExprContext(estate, &mtstate->ps);
4845 econtext = mtstate->ps.ps_ExprContext;
4846
4847 /*
4848 * Build a projection for each result rel.
4849 */
4850 resultRelInfo = mtstate->resultRelInfo;
4851 foreach(l, returningLists)
4852 {
4853 List *rlist = (List *) lfirst(l);
4854
4855 resultRelInfo->ri_returningList = rlist;
4856 resultRelInfo->ri_projectReturning =
4857 ExecBuildProjectionInfo(rlist, econtext, slot, &mtstate->ps,
4858 resultRelInfo->ri_RelationDesc->rd_att);
4859 resultRelInfo++;
4860 }
4861 }
4862 else
4863 {
4864 /*
4865 * We still must construct a dummy result tuple type, because InitPlan
4866 * expects one (maybe should change that?).
4867 */
4868 mtstate->ps.plan->targetlist = NIL;
4869 ExecInitResultTypeTL(&mtstate->ps);
4870
4871 mtstate->ps.ps_ExprContext = NULL;
4872 }
4873
4874 /* Set the list of arbiter indexes if needed for ON CONFLICT */
4875 resultRelInfo = mtstate->resultRelInfo;
4876 if (node->onConflictAction != ONCONFLICT_NONE)
4877 {
4878 /* insert may only have one relation, inheritance is not expanded */
4879 Assert(total_nrels == 1);
4880 resultRelInfo->ri_onConflictArbiterIndexes = node->arbiterIndexes;
4881 }
4882
4883 /*
4884 * If needed, Initialize target list, projection and qual for ON CONFLICT
4885 * DO UPDATE.
4886 */
4888 {
4890 ExprContext *econtext;
4891 TupleDesc relationDesc;
4892
4893 /* already exists if created by RETURNING processing above */
4894 if (mtstate->ps.ps_ExprContext == NULL)
4895 ExecAssignExprContext(estate, &mtstate->ps);
4896
4897 econtext = mtstate->ps.ps_ExprContext;
4898 relationDesc = resultRelInfo->ri_RelationDesc->rd_att;
4899
4900 /* create state for DO UPDATE SET operation */
4901 resultRelInfo->ri_onConflict = onconfl;
4902
4903 /* initialize slot for the existing tuple */
4904 onconfl->oc_Existing =
4905 table_slot_create(resultRelInfo->ri_RelationDesc,
4906 &mtstate->ps.state->es_tupleTable);
4907
4908 /*
4909 * Create the tuple slot for the UPDATE SET projection. We want a slot
4910 * of the table's type here, because the slot will be used to insert
4911 * into the table, and for RETURNING processing - which may access
4912 * system attributes.
4913 */
4914 onconfl->oc_ProjSlot =
4915 table_slot_create(resultRelInfo->ri_RelationDesc,
4916 &mtstate->ps.state->es_tupleTable);
4917
4918 /* build UPDATE SET projection state */
4919 onconfl->oc_ProjInfo =
4921 true,
4922 node->onConflictCols,
4923 relationDesc,
4924 econtext,
4925 onconfl->oc_ProjSlot,
4926 &mtstate->ps);
4927
4928 /* initialize state to evaluate the WHERE clause, if any */
4929 if (node->onConflictWhere)
4930 {
4931 ExprState *qualexpr;
4932
4933 qualexpr = ExecInitQual((List *) node->onConflictWhere,
4934 &mtstate->ps);
4935 onconfl->oc_WhereClause = qualexpr;
4936 }
4937 }
4938
4939 /*
4940 * If we have any secondary relations in an UPDATE or DELETE, they need to
4941 * be treated like non-locked relations in SELECT FOR UPDATE, i.e., the
4942 * EvalPlanQual mechanism needs to be told about them. This also goes for
4943 * the source relations in a MERGE. Locate the relevant ExecRowMarks.
4944 */
4945 arowmarks = NIL;
4946 foreach(l, node->rowMarks)
4947 {
4949 ExecRowMark *erm;
4950 ExecAuxRowMark *aerm;
4951
4952 /*
4953 * Ignore "parent" rowmarks, because they are irrelevant at runtime.
4954 * Also ignore the rowmarks belonging to child tables that have been
4955 * pruned in ExecDoInitialPruning().
4956 */
4957 if (rc->isParent ||
4958 !bms_is_member(rc->rti, estate->es_unpruned_relids))
4959 continue;
4960
4961 /* Find ExecRowMark and build ExecAuxRowMark */
4962 erm = ExecFindRowMark(estate, rc->rti, false);
4963 aerm = ExecBuildAuxRowMark(erm, subplan->targetlist);
4964 arowmarks = lappend(arowmarks, aerm);
4965 }
4966
4967 /* For a MERGE command, initialize its state */
4968 if (mtstate->operation == CMD_MERGE)
4969 ExecInitMerge(mtstate, estate);
4970
4971 EvalPlanQualSetPlan(&mtstate->mt_epqstate, subplan, arowmarks);
4972
4973 /*
4974 * If there are a lot of result relations, use a hash table to speed the
4975 * lookups. If there are not a lot, a simple linear search is faster.
4976 *
4977 * It's not clear where the threshold is, but try 64 for starters. In a
4978 * debugging build, use a small threshold so that we get some test
4979 * coverage of both code paths.
4980 */
4981#ifdef USE_ASSERT_CHECKING
4982#define MT_NRELS_HASH 4
4983#else
4984#define MT_NRELS_HASH 64
4985#endif
4986 if (nrels >= MT_NRELS_HASH)
4987 {
4988 HASHCTL hash_ctl;
4989
4990 hash_ctl.keysize = sizeof(Oid);
4991 hash_ctl.entrysize = sizeof(MTTargetRelLookup);
4992 hash_ctl.hcxt = CurrentMemoryContext;
4993 mtstate->mt_resultOidHash =
4994 hash_create("ModifyTable target hash",
4995 nrels, &hash_ctl,
4997 for (i = 0; i < nrels; i++)
4998 {
4999 Oid hashkey;
5000 MTTargetRelLookup *mtlookup;
5001 bool found;
5002
5003 resultRelInfo = &mtstate->resultRelInfo[i];
5004 hashkey = RelationGetRelid(resultRelInfo->ri_RelationDesc);
5005 mtlookup = (MTTargetRelLookup *)
5006 hash_search(mtstate->mt_resultOidHash, &hashkey,
5007 HASH_ENTER, &found);
5008 Assert(!found);
5009 mtlookup->relationIndex = i;
5010 }
5011 }
5012 else
5013 mtstate->mt_resultOidHash = NULL;
5014
5015 /*
5016 * Determine if the FDW supports batch insert and determine the batch size
5017 * (a FDW may support batching, but it may be disabled for the
5018 * server/table).
5019 *
5020 * We only do this for INSERT, so that for UPDATE/DELETE the batch size
5021 * remains set to 0.
5022 */
5023 if (operation == CMD_INSERT)
5024 {
5025 /* insert may only have one relation, inheritance is not expanded */
5026 Assert(total_nrels == 1);
5027 resultRelInfo = mtstate->resultRelInfo;
5028 if (!resultRelInfo->ri_usesFdwDirectModify &&
5029 resultRelInfo->ri_FdwRoutine != NULL &&
5030 resultRelInfo->ri_FdwRoutine->GetForeignModifyBatchSize &&
5031 resultRelInfo->ri_FdwRoutine->ExecForeignBatchInsert)
5032 {
5033 resultRelInfo->ri_BatchSize =
5034 resultRelInfo->ri_FdwRoutine->GetForeignModifyBatchSize(resultRelInfo);
5035 Assert(resultRelInfo->ri_BatchSize >= 1);
5036 }
5037 else
5038 resultRelInfo->ri_BatchSize = 1;
5039 }
5040
5041 /*
5042 * Lastly, if this is not the primary (canSetTag) ModifyTable node, add it
5043 * to estate->es_auxmodifytables so that it will be run to completion by
5044 * ExecPostprocessPlan. (It'd actually work fine to add the primary
5045 * ModifyTable node too, but there's no need.) Note the use of lcons not
5046 * lappend: we need later-initialized ModifyTable nodes to be shut down
5047 * before earlier ones. This ensures that we don't throw away RETURNING
5048 * rows that need to be seen by a later CTE subplan.
5049 */
5050 if (!mtstate->canSetTag)
5051 estate->es_auxmodifytables = lcons(mtstate,
5052 estate->es_auxmodifytables);
5053
5054 return mtstate;
5055}
#define AttributeNumberIsValid(attributeNumber)
Definition: attnum.h:34
bool bms_is_member(int x, const Bitmapset *a)
Definition: bitmapset.c:510
unsigned int Index
Definition: c.h:585
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:956
HTAB * hash_create(const char *tabname, long nelem, const HASHCTL *info, int flags)
Definition: dynahash.c:352
ProjectionInfo * ExecBuildProjectionInfo(List *targetList, ExprContext *econtext, TupleTableSlot *slot, PlanState *parent, TupleDesc inputDesc)
Definition: execExpr.c:370
ExprState * ExecInitQual(List *qual, PlanState *parent)
Definition: execExpr.c:229
ProjectionInfo * ExecBuildUpdateProjection(List *targetList, bool evalTargetList, List *targetColnos, TupleDesc relDesc, ExprContext *econtext, TupleTableSlot *slot, PlanState *parent)
Definition: execExpr.c:547
AttrNumber ExecFindJunkAttributeInTlist(List *targetlist, const char *attrName)
Definition: execJunk.c:222
ExecRowMark * ExecFindRowMark(EState *estate, Index rti, bool missing_ok)
Definition: execMain.c:2632
ExecAuxRowMark * ExecBuildAuxRowMark(ExecRowMark *erm, List *targetlist)
Definition: execMain.c:2655
void CheckValidResultRel(ResultRelInfo *resultRelInfo, CmdType operation, List *mergeActions)
Definition: execMain.c:1152
void EvalPlanQualInit(EPQState *epqstate, EState *parentestate, Plan *subplan, List *auxrowmarks, int epqParam, List *resultRelations)
Definition: execMain.c:2794
void EvalPlanQualSetPlan(EPQState *epqstate, Plan *subplan, List *auxrowmarks)
Definition: execMain.c:2836
PartitionTupleRouting * ExecSetupPartitionTupleRouting(EState *estate, Relation rel)
PlanState * ExecInitNode(Plan *node, EState *estate, int eflags)
Definition: execProcnode.c:142
const TupleTableSlotOps TTSOpsVirtual
Definition: execTuples.c:84
void ExecInitResultTypeTL(PlanState *planstate)
Definition: execTuples.c:1944
void ExecInitResultTupleSlotTL(PlanState *planstate, const TupleTableSlotOps *tts_ops)
Definition: execTuples.c:1988
void ExecInitResultRelation(EState *estate, ResultRelInfo *resultRelInfo, Index rti)
Definition: execUtils.c:881
void ExecAssignExprContext(EState *estate, PlanState *planstate)
Definition: execUtils.c:486
#define EXEC_FLAG_BACKWARD
Definition: executor.h:69
#define EXEC_FLAG_EXPLAIN_ONLY
Definition: executor.h:66
#define EXEC_FLAG_MARK
Definition: executor.h:70
@ HASH_ENTER
Definition: hsearch.h:114
#define HASH_CONTEXT
Definition: hsearch.h:102
#define HASH_ELEM
Definition: hsearch.h:95
#define HASH_BLOBS
Definition: hsearch.h:97
List * lappend(List *list, void *datum)
Definition: list.c:339
List * lappend_int(List *list, int datum)
Definition: list.c:357
List * lcons(void *datum, List *list)
Definition: list.c:495
MemoryContext CurrentMemoryContext
Definition: mcxt.c:159
static void ExecSetupTransitionCaptureState(ModifyTableState *mtstate, EState *estate)
static TupleTableSlot * ExecModifyTable(PlanState *pstate)
struct MTTargetRelLookup MTTargetRelLookup
#define MT_NRELS_HASH
static void ExecInitMerge(ModifyTableState *mtstate, EState *estate)
@ ONCONFLICT_NONE
Definition: nodes.h:424
@ ONCONFLICT_UPDATE
Definition: nodes.h:426
CmdType
Definition: nodes.h:269
@ CMD_MERGE
Definition: nodes.h:275
@ CMD_INSERT
Definition: nodes.h:273
@ CMD_DELETE
Definition: nodes.h:274
#define makeNode(_type_)
Definition: nodes.h:161
#define lfirst(lc)
Definition: pg_list.h:172
#define lfirst_node(type, lc)
Definition: pg_list.h:176
static int list_length(const List *l)
Definition: pg_list.h:152
#define NIL
Definition: pg_list.h:68
#define lfirst_int(lc)
Definition: pg_list.h:173
#define linitial_int(l)
Definition: pg_list.h:179
static void * list_nth(const List *list, int n)
Definition: pg_list.h:299
#define linitial(l)
Definition: pg_list.h:178
#define list_nth_node(type, list, n)
Definition: pg_list.h:327
#define outerPlan(node)
Definition: plannodes.h:241
#define InvalidOid
Definition: postgres_ext.h:35
unsigned int Oid
Definition: postgres_ext.h:30
#define RelationGetRelid(relation)
Definition: rel.h:516
Bitmapset * es_unpruned_relids
Definition: execnodes.h:671
List * es_auxmodifytables
Definition: execnodes.h:726
BeginForeignModify_function BeginForeignModify
Definition: fdwapi.h:231
ExecForeignBatchInsert_function ExecForeignBatchInsert
Definition: fdwapi.h:233
GetForeignModifyBatchSize_function GetForeignModifyBatchSize
Definition: fdwapi.h:234
Size keysize
Definition: hsearch.h:75
Size entrysize
Definition: hsearch.h:76
MemoryContext hcxt
Definition: hsearch.h:86
Definition: pg_list.h:54
List * mt_mergeJoinConditions
Definition: execnodes.h:1466
CmdType operation
Definition: execnodes.h:1398
TupleTableSlot * mt_merge_pending_not_matched
Definition: execnodes.h:1452
double mt_merge_deleted
Definition: execnodes.h:1457
List * mt_updateColnosLists
Definition: execnodes.h:1464
double mt_merge_inserted
Definition: execnodes.h:1455
double mt_merge_updated
Definition: execnodes.h:1456
List * mt_mergeActionLists
Definition: execnodes.h:1465
HTAB * mt_resultOidHash
Definition: execnodes.h:1424
ResultRelInfo * rootResultRelInfo
Definition: execnodes.h:1410
List * updateColnosLists
Definition: plannodes.h:304
List * arbiterIndexes
Definition: plannodes.h:324
List * onConflictCols
Definition: plannodes.h:328
List * mergeJoinConditions
Definition: plannodes.h:338
CmdType operation
Definition: plannodes.h:292
int epqParam
Definition: plannodes.h:320
List * resultRelations
Definition: plannodes.h:302
Bitmapset * fdwDirectModifyPlans
Definition: plannodes.h:316
List * onConflictSet
Definition: plannodes.h:326
List * mergeActionLists
Definition: plannodes.h:336
bool canSetTag
Definition: plannodes.h:294
List * fdwPrivLists
Definition: plannodes.h:314
List * returningLists
Definition: plannodes.h:312
List * withCheckOptionLists
Definition: plannodes.h:306
Index rootRelation
Definition: plannodes.h:298
Node * onConflictWhere
Definition: plannodes.h:330
List * rowMarks
Definition: plannodes.h:318
OnConflictAction onConflictAction
Definition: plannodes.h:322
TupleTableSlot * oc_ProjSlot
Definition: execnodes.h:429
TupleTableSlot * oc_Existing
Definition: execnodes.h:428
ExprState * oc_WhereClause
Definition: execnodes.h:431
ProjectionInfo * oc_ProjInfo
Definition: execnodes.h:430
bool isParent
Definition: plannodes.h:1554
Plan * plan
Definition: execnodes.h:1159
ExprContext * ps_ExprContext
Definition: execnodes.h:1198
TupleTableSlot * ps_ResultTupleSlot
Definition: execnodes.h:1197
ExecProcNodeMtd ExecProcNode
Definition: execnodes.h:1165
List * targetlist
Definition: plannodes.h:209
TupleDesc rd_att
Definition: rel.h:112
Form_pg_class rd_rel
Definition: rel.h:111
OnConflictSetState * ri_onConflict
Definition: execnodes.h:578
List * ri_onConflictArbiterIndexes
Definition: execnodes.h:575
struct ResultRelInfo * ri_RootResultRelInfo
Definition: execnodes.h:615
List * ri_WithCheckOptions
Definition: execnodes.h:544
List * ri_WithCheckOptionExprs
Definition: execnodes.h:547
ProjectionInfo * ri_projectReturning
Definition: execnodes.h:572
List * ri_returningList
Definition: execnodes.h:569
AttrNumber ri_RowIdAttNo
Definition: execnodes.h:490
int ri_BatchSize
Definition: execnodes.h:539

References ModifyTable::arbiterIndexes, Assert(), AttributeNumberIsValid, FdwRoutine::BeginForeignModify, bms_is_member(), ModifyTableState::canSetTag, ModifyTable::canSetTag, CheckValidResultRel(), CMD_DELETE, CMD_INSERT, CMD_MERGE, CMD_UPDATE, CurrentMemoryContext, elog, HASHCTL::entrysize, ModifyTable::epqParam, ERROR, EState::es_auxmodifytables, EState::es_tupleTable, EState::es_unpruned_relids, EvalPlanQualInit(), EvalPlanQualSetPlan(), EXEC_FLAG_BACKWARD, EXEC_FLAG_EXPLAIN_ONLY, EXEC_FLAG_MARK, ExecAssignExprContext(), ExecBuildAuxRowMark(), ExecBuildProjectionInfo(), ExecBuildUpdateProjection(), ExecFindJunkAttributeInTlist(), ExecFindRowMark(), FdwRoutine::ExecForeignBatchInsert, ExecInitMerge(), ExecInitNode(), ExecInitQual(), ExecInitResultRelation(), ExecInitResultTupleSlotTL(), ExecInitResultTypeTL(), ExecModifyTable(), PlanState::ExecProcNode, ExecSetupPartitionTupleRouting(), ExecSetupTransitionCaptureState(), ModifyTable::fdwDirectModifyPlans, ModifyTable::fdwPrivLists, ModifyTableState::fireBSTriggers, FdwRoutine::GetForeignModifyBatchSize, HASH_BLOBS, HASH_CONTEXT, hash_create(), HASH_ELEM, HASH_ENTER, hash_search(), HASHCTL::hcxt, i, InvalidOid, PlanRowMark::isParent, HASHCTL::keysize, lappend(), lappend_int(), lcons(), lfirst, lfirst_int, lfirst_node, linitial, linitial_int, list_length(), list_nth(), list_nth_node, makeNode, ModifyTable::mergeActionLists, ModifyTable::mergeJoinConditions, ModifyTableState::mt_done, ModifyTableState::mt_epqstate, ModifyTableState::mt_lastResultIndex, ModifyTableState::mt_lastResultOid, ModifyTableState::mt_merge_deleted, ModifyTableState::mt_merge_inserted, ModifyTableState::mt_merge_pending_not_matched, ModifyTableState::mt_merge_updated, ModifyTableState::mt_mergeActionLists, ModifyTableState::mt_mergeJoinConditions, ModifyTableState::mt_nrels, MT_NRELS_HASH, ModifyTableState::mt_partition_tuple_routing, ModifyTableState::mt_resultOidAttno, ModifyTableState::mt_resultOidHash, ModifyTableState::mt_updateColnosLists, NIL, OnConflictSetState::oc_Existing, OnConflictSetState::oc_ProjInfo, OnConflictSetState::oc_ProjSlot, OnConflictSetState::oc_WhereClause, ONCONFLICT_NONE, ONCONFLICT_UPDATE, ModifyTable::onConflictAction, ModifyTable::onConflictCols, ModifyTable::onConflictSet, ModifyTable::onConflictWhere, ModifyTableState::operation, ModifyTable::operation, outerPlan, outerPlanState, palloc(), PlanState::plan, ModifyTableState::ps, PlanState::ps_ExprContext, PlanState::ps_ResultTupleSlot, WithCheckOption::qual, RelationData::rd_att, RelationData::rd_rel, RelationGetRelid, MTTargetRelLookup::relationIndex, ModifyTable::resultRelations, ModifyTableState::resultRelInfo, ModifyTable::returningLists, ResultRelInfo::ri_BatchSize, ResultRelInfo::ri_FdwRoutine, ResultRelInfo::ri_onConflict, ResultRelInfo::ri_onConflictArbiterIndexes, ResultRelInfo::ri_projectReturning, ResultRelInfo::ri_RelationDesc, ResultRelInfo::ri_returningList, ResultRelInfo::ri_RootResultRelInfo, ResultRelInfo::ri_RowIdAttNo, ResultRelInfo::ri_usesFdwDirectModify, ResultRelInfo::ri_WithCheckOptionExprs, ResultRelInfo::ri_WithCheckOptions, ModifyTable::rootRelation, ModifyTableState::rootResultRelInfo, ModifyTable::rowMarks, PlanRowMark::rti, PlanState::state, table_slot_create(), Plan::targetlist, TTSOpsVirtual, ModifyTable::updateColnosLists, and ModifyTable::withCheckOptionLists.

Referenced by ExecInitNode().

◆ ExecReScanModifyTable()

void ExecReScanModifyTable ( ModifyTableState node)

Definition at line 5120 of file nodeModifyTable.c.

5121{
5122 /*
5123 * Currently, we don't need to support rescan on ModifyTable nodes. The
5124 * semantics of that would be a bit debatable anyway.
5125 */
5126 elog(ERROR, "ExecReScanModifyTable is not implemented");
5127}

References elog, and ERROR.

Referenced by ExecReScan().