]> granicus.if.org Git - postgresql/commitdiff
Improve parse representation for MERGE
authorSimon Riggs <simon@2ndQuadrant.com>
Fri, 6 Apr 2018 08:38:59 +0000 (09:38 +0100)
committerSimon Riggs <simon@2ndQuadrant.com>
Fri, 6 Apr 2018 08:38:59 +0000 (09:38 +0100)
Separation of parser data structures from executor, as
requested by Tom Lane. Further improvements possible.

While there, implement error for multiple VALUES clauses via parser
to allow line number of error, as requested by Andres Freund.

Author: Pavan Deolasee

Discussion: https://www.postgresql.org/message-id/CABOikdPpqjectFchg0FyTOpsGXyPoqwgC==OLKWuxgBOsrDDZw@mail.gmail.com

src/backend/nodes/copyfuncs.c
src/backend/nodes/equalfuncs.c
src/backend/nodes/nodeFuncs.c
src/backend/nodes/outfuncs.c
src/backend/nodes/readfuncs.c
src/backend/parser/gram.y
src/backend/parser/parse_merge.c
src/backend/rewrite/rewriteHandler.c
src/include/nodes/nodes.h
src/include/nodes/parsenodes.h
src/test/regress/expected/merge.out

index c3efca3c452fa41e9156b7725ff16e797ee50d8a..d2e4aa3c2f4eb8a66f31d24f582b8c857e581567 100644 (file)
@@ -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);
index 45ceba28309cda185f369e14481eee8b049d4713..f2dd9035df5d5b79ec0e4e91b5fdb5e490084544 100644 (file)
@@ -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);
index 4157e7eb9a397b3afbe51fe65293794270383a33..f2f8227eb2ab15dc90386eddc789e5bdee4195b1 100644 (file)
@@ -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;
index c8d962670e2783a62079a5bba267d4076f1f75aa..a6a1c16164b3bde23214a9e55e79c85d8023f99c 100644 (file)
@@ -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;
index 4518fa0cdb7b6c698305aaf6c9eb9f8aa1913d61..37e35685956729c3bfb70e78c60c909e54d0c710 100644 (file)
@@ -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))
index 1592b58bb4703df0ce542b671057772181f60939..177906e083dc99a613acff3def796d7dd91088a0 100644 (file)
@@ -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;
                                }
                        ;
 
index eb4c615ce1c032b9047efd8a98576cb01bcce77c..722cb23b86c03877e7649468d3a26d4afc36e4ab 100644 (file)
@@ -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;
index 98239f569ae76809352c34295e972bfaa3bd66a5..cb4bcd58d1634aa0cae8d7b14e5d04ac125baa87 100644 (file)
@@ -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);
index fce48026b6d1d7ce8353e17efcfc1d24a96a72a7..b1e3d53f78f8d327396b83eb6304ab97272c172b 100644 (file)
@@ -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)
index 699fa77bc70919a703f7d000eb4e75b17c8cb1d4..06abb70e947e7f7dd272670db2cb0a8646d7f67a 100644 (file)
@@ -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;
 
 /* ----------------------
index 389eeedf2895a557986e52b6897e5bd2d61838f3..03e30ef55994ea633aad7da6c1350d1c6826ab24 100644 (file)
@@ -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