PostgreSQL Source Code git master
Loading...
Searching...
No Matches
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 
)
extern

Definition at line 545 of file nodeModifyTable.c.

548{
549 Relation rel = resultRelInfo->ri_RelationDesc;
550 TupleDesc tupdesc = RelationGetDescr(rel);
551 int natts = tupdesc->natts;
552 ExprContext *econtext = GetPerTupleExprContext(estate);
555 Datum *values;
556 bool *nulls;
557
558 /* We should not be called unless this is true */
559 Assert(tupdesc->constr && tupdesc->constr->has_generated_stored);
560
561 /*
562 * Initialize the expressions if we didn't already, and check whether we
563 * can exit early because nothing needs to be computed.
564 */
565 if (cmdtype == CMD_UPDATE)
566 {
567 if (resultRelInfo->ri_GeneratedExprsU == NULL)
568 ExecInitGenerated(resultRelInfo, estate, cmdtype);
569 if (resultRelInfo->ri_NumGeneratedNeededU == 0)
570 return;
571 ri_GeneratedExprs = resultRelInfo->ri_GeneratedExprsU;
572 }
573 else
574 {
575 if (resultRelInfo->ri_GeneratedExprsI == NULL)
576 ExecInitGenerated(resultRelInfo, estate, cmdtype);
577 /* Early exit is impossible given the prior Assert */
578 Assert(resultRelInfo->ri_NumGeneratedNeededI > 0);
579 ri_GeneratedExprs = resultRelInfo->ri_GeneratedExprsI;
580 }
581
583
584 values = palloc_array(Datum, natts);
585 nulls = palloc_array(bool, natts);
586
587 slot_getallattrs(slot);
588 memcpy(nulls, slot->tts_isnull, sizeof(*nulls) * natts);
589
590 for (int i = 0; i < natts; i++)
591 {
592 CompactAttribute *attr = TupleDescCompactAttr(tupdesc, i);
593
594 if (ri_GeneratedExprs[i])
595 {
596 Datum val;
597 bool isnull;
598
599 Assert(TupleDescAttr(tupdesc, i)->attgenerated == ATTRIBUTE_GENERATED_STORED);
600
601 econtext->ecxt_scantuple = slot;
602
603 val = ExecEvalExpr(ri_GeneratedExprs[i], econtext, &isnull);
604
605 /*
606 * We must make a copy of val as we have no guarantees about where
607 * memory for a pass-by-reference Datum is located.
608 */
609 if (!isnull)
610 val = datumCopy(val, attr->attbyval, attr->attlen);
611
612 values[i] = val;
613 nulls[i] = isnull;
614 }
615 else
616 {
617 if (!nulls[i])
618 values[i] = datumCopy(slot->tts_values[i], attr->attbyval, attr->attlen);
619 }
620 }
621
622 ExecClearTuple(slot);
623 memcpy(slot->tts_values, values, sizeof(*values) * natts);
624 memcpy(slot->tts_isnull, nulls, sizeof(*nulls) * natts);
627
629}
static Datum values[MAXATTR]
Definition bootstrap.c:155
#define Assert(condition)
Definition c.h:873
Datum datumCopy(Datum value, bool typByVal, int typLen)
Definition datum.c:132
TupleTableSlot * ExecStoreVirtualTuple(TupleTableSlot *slot)
#define GetPerTupleExprContext(estate)
Definition executor.h:656
#define GetPerTupleMemoryContext(estate)
Definition executor.h:661
static Datum ExecEvalExpr(ExprState *state, ExprContext *econtext, bool *isNull)
Definition executor.h:393
#define palloc_array(type, count)
Definition fe_memutils.h:76
long val
Definition informix.c:689
int i
Definition isn.c:77
void ExecInitGenerated(ResultRelInfo *resultRelInfo, EState *estate, CmdType cmdtype)
@ CMD_UPDATE
Definition nodes.h:276
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition palloc.h:124
uint64_t Datum
Definition postgres.h:70
static int fb(int x)
#define RelationGetDescr(relation)
Definition rel.h:540
TupleTableSlot * ecxt_scantuple
Definition execnodes.h:275
Relation ri_RelationDesc
Definition execnodes.h:482
ExprState ** ri_GeneratedExprsI
Definition execnodes.h:568
int ri_NumGeneratedNeededU
Definition execnodes.h:573
ExprState ** ri_GeneratedExprsU
Definition execnodes.h:569
int ri_NumGeneratedNeededI
Definition execnodes.h:572
bool has_generated_stored
Definition tupdesc.h:46
TupleConstr * constr
Definition tupdesc.h:141
bool * tts_isnull
Definition tuptable.h:126
Datum * tts_values
Definition tuptable.h:124
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:457
static void slot_getallattrs(TupleTableSlot *slot)
Definition tuptable.h:371
static void ExecMaterializeSlot(TupleTableSlot *slot)
Definition tuptable.h:475

