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 556 of file nodeModifyTable.c.

559{
560 Relation rel = resultRelInfo->ri_RelationDesc;
561 TupleDesc tupdesc = RelationGetDescr(rel);
562 int natts = tupdesc->natts;
563 ExprContext *econtext = GetPerTupleExprContext(estate);
566 Datum *values;
567 bool *nulls;
568
569 /* We should not be called unless this is true */
570 Assert(tupdesc->constr && tupdesc->constr->has_generated_stored);
571
572 /*
573 * Initialize the expressions if we didn't already, and check whether we
574 * can exit early because nothing needs to be computed.
575 */
576 if (cmdtype == CMD_UPDATE)
577 {
578 if (resultRelInfo->ri_GeneratedExprsU == NULL)
579 ExecInitGenerated(resultRelInfo, estate, cmdtype);
580 if (resultRelInfo->ri_NumGeneratedNeededU == 0)
581 return;
582 ri_GeneratedExprs = resultRelInfo->ri_GeneratedExprsU;
583 }
584 else
585 {
586 if (resultRelInfo->ri_GeneratedExprsI == NULL)
587 ExecInitGenerated(resultRelInfo, estate, cmdtype);
588 /* Early exit is impossible given the prior Assert */
589 Assert(resultRelInfo->ri_NumGeneratedNeededI > 0);
590 ri_GeneratedExprs = resultRelInfo->ri_GeneratedExprsI;
591 }
592
594
595 values = palloc_array(Datum, natts);
596 nulls = palloc_array(bool, natts);
597
598 slot_getallattrs(slot);
599 memcpy(nulls, slot->tts_isnull, sizeof(*nulls) * natts);
600
601 for (int i = 0; i < natts; i++)
602 {
603 CompactAttribute *attr = TupleDescCompactAttr(tupdesc, i);
604
605 if (ri_GeneratedExprs[i])
606 {
607 Datum val;
608 bool isnull;
609
610 Assert(TupleDescAttr(tupdesc, i)->attgenerated == ATTRIBUTE_GENERATED_STORED);
611
612 econtext->ecxt_scantuple = slot;
613
614 val = ExecEvalExpr(ri_GeneratedExprs[i], econtext, &isnull);
615
616 /*
617 * We must make a copy of val as we have no guarantees about where
618 * memory for a pass-by-reference Datum is located.
619 */
620 if (!isnull)
621 val = datumCopy(val, attr->attbyval, attr->attlen);
622
623 values[i] = val;
624 nulls[i] = isnull;
625 }
626 else
627 {
628 if (!nulls[i])
629 values[i] = datumCopy(slot->tts_values[i], attr->attbyval, attr->attlen);
630 }
631 }
632
633 ExecClearTuple(slot);
634 memcpy(slot->tts_values, values, sizeof(*values) * natts);
635 memcpy(slot->tts_isnull, nulls, sizeof(*nulls) * natts);
638
640}
static Datum values[MAXATTR]
Definition bootstrap.c:188
#define Assert(condition)
Definition c.h:945
Datum datumCopy(Datum value, bool typByVal, int typLen)
Definition datum.c:132
TupleTableSlot * ExecStoreVirtualTuple(TupleTableSlot *slot)
#define GetPerTupleExprContext(estate)
Definition executor.h:660
#define GetPerTupleMemoryContext(estate)
Definition executor.h:665
static Datum ExecEvalExpr(ExprState *state, ExprContext *econtext, bool *isNull)
Definition executor.h:396
#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:284
Relation ri_RelationDesc
Definition execnodes.h:492
ExprState ** ri_GeneratedExprsI
Definition execnodes.h:578
int ri_NumGeneratedNeededU
Definition execnodes.h:583
ExprState ** ri_GeneratedExprsU
Definition execnodes.h:579
int ri_NumGeneratedNeededI
Definition execnodes.h:582
bool has_generated_stored
Definition tupdesc.h:46
TupleConstr * constr
Definition tupdesc.h:159
bool * tts_isnull
Definition tuptable.h:133
Datum * tts_values
Definition tuptable.h:131
static FormData_pg_attribute * TupleDescAttr(TupleDesc tupdesc, int i)
Definition tupdesc.h:178
static CompactAttribute * TupleDescCompactAttr(TupleDesc tupdesc, int i)
Definition tupdesc.h:193
static TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition tuptable.h:476
static void slot_getallattrs(TupleTableSlot *slot)
Definition tuptable.h:390
static void ExecMaterializeSlot(TupleTableSlot *slot)
Definition tuptable.h:494

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 5432 of file nodeModifyTable.c.

