On 17.03.22 12:31, Alvaro Herrera wrote:
0001 pushed.  Here's 0002 again for cfbot, with no changes other than
pgindent cleanup.

I did a cursory read through and want to offer some trivial amendments in the attached patches. The 0001 adds back various serial commas, the 0002 is assorted other stuff.

One functional change I recommend is the tab completion of the MERGE target. I think the filtering in Query_for_list_of_mergetargets is a bit too particular. For example, if a table is a possible MERGE target, and then someone adds a rule, it will disappear from the completions, without explanation, which could be confusing. I think we can be generous in what we accept and then let the actual parse analysis provide suitable error messages. Also, consider forward-compatibility if support for further targets is added. I would consider dropping Query_for_list_of_mergetargets and just using Query_for_list_of_updatables.

In any case, the min_server_version could be dropped. That is usually only used if the query would fail in an older version, but not if the command being completed wouldn't work. For example, we don't restrict in what versions you can complete partitioned indexes.
From 18ad74bfc2b6d1a758eaab9d2332532f6abb074d Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <pe...@eisentraut.org>
Date: Fri, 18 Mar 2022 11:44:16 +0100
Subject: [PATCH 1/2] fixup! MERGE SQL Command following SQL:2016

Add back serial commas.
---
 doc/src/sgml/libpq.sgml             | 2 +-
 doc/src/sgml/mvcc.sgml              | 2 +-
 doc/src/sgml/ref/create_policy.sgml | 2 +-
 doc/src/sgml/ref/insert.sgml        | 2 +-
 doc/src/sgml/ref/merge.sgml         | 6 +++---
 doc/src/sgml/trigger.sgml           | 2 +-
 src/include/nodes/execnodes.h       | 2 +-
 src/include/nodes/pathnodes.h       | 2 +-
 src/include/nodes/plannodes.h       | 2 +-
 9 files changed, 11 insertions(+), 11 deletions(-)

diff --git a/doc/src/sgml/libpq.sgml b/doc/src/sgml/libpq.sgml
index 5fcfb29a55..70233aa872 100644
--- a/doc/src/sgml/libpq.sgml
+++ b/doc/src/sgml/libpq.sgml
@@ -4128,7 +4128,7 @@ <title>Retrieving Other Result Information</title>
        <command>MERGE</command>, <command>MOVE</command>, 
<command>FETCH</command>,
        or <command>COPY</command> statement, or an <command>EXECUTE</command> 
of a
        prepared query that contains an <command>INSERT</command>,
-       <command>UPDATE</command>, <command>DELETE</command>
+       <command>UPDATE</command>, <command>DELETE</command>,
        or <command>MERGE</command> statement.
        If the command that generated the <structname>PGresult</structname> was 
anything
        else, <xref linkend="libpq-PQcmdTuples"/> returns an empty string. The 
caller
diff --git a/doc/src/sgml/mvcc.sgml b/doc/src/sgml/mvcc.sgml
index 62451d297b..9b3061c03d 100644
--- a/doc/src/sgml/mvcc.sgml
+++ b/doc/src/sgml/mvcc.sgml
@@ -955,7 +955,7 @@ <title>Table-Level Lock Modes</title>
 
         <para>
          The commands <command>UPDATE</command>,
