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

ModifyTableStateExecInitModifyTable (ModifyTable *node, EState *estate, int eflags)
 
void ExecEndModifyTable (ModifyTableState *node)
 
void ExecReScanModifyTable (ModifyTableState *node)
 

Function Documentation

◆ ExecEndModifyTable()

void ExecEndModifyTable ( ModifyTableState node)

Definition at line 2662 of file nodeModifyTable.c.

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

Referenced by ExecEndNode().

2663 {
2664  int i;
2665 
2666  /*
2667  * Allow any FDWs to shut down
2668  */
2669  for (i = 0; i < node->mt_nplans; i++)
2670  {
2671  ResultRelInfo *resultRelInfo = node->resultRelInfo + i;
2672 
2673  if (!resultRelInfo->ri_usesFdwDirectModify &&
2674  resultRelInfo->ri_FdwRoutine != NULL &&
2675  resultRelInfo->ri_FdwRoutine->EndForeignModify != NULL)
2676  resultRelInfo->ri_FdwRoutine->EndForeignModify(node->ps.state,
2677  resultRelInfo);
2678  }
2679 
2680  /* Close all the partitioned tables, leaf partitions, and their indices */
2681  if (node->mt_partition_tuple_routing)
2683 
2684  /*
2685  * Free the exprcontext
2686  */
2687  ExecFreeExprContext(&node->ps);
2688 
2689  /*
2690  * clean out the tuple table
2691  */
2693 
2694  /*
2695  * Terminate EPQ execution if active
2696  */
2697  EvalPlanQualEnd(&node->mt_epqstate);
2698 
2699  /*
2700  * shut down subplans
2701  */
2702  for (i = 0; i < node->mt_nplans; i++)
2703  ExecEndNode(node->mt_plans[i]);
2704 }
struct PartitionTupleRouting * mt_partition_tuple_routing
Definition: execnodes.h:998
void ExecEndNode(PlanState *node)
Definition: execProcnode.c:539
ResultRelInfo * resultRelInfo
Definition: execnodes.h:986
TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition: execTuples.c:475
EState * state
Definition: execnodes.h:870
void ExecFreeExprContext(PlanState *planstate)
Definition: execUtils.c:561
void EvalPlanQualEnd(EPQState *epqstate)
Definition: execMain.c:3226
TupleTableSlot * ps_ResultTupleSlot
Definition: execnodes.h:901
PlanState ps
Definition: execnodes.h:979
bool ri_usesFdwDirectModify
Definition: execnodes.h:398
EPQState mt_epqstate
Definition: execnodes.h:990
struct FdwRoutine * ri_FdwRoutine
Definition: execnodes.h:392
EndForeignModify_function EndForeignModify
Definition: fdwapi.h:206
PlanState ** mt_plans
Definition: execnodes.h:983
void ExecCleanupTupleRouting(PartitionTupleRouting *proute)
int i

◆ ExecInitModifyTable()

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

Definition at line 2093 of file nodeModifyTable.c.

