public inbox for [email protected]  
help / color / mirror / Atom feed
From: Peter Eisentraut <[email protected]>
To: Alvaro Herrera <[email protected]>
To: Justin Pryzby <[email protected]>
To: Amit Langote <[email protected]>
To: Japin Li <[email protected]>
Cc: Zhihong Yu <[email protected]>
Cc: Simon Riggs <[email protected]>
Cc: Pg Hackers <[email protected]>
Cc: Tomas Vondra <[email protected]>
Cc: Daniel Westermann <[email protected]>
Cc: Erik Rijkers <[email protected]>
Cc: Jaime Casanova <[email protected]>
Cc: Andres Freund <[email protected]>
Subject: Re: support for MERGE
Date: Fri, 18 Mar 2022 12:05:03 +0100
Message-ID: <[email protected]> (raw)
In-Reply-To: <[email protected]>
References: <[email protected]>

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 <[email protected]>
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 <[email protected]>
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



Attachments:

  [text/plain] 0001-fixup-MERGE-SQL-Command-following-SQL-2016.patch (6.7K, ../[email protected]/2-0001-fixup-MERGE-SQL-Command-following-SQL-2016.patch)
  download | inline diff:
From 18ad74bfc2b6d1a758eaab9d2332532f6abb074d Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <[email protected]>
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



  [text/plain] 0002-fixup-MERGE-SQL-Command-following-SQL-2016.patch (12.9K, ../[email protected]/3-0002-fixup-MERGE-SQL-Command-following-SQL-2016.patch)
  download | inline diff:
From 2cbb5a9c55e9316a7f26fdbcd0d056feff15c86f Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <[email protected]>
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



view thread (2+ messages)

reply

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Reply to all the recipients using the --to and --cc options:
  reply via email

  To: [email protected]
  Cc: [email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected]
  Subject: Re: support for MERGE
  In-Reply-To: <[email protected]>

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

This inbox is served by agora; see mirroring instructions
for how to clone and mirror all data and code used for this inbox