108{
114 List *mergeActionList;
116
117 /* There can't be any outer WITH to worry about */
119
121 qry->hasRecursive = false;
122
123 /* process the WITH clause independently of all else */
124 if (
stmt->withClause)
125 {
126 if (
stmt->withClause->recursive)
128 (
errcode(ERRCODE_SYNTAX_ERROR),
129 errmsg(
"WITH RECURSIVE is not supported for MERGE statement")));
130
133 }
134
135 /*
136 * Check WHEN clauses for permissions and sanity
137 */
141 foreach(l,
stmt->mergeWhenClauses)
142 {
144
145 /*
146 * Collect permissions to check, according to action types. We require
147 * SELECT privileges for DO NOTHING because it'd be irregular to have
148 * a target relation with zero privileges checked, in case DO NOTHING
149 * is the only action. There's no damage from that: any meaningful
150 * MERGE command requires at least some access to the table anyway.
151 */
153 {
156 break;
159 break;
162 break;
165 break;
166 default:
167 elog(
ERROR,
"unknown action in MERGE WHEN clause");
168 }
169
170 /*
171 * Check for unreachable WHEN clauses
172 */
173 if (is_terminal[mergeWhenClause->
matchKind])
175 (
errcode(ERRCODE_SYNTAX_ERROR),
176 errmsg(
"unreachable WHEN clause specified after unconditional WHEN clause")));
178 is_terminal[mergeWhenClause->
matchKind] =
true;
179 }
180
181 /*
182 * Set up the MERGE target table. The target table is added to the
183 * namespace below and to joinlist in transform_MERGE_to_join, so don't do
184 * it here.
185 *
186 * Initially mergeTargetRelation is the same as resultRelation, so data is
187 * read from the table being updated. However, that might be changed by
188 * the rewriter, if the target is a trigger-updatable view, to allow
189 * target data to be read from the expanded view query while updating the
190 * original view relation.
191 */
194 false, targetPerms);
195 qry->mergeTargetRelation = qry->resultRelation;
196
197 /* The target relation must be a table or a view */
202 (
errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
203 errmsg(
"cannot execute MERGE on relation \"%s\"",
206
207 /* Now transform the source relation to produce the source RTE. */
212
213 /*
214 * Check that the target table doesn't conflict with the source table.
215 * This would typically be a checkNameSpaceConflicts call, but we want a
216 * more specific error message.
217 */
221 errcode(ERRCODE_DUPLICATE_ALIAS),
222 errmsg(
"name \"%s\" specified more than once",
224 errdetail(
"The name is used both as MERGE target table and data source."));
225
226 /*
227 * There's no need for a targetlist here; it'll be set up by
228 * preprocess_targetlist later.
229 */
233
234 /*
235 * Transform the join condition. This includes references to the target
236 * side, so add that to the namespace.
237 */
241
242 /*
243 * Create the temporary query's jointree using the joinlist we built using
244 * just the source relation; the target relation is not included. The join
245 * will be constructed fully by transform_MERGE_to_join.
246 */
248
249 /* Transform the RETURNING list, if any */
252
253 /*
254 * We now have a good query shape, so now look at the WHEN conditions and
255 * action targetlists.
256 *
257 * Overall, the MERGE Query's targetlist is NIL.
258 *
259 * Each individual action has its own targetlist that needs separate
260 * transformation. These transforms don't do anything to the overall
261 * targetlist, since that is only used for resjunk columns.
262 *
263 * We can reference any column in Target or Source, which is OK because
264 * both of those already have RTEs. There is nothing like the EXCLUDED
265 * pseudo-relation for INSERT ON CONFLICT.
266 */
267 mergeActionList =
NIL;
268 foreach(l,
stmt->mergeWhenClauses)
269 {
272
276
277 /*
278 * Set namespace for the specific action. This must be done before
279 * analyzing the WHEN quals and the action targetlist.
280 */
282 qry->resultRelation,
283 sourceRTI);
284
285 /*
286 * Transform the WHEN condition.
287 *
288 * Note that these quals are NOT added to the join quals; instead they
289 * are evaluated separately during execution to decide which of the
290 * WHEN MATCHED or WHEN NOT MATCHED actions to execute.
291 */
294
295 /*
296 * Transform target lists for each INSERT and UPDATE action stmt
297 */
298 switch (
action->commandType)
299 {
301 {
309
311
314 &attrnos);
316
318
319 /*
320 * Handle INSERT much like in transformInsertStmt
321 */
323 {
324 /*
325 * We have INSERT ... DEFAULT VALUES. We can handle
326 * this case by emitting an empty targetlist --- all
327 * columns will be defaulted when the planner expands
328 * the targetlist.
329 */
331 }
332 else
333 {
334 /*
335 * Process INSERT ... VALUES with a single VALUES
336 * sublist. We treat this case separately for
337 * efficiency. The sublist is just computed directly
338 * as the Query's targetlist, with no VALUES RTE. So
339 * it works just like a SELECT without any FROM.
340 */
341
342 /*
343 * Do basic expression transformation (same as a ROW()
344 * expr, but allow SetToDefault at top level)
345 */
349 true);
350
351 /* Prepare row for assignment to target table */
354 icolumns, attrnos,
355 false);
356 }
357
358 /*
359 * Generate action's target list using the computed list
360 * of expressions. Also, mark all the target columns as
361 * needing insert permissions.
362 */
364 forthree(lc, exprList, icols, icolumns, attnos, attrnos)
365 {
370
372 attr_num,
374 false);
376
380 }
381 }
382 break;
384 {
389 }
390 break;
392 break;
393
396 break;
397 default:
398 elog(
ERROR,
"unknown action in MERGE WHEN clause");
399 }
400
402 }
403
405
406 qry->hasTargetSRFs = false;
408
410
411 return qry;
412}
Bitmapset * bms_add_member(Bitmapset *a, int x)
int errdetail(const char *fmt,...)
int errcode(int sqlerrcode)
int errmsg(const char *fmt,...)
#define ereport(elevel,...)
List * lappend(List *list, void *datum)
FromExpr * makeFromExpr(List *fromlist, Node *quals)
TargetEntry * makeTargetEntry(Expr *expr, AttrNumber resno, char *resname, bool resjunk)
Node * transformWhereClause(ParseState *pstate, Node *clause, ParseExprKind exprKind, const char *constructName)
void transformFromClause(ParseState *pstate, List *frmList)
int setTargetTable(ParseState *pstate, RangeVar *relation, bool inh, bool alsoSource, AclMode requiredPerms)
void assign_query_collations(ParseState *pstate, Query *query)
List * transformWithClause(ParseState *pstate, WithClause *withClause)
Node * transformExpr(ParseState *pstate, Node *expr, ParseExprKind exprKind)
static void setNamespaceForMergeWhen(ParseState *pstate, MergeWhenClause *mergeWhenClause, Index targetRTI, Index sourceRTI)
@ EXPR_KIND_MERGE_RETURNING
@ EXPR_KIND_VALUES_SINGLE
void addNSItemToQuery(ParseState *pstate, ParseNamespaceItem *nsitem, bool addToJoinList, bool addToRelNameSpace, bool addToVarNameSpace)
ParseNamespaceItem * GetNSItemByRangeTablePosn(ParseState *pstate, int varno, int sublevels_up)
List * transformExpressionList(ParseState *pstate, List *exprlist, ParseExprKind exprKind, bool allowDefault)
List * checkInsertTargets(ParseState *pstate, List *cols, List **attrnos)
List * transformInsertRow(ParseState *pstate, List *exprlist, List *stmtcols, List *icolumns, List *attrnos, bool strip_indirection)
void transformReturningClause(ParseState *pstate, Query *qry, ReturningClause *returningClause, ParseExprKind exprKind)
List * transformUpdateTargetList(ParseState *pstate, List *origTlist)
int errdetail_relkind_not_supported(char relkind)
#define lfirst_node(type, lc)
static int list_length(const List *l)
#define forthree(cell1, list1, cell2, list2, cell3, list3)
#define NUM_MERGE_MATCH_KINDS
@ MERGE_WHEN_NOT_MATCHED_BY_TARGET
#define RelationGetRelationName(relation)
RTEPermissionInfo * p_perminfo
ParseNamespaceItem * p_target_nsitem
Relation p_target_relation
Node * mergeJoinCondition
#define FirstLowInvalidHeapAttributeNumber