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

571{
572 Relation rel = resultRelInfo->ri_RelationDesc;
573 TupleDesc tupdesc = RelationGetDescr(rel);
574 int natts = tupdesc->natts;
575 ExprContext *econtext = GetPerTupleExprContext(estate);
578 Datum *values;
579 bool *nulls;
580
581 /* We should not be called unless this is true */
582 Assert(tupdesc->constr && tupdesc->constr->has_generated_stored);
583
584 /*
585 * Initialize the expressions if we didn't already, and check whether we
586 * can exit early because nothing needs to be computed.
587 */
588 if (cmdtype == CMD_UPDATE)
589 {
590 if (resultRelInfo->ri_GeneratedExprsU == NULL)
591 ExecInitGenerated(resultRelInfo, estate, cmdtype);
592 if (resultRelInfo->ri_NumGeneratedNeededU == 0)
593 return;
594 ri_GeneratedExprs = resultRelInfo->ri_GeneratedExprsU;
595 }
596 else
597 {
598 if (resultRelInfo->ri_GeneratedExprsI == NULL)
599 ExecInitGenerated(resultRelInfo, estate, cmdtype);
600 /* Early exit is impossible given the prior Assert */
601 Assert(resultRelInfo->ri_NumGeneratedNeededI > 0);
602 ri_GeneratedExprs = resultRelInfo->ri_GeneratedExprsI;
603 }
604
606
607 values = palloc_array(Datum, natts);
608 nulls = palloc_array(bool, natts);
609
610 slot_getallattrs(slot);
611 memcpy(nulls, slot->tts_isnull, sizeof(*nulls) * natts);
612
613 for (int i = 0; i < natts; i++)
614 {
615 CompactAttribute *attr = TupleDescCompactAttr(tupdesc, i);
616
617 if (ri_GeneratedExprs[i])
618 {
619 Datum val;
620 bool isnull;
621
622 Assert(TupleDescAttr(tupdesc, i)->attgenerated == ATTRIBUTE_GENERATED_STORED);
623
624 econtext->ecxt_scantuple = slot;
625
626 val = ExecEvalExpr(ri_GeneratedExprs[i], econtext, &isnull);
627
628 /*
629 * We must make a copy of val as we have no guarantees about where
630 * memory for a pass-by-reference Datum is located.
631 */
632 if (!isnull)
633 val = datumCopy(val, attr->attbyval, attr->attlen);
634
635 values[i] = val;
636 nulls[i] = isnull;
637 }
638 else
639 {
640 if (!nulls[i])
641 values[i] = datumCopy(slot->tts_values[i], attr->attbyval, attr->attlen);
642 }
643 }
644
645 ExecClearTuple(slot);
646 memcpy(slot->tts_values, values, sizeof(*values) * natts);
647 memcpy(slot->tts_isnull, nulls, sizeof(*nulls) * natts);
650
652}
static Datum values[MAXATTR]
Definition bootstrap.c:190
#define Assert(condition)
Definition c.h:1002
memcpy(sums, checksumBaseOffsets, sizeof(checksumBaseOffsets))
Datum datumCopy(Datum value, bool typByVal, int typLen)
Definition datum.c:132
TupleTableSlot * ExecStoreVirtualTuple(TupleTableSlot *slot)
#define GetPerTupleExprContext(estate)
Definition executor.h:665
#define GetPerTupleMemoryContext(estate)
Definition executor.h:670
static Datum ExecEvalExpr(ExprState *state, ExprContext *econtext, bool *isNull)
Definition executor.h:401
#define palloc_array(type, count)
Definition fe_memutils.h:91
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:274
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition palloc.h:138
uint64_t Datum
Definition postgres.h:70
static int fb(int x)
#define RelationGetDescr(relation)
Definition rel.h:542
TupleTableSlot * ecxt_scantuple
Definition execnodes.h:287
Relation ri_RelationDesc
Definition execnodes.h:514
ExprState ** ri_GeneratedExprsI
Definition execnodes.h:600
int ri_NumGeneratedNeededU
Definition execnodes.h:605
ExprState ** ri_GeneratedExprsU
Definition execnodes.h:601
int ri_NumGeneratedNeededI
Definition execnodes.h:604
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:195
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:495

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, memcpy(), 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 5836 of file nodeModifyTable.c.

5837{
5838 int i;
5839
5840 /*
5841 * Allow any FDWs to shut down
5842 */
5843 for (i = 0; i < node->mt_nrels; i++)
5844 {
5845 int j;
5846 ResultRelInfo *resultRelInfo = node->resultRelInfo + i;
5847
5848 if (!resultRelInfo->ri_usesFdwDirectModify &&
5849 resultRelInfo->ri_FdwRoutine != NULL &&
5850 resultRelInfo->ri_FdwRoutine->EndForeignModify != NULL)
5851 resultRelInfo->ri_FdwRoutine->EndForeignModify(node->ps.state,
5852 resultRelInfo);
5853
5854 /*
5855 * Cleanup the initialized batch slots. This only matters for FDWs
5856 * with batching, but the other cases will have ri_NumSlotsInitialized
5857 * == 0.
5858 */
5859 for (j = 0; j < resultRelInfo->ri_NumSlotsInitialized; j++)
5860 {
5861 ExecDropSingleTupleTableSlot(resultRelInfo->ri_Slots[j]);
5863 }
5864 }
5865
5866 /*
5867 * Close all the partitioned tables, leaf partitions, and their indices
5868 * and release the slot used for tuple routing, if set.
5869 */
5871 {
5873
5874 if (node->mt_root_tuple_slot)
5876 }
5877
5878 /*
5879 * Terminate EPQ execution if active
5880 */
5882
5883 /*
5884 * shut down subplan
5885 */
5887}
void EvalPlanQualEnd(EPQState *epqstate)
Definition execMain.c:3245
void ExecCleanupTupleRouting(ModifyTableState *mtstate, PartitionTupleRouting *proute)
void ExecEndNode(PlanState *node)
void ExecDropSingleTupleTableSlot(TupleTableSlot *slot)
#define outerPlanState(node)
Definition execnodes.h:1300
int j
Definition isn.c:78
EndForeignModify_function EndForeignModify
Definition fdwapi.h:241
ResultRelInfo * resultRelInfo
Definition execnodes.h:1447
struct PartitionTupleRouting * mt_partition_tuple_routing
Definition execnodes.h:1478
TupleTableSlot * mt_root_tuple_slot
Definition execnodes.h:1475
EPQState mt_epqstate
Definition execnodes.h:1457
EState * state
Definition execnodes.h:1204
TupleTableSlot ** ri_Slots
Definition execnodes.h:579
int ri_NumSlotsInitialized
Definition execnodes.h:577
struct FdwRoutine * ri_FdwRoutine
Definition execnodes.h:567
TupleTableSlot ** ri_PlanSlots
Definition execnodes.h:580
bool ri_usesFdwDirectModify
Definition execnodes.h:573

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

