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.

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 }
bool bms_is_member(int x, const Bitmapset *a)
Definition: bitmapset.c:427
static Datum values[MAXATTR]
Definition: bootstrap.c:156
Datum datumCopy(Datum value, bool typByVal, int typLen)
Definition: datum.c:132
#define ERROR
Definition: elog.h:33
#define elog(elevel,...)
Definition: elog.h:218
ExprState * ExecPrepareExpr(Expr *node, EState *estate)
Definition: execExpr.c:746
TupleTableSlot * ExecStoreVirtualTuple(TupleTableSlot *slot)
Definition: execTuples.c:1552
Bitmapset * ExecGetExtraUpdatedCols(ResultRelInfo *relinfo, EState *estate)
Definition: execUtils.c:1321
#define GetPerTupleExprContext(estate)
Definition: executor.h:533
#define GetPerTupleMemoryContext(estate)
Definition: executor.h:538
static Datum ExecEvalExpr(ExprState *state, ExprContext *econtext, bool *isNull)
Definition: executor.h:316
long val
Definition: informix.c:664
int i
Definition: isn.c:73
Assert(fmt[strlen(fmt) - 1] !='\n')
void * palloc(Size size)
Definition: mcxt.c:1062
@ CMD_UPDATE
Definition: nodes.h:686
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:207
uintptr_t Datum
Definition: postgres.h:411
#define RelationGetDescr(relation)
Definition: rel.h:503
#define RelationGetRelationName(relation)
Definition: rel.h:511
Node * build_column_default(Relation rel, int attrno)
MemoryContext es_query_cxt
Definition: execnodes.h:601
TupleTableSlot * ecxt_scantuple
Definition: execnodes.h:227
TriggerDesc * trigdesc
Definition: rel.h:115
Relation ri_RelationDesc
Definition: execnodes.h:412
ExprState ** ri_GeneratedExprs
Definition: execnodes.h:481
int ri_NumGeneratedNeeded
Definition: execnodes.h:484
bool trig_update_before_row
Definition: reltrigger.h:61
bool has_generated_stored
Definition: tupdesc.h:45
TupleConstr * constr
Definition: tupdesc.h:85
bool * tts_isnull
Definition: tuptable.h:128
Datum * tts_values
Definition: tuptable.h:126
#define FirstLowInvalidHeapAttributeNumber
Definition: sysattr.h:27
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92
static TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition: tuptable.h:425
static void slot_getallattrs(TupleTableSlot *slot)
Definition: tuptable.h:354
static void ExecMaterializeSlot(TupleTableSlot *slot)
Definition: tuptable.h:443

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().

◆ ExecEndModifyTable()

void ExecEndModifyTable ( ModifyTableState node)

Definition at line 3169 of file nodeModifyTable.c.

3170 {
3171  int i;
3172 
3173  /*
3174  * Allow any FDWs to shut down
3175  */
3176  for (i = 0; i < node->mt_nrels; i++)
3177  {
3178  int j;
3179  ResultRelInfo *resultRelInfo = node->resultRelInfo + i;
3180 
3181  if (!resultRelInfo->ri_usesFdwDirectModify &&
3182  resultRelInfo->ri_FdwRoutine != NULL &&
3183  resultRelInfo->ri_FdwRoutine->EndForeignModify != NULL)
3184  resultRelInfo->ri_FdwRoutine->EndForeignModify(node->ps.state,
3185  resultRelInfo);
3186 
3187  /*
3188  * Cleanup the initialized batch slots. This only matters for FDWs
3189  * with batching, but the other cases will have ri_NumSlotsInitialized
3190  * == 0.
3191  */
3192  for (j = 0; j < resultRelInfo->ri_NumSlotsInitialized; j++)
3193  {
3194  ExecDropSingleTupleTableSlot(resultRelInfo->ri_Slots[j]);
3195  ExecDropSingleTupleTableSlot(resultRelInfo->ri_PlanSlots[j]);
3196  }
3197  }
3198 
3199  /*
3200  * Close all the partitioned tables, leaf partitions, and their indices
3201  * and release the slot used for tuple routing, if set.
3202  */
3203  if (node->mt_partition_tuple_routing)
3204  {
3206 
3207  if (node->mt_root_tuple_slot)
3209  }
3210 
3211  /*
3212  * Free the exprcontext
3213  */
3214  ExecFreeExprContext(&node->ps);
3215 
3216  /*
3217  * clean out the tuple table
3218  */
3219  if (node->ps.ps_ResultTupleSlot)
3221 
3222  /*
3223  * Terminate EPQ execution if active
3224  */
3225  EvalPlanQualEnd(&node->mt_epqstate);
3226 
3227  /*
3228  * shut down subplan
3229  */
3230  ExecEndNode(outerPlanState(node));
3231 }
void EvalPlanQualEnd(EPQState *epqstate)
Definition: execMain.c:2834
void ExecCleanupTupleRouting(ModifyTableState *mtstate, PartitionTupleRouting *proute)
void ExecEndNode(PlanState *node)
Definition: execProcnode.c:556
void ExecDropSingleTupleTableSlot(TupleTableSlot *slot)
Definition: execTuples.c:1254
void ExecFreeExprContext(PlanState *planstate)
Definition: execUtils.c:650
#define outerPlanState(node)
Definition: execnodes.h:1063
int j
Definition: isn.c:74
EndForeignModify_function EndForeignModify
Definition: fdwapi.h:237
ResultRelInfo * resultRelInfo
Definition: execnodes.h:1193
struct PartitionTupleRouting * mt_partition_tuple_routing
Definition: execnodes.h:1224
TupleTableSlot * mt_root_tuple_slot
Definition: execnodes.h:1221
EPQState mt_epqstate
Definition: execnodes.h:1203
PlanState ps
Definition: execnodes.h:1188
EState * state
Definition: execnodes.h:969
TupleTableSlot * ps_ResultTupleSlot
Definition: execnodes.h:1005
TupleTableSlot ** ri_Slots
Definition: execnodes.h:468
int ri_NumSlotsInitialized
Definition: execnodes.h:466
struct FdwRoutine * ri_FdwRoutine
Definition: execnodes.h:456
TupleTableSlot ** ri_PlanSlots
Definition: execnodes.h:469
bool ri_usesFdwDirectModify
Definition: execnodes.h:462

References FdwRoutine::EndForeignModify, EvalPlanQualEnd(), ExecCleanupTupleRouting(), ExecClearTuple(), ExecDropSingleTupleTableSlot(), ExecEndNode(), ExecFreeExprContext(), i, j, 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_NumSlotsInitialized, ResultRelInfo::ri_PlanSlots, ResultRelInfo::ri_Slots, ResultRelInfo::ri_usesFdwDirectModify, and PlanState::state.

Referenced by ExecEndNode().

◆ ExecInitModifyTable()

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

Definition at line 2708 of file nodeModifyTable.c.

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

References ModifyTable::arbiterIndexes, Assert(), AttributeNumberIsValid, FdwRoutine::BeginForeignModify, bms_is_member(), ModifyTableState::canSetTag, ModifyTable::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, ModifyTableState::operation, ModifyTable::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().

◆ ExecReScanModifyTable()

void ExecReScanModifyTable ( ModifyTableState node)

Definition at line 3234 of file nodeModifyTable.c.

3235 {
3236  /*
3237  * Currently, we don't need to support rescan on ModifyTable nodes. The
3238  * semantics of that would be a bit debatable anyway.
3239  */
3240  elog(ERROR, "ExecReScanModifyTable is not implemented");
3241 }

References elog, and ERROR.

Referenced by ExecReScan().