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

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

5426{
5427 int i;
5428
5429 /*
5430 * Allow any FDWs to shut down
5431 */
5432 for (i = 0; i < node->mt_nrels; i++)
5433 {
5434 int j;
5435 ResultRelInfo *resultRelInfo = node->resultRelInfo + i;
5436
5437 if (!resultRelInfo->ri_usesFdwDirectModify &&
5438 resultRelInfo->ri_FdwRoutine != NULL &&
5439 resultRelInfo->ri_FdwRoutine->EndForeignModify != NULL)
5440 resultRelInfo->ri_FdwRoutine->EndForeignModify(node->ps.state,
5441 resultRelInfo);
5442
5443 /*
5444 * Cleanup the initialized batch slots. This only matters for FDWs
5445 * with batching, but the other cases will have ri_NumSlotsInitialized
5446 * == 0.
5447 */
5448 for (j = 0; j < resultRelInfo->ri_NumSlotsInitialized; j++)
5449 {
5450 ExecDropSingleTupleTableSlot(resultRelInfo->ri_Slots[j]);
5452 }
5453 }
5454
5455 /*
5456 * Close all the partitioned tables, leaf partitions, and their indices
5457 * and release the slot used for tuple routing, if set.
5458 */
5460 {
5462
5463 if (node->mt_root_tuple_slot)
5465 }
5466
5467 /*
5468 * Terminate EPQ execution if active
5469 */
5471
5472 /*
5473 * shut down subplan
5474 */
5476}
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:1264
int j
Definition isn.c:78
EndForeignModify_function EndForeignModify
Definition fdwapi.h:237
ResultRelInfo * resultRelInfo
Definition execnodes.h:1411
struct PartitionTupleRouting * mt_partition_tuple_routing
Definition execnodes.h:1442
TupleTableSlot * mt_root_tuple_slot
Definition execnodes.h:1439
EPQState mt_epqstate
Definition execnodes.h:1421
EState * state
Definition execnodes.h:1170
TupleTableSlot ** ri_Slots
Definition execnodes.h:548
int ri_NumSlotsInitialized
Definition execnodes.h:546
struct FdwRoutine * ri_FdwRoutine
Definition execnodes.h:536
TupleTableSlot ** ri_PlanSlots
Definition execnodes.h:549
bool ri_usesFdwDirectModify
Definition execnodes.h:542

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

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

4155{
4156 EState *estate = mtstate->ps.state;
4157
4158 Assert(!resultRelInfo->ri_projectNewInfoValid);
4159
4160 resultRelInfo->ri_oldTupleSlot =
4161 table_slot_create(resultRelInfo->ri_RelationDesc,
4162 &estate->es_tupleTable);
4163 resultRelInfo->ri_newTupleSlot =
4164 table_slot_create(resultRelInfo->ri_RelationDesc,
4165 &estate->es_tupleTable);
4166 resultRelInfo->ri_projectNewInfoValid = true;
4167}
List * es_tupleTable
Definition execnodes.h:715
bool ri_projectNewInfoValid
Definition execnodes.h:512
TupleTableSlot * ri_oldTupleSlot
Definition execnodes.h:510
TupleTableSlot * ri_newTupleSlot
Definition execnodes.h:508
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 4826 of file nodeModifyTable.c.

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

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

5480{
5481 /*
5482 * Currently, we don't need to support rescan on ModifyTable nodes. The
5483 * semantics of that would be a bit debatable anyway.
5484 */
5485 elog(ERROR, "ExecReScanModifyTable is not implemented");
5486}

References elog, and ERROR.

Referenced by ExecReScan().