457{
458 Relation rel = resultRelInfo->ri_RelationDesc;
459 TupleDesc tupdesc = RelationGetDescr(rel);
460 int natts = tupdesc->natts;
463 Bitmapset *updatedCols;
465
466 /* Nothing to do if no generated columns */
467 if (!(tupdesc->constr && (tupdesc->constr->has_generated_stored || tupdesc->constr->has_generated_virtual)))
468 return;
469
470 /*
471 * In an UPDATE, we can skip computing any generated columns that do not
472 * depend on any UPDATE target column. But if there is a BEFORE ROW
473 * UPDATE trigger, we cannot skip because the trigger might change more
474 * columns.
475 */
476 if (cmdtype == CMD_UPDATE &&
478 updatedCols = ExecGetUpdatedCols(resultRelInfo, estate);
479 else
480 updatedCols = NULL;
481
482 /*
483 * Make sure these data structures are built in the per-query memory
484 * context so they'll survive throughout the query.
485 */
487
488 ri_GeneratedExprs = (ExprState **) palloc0(natts * sizeof(ExprState *));
490
491 for (int i = 0; i < natts; i++)
492 {
493 char attgenerated = TupleDescAttr(tupdesc, i)->attgenerated;
494
495 if (attgenerated)
496 {
497 Expr *expr;
498
499 /* Fetch the GENERATED AS expression tree */
500 expr = (Expr *) build_column_default(rel, i + 1);
501 if (expr == NULL)
502 elog(ERROR, "no generation expression found for column number %d of table \"%s\"",
503 i + 1, RelationGetRelationName(rel));
504
505 /*
506 * If it's an update with a known set of update target columns,
507 * see if we can skip the computation.
508 */
509 if (updatedCols)
510 {
511 Bitmapset *attrs_used = NULL;
512
513 pull_varattnos((Node *) expr, 1, &attrs_used);
514
515 if (!bms_overlap(updatedCols, attrs_used))
516 continue; /* need not update this column */
517 }
518
519 /* No luck, so prepare the expression for execution */
520 if (attgenerated == ATTRIBUTE_GENERATED_STORED)
521 {
522 ri_GeneratedExprs[i] = ExecPrepareExpr(expr, estate);
524 }
525
526 /* If UPDATE, mark column in resultRelInfo->ri_extraUpdatedCols */
527 if (cmdtype == CMD_UPDATE)
528 resultRelInfo->ri_extraUpdatedCols =
529 bms_add_member(resultRelInfo->ri_extraUpdatedCols,
531 }
532 }
533
534 if (ri_NumGeneratedNeeded == 0)
535 {
536 /* didn't need it after all */
539 }
540
541 /* Save in appropriate set of fields */
542 if (cmdtype == CMD_UPDATE)
543 {
544 /* Don't call twice */
545 Assert(resultRelInfo->ri_GeneratedExprsU == NULL);
546
547 resultRelInfo->ri_GeneratedExprsU = ri_GeneratedExprs;
549
550 resultRelInfo->ri_extraUpdatedCols_valid = true;
551 }
552 else
553 {
554 /* Don't call twice */
555 Assert(resultRelInfo->ri_GeneratedExprsI == NULL);
556
557 resultRelInfo->ri_GeneratedExprsI = ri_GeneratedExprs;
559 }
560
562}
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition bitmapset.c:934
bool bms_overlap(const Bitmapset *a, const Bitmapset *b)
Definition bitmapset.c:710
#define ERROR
Definition elog.h:40
#define elog(elevel,...)
Definition elog.h:228
ExprState * ExecPrepareExpr(Expr *node, EState *estate)
Definition execExpr.c:765
Bitmapset * ExecGetUpdatedCols(ResultRelInfo *relinfo, EState *estate)
Definition execUtils.c:1408
void pfree(void *pointer)
Definition mcxt.c:1619
void * palloc0(Size size)
Definition mcxt.c:1420
#define RelationGetRelationName(relation)
Definition rel.h:550
Node * build_column_default(Relation rel, int attrno)
MemoryContext es_query_cxt
Definition execnodes.h:747
Definition nodes.h:133
TriggerDesc * trigdesc
Definition rel.h:117
bool ri_extraUpdatedCols_valid
Definition execnodes.h:534
Bitmapset * ri_extraUpdatedCols
Definition execnodes.h:532
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 4434 of file nodeModifyTable.c.

4436{
4437 EState *estate = mtstate->ps.state;
4438
4439 Assert(!resultRelInfo->ri_projectNewInfoValid);
4440
4441 resultRelInfo->ri_oldTupleSlot =
4442 table_slot_create(resultRelInfo->ri_RelationDesc,
4443 &estate->es_tupleTable);
4444 resultRelInfo->ri_newTupleSlot =
4445 table_slot_create(resultRelInfo->ri_RelationDesc,
4446 &estate->es_tupleTable);
4447 resultRelInfo->ri_projectNewInfoValid = true;
4448}
List * es_tupleTable
Definition execnodes.h:749
bool ri_projectNewInfoValid
Definition execnodes.h:543
TupleTableSlot * ri_oldTupleSlot
Definition execnodes.h:541
TupleTableSlot * ri_newTupleSlot
Definition execnodes.h:539
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 5117 of file nodeModifyTable.c.

5118{
5119 ModifyTableState *mtstate;
5120 Plan *subplan = outerPlan(node);
5121 CmdType operation = node->operation;
5123 int nrels;
5124 List *resultRelations = NIL;
5125 List *withCheckOptionLists = NIL;
5126 List *returningLists = NIL;
5127 List *updateColnosLists = NIL;
5128 List *mergeActionLists = NIL;
5129 List *mergeJoinConditions = NIL;
5130 List *fdwPrivLists = NIL;
5131 Bitmapset *fdwDirectModifyPlans = NULL;
5132 ResultRelInfo *resultRelInfo;
5133 List *arowmarks;
5134 ListCell *l;
5135 int i;
5136 Relation rel;
5137
5138 /* check for unsupported flags */
5139 Assert(!(eflags & (EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK)));
5140
5141 /*
5142 * Only consider unpruned relations for initializing their ResultRelInfo
5143 * struct and other fields such as withCheckOptions, etc.
5144 *
5145 * Note: We must avoid pruning every result relation. This is important
5146 * for MERGE, since even if every result relation is pruned from the
5147 * subplan, there might still be NOT MATCHED rows, for which there may be
5148 * INSERT actions to perform. To allow these actions to be found, at
5149 * least one result relation must be kept. Also, when inserting into a
5150 * partitioned table, ExecInitPartitionInfo() needs a ResultRelInfo struct
5151 * as a reference for building the ResultRelInfo of the target partition.
5152 * In either case, it doesn't matter which result relation is kept, so we
5153 * just keep the first one, if all others have been pruned. See also,
5154 * ExecDoInitialPruning(), which ensures that this first result relation
5155 * has been locked.
5156 */
5157 i = 0;
5158 foreach(l, node->resultRelations)
5159 {
5160 Index rti = lfirst_int(l);
5161 bool keep_rel;
5162
5164 if (!keep_rel && i == total_nrels - 1 && resultRelations == NIL)
5165 {
5166 /* all result relations pruned; keep the first one */
5167 keep_rel = true;
5168 rti = linitial_int(node->resultRelations);
5169 i = 0;
5170 }
5171
5172 if (keep_rel)
5173 {
5174 List *fdwPrivList = (List *) list_nth(node->fdwPrivLists, i);
5175
5176 resultRelations = lappend_int(resultRelations, rti);
5177 if (node->withCheckOptionLists)
5178 {
5181 i);
5182
5183 withCheckOptionLists = lappend(withCheckOptionLists, withCheckOptions);
5184 }
5185 if (node->returningLists)
5186 {
5187 List *returningList = list_nth_node(List,
5188 node->returningLists,
5189 i);
5190
5191 returningLists = lappend(returningLists, returningList);
5192 }
5193 if (node->updateColnosLists)
5194 {
5196
5197 updateColnosLists = lappend(updateColnosLists, updateColnosList);
5198 }
5199 if (node->mergeActionLists)
5200 {
5201 List *mergeActionList = list_nth(node->mergeActionLists, i);
5202
5203 mergeActionLists = lappend(mergeActionLists, mergeActionList);
5204 }
5205 if (node->mergeJoinConditions)
5206 {
5207 List *mergeJoinCondition = list_nth(node->mergeJoinConditions, i);
5208
5209 mergeJoinConditions = lappend(mergeJoinConditions, mergeJoinCondition);
5210 }
5211
5212 /*
5213 * fdwPrivLists/fdwDirectModifyPlans are re-indexed to match
5214 * resultRelations
5215 */
5216 fdwPrivLists = lappend(fdwPrivLists, fdwPrivList);
5218 {
5219 int new_index = list_length(resultRelations) - 1;
5220
5221 fdwDirectModifyPlans = bms_add_member(fdwDirectModifyPlans,
5222 new_index);
5223 }
5224 }
5225 i++;
5226 }
5227 nrels = list_length(resultRelations);
5228 Assert(nrels > 0);
5229
5230 /*
5231 * create state structure
5232 */
5233 mtstate = makeNode(ModifyTableState);
5234 mtstate->ps.plan = (Plan *) node;
5235 mtstate->ps.state = estate;
5236 mtstate->ps.ExecProcNode = ExecModifyTable;
5237
5238 mtstate->operation = operation;
5239 mtstate->canSetTag = node->canSetTag;
5240 mtstate->mt_done = false;
5241
5242 mtstate->mt_nrels = nrels;
5243 mtstate->resultRelInfo = palloc_array(ResultRelInfo, nrels);
5244
5246 mtstate->mt_merge_inserted = 0;
5247 mtstate->mt_merge_updated = 0;
5248 mtstate->mt_merge_deleted = 0;
5249 mtstate->mt_updateColnosLists = updateColnosLists;
5250 mtstate->mt_mergeActionLists = mergeActionLists;
5251 mtstate->mt_mergeJoinConditions = mergeJoinConditions;
5252 mtstate->mt_fdwPrivLists = fdwPrivLists;
5253
5254 /*----------
5255 * Resolve the target relation. This is the same as:
5256 *
5257 * - the relation for which we will fire FOR STATEMENT triggers,
5258 * - the relation into whose tuple format all captured transition tuples
5259 * must be converted, and
5260 * - the root partitioned table used for tuple routing.
5261 *
5262 * If it's a partitioned or inherited table, the root partition or
5263 * appendrel RTE doesn't appear elsewhere in the plan and its RT index is
5264 * given explicitly in node->rootRelation. Otherwise, the target relation
5265 * is the sole relation in the node->resultRelations list and, since it can
5266 * never be pruned, also in the resultRelations list constructed above.
5267 *----------
5268 */
5269 if (node->rootRelation > 0)
5270 {
5274 node->rootRelation);
5275 }
5276 else
5277 {
5278 Assert(list_length(node->resultRelations) == 1);
5279 Assert(list_length(resultRelations) == 1);
5280 mtstate->rootResultRelInfo = mtstate->resultRelInfo;
5281 ExecInitResultRelation(estate, mtstate->resultRelInfo,
5282 linitial_int(resultRelations));
5283 }
5284
5285 /* set up epqstate with dummy subplan data for the moment */
5286 EvalPlanQualInit(&mtstate->mt_epqstate, estate, NULL, NIL,
5287 node->epqParam, resultRelations);
5288 mtstate->fireBSTriggers = true;
5289
5290 /*
5291 * Build state for collecting transition tuples. This requires having a
5292 * valid trigger query context, so skip it in explain-only mode.
5293 */
5294 if (!(eflags & EXEC_FLAG_EXPLAIN_ONLY))
5295 ExecSetupTransitionCaptureState(mtstate, estate);
5296
5297 /*
5298 * Open all the result relations and initialize the ResultRelInfo structs.
5299 * (But root relation was initialized above, if it's part of the array.)
5300 * We must do this before initializing the subplan, because direct-modify
5301 * FDWs expect their ResultRelInfos to be available.
5302 */
5303 resultRelInfo = mtstate->resultRelInfo;
5304 i = 0;
5305 foreach(l, resultRelations)
5306 {
5307 Index resultRelation = lfirst_int(l);
5309
5310 if (mergeActionLists)
5311 mergeActions = list_nth(mergeActionLists, i);
5312
5313 if (resultRelInfo != mtstate->rootResultRelInfo)
5314 {
5315 ExecInitResultRelation(estate, resultRelInfo, resultRelation);
5316
5317 /*
5318 * For child result relations, store the root result relation
5319 * pointer. We do so for the convenience of places that want to
5320 * look at the query's original target relation but don't have the
5321 * mtstate handy.
5322 */
5323 resultRelInfo->ri_RootResultRelInfo = mtstate->rootResultRelInfo;
5324 }
5325
5326 /* Initialize the usesFdwDirectModify flag */
5327 resultRelInfo->ri_usesFdwDirectModify =
5328 bms_is_member(i, fdwDirectModifyPlans);
5329
5330 /*
5331 * Verify result relation is a valid target for the current operation
5332 */
5333 CheckValidResultRel(resultRelInfo, operation, node->onConflictAction,
5334 mergeActions, node);
5335
5336 resultRelInfo++;
5337 i++;
5338 }
5339
5340 /*
5341 * Now we may initialize the subplan.
5342 */
5343 outerPlanState(mtstate) = ExecInitNode(subplan, estate, eflags);
5344
5345 /*
5346 * Do additional per-result-relation initialization.
5347 */
5348 for (i = 0; i < nrels; i++)
5349 {
5350 resultRelInfo = &mtstate->resultRelInfo[i];
5351
5352 /* Let FDWs init themselves for foreign-table result rels */
5353 if (!resultRelInfo->ri_usesFdwDirectModify &&
5354 resultRelInfo->ri_FdwRoutine != NULL &&
5355 resultRelInfo->ri_FdwRoutine->BeginForeignModify != NULL)
5356 {
5357 List *fdw_private = (List *) list_nth(fdwPrivLists, i);
5358
5359 resultRelInfo->ri_FdwRoutine->BeginForeignModify(mtstate,
5360 resultRelInfo,
5361 fdw_private,
5362 i,
5363 eflags);
5364 }
5365
5366 /*
5367 * For UPDATE/DELETE/MERGE, find the appropriate junk attr now, either
5368 * a 'ctid' or 'wholerow' attribute depending on relkind. For foreign
5369 * tables, the FDW might have created additional junk attr(s), but
5370 * those are no concern of ours.
5371 */
5374 {
5375 char relkind;
5376
5377 relkind = resultRelInfo->ri_RelationDesc->rd_rel->relkind;
5378 if (relkind == RELKIND_RELATION ||
5379 relkind == RELKIND_MATVIEW ||
5380 relkind == RELKIND_PARTITIONED_TABLE)
5381 {
5382 resultRelInfo->ri_RowIdAttNo =
5383 ExecFindJunkAttributeInTlist(subplan->targetlist, "ctid");
5384
5385 /*
5386 * For heap relations, a ctid junk attribute must be present.
5387 * Partitioned tables should only appear here when all leaf
5388 * partitions were pruned, in which case no rows can be
5389 * produced and ctid is not needed.
5390 */
5391 if (relkind == RELKIND_PARTITIONED_TABLE)
5392 Assert(nrels == 1);
5393 else if (!AttributeNumberIsValid(resultRelInfo->ri_RowIdAttNo))
5394 elog(ERROR, "could not find junk ctid column");
5395 }
5396 else if (relkind == RELKIND_FOREIGN_TABLE)
5397 {
5398 /*
5399 * We don't support MERGE with foreign tables for now. (It's
5400 * problematic because the implementation uses CTID.)
5401 */
5403
5404 /*
5405 * When there is a row-level trigger, there should be a
5406 * wholerow attribute. We also require it to be present in
5407 * UPDATE and MERGE, so we can get the values of unchanged
5408 * columns.
5409 */
5410 resultRelInfo->ri_RowIdAttNo =
5412 "wholerow");
5413 if ((mtstate->operation == CMD_UPDATE || mtstate->operation == CMD_MERGE) &&
5414 !AttributeNumberIsValid(resultRelInfo->ri_RowIdAttNo))
5415 elog(ERROR, "could not find junk wholerow column");
5416 }
5417 else
5418 {
5419 /* Other valid target relkinds must provide wholerow */
5420 resultRelInfo->ri_RowIdAttNo =
5422 "wholerow");
5423 if (!AttributeNumberIsValid(resultRelInfo->ri_RowIdAttNo))
5424 elog(ERROR, "could not find junk wholerow column");
5425 }
5426 }
5427 }
5428
5429 /*
5430 * If this is an inherited update/delete/merge, there will be a junk
5431 * attribute named "tableoid" present in the subplan's targetlist. It
5432 * will be used to identify the result relation for a given tuple to be
5433 * updated/deleted/merged.
5434 */
5435 mtstate->mt_resultOidAttno =
5436 ExecFindJunkAttributeInTlist(subplan->targetlist, "tableoid");
5438 mtstate->mt_lastResultOid = InvalidOid; /* force lookup at first tuple */
5439 mtstate->mt_lastResultIndex = 0; /* must be zero if no such attr */
5440
5441 /* Get the root target relation */
5442 rel = mtstate->rootResultRelInfo->ri_RelationDesc;
5443
5444 /*
5445 * Build state for tuple routing if it's a partitioned INSERT. An UPDATE
5446 * or MERGE might need this too, but only if it actually moves tuples
5447 * between partitions; in that case setup is done by
5448 * ExecCrossPartitionUpdate.
5449 */
5450 if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE &&
5453 ExecSetupPartitionTupleRouting(estate, rel);
5454
5455 /*
5456 * Initialize any WITH CHECK OPTION constraints if needed.
5457 */
5458 resultRelInfo = mtstate->resultRelInfo;
5459 foreach(l, withCheckOptionLists)
5460 {
5461 List *wcoList = (List *) lfirst(l);
5462 List *wcoExprs = NIL;
5463 ListCell *ll;
5464
5465 foreach(ll, wcoList)
5466 {
5468 ExprState *wcoExpr = ExecInitQual((List *) wco->qual,
5469 &mtstate->ps);
5470
5472 }
5473
5474 resultRelInfo->ri_WithCheckOptions = wcoList;
5475 resultRelInfo->ri_WithCheckOptionExprs = wcoExprs;
5476 resultRelInfo++;
5477 }
5478
5479 /*
5480 * Initialize RETURNING projections if needed.
5481 */
5482 if (returningLists)
5483 {
5484 TupleTableSlot *slot;
5485 ExprContext *econtext;
5486
5487 /*
5488 * Initialize result tuple slot and assign its rowtype using the plan
5489 * node's declared targetlist, which the planner set up to be the same
5490 * as the first (before runtime pruning) RETURNING list. We assume
5491 * all the result rels will produce compatible output.
5492 */
5494 slot = mtstate->ps.ps_ResultTupleSlot;
5495
5496 /* Need an econtext too */
5497 if (mtstate->ps.ps_ExprContext == NULL)
5498 ExecAssignExprContext(estate, &mtstate->ps);
5499 econtext = mtstate->ps.ps_ExprContext;
5500
5501 /*
5502 * Build a projection for each result rel.
5503 */
5504 resultRelInfo = mtstate->resultRelInfo;
5505 foreach(l, returningLists)
5506 {
5507 List *rlist = (List *) lfirst(l);
5508
5509 resultRelInfo->ri_returningList = rlist;
5510 resultRelInfo->ri_projectReturning =
5511 ExecBuildProjectionInfo(rlist, econtext, slot, &mtstate->ps,
5512 resultRelInfo->ri_RelationDesc->rd_att);
5513 resultRelInfo++;
5514 }
5515 }
5516 else
5517 {
5518 /*
5519 * We still must construct a dummy result tuple type, because InitPlan
5520 * expects one (maybe should change that?).
5521 */
5522 ExecInitResultTypeTL(&mtstate->ps);
5523
5524 mtstate->ps.ps_ExprContext = NULL;
5525 }
5526
5527 /* Set the list of arbiter indexes if needed for ON CONFLICT */
5528 resultRelInfo = mtstate->resultRelInfo;
5529 if (node->onConflictAction != ONCONFLICT_NONE)
5530 {
5531 /* insert may only have one relation, inheritance is not expanded */
5532 Assert(total_nrels == 1);
5533 resultRelInfo->ri_onConflictArbiterIndexes = node->arbiterIndexes;
5534 }
5535
5536 /*
5537 * For ON CONFLICT DO SELECT/UPDATE, initialize the ON CONFLICT action
5538 * state.
5539 */
5540 if (node->onConflictAction == ONCONFLICT_UPDATE ||
5542 {
5544
5545 /* already exists if created by RETURNING processing above */
5546 if (mtstate->ps.ps_ExprContext == NULL)
5547 ExecAssignExprContext(estate, &mtstate->ps);
5548
5549 /* action state for DO SELECT/UPDATE */
5550 resultRelInfo->ri_onConflict = onconfl;
5551
5552 /* lock strength for DO SELECT [FOR UPDATE/SHARE] */
5554
5555 /* initialize slot for the existing tuple */
5556 onconfl->oc_Existing =
5557 table_slot_create(resultRelInfo->ri_RelationDesc,
5558 &mtstate->ps.state->es_tupleTable);
5559
5560 /*
5561 * For ON CONFLICT DO UPDATE, initialize target list and projection.
5562 */
5564 {
5565 ExprContext *econtext;
5567
5568 econtext = mtstate->ps.ps_ExprContext;
5569 relationDesc = resultRelInfo->ri_RelationDesc->rd_att;
5570
5571 /*
5572 * Create the tuple slot for the UPDATE SET projection. We want a
5573 * slot of the table's type here, because the slot will be used to
5574 * insert into the table, and for RETURNING processing - which may
5575 * access system attributes.
5576 */
5577 onconfl->oc_ProjSlot =
5578 table_slot_create(resultRelInfo->ri_RelationDesc,
5579 &mtstate->ps.state->es_tupleTable);
5580
5581 /* build UPDATE SET projection state */
5582 onconfl->oc_ProjInfo =
5584 true,
5585 node->onConflictCols,
5587 econtext,
5588 onconfl->oc_ProjSlot,
5589 &mtstate->ps);
5590 }
5591
5592 /* initialize state to evaluate the WHERE clause, if any */
5593 if (node->onConflictWhere)
5594 {
5595 ExprState *qualexpr;
5596
5597 qualexpr = ExecInitQual((List *) node->onConflictWhere,
5598 &mtstate->ps);
5599 onconfl->oc_WhereClause = qualexpr;
5600 }
5601 }
5602
5603 /*
5604 * If needed, initialize the target range for FOR PORTION OF.
5605 */
5606 if (node->forPortionOf)
5607 {
5609 TupleDesc tupDesc;
5610 ForPortionOfExpr *forPortionOf;
5611 Datum targetRange;
5612 bool isNull;
5613 ExprContext *econtext;
5616
5617 rootRelInfo = mtstate->resultRelInfo;
5618 if (rootRelInfo->ri_RootResultRelInfo)
5620
5621 tupDesc = rootRelInfo->ri_RelationDesc->rd_att;
5622 forPortionOf = (ForPortionOfExpr *) node->forPortionOf;
5623
5624 /* Eval the FOR PORTION OF target */
5625 if (mtstate->ps.ps_ExprContext == NULL)
5626 ExecAssignExprContext(estate, &mtstate->ps);
5627 econtext = mtstate->ps.ps_ExprContext;
5628
5629 exprState = ExecPrepareExpr((Expr *) forPortionOf->targetRange, estate);
5630 targetRange = ExecEvalExpr(exprState, econtext, &isNull);
5631
5632 /*
5633 * FOR PORTION OF ... TO ... FROM should never give us a NULL target,
5634 * but FOR PORTION OF (...) could.
5635 */
5636 if (isNull)
5637 ereport(ERROR,
5638 (errmsg("FOR PORTION OF target was null")),
5639 executor_errposition(estate, forPortionOf->targetLocation));
5640
5641 /* Create state for FOR PORTION OF operation */
5642
5644 fpoState->fp_rangeName = forPortionOf->range_name;
5645 fpoState->fp_rangeType = forPortionOf->rangeType;
5646 fpoState->fp_rangeAttno = forPortionOf->rangeVar->varattno;
5647 fpoState->fp_targetRange = targetRange;
5648
5649 /* Initialize slot for the existing tuple */
5650
5651 fpoState->fp_Existing =
5652 table_slot_create(rootRelInfo->ri_RelationDesc,
5653 &mtstate->ps.state->es_tupleTable);
5654
5655 /* Create the tuple slot for INSERTing the temporal leftovers */
5656
5657 fpoState->fp_Leftover =
5658 ExecInitExtraTupleSlot(mtstate->ps.state, tupDesc, &TTSOpsVirtual);
5659
5660 rootRelInfo->ri_forPortionOf = fpoState;
5661
5662 /*
5663 * Make sure the root relation has the FOR PORTION OF clause too. Each
5664 * partition needs its own TupleTableSlot, since they can have
5665 * different descriptors, so they'll use the root fpoState to
5666 * initialize one if necessary.
5667 */
5668 if (node->rootRelation > 0)
5670
5671 if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE &&
5672 mtstate->mt_partition_tuple_routing == NULL)
5673 {
5674 /*
5675 * We will need tuple routing to insert temporal leftovers. Since
5676 * we are initializing things before ExecCrossPartitionUpdate
5677 * runs, we must do everything it needs as well.
5678 */
5681
5682 /* Things built here have to last for the query duration. */
5684
5687
5688 /*
5689 * Before a partition's tuple can be re-routed, it must first be
5690 * converted to the root's format, so we'll need a slot for
5691 * storing such tuples.
5692 */
5693 Assert(mtstate->mt_root_tuple_slot == NULL);
5695
5697 }
5698
5699 /*
5700 * Don't free the ExprContext here because the result must last for
5701 * the whole query.
5702 */
5703 }
5704
5705 /*
5706 * If we have any secondary relations in an UPDATE or DELETE, they need to
5707 * be treated like non-locked relations in SELECT FOR UPDATE, i.e., the
5708 * EvalPlanQual mechanism needs to be told about them. This also goes for
5709 * the source relations in a MERGE. Locate the relevant ExecRowMarks.
5710 */
5711 arowmarks = NIL;
5712 foreach(l, node->rowMarks)
5713 {
5715 RangeTblEntry *rte = exec_rt_fetch(rc->rti, estate);
5718
5719 /* ignore "parent" rowmarks; they are irrelevant at runtime */
5720 if (rc->isParent)
5721 continue;
5722
5723 /*
5724 * Also ignore rowmarks belonging to child tables that have been
5725 * pruned in ExecDoInitialPruning().
5726 */
5727 if (rte->rtekind == RTE_RELATION &&
5728 !bms_is_member(rc->rti, estate->es_unpruned_relids))
5729 continue;
5730
5731 /* Find ExecRowMark and build ExecAuxRowMark */
5732 erm = ExecFindRowMark(estate, rc->rti, false);
5735 }
5736
5737 /* For a MERGE command, initialize its state */
5738 if (mtstate->operation == CMD_MERGE)
5739 ExecInitMerge(mtstate, estate);
5740
5741 EvalPlanQualSetPlan(&mtstate->mt_epqstate, subplan, arowmarks);
5742
5743 /*
5744 * If there are a lot of result relations, use a hash table to speed the
5745 * lookups. If there are not a lot, a simple linear search is faster.
5746 *
5747 * It's not clear where the threshold is, but try 64 for starters. In a
5748 * debugging build, use a small threshold so that we get some test
5749 * coverage of both code paths.
5750 */
5751#ifdef USE_ASSERT_CHECKING
5752#define MT_NRELS_HASH 4
5753#else
5754#define MT_NRELS_HASH 64
5755#endif
5756 if (nrels >= MT_NRELS_HASH)
5757 {
5759
5760 hash_ctl.keysize = sizeof(Oid);
5761 hash_ctl.entrysize = sizeof(MTTargetRelLookup);
5763 mtstate->mt_resultOidHash =
5764 hash_create("ModifyTable target hash",
5765 nrels, &hash_ctl,
5767 for (i = 0; i < nrels; i++)
5768 {
5769 Oid hashkey;
5771 bool found;
5772
5773 resultRelInfo = &mtstate->resultRelInfo[i];
5774 hashkey = RelationGetRelid(resultRelInfo->ri_RelationDesc);
5777 HASH_ENTER, &found);
5778 Assert(!found);
5779 mtlookup->relationIndex = i;
5780 }
5781 }
5782 else
5783 mtstate->mt_resultOidHash = NULL;
5784
5785 /*
5786 * Determine if the FDW supports batch insert and determine the batch size
5787 * (a FDW may support batching, but it may be disabled for the
5788 * server/table).
5789 *
5790 * We only do this for INSERT, so that for UPDATE/DELETE the batch size
5791 * remains set to 0.
5792 */
5793 if (operation == CMD_INSERT)
5794 {
5795 /* insert may only have one relation, inheritance is not expanded */
5796 Assert(total_nrels == 1);
5797 resultRelInfo = mtstate->resultRelInfo;
5798 if (!resultRelInfo->ri_usesFdwDirectModify &&
5799 resultRelInfo->ri_FdwRoutine != NULL &&
5800 resultRelInfo->ri_FdwRoutine->GetForeignModifyBatchSize &&
5801 resultRelInfo->ri_FdwRoutine->ExecForeignBatchInsert)
5802 {
5803 resultRelInfo->ri_BatchSize =
5804 resultRelInfo->ri_FdwRoutine->GetForeignModifyBatchSize(resultRelInfo);
5805 Assert(resultRelInfo->ri_BatchSize >= 1);
5806 }
5807 else
5808 resultRelInfo->ri_BatchSize = 1;
5809 }
5810
5811 /*
5812 * Lastly, if this is not the primary (canSetTag) ModifyTable node, add it
5813 * to estate->es_auxmodifytables so that it will be run to completion by
5814 * ExecPostprocessPlan. (It'd actually work fine to add the primary
5815 * ModifyTable node too, but there's no need.) Note the use of lcons not
5816 * lappend: we need later-initialized ModifyTable nodes to be shut down
5817 * before earlier ones. This ensures that we don't throw away RETURNING
5818 * rows that need to be seen by a later CTE subplan.
5819 */
5820 if (!mtstate->canSetTag)
5821 estate->es_auxmodifytables = lcons(mtstate,
5822 estate->es_auxmodifytables);
5823
5824 return mtstate;
5825}
#define AttributeNumberIsValid(attributeNumber)
Definition attnum.h:34
bool bms_is_member(int x, const Bitmapset *a)
Definition bitmapset.c:645
unsigned int Index
Definition c.h:757
static DataChecksumsWorkerOperation operation
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition dynahash.c:889
HTAB * hash_create(const char *tabname, int64 nelem, const HASHCTL *info, int flags)
Definition dynahash.c:360
#define ereport(elevel,...)
Definition elog.h:152
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:2622
ExecAuxRowMark * ExecBuildAuxRowMark(ExecRowMark *erm, List *targetlist)
Definition execMain.c:2645
void CheckValidResultRel(ResultRelInfo *resultRelInfo, CmdType operation, OnConflictAction onConflictAction, List *mergeActions, ModifyTable *mtnode)
Definition execMain.c:1065
void EvalPlanQualInit(EPQState *epqstate, EState *parentestate, Plan *subplan, List *auxrowmarks, int epqParam, List *resultRelations)
Definition execMain.c:2784
void EvalPlanQualSetPlan(EPQState *epqstate, Plan *subplan, List *auxrowmarks)
Definition execMain.c:2825
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)
TupleTableSlot * ExecInitExtraTupleSlot(EState *estate, TupleDesc tupledesc, const TupleTableSlotOps *tts_ops)
void ExecInitResultTupleSlotTL(PlanState *planstate, const TupleTableSlotOps *tts_ops)
int executor_errposition(EState *estate, int location)
Definition execUtils.c:962
void ExecInitResultRelation(EState *estate, ResultRelInfo *resultRelInfo, Index rti)
Definition execUtils.c:906
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:708
#define EXEC_FLAG_EXPLAIN_ONLY
Definition executor.h:67
#define EXEC_FLAG_MARK
Definition executor.h:71
@ HASH_ENTER
Definition hsearch.h:109
#define HASH_CONTEXT
Definition hsearch.h:97
#define HASH_ELEM
Definition hsearch.h:90
#define HASH_BLOBS
Definition hsearch.h:92
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:161
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:426
@ ONCONFLICT_SELECT
Definition nodes.h:429
@ ONCONFLICT_UPDATE
Definition nodes.h:428
CmdType
Definition nodes.h:271
@ CMD_MERGE
Definition nodes.h:277
@ CMD_INSERT
Definition nodes.h:275
@ CMD_DELETE
Definition nodes.h:276
#define makeNode(_type_)
Definition nodes.h:159
static char * errmsg
@ 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:331
#define list_nth_node(type, list, n)
Definition pg_list.h:359
#define outerPlan(node)
Definition plannodes.h:267
#define InvalidOid
unsigned int Oid
#define RelationGetRelid(relation)
Definition rel.h:516
Bitmapset * es_unpruned_relids
Definition execnodes.h:710
List * es_auxmodifytables
Definition execnodes.h:764
BeginForeignModify_function BeginForeignModify
Definition fdwapi.h:235
ExecForeignBatchInsert_function ExecForeignBatchInsert
Definition fdwapi.h:237
GetForeignModifyBatchSize_function GetForeignModifyBatchSize
Definition fdwapi.h:238
ParseLoc targetLocation
Definition primnodes.h:2447
Size keysize
Definition hsearch.h:69
Definition pg_list.h:54
List * mt_mergeJoinConditions
Definition execnodes.h:1512
TupleTableSlot * mt_merge_pending_not_matched
Definition execnodes.h:1497
double mt_merge_deleted
Definition execnodes.h:1502
List * mt_updateColnosLists
Definition execnodes.h:1510
double mt_merge_inserted
Definition execnodes.h:1500
List * mt_fdwPrivLists
Definition execnodes.h:1513
double mt_merge_updated
Definition execnodes.h:1501
List * mt_mergeActionLists
Definition execnodes.h:1511
HTAB * mt_resultOidHash
Definition execnodes.h:1469
ResultRelInfo * rootResultRelInfo
Definition execnodes.h:1455
List * updateColnosLists
Definition plannodes.h:350
List * arbiterIndexes
Definition plannodes.h:370
List * onConflictCols
Definition plannodes.h:376
List * mergeJoinConditions
Definition plannodes.h:388
CmdType operation
Definition plannodes.h:340
Node * forPortionOf
Definition plannodes.h:380
List * resultRelations
Definition plannodes.h:348
Bitmapset * fdwDirectModifyPlans
Definition plannodes.h:362
List * onConflictSet
Definition plannodes.h:374
List * mergeActionLists
Definition plannodes.h:386
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:450
Plan * plan
Definition execnodes.h:1202
ExprContext * ps_ExprContext
Definition execnodes.h:1243
TupleTableSlot * ps_ResultTupleSlot
Definition execnodes.h:1242
ExecProcNodeMtd ExecProcNode
Definition execnodes.h:1208
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:617
List * ri_onConflictArbiterIndexes
Definition execnodes.h:614
struct ResultRelInfo * ri_RootResultRelInfo
Definition execnodes.h:655
List * ri_WithCheckOptions
Definition execnodes.h:583
ForPortionOfState * ri_forPortionOf
Definition execnodes.h:626
List * ri_WithCheckOptionExprs
Definition execnodes.h:586
ProjectionInfo * ri_projectReturning
Definition execnodes.h:611
List * ri_returningList
Definition execnodes.h:608
AttrNumber ri_RowIdAttNo
Definition execnodes.h:529
AttrNumber varattno
Definition primnodes.h:275