References Assert, CompactAttribute::attbyval, CompactAttribute::attlen, CMD_UPDATE, TupleDescData::constr, datumCopy(), ExprContext::ecxt_scantuple, ExecClearTuple(), ExecEvalExpr(), ExecInitGenerated(), ExecMaterializeSlot(), ExecStoreVirtualTuple(), fb(), GetPerTupleExprContext, GetPerTupleMemoryContext, TupleConstr::has_generated_stored, i, MemoryContextSwitchTo(), TupleDescData::natts, palloc_array, 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)
extern

Definition at line 5220 of file nodeModifyTable.c.

5221{
5222 int i;
5223
5224 /*
5225 * Allow any FDWs to shut down
5226 */
5227 for (i = 0; i < node->mt_nrels; i++)
5228 {
5229 int j;
5230 ResultRelInfo *resultRelInfo = node->resultRelInfo + i;
5231
5232 if (!resultRelInfo->ri_usesFdwDirectModify &&
5233 resultRelInfo->ri_FdwRoutine != NULL &&
5234 resultRelInfo->ri_FdwRoutine->EndForeignModify != NULL)
5235 resultRelInfo->ri_FdwRoutine->EndForeignModify(node->ps.state,
5236 resultRelInfo);
5237
5238 /*
5239 * Cleanup the initialized batch slots. This only matters for FDWs
5240 * with batching, but the other cases will have ri_NumSlotsInitialized
5241 * == 0.
5242 */
5243 for (j = 0; j < resultRelInfo->ri_NumSlotsInitialized; j++)
5244 {
5245 ExecDropSingleTupleTableSlot(resultRelInfo->ri_Slots[j]);
5247 }
5248 }
5249
5250 /*
5251 * Close all the partitioned tables, leaf partitions, and their indices
5252 * and release the slot used for tuple routing, if set.
5253 */
5255 {
5257
5258 if (node->mt_root_tuple_slot)
5260 }
5261
5262 /*
5263 * Terminate EPQ execution if active
5264 */
5266
5267 /*
5268 * shut down subplan
5269 */
5271}
void EvalPlanQualEnd(EPQState *epqstate)
Definition execMain.c:3183
void ExecCleanupTupleRouting(ModifyTableState *mtstate, PartitionTupleRouting *proute)
void ExecEndNode(PlanState *node)
void ExecDropSingleTupleTableSlot(TupleTableSlot *slot)
#define outerPlanState(node)
Definition execnodes.h:1263
int j
Definition isn.c:78
EndForeignModify_function EndForeignModify
Definition fdwapi.h:237
ResultRelInfo * resultRelInfo
Definition execnodes.h:1410
struct PartitionTupleRouting * mt_partition_tuple_routing
Definition execnodes.h:1441
TupleTableSlot * mt_root_tuple_slot
Definition execnodes.h:1438
EPQState mt_epqstate
Definition execnodes.h:1420
EState * state
Definition execnodes.h:1169
TupleTableSlot ** ri_Slots
Definition execnodes.h:547
int ri_NumSlotsInitialized
Definition execnodes.h:545
struct FdwRoutine * ri_FdwRoutine
Definition execnodes.h:535
TupleTableSlot ** ri_PlanSlots
Definition execnodes.h:548
bool ri_usesFdwDirectModify
Definition execnodes.h:541

References FdwRoutine::EndForeignModify, EvalPlanQualEnd(), ExecCleanupTupleRouting(), ExecDropSingleTupleTableSlot(), ExecEndNode(), fb(), 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 
)
extern

Definition at line 431 of file nodeModifyTable.c.

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

Definition at line 3960 of file nodeModifyTable.c.

3962{
3963 EState *estate = mtstate->ps.state;
3964
3965 Assert(!resultRelInfo->ri_projectNewInfoValid);
3966
3967 resultRelInfo->ri_oldTupleSlot =
3968 table_slot_create(resultRelInfo->ri_RelationDesc,
3969 &estate->es_tupleTable);
3970 resultRelInfo->ri_newTupleSlot =
3971 table_slot_create(resultRelInfo->ri_RelationDesc,
3972 &estate->es_tupleTable);
3973 resultRelInfo->ri_projectNewInfoValid = true;
3974}
List * es_tupleTable
Definition execnodes.h:714
bool ri_projectNewInfoValid
Definition execnodes.h:511
TupleTableSlot * ri_oldTupleSlot
Definition execnodes.h:509
TupleTableSlot * ri_newTupleSlot
Definition execnodes.h:507
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 
)
extern

Definition at line 4632 of file nodeModifyTable.c.

