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

Go to the source code of this file.

Functions

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

Function Documentation

◆ ExecComputeStoredGenerated()

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

Definition at line 257 of file nodeModifyTable.c.

References Assert, bms_is_member(), build_column_default(), CMD_UPDATE, TupleDescData::constr, datumCopy(), ExprContext::ecxt_scantuple, elog, ERROR, EState::es_query_cxt, ExecClearTuple(), ExecEvalExpr(), ExecGetExtraUpdatedCols(), ExecMaterializeSlot(), ExecPrepareExpr(), ExecStoreVirtualTuple(), FirstLowInvalidHeapAttributeNumber, GetPerTupleExprContext, GetPerTupleMemoryContext, TupleConstr::has_generated_stored, i, MemoryContextSwitchTo(), TupleDescData::natts, palloc(), RelationGetDescr, RelationGetRelationName, ResultRelInfo::ri_GeneratedExprs, ResultRelInfo::ri_NumGeneratedNeeded, ResultRelInfo::ri_RelationDesc, slot_getallattrs(), TriggerDesc::trig_update_before_row, RelationData::trigdesc, TupleTableSlot::tts_isnull, TupleTableSlot::tts_values, TupleDescAttr, val, and values.

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

260 {
261  Relation rel = resultRelInfo->ri_RelationDesc;
262  TupleDesc tupdesc = RelationGetDescr(rel);
263  int natts = tupdesc->natts;
264  MemoryContext oldContext;
265  Datum *values;
266  bool *nulls;
267 
268  Assert(tupdesc->constr && tupdesc->constr->has_generated_stored);
269 
270  /*
271  * If first time through for this result relation, build expression
272  * nodetrees for rel's stored generation expressions. Keep them in the
273  * per-query memory context so they'll survive throughout the query.
274  */
275  if (resultRelInfo->ri_GeneratedExprs == NULL)
276  {
277  oldContext = MemoryContextSwitchTo(estate->es_query_cxt);
278 
279  resultRelInfo->ri_GeneratedExprs =
280  (ExprState **) palloc(natts * sizeof(ExprState *));
281  resultRelInfo->ri_NumGeneratedNeeded = 0;
282 
283  for (int i = 0; i < natts; i++)
284  {
285  if (TupleDescAttr(tupdesc, i)->attgenerated == ATTRIBUTE_GENERATED_STORED)
286  {
287  Expr *expr;
288 
289  /*
290  * If it's an update and the current column was not marked as
291  * being updated, then we can skip the computation. But if
292  * there is a BEFORE ROW UPDATE trigger, we cannot skip
293  * because the trigger might affect additional columns.
294  */
295  if (cmdtype == CMD_UPDATE &&
296  !(rel->trigdesc && rel->trigdesc->trig_update_before_row) &&
298  ExecGetExtraUpdatedCols(resultRelInfo, estate)))
299  {
300  resultRelInfo->ri_GeneratedExprs[i] = NULL;
301  continue;
302  }
303 
304  expr = (Expr *) build_column_default(rel, i + 1);
305  if (expr == NULL)
306  elog(ERROR, "no generation expression found for column number %d of table \"%s\"",
307  i + 1, RelationGetRelationName(rel));
308 
309  resultRelInfo->ri_GeneratedExprs[i] = ExecPrepareExpr(expr, estate);
310  resultRelInfo->ri_NumGeneratedNeeded++;
311  }
312  }
313 
314  MemoryContextSwitchTo(oldContext);
315  }
316 
317  /*
318  * If no generated columns have been affected by this change, then skip
319  * the rest.
320  */
321  if (resultRelInfo->ri_NumGeneratedNeeded == 0)
322  return;
323 
324  oldContext = MemoryContextSwitchTo(GetPerTupleMemoryContext(estate));
325 
326  values = palloc(sizeof(*values) * natts);
327  nulls = palloc(sizeof(*nulls) * natts);
328 
329  slot_getallattrs(slot);
330  memcpy(nulls, slot->tts_isnull, sizeof(*nulls) * natts);
331 
332  for (int i = 0; i < natts; i++)
333  {
334  Form_pg_attribute attr = TupleDescAttr(tupdesc, i);
335 
336  if (attr->attgenerated == ATTRIBUTE_GENERATED_STORED &&
337  resultRelInfo->ri_GeneratedExprs[i])
338  {
339  ExprContext *econtext;
340  Datum val;
341  bool isnull;
342 
343  econtext = GetPerTupleExprContext(estate);
344  econtext->ecxt_scantuple = slot;
345 
346  val = ExecEvalExpr(resultRelInfo->ri_GeneratedExprs[i], econtext, &isnull);
347 
348  /*
349  * We must make a copy of val as we have no guarantees about where
350  * memory for a pass-by-reference Datum is located.
351  */
352  if (!isnull)
353  val = datumCopy(val, attr->attbyval, attr->attlen);
354 
355  values[i] = val;
356  nulls[i] = isnull;
357  }
358  else
359  {
360  if (!nulls[i])
361  values[i] = datumCopy(slot->tts_values[i], attr->attbyval, attr->attlen);
362  }
363  }
364 
365  ExecClearTuple(slot);
366  memcpy(slot->tts_values, values, sizeof(*values) * natts);
367  memcpy(slot->tts_isnull, nulls, sizeof(*nulls) * natts);
368  ExecStoreVirtualTuple(slot);
369  ExecMaterializeSlot(slot);
370 
371  MemoryContextSwitchTo(oldContext);
372 }
Relation ri_RelationDesc
Definition: execnodes.h:411
Bitmapset * ExecGetExtraUpdatedCols(ResultRelInfo *relinfo, EState *estate)
Definition: execUtils.c:1321
static TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition: tuptable.h:425
#define RelationGetDescr(relation)
Definition: rel.h:495
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
Datum * tts_values
Definition: tuptable.h:126
#define FirstLowInvalidHeapAttributeNumber
Definition: sysattr.h:27
ExprState * ExecPrepareExpr(Expr *node, EState *estate)
Definition: execExpr.c:746
#define GetPerTupleExprContext(estate)
Definition: executor.h:533
bool has_generated_stored
Definition: tupdesc.h:45
MemoryContext es_query_cxt
Definition: execnodes.h:599
#define ERROR
Definition: elog.h:46
TriggerDesc * trigdesc
Definition: rel.h:115
static void slot_getallattrs(TupleTableSlot *slot)
Definition: tuptable.h:354
bool * tts_isnull
Definition: tuptable.h:128
static Datum ExecEvalExpr(ExprState *state, ExprContext *econtext, bool *isNull)
Definition: executor.h:316
TupleConstr * constr
Definition: tupdesc.h:85
ExprState ** ri_GeneratedExprs
Definition: execnodes.h:479
bool trig_update_before_row
Definition: reltrigger.h:61
#define RelationGetRelationName(relation)
Definition: rel.h:503
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:203
Datum datumCopy(Datum value, bool typByVal, int typLen)
Definition: datum.c:131
int ri_NumGeneratedNeeded
Definition: execnodes.h:482
Node * build_column_default(Relation rel, int attrno)
uintptr_t Datum
Definition: postgres.h:411
static void ExecMaterializeSlot(TupleTableSlot *slot)
Definition: tuptable.h:443
#define Assert(condition)
Definition: c.h:804
TupleTableSlot * ecxt_scantuple
Definition: execnodes.h:226
#define GetPerTupleMemoryContext(estate)
Definition: executor.h:538
static Datum values[MAXATTR]
Definition: bootstrap.c:166
void * palloc(Size size)
Definition: mcxt.c:1062
#define elog(elevel,...)
Definition: elog.h:232
int i
bool bms_is_member(int x, const Bitmapset *a)
Definition: bitmapset.c:427
long val
Definition: informix.c:664
TupleTableSlot * ExecStoreVirtualTuple(TupleTableSlot *slot)
Definition: execTuples.c:1552

