4617{
4622 int nrels;
4624 List *withCheckOptionLists =
NIL;
4626 List *updateColnosLists =
NIL;
4628 List *mergeJoinConditions =
NIL;
4634
4635 /* check for unsupported flags */
4637
4638 /*
4639 * Only consider unpruned relations for initializing their ResultRelInfo
4640 * struct and other fields such as withCheckOptions, etc.
4641 *
4642 * Note: We must avoid pruning every result relation. This is important
4643 * for MERGE, since even if every result relation is pruned from the
4644 * subplan, there might still be NOT MATCHED rows, for which there may be
4645 * INSERT actions to perform. To allow these actions to be found, at
4646 * least one result relation must be kept. Also, when inserting into a
4647 * partitioned table, ExecInitPartitionInfo() needs a ResultRelInfo struct
4648 * as a reference for building the ResultRelInfo of the target partition.
4649 * In either case, it doesn't matter which result relation is kept, so we
4650 * just keep the first one, if all others have been pruned. See also,
4651 * ExecDoInitialPruning(), which ensures that this first result relation
4652 * has been locked.
4653 */
4656 {
4658 bool keep_rel;
4659
4661 if (!keep_rel &&
i == total_nrels - 1 && resultRelations ==
NIL)
4662 {
4663 /* all result relations pruned; keep the first one */
4664 keep_rel = true;
4667 }
4668
4669 if (keep_rel)
4670 {
4671 resultRelations =
lappend_int(resultRelations, rti);
4673 {
4677
4678 withCheckOptionLists =
lappend(withCheckOptionLists, withCheckOptions);
4679 }
4681 {
4685
4686 returningLists =
lappend(returningLists, returningList);
4687 }
4689 {
4691
4692 updateColnosLists =
lappend(updateColnosLists, updateColnosList);
4693 }
4695 {
4697
4698 mergeActionLists =
lappend(mergeActionLists, mergeActionList);
4699 }
4701 {
4703
4704 mergeJoinConditions =
lappend(mergeJoinConditions, mergeJoinCondition);
4705 }
4706 }
4708 }
4711
4712 /*
4713 * create state structure
4714 */
4719
4723
4727
4735
4736 /*----------
4737 * Resolve the target relation. This is the same as:
4738 *
4739 * - the relation for which we will fire FOR STATEMENT triggers,
4740 * - the relation into whose tuple format all captured transition tuples
4741 * must be converted, and
4742 * - the root partitioned table used for tuple routing.
4743 *
4744 * If it's a partitioned or inherited table, the root partition or
4745 * appendrel RTE doesn't appear elsewhere in the plan and its RT index is
4746 * given explicitly in node->rootRelation. Otherwise, the target relation
4747 * is the sole relation in the node->resultRelations list and, since it can
4748 * never be pruned, also in the resultRelations list constructed above.
4749 *----------
4750 */
4752 {
4757 }
4758 else
4759 {
4765 }
4766
4767 /* set up epqstate with dummy subplan data for the moment */
4771
4772 /*
4773 * Build state for collecting transition tuples. This requires having a
4774 * valid trigger query context, so skip it in explain-only mode.
4775 */
4778
4779 /*
4780 * Open all the result relations and initialize the ResultRelInfo structs.
4781 * (But root relation was initialized above, if it's part of the array.)
4782 * We must do this before initializing the subplan, because direct-modify
4783 * FDWs expect their ResultRelInfos to be available.
4784 */
4787 foreach(l, resultRelations)
4788 {
4791
4792 if (mergeActionLists)
4793 mergeActions =
list_nth(mergeActionLists,
i);
4794
4796 {
4798
4799 /*
4800 * For child result relations, store the root result relation
4801 * pointer. We do so for the convenience of places that want to
4802 * look at the query's original target relation but don't have the
4803 * mtstate handy.
4804 */
4806 }
4807
4808 /* Initialize the usesFdwDirectModify flag */
4811
4812 /*
4813 * Verify result relation is a valid target for the current operation
4814 */
4816 mergeActions);
4817
4818 resultRelInfo++;
4820 }
4821
4822 /*
4823 * Now we may initialize the subplan.
4824 */
4826
4827 /*
4828 * Do additional per-result-relation initialization.
4829 */
4830 for (
i = 0;
i < nrels;
i++)
4831 {
4833
4834 /* Let FDWs init themselves for foreign-table result rels */
4838 {
4840
4842 resultRelInfo,
4843 fdw_private,
4845 eflags);
4846 }
4847
4848 /*
4849 * For UPDATE/DELETE/MERGE, find the appropriate junk attr now, either
4850 * a 'ctid' or 'wholerow' attribute depending on relkind. For foreign
4851 * tables, the FDW might have created additional junk attr(s), but
4852 * those are no concern of ours.
4853 */
4856 {
4857 char relkind;
4858
4860 if (relkind == RELKIND_RELATION ||
4861 relkind == RELKIND_MATVIEW ||
4862 relkind == RELKIND_PARTITIONED_TABLE)
4863 {
4867 elog(
ERROR,
"could not find junk ctid column");
4868 }
4869 else if (relkind == RELKIND_FOREIGN_TABLE)
4870 {
4871 /*
4872 * We don't support MERGE with foreign tables for now. (It's
4873 * problematic because the implementation uses CTID.)
4874 */
4876
4877 /*
4878 * When there is a row-level trigger, there should be a
4879 * wholerow attribute. We also require it to be present in
4880 * UPDATE and MERGE, so we can get the values of unchanged
4881 * columns.
4882 */
4885 "wholerow");
4888 elog(
ERROR,
"could not find junk wholerow column");
4889 }
4890 else
4891 {
4892 /* Other valid target relkinds must provide wholerow */
4895 "wholerow");
4897 elog(
ERROR,
"could not find junk wholerow column");
4898 }
4899 }
4900 }
4901
4902 /*
4903 * If this is an inherited update/delete/merge, there will be a junk
4904 * attribute named "tableoid" present in the subplan's targetlist. It
4905 * will be used to identify the result relation for a given tuple to be
4906 * updated/deleted/merged.
4907 */
4913
4914 /* Get the root target relation */
4916
4917 /*
4918 * Build state for tuple routing if it's a partitioned INSERT. An UPDATE
4919 * or MERGE might need this too, but only if it actually moves tuples
4920 * between partitions; in that case setup is done by
4921 * ExecCrossPartitionUpdate.
4922 */
4923 if (rel->
rd_rel->relkind == RELKIND_PARTITIONED_TABLE &&
4927
4928 /*
4929 * Initialize any WITH CHECK OPTION constraints if needed.
4930 */
4932 foreach(l, withCheckOptionLists)
4933 {
4937
4938 foreach(ll, wcoList)
4939 {
4943
4944 wcoExprs =
lappend(wcoExprs, wcoExpr);
4945 }
4946
4949 resultRelInfo++;
4950 }
4951
4952 /*
4953 * Initialize RETURNING projections if needed.
4954 */
4955 if (returningLists)
4956 {
4959
4960 /*
4961 * Initialize result tuple slot and assign its rowtype using the plan
4962 * node's declared targetlist, which the planner set up to be the same
4963 * as the first (before runtime pruning) RETURNING list. We assume
4964 * all the result rels will produce compatible output.
4965 */
4968
4969 /* Need an econtext too */
4973
4974 /*
4975 * Build a projection for each result rel.
4976 */
4978 foreach(l, returningLists)
4979 {
4981
4986 resultRelInfo++;
4987 }
4988 }
4989 else
4990 {
4991 /*
4992 * We still must construct a dummy result tuple type, because InitPlan
4993 * expects one (maybe should change that?).
4994 */
4996
4998 }
4999
5000 /* Set the list of arbiter indexes if needed for ON CONFLICT */
5003 {
5004 /* insert may only have one relation, inheritance is not expanded */
5005 Assert(total_nrels == 1);
5007 }
5008
5009 /*
5010 * If needed, Initialize target list, projection and qual for ON CONFLICT
5011 * DO UPDATE.
5012 */
5014 {
5018
5019 /* already exists if created by RETURNING processing above */
5022
5025
5026 /* create state for DO UPDATE SET operation */
5028
5029 /* initialize slot for the existing tuple */
5033
5034 /*
5035 * Create the tuple slot for the UPDATE SET projection. We want a slot
5036 * of the table's type here, because the slot will be used to insert
5037 * into the table, and for RETURNING processing - which may access
5038 * system attributes.
5039 */
5043
5044 /* build UPDATE SET projection state */
5047 true,
5049 relationDesc,
5050 econtext,
5053
5054 /* initialize state to evaluate the WHERE clause, if any */
5056 {
5058
5062 }
5063 }
5064
5065 /*
5066 * If we have any secondary relations in an UPDATE or DELETE, they need to
5067 * be treated like non-locked relations in SELECT FOR UPDATE, i.e., the
5068 * EvalPlanQual mechanism needs to be told about them. This also goes for
5069 * the source relations in a MERGE. Locate the relevant ExecRowMarks.
5070 */
5073 {
5077
5078 /*
5079 * Ignore "parent" rowmarks, because they are irrelevant at runtime.
5080 * Also ignore the rowmarks belonging to child tables that have been
5081 * pruned in ExecDoInitialPruning().
5082 */
5085 continue;
5086
5087 /* Find ExecRowMark and build ExecAuxRowMark */
5090 arowmarks =
lappend(arowmarks, aerm);
5091 }
5092
5093 /* For a MERGE command, initialize its state */
5096
5098
5099 /*
5100 * If there are a lot of result relations, use a hash table to speed the
5101 * lookups. If there are not a lot, a simple linear search is faster.
5102 *
5103 * It's not clear where the threshold is, but try 64 for starters. In a
5104 * debugging build, use a small threshold so that we get some test
5105 * coverage of both code paths.
5106 */
5107#ifdef USE_ASSERT_CHECKING
5108#define MT_NRELS_HASH 4
5109#else
5110#define MT_NRELS_HASH 64
5111#endif
5113 {
5115
5121 nrels, &hash_ctl,
5123 for (
i = 0;
i < nrels;
i++)
5124 {
5127 bool found;
5128
5136 }
5137 }
5138 else
5140
5141 /*
5142 * Determine if the FDW supports batch insert and determine the batch size
5143 * (a FDW may support batching, but it may be disabled for the
5144 * server/table).
5145 *
5146 * We only do this for INSERT, so that for UPDATE/DELETE the batch size
5147 * remains set to 0.
5148 */
5150 {
5151 /* insert may only have one relation, inheritance is not expanded */
5152 Assert(total_nrels == 1);
5158 {
5162 }
5163 else
5165 }
5166
5167 /*
5168 * Lastly, if this is not the primary (canSetTag) ModifyTable node, add it
5169 * to estate->es_auxmodifytables so that it will be run to completion by
5170 * ExecPostprocessPlan. (It'd actually work fine to add the primary
5171 * ModifyTable node too, but there's no need.) Note the use of lcons not
5172 * lappend: we need later-initialized ModifyTable nodes to be shut down
5173 * before earlier ones. This ensures that we don't throw away RETURNING
5174 * rows that need to be seen by a later CTE subplan.
5175 */
5179
5180 return mtstate;
5181}
#define AttributeNumberIsValid(attributeNumber)
bool bms_is_member(int x, const Bitmapset *a)
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
HTAB * hash_create(const char *tabname, int64 nelem, const HASHCTL *info, int flags)
ProjectionInfo * ExecBuildProjectionInfo(List *targetList, ExprContext *econtext, TupleTableSlot *slot, PlanState *parent, TupleDesc inputDesc)
ExprState * ExecInitQual(List *qual, PlanState *parent)
ProjectionInfo * ExecBuildUpdateProjection(List *targetList, bool evalTargetList, List *targetColnos, TupleDesc relDesc, ExprContext *econtext, TupleTableSlot *slot, PlanState *parent)
AttrNumber ExecFindJunkAttributeInTlist(List *targetlist, const char *attrName)
ExecRowMark * ExecFindRowMark(EState *estate, Index rti, bool missing_ok)
ExecAuxRowMark * ExecBuildAuxRowMark(ExecRowMark *erm, List *targetlist)
void CheckValidResultRel(ResultRelInfo *resultRelInfo, CmdType operation, OnConflictAction onConflictAction, List *mergeActions)
void EvalPlanQualInit(EPQState *epqstate, EState *parentestate, Plan *subplan, List *auxrowmarks, int epqParam, List *resultRelations)
void EvalPlanQualSetPlan(EPQState *epqstate, Plan *subplan, List *auxrowmarks)
PartitionTupleRouting * ExecSetupPartitionTupleRouting(EState *estate, Relation rel)
PlanState * ExecInitNode(Plan *node, EState *estate, int eflags)
const TupleTableSlotOps TTSOpsVirtual
void ExecInitResultTypeTL(PlanState *planstate)
void ExecInitResultTupleSlotTL(PlanState *planstate, const TupleTableSlotOps *tts_ops)
void ExecInitResultRelation(EState *estate, ResultRelInfo *resultRelInfo, Index rti)
void ExecAssignExprContext(EState *estate, PlanState *planstate)
#define EXEC_FLAG_BACKWARD
#define EXEC_FLAG_EXPLAIN_ONLY
List * lappend(List *list, void *datum)
List * lappend_int(List *list, int datum)
List * lcons(void *datum, List *list)
MemoryContext CurrentMemoryContext
static void ExecSetupTransitionCaptureState(ModifyTableState *mtstate, EState *estate)
static TupleTableSlot * ExecModifyTable(PlanState *pstate)
struct MTTargetRelLookup MTTargetRelLookup
static void ExecInitMerge(ModifyTableState *mtstate, EState *estate)
#define lfirst_node(type, lc)
static int list_length(const List *l)
static void * list_nth(const List *list, int n)
#define list_nth_node(type, list, n)
#define RelationGetRelid(relation)
Bitmapset * es_unpruned_relids
List * es_auxmodifytables
BeginForeignModify_function BeginForeignModify
ExecForeignBatchInsert_function ExecForeignBatchInsert
GetForeignModifyBatchSize_function GetForeignModifyBatchSize
List * mt_mergeJoinConditions
TupleTableSlot * mt_merge_pending_not_matched
List * mt_updateColnosLists
List * mt_mergeActionLists
ResultRelInfo * rootResultRelInfo
List * mergeJoinConditions
Bitmapset * fdwDirectModifyPlans
List * withCheckOptionLists
OnConflictAction onConflictAction
TupleTableSlot * oc_ProjSlot
TupleTableSlot * oc_Existing
ExprState * oc_WhereClause
ProjectionInfo * oc_ProjInfo
ExprContext * ps_ExprContext
TupleTableSlot * ps_ResultTupleSlot
ExecProcNodeMtd ExecProcNode
OnConflictSetState * ri_onConflict
List * ri_onConflictArbiterIndexes
struct ResultRelInfo * ri_RootResultRelInfo
List * ri_WithCheckOptions
List * ri_WithCheckOptionExprs
ProjectionInfo * ri_projectReturning