diff options
Diffstat (limited to 'src/backend/parser')
-rw-r--r-- | src/backend/parser/gram.y | 92 | ||||
-rw-r--r-- | src/backend/parser/parse_merge.c | 86 |
2 files changed, 75 insertions, 103 deletions
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index 1592b58bb47..177906e083d 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -241,6 +241,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query); PartitionSpec *partspec; PartitionBoundSpec *partboundspec; RoleSpec *rolespec; + MergeWhenClause *mergewhen; } %type <node> stmt schema_stmt @@ -400,6 +401,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query); TriggerTransitions TriggerReferencing publication_name_list vacuum_relation_list opt_vacuum_relation_list + merge_values_clause %type <list> group_by_list %type <node> group_by_item empty_grouping_set rollup_clause cube_clause @@ -460,6 +462,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query); %type <istmt> insert_rest %type <infer> opt_conf_expr %type <onconflict> opt_on_conflict +%type <mergewhen> merge_insert merge_update merge_delete %type <vsetstmt> generic_set set_rest set_rest_more generic_reset reset_rest SetResetClause FunctionSetResetClause @@ -587,7 +590,6 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query); %type <node> merge_when_clause opt_merge_when_and_condition %type <list> merge_when_list -%type <node> merge_update merge_delete merge_insert /* * Non-keyword token types. These are hard-wired into the "flex" lexer. @@ -11116,7 +11118,7 @@ MergeStmt: m->relation = $4; m->source_relation = $6; m->join_condition = $8; - m->mergeActionList = $9; + m->mergeWhenClauses = $9; $$ = (Node *)m; } @@ -11131,45 +11133,37 @@ merge_when_list: merge_when_clause: WHEN MATCHED opt_merge_when_and_condition THEN merge_update { - MergeAction *m = makeNode(MergeAction); + $5->matched = true; + $5->commandType = CMD_UPDATE; + $5->condition = $3; - m->matched = true; - m->commandType = CMD_UPDATE; - m->condition = $3; - m->stmt = $5; - - $$ = (Node *)m; + $$ = (Node *) $5; } | WHEN MATCHED opt_merge_when_and_condition THEN merge_delete { - MergeAction *m = makeNode(MergeAction); + MergeWhenClause *m = makeNode(MergeWhenClause); m->matched = true; m->commandType = CMD_DELETE; m->condition = $3; - m->stmt = $5; $$ = (Node *)m; } | WHEN NOT MATCHED opt_merge_when_and_condition THEN merge_insert { - MergeAction *m = makeNode(MergeAction); + $6->matched = false; + $6->commandType = CMD_INSERT; + $6->condition = $4; - m->matched = false; - m->commandType = CMD_INSERT; - m->condition = $4; - m->stmt = $6; - - $$ = (Node *)m; + $$ = (Node *) $6; } | WHEN NOT MATCHED opt_merge_when_and_condition THEN DO NOTHING { - MergeAction *m = makeNode(MergeAction); + MergeWhenClause *m = makeNode(MergeWhenClause); m->matched = false; m->commandType = CMD_NOTHING; m->condition = $4; - m->stmt = NULL; $$ = (Node *)m; } @@ -11181,65 +11175,63 @@ opt_merge_when_and_condition: ; merge_delete: - DELETE_P - { - DeleteStmt *n = makeNode(DeleteStmt); - $$ = (Node *)n; - } + DELETE_P { $$ = NULL; } ; merge_update: UPDATE SET set_clause_list { - UpdateStmt *n = makeNode(UpdateStmt); + MergeWhenClause *n = makeNode(MergeWhenClause); n->targetList = $3; - $$ = (Node *)n; + $$ = n; } ; merge_insert: - INSERT values_clause + INSERT merge_values_clause { - InsertStmt *n = makeNode(InsertStmt); + MergeWhenClause *n = makeNode(MergeWhenClause); n->cols = NIL; - n->selectStmt = $2; - - $$ = (Node *)n; + n->values = $2; + $$ = n; } - | INSERT OVERRIDING override_kind VALUE_P values_clause + | INSERT OVERRIDING override_kind VALUE_P merge_values_clause { - InsertStmt *n = makeNode(InsertStmt); + MergeWhenClause *n = makeNode(MergeWhenClause); n->cols = NIL; n->override = $3; - n->selectStmt = $5; - - $$ = (Node *)n; + n->values = $5; + $$ = n; } - | INSERT '(' insert_column_list ')' values_clause + | INSERT '(' insert_column_list ')' merge_values_clause { - InsertStmt *n = makeNode(InsertStmt); + MergeWhenClause *n = makeNode(MergeWhenClause); n->cols = $3; - n->selectStmt = $5; - - $$ = (Node *)n; + n->values = $5; + $$ = n; } - | INSERT '(' insert_column_list ')' OVERRIDING override_kind VALUE_P values_clause + | INSERT '(' insert_column_list ')' OVERRIDING override_kind VALUE_P merge_values_clause { - InsertStmt *n = makeNode(InsertStmt); + MergeWhenClause *n = makeNode(MergeWhenClause); n->cols = $3; n->override = $6; - n->selectStmt = $8; - - $$ = (Node *)n; + n->values = $8; + $$ = n; } | INSERT DEFAULT VALUES { - InsertStmt *n = makeNode(InsertStmt); + MergeWhenClause *n = makeNode(MergeWhenClause); n->cols = NIL; - n->selectStmt = NULL; + n->values = NIL; + $$ = n; + } + ; - $$ = (Node *)n; +merge_values_clause: + VALUES '(' expr_list ')' + { + $$ = $3; } ; 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; |