◆ ExecEndModifyTable()

void ExecEndModifyTable ( ModifyTableState node)

Definition at line 3144 of file nodeModifyTable.c.

References FdwRoutine::EndForeignModify, EvalPlanQualEnd(), ExecCleanupTupleRouting(), ExecClearTuple(), ExecDropSingleTupleTableSlot(), ExecEndNode(), ExecFreeExprContext(), i, ModifyTableState::mt_epqstate, ModifyTableState::mt_nrels, ModifyTableState::mt_partition_tuple_routing, ModifyTableState::mt_root_tuple_slot, outerPlanState, ModifyTableState::ps, PlanState::ps_ResultTupleSlot, ModifyTableState::resultRelInfo, ResultRelInfo::ri_FdwRoutine, ResultRelInfo::ri_usesFdwDirectModify, and PlanState::state.

Referenced by ExecEndNode().

3145 {
3146  int i;
3147 
3148  /*
3149  * Allow any FDWs to shut down
3150  */
3151  for (i = 0; i < node->mt_nrels; i++)
3152  {
3153  ResultRelInfo *resultRelInfo = node->resultRelInfo + i;
3154 
3155  if (!resultRelInfo->ri_usesFdwDirectModify &&
3156  resultRelInfo->ri_FdwRoutine != NULL &&
3157  resultRelInfo->ri_FdwRoutine->EndForeignModify != NULL)
3158  resultRelInfo->ri_FdwRoutine->EndForeignModify(node->ps.state,
3159  resultRelInfo);
3160  }
3161 
3162  /*
3163  * Close all the partitioned tables, leaf partitions, and their indices
3164  * and release the slot used for tuple routing, if set.
3165  */
3166  if (node->mt_partition_tuple_routing)
3167  {
3169 
3170  if (node->mt_root_tuple_slot)
3172  }
3173 
3174  /*
3175  * Free the exprcontext
3176  */
3177  ExecFreeExprContext(&node->ps);
3178 
3179  /*
3180  * clean out the tuple table
3181  */
3182  if (node->ps.ps_ResultTupleSlot)
3184 
3185  /*
3186  * Terminate EPQ execution if active
3187  */
3188  EvalPlanQualEnd(&node->mt_epqstate);
3189 
3190  /*
3191  * shut down subplan
3192  */
3193  ExecEndNode(outerPlanState(node));
3194 }
static TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition: tuptable.h:425
struct PartitionTupleRouting * mt_partition_tuple_routing
Definition: execnodes.h:1222
void ExecEndNode(PlanState *node)
Definition: execProcnode.c:556
ResultRelInfo * resultRelInfo
Definition: execnodes.h:1191
EState * state
Definition: execnodes.h:967
void ExecFreeExprContext(PlanState *planstate)
Definition: execUtils.c:650
void EvalPlanQualEnd(EPQState *epqstate)
Definition: execMain.c:2834
TupleTableSlot * ps_ResultTupleSlot
Definition: execnodes.h:1003
PlanState ps
Definition: execnodes.h:1186
void ExecCleanupTupleRouting(ModifyTableState *mtstate, PartitionTupleRouting *proute)
bool ri_usesFdwDirectModify
Definition: execnodes.h:461
#define outerPlanState(node)
Definition: execnodes.h:1061
void ExecDropSingleTupleTableSlot(TupleTableSlot *slot)
Definition: execTuples.c:1254
EPQState mt_epqstate
Definition: execnodes.h:1201
struct FdwRoutine * ri_FdwRoutine
Definition: execnodes.h:455
EndForeignModify_function EndForeignModify
Definition: fdwapi.h:237
TupleTableSlot * mt_root_tuple_slot
Definition: execnodes.h:1219
int i