5433{
5434 int i;
5435
5436 /*
5437 * Allow any FDWs to shut down
5438 */
5439 for (i = 0; i < node->mt_nrels; i++)
5440 {
5441 int j;
5442 ResultRelInfo *resultRelInfo = node->resultRelInfo + i;
5443
5444 if (!resultRelInfo->ri_usesFdwDirectModify &&
5445 resultRelInfo->ri_FdwRoutine != NULL &&
5446 resultRelInfo->ri_FdwRoutine->EndForeignModify != NULL)
5447 resultRelInfo->ri_FdwRoutine->EndForeignModify(node->ps.state,
5448 resultRelInfo);
5449
5450 /*
5451 * Cleanup the initialized batch slots. This only matters for FDWs
5452 * with batching, but the other cases will have ri_NumSlotsInitialized
5453 * == 0.
5454 */
5455 for (j = 0; j < resultRelInfo->ri_NumSlotsInitialized; j++)
5456 {
5457 ExecDropSingleTupleTableSlot(resultRelInfo->ri_Slots[j]);
5459 }
5460 }
5461
5462 /*
5463 * Close all the partitioned tables, leaf partitions, and their indices
5464 * and release the slot used for tuple routing, if set.
5465 */
5467 {
5469
5470 if (node->mt_root_tuple_slot)
5472 }
5473
5474 /*
5475 * Terminate EPQ execution if active
5476 */
5478
5479 /*
5480 * shut down subplan
5481 */
5483}
void EvalPlanQualEnd(EPQState *epqstate)
Definition execMain.c:3198
void ExecCleanupTupleRouting(ModifyTableState *mtstate, PartitionTupleRouting *proute)
void ExecEndNode(PlanState *node)
void ExecDropSingleTupleTableSlot(TupleTableSlot *slot)
#define outerPlanState(node)
Definition execnodes.h:1273
int j
Definition isn.c:78
EndForeignModify_function EndForeignModify
Definition fdwapi.h:237
ResultRelInfo * resultRelInfo
Definition execnodes.h:1420
struct PartitionTupleRouting * mt_partition_tuple_routing
Definition execnodes.h:1451
TupleTableSlot * mt_root_tuple_slot
Definition execnodes.h:1448
EPQState mt_epqstate
Definition execnodes.h:1430
EState * state
Definition execnodes.h:1179
TupleTableSlot ** ri_Slots
Definition execnodes.h:557
int ri_NumSlotsInitialized
Definition execnodes.h:555
struct FdwRoutine * ri_FdwRoutine
Definition execnodes.h:545
TupleTableSlot ** ri_PlanSlots
Definition execnodes.h:558
bool ri_usesFdwDirectModify
Definition execnodes.h:551

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 442 of file nodeModifyTable.c.

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

4162{
4163 EState *estate = mtstate->ps.state;
4164
4165 Assert(!resultRelInfo->ri_projectNewInfoValid);
4166
4167 resultRelInfo->ri_oldTupleSlot =
4168 table_slot_create(resultRelInfo->ri_RelationDesc,
4169 &estate->es_tupleTable);
4170 resultRelInfo->ri_newTupleSlot =
4171 table_slot_create(resultRelInfo->ri_RelationDesc,
4172 &estate->es_tupleTable);
4173 resultRelInfo->ri_projectNewInfoValid = true;
4174}
List * es_tupleTable
Definition execnodes.h:724
bool ri_projectNewInfoValid
Definition execnodes.h:521
TupleTableSlot * ri_oldTupleSlot
Definition execnodes.h:519
TupleTableSlot * ri_newTupleSlot
Definition execnodes.h:517
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 4833 of file nodeModifyTable.c.

