diff options
Diffstat (limited to 'src/backend/parser/parse_merge.c')
-rw-r--r-- | src/backend/parser/parse_merge.c | 86 |
1 files changed, 33 insertions, 53 deletions
diff --git a/src/backend/parser/parse_merge.c b/src/backend/parser/parse_merge.c index eb4c615ce1c..722cb23b86c 100644 --- a/src/backend/parser/parse_merge.c +++ b/src/backend/parser/parse_merge.c @@ -33,8 +33,8 @@ static int transformMergeJoinClause(ParseState *pstate, Node *merge, List **mergeSourceTargetList); -static void setNamespaceForMergeAction(ParseState *pstate, - MergeAction *action); +static void setNamespaceForMergeWhen(ParseState *pstate, + MergeWhenClause *mergeWhenClause); static void setNamespaceVisibilityForRTE(List *namespace, RangeTblEntry *rte, bool rel_visible, bool cols_visible); @@ -138,7 +138,7 @@ transformMergeJoinClause(ParseState *pstate, Node *merge, * that columns can be referenced unqualified from these relations. */ static void -setNamespaceForMergeAction(ParseState *pstate, MergeAction *action) +setNamespaceForMergeWhen(ParseState *pstate, MergeWhenClause *mergeWhenClause) { RangeTblEntry *targetRelRTE, *sourceRelRTE; @@ -152,7 +152,7 @@ setNamespaceForMergeAction(ParseState *pstate, MergeAction *action) */ sourceRelRTE = rt_fetch(list_length(pstate->p_rtable) - 1, pstate->p_rtable); - switch (action->commandType) + switch (mergeWhenClause->commandType) { case CMD_INSERT: @@ -198,6 +198,7 @@ transformMergeStmt(ParseState *pstate, MergeStmt *stmt) bool is_terminal[2]; JoinExpr *joinexpr; RangeTblEntry *resultRelRTE, *mergeRelRTE; + List *mergeActionList; /* There can't be any outer WITH to worry about */ Assert(pstate->p_ctenamespace == NIL); @@ -222,43 +223,18 @@ transformMergeStmt(ParseState *pstate, MergeStmt *stmt) */ is_terminal[0] = false; is_terminal[1] = false; - foreach(l, stmt->mergeActionList) + foreach(l, stmt->mergeWhenClauses) { - MergeAction *action = (MergeAction *) lfirst(l); - int when_type = (action->matched ? 0 : 1); + MergeWhenClause *mergeWhenClause = (MergeWhenClause *) lfirst(l); + int when_type = (mergeWhenClause->matched ? 0 : 1); /* * Collect action types so we can check Target permissions */ - switch (action->commandType) + switch (mergeWhenClause->commandType) { case CMD_INSERT: - { - InsertStmt *istmt = (InsertStmt *) action->stmt; - SelectStmt *selectStmt = (SelectStmt *) istmt->selectStmt; - - /* - * The grammar allows attaching ORDER BY, LIMIT, FOR - * UPDATE, or WITH to a VALUES clause and also multiple - * VALUES clauses. If we have any of those, ERROR. - */ - if (selectStmt && (selectStmt->valuesLists == NIL || - selectStmt->sortClause != NIL || - selectStmt->limitOffset != NULL || - selectStmt->limitCount != NULL || - selectStmt->lockingClause != NIL || - selectStmt->withClause != NULL)) - ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("SELECT not allowed in MERGE INSERT statement"))); - - if (selectStmt && list_length(selectStmt->valuesLists) > 1) - ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("Multiple VALUES clauses not allowed in MERGE INSERT statement"))); - - targetPerms |= ACL_INSERT; - } + targetPerms |= ACL_INSERT; break; case CMD_UPDATE: targetPerms |= ACL_UPDATE; @@ -275,7 +251,7 @@ transformMergeStmt(ParseState *pstate, MergeStmt *stmt) /* * Check for unreachable WHEN clauses */ - if (action->condition == NULL) + if (mergeWhenClause->condition == NULL) is_terminal[when_type] = true; else if (is_terminal[when_type]) ereport(ERROR, @@ -461,15 +437,20 @@ transformMergeStmt(ParseState *pstate, MergeStmt *stmt) * both of those already have RTEs. There is nothing like the EXCLUDED * pseudo-relation for INSERT ON CONFLICT. */ - foreach(l, stmt->mergeActionList) + mergeActionList = NIL; + foreach(l, stmt->mergeWhenClauses) { - MergeAction *action = (MergeAction *) lfirst(l); + MergeWhenClause *mergeWhenClause = (MergeWhenClause *) lfirst(l); + MergeAction *action = makeNode(MergeAction); + + action->commandType = mergeWhenClause->commandType; + action->matched = mergeWhenClause->matched; /* * Set namespace for the specific action. This must be done before * analyzing the WHEN quals and the action targetlisst. */ - setNamespaceForMergeAction(pstate, action); + setNamespaceForMergeWhen(pstate, mergeWhenClause); /* * Transform the when condition. @@ -478,7 +459,7 @@ transformMergeStmt(ParseState *pstate, MergeStmt *stmt) * are evaluated separately during execution to decide which of the * WHEN MATCHED or WHEN NOT MATCHED actions to execute. */ - action->qual = transformWhereClause(pstate, action->condition, + action->qual = transformWhereClause(pstate, mergeWhenClause->condition, EXPR_KIND_MERGE_WHEN_AND, "WHEN"); /* @@ -488,8 +469,6 @@ transformMergeStmt(ParseState *pstate, MergeStmt *stmt) { case CMD_INSERT: { - InsertStmt *istmt = (InsertStmt *) action->stmt; - SelectStmt *selectStmt = (SelectStmt *) istmt->selectStmt; List *exprList = NIL; ListCell *lc; RangeTblEntry *rte; @@ -500,13 +479,17 @@ transformMergeStmt(ParseState *pstate, MergeStmt *stmt) pstate->p_is_insert = true; - icolumns = checkInsertTargets(pstate, istmt->cols, &attrnos); + icolumns = checkInsertTargets(pstate, + mergeWhenClause->cols, + &attrnos); Assert(list_length(icolumns) == list_length(attrnos)); + action->override = mergeWhenClause->override; + /* * Handle INSERT much like in transformInsertStmt */ - if (selectStmt == NULL) + if (mergeWhenClause->values == NIL) { /* * We have INSERT ... DEFAULT VALUES. We can handle @@ -525,23 +508,19 @@ transformMergeStmt(ParseState *pstate, MergeStmt *stmt) * as the Query's targetlist, with no VALUES RTE. So * it works just like a SELECT without any FROM. */ - List *valuesLists = selectStmt->valuesLists; - - Assert(list_length(valuesLists) == 1); - Assert(selectStmt->intoClause == NULL); /* * Do basic expression transformation (same as a ROW() * expr, but allow SetToDefault at top level) */ exprList = transformExpressionList(pstate, - (List *) linitial(valuesLists), + mergeWhenClause->values, EXPR_KIND_VALUES_SINGLE, true); /* Prepare row for assignment to target table */ exprList = transformInsertRow(pstate, exprList, - istmt->cols, + mergeWhenClause->cols, icolumns, attrnos, false); } @@ -580,10 +559,9 @@ transformMergeStmt(ParseState *pstate, MergeStmt *stmt) break; case CMD_UPDATE: { - UpdateStmt *ustmt = (UpdateStmt *) action->stmt; - pstate->p_is_insert = false; - action->targetList = transformUpdateTargetList(pstate, ustmt->targetList); + action->targetList = transformUpdateTargetList(pstate, + mergeWhenClause->targetList); } break; case CMD_DELETE: @@ -595,9 +573,11 @@ transformMergeStmt(ParseState *pstate, MergeStmt *stmt) default: elog(ERROR, "unknown action in MERGE WHEN clause"); } + + mergeActionList = lappend(mergeActionList, action); } - qry->mergeActionList = stmt->mergeActionList; + qry->mergeActionList = mergeActionList; /* XXX maybe later */ qry->returningList = NULL; |