◆ ExecInitModifyTable()

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

Definition at line 2683 of file nodeModifyTable.c.

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

Referenced by ExecInitNode().

2684 {
2685  ModifyTableState *mtstate;
2686  Plan *subplan = outerPlan(node);
2687  CmdType operation = node->operation;
2688  int nrels = list_length(node->resultRelations);
2689  ResultRelInfo *resultRelInfo;
2690  List *arowmarks;
2691  ListCell *l;
2692  int i;
2693  Relation rel;
2694 
2695  /* check for unsupported flags */
2696  Assert(!(eflags & (EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK)));
2697 
2698  /*
2699  * create state structure
2700  */
2701  mtstate = makeNode(ModifyTableState);
2702  mtstate->ps.plan = (Plan *) node;
2703  mtstate->ps.state = estate;
2704  mtstate->ps.ExecProcNode = ExecModifyTable;
2705 
2706  mtstate->operation = operation;
2707  mtstate->canSetTag = node->canSetTag;
2708  mtstate->mt_done = false;
2709 
2710  mtstate->mt_nrels = nrels;
2711  mtstate->resultRelInfo = (ResultRelInfo *)
2712  palloc(nrels * sizeof(ResultRelInfo));
2713 
2714  /*----------
2715  * Resolve the target relation. This is the same as:
2716  *
2717  * - the relation for which we will fire FOR STATEMENT triggers,
2718  * - the relation into whose tuple format all captured transition tuples
2719  * must be converted, and
2720  * - the root partitioned table used for tuple routing.
2721  *
2722  * If it's a partitioned table, the root partition doesn't appear
2723  * elsewhere in the plan and its RT index is given explicitly in
2724  * node->rootRelation. Otherwise (i.e. table inheritance) the target
2725  * relation is the first relation in the node->resultRelations list.
2726  *----------
2727  */
2728  if (node->rootRelation > 0)
2729  {
2731  ExecInitResultRelation(estate, mtstate->rootResultRelInfo,
2732  node->rootRelation);
2733  }
2734  else
2735  {
2736  mtstate->rootResultRelInfo = mtstate->resultRelInfo;
2737  ExecInitResultRelation(estate, mtstate->resultRelInfo,
2738  linitial_int(node->resultRelations));
2739  }
2740 
2741  /* set up epqstate with dummy subplan data for the moment */
2742  EvalPlanQualInit(&mtstate->mt_epqstate, estate, NULL, NIL, node->epqParam);
2743  mtstate->fireBSTriggers = true;
2744 
2745  /*
2746  * Build state for collecting transition tuples. This requires having a
2747  * valid trigger query context, so skip it in explain-only mode.
2748  */
2749  if (!(eflags & EXEC_FLAG_EXPLAIN_ONLY))
2750  ExecSetupTransitionCaptureState(mtstate, estate);
2751 
2752  /*
2753  * Open all the result relations and initialize the ResultRelInfo structs.
2754  * (But root relation was initialized above, if it's part of the array.)
2755  * We must do this before initializing the subplan, because direct-modify
2756  * FDWs expect their ResultRelInfos to be available.
2757  */
2758  resultRelInfo = mtstate->resultRelInfo;
2759  i = 0;
2760  foreach(l, node->resultRelations)
2761  {
2762  Index resultRelation = lfirst_int(l);
2763 
2764  if (resultRelInfo != mtstate->rootResultRelInfo)
2765  {
2766  ExecInitResultRelation(estate, resultRelInfo, resultRelation);
2767 
2768  /*
2769  * For child result relations, store the root result relation
2770  * pointer. We do so for the convenience of places that want to
2771  * look at the query's original target relation but don't have the
2772  * mtstate handy.
2773  */
2774  resultRelInfo->ri_RootResultRelInfo = mtstate->rootResultRelInfo;
2775  }
2776 
2777  /* Initialize the usesFdwDirectModify flag */
2778  resultRelInfo->ri_usesFdwDirectModify = bms_is_member(i,
2779  node->fdwDirectModifyPlans);
2780 
2781  /*
2782  * Verify result relation is a valid target for the current operation
2783  */
2784  CheckValidResultRel(resultRelInfo, operation);
2785 
2786  resultRelInfo++;
2787  i++;
2788  }
2789 
2790  /*
2791  * Now we may initialize the subplan.
2792  */
2793  outerPlanState(mtstate) = ExecInitNode(subplan, estate, eflags);
2794 
2795  /*
2796  * Do additional per-result-relation initialization.
2797  */
2798  for (i = 0; i < nrels; i++)
2799  {
2800  resultRelInfo = &mtstate->resultRelInfo[i];
2801 
2802  /* Let FDWs init themselves for foreign-table result rels */
2803  if (!resultRelInfo->ri_usesFdwDirectModify &&
2804  resultRelInfo->ri_FdwRoutine != NULL &&
2805  resultRelInfo->ri_FdwRoutine->BeginForeignModify != NULL)
2806  {
2807  List *fdw_private = (List *) list_nth(node->fdwPrivLists, i);
2808 
2809  resultRelInfo->ri_FdwRoutine->BeginForeignModify(mtstate,
2810  resultRelInfo,
2811  fdw_private,
2812  i,
2813  eflags);
2814  }
2815 
2816  /*
2817  * For UPDATE/DELETE, find the appropriate junk attr now, either a
2818  * 'ctid' or 'wholerow' attribute depending on relkind. For foreign
2819  * tables, the FDW might have created additional junk attr(s), but
2820  * those are no concern of ours.
2821  */
2822  if (operation == CMD_UPDATE || operation == CMD_DELETE)
2823  {
2824  char relkind;
2825 
2826  relkind = resultRelInfo->ri_RelationDesc->rd_rel->relkind;
2827  if (relkind == RELKIND_RELATION ||
2828  relkind == RELKIND_MATVIEW ||
2829  relkind == RELKIND_PARTITIONED_TABLE)
2830  {
2831  resultRelInfo->ri_RowIdAttNo =
2832  ExecFindJunkAttributeInTlist(subplan->targetlist, "ctid");
2833  if (!AttributeNumberIsValid(resultRelInfo->ri_RowIdAttNo))
2834  elog(ERROR, "could not find junk ctid column");
2835  }
2836  else if (relkind == RELKIND_FOREIGN_TABLE)
2837  {
2838  /*
2839  * When there is a row-level trigger, there should be a
2840  * wholerow attribute. We also require it to be present in
2841  * UPDATE, so we can get the values of unchanged columns.
2842  */
2843  resultRelInfo->ri_RowIdAttNo =
2845  "wholerow");
2846  if (mtstate->operation == CMD_UPDATE &&
2847  !AttributeNumberIsValid(resultRelInfo->ri_RowIdAttNo))
2848  elog(ERROR, "could not find junk wholerow column");
2849  }
2850  else
2851  {
2852  /* Other valid target relkinds must provide wholerow */
2853  resultRelInfo->ri_RowIdAttNo =
2855  "wholerow");
2856  if (!AttributeNumberIsValid(resultRelInfo->ri_RowIdAttNo))
2857  elog(ERROR, "could not find junk wholerow column");
2858  }
2859  }
2860  }
2861 
2862  /*
2863  * If this is an inherited update/delete, there will be a junk attribute
2864  * named "tableoid" present in the subplan's targetlist. It will be used
2865  * to identify the result relation for a given tuple to be
2866  * updated/deleted.
2867  */
2868  mtstate->mt_resultOidAttno =
2869  ExecFindJunkAttributeInTlist(subplan->targetlist, "tableoid");
2870  Assert(AttributeNumberIsValid(mtstate->mt_resultOidAttno) || nrels == 1);
2871  mtstate->mt_lastResultOid = InvalidOid; /* force lookup at first tuple */
2872  mtstate->mt_lastResultIndex = 0; /* must be zero if no such attr */
2873 
2874  /* Get the root target relation */
2875  rel = mtstate->rootResultRelInfo->ri_RelationDesc;
2876 
2877  /*
2878  * Build state for tuple routing if it's a partitioned INSERT. An UPDATE
2879  * might need this too, but only if it actually moves tuples between
2880  * partitions; in that case setup is done by ExecCrossPartitionUpdate.
2881  */
2882  if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE &&
2883  operation == CMD_INSERT)
2884  mtstate->mt_partition_tuple_routing =
2885  ExecSetupPartitionTupleRouting(estate, rel);
2886 
2887  /*
2888  * Initialize any WITH CHECK OPTION constraints if needed.
2889  */
2890  resultRelInfo = mtstate->resultRelInfo;
2891  foreach(l, node->withCheckOptionLists)
2892  {
2893  List *wcoList = (List *) lfirst(l);
2894  List *wcoExprs = NIL;
2895  ListCell *ll;
2896 
2897  foreach(ll, wcoList)
2898  {
2899  WithCheckOption *wco = (WithCheckOption *) lfirst(ll);
2900  ExprState *wcoExpr = ExecInitQual((List *) wco->qual,
2901  &mtstate->ps);
2902 
2903  wcoExprs = lappend(wcoExprs, wcoExpr);
2904  }
2905 
2906  resultRelInfo->ri_WithCheckOptions = wcoList;
2907  resultRelInfo->ri_WithCheckOptionExprs = wcoExprs;
2908  resultRelInfo++;
2909  }
2910 
2911  /*
2912  * Initialize RETURNING projections if needed.
2913  */
2914  if (node->returningLists)
2915  {
2916  TupleTableSlot *slot;
2917  ExprContext *econtext;
2918 
2919  /*
2920  * Initialize result tuple slot and assign its rowtype using the first
2921  * RETURNING list. We assume the rest will look the same.
2922  */
2923  mtstate->ps.plan->targetlist = (List *) linitial(node->returningLists);
2924 
2925  /* Set up a slot for the output of the RETURNING projection(s) */
2927  slot = mtstate->ps.ps_ResultTupleSlot;
2928 
2929  /* Need an econtext too */
2930  if (mtstate->ps.ps_ExprContext == NULL)
2931  ExecAssignExprContext(estate, &mtstate->ps);
2932  econtext = mtstate->ps.ps_ExprContext;
2933 
2934  /*
2935  * Build a projection for each result rel.
2936  */
2937  resultRelInfo = mtstate->resultRelInfo;
2938  foreach(l, node->returningLists)
2939  {
2940  List *rlist = (List *) lfirst(l);
2941 
2942  resultRelInfo->ri_returningList = rlist;
2943  resultRelInfo->ri_projectReturning =
2944  ExecBuildProjectionInfo(rlist, econtext, slot, &mtstate->ps,
2945  resultRelInfo->ri_RelationDesc->rd_att);
2946  resultRelInfo++;
2947  }
2948  }
2949  else
2950  {
2951  /*
2952  * We still must construct a dummy result tuple type, because InitPlan
2953  * expects one (maybe should change that?).
2954  */
2955  mtstate->ps.plan->targetlist = NIL;
2956  ExecInitResultTypeTL(&mtstate->ps);
2957 
2958  mtstate->ps.ps_ExprContext = NULL;
2959  }
2960 
2961  /* Set the list of arbiter indexes if needed for ON CONFLICT */
2962  resultRelInfo = mtstate->resultRelInfo;
2963  if (node->onConflictAction != ONCONFLICT_NONE)
2964  {
2965  /* insert may only have one relation, inheritance is not expanded */
2966  Assert(nrels == 1);
2967  resultRelInfo->ri_onConflictArbiterIndexes = node->arbiterIndexes;
2968  }
2969 
2970  /*
2971  * If needed, Initialize target list, projection and qual for ON CONFLICT
2972  * DO UPDATE.
2973  */
2974  if (node->onConflictAction == ONCONFLICT_UPDATE)
2975  {
2977  ExprContext *econtext;
2978  TupleDesc relationDesc;
2979 
2980  /* already exists if created by RETURNING processing above */
2981  if (mtstate->ps.ps_ExprContext == NULL)
2982  ExecAssignExprContext(estate, &mtstate->ps);
2983 
2984  econtext = mtstate->ps.ps_ExprContext;
2985  relationDesc = resultRelInfo->ri_RelationDesc->rd_att;
2986 
2987  /* create state for DO UPDATE SET operation */
2988  resultRelInfo->ri_onConflict = onconfl;
2989 
2990  /* initialize slot for the existing tuple */
2991  onconfl->oc_Existing =
2992  table_slot_create(resultRelInfo->ri_RelationDesc,
2993  &mtstate->ps.state->es_tupleTable);
2994 
2995  /*
2996  * Create the tuple slot for the UPDATE SET projection. We want a slot
2997  * of the table's type here, because the slot will be used to insert
2998  * into the table, and for RETURNING processing - which may access
2999  * system attributes.
3000  */
3001  onconfl->oc_ProjSlot =
3002  table_slot_create(resultRelInfo->ri_RelationDesc,
3003  &mtstate->ps.state->es_tupleTable);
3004 
3005  /* build UPDATE SET projection state */
3006  onconfl->oc_ProjInfo =
3008  true,
3009  node->onConflictCols,
3010  relationDesc,
3011  econtext,
3012  onconfl->oc_ProjSlot,
3013  &mtstate->ps);
3014 
3015  /* initialize state to evaluate the WHERE clause, if any */
3016  if (node->onConflictWhere)
3017  {
3018  ExprState *qualexpr;
3019 
3020  qualexpr = ExecInitQual((List *) node->onConflictWhere,
3021  &mtstate->ps);
3022  onconfl->oc_WhereClause = qualexpr;
3023  }
3024  }
3025 
3026  /*
3027  * If we have any secondary relations in an UPDATE or DELETE, they need to
3028  * be treated like non-locked relations in SELECT FOR UPDATE, ie, the
3029  * EvalPlanQual mechanism needs to be told about them. Locate the
3030  * relevant ExecRowMarks.
3031  */
3032  arowmarks = NIL;
3033  foreach(l, node->rowMarks)
3034  {
3036  ExecRowMark *erm;
3037  ExecAuxRowMark *aerm;
3038 
3039  /* ignore "parent" rowmarks; they are irrelevant at runtime */
3040  if (rc->isParent)
3041  continue;
3042 
3043  /* Find ExecRowMark and build ExecAuxRowMark */
3044  erm = ExecFindRowMark(estate, rc->rti, false);
3045  aerm = ExecBuildAuxRowMark(erm, subplan->targetlist);
3046  arowmarks = lappend(arowmarks, aerm);
3047  }
3048 
3049  EvalPlanQualSetPlan(&mtstate->mt_epqstate, subplan, arowmarks);
3050 
3051  /*
3052  * If there are a lot of result relations, use a hash table to speed the
3053  * lookups. If there are not a lot, a simple linear search is faster.
3054  *
3055  * It's not clear where the threshold is, but try 64 for starters. In a
3056  * debugging build, use a small threshold so that we get some test
3057  * coverage of both code paths.
3058  */
3059 #ifdef USE_ASSERT_CHECKING
3060 #define MT_NRELS_HASH 4
3061 #else
3062 #define MT_NRELS_HASH 64
3063 #endif
3064  if (nrels >= MT_NRELS_HASH)
3065  {
3066  HASHCTL hash_ctl;
3067 
3068  hash_ctl.keysize = sizeof(Oid);
3069  hash_ctl.entrysize = sizeof(MTTargetRelLookup);
3070  hash_ctl.hcxt = CurrentMemoryContext;
3071  mtstate->mt_resultOidHash =
3072  hash_create("ModifyTable target hash",
3073  nrels, &hash_ctl,
3075  for (i = 0; i < nrels; i++)
3076  {
3077  Oid hashkey;
3078  MTTargetRelLookup *mtlookup;
3079  bool found;
3080 
3081  resultRelInfo = &mtstate->resultRelInfo[i];
3082  hashkey = RelationGetRelid(resultRelInfo->ri_RelationDesc);
3083  mtlookup = (MTTargetRelLookup *)
3084  hash_search(mtstate->mt_resultOidHash, &hashkey,
3085  HASH_ENTER, &found);
3086  Assert(!found);
3087  mtlookup->relationIndex = i;
3088  }
3089  }
3090  else
3091  mtstate->mt_resultOidHash = NULL;
3092 
3093  /*
3094  * Determine if the FDW supports batch insert and determine the batch
3095  * size (a FDW may support batching, but it may be disabled for the
3096  * server/table).
3097  *
3098  * We only do this for INSERT, so that for UPDATE/DELETE the batch
3099  * size remains set to 0.
3100  */
3101  if (operation == CMD_INSERT)
3102  {
3103  /* insert may only have one relation, inheritance is not expanded */
3104  Assert(nrels == 1);
3105  resultRelInfo = mtstate->resultRelInfo;
3106  if (!resultRelInfo->ri_usesFdwDirectModify &&
3107  resultRelInfo->ri_FdwRoutine != NULL &&
3108  resultRelInfo->ri_FdwRoutine->GetForeignModifyBatchSize &&
3109  resultRelInfo->ri_FdwRoutine->ExecForeignBatchInsert)
3110  {
3111  resultRelInfo->ri_BatchSize =
3112  resultRelInfo->ri_FdwRoutine->GetForeignModifyBatchSize(resultRelInfo);
3113  Assert(resultRelInfo->ri_BatchSize >= 1);
3114  }
3115  else
3116  resultRelInfo->ri_BatchSize = 1;
3117  }
3118 
3119  /*
3120  * Lastly, if this is not the primary (canSetTag) ModifyTable node, add it
3121  * to estate->es_auxmodifytables so that it will be run to completion by
3122  * ExecPostprocessPlan. (It'd actually work fine to add the primary
3123  * ModifyTable node too, but there's no need.) Note the use of lcons not
3124  * lappend: we need later-initialized ModifyTable nodes to be shut down
3125  * before earlier ones. This ensures that we don't throw away RETURNING
3126  * rows that need to be seen by a later CTE subplan.
3127  */
3128  if (!mtstate->canSetTag)
3129  estate->es_auxmodifytables = lcons(mtstate,
3130  estate->es_auxmodifytables);
3131 
3132  return mtstate;
3133 }
TupleTableSlot * table_slot_create(Relation relation, List **reglist)
Definition: tableam.c:91
#define NIL
Definition: pg_list.h:65
List * arbiterIndexes
Definition: plannodes.h:234
Relation ri_RelationDesc
Definition: execnodes.h:411
Bitmapset * fdwDirectModifyPlans
Definition: plannodes.h:230
#define HASH_CONTEXT
Definition: hsearch.h:102
#define HASH_ELEM
Definition: hsearch.h:95
MemoryContext hcxt
Definition: hsearch.h:86
struct PartitionTupleRouting * mt_partition_tuple_routing
Definition: execnodes.h:1222
AttrNumber ExecFindJunkAttributeInTlist(List *targetlist, const char *attrName)
Definition: execJunk.c:222
List * withCheckOptionLists
Definition: plannodes.h:227
void ExecInitResultRelation(EState *estate, ResultRelInfo *resultRelInfo, Index rti)
Definition: execUtils.c:834
ResultRelInfo * resultRelInfo
Definition: execnodes.h:1191
ExprContext * ps_ExprContext
Definition: execnodes.h:1004
const TupleTableSlotOps TTSOpsVirtual
Definition: execTuples.c:83
Size entrysize
Definition: hsearch.h:76
bool canSetTag
Definition: plannodes.h:221
CmdType operation
Definition: execnodes.h:1187
ResultRelInfo * rootResultRelInfo
Definition: execnodes.h:1199
void EvalPlanQualSetPlan(EPQState *epqstate, Plan *subplan, List *auxrowmarks)
Definition: execMain.c:2452
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:954
EState * state
Definition: execnodes.h:967
Form_pg_class rd_rel
Definition: rel.h:109
unsigned int Oid
Definition: postgres_ext.h:31
ExprState * ExecInitQual(List *qual, PlanState *parent)
Definition: execExpr.c:209
List * onConflictSet
Definition: plannodes.h:235
Index rootRelation
Definition: plannodes.h:223
List * resultRelations
Definition: plannodes.h:225
List * ri_WithCheckOptionExprs
Definition: execnodes.h:473
#define linitial_int(l)
Definition: pg_list.h:175
TupleTableSlot * oc_Existing
Definition: execnodes.h:380
TupleTableSlot * ps_ResultTupleSlot
Definition: execnodes.h:1003
List * rowMarks
Definition: plannodes.h:231
ProjectionInfo * ExecBuildUpdateProjection(List *targetList, bool evalTargetList, List *targetColnos, TupleDesc relDesc, ExprContext *econtext, TupleTableSlot *slot, PlanState *parent)
Definition: execExpr.c:513
#define linitial(l)
Definition: pg_list.h:174
#define ERROR
Definition: elog.h:46
PlanState ps
Definition: execnodes.h:1186
ProjectionInfo * oc_ProjInfo
Definition: execnodes.h:382
#define lfirst_int(lc)
Definition: pg_list.h:170
static void * list_nth(const List *list, int n)
Definition: pg_list.h:278
bool ri_usesFdwDirectModify
Definition: execnodes.h:461
static void ExecSetupTransitionCaptureState(ModifyTableState *mtstate, EState *estate)
struct ResultRelInfo * ri_RootResultRelInfo
Definition: execnodes.h:511
void CheckValidResultRel(ResultRelInfo *resultRelInfo, CmdType operation)
Definition: execMain.c:992
#define EXEC_FLAG_BACKWARD
Definition: executor.h:58
#define lfirst_node(type, lc)
Definition: pg_list.h:172
#define outerPlanState(node)
Definition: execnodes.h:1061
void ExecInitResultTypeTL(PlanState *planstate)
Definition: execTuples.c:1755
List * fdwPrivLists
Definition: plannodes.h:229
EPQState mt_epqstate
Definition: execnodes.h:1201
HTAB * hash_create(const char *tabname, long nelem, const HASHCTL *info, int flags)
Definition: dynahash.c:349
ProjectionInfo * ri_projectReturning
Definition: execnodes.h:488
struct FdwRoutine * ri_FdwRoutine
Definition: execnodes.h:455
MemoryContext CurrentMemoryContext
Definition: mcxt.c:42
ExprState * oc_WhereClause
Definition: execnodes.h:383
GetForeignModifyBatchSize_function GetForeignModifyBatchSize
Definition: fdwapi.h:234
#define outerPlan(node)
Definition: plannodes.h:171
List * lappend(List *list, void *datum)
Definition: list.c:336
void EvalPlanQualInit(EPQState *epqstate, EState *parentestate, Plan *subplan, List *auxrowmarks, int epqParam)
Definition: execMain.c:2413
OnConflictSetState * ri_onConflict
Definition: execnodes.h:494
#define AttributeNumberIsValid(attributeNumber)
Definition: attnum.h:34
#define HASH_BLOBS
Definition: hsearch.h:97
static TupleTableSlot * ExecModifyTable(PlanState *pstate)
List * es_tupleTable
Definition: execnodes.h:601
List * es_auxmodifytables
Definition: execnodes.h:613
ExecProcNodeMtd ExecProcNode
Definition: execnodes.h:971
List * ri_WithCheckOptions
Definition: execnodes.h:470
Size keysize
Definition: hsearch.h:75
unsigned int Index
Definition: c.h:549
TupleDesc rd_att
Definition: rel.h:110
Plan * plan
Definition: execnodes.h:965
#define InvalidOid
Definition: postgres_ext.h:36
TupleTableSlot * oc_ProjSlot
Definition: execnodes.h:381
AttrNumber ri_RowIdAttNo
Definition: execnodes.h:426
List * lcons(void *datum, List *list)
Definition: list.c:468
ExecForeignBatchInsert_function ExecForeignBatchInsert
Definition: fdwapi.h:233
#define makeNode(_type_)
Definition: nodes.h:587
int ri_BatchSize
Definition: execnodes.h:465
#define Assert(condition)
Definition: c.h:804
#define lfirst(lc)
Definition: pg_list.h:169
#define EXEC_FLAG_MARK
Definition: executor.h:59
OnConflictAction onConflictAction
Definition: plannodes.h:233
void ExecAssignExprContext(EState *estate, PlanState *planstate)
Definition: execUtils.c:480
static int list_length(const List *l)
Definition: pg_list.h:149
#define MT_NRELS_HASH
void ExecInitResultTupleSlotTL(PlanState *planstate, const TupleTableSlotOps *tts_ops)
Definition: execTuples.c:1799
struct MTTargetRelLookup MTTargetRelLookup
List * onConflictCols
Definition: plannodes.h:236
List * targetlist
Definition: plannodes.h:141
void * palloc(Size size)
Definition: mcxt.c:1062
ProjectionInfo * ExecBuildProjectionInfo(List *targetList, ExprContext *econtext, TupleTableSlot *slot, PlanState *parent, TupleDesc inputDesc)
Definition: execExpr.c:353
CmdType operation
Definition: plannodes.h:220
#define elog(elevel,...)
Definition: elog.h:232
int i
List * returningLists
Definition: plannodes.h:228
bool isParent
Definition: plannodes.h:1125
BeginForeignModify_function BeginForeignModify
Definition: fdwapi.h:231
PlanState * ExecInitNode(Plan *node, EState *estate, int eflags)
Definition: execProcnode.c:141
Definition: pg_list.h:50
bool bms_is_member(int x, const Bitmapset *a)
Definition: bitmapset.c:427
#define EXEC_FLAG_EXPLAIN_ONLY
Definition: executor.h:56
#define RelationGetRelid(relation)
Definition: rel.h:469
List * ri_onConflictArbiterIndexes
Definition: execnodes.h:491
CmdType
Definition: nodes.h:682
ExecAuxRowMark * ExecBuildAuxRowMark(ExecRowMark *erm, List *targetlist)
Definition: execMain.c:2289
List * ri_returningList
Definition: execnodes.h:485
int epqParam
Definition: plannodes.h:232
Node * onConflictWhere
Definition: plannodes.h:237
ExecRowMark * ExecFindRowMark(EState *estate, Index rti, bool missing_ok)
Definition: execMain.c:2266
HTAB * mt_resultOidHash
Definition: execnodes.h:1213
PartitionTupleRouting * ExecSetupPartitionTupleRouting(EState *estate, Relation rel)

◆ ExecReScanModifyTable()

void ExecReScanModifyTable ( ModifyTableState node)

Definition at line 3197 of file nodeModifyTable.c.

References elog, and ERROR.

Referenced by ExecReScan().

3198 {
3199  /*
3200  * Currently, we don't need to support rescan on ModifyTable nodes. The
3201  * semantics of that would be a bit debatable anyway.
3202  */
3203  elog(ERROR, "ExecReScanModifyTable is not implemented");
3204 }
#define ERROR
Definition: elog.h:46
#define elog(elevel,...)
Definition: elog.h:232