References ModifyTable::arbiterIndexes, Assert, AttributeNumberIsValid, FdwRoutine::BeginForeignModify, bms_is_member(), ModifyTable::canSetTag, ModifyTableState::canSetTag, castNode, CheckValidResultRel(), CMD_DELETE, CMD_INSERT, CMD_UPDATE, elog, ModifyTable::epqParam, ERROR, EState::es_auxmodifytables, EState::es_result_relation_info, EState::es_result_relations, EState::es_root_result_relations, EState::es_trig_tuple_slot, EvalPlanQualInit(), EvalPlanQualSetPlan(), ModifyTable::exclRelTlist, EXEC_FLAG_BACKWARD, EXEC_FLAG_EXPLAIN_ONLY, EXEC_FLAG_MARK, ExecAssignExprContext(), ExecBuildAuxRowMark(), ExecBuildProjectionInfo(), ExecCheckPlanOutput(), ExecFindJunkAttribute(), ExecFindRowMark(), ExecInitExtraTupleSlot(), ExecInitJunkFilter(), ExecInitNode(), ExecInitQual(), ExecInitResultTupleSlotTL(), ExecModifyTable(), ExecOpenIndices(), PlanState::ExecProcNode, ExecSetupChildParentMapForSubplan(), ExecSetupPartitionTupleRouting(), ExecSetupTransitionCaptureState(), ExecTypeFromTL(), ModifyTable::fdwDirectModifyPlans, ModifyTable::fdwPrivLists, ModifyTableState::fireBSTriggers, getTargetResultRelInfo(), i, PlanRowMark::isParent, JunkFilter::jf_junkAttNo, lappend(), lcons(), lfirst, lfirst_node, linitial, list_length(), list_nth(), makeNode, map_partition_varattnos(), ModifyTableState::mt_arbiterindexes, ModifyTableState::mt_arowmarks, ModifyTableState::mt_conflproj, ModifyTableState::mt_done, ModifyTableState::mt_epqstate, ModifyTableState::mt_excludedtlist, ModifyTableState::mt_existing, ModifyTableState::mt_nplans, ModifyTableState::mt_onconflict, ModifyTableState::mt_partition_tuple_routing, ModifyTableState::mt_plans, ModifyTableState::mt_whichplan, NIL, ModifyTable::nominalRelation, PartitionTupleRouting::num_partitions, ONCONFLICT_NONE, ONCONFLICT_UPDATE, ModifyTable::onConflictAction, ModifyTable::onConflictSet, ModifyTable::onConflictWhere, ModifyTable::operation, ModifyTableState::operation, palloc0(), ModifyTable::partColsUpdated, PartitionTupleRouting::partitions, PlanState::plan, ModifyTable::plans, ModifyTableState::ps, PlanState::ps_ExprContext, PlanState::ps_ResultTupleSlot, WithCheckOption::qual, RelationData::rd_att, RelationData::rd_rel, RELKIND_FOREIGN_TABLE, RELKIND_MATVIEW, RELKIND_PARTITIONED_TABLE, RELKIND_RELATION, TargetEntry::resjunk, ModifyTable::resultRelIndex, ModifyTableState::resultRelInfo, ModifyTable::returningLists, ResultRelInfo::ri_FdwRoutine, ResultRelInfo::ri_IndexRelationDescs, ResultRelInfo::ri_junkFilter, ResultRelInfo::ri_onConflictSetProj, ResultRelInfo::ri_onConflictSetWhere, ResultRelInfo::ri_projectReturning, ResultRelInfo::ri_RangeTableIndex, ResultRelInfo::ri_RelationDesc, ResultRelInfo::ri_TrigDesc, ResultRelInfo::ri_usesFdwDirectModify, ResultRelInfo::ri_WithCheckOptionExprs, ResultRelInfo::ri_WithCheckOptions, ModifyTable::rootResultRelIndex, ModifyTableState::rootResultRelInfo, ModifyTable::rowMarks, PlanRowMark::rti, PlanState::state, Plan::targetlist, tupleDesc::tdhasoid, TriggerDesc::trig_update_before_row, and ModifyTable::withCheckOptionLists.

Referenced by ExecInitNode().