4633{
4634 ModifyTableState *mtstate;
4635 Plan *subplan = outerPlan(node);
4636 CmdType operation = node->operation;
4638 int nrels;
4639 List *resultRelations = NIL;
4640 List *withCheckOptionLists = NIL;
4641 List *returningLists = NIL;
4642 List *updateColnosLists = NIL;
4643 List *mergeActionLists = NIL;
4644 List *mergeJoinConditions = NIL;
4645 ResultRelInfo *resultRelInfo;
4646 List *arowmarks;
4647 ListCell *l;
4648 int i;
4649 Relation rel;
4650
4651 /* check for unsupported flags */
4652 Assert(!(eflags & (EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK)));
4653
4654 /*
4655 * Only consider unpruned relations for initializing their ResultRelInfo
4656 * struct and other fields such as withCheckOptions, etc.
4657 *
4658 * Note: We must avoid pruning every result relation. This is important
4659 * for MERGE, since even if every result relation is pruned from the
4660 * subplan, there might still be NOT MATCHED rows, for which there may be
4661 * INSERT actions to perform. To allow these actions to be found, at
4662 * least one result relation must be kept. Also, when inserting into a
4663 * partitioned table, ExecInitPartitionInfo() needs a ResultRelInfo struct
4664 * as a reference for building the ResultRelInfo of the target partition.
4665 * In either case, it doesn't matter which result relation is kept, so we
4666 * just keep the first one, if all others have been pruned. See also,
4667 * ExecDoInitialPruning(), which ensures that this first result relation
4668 * has been locked.
4669 */
4670 i = 0;
4671 foreach(l, node->resultRelations)
4672 {
4673 Index rti = lfirst_int(l);
4674 bool keep_rel;
4675
4677 if (!keep_rel && i == total_nrels - 1 && resultRelations == NIL)
4678 {
4679 /* all result relations pruned; keep the first one */
4680 keep_rel = true;
4681 rti = linitial_int(node->resultRelations);
4682 i = 0;
4683 }
4684
4685 if (keep_rel)
4686 {
4687 resultRelations = lappend_int(resultRelations, rti);
4688 if (node->withCheckOptionLists)
4689 {
4692 i);
4693
4694 withCheckOptionLists = lappend(withCheckOptionLists, withCheckOptions);
4695 }
4696 if (node->returningLists)
4697 {
4698 List *returningList = list_nth_node(List,
4699 node->returningLists,
4700 i);
4701
4702 returningLists = lappend(returningLists, returningList);
4703 }
4704 if (node->updateColnosLists)
4705 {
4707
4708 updateColnosLists = lappend(updateColnosLists, updateColnosList);
4709 }
4710 if (node->mergeActionLists)
4711 {
4712 List *mergeActionList = list_nth(node->mergeActionLists, i);
4713
4714 mergeActionLists = lappend(mergeActionLists, mergeActionList);
4715 }
4716 if (node->mergeJoinConditions)
4717 {
4718 List *mergeJoinCondition = list_nth(node->mergeJoinConditions, i);
4719
4720 mergeJoinConditions = lappend(mergeJoinConditions, mergeJoinCondition);
4721 }
4722 }
4723 i++;
4724 }
4725 nrels = list_length(resultRelations);
4726 Assert(nrels > 0);
4727
4728 /*
4729 * create state structure
4730 */
4731 mtstate = makeNode(ModifyTableState);
4732 mtstate->ps.plan = (Plan *) node;
4733 mtstate->ps.state = estate;
4734 mtstate->ps.ExecProcNode = ExecModifyTable;
4735
4736 mtstate->operation = operation;
4737 mtstate->canSetTag = node->canSetTag;
4738 mtstate->mt_done = false;
4739
4740 mtstate->mt_nrels = nrels;
4741 mtstate->resultRelInfo = palloc_array(ResultRelInfo, nrels);
4742
4744 mtstate->mt_merge_inserted = 0;
4745 mtstate->mt_merge_updated = 0;
4746 mtstate->mt_merge_deleted = 0;
4747 mtstate->mt_updateColnosLists = updateColnosLists;
4748 mtstate->mt_mergeActionLists = mergeActionLists;
4749 mtstate->mt_mergeJoinConditions = mergeJoinConditions;
4750
4751 /*----------
4752 * Resolve the target relation. This is the same as:
4753 *
4754 * - the relation for which we will fire FOR STATEMENT triggers,
4755 * - the relation into whose tuple format all captured transition tuples
4756 * must be converted, and
4757 * - the root partitioned table used for tuple routing.
4758 *
4759 * If it's a partitioned or inherited table, the root partition or
4760 * appendrel RTE doesn't appear elsewhere in the plan and its RT index is
4761 * given explicitly in node->rootRelation. Otherwise, the target relation
4762 * is the sole relation in the node->resultRelations list and, since it can
4763 * never be pruned, also in the resultRelations list constructed above.
4764 *----------
4765 */
4766 if (node->rootRelation > 0)
4767 {
4771 node->rootRelation);
4772 }
4773 else
4774 {
4775 Assert(list_length(node->resultRelations) == 1);
4776 Assert(list_length(resultRelations) == 1);
4777 mtstate->rootResultRelInfo = mtstate->resultRelInfo;
4778 ExecInitResultRelation(estate, mtstate->resultRelInfo,
4779 linitial_int(resultRelations));
4780 }
4781
4782 /* set up epqstate with dummy subplan data for the moment */
4783 EvalPlanQualInit(&mtstate->mt_epqstate, estate, NULL, NIL,
4784 node->epqParam, resultRelations);
4785 mtstate->fireBSTriggers = true;
4786
4787 /*
4788 * Build state for collecting transition tuples. This requires having a
4789 * valid trigger query context, so skip it in explain-only mode.
4790 */
4791 if (!(eflags & EXEC_FLAG_EXPLAIN_ONLY))
4792 ExecSetupTransitionCaptureState(mtstate, estate);
4793
4794 /*
4795 * Open all the result relations and initialize the ResultRelInfo structs.
4796 * (But root relation was initialized above, if it's part of the array.)
4797 * We must do this before initializing the subplan, because direct-modify
4798 * FDWs expect their ResultRelInfos to be available.
4799 */
4800 resultRelInfo = mtstate->resultRelInfo;
4801 i = 0;
4802 foreach(l, resultRelations)
4803 {
4804 Index resultRelation = lfirst_int(l);
4806
4807 if (mergeActionLists)
4808 mergeActions = list_nth(mergeActionLists, i);
4809
4810 if (resultRelInfo != mtstate->rootResultRelInfo)
4811 {
4812 ExecInitResultRelation(estate, resultRelInfo, resultRelation);
4813
4814 /*
4815 * For child result relations, store the root result relation
4816 * pointer. We do so for the convenience of places that want to
4817 * look at the query's original target relation but don't have the
4818 * mtstate handy.
4819 */
4820 resultRelInfo->ri_RootResultRelInfo = mtstate->rootResultRelInfo;
4821 }
4822
4823 /* Initialize the usesFdwDirectModify flag */
4824 resultRelInfo->ri_usesFdwDirectModify =
4826
4827 /*
4828 * Verify result relation is a valid target for the current operation
4829 */
4830 CheckValidResultRel(resultRelInfo, operation, node->onConflictAction,
4831 mergeActions);
4832
4833 resultRelInfo++;
4834 i++;
4835 }
4836
4837 /*
4838 * Now we may initialize the subplan.
4839 */
4840 outerPlanState(mtstate) = ExecInitNode(subplan, estate, eflags);
4841
4842 /*
4843 * Do additional per-result-relation initialization.
4844 */
4845 for (i = 0; i < nrels; i++)
4846 {
4847 resultRelInfo = &mtstate->resultRelInfo[i];
4848
4849 /* Let FDWs init themselves for foreign-table result rels */
4850 if (!resultRelInfo->ri_usesFdwDirectModify &&
4851 resultRelInfo->ri_FdwRoutine != NULL &&
4852 resultRelInfo->ri_FdwRoutine->BeginForeignModify != NULL)
4853 {
4854 List *fdw_private = (List *) list_nth(node->fdwPrivLists, i);
4855
4856 resultRelInfo->ri_FdwRoutine->BeginForeignModify(mtstate,
4857 resultRelInfo,
4858 fdw_private,
4859 i,
4860 eflags);
4861 }
4862
4863 /*
4864 * For UPDATE/DELETE/MERGE, find the appropriate junk attr now, either
4865 * a 'ctid' or 'wholerow' attribute depending on relkind. For foreign
4866 * tables, the FDW might have created additional junk attr(s), but
4867 * those are no concern of ours.
4868 */
4869 if (operation == CMD_UPDATE || operation == CMD_DELETE ||
4870 operation == CMD_MERGE)
4871 {
4872 char relkind;
4873
4874 relkind = resultRelInfo->ri_RelationDesc->rd_rel->relkind;
4875 if (relkind == RELKIND_RELATION ||
4876 relkind == RELKIND_MATVIEW ||
4877 relkind == RELKIND_PARTITIONED_TABLE)
4878 {
4879 resultRelInfo->ri_RowIdAttNo =
4880 ExecFindJunkAttributeInTlist(subplan->targetlist, "ctid");
4881
4882 /*
4883 * For heap relations, a ctid junk attribute must be present.
4884 * Partitioned tables should only appear here when all leaf
4885 * partitions were pruned, in which case no rows can be
4886 * produced and ctid is not needed.
4887 */
4888 if (relkind == RELKIND_PARTITIONED_TABLE)
4889 Assert(nrels == 1);
4890 else if (!AttributeNumberIsValid(resultRelInfo->ri_RowIdAttNo))
4891 elog(ERROR, "could not find junk ctid column");
4892 }
4893 else if (relkind == RELKIND_FOREIGN_TABLE)
4894 {
4895 /*
4896 * We don't support MERGE with foreign tables for now. (It's
4897 * problematic because the implementation uses CTID.)
4898 */
4899 Assert(operation != CMD_MERGE);
4900
4901 /*
4902 * When there is a row-level trigger, there should be a
4903 * wholerow attribute. We also require it to be present in
4904 * UPDATE and MERGE, so we can get the values of unchanged
4905 * columns.
4906 */
4907 resultRelInfo->ri_RowIdAttNo =
4909 "wholerow");
4910 if ((mtstate->operation == CMD_UPDATE || mtstate->operation == CMD_MERGE) &&
4911 !AttributeNumberIsValid(resultRelInfo->ri_RowIdAttNo))
4912 elog(ERROR, "could not find junk wholerow column");
4913 }
4914 else
4915 {
4916 /* Other valid target relkinds must provide wholerow */
4917 resultRelInfo->ri_RowIdAttNo =
4919 "wholerow");
4920 if (!AttributeNumberIsValid(resultRelInfo->ri_RowIdAttNo))
4921 elog(ERROR, "could not find junk wholerow column");
4922 }
4923 }
4924 }
4925
4926 /*
4927 * If this is an inherited update/delete/merge, there will be a junk
4928 * attribute named "tableoid" present in the subplan's targetlist. It
4929 * will be used to identify the result relation for a given tuple to be
4930 * updated/deleted/merged.
4931 */
4932 mtstate->mt_resultOidAttno =
4933 ExecFindJunkAttributeInTlist(subplan->targetlist, "tableoid");
4935 mtstate->mt_lastResultOid = InvalidOid; /* force lookup at first tuple */
4936 mtstate->mt_lastResultIndex = 0; /* must be zero if no such attr */
4937
4938 /* Get the root target relation */
4939 rel = mtstate->rootResultRelInfo->ri_RelationDesc;
4940
4941 /*
4942 * Build state for tuple routing if it's a partitioned INSERT. An UPDATE
4943 * or MERGE might need this too, but only if it actually moves tuples
4944 * between partitions; in that case setup is done by
4945 * ExecCrossPartitionUpdate.
4946 */
4947 if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE &&
4948 operation == CMD_INSERT)
4950 ExecSetupPartitionTupleRouting(estate, rel);
4951
4952 /*
4953 * Initialize any WITH CHECK OPTION constraints if needed.
4954 */
4955 resultRelInfo = mtstate->resultRelInfo;
4956 foreach(l, withCheckOptionLists)
4957 {
4958 List *wcoList = (List *) lfirst(l);
4959 List *wcoExprs = NIL;
4960 ListCell *ll;
4961
4962 foreach(ll, wcoList)
4963 {
4965 ExprState *wcoExpr = ExecInitQual((List *) wco->qual,
4966 &mtstate->ps);
4967
4969 }
4970
4971 resultRelInfo->ri_WithCheckOptions = wcoList;
4972 resultRelInfo->ri_WithCheckOptionExprs = wcoExprs;
4973 resultRelInfo++;
4974 }
4975
4976 /*
4977 * Initialize RETURNING projections if needed.
4978 */
4979 if (returningLists)
4980 {
4981 TupleTableSlot *slot;
4982 ExprContext *econtext;
4983
4984 /*
4985 * Initialize result tuple slot and assign its rowtype using the plan
4986 * node's declared targetlist, which the planner set up to be the same
4987 * as the first (before runtime pruning) RETURNING list. We assume
4988 * all the result rels will produce compatible output.
4989 */
4991 slot = mtstate->ps.ps_ResultTupleSlot;
4992
4993 /* Need an econtext too */
4994 if (mtstate->ps.ps_ExprContext == NULL)
4995 ExecAssignExprContext(estate, &mtstate->ps);
4996 econtext = mtstate->ps.ps_ExprContext;
4997
4998 /*
4999 * Build a projection for each result rel.
5000 */
5001 resultRelInfo = mtstate->resultRelInfo;
5002 foreach(l, returningLists)
5003 {
5004 List *rlist = (List *) lfirst(l);
5005
5006 resultRelInfo->ri_returningList = rlist;
5007 resultRelInfo->ri_projectReturning =
5008 ExecBuildProjectionInfo(rlist, econtext, slot, &mtstate->ps,
5009 resultRelInfo->ri_RelationDesc->rd_att);
5010 resultRelInfo++;
5011 }
5012 }
5013 else
5014 {
5015 /*
5016 * We still must construct a dummy result tuple type, because InitPlan
5017 * expects one (maybe should change that?).
5018 */
5019 ExecInitResultTypeTL(&mtstate->ps);
5020
5021 mtstate->ps.ps_ExprContext = NULL;
5022 }
5023
5024 /* Set the list of arbiter indexes if needed for ON CONFLICT */
5025 resultRelInfo = mtstate->resultRelInfo;
5026 if (node->onConflictAction != ONCONFLICT_NONE)
5027 {
5028 /* insert may only have one relation, inheritance is not expanded */
5029 Assert(total_nrels == 1);
5030 resultRelInfo->ri_onConflictArbiterIndexes = node->arbiterIndexes;
5031 }
5032
5033 /*
5034 * If needed, Initialize target list, projection and qual for ON CONFLICT
5035 * DO UPDATE.
5036 */
5038 {
5040 ExprContext *econtext;
5042
5043 /* already exists if created by RETURNING processing above */
5044 if (mtstate->ps.ps_ExprContext == NULL)
5045 ExecAssignExprContext(estate, &mtstate->ps);
5046
5047 econtext = mtstate->ps.ps_ExprContext;
5048 relationDesc = resultRelInfo->ri_RelationDesc->rd_att;
5049
5050 /* create state for DO UPDATE SET operation */
5051 resultRelInfo->ri_onConflict = onconfl;
5052
5053 /* initialize slot for the existing tuple */
5055 table_slot_create(resultRelInfo->ri_RelationDesc,
5056 &mtstate->ps.state->es_tupleTable);
5057
5058 /*
5059 * Create the tuple slot for the UPDATE SET projection. We want a slot
5060 * of the table's type here, because the slot will be used to insert
5061 * into the table, and for RETURNING processing - which may access
5062 * system attributes.
5063 */
5064 onconfl->oc_ProjSlot =
5065 table_slot_create(resultRelInfo->ri_RelationDesc,
5066 &mtstate->ps.state->es_tupleTable);
5067
5068 /* build UPDATE SET projection state */
5069 onconfl->oc_ProjInfo =
5071 true,
5072 node->onConflictCols,
5074 econtext,
5075 onconfl->oc_ProjSlot,
5076 &mtstate->ps);
5077
5078 /* initialize state to evaluate the WHERE clause, if any */
5079 if (node->onConflictWhere)
5080 {
5081 ExprState *qualexpr;
5082
5083 qualexpr = ExecInitQual((List *) node->onConflictWhere,
5084 &mtstate->ps);
5085 onconfl->oc_WhereClause = qualexpr;
5086 }
5087 }
5088
5089 /*
5090 * If we have any secondary relations in an UPDATE or DELETE, they need to
5091 * be treated like non-locked relations in SELECT FOR UPDATE, i.e., the
5092 * EvalPlanQual mechanism needs to be told about them. This also goes for
5093 * the source relations in a MERGE. Locate the relevant ExecRowMarks.
5094 */
5095 arowmarks = NIL;
5096 foreach(l, node->rowMarks)
5097 {
5099 RangeTblEntry *rte = exec_rt_fetch(rc->rti, estate);
5102
5103 /* ignore "parent" rowmarks; they are irrelevant at runtime */
5104 if (rc->isParent)
5105 continue;
5106
5107 /*
5108 * Also ignore rowmarks belonging to child tables that have been
5109 * pruned in ExecDoInitialPruning().
5110 */
5111 if (rte->rtekind == RTE_RELATION &&
5112 !bms_is_member(rc->rti, estate->es_unpruned_relids))
5113 continue;
5114
5115 /* Find ExecRowMark and build ExecAuxRowMark */
5116 erm = ExecFindRowMark(estate, rc->rti, false);
5119 }
5120
5121 /* For a MERGE command, initialize its state */
5122 if (mtstate->operation == CMD_MERGE)
5123 ExecInitMerge(mtstate, estate);
5124
5125 EvalPlanQualSetPlan(&mtstate->mt_epqstate, subplan, arowmarks);
5126
5127 /*
5128 * If there are a lot of result relations, use a hash table to speed the
5129 * lookups. If there are not a lot, a simple linear search is faster.
5130 *
5131 * It's not clear where the threshold is, but try 64 for starters. In a
5132 * debugging build, use a small threshold so that we get some test
5133 * coverage of both code paths.
5134 */
5135#ifdef USE_ASSERT_CHECKING
5136#define MT_NRELS_HASH 4
5137#else
5138#define MT_NRELS_HASH 64
5139#endif
5140 if (nrels >= MT_NRELS_HASH)
5141 {
5143
5144 hash_ctl.keysize = sizeof(Oid);
5145 hash_ctl.entrysize = sizeof(MTTargetRelLookup);
5147 mtstate->mt_resultOidHash =
5148 hash_create("ModifyTable target hash",
5149 nrels, &hash_ctl,
5151 for (i = 0; i < nrels; i++)
5152 {
5153 Oid hashkey;
5155 bool found;
5156
5157 resultRelInfo = &mtstate->resultRelInfo[i];
5158 hashkey = RelationGetRelid(resultRelInfo->ri_RelationDesc);
5161 HASH_ENTER, &found);
5162 Assert(!found);
5163 mtlookup->relationIndex = i;
5164 }
5165 }
5166 else
5167 mtstate->mt_resultOidHash = NULL;
5168
5169 /*
5170 * Determine if the FDW supports batch insert and determine the batch size
5171 * (a FDW may support batching, but it may be disabled for the
5172 * server/table).
5173 *
5174 * We only do this for INSERT, so that for UPDATE/DELETE the batch size
5175 * remains set to 0.
5176 */
5177 if (operation == CMD_INSERT)
5178 {
5179 /* insert may only have one relation, inheritance is not expanded */
5180 Assert(total_nrels == 1);
5181 resultRelInfo = mtstate->resultRelInfo;
5182 if (!resultRelInfo->ri_usesFdwDirectModify &&
5183 resultRelInfo->ri_FdwRoutine != NULL &&
5184 resultRelInfo->ri_FdwRoutine->GetForeignModifyBatchSize &&
5185 resultRelInfo->ri_FdwRoutine->ExecForeignBatchInsert)
5186 {
5187 resultRelInfo->ri_BatchSize =
5188 resultRelInfo->ri_FdwRoutine->GetForeignModifyBatchSize(resultRelInfo);
5189 Assert(resultRelInfo->ri_BatchSize >= 1);
5190 }
5191 else
5192 resultRelInfo->ri_BatchSize = 1;
5193 }
5194
5195 /*
5196 * Lastly, if this is not the primary (canSetTag) ModifyTable node, add it
5197 * to estate->es_auxmodifytables so that it will be run to completion by
5198 * ExecPostprocessPlan. (It'd actually work fine to add the primary
5199 * ModifyTable node too, but there's no need.) Note the use of lcons not
5200 * lappend: we need later-initialized ModifyTable nodes to be shut down
5201 * before earlier ones. This ensures that we don't throw away RETURNING
5202 * rows that need to be seen by a later CTE subplan.
5203 */
5204 if (!mtstate->canSetTag)
5205 estate->es_auxmodifytables = lcons(mtstate,
5206 estate->es_auxmodifytables);
5207
5208 return mtstate;
5209}
#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:628
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition dynahash.c:952
HTAB * hash_create(const char *tabname, int64 nelem, const HASHCTL *info, int flags)
Definition dynahash.c:358
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:2560
ExecAuxRowMark * ExecBuildAuxRowMark(ExecRowMark *erm, List *targetlist)
Definition execMain.c:2583
void CheckValidResultRel(ResultRelInfo *resultRelInfo, CmdType operation, OnConflictAction onConflictAction, List *mergeActions)
Definition execMain.c:1054
void EvalPlanQualInit(EPQState *epqstate, EState *parentestate, Plan *subplan, List *auxrowmarks, int epqParam, List *resultRelations)
Definition execMain.c:2722
void EvalPlanQualSetPlan(EPQState *epqstate, Plan *subplan, List *auxrowmarks)
Definition execMain.c:2763
PartitionTupleRouting * ExecSetupPartitionTupleRouting(EState *estate, Relation rel)
PlanState * ExecInitNode(Plan *node, EState *estate, int eflags)
const TupleTableSlotOps TTSOpsVirtual
Definition execTuples.c:84
void ExecInitResultTypeTL(PlanState *planstate)
void ExecInitResultTupleSlotTL(PlanState *planstate, const TupleTableSlotOps *tts_ops)
void ExecInitResultRelation(EState *estate, ResultRelInfo *resultRelInfo, Index rti)
Definition execUtils.c:880
void ExecAssignExprContext(EState *estate, PlanState *planstate)
Definition execUtils.c:485
#define EXEC_FLAG_BACKWARD
Definition executor.h:69
static RangeTblEntry * exec_rt_fetch(Index rti, EState *estate)
Definition executor.h:697
#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:160
static void ExecSetupTransitionCaptureState(ModifyTableState *mtstate, EState *estate)
static TupleTableSlot * ExecModifyTable(PlanState *pstate)
#define MT_NRELS_HASH
static void ExecInitMerge(ModifyTableState *mtstate, EState *estate)
@ ONCONFLICT_NONE
Definition nodes.h:428
@ ONCONFLICT_UPDATE
Definition nodes.h:430
CmdType
Definition nodes.h:273
@ CMD_MERGE
Definition nodes.h:279
@ CMD_INSERT
Definition nodes.h:277
@ CMD_DELETE
Definition nodes.h:278
#define makeNode(_type_)
Definition nodes.h:161
@ RTE_RELATION
#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 list_nth_node(type, list, n)
Definition pg_list.h:327
#define outerPlan(node)
Definition plannodes.h:261
#define InvalidOid
unsigned int Oid
#define RelationGetRelid(relation)
Definition rel.h:514
Bitmapset * es_unpruned_relids
Definition execnodes.h:675
List * es_auxmodifytables
Definition execnodes.h:729
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
Definition pg_list.h:54
List * mt_mergeJoinConditions
Definition execnodes.h:1474
TupleTableSlot * mt_merge_pending_not_matched
Definition execnodes.h:1460
double mt_merge_deleted
Definition execnodes.h:1465
List * mt_updateColnosLists
Definition execnodes.h:1472
double mt_merge_inserted
Definition execnodes.h:1463
double mt_merge_updated
Definition execnodes.h:1464
List * mt_mergeActionLists
Definition execnodes.h:1473
HTAB * mt_resultOidHash
Definition execnodes.h:1432
ResultRelInfo * rootResultRelInfo
Definition execnodes.h:1418
List * updateColnosLists
Definition plannodes.h:344
List * arbiterIndexes
Definition plannodes.h:364
List * onConflictCols
Definition plannodes.h:368
List * mergeJoinConditions
Definition plannodes.h:378
CmdType operation
Definition plannodes.h:334
List * resultRelations
Definition plannodes.h:342
Bitmapset * fdwDirectModifyPlans
Definition plannodes.h:356
List * onConflictSet
Definition plannodes.h:366
List * mergeActionLists
Definition plannodes.h:376
bool canSetTag
Definition plannodes.h:336
List * fdwPrivLists
Definition plannodes.h:354
List * returningLists
Definition plannodes.h:352
List * withCheckOptionLists
Definition plannodes.h:346
Index rootRelation
Definition plannodes.h:340
Node * onConflictWhere
Definition plannodes.h:370
List * rowMarks
Definition plannodes.h:358
OnConflictAction onConflictAction
Definition plannodes.h:362
TupleTableSlot * oc_Existing
Definition execnodes.h:435
Plan * plan
Definition execnodes.h:1167
ExprContext * ps_ExprContext
Definition execnodes.h:1206
TupleTableSlot * ps_ResultTupleSlot
Definition execnodes.h:1205
ExecProcNodeMtd ExecProcNode
Definition execnodes.h:1173
List * targetlist
Definition plannodes.h:229
TupleDesc rd_att
Definition rel.h:112
Form_pg_class rd_rel
Definition rel.h:111
OnConflictSetState * ri_onConflict
Definition execnodes.h:585
List * ri_onConflictArbiterIndexes
Definition execnodes.h:582
struct ResultRelInfo * ri_RootResultRelInfo
Definition execnodes.h:620
List * ri_WithCheckOptions
Definition execnodes.h:551
List * ri_WithCheckOptionExprs
Definition execnodes.h:554
ProjectionInfo * ri_projectReturning
Definition execnodes.h:579
List * ri_returningList
Definition execnodes.h:576
AttrNumber ri_RowIdAttNo
Definition execnodes.h:497

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, 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, exec_rt_fetch(), ExecAssignExprContext(), ExecBuildAuxRowMark(), ExecBuildProjectionInfo(), ExecBuildUpdateProjection(), ExecFindJunkAttributeInTlist(), ExecFindRowMark(), FdwRoutine::ExecForeignBatchInsert, ExecInitMerge(), ExecInitNode(), ExecInitQual(), ExecInitResultRelation(), ExecInitResultTupleSlotTL(), ExecInitResultTypeTL(), ExecModifyTable(), PlanState::ExecProcNode, ExecSetupPartitionTupleRouting(), ExecSetupTransitionCaptureState(), fb(), ModifyTable::fdwDirectModifyPlans, ModifyTable::fdwPrivLists, ModifyTableState::fireBSTriggers, FdwRoutine::GetForeignModifyBatchSize, HASH_BLOBS, HASH_CONTEXT, hash_create(), HASH_ELEM, HASH_ENTER, hash_search(), i, InvalidOid, PlanRowMark::isParent, HASHCTL::keysize, lappend(), lappend_int(), lcons(), lfirst, lfirst_int, lfirst_node, 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, ONCONFLICT_NONE, ONCONFLICT_UPDATE, ModifyTable::onConflictAction, ModifyTable::onConflictCols, ModifyTable::onConflictSet, ModifyTable::onConflictWhere, ModifyTableState::operation, ModifyTable::operation, outerPlan, outerPlanState, palloc_array, PlanState::plan, ModifyTableState::ps, PlanState::ps_ExprContext, PlanState::ps_ResultTupleSlot, RelationData::rd_att, RelationData::rd_rel, RelationGetRelid, 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, RTE_RELATION, PlanRowMark::rti, PlanState::state, table_slot_create(), Plan::targetlist, TTSOpsVirtual, ModifyTable::updateColnosLists, and ModifyTable::withCheckOptionLists.

Referenced by ExecInitNode().

◆ ExecReScanModifyTable()

void ExecReScanModifyTable ( ModifyTableState node)
extern

Definition at line 5274 of file nodeModifyTable.c.

5275{
5276 /*
5277 * Currently, we don't need to support rescan on ModifyTable nodes. The
5278 * semantics of that would be a bit debatable anyway.
5279 */
5280 elog(ERROR, "ExecReScanModifyTable is not implemented");
5281}

References elog, and ERROR.

Referenced by ExecReScan().