diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c index c3efca3c45..d2e4aa3c2f 100644 --- a/src/backend/nodes/copyfuncs.c +++ b/src/backend/nodes/copyfuncs.c @@ -2136,6 +2136,20 @@ _copyOnConflictExpr(const OnConflictExpr *from) return newnode; } +static MergeAction * +_copyMergeAction(const MergeAction *from) +{ + MergeAction *newnode = makeNode(MergeAction); + + COPY_SCALAR_FIELD(matched); + COPY_SCALAR_FIELD(commandType); + COPY_SCALAR_FIELD(override); + COPY_NODE_FIELD(qual); + COPY_NODE_FIELD(targetList); + + return newnode; +} + /* **************************************************************** * relation.h copy functions * @@ -3054,24 +3068,24 @@ _copyMergeStmt(const MergeStmt *from) COPY_NODE_FIELD(relation); COPY_NODE_FIELD(source_relation); COPY_NODE_FIELD(join_condition); - COPY_NODE_FIELD(mergeActionList); + COPY_NODE_FIELD(mergeWhenClauses); COPY_NODE_FIELD(withClause); return newnode; } -static MergeAction * -_copyMergeAction(const MergeAction *from) +static MergeWhenClause * +_copyMergeWhenClause(const MergeWhenClause *from) { - MergeAction *newnode = makeNode(MergeAction); + MergeWhenClause *newnode = makeNode(MergeWhenClause); COPY_SCALAR_FIELD(matched); COPY_SCALAR_FIELD(commandType); COPY_NODE_FIELD(condition); - COPY_NODE_FIELD(qual); - COPY_NODE_FIELD(stmt); COPY_NODE_FIELD(targetList); - + COPY_NODE_FIELD(cols); + COPY_NODE_FIELD(values); + COPY_SCALAR_FIELD(override); return newnode; } @@ -5059,6 +5073,9 @@ copyObjectImpl(const void *from) case T_OnConflictExpr: retval = _copyOnConflictExpr(from); break; + case T_MergeAction: + retval = _copyMergeAction(from); + break; /* * RELATION NODES @@ -5140,8 +5157,8 @@ copyObjectImpl(const void *from) case T_MergeStmt: retval = _copyMergeStmt(from); break; - case T_MergeAction: - retval = _copyMergeAction(from); + case T_MergeWhenClause: + retval = _copyMergeWhenClause(from); break; case T_SelectStmt: retval = _copySelectStmt(from); diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c index 45ceba2830..f2dd9035df 100644 --- a/src/backend/nodes/equalfuncs.c +++ b/src/backend/nodes/equalfuncs.c @@ -812,6 +812,18 @@ _equalOnConflictExpr(const OnConflictExpr *a, const OnConflictExpr *b) return true; } + +static bool +_equalMergeAction(const MergeAction *a, const MergeAction *b) +{ + COMPARE_SCALAR_FIELD(matched); + COMPARE_SCALAR_FIELD(commandType); + COMPARE_SCALAR_FIELD(override); + COMPARE_NODE_FIELD(qual); + COMPARE_NODE_FIELD(targetList); + + return true; +} /* * Stuff from relation.h */ @@ -1050,21 +1062,22 @@ _equalMergeStmt(const MergeStmt *a, const MergeStmt *b) COMPARE_NODE_FIELD(relation); COMPARE_NODE_FIELD(source_relation); COMPARE_NODE_FIELD(join_condition); - COMPARE_NODE_FIELD(mergeActionList); + COMPARE_NODE_FIELD(mergeWhenClauses); COMPARE_NODE_FIELD(withClause); return true; } static bool -_equalMergeAction(const MergeAction *a, const MergeAction *b) +_equalMergeWhenClause(const MergeWhenClause *a, const MergeWhenClause *b) { COMPARE_SCALAR_FIELD(matched); COMPARE_SCALAR_FIELD(commandType); COMPARE_NODE_FIELD(condition); - COMPARE_NODE_FIELD(qual); - COMPARE_NODE_FIELD(stmt); COMPARE_NODE_FIELD(targetList); + COMPARE_NODE_FIELD(cols); + COMPARE_NODE_FIELD(values); + COMPARE_SCALAR_FIELD(override); return true; } @@ -3192,6 +3205,9 @@ equal(const void *a, const void *b) case T_OnConflictExpr: retval = _equalOnConflictExpr(a, b); break; + case T_MergeAction: + retval = _equalMergeAction(a, b); + break; case T_JoinExpr: retval = _equalJoinExpr(a, b); break; @@ -3263,8 +3279,8 @@ equal(const void *a, const void *b) case T_MergeStmt: retval = _equalMergeStmt(a, b); break; - case T_MergeAction: - retval = _equalMergeAction(a, b); + case T_MergeWhenClause: + retval = _equalMergeWhenClause(a, b); break; case T_SelectStmt: retval = _equalSelectStmt(a, b); diff --git a/src/backend/nodes/nodeFuncs.c b/src/backend/nodes/nodeFuncs.c index 4157e7eb9a..f2f8227eb2 100644 --- a/src/backend/nodes/nodeFuncs.c +++ b/src/backend/nodes/nodeFuncs.c @@ -3444,19 +3444,23 @@ raw_expression_tree_walker(Node *node, return true; if (walker(stmt->join_condition, context)) return true; - if (walker(stmt->mergeActionList, context)) + if (walker(stmt->mergeWhenClauses, context)) return true; if (walker(stmt->withClause, context)) return true; } break; - case T_MergeAction: + case T_MergeWhenClause: { - MergeAction *action = (MergeAction *) node; + MergeWhenClause *mergeWhenClause = (MergeWhenClause *) node; - if (walker(action->targetList, context)) + if (walker(mergeWhenClause->condition, context)) return true; - if (walker(action->qual, context)) + if (walker(mergeWhenClause->targetList, context)) + return true; + if (walker(mergeWhenClause->cols, context)) + return true; + if (walker(mergeWhenClause->values, context)) return true; } break; diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c index c8d962670e..a6a1c16164 100644 --- a/src/backend/nodes/outfuncs.c +++ b/src/backend/nodes/outfuncs.c @@ -396,16 +396,17 @@ _outModifyTable(StringInfo str, const ModifyTable *node) } static void -_outMergeAction(StringInfo str, const MergeAction *node) +_outMergeWhenClause(StringInfo str, const MergeWhenClause *node) { - WRITE_NODE_TYPE("MERGEACTION"); + WRITE_NODE_TYPE("MERGEWHENCLAUSE"); WRITE_BOOL_FIELD(matched); WRITE_ENUM_FIELD(commandType, CmdType); WRITE_NODE_FIELD(condition); - WRITE_NODE_FIELD(qual); - WRITE_NODE_FIELD(stmt); WRITE_NODE_FIELD(targetList); + WRITE_NODE_FIELD(cols); + WRITE_NODE_FIELD(values); + WRITE_ENUM_FIELD(override, OverridingKind); } static void @@ -1724,6 +1725,17 @@ _outOnConflictExpr(StringInfo str, const OnConflictExpr *node) WRITE_NODE_FIELD(exclRelTlist); } +static void +_outMergeAction(StringInfo str, const MergeAction *node) +{ + WRITE_NODE_TYPE("MERGEACTION"); + + WRITE_BOOL_FIELD(matched); + WRITE_ENUM_FIELD(commandType, CmdType); + WRITE_NODE_FIELD(qual); + WRITE_NODE_FIELD(targetList); +} + /***************************************************************************** * * Stuff from relation.h. @@ -3679,8 +3691,8 @@ outNode(StringInfo str, const void *obj) case T_ModifyTable: _outModifyTable(str, obj); break; - case T_MergeAction: - _outMergeAction(str, obj); + case T_MergeWhenClause: + _outMergeWhenClause(str, obj); break; case T_Append: _outAppend(str, obj); @@ -3958,6 +3970,9 @@ outNode(StringInfo str, const void *obj) case T_OnConflictExpr: _outOnConflictExpr(str, obj); break; + case T_MergeAction: + _outMergeAction(str, obj); + break; case T_Path: _outPath(str, obj); break; diff --git a/src/backend/nodes/readfuncs.c b/src/backend/nodes/readfuncs.c index 4518fa0cdb..37e3568595 100644 --- a/src/backend/nodes/readfuncs.c +++ b/src/backend/nodes/readfuncs.c @@ -1331,6 +1331,22 @@ _readOnConflictExpr(void) READ_DONE(); } +/* + * _readMergeAction + */ +static MergeAction * +_readMergeAction(void) +{ + READ_LOCALS(MergeAction); + + READ_BOOL_FIELD(matched); + READ_ENUM_FIELD(commandType, CmdType); + READ_NODE_FIELD(qual); + READ_NODE_FIELD(targetList); + + READ_DONE(); +} + /* * Stuff from parsenodes.h. */ @@ -1602,19 +1618,20 @@ _readModifyTable(void) } /* - * _readMergeAction + * _readMergeWhenClause */ -static MergeAction * -_readMergeAction(void) +static MergeWhenClause * +_readMergeWhenClause(void) { - READ_LOCALS(MergeAction); + READ_LOCALS(MergeWhenClause); READ_BOOL_FIELD(matched); READ_ENUM_FIELD(commandType, CmdType); READ_NODE_FIELD(condition); - READ_NODE_FIELD(qual); - READ_NODE_FIELD(stmt); READ_NODE_FIELD(targetList); + READ_NODE_FIELD(cols); + READ_NODE_FIELD(values); + READ_ENUM_FIELD(override, OverridingKind); READ_DONE(); } @@ -2596,6 +2613,8 @@ parseNodeString(void) return_value = _readFromExpr(); else if (MATCH("ONCONFLICTEXPR", 14)) return_value = _readOnConflictExpr(); + else if (MATCH("MERGEACTION", 11)) + return_value = _readMergeAction(); else if (MATCH("RTE", 3)) return_value = _readRangeTblEntry(); else if (MATCH("RANGETBLFUNCTION", 16)) @@ -2618,8 +2637,8 @@ parseNodeString(void) return_value = _readProjectSet(); else if (MATCH("MODIFYTABLE", 11)) return_value = _readModifyTable(); - else if (MATCH("MERGEACTION", 11)) - return_value = _readMergeAction(); + else if (MATCH("MERGEWHENCLAUSE", 15)) + return_value = _readMergeWhenClause(); else if (MATCH("APPEND", 6)) return_value = _readAppend(); else if (MATCH("MERGEAPPEND", 11)) diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index 1592b58bb4..177906e083 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 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 group_by_list %type group_by_item empty_grouping_set rollup_clause cube_clause @@ -460,6 +462,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query); %type insert_rest %type opt_conf_expr %type opt_on_conflict +%type merge_insert merge_update merge_delete %type 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 merge_when_clause opt_merge_when_and_condition %type merge_when_list -%type 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 eb4c615ce1..722cb23b86 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; diff --git a/src/backend/rewrite/rewriteHandler.c b/src/backend/rewrite/rewriteHandler.c index 98239f569a..cb4bcd58d1 100644 --- a/src/backend/rewrite/rewriteHandler.c +++ b/src/backend/rewrite/rewriteHandler.c @@ -3417,12 +3417,10 @@ RewriteQuery(Query *parsetree, List *rewrite_events) break; case CMD_INSERT: { - InsertStmt *istmt = (InsertStmt *) action->stmt; - action->targetList = rewriteTargetListIU(action->targetList, action->commandType, - istmt->override, + action->override, rt_entry_relation, parsetree->resultRelation, NULL); diff --git a/src/include/nodes/nodes.h b/src/include/nodes/nodes.h index fce48026b6..b1e3d53f78 100644 --- a/src/include/nodes/nodes.h +++ b/src/include/nodes/nodes.h @@ -269,6 +269,7 @@ typedef enum NodeTag T_RollupData, T_GroupingSetData, T_StatisticExtInfo, + T_MergeAction, /* * TAGS FOR MEMORY NODES (memnodes.h) @@ -310,7 +311,6 @@ typedef enum NodeTag T_DeleteStmt, T_UpdateStmt, T_MergeStmt, - T_MergeAction, T_SelectStmt, T_AlterTableStmt, T_AlterTableCmd, @@ -475,6 +475,7 @@ typedef enum NodeTag T_PartitionRangeDatum, T_PartitionCmd, T_VacuumRelation, + T_MergeWhenClause, /* * TAGS FOR REPLICATION GRAMMAR PARSE NODES (replnodes.h) diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h index 699fa77bc7..06abb70e94 100644 --- a/src/include/nodes/parsenodes.h +++ b/src/include/nodes/parsenodes.h @@ -1518,19 +1518,34 @@ typedef struct MergeStmt RangeVar *relation; /* target relation to merge into */ Node *source_relation; /* source relation */ Node *join_condition; /* join condition between source and target */ - List *mergeActionList; /* list of MergeAction(s) */ + List *mergeWhenClauses; /* list of MergeWhenClause(es) */ WithClause *withClause; /* WITH clause */ } MergeStmt; -typedef struct MergeAction +typedef struct MergeWhenClause { NodeTag type; bool matched; /* true=MATCHED, false=NOT MATCHED */ - Node *condition; /* WHEN AND conditions (raw parser) */ - Node *qual; /* transformed WHEN AND conditions */ CmdType commandType; /* INSERT/UPDATE/DELETE/DO NOTHING */ - Node *stmt; /* T_UpdateStmt etc */ - List *targetList; /* the target list (of ResTarget) */ + Node *condition; /* WHEN AND conditions (raw parser) */ + List *targetList; /* INSERT/UPDATE targetlist */ + /* the following members are only useful for INSERT action */ + List *cols; /* optional: names of the target columns */ + List *values; /* VALUES to INSERT, or NULL */ + OverridingKind override; /* OVERRIDING clause */ +} MergeWhenClause; + +/* + * WHEN [NOT] MATCHED THEN action info + */ +typedef struct MergeAction +{ + NodeTag type; + bool matched; /* true=MATCHED, false=NOT MATCHED */ + OverridingKind override; /* OVERRIDING clause */ + Node *qual; /* transformed WHEN AND conditions */ + CmdType commandType; /* INSERT/UPDATE/DELETE/DO NOTHING */ + List *targetList; /* the target list (of ResTarget) */ } MergeAction; /* ---------------------- diff --git a/src/test/regress/expected/merge.out b/src/test/regress/expected/merge.out index 389eeedf28..03e30ef559 100644 --- a/src/test/regress/expected/merge.out +++ b/src/test/regress/expected/merge.out @@ -90,7 +90,9 @@ USING source AS s ON t.tid = s.sid WHEN NOT MATCHED THEN INSERT VALUES (1,1), (2,2); -ERROR: Multiple VALUES clauses not allowed in MERGE INSERT statement +ERROR: syntax error at or near "," +LINE 5: INSERT VALUES (1,1), (2,2); + ^ ; -- SELECT query for INSERT MERGE INTO target t