2094 {
2095  ModifyTableState *mtstate;
2096  CmdType operation = node->operation;
2097  int nplans = list_length(node->plans);
2098  ResultRelInfo *saved_resultRelInfo;
2099  ResultRelInfo *resultRelInfo;
2100  Plan *subplan;
2101  int firstVarno = 0;
2102  Relation firstResultRel = NULL;
2103  ListCell *l;
2104  int i;
2105  Relation rel;
2106  bool update_tuple_routing_needed = node->partColsUpdated;
2107  PartitionTupleRouting *proute = NULL;
2108  int num_partitions = 0;
2109 
2110  /* check for unsupported flags */
2111  Assert(!(eflags & (EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK)));
2112 
2113  /*
2114  * create state structure
2115  */
2116  mtstate = makeNode(ModifyTableState);
2117  mtstate->ps.plan = (Plan *) node;
2118  mtstate->ps.state = estate;
2119  mtstate->ps.ExecProcNode = ExecModifyTable;
2120 
2121  mtstate->operation = operation;
2122  mtstate->canSetTag = node->canSetTag;
2123  mtstate->mt_done = false;
2124 
2125  mtstate->mt_plans = (PlanState **) palloc0(sizeof(PlanState *) * nplans);
2126  mtstate->resultRelInfo = estate->es_result_relations + node->resultRelIndex;
2127 
2128  /* If modifying a partitioned table, initialize the root table info */
2129  if (node->rootResultRelIndex >= 0)
2130  mtstate->rootResultRelInfo = estate->es_root_result_relations +
2131  node->rootResultRelIndex;
2132 
2133  mtstate->mt_arowmarks = (List **) palloc0(sizeof(List *) * nplans);
2134  mtstate->mt_nplans = nplans;
2135  mtstate->mt_onconflict = node->onConflictAction;
2136  mtstate->mt_arbiterindexes = node->arbiterIndexes;
2137 
2138  /* set up epqstate with dummy subplan data for the moment */
2139  EvalPlanQualInit(&mtstate->mt_epqstate, estate, NULL, NIL, node->epqParam);
2140  mtstate->fireBSTriggers = true;
2141 
2142  /*
2143  * call ExecInitNode on each of the plans to be executed and save the
2144  * results into the array "mt_plans". This is also a convenient place to
2145  * verify that the proposed target relations are valid and open their
2146  * indexes for insertion of new index entries. Note we *must* set
2147  * estate->es_result_relation_info correctly while we initialize each
2148  * sub-plan; ExecContextForcesOids depends on that!
2149  */
2150  saved_resultRelInfo = estate->es_result_relation_info;
2151 
2152  resultRelInfo = mtstate->resultRelInfo;
2153  i = 0;
2154  foreach(l, node->plans)
2155  {
2156  subplan = (Plan *) lfirst(l);
2157 
2158  /* Initialize the usesFdwDirectModify flag */
2159  resultRelInfo->ri_usesFdwDirectModify = bms_is_member(i,
2160  node->fdwDirectModifyPlans);
2161 
2162  /*
2163  * Verify result relation is a valid target for the current operation
2164  */
2165  CheckValidResultRel(resultRelInfo, operation);
2166 
2167  /*
2168  * If there are indices on the result relation, open them and save
2169  * descriptors in the result relation info, so that we can add new
2170  * index entries for the tuples we add/update. We need not do this
2171  * for a DELETE, however, since deletion doesn't affect indexes. Also,
2172  * inside an EvalPlanQual operation, the indexes might be open
2173  * already, since we share the resultrel state with the original
2174  * query.
2175  */
2176  if (resultRelInfo->ri_RelationDesc->rd_rel->relhasindex &&
2177  operation != CMD_DELETE &&
2178  resultRelInfo->ri_IndexRelationDescs == NULL)
2179  ExecOpenIndices(resultRelInfo, mtstate->mt_onconflict != ONCONFLICT_NONE);
2180 
2181  /*
2182  * If this is an UPDATE and a BEFORE UPDATE trigger is present, the
2183  * trigger itself might modify the partition-key values. So arrange
2184  * for tuple routing.
2185  */
2186  if (resultRelInfo->ri_TrigDesc &&
2187  resultRelInfo->ri_TrigDesc->trig_update_before_row &&
2188  operation == CMD_UPDATE)
2189  update_tuple_routing_needed = true;
2190 
2191  /* Now init the plan for this result rel */
2192  estate->es_result_relation_info = resultRelInfo;
2193  mtstate->mt_plans[i] = ExecInitNode(subplan, estate, eflags);
2194 
2195  /* Also let FDWs init themselves for foreign-table result rels */
2196  if (!resultRelInfo->ri_usesFdwDirectModify &&
2197  resultRelInfo->ri_FdwRoutine != NULL &&
2198  resultRelInfo->ri_FdwRoutine->BeginForeignModify != NULL)
2199  {
2200  List *fdw_private = (List *) list_nth(node->fdwPrivLists, i);
2201 
2202  resultRelInfo->ri_FdwRoutine->BeginForeignModify(mtstate,
2203  resultRelInfo,
2204  fdw_private,
2205  i,
2206  eflags);
2207  }
2208 
2209  resultRelInfo++;
2210  i++;
2211  }
2212 
2213  estate->es_result_relation_info = saved_resultRelInfo;
2214 
2215  /* Get the target relation */
2216  rel = (getTargetResultRelInfo(mtstate))->ri_RelationDesc;
2217 
2218  /*
2219  * If it's not a partitioned table after all, UPDATE tuple routing should
2220  * not be attempted.
2221  */
2222  if (rel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
2223  update_tuple_routing_needed = false;
2224 
2225  /*
2226  * Build state for tuple routing if it's an INSERT or if it's an UPDATE of
2227  * partition key.
2228  */
2229  if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE &&
2230  (operation == CMD_INSERT || update_tuple_routing_needed))
2231  {
2232  proute = mtstate->mt_partition_tuple_routing =
2234  rel, node->nominalRelation,
2235  estate);
2236  num_partitions = proute->num_partitions;
2237 
2238  /*
2239  * Below are required as reference objects for mapping partition
2240  * attno's in expressions such as WithCheckOptions and RETURNING.
2241  */
2242  firstVarno = mtstate->resultRelInfo[0].ri_RangeTableIndex;
2243  firstResultRel = mtstate->resultRelInfo[0].ri_RelationDesc;
2244  }
2245 
2246  /*
2247  * Build state for collecting transition tuples. This requires having a
2248  * valid trigger query context, so skip it in explain-only mode.
2249  */
2250  if (!(eflags & EXEC_FLAG_EXPLAIN_ONLY))
2251  ExecSetupTransitionCaptureState(mtstate, estate);
2252 
2253  /*
2254  * Construct mapping from each of the per-subplan partition attnos to the
2255  * root attno. This is required when during update row movement the tuple
2256  * descriptor of a source partition does not match the root partitioned
2257  * table descriptor. In such a case we need to convert tuples to the root
2258  * tuple descriptor, because the search for destination partition starts
2259  * from the root. Skip this setup if it's not a partition key update.
2260  */
2261  if (update_tuple_routing_needed)
2263 
2264  /*
2265  * Initialize any WITH CHECK OPTION constraints if needed.
2266  */
2267  resultRelInfo = mtstate->resultRelInfo;
2268  i = 0;
2269  foreach(l, node->withCheckOptionLists)
2270  {
2271  List *wcoList = (List *) lfirst(l);
2272  List *wcoExprs = NIL;
2273  ListCell *ll;
2274 
2275  foreach(ll, wcoList)
2276  {
2277  WithCheckOption *wco = (WithCheckOption *) lfirst(ll);
2278  ExprState *wcoExpr = ExecInitQual((List *) wco->qual,
2279  mtstate->mt_plans[i]);
2280 
2281  wcoExprs = lappend(wcoExprs, wcoExpr);
2282  }
2283 
2284  resultRelInfo->ri_WithCheckOptions = wcoList;
2285  resultRelInfo->ri_WithCheckOptionExprs = wcoExprs;
2286  resultRelInfo++;
2287  i++;
2288  }
2289 
2290  /*
2291  * Build WITH CHECK OPTION constraints for each leaf partition rel. Note
2292  * that we didn't build the withCheckOptionList for each partition within
2293  * the planner, but simple translation of the varattnos for each partition
2294  * will suffice. This only occurs for the INSERT case or for UPDATE row
2295  * movement. DELETEs and local UPDATEs are handled above.
2296  */
2297  if (node->withCheckOptionLists != NIL && num_partitions > 0)
2298  {
2299  List *first_wcoList;
2300 
2301  /*
2302  * In case of INSERT on partitioned tables, there is only one plan.
2303  * Likewise, there is only one WITH CHECK OPTIONS list, not one per
2304  * partition. Whereas for UPDATE, there are as many WCOs as there are
2305  * plans. So in either case, use the WCO expression of the first
2306  * resultRelInfo as a reference to calculate attno's for the WCO
2307  * expression of each of the partitions. We make a copy of the WCO
2308  * qual for each partition. Note that, if there are SubPlans in there,
2309  * they all end up attached to the one parent Plan node.
2310  */
2311  Assert(update_tuple_routing_needed ||
2312  (operation == CMD_INSERT &&
2313  list_length(node->withCheckOptionLists) == 1 &&
2314  mtstate->mt_nplans == 1));
2315 
2316  first_wcoList = linitial(node->withCheckOptionLists);
2317  for (i = 0; i < num_partitions; i++)
2318  {
2319  Relation partrel;
2320  List *mapped_wcoList;
2321  List *wcoExprs = NIL;
2322  ListCell *ll;
2323 
2324  resultRelInfo = proute->partitions[i];
2325 
2326  /*
2327  * If we are referring to a resultRelInfo from one of the update
2328  * result rels, that result rel would already have
2329  * WithCheckOptions initialized.
2330  */
2331  if (resultRelInfo->ri_WithCheckOptions)
2332  continue;
2333 
2334  partrel = resultRelInfo->ri_RelationDesc;
2335 
2336  mapped_wcoList = map_partition_varattnos(first_wcoList,
2337  firstVarno,
2338  partrel, firstResultRel,
2339  NULL);
2340  foreach(ll, mapped_wcoList)
2341  {
2343  ExprState *wcoExpr = ExecInitQual(castNode(List, wco->qual),
2344  &mtstate->ps);
2345 
2346  wcoExprs = lappend(wcoExprs, wcoExpr);
2347  }
2348 
2349  resultRelInfo->ri_WithCheckOptions = mapped_wcoList;
2350  resultRelInfo->ri_WithCheckOptionExprs = wcoExprs;
2351  }
2352  }
2353 
2354  /*
2355  * Initialize RETURNING projections if needed.
2356  */
2357  if (node->returningLists)
2358  {
2359  TupleTableSlot *slot;
2360  ExprContext *econtext;
2361  List *firstReturningList;
2362 
2363  /*
2364  * Initialize result tuple slot and assign its rowtype using the first
2365  * RETURNING list. We assume the rest will look the same.
2366  */
2367  mtstate->ps.plan->targetlist = (List *) linitial(node->returningLists);
2368 
2369  /* Set up a slot for the output of the RETURNING projection(s) */
2370  ExecInitResultTupleSlotTL(estate, &mtstate->ps);
2371  slot = mtstate->ps.ps_ResultTupleSlot;
2372 
2373  /* Need an econtext too */
2374  if (mtstate->ps.ps_ExprContext == NULL)
2375  ExecAssignExprContext(estate, &mtstate->ps);
2376  econtext = mtstate->ps.ps_ExprContext;
2377 
2378  /*
2379  * Build a projection for each result rel.
2380  */
2381  resultRelInfo = mtstate->resultRelInfo;
2382  foreach(l, node->returningLists)
2383  {
2384  List *rlist = (List *) lfirst(l);
2385 
2386  resultRelInfo->ri_projectReturning =
2387  ExecBuildProjectionInfo(rlist, econtext, slot, &mtstate->ps,
2388  resultRelInfo->ri_RelationDesc->rd_att);
2389  resultRelInfo++;
2390  }
2391 
2392  /*
2393  * Build a projection for each leaf partition rel. Note that we
2394  * didn't build the returningList for each partition within the
2395  * planner, but simple translation of the varattnos for each partition
2396  * will suffice. This only occurs for the INSERT case or for UPDATE
2397  * row movement. DELETEs and local UPDATEs are handled above.
2398  */
2399  firstReturningList = linitial(node->returningLists);
2400  for (i = 0; i < num_partitions; i++)
2401  {
2402  Relation partrel;
2403  List *rlist;
2404 
2405  resultRelInfo = proute->partitions[i];
2406 
2407  /*
2408  * If we are referring to a resultRelInfo from one of the update
2409  * result rels, that result rel would already have a returningList
2410  * built.
2411  */
2412  if (resultRelInfo->ri_projectReturning)
2413  continue;
2414 
2415  partrel = resultRelInfo->ri_RelationDesc;
2416 
2417  /*
2418  * Use the returning expression of the first resultRelInfo as a
2419  * reference to calculate attno's for the returning expression of
2420  * each of the partitions.
2421  */
2422  rlist = map_partition_varattnos(firstReturningList,
2423  firstVarno,
2424  partrel, firstResultRel, NULL);
2425  resultRelInfo->ri_projectReturning =
2426  ExecBuildProjectionInfo(rlist, econtext, slot, &mtstate->ps,
2427  resultRelInfo->ri_RelationDesc->rd_att);
2428  }
2429  }
2430  else
2431  {
2432  /*
2433  * We still must construct a dummy result tuple type, because InitPlan
2434  * expects one (maybe should change that?).
2435  */
2436  mtstate->ps.plan->targetlist = NIL;
2437  ExecInitResultTupleSlotTL(estate, &mtstate->ps);
2438 
2439  mtstate->ps.ps_ExprContext = NULL;
2440  }
2441 
2442  /*
2443  * If needed, Initialize target list, projection and qual for ON CONFLICT
2444  * DO UPDATE.
2445  */
2446  resultRelInfo = mtstate->resultRelInfo;
2447  if (node->onConflictAction == ONCONFLICT_UPDATE)
2448  {
2449  ExprContext *econtext;
2450  TupleDesc relationDesc;
2451  TupleDesc tupDesc;
2452 
2453  /* insert may only have one plan, inheritance is not expanded */
2454  Assert(nplans == 1);
2455 
2456  /* already exists if created by RETURNING processing above */
2457  if (mtstate->ps.ps_ExprContext == NULL)
2458  ExecAssignExprContext(estate, &mtstate->ps);
2459 
2460  econtext = mtstate->ps.ps_ExprContext;
2461  relationDesc = resultRelInfo->ri_RelationDesc->rd_att;
2462 
2463  /* initialize slot for the existing tuple */
2464  mtstate->mt_existing =
2465  ExecInitExtraTupleSlot(mtstate->ps.state, relationDesc);
2466 
2467  /* carried forward solely for the benefit of explain */
2468  mtstate->mt_excludedtlist = node->exclRelTlist;
2469 
2470  /* create target slot for UPDATE SET projection */
2471  tupDesc = ExecTypeFromTL((List *) node->onConflictSet,
2472  relationDesc->tdhasoid);
2473  mtstate->mt_conflproj =
2474  ExecInitExtraTupleSlot(mtstate->ps.state, tupDesc);
2475 
2476  /* build UPDATE SET projection state */
2477  resultRelInfo->ri_onConflictSetProj =
2478  ExecBuildProjectionInfo(node->onConflictSet, econtext,
2479  mtstate->mt_conflproj, &mtstate->ps,
2480  relationDesc);
2481 
2482  /* build DO UPDATE WHERE clause expression */
2483  if (node->onConflictWhere)
2484  {
2485  ExprState *qualexpr;
2486 
2487  qualexpr = ExecInitQual((List *) node->onConflictWhere,
2488  &mtstate->ps);
2489 
2490  resultRelInfo->ri_onConflictSetWhere = qualexpr;
2491  }
2492  }
2493 
2494  /*
2495  * If we have any secondary relations in an UPDATE or DELETE, they need to
2496  * be treated like non-locked relations in SELECT FOR UPDATE, ie, the
2497  * EvalPlanQual mechanism needs to be told about them. Locate the
2498  * relevant ExecRowMarks.
2499  */
2500  foreach(l, node->rowMarks)
2501  {
2503  ExecRowMark *erm;
2504 
2505  /* ignore "parent" rowmarks; they are irrelevant at runtime */
2506  if (rc->isParent)
2507  continue;
2508 
2509  /* find ExecRowMark (same for all subplans) */
2510  erm = ExecFindRowMark(estate, rc->rti, false);
2511 
2512  /* build ExecAuxRowMark for each subplan */
2513  for (i = 0; i < nplans; i++)
2514  {
2515  ExecAuxRowMark *aerm;
2516 
2517  subplan = mtstate->mt_plans[i]->plan;
2518  aerm = ExecBuildAuxRowMark(erm, subplan->targetlist);
2519  mtstate->mt_arowmarks[i] = lappend(mtstate->mt_arowmarks[i], aerm);
2520  }
2521  }
2522 
2523  /* select first subplan */
2524  mtstate->mt_whichplan = 0;
2525  subplan = (Plan *) linitial(node->plans);
2526  EvalPlanQualSetPlan(&mtstate->mt_epqstate, subplan,
2527  mtstate->mt_arowmarks[0]);
2528 
2529  /*
2530  * Initialize the junk filter(s) if needed. INSERT queries need a filter
2531  * if there are any junk attrs in the tlist. UPDATE and DELETE always
2532  * need a filter, since there's always at least one junk attribute present
2533  * --- no need to look first. Typically, this will be a 'ctid' or
2534  * 'wholerow' attribute, but in the case of a foreign data wrapper it
2535  * might be a set of junk attributes sufficient to identify the remote
2536  * row.
2537  *
2538  * If there are multiple result relations, each one needs its own junk
2539  * filter. Note multiple rels are only possible for UPDATE/DELETE, so we
2540  * can't be fooled by some needing a filter and some not.
2541  *
2542  * This section of code is also a convenient place to verify that the
2543  * output of an INSERT or UPDATE matches the target table(s).
2544  */
2545  {
2546  bool junk_filter_needed = false;
2547 
2548  switch (operation)
2549  {
2550  case CMD_INSERT:
2551  foreach(l, subplan->targetlist)
2552  {
2553  TargetEntry *tle = (TargetEntry *) lfirst(l);
2554 
2555  if (tle->resjunk)
2556  {
2557  junk_filter_needed = true;
2558  break;
2559  }
2560  }
2561  break;
2562  case CMD_UPDATE:
2563  case CMD_DELETE:
2564  junk_filter_needed = true;
2565  break;
2566  default:
2567  elog(ERROR, "unknown operation");
2568  break;
2569  }
2570 
2571  if (junk_filter_needed)
2572  {
2573  resultRelInfo = mtstate->resultRelInfo;
2574  for (i = 0; i < nplans; i++)
2575  {
2576  JunkFilter *j;
2577 
2578  subplan = mtstate->mt_plans[i]->plan;
2579  if (operation == CMD_INSERT || operation == CMD_UPDATE)
2580  ExecCheckPlanOutput(resultRelInfo->ri_RelationDesc,
2581  subplan->targetlist);
2582 
2583  j = ExecInitJunkFilter(subplan->targetlist,
2584  resultRelInfo->ri_RelationDesc->rd_att->tdhasoid,
2585  ExecInitExtraTupleSlot(estate, NULL));
2586 
2587  if (operation == CMD_UPDATE || operation == CMD_DELETE)
2588  {
2589  /* For UPDATE/DELETE, find the appropriate junk attr now */
2590  char relkind;
2591 
2592  relkind = resultRelInfo->ri_RelationDesc->rd_rel->relkind;
2593  if (relkind == RELKIND_RELATION ||
2594  relkind == RELKIND_MATVIEW ||
2595  relkind == RELKIND_PARTITIONED_TABLE)
2596  {
2597  j->jf_junkAttNo = ExecFindJunkAttribute(j, "ctid");
2599  elog(ERROR, "could not find junk ctid column");
2600  }
2601  else if (relkind == RELKIND_FOREIGN_TABLE)
2602  {
2603  /*
2604  * When there is a row-level trigger, there should be
2605  * a wholerow attribute.
2606  */
2607  j->jf_junkAttNo = ExecFindJunkAttribute(j, "wholerow");
2608  }
2609  else
2610  {
2611  j->jf_junkAttNo = ExecFindJunkAttribute(j, "wholerow");
2613  elog(ERROR, "could not find junk wholerow column");
2614  }
2615  }
2616 
2617  resultRelInfo->ri_junkFilter = j;
2618  resultRelInfo++;
2619  }
2620  }
2621  else
2622  {
2623  if (operation == CMD_INSERT)
2625  subplan->targetlist);
2626  }
2627  }
2628 
2629  /*
2630  * Set up a tuple table slot for use for trigger output tuples. In a plan
2631  * containing multiple ModifyTable nodes, all can share one such slot, so
2632  * we keep it in the estate.
2633  */
2634  if (estate->es_trig_tuple_slot == NULL)
2635  estate->es_trig_tuple_slot = ExecInitExtraTupleSlot(estate, NULL);
2636 
2637  /*
2638  * Lastly, if this is not the primary (canSetTag) ModifyTable node, add it
2639  * to estate->es_auxmodifytables so that it will be run to completion by
2640  * ExecPostprocessPlan. (It'd actually work fine to add the primary
2641  * ModifyTable node too, but there's no need.) Note the use of lcons not
2642  * lappend: we need later-initialized ModifyTable nodes to be shut down
2643  * before earlier ones. This ensures that we don't throw away RETURNING
2644  * rows that need to be seen by a later CTE subplan.
2645  */
2646  if (!mtstate->canSetTag)
2647  estate->es_auxmodifytables = lcons(mtstate,
2648  estate->es_auxmodifytables);
2649 
2650  return mtstate;
2651 }
AttrNumber jf_junkAttNo
Definition: execnodes.h:350
#define NIL
Definition: pg_list.h:69
JunkFilter * ri_junkFilter
Definition: execnodes.h:410
List * arbiterIndexes
Definition: plannodes.h:234
Relation ri_RelationDesc
Definition: execnodes.h:368
Bitmapset * fdwDirectModifyPlans
Definition: plannodes.h:230
ExprState * ri_onConflictSetWhere
Definition: execnodes.h:419
Index nominalRelation
Definition: plannodes.h:219
static ResultRelInfo * getTargetResultRelInfo(ModifyTableState *node)
bool tdhasoid
Definition: tupdesc.h:82
ProjectionInfo * ri_onConflictSetProj
Definition: execnodes.h:416
struct PartitionTupleRouting * mt_partition_tuple_routing
Definition: execnodes.h:998
List * withCheckOptionLists
Definition: plannodes.h:227
#define castNode(_type_, nodeptr)
Definition: nodes.h:582
int resultRelIndex
Definition: plannodes.h:224
ResultRelInfo * resultRelInfo
Definition: execnodes.h:986
AttrNumber ExecFindJunkAttribute(JunkFilter *junkfilter, const char *attrName)
Definition: execJunk.c:209
ExprContext * ps_ExprContext
Definition: execnodes.h:902
TupleTableSlot * mt_conflproj
Definition: execnodes.h:997
#define RELKIND_MATVIEW
Definition: pg_class.h:165
bool partColsUpdated
Definition: plannodes.h:222
PartitionTupleRouting * ExecSetupPartitionTupleRouting(ModifyTableState *mtstate, Relation rel, Index resultRTindex, EState *estate)
Definition: execPartition.c:49
bool canSetTag
Definition: plannodes.h:218
CmdType operation
Definition: execnodes.h:980
ResultRelInfo * rootResultRelInfo
Definition: execnodes.h:987
void EvalPlanQualSetPlan(EPQState *epqstate, Plan *subplan, List *auxrowmarks)
Definition: execMain.c:2831
EState * state
Definition: execnodes.h:870
Form_pg_class rd_rel
Definition: rel.h:114
List * plans
Definition: plannodes.h:226
ResultRelInfo ** partitions
Definition: execPartition.h:94
TupleTableSlot * ExecInitExtraTupleSlot(EState *estate, TupleDesc tupledesc)
Definition: execTuples.c:910
ExprState * ExecInitQual(List *qual, PlanState *parent)
Definition: execExpr.c:204
Index ri_RangeTableIndex
Definition: execnodes.h:365
List * onConflictSet
Definition: plannodes.h:235
int rootResultRelIndex
Definition: plannodes.h:225
void ExecOpenIndices(ResultRelInfo *resultRelInfo, bool speculative)
Definition: execIndexing.c:149
TupleTableSlot * mt_existing
Definition: execnodes.h:995
List * ri_WithCheckOptionExprs
Definition: execnodes.h:404
OnConflictAction mt_onconflict
Definition: execnodes.h:992
TupleTableSlot * ps_ResultTupleSlot
Definition: execnodes.h:901
static void ExecSetupChildParentMapForSubplan(ModifyTableState *mtstate)
List * rowMarks
Definition: plannodes.h:231
bool resjunk
Definition: primnodes.h:1382
#define linitial(l)
Definition: pg_list.h:111
List * map_partition_varattnos(List *expr, int fromrel_varno, Relation to_rel, Relation from_rel, bool *found_whole_row)
Definition: partition.c:1475
#define ERROR
Definition: elog.h:43
PlanState ps
Definition: execnodes.h:979
bool ri_usesFdwDirectModify
Definition: execnodes.h:398
static void ExecSetupTransitionCaptureState(ModifyTableState *mtstate, EState *estate)
void CheckValidResultRel(ResultRelInfo *resultRelInfo, CmdType operation)
Definition: execMain.c:1098
#define EXEC_FLAG_BACKWARD
Definition: executor.h:61
#define lfirst_node(type, lc)
Definition: pg_list.h:109
void * list_nth(const List *list, int n)
Definition: list.c:410
ResultRelInfo * es_result_relations
Definition: execnodes.h:455
JunkFilter * ExecInitJunkFilter(List *targetList, bool hasoid, TupleTableSlot *slot)
Definition: execJunk.c:61
List * fdwPrivLists
Definition: plannodes.h:229
EPQState mt_epqstate
Definition: execnodes.h:990
bool trig_update_before_row
Definition: reltrigger.h:60
ProjectionInfo * ri_projectReturning
Definition: execnodes.h:413
struct FdwRoutine * ri_FdwRoutine
Definition: execnodes.h:392
#define RELKIND_FOREIGN_TABLE
Definition: pg_class.h:167
TupleTableSlot * es_trig_tuple_slot
Definition: execnodes.h:477
TriggerDesc * ri_TrigDesc
Definition: execnodes.h:380
TupleDesc ExecTypeFromTL(List *targetList, bool hasoid)
Definition: execTuples.c:944
List * lappend(List *list, void *datum)
Definition: list.c:128
PlanState ** mt_plans
Definition: execnodes.h:983
#define AttributeNumberIsValid(attributeNumber)
Definition: attnum.h:34
static TupleTableSlot * ExecModifyTable(PlanState *pstate)
#define RELKIND_PARTITIONED_TABLE
Definition: pg_class.h:168
void * palloc0(Size size)
Definition: mcxt.c:864
List * es_auxmodifytables
Definition: execnodes.h:505
ExecProcNodeMtd ExecProcNode
Definition: execnodes.h:874
List * ri_WithCheckOptions
Definition: execnodes.h:401
void ExecInitResultTupleSlotTL(EState *estate, PlanState *planstate)
Definition: execTuples.c:870
TupleDesc rd_att
Definition: rel.h:115
void EvalPlanQualInit(EPQState *epqstate, EState *estate, Plan *subplan, List *auxrowmarks, int epqParam)
Definition: execMain.c:2812
Plan * plan
Definition: execnodes.h:868
List * lcons(void *datum, List *list)
Definition: list.c:259
#define makeNode(_type_)
Definition: nodes.h:561
static void ExecCheckPlanOutput(Relation resultRel, List *targetList)
#define Assert(condition)
Definition: c.h:688
#define lfirst(lc)
Definition: pg_list.h:106
#define EXEC_FLAG_MARK
Definition: executor.h:62
OnConflictAction onConflictAction
Definition: plannodes.h:233
void ExecAssignExprContext(EState *estate, PlanState *planstate)
Definition: execUtils.c:425
static int list_length(const List *l)
Definition: pg_list.h:89
List * targetlist
Definition: plannodes.h:144
List * mt_arbiterindexes
Definition: execnodes.h:993
List * mt_excludedtlist
Definition: execnodes.h:996
ProjectionInfo * ExecBuildProjectionInfo(List *targetList, ExprContext *econtext, TupleTableSlot *slot, PlanState *parent, TupleDesc inputDesc)
Definition: execExpr.c:348
CmdType operation
Definition: plannodes.h:217
ResultRelInfo * es_root_result_relations
Definition: execnodes.h:466
int i
List * returningLists
Definition: plannodes.h:228
bool isParent
Definition: plannodes.h:1033
#define elog
Definition: elog.h:219
BeginForeignModify_function BeginForeignModify
Definition: fdwapi.h:202
#define RELKIND_RELATION
Definition: pg_class.h:160
PlanState * ExecInitNode(Plan *node, EState *estate, int eflags)
Definition: execProcnode.c:139
Definition: pg_list.h:45
bool bms_is_member(int x, const Bitmapset *a)
Definition: bitmapset.c:464
#define EXEC_FLAG_EXPLAIN_ONLY
Definition: executor.h:59
CmdType
Definition: nodes.h:653
RelationPtr ri_IndexRelationDescs
Definition: execnodes.h:374
ExecAuxRowMark * ExecBuildAuxRowMark(ExecRowMark *erm, List *targetlist)
Definition: execMain.c:2425
List * exclRelTlist
Definition: plannodes.h:238
List ** mt_arowmarks
Definition: execnodes.h:989
int epqParam
Definition: plannodes.h:232
Node * onConflictWhere
Definition: plannodes.h:236
ExecRowMark * ExecFindRowMark(EState *estate, Index rti, bool missing_ok)
Definition: execMain.c:2401
ResultRelInfo * es_result_relation_info
Definition: execnodes.h:457

◆ ExecReScanModifyTable()

void ExecReScanModifyTable ( ModifyTableState node)

Definition at line 2707 of file nodeModifyTable.c.

References elog, and ERROR.

Referenced by ExecReScan().

2708 {
2709  /*
2710  * Currently, we don't need to support rescan on ModifyTable nodes. The
2711  * semantics of that would be a bit debatable anyway.
2712  */
2713  elog(ERROR, "ExecReScanModifyTable is not implemented");
2714 }
#define ERROR
Definition: elog.h:43
#define elog
Definition: elog.h:219