-         <command>DELETE</command>, <command>INSERT</command> and
+         <command>DELETE</command>, <command>INSERT</command>, and
          <command>MERGE</command>
          acquire this lock mode on the target table (in addition to
          <literal>ACCESS SHARE</literal> locks on any other referenced
diff --git a/doc/src/sgml/ref/create_policy.sgml 
b/doc/src/sgml/ref/create_policy.sgml
index f45882814d..c8ecc06347 100644
--- a/doc/src/sgml/ref/create_policy.sgml
+++ b/doc/src/sgml/ref/create_policy.sgml
@@ -619,7 +619,7 @@ <title>Notes</title>
   <para>
    No separate policy exists for <command>MERGE</command>. Instead, the 
policies
    defined for <command>SELECT</command>, <command>INSERT</command>,
-   <command>UPDATE</command> and <command>DELETE</command> are applied
+   <command>UPDATE</command>, and <command>DELETE</command> are applied
    while executing <command>MERGE</command>, depending on the actions that are
    performed.
   </para>
diff --git a/doc/src/sgml/ref/insert.sgml b/doc/src/sgml/ref/insert.sgml
index ad61d757af..41cafc8455 100644
--- a/doc/src/sgml/ref/insert.sgml
+++ b/doc/src/sgml/ref/insert.sgml
@@ -592,7 +592,7 @@ <title>Notes</title>
 
   <para>
    You may also wish to consider using <command>MERGE</command>, since that
-   allows mixing <command>INSERT</command>, <command>UPDATE</command> and
+   allows mixing <command>INSERT</command>, <command>UPDATE</command>, and
    <command>DELETE</command> within a single statement.
    See <xref linkend="sql-merge"/>.
   </para>
diff --git a/doc/src/sgml/ref/merge.sgml b/doc/src/sgml/ref/merge.sgml
index 73778666e9..3a1823ceed 100644
--- a/doc/src/sgml/ref/merge.sgml
+++ b/doc/src/sgml/ref/merge.sgml
@@ -118,8 +118,8 @@ <title>Description</title>
   <para>
    <command>MERGE</command> is not supported if the
    <replaceable class="parameter">target_table_name</replaceable> is a
-   materialized view, foreign table or if it has any
-   <literal>RULEs</literal> defined on it.
+   materialized view, foreign table, or if it has any
+   rules defined on it.
   </para>
  </refsect1>
 
@@ -153,7 +153,7 @@ <title>Parameters</title>
     <term><replaceable class="parameter">source_table_name</replaceable></term>
     <listitem>
      <para>
-      The name (optionally schema-qualified) of the source table, view or
+      The name (optionally schema-qualified) of the source table, view, or
       transition table.
      </para>
     </listitem>
diff --git a/doc/src/sgml/trigger.sgml b/doc/src/sgml/trigger.sgml
index 2662be243f..04e702a795 100644
--- a/doc/src/sgml/trigger.sgml
+++ b/doc/src/sgml/trigger.sgml
@@ -195,7 +195,7 @@ <title>Overview of Trigger Behavior</title>
    <para>
     No separate triggers are defined for <command>MERGE</command>. Instead,
     statement-level or row-level <command>UPDATE</command>,
-    <command>DELETE</command> and <command>INSERT</command> triggers are fired
+    <command>DELETE</command>, and <command>INSERT</command> triggers are fired
     depending on (for statement-level triggers) what actions are specified in
     the <command>MERGE</command> query and (for row-level triggers) what
     actions are performed.
diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h
index 84e3ebf7a6..11e295890c 100644
--- a/src/include/nodes/execnodes.h
+++ b/src/include/nodes/execnodes.h
@@ -1222,7 +1222,7 @@ typedef struct ProjectSetState
 typedef struct ModifyTableState
 {
        PlanState       ps;                             /* its first field is 
NodeTag */
-       CmdType         operation;              /* INSERT, UPDATE, DELETE or 
MERGE */
+       CmdType         operation;              /* INSERT, UPDATE, DELETE, or 
MERGE */
        bool            canSetTag;              /* do we set the command 
tag/es_processed? */
        bool            mt_done;                /* are we done? */
        int                     mt_nrels;               /* number of entries in 
resultRelInfo[] */
diff --git a/src/include/nodes/pathnodes.h b/src/include/nodes/pathnodes.h
index 1092c87434..365000bdcd 100644
--- a/src/include/nodes/pathnodes.h
+++ b/src/include/nodes/pathnodes.h
@@ -1885,7 +1885,7 @@ typedef struct ModifyTablePath
 {
        Path            path;
        Path       *subpath;            /* Path producing source data */
-       CmdType         operation;              /* INSERT, UPDATE, DELETE or 
MERGE */
+       CmdType         operation;              /* INSERT, UPDATE, DELETE, or 
MERGE */
        bool            canSetTag;              /* do we set the command 
tag/es_processed? */
        Index           nominalRelation;        /* Parent RT index for use of 
EXPLAIN */
        Index           rootRelation;   /* Root RT index, if target is 
partitioned */
diff --git a/src/include/nodes/plannodes.h b/src/include/nodes/plannodes.h
index aa712cea71..50ef3dda05 100644
--- a/src/include/nodes/plannodes.h
+++ b/src/include/nodes/plannodes.h
@@ -218,7 +218,7 @@ typedef struct ProjectSet
 typedef struct ModifyTable
 {
        Plan            plan;
-       CmdType         operation;              /* INSERT, UPDATE, DELETE or 
MERGE */
+       CmdType         operation;              /* INSERT, UPDATE, DELETE, or 
MERGE */
        bool            canSetTag;              /* do we set the command 
tag/es_processed? */
        Index           nominalRelation;        /* Parent RT index for use of 
EXPLAIN */
        Index           rootRelation;   /* Root RT index, if target is 
partitioned */
-- 
2.35.1

From 2cbb5a9c55e9316a7f26fdbcd0d056feff15c86f Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <pe...@eisentraut.org>
Date: Fri, 18 Mar 2022 12:04:20 +0100
Subject: [PATCH 2/2] fixup! MERGE SQL Command following SQL:2016

---
 doc/src/sgml/mvcc.sgml                 |  2 +-
 doc/src/sgml/ref/insert.sgml           |  2 +-
 doc/src/sgml/ref/merge.sgml            | 36 ++++++++++++--------------
 src/backend/catalog/sql_features.txt   |  2 +-
 src/backend/executor/README            |  2 +-
 src/backend/executor/nodeModifyTable.c |  6 ++---
 src/backend/parser/gram.y              | 24 ++++++++---------
 src/backend/parser/parse_merge.c       |  2 +-
 src/bin/psql/tab-complete.c            | 19 +++++---------
 9 files changed, 42 insertions(+), 53 deletions(-)

diff --git a/doc/src/sgml/mvcc.sgml b/doc/src/sgml/mvcc.sgml
index 9b3061c03d..db86326aef 100644
--- a/doc/src/sgml/mvcc.sgml
+++ b/doc/src/sgml/mvcc.sgml
@@ -450,7 +450,7 @@ <title>Read Committed Isolation Level</title>
     and a unique index is present and a duplicate row is concurrently
     inserted, then a uniqueness violation is raised.
     <command>MERGE</command> does not attempt to avoid the
-    <literal>ERROR</literal> by executing an <command>UPDATE</command>.
+    error by executing an <command>UPDATE</command>.
    </para>
 
    <para>
diff --git a/doc/src/sgml/ref/insert.sgml b/doc/src/sgml/ref/insert.sgml
index 41cafc8455..a9af9959c0 100644
--- a/doc/src/sgml/ref/insert.sgml
+++ b/doc/src/sgml/ref/insert.sgml
@@ -766,7 +766,7 @@ <title>Compatibility</title>
    Also, the case in
    which a column name list is omitted, but not all the columns are
    filled from the <literal>VALUES</literal> clause or 
<replaceable>query</replaceable>,
-   is disallowed by the standard. If you prefer a more SQL Standard
+   is disallowed by the standard. If you prefer a more SQL standard
    conforming statement than <literal>ON CONFLICT</literal>, see
    <xref linkend="sql-merge"/>.
   </para>
diff --git a/doc/src/sgml/ref/merge.sgml b/doc/src/sgml/ref/merge.sgml
index 3a1823ceed..8d1d160e02 100644
--- a/doc/src/sgml/ref/merge.sgml
+++ b/doc/src/sgml/ref/merge.sgml
@@ -13,7 +13,7 @@
 
  <refnamediv>
   <refname>MERGE</refname>
-  <refpurpose>insert, update, or delete rows of a table based upon source 
data</refpurpose>
+  <refpurpose>conditionally insert, update, or delete rows of a 
table</refpurpose>
  </refnamediv>
 
  <refsynopsisdiv>
@@ -24,32 +24,32 @@
 ON <replaceable class="parameter">join_condition</replaceable>
 <replaceable class="parameter">when_clause</replaceable> [...]
 
-where <replaceable class="parameter">data_source</replaceable> is
+<phrase>where <replaceable class="parameter">data_source</replaceable> 
is</phrase>
 
 { <replaceable class="parameter">source_table_name</replaceable> |
-  ( source_query )
+  ( <replaceable class="parameter">source_query</replaceable> )
 }
 [ [ AS ] <replaceable class="parameter">source_alias</replaceable> ]
 
-and <replaceable class="parameter">when_clause</replaceable> is
+<phrase>and <replaceable class="parameter">when_clause</replaceable> 
is</phrase>
 
 { WHEN MATCHED [ AND <replaceable class="parameter">condition</replaceable> ] 
THEN { <replaceable class="parameter">merge_update</replaceable> | <replaceable 
class="parameter">merge_delete</replaceable> | DO NOTHING } |
   WHEN NOT MATCHED [ AND <replaceable 
class="parameter">condition</replaceable> ] THEN { <replaceable 
class="parameter">merge_insert</replaceable> | DO NOTHING }
 }
 
-and <replaceable class="parameter">merge_insert</replaceable> is
+<phrase>and <replaceable class="parameter">merge_insert</replaceable> 
is</phrase>
 
 INSERT [( <replaceable class="parameter">column_name</replaceable> [, ...] )]
 [ OVERRIDING { SYSTEM | USER } VALUE ]
 { VALUES ( { <replaceable class="parameter">expression</replaceable> | DEFAULT 
} [, ...] ) | DEFAULT VALUES }
 
-and <replaceable class="parameter">merge_update</replaceable> is
+<phrase>and <replaceable class="parameter">merge_update</replaceable> 
is</phrase>
 
 UPDATE SET { <replaceable class="parameter">column_name</replaceable> = { 
<replaceable class="parameter">expression</replaceable> | DEFAULT } |
              ( <replaceable class="parameter">column_name</replaceable> [, 
...] ) = ( { <replaceable class="parameter">expression</replaceable> | DEFAULT 
} [, ...] )
            } [, ...]
 
-and <replaceable class="parameter">merge_delete</replaceable> is
+<phrase>and <replaceable class="parameter">merge_delete</replaceable> 
is</phrase>
 
 DELETE
 </synopsis>
@@ -414,18 +414,18 @@ <title>Outputs</title>
    On successful completion, a <command>MERGE</command> command returns a 
command
    tag of the form
 <screen>
-MERGE <replaceable class="parameter">total-count</replaceable>
+MERGE <replaceable class="parameter">total_count</replaceable>
 </screen>
-   The <replaceable class="parameter">total-count</replaceable> is the total
+   The <replaceable class="parameter">total_count</replaceable> is the total
    number of rows changed (whether inserted, updated, or deleted).
-   If <replaceable class="parameter">total-count</replaceable> is 0, no rows
+   If <replaceable class="parameter">total_count</replaceable> is 0, no rows
    were changed in any way.
   </para>
 
  </refsect1>
 
  <refsect1>
-  <title>Execution</title>
+  <title>Notes</title>
 
   <para>
    The following steps take place during the execution of
@@ -458,7 +458,7 @@ <title>Execution</title>
         </listitem>
         <listitem>
          <para>
-          When a condition returns true, perform the following actions
+          When a condition returns true, perform the following actions:
           <orderedlist>
            <listitem>
             <para>
@@ -531,10 +531,6 @@ <title>Execution</title>
    possible that no action will be taken for a candidate change row.
   </para>
 
- </refsect1>
- <refsect1>
-  <title>Notes</title>
-
   <para>
    The order in which rows are generated from the data source is
    indeterminate by default.
@@ -550,7 +546,6 @@ <title>Notes</title>
    <literal>RETURNING</literal> or <literal>WITH</literal> clauses.
   </para>
 
-  <tip>
    <para>
     You may also wish to consider using <command>INSERT ... ON 
CONFLICT</command>
     as an alternative statement which offers the ability to run an
@@ -558,7 +553,6 @@ <title>Notes</title>
     occurs.  There are a variety of differences and restrictions between
     the two statement types and they are not interchangeable.
    </para>
-  </tip>
  </refsect1>
 
  <refsect1>
@@ -578,10 +572,12 @@ <title>Examples</title>
   INSERT (CustomerId, Balance)
   VALUES (T.CustomerId, T.TransactionValue);
 </programlisting>
+  </para>
 
-   notice that this would be exactly equivalent to the following
+  <para>
+   Notice that this would be exactly equivalent to the following
    statement because the <literal>MATCHED</literal> result does not change
-   during execution
+   during execution.
 
 <programlisting>
 MERGE INTO CustomerAccount CA
diff --git a/src/backend/catalog/sql_features.txt 
b/src/backend/catalog/sql_features.txt
index d4cb8128ff..4c3e29111d 100644
--- a/src/backend/catalog/sql_features.txt
+++ b/src/backend/catalog/sql_features.txt
@@ -240,7 +240,7 @@ F311        Schema definition statement     02      CREATE 
TABLE for persistent base tables YES
 F311   Schema definition statement     03      CREATE VIEW     YES     
 F311   Schema definition statement     04      CREATE VIEW: WITH CHECK OPTION  
YES     
 F311   Schema definition statement     05      GRANT statement YES     
-F312   MERGE statement                 YES     also consider INSERT ... ON 
CONFLICT DO UPDATE
+F312   MERGE statement                 YES     
 F313   Enhanced MERGE statement                        YES     
 F314   MERGE statement with DELETE branch                      YES     
 F321   User authorization                      YES     
diff --git a/src/backend/executor/README b/src/backend/executor/README
index ea7469508e..0b5183fc4a 100644
--- a/src/backend/executor/README
+++ b/src/backend/executor/README
@@ -226,7 +226,7 @@ are simple Vars using only one step instead of two.
 MERGE
 -----
 
-MERGE is a multiple-table, multiple-action command: it specifies a target
+MERGE is a multiple-table, multiple-action command: It specifies a target
 table and a source relation, and can contain multiple WHEN MATCHED and
 WHEN NOT MATCHED clauses, each of which specifies one UPDATE, INSERT,
 UPDATE, or DO NOTHING actions.  The target table is modified by MERGE,
diff --git a/src/backend/executor/nodeModifyTable.c 
b/src/backend/executor/nodeModifyTable.c
index 6fc318583a..02b6513423 100644
--- a/src/backend/executor/nodeModifyTable.c
+++ b/src/backend/executor/nodeModifyTable.c
@@ -2290,7 +2290,7 @@ ExecOnConflictUpdate(ModifyTableContext *context,
                         * to break.
                         *
                         * It is the user's responsibility to prevent this 
situation from
-                        * occurring.  These problems are why SQL Standard 
similarly
+                        * occurring.  These problems are why the SQL standard 
similarly
                         * specifies that for SQL MERGE, an exception must be 
raised in
                         * the event of an attempt to update the same row twice.
                         */
@@ -2303,7 +2303,7 @@ ExecOnConflictUpdate(ModifyTableContext *context,
                        if (TransactionIdIsCurrentTransactionId(xmin))
                                ereport(ERROR,
                                                
(errcode(ERRCODE_CARDINALITY_VIOLATION),
-                               /*- translator: %s is a SQL command name */
+                               /* translator: %s is a SQL command name */
                                                 errmsg("%s command cannot 
affect row a second time",
                                                                "ON CONFLICT DO 
UPDATE"),
                                                 errhint("Ensure that no rows 
proposed for insertion within the same command have duplicate constrained 
values.")));
@@ -2723,7 +2723,7 @@ lmerge_matched:;
                                if 
(TransactionIdIsCurrentTransactionId(context->tmfd.xmax))
                                        ereport(ERROR,
                                                        
(errcode(ERRCODE_CARDINALITY_VIOLATION),
-                                       /*- translator: %s is a SQL command 
name */
+                                       /* translator: %s is a SQL command name 
*/
                                                         errmsg("%s command 
cannot affect row a second time",
                                                                        
"MERGE"),
                                                         errhint("Ensure that 
not more than one source row matches any one target row.")));
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index 34371d3869..6ad50fa11d 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -11475,7 +11475,7 @@ set_target_list:
 /*****************************************************************************
  *
  *             QUERY:
- *                             MERGE STATEMENTS
+ *                             MERGE
  *
  *****************************************************************************/
 
@@ -11495,13 +11495,13 @@ MergeStmt:
 
                                        $$ = (Node *)m;
                                }
-                       ;
+               ;
 
 
 merge_when_list:
                        merge_when_clause                                       
        { $$ = list_make1($1); }
                        | merge_when_list merge_when_clause             { $$ = 
lappend($1,$2); }
-                       ;
+               ;
 
 merge_when_clause:
                        WHEN MATCHED opt_merge_when_and_condition THEN 
merge_update
@@ -11550,16 +11550,16 @@ merge_when_clause:
 
                                        $$ = (Node *)m;
                                }
-                       ;
+               ;
 
 opt_merge_when_and_condition:
-                       AND a_expr                              { $$ = $2; }
-                       |                                               { $$ = 
NULL; }
-                       ;
+                       AND a_expr                              { $$ = $2; }
+                       |                                               { $$ = 
NULL; }
+               ;
 
 merge_delete:
-                       DELETE_P                                { $$ = NULL; }
-                       ;
+                       DELETE_P                                { $$ = NULL; }
+               ;
 
 merge_update:
                        UPDATE SET set_clause_list
@@ -11569,7 +11569,7 @@ merge_update:
 
                                        $$ = n;
                                }
-                       ;
+               ;
 
 merge_insert:
                        INSERT merge_values_clause
@@ -11609,14 +11609,14 @@ merge_insert:
                                        n->values = NIL;
                                        $$ = 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 1f0f9058b3..0f54e9e8e1 100644
--- a/src/backend/parser/parse_merge.c
+++ b/src/backend/parser/parse_merge.c
@@ -383,7 +383,7 @@ transformMergeStmt(ParseState *pstate, MergeStmt *stmt)
 
        qry->mergeActionList = mergeActionList;
 
-       /* RETURNING could potentially be added in the future, but not in SQL 
Std */
+       /* RETURNING could potentially be added in the future, but not in SQL 
std */
        qry->returningList = NULL;
 
        qry->hasTargetSRFs = false;
diff --git a/src/bin/psql/tab-complete.c b/src/bin/psql/tab-complete.c
index 85ed254d85..09054b22e8 100644
--- a/src/bin/psql/tab-complete.c
+++ b/src/bin/psql/tab-complete.c
@@ -804,24 +804,17 @@ static const SchemaQuery Query_for_list_of_updatables = {
 
 /* Relations supporting MERGE */
 static const SchemaQuery Query_for_list_of_mergetargets = {
-       /* min_server_version */
-       150000,
-       /* catname */
-       "pg_catalog.pg_class c",
-       /* selcondition */
+       .min_server_version = 150000,
+       .catname = "pg_catalog.pg_class c",
+       .selcondition =
        "c.relkind IN (" CppAsString2(RELKIND_RELATION) ", "
        CppAsString2(RELKIND_PARTITIONED_TABLE) ") AND "
        "c.relhasrules = false AND "
        "(c.relhassubclass = false OR "
        " c.relkind = " CppAsString2(RELKIND_PARTITIONED_TABLE) ")",
-       /* viscondition */
-       "pg_catalog.pg_table_is_visible(c.oid)",
-       /* namespace */
-       "c.relnamespace",
-       /* result */
-       "pg_catalog.quote_ident(c.relname)",
-       /* qualresult */
-       NULL
+       .viscondition = "pg_catalog.pg_table_is_visible(c.oid)",
+       .namespace = "c.relnamespace",
+       .result = "pg_catalog.quote_ident(c.relname)",
 };
 
 /* Relations supporting SELECT */
-- 
2.35.1

Reply via email to