References ModifyTable::arbiterIndexes, Assert, AttributeNumberIsValid, FdwRoutine::BeginForeignModify, bms_add_member(), bms_is_member(), ModifyTableState::canSetTag, ModifyTable::canSetTag, CheckValidResultRel(), CMD_DELETE, CMD_INSERT, CMD_MERGE, CMD_UPDATE, CurrentMemoryContext, elog, ModifyTable::epqParam, ereport, errmsg, ERROR, EState::es_auxmodifytables, EState::es_query_cxt, 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(), ExecEvalExpr(), ExecFindJunkAttributeInTlist(), ExecFindRowMark(), FdwRoutine::ExecForeignBatchInsert, ExecInitExtraTupleSlot(), ExecInitMerge(), ExecInitNode(), ExecInitQual(), ExecInitResultRelation(), ExecInitResultTupleSlotTL(), ExecInitResultTypeTL(), ExecModifyTable(), ExecPrepareExpr(), PlanState::ExecProcNode, ExecSetupPartitionTupleRouting(), ExecSetupTransitionCaptureState(), executor_errposition(), fb(), ModifyTable::fdwDirectModifyPlans, ModifyTable::fdwPrivLists, ModifyTableState::fireBSTriggers, ModifyTable::forPortionOf, 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, MemoryContextSwitchTo(), ModifyTable::mergeActionLists, ModifyTable::mergeJoinConditions, ModifyTableState::mt_done, ModifyTableState::mt_epqstate, ModifyTableState::mt_fdwPrivLists, 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_root_tuple_slot, ModifyTableState::mt_updateColnosLists, NIL, OnConflictActionState::oc_LockStrength, ONCONFLICT_NONE, ONCONFLICT_SELECT, ONCONFLICT_UPDATE, ModifyTable::onConflictAction, ModifyTable::onConflictCols, ModifyTable::onConflictLockStrength, ModifyTable::onConflictSet, ModifyTable::onConflictWhere, operation, ModifyTableState::operation, ModifyTable::operation, outerPlan, outerPlanState, palloc_array, PlanState::plan, ModifyTableState::ps, PlanState::ps_ExprContext, PlanState::ps_ResultTupleSlot, ForPortionOfExpr::range_name, ForPortionOfExpr::rangeType, ForPortionOfExpr::rangeVar, RelationData::rd_att, RelationData::rd_rel, RelationGetRelid, ModifyTable::resultRelations, ModifyTableState::resultRelInfo, ModifyTable::returningLists, ResultRelInfo::ri_BatchSize, ResultRelInfo::ri_FdwRoutine, ResultRelInfo::ri_forPortionOf, 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, ForPortionOfExpr::targetLocation, ForPortionOfExpr::targetRange, TTSOpsVirtual, ModifyTable::updateColnosLists, Var::varattno, and ModifyTable::withCheckOptionLists.

Referenced by ExecInitNode().

◆ ExecReScanModifyTable()

void ExecReScanModifyTable ( ModifyTableState node)
extern

Definition at line 5890 of file nodeModifyTable.c.

5891{
5892 /*
5893 * Currently, we don't need to support rescan on ModifyTable nodes. The
5894 * semantics of that would be a bit debatable anyway.
5895 */
5896 elog(ERROR, "ExecReScanModifyTable is not implemented");
5897}

References elog, and ERROR.

Referenced by ExecReScan().