4834{
4835 ModifyTableState *mtstate;
4836 Plan *subplan = outerPlan(node);
4837 CmdType operation = node->operation;
4839 int nrels;
4840 List *resultRelations = NIL;
4841 List *withCheckOptionLists = NIL;
4842 List *returningLists = NIL;
4843 List *updateColnosLists = NIL;
4844 List *mergeActionLists = NIL;
4845 List *mergeJoinConditions = NIL;
4846 ResultRelInfo *resultRelInfo;
4847 List *arowmarks;
4848 ListCell *l;
4849 int i;
4850 Relation rel;
4851
4852 /* check for unsupported flags */
4853 Assert(!(eflags & (EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK)));
4854
4855 /*
4856 * Only consider unpruned relations for initializing their ResultRelInfo
4857 * struct and other fields such as withCheckOptions, etc.
4858 *
4859 * Note: We must avoid pruning every result relation. This is important
4860 * for MERGE, since even if every result relation is pruned from the
4861 * subplan, there might still be NOT MATCHED rows, for which there may be
4862 * INSERT actions to perform. To allow these actions to be found, at
4863 * least one result relation must be kept. Also, when inserting into a
4864 * partitioned table, ExecInitPartitionInfo() needs a ResultRelInfo struct
4865 * as a reference for building the ResultRelInfo of the target partition.
4866 * In either case, it doesn't matter which result relation is kept, so we
4867 * just keep the first one, if all others have been pruned. See also,
4868 * ExecDoInitialPruning(), which ensures that this first result relation
4869 * has been locked.
4870 */
4871 i = 0;
4872 foreach(l, node->resultRelations)
4873 {
4874 Index rti = lfirst_int(l);
4875 bool keep_rel;
4876
4878 if (!keep_rel && i == total_nrels - 1 && resultRelations == NIL)
4879 {
4880 /* all result relations pruned; keep the first one */
4881 keep_rel = true;
4882 rti = linitial_int(node->resultRelations);
4883 i = 0;
4884 }
4885
4886 if (keep_rel)
4887 {
4888 resultRelations = lappend_int(resultRelations, rti);
4889 if (node->withCheckOptionLists)
4890 {
4893 i);
4894
4895 withCheckOptionLists = lappend(withCheckOptionLists, withCheckOptions);
4896 }
4897 if (node->returningLists)
4898 {
4899 List *returningList = list_nth_node(List,
4900 node->returningLists,
4901 i);
4902
4903 returningLists = lappend(returningLists, returningList);
4904 }
4905 if (node->updateColnosLists)
4906 {
4908
4909 updateColnosLists = lappend(updateColnosLists, updateColnosList);
4910 }
4911 if (node->mergeActionLists)
4912 {
4913 List *mergeActionList = list_nth(node->mergeActionLists, i);
4914
4915 mergeActionLists = lappend(mergeActionLists, mergeActionList);
4916 }
4917 if (node->mergeJoinConditions)
4918 {
4919 List *mergeJoinCondition = list_nth(node->mergeJoinConditions, i);
4920
4921 mergeJoinConditions = lappend(mergeJoinConditions, mergeJoinCondition);
4922 }
4923 }
4924 i++;
4925 }
4926 nrels = list_length(resultRelations);
4927 Assert(nrels > 0);
4928
4929 /*
4930 * create state structure
4931 */
4932 mtstate = makeNode(ModifyTableState);
4933 mtstate->ps.plan = (Plan *) node;
4934 mtstate->ps.state = estate;
4935 mtstate->ps.ExecProcNode = ExecModifyTable;
4936
4937 mtstate->operation = operation;
4938 mtstate->canSetTag = node->canSetTag;
4939 mtstate->mt_done = false;
4940
4941 mtstate->mt_nrels = nrels;
4942 mtstate->resultRelInfo = palloc_array(ResultRelInfo, nrels);
4943
4945 mtstate->mt_merge_inserted = 0;
4946 mtstate->mt_merge_updated = 0;
4947 mtstate->mt_merge_deleted = 0;
4948 mtstate->mt_updateColnosLists = updateColnosLists;
4949 mtstate->mt_mergeActionLists = mergeActionLists;
4950 mtstate->mt_mergeJoinConditions = mergeJoinConditions;
4951
4952 /*----------
4953 * Resolve the target relation. This is the same as:
4954 *
4955 * - the relation for which we will fire FOR STATEMENT triggers,
4956 * - the relation into whose tuple format all captured transition tuples
4957 * must be converted, and
4958 * - the root partitioned table used for tuple routing.
4959 *
4960 * If it's a partitioned or inherited table, the root partition or
4961 * appendrel RTE doesn't appear elsewhere in the plan and its RT index is
4962 * given explicitly in node->rootRelation. Otherwise, the target relation
4963 * is the sole relation in the node->resultRelations list and, since it can
4964 * never be pruned, also in the resultRelations list constructed above.
4965 *----------
4966 */
4967 if (node->rootRelation > 0)
4968 {
4972 node->rootRelation);
4973 }
4974 else
4975 {
4976 Assert(list_length(node->resultRelations) == 1);
4977 Assert(list_length(resultRelations) == 1);
4978 mtstate->rootResultRelInfo = mtstate->resultRelInfo;
4979 ExecInitResultRelation(estate, mtstate->resultRelInfo,
4980 linitial_int(resultRelations));
4981 }
4982
4983 /* set up epqstate with dummy subplan data for the moment */
4984 EvalPlanQualInit(&mtstate->mt_epqstate, estate, NULL, NIL,
4985 node->epqParam, resultRelations);
4986 mtstate->fireBSTriggers = true;
4987
4988 /*
4989 * Build state for collecting transition tuples. This requires having a
4990 * valid trigger query context, so skip it in explain-only mode.
4991 */
4992 if (!(eflags & EXEC_FLAG_EXPLAIN_ONLY))
4993 ExecSetupTransitionCaptureState(mtstate, estate);
4994
4995 /*
4996 * Open all the result relations and initialize the ResultRelInfo structs.
4997 * (But root relation was initialized above, if it's part of the array.)
4998 * We must do this before initializing the subplan, because direct-modify
4999 * FDWs expect their ResultRelInfos to be available.
5000 */
5001 resultRelInfo = mtstate->resultRelInfo;
5002 i = 0;
5003 foreach(l, resultRelations)
5004 {
5005 Index resultRelation = lfirst_int(l);
5007
5008 if (mergeActionLists)
5009 mergeActions = list_nth(mergeActionLists, i);
5010
5011 if (resultRelInfo != mtstate->rootResultRelInfo)
5012 {
5013 ExecInitResultRelation(estate, resultRelInfo, resultRelation);
5014
5015 /*
5016 * For child result relations, store the root result relation
5017 * pointer. We do so for the convenience of places that want to
5018 * look at the query's original target relation but don't have the
5019 * mtstate handy.
5020 */
5021 resultRelInfo->ri_RootResultRelInfo = mtstate->rootResultRelInfo;
5022 }
5023
5024 /* Initialize the usesFdwDirectModify flag */
5025 resultRelInfo->ri_usesFdwDirectModify =
5027
5028 /*
5029 * Verify result relation is a valid target for the current operation
5030 */
5031 CheckValidResultRel(resultRelInfo, operation, node->onConflictAction,
5032 mergeActions);
5033
5034 resultRelInfo++;
5035 i++;
5036 }
5037
5038 /*
5039 * Now we may initialize the subplan.
5040 */
5041 outerPlanState(mtstate) = ExecInitNode(subplan, estate, eflags);
5042
5043 /*
5044 * Do additional per-result-relation initialization.
5045 */
5046 for (i = 0; i < nrels; i++)
5047 {
5048 resultRelInfo = &mtstate->resultRelInfo[i];
5049
5050 /* Let FDWs init themselves for foreign-table result rels */
5051 if (!resultRelInfo->ri_usesFdwDirectModify &&
5052 resultRelInfo->ri_FdwRoutine != NULL &&
5053 resultRelInfo->ri_FdwRoutine->BeginForeignModify != NULL)
5054 {
5055 List *fdw_private = (List *) list_nth(node->fdwPrivLists, i);
5056
5057 resultRelInfo->ri_FdwRoutine->BeginForeignModify(mtstate,
5058 resultRelInfo,
5059 fdw_private,
5060 i,
5061 eflags);
5062 }
5063
5064 /*
5065 * For UPDATE/DELETE/MERGE, find the appropriate junk attr now, either
5066 * a 'ctid' or 'wholerow' attribute depending on relkind. For foreign
5067 * tables, the FDW might have created additional junk attr(s), but
5068 * those are no concern of ours.
5069 */
5070 if (operation == CMD_UPDATE || operation == CMD_DELETE ||
5071 operation == CMD_MERGE)
5072 {
5073 char relkind;
5074
5075 relkind = resultRelInfo->ri_RelationDesc->rd_rel->relkind;
5076 if (relkind == RELKIND_RELATION ||
5077 relkind == RELKIND_MATVIEW ||
5078 relkind == RELKIND_PARTITIONED_TABLE)
5079 {
5080 resultRelInfo->ri_RowIdAttNo =
5081 ExecFindJunkAttributeInTlist(subplan->targetlist, "ctid");
5082
5083 /*
5084 * For heap relations, a ctid junk attribute must be present.
5085 * Partitioned tables should only appear here when all leaf
5086 * partitions were pruned, in which case no rows can be
5087 * produced and ctid is not needed.
5088 */
5089 if (relkind == RELKIND_PARTITIONED_TABLE)
5090 Assert(nrels == 1);
5091 else if (!AttributeNumberIsValid(resultRelInfo->ri_RowIdAttNo))
5092 elog(ERROR, "could not find junk ctid column");
5093 }
5094 else if (relkind == RELKIND_FOREIGN_TABLE)
5095 {
5096 /*
5097 * We don't support MERGE with foreign tables for now. (It's
5098 * problematic because the implementation uses CTID.)
5099 */
5100 Assert(operation != CMD_MERGE);
5101
5102 /*
5103 * When there is a row-level trigger, there should be a
5104 * wholerow attribute. We also require it to be present in
5105 * UPDATE and MERGE, so we can get the values of unchanged
5106 * columns.
5107 */
5108 resultRelInfo->ri_RowIdAttNo =
5110 "wholerow");
5111 if ((mtstate->operation == CMD_UPDATE || mtstate->operation == CMD_MERGE) &&
5112 !AttributeNumberIsValid(resultRelInfo->ri_RowIdAttNo))
5113 elog(ERROR, "could not find junk wholerow column");
5114 }
5115 else
5116 {
5117 /* Other valid target relkinds must provide wholerow */
5118 resultRelInfo->ri_RowIdAttNo =
5120 "wholerow");
5121 if (!AttributeNumberIsValid(resultRelInfo->ri_RowIdAttNo))
5122 elog(ERROR, "could not find junk wholerow column");
5123 }
5124 }
5125 }
5126
5127 /*
5128 * If this is an inherited update/delete/merge, there will be a junk
5129 * attribute named "tableoid" present in the subplan's targetlist. It
5130 * will be used to identify the result relation for a given tuple to be
5131 * updated/deleted/merged.
5132 */
5133 mtstate->mt_resultOidAttno =
5134 ExecFindJunkAttributeInTlist(subplan->targetlist, "tableoid");
5136 mtstate->mt_lastResultOid = InvalidOid; /* force lookup at first tuple */
5137 mtstate->mt_lastResultIndex = 0; /* must be zero if no such attr */
5138
5139 /* Get the root target relation */
5140 rel = mtstate->rootResultRelInfo->ri_RelationDesc;
5141
5142 /*
5143 * Build state for tuple routing if it's a partitioned INSERT. An UPDATE
5144 * or MERGE might need this too, but only if it actually moves tuples
5145 * between partitions; in that case setup is done by
5146 * ExecCrossPartitionUpdate.
5147 */
5148 if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE &&
5149 operation == CMD_INSERT)
5151 ExecSetupPartitionTupleRouting(estate, rel);
5152
5153 /*
5154 * Initialize any WITH CHECK OPTION constraints if needed.
5155 */
5156 resultRelInfo = mtstate->resultRelInfo;
5157 foreach(l, withCheckOptionLists)
5158 {
5159 List *wcoList = (List *) lfirst(l);
5160 List *wcoExprs = NIL;
5161 ListCell *ll;
5162
5163 foreach(ll, wcoList)
5164 {
5166 ExprState *wcoExpr = ExecInitQual((List *) wco->qual,
5167 &mtstate->ps);
5168
5170 }
5171
5172 resultRelInfo->ri_WithCheckOptions = wcoList;
5173 resultRelInfo->ri_WithCheckOptionExprs = wcoExprs;
5174 resultRelInfo++;
5175 }
5176
5177 /*
5178 * Initialize RETURNING projections if needed.
5179 */
5180 if (returningLists)
5181 {
5182 TupleTableSlot *slot;
5183 ExprContext *econtext;
5184
5185 /*
5186 * Initialize result tuple slot and assign its rowtype using the plan
5187 * node's declared targetlist, which the planner set up to be the same
5188 * as the first (before runtime pruning) RETURNING list. We assume
5189 * all the result rels will produce compatible output.
5190 */
5192 slot = mtstate->ps.ps_ResultTupleSlot;
5193
5194 /* Need an econtext too */
5195 if (mtstate->ps.ps_ExprContext == NULL)
5196 ExecAssignExprContext(estate, &mtstate->ps);
5197 econtext = mtstate->ps.ps_ExprContext;
5198
5199 /*
5200 * Build a projection for each result rel.
5201 */
5202 resultRelInfo = mtstate->resultRelInfo;
5203 foreach(l, returningLists)
5204 {
5205 List *rlist = (List *) lfirst(l);
5206
5207 resultRelInfo->ri_returningList = rlist;
5208 resultRelInfo->ri_projectReturning =
5209 ExecBuildProjectionInfo(rlist, econtext, slot, &mtstate->ps,
5210 resultRelInfo->ri_RelationDesc->rd_att);
5211 resultRelInfo++;
5212 }
5213 }
5214 else
5215 {
5216 /*
5217 * We still must construct a dummy result tuple type, because InitPlan
5218 * expects one (maybe should change that?).
5219 */
5220 ExecInitResultTypeTL(&mtstate->ps);
5221
5222 mtstate->ps.ps_ExprContext = NULL;
5223 }
5224
5225 /* Set the list of arbiter indexes if needed for ON CONFLICT */
5226 resultRelInfo = mtstate->resultRelInfo;
5227 if (node->onConflictAction != ONCONFLICT_NONE)
5228 {
5229 /* insert may only have one relation, inheritance is not expanded */
5230 Assert(total_nrels == 1);
5231 resultRelInfo->ri_onConflictArbiterIndexes = node->arbiterIndexes;
5232 }
5233
5234 /*
5235 * For ON CONFLICT DO SELECT/UPDATE, initialize the ON CONFLICT action
5236 * state.
5237 */
5238 if (node->onConflictAction == ONCONFLICT_UPDATE ||
5240 {
5242
5243 /* already exists if created by RETURNING processing above */
5244 if (mtstate->ps.ps_ExprContext == NULL)
5245 ExecAssignExprContext(estate, &mtstate->ps);
5246
5247 /* action state for DO SELECT/UPDATE */
5248 resultRelInfo->ri_onConflict = onconfl;
5249
5250 /* lock strength for DO SELECT [FOR UPDATE/SHARE] */
5252
5253 /* initialize slot for the existing tuple */
5254 onconfl->oc_Existing =
5255 table_slot_create(resultRelInfo->ri_RelationDesc,
5256 &mtstate->ps.state->es_tupleTable);
5257
5258 /*
5259 * For ON CONFLICT DO UPDATE, initialize target list and projection.
5260 */
5262 {
5263 ExprContext *econtext;
5265
5266 econtext = mtstate->ps.ps_ExprContext;
5267 relationDesc = resultRelInfo->ri_RelationDesc->rd_att;
5268
5269 /*
5270 * Create the tuple slot for the UPDATE SET projection. We want a
5271 * slot of the table's type here, because the slot will be used to
5272 * insert into the table, and for RETURNING processing - which may
5273 * access system attributes.
5274 */
5275 onconfl->oc_ProjSlot =
5276 table_slot_create(resultRelInfo->ri_RelationDesc,
5277 &mtstate->ps.state->es_tupleTable);
5278
5279 /* build UPDATE SET projection state */
5280 onconfl->oc_ProjInfo =
5282 true,
5283 node->onConflictCols,
5285 econtext,
5286 onconfl->oc_ProjSlot,
5287 &mtstate->ps);
5288 }
5289
5290 /* initialize state to evaluate the WHERE clause, if any */
5291 if (node->onConflictWhere)
5292 {
5293 ExprState *qualexpr;
5294
5295 qualexpr = ExecInitQual((List *) node->onConflictWhere,
5296 &mtstate->ps);
5297 onconfl->oc_WhereClause = qualexpr;
5298 }
5299 }
5300
5301 /*
5302 * If we have any secondary relations in an UPDATE or DELETE, they need to
5303 * be treated like non-locked relations in SELECT FOR UPDATE, i.e., the
5304 * EvalPlanQual mechanism needs to be told about them. This also goes for
5305 * the source relations in a MERGE. Locate the relevant ExecRowMarks.
5306 */
5307 arowmarks = NIL;
5308 foreach(l, node->rowMarks)
5309 {
5311 RangeTblEntry *rte = exec_rt_fetch(rc->rti, estate);
5314
5315 /* ignore "parent" rowmarks; they are irrelevant at runtime */
5316 if (rc->isParent)
5317 continue;
5318
5319 /*
5320 * Also ignore rowmarks belonging to child tables that have been
5321 * pruned in ExecDoInitialPruning().
5322 */
5323 if (rte->rtekind == RTE_RELATION &&
5324 !bms_is_member(rc->rti, estate->es_unpruned_relids))
5325 continue;
5326
5327 /* Find ExecRowMark and build ExecAuxRowMark */
5328 erm = ExecFindRowMark(estate, rc->rti, false);
5331 }
5332
5333 /* For a MERGE command, initialize its state */
5334 if (mtstate->operation == CMD_MERGE)
5335 ExecInitMerge(mtstate, estate);
5336
5337 EvalPlanQualSetPlan(&mtstate->mt_epqstate, subplan, arowmarks);
5338
5339 /*
5340 * If there are a lot of result relations, use a hash table to speed the
5341 * lookups. If there are not a lot, a simple linear search is faster.
5342 *
5343 * It's not clear where the threshold is, but try 64 for starters. In a
5344 * debugging build, use a small threshold so that we get some test
5345 * coverage of both code paths.
5346 */
5347#ifdef USE_ASSERT_CHECKING
5348#define MT_NRELS_HASH 4
5349#else
5350#define MT_NRELS_HASH 64
5351#endif
5352 if (nrels >= MT_NRELS_HASH)
5353 {
5355
5356 hash_ctl.keysize = sizeof(Oid);
5357 hash_ctl.entrysize = sizeof(MTTargetRelLookup);
5359 mtstate->mt_resultOidHash =
5360 hash_create("ModifyTable target hash",
5361 nrels, &hash_ctl,
5363 for (i = 0; i < nrels; i++)
5364 {
5365 Oid hashkey;
5367 bool found;
5368
5369 resultRelInfo = &mtstate->resultRelInfo[i];
5370 hashkey = RelationGetRelid(resultRelInfo->ri_RelationDesc);
5373 HASH_ENTER, &found);
5374 Assert(!found);
5375 mtlookup->relationIndex = i;
5376 }
5377 }
5378 else
5379 mtstate->mt_resultOidHash = NULL;
5380
5381 /*
5382 * Determine if the FDW supports batch insert and determine the batch size
5383 * (a FDW may support batching, but it may be disabled for the
5384 * server/table).
5385 *
5386 * We only do this for INSERT, so that for UPDATE/DELETE the batch size
5387 * remains set to 0.
5388 */
5389 if (operation == CMD_INSERT)
5390 {
5391 /* insert may only have one relation, inheritance is not expanded */
5392 Assert(total_nrels == 1);
5393 resultRelInfo = mtstate->resultRelInfo;
5394 if (!resultRelInfo->ri_usesFdwDirectModify &&
5395 resultRelInfo->ri_FdwRoutine != NULL &&
5396 resultRelInfo->ri_FdwRoutine->GetForeignModifyBatchSize &&
5397 resultRelInfo->ri_FdwRoutine->ExecForeignBatchInsert)
5398 {
5399 resultRelInfo->ri_BatchSize =
5400 resultRelInfo->ri_FdwRoutine->GetForeignModifyBatchSize(resultRelInfo);
5401 Assert(resultRelInfo->ri_BatchSize >= 1);
5402 }
5403 else
5404 resultRelInfo->ri_BatchSize = 1;
5405 }
5406
5407 /*
5408 * Lastly, if this is not the primary (canSetTag) ModifyTable node, add it
5409 * to estate->es_auxmodifytables so that it will be run to completion by
5410 * ExecPostprocessPlan. (It'd actually work fine to add the primary
5411 * ModifyTable node too, but there's no need.) Note the use of lcons not
5412 * lappend: we need later-initialized ModifyTable nodes to be shut down
5413 * before earlier ones. This ensures that we don't throw away RETURNING
5414 * rows that need to be seen by a later CTE subplan.
5415 */
5416 if (!mtstate->canSetTag)
5417 estate->es_auxmodifytables = lcons(mtstate,
5418 estate->es_auxmodifytables);
5419
5420 return mtstate;
5421}
#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:700
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:391
ExprState * ExecInitQual(List *qual, PlanState *parent)
Definition execExpr.c:250
ProjectionInfo * ExecBuildUpdateProjection(List *targetList, bool evalTargetList, List *targetColnos, TupleDesc relDesc, ExprContext *econtext, TupleTableSlot *slot, PlanState *parent)
Definition execExpr.c:568
AttrNumber ExecFindJunkAttributeInTlist(List *targetlist, const char *attrName)
Definition execJunk.c:222
ExecRowMark * ExecFindRowMark(EState *estate, Index rti, bool missing_ok)
Definition execMain.c:2575
ExecAuxRowMark * ExecBuildAuxRowMark(ExecRowMark *erm, List *targetlist)
Definition execMain.c:2598
void CheckValidResultRel(ResultRelInfo *resultRelInfo, CmdType operation, OnConflictAction onConflictAction, List *mergeActions)
Definition execMain.c:1056
void EvalPlanQualInit(EPQState *epqstate, EState *parentestate, Plan *subplan, List *auxrowmarks, int epqParam, List *resultRelations)
Definition execMain.c:2737
void EvalPlanQualSetPlan(EPQState *epqstate, Plan *subplan, List *auxrowmarks)
Definition execMain.c:2778
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:885
void ExecAssignExprContext(EState *estate, PlanState *planstate)
Definition execUtils.c:490
#define EXEC_FLAG_BACKWARD
Definition executor.h:70
static RangeTblEntry * exec_rt_fetch(Index rti, EState *estate)
Definition executor.h:701
#define EXEC_FLAG_EXPLAIN_ONLY
Definition executor.h:67
#define EXEC_FLAG_MARK
Definition executor.h:71
@ 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_SELECT
Definition nodes.h:431
@ 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:265
#define InvalidOid
unsigned int Oid
#define RelationGetRelid(relation)
Definition rel.h:514
Bitmapset * es_unpruned_relids
Definition execnodes.h:685
List * es_auxmodifytables
Definition execnodes.h:739
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:1484
TupleTableSlot * mt_merge_pending_not_matched
Definition execnodes.h:1470
double mt_merge_deleted
Definition execnodes.h:1475
List * mt_updateColnosLists
Definition execnodes.h:1482
double mt_merge_inserted
Definition execnodes.h:1473
double mt_merge_updated
Definition execnodes.h:1474
List * mt_mergeActionLists
Definition execnodes.h:1483
HTAB * mt_resultOidHash
Definition execnodes.h:1442
ResultRelInfo * rootResultRelInfo
Definition execnodes.h:1428
List * updateColnosLists
Definition plannodes.h:348
List * arbiterIndexes
Definition plannodes.h:368
List * onConflictCols
Definition plannodes.h:374
List * mergeJoinConditions
Definition plannodes.h:384
CmdType operation
Definition plannodes.h:338
List * resultRelations
Definition plannodes.h:346
Bitmapset * fdwDirectModifyPlans
Definition plannodes.h:360
List * onConflictSet
Definition plannodes.h:372
List * mergeActionLists
Definition plannodes.h:382
bool canSetTag
Definition plannodes.h:340
List * fdwPrivLists
Definition plannodes.h:358
List * returningLists
Definition plannodes.h:356
List * withCheckOptionLists
Definition plannodes.h:350
LockClauseStrength onConflictLockStrength
Definition plannodes.h:370
Index rootRelation
Definition plannodes.h:344
Node * onConflictWhere
Definition plannodes.h:376
List * rowMarks
Definition plannodes.h:362
OnConflictAction onConflictAction
Definition plannodes.h:366
LockClauseStrength oc_LockStrength
Definition execnodes.h:447
Plan * plan
Definition execnodes.h:1177
ExprContext * ps_ExprContext
Definition execnodes.h:1216
TupleTableSlot * ps_ResultTupleSlot
Definition execnodes.h:1215
ExecProcNodeMtd ExecProcNode
Definition execnodes.h:1183
List * targetlist
Definition plannodes.h:233
TupleDesc rd_att
Definition rel.h:112
Form_pg_class rd_rel
Definition rel.h:111
OnConflictActionState * ri_onConflict
Definition execnodes.h:595
List * ri_onConflictArbiterIndexes
Definition execnodes.h:592
struct ResultRelInfo * ri_RootResultRelInfo
Definition execnodes.h:630
List * ri_WithCheckOptions
Definition execnodes.h:561
List * ri_WithCheckOptionExprs
Definition execnodes.h:564
ProjectionInfo * ri_projectReturning
Definition execnodes.h:589
List * ri_returningList
Definition execnodes.h:586
AttrNumber ri_RowIdAttNo
Definition execnodes.h:507

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, OnConflictActionState::oc_LockStrength, ONCONFLICT_NONE, ONCONFLICT_SELECT, ONCONFLICT_UPDATE, ModifyTable::onConflictAction, ModifyTable::onConflictCols, ModifyTable::onConflictLockStrength, 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 5486 of file nodeModifyTable.c.

5487{
5488 /*
5489 * Currently, we don't need to support rescan on ModifyTable nodes. The
5490 * semantics of that would be a bit debatable anyway.
5491 */
5492 elog(ERROR, "ExecReScanModifyTable is not implemented");
5493}

References elog, and ERROR.

Referenced by ExecReScan().