On Wed, Jun 30, 2021 at 7:48 PM vignesh C <vignes...@gmail.com> wrote:
>
> On Thu, May 13, 2021 at 8:09 PM vignesh C <vignes...@gmail.com> wrote:
> >
> > On Thu, May 13, 2021 at 4:58 AM Alvaro Herrera <alvhe...@alvh.no-ip.org> 
> > wrote:
> > >
> >
> > Thanks for the comments, Attached patch has the changes for the same.
> >
>
> The Patch was not applying on Head, the attached patch is rebased on
> top of Head.

The patch was not applying on the head because of the recent commit
"8aafb02616753f5c6c90bbc567636b73c0cbb9d4", attached patch which is
rebased on HEAD.

Regards,
Vignesh
From 5ccc262d895d688fbca42d795ea01c7c16c09b54 Mon Sep 17 00:00:00 2001
From: vignesh <vignes...@gmail.com>
Date: Tue, 6 Jul 2021 20:22:45 +0530
Subject: [PATCH v8] Enhance error message to include option name in case of
 duplicate option error.

Enhanced error message to include option name in case of duplication
option error, so that the user can easily identify the error.
---
 contrib/file_fdw/file_fdw.c                 |  13 +--
 src/backend/catalog/aclchk.c                |  14 +--
 src/backend/commands/copy.c                 |  57 +++-------
 src/backend/commands/dbcommands.c           |  76 +++----------
 src/backend/commands/extension.c            |  23 +---
 src/backend/commands/foreigncmds.c          |  21 ++--
 src/backend/commands/functioncmds.c         |  59 ++++------
 src/backend/commands/publicationcmds.c      |  30 ++---
 src/backend/commands/sequence.c             |  48 ++------
 src/backend/commands/subscriptioncmds.c     |  62 +++++-----
 src/backend/commands/tablecmds.c            |   4 +-
 src/backend/commands/typecmds.c             |  34 ++----
 src/backend/commands/user.c                 | 118 +++++---------------
 src/backend/parser/parse_utilcmd.c          |   4 +-
 src/backend/replication/pgoutput/pgoutput.c |  23 ++--
 src/backend/replication/walsender.c         |  15 +--
 src/backend/tcop/utility.c                  |  20 ++--
 src/include/commands/defrem.h               |  16 ++-
 src/include/commands/publicationcmds.h      |   4 +-
 src/include/commands/subscriptioncmds.h     |   4 +-
 src/include/commands/typecmds.h             |   2 +-
 src/include/commands/user.h                 |   2 +-
 src/test/regress/expected/copy2.out         |  24 ++--
 src/test/regress/expected/foreign_data.out  |   8 +-
 src/test/regress/expected/publication.out   |   4 +-
 25 files changed, 232 insertions(+), 453 deletions(-)

diff --git a/contrib/file_fdw/file_fdw.c b/contrib/file_fdw/file_fdw.c
index 2c2f149fb0..f49dd47930 100644
--- a/contrib/file_fdw/file_fdw.c
+++ b/contrib/file_fdw/file_fdw.c
@@ -200,6 +200,7 @@ file_fdw_validator(PG_FUNCTION_ARGS)
 	char	   *filename = NULL;
 	DefElem    *force_not_null = NULL;
 	DefElem    *force_null = NULL;
+	DefElem    *def;
 	List	   *other_options = NIL;
 	ListCell   *cell;
 
@@ -209,7 +210,7 @@ file_fdw_validator(PG_FUNCTION_ARGS)
 	 */
 	foreach(cell, options_list)
 	{
-		DefElem    *def = (DefElem *) lfirst(cell);
+		def = (DefElem *) lfirst(cell);
 
 		if (!is_valid_option(def->defname, catalog))
 		{
@@ -290,10 +291,7 @@ file_fdw_validator(PG_FUNCTION_ARGS)
 		else if (strcmp(def->defname, "force_not_null") == 0)
 		{
 			if (force_not_null)
-				ereport(ERROR,
-						(errcode(ERRCODE_SYNTAX_ERROR),
-						 errmsg("conflicting or redundant options"),
-						 errhint("Option \"force_not_null\" supplied more than once for a column.")));
+				ReportDuplicateOptionError(def, NULL);
 			force_not_null = def;
 			/* Don't care what the value is, as long as it's a legal boolean */
 			(void) defGetBoolean(def);
@@ -302,10 +300,7 @@ file_fdw_validator(PG_FUNCTION_ARGS)
 		else if (strcmp(def->defname, "force_null") == 0)
 		{
 			if (force_null)
-				ereport(ERROR,
-						(errcode(ERRCODE_SYNTAX_ERROR),
-						 errmsg("conflicting or redundant options"),
-						 errhint("Option \"force_null\" supplied more than once for a column.")));
+				ReportDuplicateOptionError(def, NULL);
 			force_null = def;
 			(void) defGetBoolean(def);
 		}
diff --git a/src/backend/catalog/aclchk.c b/src/backend/catalog/aclchk.c
index 53392414f1..264cdc2730 100644
--- a/src/backend/catalog/aclchk.c
+++ b/src/backend/catalog/aclchk.c
@@ -59,6 +59,7 @@
 #include "catalog/pg_ts_template.h"
 #include "catalog/pg_type.h"
 #include "commands/dbcommands.h"
+#include "commands/defrem.h"
 #include "commands/event_trigger.h"
 #include "commands/extension.h"
 #include "commands/proclang.h"
@@ -910,30 +911,25 @@ ExecAlterDefaultPrivilegesStmt(ParseState *pstate, AlterDefaultPrivilegesStmt *s
 	List	   *nspnames = NIL;
 	DefElem    *drolespecs = NULL;
 	DefElem    *dnspnames = NULL;
+	DefElem    *defel;
 	AclMode		all_privileges;
 	const char *errormsg;
 
 	/* Deconstruct the "options" part of the statement */
 	foreach(cell, stmt->options)
 	{
-		DefElem    *defel = (DefElem *) lfirst(cell);
+		defel = (DefElem *) lfirst(cell);
 
 		if (strcmp(defel->defname, "schemas") == 0)
 		{
 			if (dnspnames)
-				ereport(ERROR,
-						(errcode(ERRCODE_SYNTAX_ERROR),
-						 errmsg("conflicting or redundant options"),
-						 parser_errposition(pstate, defel->location)));
+				ReportDuplicateOptionError(defel, pstate);
 			dnspnames = defel;
 		}
 		else if (strcmp(defel->defname, "roles") == 0)
 		{
 			if (drolespecs)
-				ereport(ERROR,
-						(errcode(ERRCODE_SYNTAX_ERROR),
-						 errmsg("conflicting or redundant options"),
-						 parser_errposition(pstate, defel->location)));
+				ReportDuplicateOptionError(defel, pstate);
 			drolespecs = defel;
 		}
 		else
diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index 8265b981eb..0d13daab4c 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -340,6 +340,7 @@ ProcessCopyOptions(ParseState *pstate,
 	bool		freeze_specified = false;
 	bool		header_specified = false;
 	ListCell   *option;
+	DefElem    *defel;
 
 	/* Support external use for option sanity checking */
 	if (opts_out == NULL)
@@ -350,17 +351,14 @@ ProcessCopyOptions(ParseState *pstate,
 	/* Extract options from the statement node tree */
 	foreach(option, options)
 	{
-		DefElem    *defel = lfirst_node(DefElem, option);
+		defel = lfirst_node(DefElem, option);
 
 		if (strcmp(defel->defname, "format") == 0)
 		{
 			char	   *fmt = defGetString(defel);
 
 			if (format_specified)
-				ereport(ERROR,
-						(errcode(ERRCODE_SYNTAX_ERROR),
-						 errmsg("conflicting or redundant options"),
-						 parser_errposition(pstate, defel->location)));
+				ReportDuplicateOptionError(defel, pstate);
 			format_specified = true;
 			if (strcmp(fmt, "text") == 0)
 				 /* default format */ ;
@@ -377,57 +375,39 @@ ProcessCopyOptions(ParseState *pstate,
 		else if (strcmp(defel->defname, "freeze") == 0)
 		{
 			if (freeze_specified)
-				ereport(ERROR,
-						(errcode(ERRCODE_SYNTAX_ERROR),
-						 errmsg("conflicting or redundant options"),
-						 parser_errposition(pstate, defel->location)));
+				ReportDuplicateOptionError(defel, pstate);
 			freeze_specified = true;
 			opts_out->freeze = defGetBoolean(defel);
 		}
 		else if (strcmp(defel->defname, "delimiter") == 0)
 		{
 			if (opts_out->delim)
-				ereport(ERROR,
-						(errcode(ERRCODE_SYNTAX_ERROR),
-						 errmsg("conflicting or redundant options"),
-						 parser_errposition(pstate, defel->location)));
+				ReportDuplicateOptionError(defel, pstate);
 			opts_out->delim = defGetString(defel);
 		}
 		else if (strcmp(defel->defname, "null") == 0)
 		{
 			if (opts_out->null_print)
-				ereport(ERROR,
-						(errcode(ERRCODE_SYNTAX_ERROR),
-						 errmsg("conflicting or redundant options"),
-						 parser_errposition(pstate, defel->location)));
+				ReportDuplicateOptionError(defel, pstate);
 			opts_out->null_print = defGetString(defel);
 		}
 		else if (strcmp(defel->defname, "header") == 0)
 		{
 			if (header_specified)
-				ereport(ERROR,
-						(errcode(ERRCODE_SYNTAX_ERROR),
-						 errmsg("conflicting or redundant options"),
-						 parser_errposition(pstate, defel->location)));
+				ReportDuplicateOptionError(defel, pstate);
 			header_specified = true;
 			opts_out->header_line = defGetBoolean(defel);
 		}
 		else if (strcmp(defel->defname, "quote") == 0)
 		{
 			if (opts_out->quote)
-				ereport(ERROR,
-						(errcode(ERRCODE_SYNTAX_ERROR),
-						 errmsg("conflicting or redundant options"),
-						 parser_errposition(pstate, defel->location)));
+				ReportDuplicateOptionError(defel, pstate);
 			opts_out->quote = defGetString(defel);
 		}
 		else if (strcmp(defel->defname, "escape") == 0)
 		{
 			if (opts_out->escape)
-				ereport(ERROR,
-						(errcode(ERRCODE_SYNTAX_ERROR),
-						 errmsg("conflicting or redundant options"),
-						 parser_errposition(pstate, defel->location)));
+				ReportDuplicateOptionError(defel, pstate);
 			opts_out->escape = defGetString(defel);
 		}
 		else if (strcmp(defel->defname, "force_quote") == 0)
@@ -451,10 +431,7 @@ ProcessCopyOptions(ParseState *pstate,
 		else if (strcmp(defel->defname, "force_not_null") == 0)
 		{
 			if (opts_out->force_notnull)
-				ereport(ERROR,
-						(errcode(ERRCODE_SYNTAX_ERROR),
-						 errmsg("conflicting or redundant options"),
-						 parser_errposition(pstate, defel->location)));
+				ReportDuplicateOptionError(defel, pstate);
 			if (defel->arg && IsA(defel->arg, List))
 				opts_out->force_notnull = castNode(List, defel->arg);
 			else
@@ -467,9 +444,7 @@ ProcessCopyOptions(ParseState *pstate,
 		else if (strcmp(defel->defname, "force_null") == 0)
 		{
 			if (opts_out->force_null)
-				ereport(ERROR,
-						(errcode(ERRCODE_SYNTAX_ERROR),
-						 errmsg("conflicting or redundant options")));
+				ReportDuplicateOptionError(defel, pstate);
 			if (defel->arg && IsA(defel->arg, List))
 				opts_out->force_null = castNode(List, defel->arg);
 			else
@@ -487,10 +462,7 @@ ProcessCopyOptions(ParseState *pstate,
 			 * allowed for the column list to be NIL.
 			 */
 			if (opts_out->convert_selectively)
-				ereport(ERROR,
-						(errcode(ERRCODE_SYNTAX_ERROR),
-						 errmsg("conflicting or redundant options"),
-						 parser_errposition(pstate, defel->location)));
+				ReportDuplicateOptionError(defel, pstate);
 			opts_out->convert_selectively = true;
 			if (defel->arg == NULL || IsA(defel->arg, List))
 				opts_out->convert_select = castNode(List, defel->arg);
@@ -504,10 +476,7 @@ ProcessCopyOptions(ParseState *pstate,
 		else if (strcmp(defel->defname, "encoding") == 0)
 		{
 			if (opts_out->file_encoding >= 0)
-				ereport(ERROR,
-						(errcode(ERRCODE_SYNTAX_ERROR),
-						 errmsg("conflicting or redundant options"),
-						 parser_errposition(pstate, defel->location)));
+				ReportDuplicateOptionError(defel, pstate);
 			opts_out->file_encoding = pg_char_to_encoding(defGetString(defel));
 			if (opts_out->file_encoding < 0)
 				ereport(ERROR,
diff --git a/src/backend/commands/dbcommands.c b/src/backend/commands/dbcommands.c
index 2b159b60eb..0aa2311ad2 100644
--- a/src/backend/commands/dbcommands.c
+++ b/src/backend/commands/dbcommands.c
@@ -143,100 +143,71 @@ createdb(ParseState *pstate, const CreatedbStmt *stmt)
 	int			notherbackends;
 	int			npreparedxacts;
 	createdb_failure_params fparms;
+	DefElem    *defel;
 
 	/* Extract options from the statement node tree */
 	foreach(option, stmt->options)
 	{
-		DefElem    *defel = (DefElem *) lfirst(option);
+		defel = (DefElem *) lfirst(option);
 
 		if (strcmp(defel->defname, "tablespace") == 0)
 		{
 			if (dtablespacename)
-				ereport(ERROR,
-						(errcode(ERRCODE_SYNTAX_ERROR),
-						 errmsg("conflicting or redundant options"),
-						 parser_errposition(pstate, defel->location)));
+				ReportDuplicateOptionError(defel, pstate);
 			dtablespacename = defel;
 		}
 		else if (strcmp(defel->defname, "owner") == 0)
 		{
 			if (downer)
-				ereport(ERROR,
-						(errcode(ERRCODE_SYNTAX_ERROR),
-						 errmsg("conflicting or redundant options"),
-						 parser_errposition(pstate, defel->location)));
+				ReportDuplicateOptionError(defel, pstate);
 			downer = defel;
 		}
 		else if (strcmp(defel->defname, "template") == 0)
 		{
 			if (dtemplate)
-				ereport(ERROR,
-						(errcode(ERRCODE_SYNTAX_ERROR),
-						 errmsg("conflicting or redundant options"),
-						 parser_errposition(pstate, defel->location)));
+				ReportDuplicateOptionError(defel, pstate);
 			dtemplate = defel;
 		}
 		else if (strcmp(defel->defname, "encoding") == 0)
 		{
 			if (dencoding)
-				ereport(ERROR,
-						(errcode(ERRCODE_SYNTAX_ERROR),
-						 errmsg("conflicting or redundant options"),
-						 parser_errposition(pstate, defel->location)));
+				ReportDuplicateOptionError(defel, pstate);
 			dencoding = defel;
 		}
 		else if (strcmp(defel->defname, "locale") == 0)
 		{
 			if (dlocale)
-				ereport(ERROR,
-						(errcode(ERRCODE_SYNTAX_ERROR),
-						 errmsg("conflicting or redundant options"),
-						 parser_errposition(pstate, defel->location)));
+				ReportDuplicateOptionError(defel, pstate);
 			dlocale = defel;
 		}
 		else if (strcmp(defel->defname, "lc_collate") == 0)
 		{
 			if (dcollate)
-				ereport(ERROR,
-						(errcode(ERRCODE_SYNTAX_ERROR),
-						 errmsg("conflicting or redundant options"),
-						 parser_errposition(pstate, defel->location)));
+				ReportDuplicateOptionError(defel, pstate);
 			dcollate = defel;
 		}
 		else if (strcmp(defel->defname, "lc_ctype") == 0)
 		{
 			if (dctype)
-				ereport(ERROR,
-						(errcode(ERRCODE_SYNTAX_ERROR),
-						 errmsg("conflicting or redundant options"),
-						 parser_errposition(pstate, defel->location)));
+				ReportDuplicateOptionError(defel, pstate);
 			dctype = defel;
 		}
 		else if (strcmp(defel->defname, "is_template") == 0)
 		{
 			if (distemplate)
-				ereport(ERROR,
-						(errcode(ERRCODE_SYNTAX_ERROR),
-						 errmsg("conflicting or redundant options"),
-						 parser_errposition(pstate, defel->location)));
+				ReportDuplicateOptionError(defel, pstate);
 			distemplate = defel;
 		}
 		else if (strcmp(defel->defname, "allow_connections") == 0)
 		{
 			if (dallowconnections)
-				ereport(ERROR,
-						(errcode(ERRCODE_SYNTAX_ERROR),
-						 errmsg("conflicting or redundant options"),
-						 parser_errposition(pstate, defel->location)));
+				ReportDuplicateOptionError(defel, pstate);
 			dallowconnections = defel;
 		}
 		else if (strcmp(defel->defname, "connection_limit") == 0)
 		{
 			if (dconnlimit)
-				ereport(ERROR,
-						(errcode(ERRCODE_SYNTAX_ERROR),
-						 errmsg("conflicting or redundant options"),
-						 parser_errposition(pstate, defel->location)));
+				ReportDuplicateOptionError(defel, pstate);
 			dconnlimit = defel;
 		}
 		else if (strcmp(defel->defname, "location") == 0)
@@ -1488,46 +1459,35 @@ AlterDatabase(ParseState *pstate, AlterDatabaseStmt *stmt, bool isTopLevel)
 	Datum		new_record[Natts_pg_database];
 	bool		new_record_nulls[Natts_pg_database];
 	bool		new_record_repl[Natts_pg_database];
+	DefElem    *defel;
 
 	/* Extract options from the statement node tree */
 	foreach(option, stmt->options)
 	{
-		DefElem    *defel = (DefElem *) lfirst(option);
+		defel = (DefElem *) lfirst(option);
 
 		if (strcmp(defel->defname, "is_template") == 0)
 		{
 			if (distemplate)
-				ereport(ERROR,
-						(errcode(ERRCODE_SYNTAX_ERROR),
-						 errmsg("conflicting or redundant options"),
-						 parser_errposition(pstate, defel->location)));
+				ReportDuplicateOptionError(defel, pstate);
 			distemplate = defel;
 		}
 		else if (strcmp(defel->defname, "allow_connections") == 0)
 		{
 			if (dallowconnections)
-				ereport(ERROR,
-						(errcode(ERRCODE_SYNTAX_ERROR),
-						 errmsg("conflicting or redundant options"),
-						 parser_errposition(pstate, defel->location)));
+				ReportDuplicateOptionError(defel, pstate);
 			dallowconnections = defel;
 		}
 		else if (strcmp(defel->defname, "connection_limit") == 0)
 		{
 			if (dconnlimit)
-				ereport(ERROR,
-						(errcode(ERRCODE_SYNTAX_ERROR),
-						 errmsg("conflicting or redundant options"),
-						 parser_errposition(pstate, defel->location)));
+				ReportDuplicateOptionError(defel, pstate);
 			dconnlimit = defel;
 		}
 		else if (strcmp(defel->defname, "tablespace") == 0)
 		{
 			if (dtablespace)
-				ereport(ERROR,
-						(errcode(ERRCODE_SYNTAX_ERROR),
-						 errmsg("conflicting or redundant options"),
-						 parser_errposition(pstate, defel->location)));
+				ReportDuplicateOptionError(defel, pstate);
 			dtablespace = defel;
 		}
 		else
diff --git a/src/backend/commands/extension.c b/src/backend/commands/extension.c
index 41857feda9..962ddb5ffe 100644
--- a/src/backend/commands/extension.c
+++ b/src/backend/commands/extension.c
@@ -1683,6 +1683,7 @@ CreateExtension(ParseState *pstate, CreateExtensionStmt *stmt)
 	DefElem    *d_schema = NULL;
 	DefElem    *d_new_version = NULL;
 	DefElem    *d_cascade = NULL;
+	DefElem    *defel;
 	char	   *schemaName = NULL;
 	char	   *versionName = NULL;
 	bool		cascade = false;
@@ -1726,35 +1727,26 @@ CreateExtension(ParseState *pstate, CreateExtensionStmt *stmt)
 	/* Deconstruct the statement option list */
 	foreach(lc, stmt->options)
 	{
-		DefElem    *defel = (DefElem *) lfirst(lc);
+		defel = (DefElem *) lfirst(lc);
 
 		if (strcmp(defel->defname, "schema") == 0)
 		{
 			if (d_schema)
-				ereport(ERROR,
-						(errcode(ERRCODE_SYNTAX_ERROR),
-						 errmsg("conflicting or redundant options"),
-						 parser_errposition(pstate, defel->location)));
+				ReportDuplicateOptionError(defel, pstate);
 			d_schema = defel;
 			schemaName = defGetString(d_schema);
 		}
 		else if (strcmp(defel->defname, "new_version") == 0)
 		{
 			if (d_new_version)
-				ereport(ERROR,
-						(errcode(ERRCODE_SYNTAX_ERROR),
-						 errmsg("conflicting or redundant options"),
-						 parser_errposition(pstate, defel->location)));
+				ReportDuplicateOptionError(defel, pstate);
 			d_new_version = defel;
 			versionName = defGetString(d_new_version);
 		}
 		else if (strcmp(defel->defname, "cascade") == 0)
 		{
 			if (d_cascade)
-				ereport(ERROR,
-						(errcode(ERRCODE_SYNTAX_ERROR),
-						 errmsg("conflicting or redundant options"),
-						 parser_errposition(pstate, defel->location)));
+				ReportDuplicateOptionError(defel, pstate);
 			d_cascade = defel;
 			cascade = defGetBoolean(d_cascade);
 		}
@@ -3051,10 +3043,7 @@ ExecAlterExtensionStmt(ParseState *pstate, AlterExtensionStmt *stmt)
 		if (strcmp(defel->defname, "new_version") == 0)
 		{
 			if (d_new_version)
-				ereport(ERROR,
-						(errcode(ERRCODE_SYNTAX_ERROR),
-						 errmsg("conflicting or redundant options"),
-						 parser_errposition(pstate, defel->location)));
+				ReportDuplicateOptionError(defel, pstate);
 			d_new_version = defel;
 		}
 		else
diff --git a/src/backend/commands/foreigncmds.c b/src/backend/commands/foreigncmds.c
index bc36311d38..26a6a473ec 100644
--- a/src/backend/commands/foreigncmds.c
+++ b/src/backend/commands/foreigncmds.c
@@ -515,11 +515,12 @@ lookup_fdw_validator_func(DefElem *validator)
  * Process function options of CREATE/ALTER FDW
  */
 static void
-parse_func_options(List *func_options,
+parse_func_options(ParseState *pstate, List *func_options,
 				   bool *handler_given, Oid *fdwhandler,
 				   bool *validator_given, Oid *fdwvalidator)
 {
 	ListCell   *cell;
+	DefElem    *def;
 
 	*handler_given = false;
 	*validator_given = false;
@@ -529,23 +530,19 @@ parse_func_options(List *func_options,
 
 	foreach(cell, func_options)
 	{
-		DefElem    *def = (DefElem *) lfirst(cell);
+		def = (DefElem *) lfirst(cell);
 
 		if (strcmp(def->defname, "handler") == 0)
 		{
 			if (*handler_given)
-				ereport(ERROR,
-						(errcode(ERRCODE_SYNTAX_ERROR),
-						 errmsg("conflicting or redundant options")));
+				ReportDuplicateOptionError(def, pstate);
 			*handler_given = true;
 			*fdwhandler = lookup_fdw_handler_func(def);
 		}
 		else if (strcmp(def->defname, "validator") == 0)
 		{
 			if (*validator_given)
-				ereport(ERROR,
-						(errcode(ERRCODE_SYNTAX_ERROR),
-						 errmsg("conflicting or redundant options")));
+				ReportDuplicateOptionError(def, pstate);
 			*validator_given = true;
 			*fdwvalidator = lookup_fdw_validator_func(def);
 		}
@@ -559,7 +556,7 @@ parse_func_options(List *func_options,
  * Create a foreign-data wrapper
  */
 ObjectAddress
-CreateForeignDataWrapper(CreateFdwStmt *stmt)
+CreateForeignDataWrapper(ParseState *pstate, CreateFdwStmt *stmt)
 {
 	Relation	rel;
 	Datum		values[Natts_pg_foreign_data_wrapper];
@@ -611,7 +608,7 @@ CreateForeignDataWrapper(CreateFdwStmt *stmt)
 	values[Anum_pg_foreign_data_wrapper_fdwowner - 1] = ObjectIdGetDatum(ownerId);
 
 	/* Lookup handler and validator functions, if given */
-	parse_func_options(stmt->func_options,
+	parse_func_options(pstate, stmt->func_options,
 					   &handler_given, &fdwhandler,
 					   &validator_given, &fdwvalidator);
 
@@ -675,7 +672,7 @@ CreateForeignDataWrapper(CreateFdwStmt *stmt)
  * Alter foreign-data wrapper
  */
 ObjectAddress
-AlterForeignDataWrapper(AlterFdwStmt *stmt)
+AlterForeignDataWrapper(ParseState *pstate, AlterFdwStmt *stmt)
 {
 	Relation	rel;
 	HeapTuple	tp;
@@ -717,7 +714,7 @@ AlterForeignDataWrapper(AlterFdwStmt *stmt)
 	memset(repl_null, false, sizeof(repl_null));
 	memset(repl_repl, false, sizeof(repl_repl));
 
-	parse_func_options(stmt->func_options,
+	parse_func_options(pstate, stmt->func_options,
 					   &handler_given, &fdwhandler,
 					   &validator_given, &fdwvalidator);
 
diff --git a/src/backend/commands/functioncmds.c b/src/backend/commands/functioncmds.c
index 736d04780a..c3ca5cdfac 100644
--- a/src/backend/commands/functioncmds.c
+++ b/src/backend/commands/functioncmds.c
@@ -523,7 +523,7 @@ compute_common_attribute(ParseState *pstate,
 		if (is_procedure)
 			goto procedure_error;
 		if (*volatility_item)
-			goto duplicate_error;
+			ReportDuplicateOptionError(defel, pstate);
 
 		*volatility_item = defel;
 	}
@@ -532,14 +532,14 @@ compute_common_attribute(ParseState *pstate,
 		if (is_procedure)
 			goto procedure_error;
 		if (*strict_item)
-			goto duplicate_error;
+			ReportDuplicateOptionError(defel, pstate);
 
 		*strict_item = defel;
 	}
 	else if (strcmp(defel->defname, "security") == 0)
 	{
 		if (*security_item)
-			goto duplicate_error;
+			ReportDuplicateOptionError(defel, pstate);
 
 		*security_item = defel;
 	}
@@ -548,7 +548,7 @@ compute_common_attribute(ParseState *pstate,
 		if (is_procedure)
 			goto procedure_error;
 		if (*leakproof_item)
-			goto duplicate_error;
+			ReportDuplicateOptionError(defel, pstate);
 
 		*leakproof_item = defel;
 	}
@@ -561,7 +561,7 @@ compute_common_attribute(ParseState *pstate,
 		if (is_procedure)
 			goto procedure_error;
 		if (*cost_item)
-			goto duplicate_error;
+			ReportDuplicateOptionError(defel, pstate);
 
 		*cost_item = defel;
 	}
@@ -570,7 +570,7 @@ compute_common_attribute(ParseState *pstate,
 		if (is_procedure)
 			goto procedure_error;
 		if (*rows_item)
-			goto duplicate_error;
+			ReportDuplicateOptionError(defel, pstate);
 
 		*rows_item = defel;
 	}
@@ -579,7 +579,7 @@ compute_common_attribute(ParseState *pstate,
 		if (is_procedure)
 			goto procedure_error;
 		if (*support_item)
-			goto duplicate_error;
+			ReportDuplicateOptionError(defel, pstate);
 
 		*support_item = defel;
 	}
@@ -588,7 +588,7 @@ compute_common_attribute(ParseState *pstate,
 		if (is_procedure)
 			goto procedure_error;
 		if (*parallel_item)
-			goto duplicate_error;
+			ReportDuplicateOptionError(defel, pstate);
 
 		*parallel_item = defel;
 	}
@@ -598,13 +598,6 @@ compute_common_attribute(ParseState *pstate,
 	/* Recognized an option */
 	return true;
 
-duplicate_error:
-	ereport(ERROR,
-			(errcode(ERRCODE_SYNTAX_ERROR),
-			 errmsg("conflicting or redundant options"),
-			 parser_errposition(pstate, defel->location)));
-	return false;				/* keep compiler quiet */
-
 procedure_error:
 	ereport(ERROR,
 			(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
@@ -757,45 +750,34 @@ compute_function_attributes(ParseState *pstate,
 	DefElem    *rows_item = NULL;
 	DefElem    *support_item = NULL;
 	DefElem    *parallel_item = NULL;
+	DefElem    *defel;
 
 	foreach(option, options)
 	{
-		DefElem    *defel = (DefElem *) lfirst(option);
+		defel = (DefElem *) lfirst(option);
 
 		if (strcmp(defel->defname, "as") == 0)
 		{
 			if (as_item)
-				ereport(ERROR,
-						(errcode(ERRCODE_SYNTAX_ERROR),
-						 errmsg("conflicting or redundant options"),
-						 parser_errposition(pstate, defel->location)));
+				ReportDuplicateOptionError(defel, pstate);
 			as_item = defel;
 		}
 		else if (strcmp(defel->defname, "language") == 0)
 		{
 			if (language_item)
-				ereport(ERROR,
-						(errcode(ERRCODE_SYNTAX_ERROR),
-						 errmsg("conflicting or redundant options"),
-						 parser_errposition(pstate, defel->location)));
+				ReportDuplicateOptionError(defel, pstate);
 			language_item = defel;
 		}
 		else if (strcmp(defel->defname, "transform") == 0)
 		{
 			if (transform_item)
-				ereport(ERROR,
-						(errcode(ERRCODE_SYNTAX_ERROR),
-						 errmsg("conflicting or redundant options"),
-						 parser_errposition(pstate, defel->location)));
+				ReportDuplicateOptionError(defel, pstate);
 			transform_item = defel;
 		}
 		else if (strcmp(defel->defname, "window") == 0)
 		{
 			if (windowfunc_item)
-				ereport(ERROR,
-						(errcode(ERRCODE_SYNTAX_ERROR),
-						 errmsg("conflicting or redundant options"),
-						 parser_errposition(pstate, defel->location)));
+				ReportDuplicateOptionError(defel, pstate);
 			if (is_procedure)
 				ereport(ERROR,
 						(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
@@ -2070,12 +2052,13 @@ IsThereFunctionInNamespace(const char *proname, int pronargs,
  * See at ExecuteCallStmt() about the atomic argument.
  */
 void
-ExecuteDoStmt(DoStmt *stmt, bool atomic)
+ExecuteDoStmt(ParseState *pstate, DoStmt *stmt, bool atomic)
 {
 	InlineCodeBlock *codeblock = makeNode(InlineCodeBlock);
 	ListCell   *arg;
 	DefElem    *as_item = NULL;
 	DefElem    *language_item = NULL;
+	DefElem    *defel;
 	char	   *language;
 	Oid			laninline;
 	HeapTuple	languageTuple;
@@ -2084,22 +2067,18 @@ ExecuteDoStmt(DoStmt *stmt, bool atomic)
 	/* Process options we got from gram.y */
 	foreach(arg, stmt->args)
 	{
-		DefElem    *defel = (DefElem *) lfirst(arg);
+		defel = (DefElem *) lfirst(arg);
 
 		if (strcmp(defel->defname, "as") == 0)
 		{
 			if (as_item)
-				ereport(ERROR,
-						(errcode(ERRCODE_SYNTAX_ERROR),
-						 errmsg("conflicting or redundant options")));
+				ReportDuplicateOptionError(defel, pstate);
 			as_item = defel;
 		}
 		else if (strcmp(defel->defname, "language") == 0)
 		{
 			if (language_item)
-				ereport(ERROR,
-						(errcode(ERRCODE_SYNTAX_ERROR),
-						 errmsg("conflicting or redundant options")));
+				ReportDuplicateOptionError(defel, pstate);
 			language_item = defel;
 		}
 		else
diff --git a/src/backend/commands/publicationcmds.c b/src/backend/commands/publicationcmds.c
index 95c253c8e0..93ad657c02 100644
--- a/src/backend/commands/publicationcmds.c
+++ b/src/backend/commands/publicationcmds.c
@@ -55,13 +55,15 @@ static void PublicationAddTables(Oid pubid, List *rels, bool if_not_exists,
 static void PublicationDropTables(Oid pubid, List *rels, bool missing_ok);
 
 static void
-parse_publication_options(List *options,
+parse_publication_options(ParseState *pstate,
+						  List *options,
 						  bool *publish_given,
 						  PublicationActions *pubactions,
 						  bool *publish_via_partition_root_given,
 						  bool *publish_via_partition_root)
 {
 	ListCell   *lc;
+	DefElem    *defel;
 
 	*publish_given = false;
 	*publish_via_partition_root_given = false;
@@ -76,7 +78,7 @@ parse_publication_options(List *options,
 	/* Parse options */
 	foreach(lc, options)
 	{
-		DefElem    *defel = (DefElem *) lfirst(lc);
+		defel = (DefElem *) lfirst(lc);
 
 		if (strcmp(defel->defname, "publish") == 0)
 		{
@@ -85,9 +87,7 @@ parse_publication_options(List *options,
 			ListCell   *lc;
 
 			if (*publish_given)
-				ereport(ERROR,
-						(errcode(ERRCODE_SYNTAX_ERROR),
-						 errmsg("conflicting or redundant options")));
+				ReportDuplicateOptionError(defel, pstate);
 
 			/*
 			 * If publish option was given only the explicitly listed actions
@@ -128,9 +128,7 @@ parse_publication_options(List *options,
 		else if (strcmp(defel->defname, "publish_via_partition_root") == 0)
 		{
 			if (*publish_via_partition_root_given)
-				ereport(ERROR,
-						(errcode(ERRCODE_SYNTAX_ERROR),
-						 errmsg("conflicting or redundant options")));
+				ReportDuplicateOptionError(defel, pstate);
 			*publish_via_partition_root_given = true;
 			*publish_via_partition_root = defGetBoolean(defel);
 		}
@@ -145,7 +143,7 @@ parse_publication_options(List *options,
  * Create new publication.
  */
 ObjectAddress
-CreatePublication(CreatePublicationStmt *stmt)
+CreatePublication(ParseState *pstate, CreatePublicationStmt *stmt)
 {
 	Relation	rel;
 	ObjectAddress myself;
@@ -192,7 +190,8 @@ CreatePublication(CreatePublicationStmt *stmt)
 		DirectFunctionCall1(namein, CStringGetDatum(stmt->pubname));
 	values[Anum_pg_publication_pubowner - 1] = ObjectIdGetDatum(GetUserId());
 
-	parse_publication_options(stmt->options,
+	parse_publication_options(pstate,
+							  stmt->options,
 							  &publish_given, &pubactions,
 							  &publish_via_partition_root_given,
 							  &publish_via_partition_root);
@@ -256,8 +255,8 @@ CreatePublication(CreatePublicationStmt *stmt)
  * Change options of a publication.
  */
 static void
-AlterPublicationOptions(AlterPublicationStmt *stmt, Relation rel,
-						HeapTuple tup)
+AlterPublicationOptions(ParseState *pstate, AlterPublicationStmt *stmt,
+						Relation rel, HeapTuple tup)
 {
 	bool		nulls[Natts_pg_publication];
 	bool		replaces[Natts_pg_publication];
@@ -269,7 +268,8 @@ AlterPublicationOptions(AlterPublicationStmt *stmt, Relation rel,
 	ObjectAddress obj;
 	Form_pg_publication pubform;
 
-	parse_publication_options(stmt->options,
+	parse_publication_options(pstate,
+							  stmt->options,
 							  &publish_given, &pubactions,
 							  &publish_via_partition_root_given,
 							  &publish_via_partition_root);
@@ -434,7 +434,7 @@ AlterPublicationTables(AlterPublicationStmt *stmt, Relation rel,
  * AlterPublicationTables.
  */
 void
-AlterPublication(AlterPublicationStmt *stmt)
+AlterPublication(ParseState *pstate, AlterPublicationStmt *stmt)
 {
 	Relation	rel;
 	HeapTuple	tup;
@@ -459,7 +459,7 @@ AlterPublication(AlterPublicationStmt *stmt)
 					   stmt->pubname);
 
 	if (stmt->options)
-		AlterPublicationOptions(stmt, rel, tup);
+		AlterPublicationOptions(pstate, stmt, rel, tup);
 	else
 		AlterPublicationTables(stmt, rel, tup);
 
diff --git a/src/backend/commands/sequence.c b/src/backend/commands/sequence.c
index 0415df9ccb..155d332e43 100644
--- a/src/backend/commands/sequence.c
+++ b/src/backend/commands/sequence.c
@@ -1247,6 +1247,7 @@ init_params(ParseState *pstate, List *options, bool for_identity,
 	DefElem    *min_value = NULL;
 	DefElem    *cache_value = NULL;
 	DefElem    *is_cycled = NULL;
+	DefElem    *defel;
 	ListCell   *option;
 	bool		reset_max_value = false;
 	bool		reset_min_value = false;
@@ -1256,95 +1257,68 @@ init_params(ParseState *pstate, List *options, bool for_identity,
 
 	foreach(option, options)
 	{
-		DefElem    *defel = (DefElem *) lfirst(option);
+		defel = (DefElem *) lfirst(option);
 
 		if (strcmp(defel->defname, "as") == 0)
 		{
 			if (as_type)
-				ereport(ERROR,
-						(errcode(ERRCODE_SYNTAX_ERROR),
-						 errmsg("conflicting or redundant options"),
-						 parser_errposition(pstate, defel->location)));
+				ReportDuplicateOptionError(defel, pstate);
 			as_type = defel;
 			*need_seq_rewrite = true;
 		}
 		else if (strcmp(defel->defname, "increment") == 0)
 		{
 			if (increment_by)
-				ereport(ERROR,
-						(errcode(ERRCODE_SYNTAX_ERROR),
-						 errmsg("conflicting or redundant options"),
-						 parser_errposition(pstate, defel->location)));
+				ReportDuplicateOptionError(defel, pstate);
 			increment_by = defel;
 			*need_seq_rewrite = true;
 		}
 		else if (strcmp(defel->defname, "start") == 0)
 		{
 			if (start_value)
-				ereport(ERROR,
-						(errcode(ERRCODE_SYNTAX_ERROR),
-						 errmsg("conflicting or redundant options"),
-						 parser_errposition(pstate, defel->location)));
+				ReportDuplicateOptionError(defel, pstate);
 			start_value = defel;
 			*need_seq_rewrite = true;
 		}
 		else if (strcmp(defel->defname, "restart") == 0)
 		{
 			if (restart_value)
-				ereport(ERROR,
-						(errcode(ERRCODE_SYNTAX_ERROR),
-						 errmsg("conflicting or redundant options"),
-						 parser_errposition(pstate, defel->location)));
+				ReportDuplicateOptionError(defel, pstate);
 			restart_value = defel;
 			*need_seq_rewrite = true;
 		}
 		else if (strcmp(defel->defname, "maxvalue") == 0)
 		{
 			if (max_value)
-				ereport(ERROR,
-						(errcode(ERRCODE_SYNTAX_ERROR),
-						 errmsg("conflicting or redundant options"),
-						 parser_errposition(pstate, defel->location)));
+				ReportDuplicateOptionError(defel, pstate);
 			max_value = defel;
 			*need_seq_rewrite = true;
 		}
 		else if (strcmp(defel->defname, "minvalue") == 0)
 		{
 			if (min_value)
-				ereport(ERROR,
-						(errcode(ERRCODE_SYNTAX_ERROR),
-						 errmsg("conflicting or redundant options"),
-						 parser_errposition(pstate, defel->location)));
+				ReportDuplicateOptionError(defel, pstate);
 			min_value = defel;
 			*need_seq_rewrite = true;
 		}
 		else if (strcmp(defel->defname, "cache") == 0)
 		{
 			if (cache_value)
-				ereport(ERROR,
-						(errcode(ERRCODE_SYNTAX_ERROR),
-						 errmsg("conflicting or redundant options"),
-						 parser_errposition(pstate, defel->location)));
+				ReportDuplicateOptionError(defel, pstate);
 			cache_value = defel;
 			*need_seq_rewrite = true;
 		}
 		else if (strcmp(defel->defname, "cycle") == 0)
 		{
 			if (is_cycled)
-				ereport(ERROR,
-						(errcode(ERRCODE_SYNTAX_ERROR),
-						 errmsg("conflicting or redundant options"),
-						 parser_errposition(pstate, defel->location)));
+				ReportDuplicateOptionError(defel, pstate);
 			is_cycled = defel;
 			*need_seq_rewrite = true;
 		}
 		else if (strcmp(defel->defname, "owned_by") == 0)
 		{
 			if (*owned_by)
-				ereport(ERROR,
-						(errcode(ERRCODE_SYNTAX_ERROR),
-						 errmsg("conflicting or redundant options"),
-						 parser_errposition(pstate, defel->location)));
+				ReportDuplicateOptionError(defel, pstate);
 			*owned_by = defGetQualifiedName(defel);
 		}
 		else if (strcmp(defel->defname, "sequence_name") == 0)
diff --git a/src/backend/commands/subscriptioncmds.c b/src/backend/commands/subscriptioncmds.c
index eb88d877a5..e064b90e3a 100644
--- a/src/backend/commands/subscriptioncmds.c
+++ b/src/backend/commands/subscriptioncmds.c
@@ -96,7 +96,8 @@ static void ReportSlotConnectionError(List *rstates, Oid subid, char *slotname,
  * Caller is expected to have cleared 'opts'.
  */
 static void
-parse_subscription_options(List *stmt_options, bits32 supported_opts, SubOpts *opts)
+parse_subscription_options(ParseState *pstate, List *stmt_options,
+						   bits32 supported_opts, SubOpts *opts)
 {
 	ListCell   *lc;
 
@@ -133,9 +134,7 @@ parse_subscription_options(List *stmt_options, bits32 supported_opts, SubOpts *o
 			strcmp(defel->defname, "connect") == 0)
 		{
 			if (IsSet(opts->specified_opts, SUBOPT_CONNECT))
-				ereport(ERROR,
-						(errcode(ERRCODE_SYNTAX_ERROR),
-						 errmsg("conflicting or redundant options")));
+				ReportDuplicateOptionError(defel, pstate);
 
 			opts->specified_opts |= SUBOPT_CONNECT;
 			opts->connect = defGetBoolean(defel);
@@ -144,9 +143,7 @@ parse_subscription_options(List *stmt_options, bits32 supported_opts, SubOpts *o
 				 strcmp(defel->defname, "enabled") == 0)
 		{
 			if (IsSet(opts->specified_opts, SUBOPT_ENABLED))
-				ereport(ERROR,
-						(errcode(ERRCODE_SYNTAX_ERROR),
-						 errmsg("conflicting or redundant options")));
+				ReportDuplicateOptionError(defel, pstate);
 
 			opts->specified_opts |= SUBOPT_ENABLED;
 			opts->enabled = defGetBoolean(defel);
@@ -155,9 +152,7 @@ parse_subscription_options(List *stmt_options, bits32 supported_opts, SubOpts *o
 				 strcmp(defel->defname, "create_slot") == 0)
 		{
 			if (IsSet(opts->specified_opts, SUBOPT_CREATE_SLOT))
-				ereport(ERROR,
-						(errcode(ERRCODE_SYNTAX_ERROR),
-						 errmsg("conflicting or redundant options")));
+				ReportDuplicateOptionError(defel, pstate);
 
 			opts->specified_opts |= SUBOPT_CREATE_SLOT;
 			opts->create_slot = defGetBoolean(defel);
@@ -166,9 +161,7 @@ parse_subscription_options(List *stmt_options, bits32 supported_opts, SubOpts *o
 				 strcmp(defel->defname, "slot_name") == 0)
 		{
 			if (IsSet(opts->specified_opts, SUBOPT_SLOT_NAME))
-				ereport(ERROR,
-						(errcode(ERRCODE_SYNTAX_ERROR),
-						 errmsg("conflicting or redundant options")));
+				ReportDuplicateOptionError(defel, pstate);
 
 			opts->specified_opts |= SUBOPT_SLOT_NAME;
 			opts->slot_name = defGetString(defel);
@@ -181,9 +174,7 @@ parse_subscription_options(List *stmt_options, bits32 supported_opts, SubOpts *o
 				 strcmp(defel->defname, "copy_data") == 0)
 		{
 			if (IsSet(opts->specified_opts, SUBOPT_COPY_DATA))
-				ereport(ERROR,
-						(errcode(ERRCODE_SYNTAX_ERROR),
-						 errmsg("conflicting or redundant options")));
+				ReportDuplicateOptionError(defel, pstate);
 
 			opts->specified_opts |= SUBOPT_COPY_DATA;
 			opts->copy_data = defGetBoolean(defel);
@@ -192,9 +183,7 @@ parse_subscription_options(List *stmt_options, bits32 supported_opts, SubOpts *o
 				 strcmp(defel->defname, "synchronous_commit") == 0)
 		{
 			if (IsSet(opts->specified_opts, SUBOPT_SYNCHRONOUS_COMMIT))
-				ereport(ERROR,
-						(errcode(ERRCODE_SYNTAX_ERROR),
-						 errmsg("conflicting or redundant options")));
+				ReportDuplicateOptionError(defel, pstate);
 
 			opts->specified_opts |= SUBOPT_SYNCHRONOUS_COMMIT;
 			opts->synchronous_commit = defGetString(defel);
@@ -208,9 +197,7 @@ parse_subscription_options(List *stmt_options, bits32 supported_opts, SubOpts *o
 				 strcmp(defel->defname, "refresh") == 0)
 		{
 			if (IsSet(opts->specified_opts, SUBOPT_REFRESH))
-				ereport(ERROR,
-						(errcode(ERRCODE_SYNTAX_ERROR),
-						 errmsg("conflicting or redundant options")));
+				ReportDuplicateOptionError(defel, pstate);
 
 			opts->specified_opts |= SUBOPT_REFRESH;
 			opts->refresh = defGetBoolean(defel);
@@ -219,9 +206,7 @@ parse_subscription_options(List *stmt_options, bits32 supported_opts, SubOpts *o
 				 strcmp(defel->defname, "binary") == 0)
 		{
 			if (IsSet(opts->specified_opts, SUBOPT_BINARY))
-				ereport(ERROR,
-						(errcode(ERRCODE_SYNTAX_ERROR),
-						 errmsg("conflicting or redundant options")));
+				ReportDuplicateOptionError(defel, pstate);
 
 			opts->specified_opts |= SUBOPT_BINARY;
 			opts->binary = defGetBoolean(defel);
@@ -230,9 +215,7 @@ parse_subscription_options(List *stmt_options, bits32 supported_opts, SubOpts *o
 				 strcmp(defel->defname, "streaming") == 0)
 		{
 			if (IsSet(opts->specified_opts, SUBOPT_STREAMING))
-				ereport(ERROR,
-						(errcode(ERRCODE_SYNTAX_ERROR),
-						 errmsg("conflicting or redundant options")));
+				ReportDuplicateOptionError(defel, pstate);
 
 			opts->specified_opts |= SUBOPT_STREAMING;
 			opts->streaming = defGetBoolean(defel);
@@ -362,7 +345,8 @@ publicationListToArray(List *publist)
  * Create new subscription.
  */
 ObjectAddress
-CreateSubscription(CreateSubscriptionStmt *stmt, bool isTopLevel)
+CreateSubscription(ParseState *pstate, CreateSubscriptionStmt *stmt,
+				   bool isTopLevel)
 {
 	Relation	rel;
 	ObjectAddress myself;
@@ -386,7 +370,7 @@ CreateSubscription(CreateSubscriptionStmt *stmt, bool isTopLevel)
 					  SUBOPT_SLOT_NAME | SUBOPT_COPY_DATA |
 					  SUBOPT_SYNCHRONOUS_COMMIT | SUBOPT_BINARY |
 					  SUBOPT_STREAMING);
-	parse_subscription_options(stmt->options, supported_opts, &opts);
+	parse_subscription_options(pstate, stmt->options, supported_opts, &opts);
 
 	/*
 	 * Since creating a replication slot is not transactional, rolling back
@@ -778,7 +762,8 @@ AlterSubscription_refresh(Subscription *sub, bool copy_data)
  * Alter the existing subscription.
  */
 ObjectAddress
-AlterSubscription(AlterSubscriptionStmt *stmt, bool isTopLevel)
+AlterSubscription(ParseState *pstate, AlterSubscriptionStmt *stmt,
+				  bool isTopLevel)
 {
 	Relation	rel;
 	ObjectAddress myself;
@@ -831,7 +816,8 @@ AlterSubscription(AlterSubscriptionStmt *stmt, bool isTopLevel)
 								  SUBOPT_SYNCHRONOUS_COMMIT | SUBOPT_BINARY |
 								  SUBOPT_STREAMING);
 
-				parse_subscription_options(stmt->options, supported_opts, &opts);
+				parse_subscription_options(pstate, stmt->options,
+										   supported_opts, &opts);
 
 				if (IsSet(opts.specified_opts, SUBOPT_SLOT_NAME))
 				{
@@ -876,7 +862,8 @@ AlterSubscription(AlterSubscriptionStmt *stmt, bool isTopLevel)
 
 		case ALTER_SUBSCRIPTION_ENABLED:
 			{
-				parse_subscription_options(stmt->options, SUBOPT_ENABLED, &opts);
+				parse_subscription_options(pstate, stmt->options,
+										   SUBOPT_ENABLED, &opts);
 				Assert(IsSet(opts.specified_opts, SUBOPT_ENABLED));
 
 				if (!sub->slotname && opts.enabled)
@@ -910,7 +897,8 @@ AlterSubscription(AlterSubscriptionStmt *stmt, bool isTopLevel)
 		case ALTER_SUBSCRIPTION_SET_PUBLICATION:
 			{
 				supported_opts = SUBOPT_COPY_DATA | SUBOPT_REFRESH;
-				parse_subscription_options(stmt->options, supported_opts, &opts);
+				parse_subscription_options(pstate, stmt->options,
+										   supported_opts, &opts);
 
 				values[Anum_pg_subscription_subpublications - 1] =
 					publicationListToArray(stmt->publication);
@@ -948,7 +936,8 @@ AlterSubscription(AlterSubscriptionStmt *stmt, bool isTopLevel)
 				if (isadd)
 					supported_opts |= SUBOPT_COPY_DATA;
 
-				parse_subscription_options(stmt->options, supported_opts, &opts);
+				parse_subscription_options(pstate, stmt->options,
+										   supported_opts, &opts);
 
 				publist = merge_publications(sub->publications, stmt->publication, isadd, stmt->subname);
 				values[Anum_pg_subscription_subpublications - 1] =
@@ -984,7 +973,8 @@ AlterSubscription(AlterSubscriptionStmt *stmt, bool isTopLevel)
 							(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
 							 errmsg("ALTER SUBSCRIPTION ... REFRESH is not allowed for disabled subscriptions")));
 
-				parse_subscription_options(stmt->options, SUBOPT_COPY_DATA, &opts);
+				parse_subscription_options(pstate, stmt->options,
+										   SUBOPT_COPY_DATA, &opts);
 
 				PreventInTransactionBlock(isTopLevel, "ALTER SUBSCRIPTION ... REFRESH");
 
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index 97a9725df7..b3717d110e 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -7494,9 +7494,7 @@ ATExecSetIdentity(Relation rel, const char *colName, Node *def, LOCKMODE lockmod
 		if (strcmp(defel->defname, "generated") == 0)
 		{
 			if (generatedEl)
-				ereport(ERROR,
-						(errcode(ERRCODE_SYNTAX_ERROR),
-						 errmsg("conflicting or redundant options")));
+				ReportDuplicateOptionError(defel, NULL);
 			generatedEl = defel;
 		}
 		else
diff --git a/src/backend/commands/typecmds.c b/src/backend/commands/typecmds.c
index 58ec65c6af..c65d6d4c32 100644
--- a/src/backend/commands/typecmds.c
+++ b/src/backend/commands/typecmds.c
@@ -330,10 +330,7 @@ DefineType(ParseState *pstate, List *names, List *parameters)
 			continue;
 		}
 		if (*defelp != NULL)
-			ereport(ERROR,
-					(errcode(ERRCODE_SYNTAX_ERROR),
-					 errmsg("conflicting or redundant options"),
-					 parser_errposition(pstate, defel->location)));
+			ReportDuplicateOptionError(defel, pstate);
 		*defelp = defel;
 	}
 
@@ -1336,7 +1333,7 @@ checkEnumOwner(HeapTuple tup)
  * and users might have queries with that same assumption.
  */
 ObjectAddress
-DefineRange(CreateRangeStmt *stmt)
+DefineRange(ParseState *pstate, CreateRangeStmt *stmt)
 {
 	char	   *typeName;
 	Oid			typeNamespace;
@@ -1366,6 +1363,7 @@ DefineRange(CreateRangeStmt *stmt)
 	ObjectAddress address;
 	ObjectAddress mltrngaddress PG_USED_FOR_ASSERTS_ONLY;
 	Oid			castFuncOid;
+	DefElem    *defel;
 
 	/* Convert list of names to a name and namespace */
 	typeNamespace = QualifiedNameGetCreationNamespace(stmt->typeName,
@@ -1406,55 +1404,43 @@ DefineRange(CreateRangeStmt *stmt)
 	/* Extract the parameters from the parameter list */
 	foreach(lc, stmt->params)
 	{
-		DefElem    *defel = (DefElem *) lfirst(lc);
+		defel = (DefElem *) lfirst(lc);
 
 		if (strcmp(defel->defname, "subtype") == 0)
 		{
 			if (OidIsValid(rangeSubtype))
-				ereport(ERROR,
-						(errcode(ERRCODE_SYNTAX_ERROR),
-						 errmsg("conflicting or redundant options")));
+				ReportDuplicateOptionError(defel, pstate);
 			/* we can look up the subtype name immediately */
 			rangeSubtype = typenameTypeId(NULL, defGetTypeName(defel));
 		}
 		else if (strcmp(defel->defname, "subtype_opclass") == 0)
 		{
 			if (rangeSubOpclassName != NIL)
-				ereport(ERROR,
-						(errcode(ERRCODE_SYNTAX_ERROR),
-						 errmsg("conflicting or redundant options")));
+				ReportDuplicateOptionError(defel, pstate);
 			rangeSubOpclassName = defGetQualifiedName(defel);
 		}
 		else if (strcmp(defel->defname, "collation") == 0)
 		{
 			if (rangeCollationName != NIL)
-				ereport(ERROR,
-						(errcode(ERRCODE_SYNTAX_ERROR),
-						 errmsg("conflicting or redundant options")));
+				ReportDuplicateOptionError(defel, pstate);
 			rangeCollationName = defGetQualifiedName(defel);
 		}
 		else if (strcmp(defel->defname, "canonical") == 0)
 		{
 			if (rangeCanonicalName != NIL)
-				ereport(ERROR,
-						(errcode(ERRCODE_SYNTAX_ERROR),
-						 errmsg("conflicting or redundant options")));
+				ReportDuplicateOptionError(defel, pstate);
 			rangeCanonicalName = defGetQualifiedName(defel);
 		}
 		else if (strcmp(defel->defname, "subtype_diff") == 0)
 		{
 			if (rangeSubtypeDiffName != NIL)
-				ereport(ERROR,
-						(errcode(ERRCODE_SYNTAX_ERROR),
-						 errmsg("conflicting or redundant options")));
+				ReportDuplicateOptionError(defel, pstate);
 			rangeSubtypeDiffName = defGetQualifiedName(defel);
 		}
 		else if (strcmp(defel->defname, "multirange_type_name") == 0)
 		{
 			if (multirangeTypeName != NULL)
-				ereport(ERROR,
-						(errcode(ERRCODE_SYNTAX_ERROR),
-						 errmsg("conflicting or redundant options")));
+				ReportDuplicateOptionError(defel, pstate);
 			/* we can look up the subtype name immediately */
 			multirangeNamespace = QualifiedNameGetCreationNamespace(defGetQualifiedName(defel),
 																	&multirangeTypeName);
diff --git a/src/backend/commands/user.c b/src/backend/commands/user.c
index 65bb733958..5045ae3daf 100644
--- a/src/backend/commands/user.c
+++ b/src/backend/commands/user.c
@@ -27,6 +27,7 @@
 #include "catalog/pg_db_role_setting.h"
 #include "commands/comment.h"
 #include "commands/dbcommands.h"
+#include "commands/defrem.h"
 #include "commands/seclabel.h"
 #include "commands/user.h"
 #include "libpq/crypt.h"
@@ -106,6 +107,7 @@ CreateRole(ParseState *pstate, CreateRoleStmt *stmt)
 	DefElem    *dadminmembers = NULL;
 	DefElem    *dvalidUntil = NULL;
 	DefElem    *dbypassRLS = NULL;
+	DefElem    *defel;
 
 	/* The defaults can vary depending on the original statement type */
 	switch (stmt->stmt_type)
@@ -123,15 +125,12 @@ CreateRole(ParseState *pstate, CreateRoleStmt *stmt)
 	/* Extract options from the statement node tree */
 	foreach(option, stmt->options)
 	{
-		DefElem    *defel = (DefElem *) lfirst(option);
+		defel = (DefElem *) lfirst(option);
 
 		if (strcmp(defel->defname, "password") == 0)
 		{
 			if (dpassword)
-				ereport(ERROR,
-						(errcode(ERRCODE_SYNTAX_ERROR),
-						 errmsg("conflicting or redundant options"),
-						 parser_errposition(pstate, defel->location)));
+				ReportDuplicateOptionError(defel, pstate);
 			dpassword = defel;
 		}
 		else if (strcmp(defel->defname, "sysid") == 0)
@@ -142,109 +141,73 @@ CreateRole(ParseState *pstate, CreateRoleStmt *stmt)
 		else if (strcmp(defel->defname, "superuser") == 0)
 		{
 			if (dissuper)
-				ereport(ERROR,
-						(errcode(ERRCODE_SYNTAX_ERROR),
-						 errmsg("conflicting or redundant options"),
-						 parser_errposition(pstate, defel->location)));
+				ReportDuplicateOptionError(defel, pstate);
 			dissuper = defel;
 		}
 		else if (strcmp(defel->defname, "inherit") == 0)
 		{
 			if (dinherit)
-				ereport(ERROR,
-						(errcode(ERRCODE_SYNTAX_ERROR),
-						 errmsg("conflicting or redundant options"),
-						 parser_errposition(pstate, defel->location)));
+				ReportDuplicateOptionError(defel, pstate);
 			dinherit = defel;
 		}
 		else if (strcmp(defel->defname, "createrole") == 0)
 		{
 			if (dcreaterole)
-				ereport(ERROR,
-						(errcode(ERRCODE_SYNTAX_ERROR),
-						 errmsg("conflicting or redundant options"),
-						 parser_errposition(pstate, defel->location)));
+				ReportDuplicateOptionError(defel, pstate);
 			dcreaterole = defel;
 		}
 		else if (strcmp(defel->defname, "createdb") == 0)
 		{
 			if (dcreatedb)
-				ereport(ERROR,
-						(errcode(ERRCODE_SYNTAX_ERROR),
-						 errmsg("conflicting or redundant options"),
-						 parser_errposition(pstate, defel->location)));
+				ReportDuplicateOptionError(defel, pstate);
 			dcreatedb = defel;
 		}
 		else if (strcmp(defel->defname, "canlogin") == 0)
 		{
 			if (dcanlogin)
-				ereport(ERROR,
-						(errcode(ERRCODE_SYNTAX_ERROR),
-						 errmsg("conflicting or redundant options"),
-						 parser_errposition(pstate, defel->location)));
+				ReportDuplicateOptionError(defel, pstate);
 			dcanlogin = defel;
 		}
 		else if (strcmp(defel->defname, "isreplication") == 0)
 		{
 			if (disreplication)
-				ereport(ERROR,
-						(errcode(ERRCODE_SYNTAX_ERROR),
-						 errmsg("conflicting or redundant options"),
-						 parser_errposition(pstate, defel->location)));
+				ReportDuplicateOptionError(defel, pstate);
 			disreplication = defel;
 		}
 		else if (strcmp(defel->defname, "connectionlimit") == 0)
 		{
 			if (dconnlimit)
-				ereport(ERROR,
-						(errcode(ERRCODE_SYNTAX_ERROR),
-						 errmsg("conflicting or redundant options"),
-						 parser_errposition(pstate, defel->location)));
+				ReportDuplicateOptionError(defel, pstate);
 			dconnlimit = defel;
 		}
 		else if (strcmp(defel->defname, "addroleto") == 0)
 		{
 			if (daddroleto)
-				ereport(ERROR,
-						(errcode(ERRCODE_SYNTAX_ERROR),
-						 errmsg("conflicting or redundant options"),
-						 parser_errposition(pstate, defel->location)));
+				ReportDuplicateOptionError(defel, pstate);
 			daddroleto = defel;
 		}
 		else if (strcmp(defel->defname, "rolemembers") == 0)
 		{
 			if (drolemembers)
-				ereport(ERROR,
-						(errcode(ERRCODE_SYNTAX_ERROR),
-						 errmsg("conflicting or redundant options"),
-						 parser_errposition(pstate, defel->location)));
+				ReportDuplicateOptionError(defel, pstate);
 			drolemembers = defel;
 		}
 		else if (strcmp(defel->defname, "adminmembers") == 0)
 		{
 			if (dadminmembers)
-				ereport(ERROR,
-						(errcode(ERRCODE_SYNTAX_ERROR),
-						 errmsg("conflicting or redundant options"),
-						 parser_errposition(pstate, defel->location)));
+				ReportDuplicateOptionError(defel, pstate);
 			dadminmembers = defel;
 		}
 		else if (strcmp(defel->defname, "validUntil") == 0)
 		{
 			if (dvalidUntil)
-				ereport(ERROR,
-						(errcode(ERRCODE_SYNTAX_ERROR),
-						 errmsg("conflicting or redundant options"),
-						 parser_errposition(pstate, defel->location)));
+				ReportDuplicateOptionError(defel, pstate);
 			dvalidUntil = defel;
 		}
 		else if (strcmp(defel->defname, "bypassrls") == 0)
 		{
 			if (dbypassRLS)
-				ereport(ERROR,
-						(errcode(ERRCODE_SYNTAX_ERROR),
-						 errmsg("conflicting or redundant options"),
-						 parser_errposition(pstate, defel->location)));
+				ReportDuplicateOptionError(defel, pstate);
 			dbypassRLS = defel;
 		}
 		else
@@ -528,7 +491,7 @@ CreateRole(ParseState *pstate, CreateRoleStmt *stmt)
  * "ALTER ROLE role ROLE rolenames", we don't document it.
  */
 Oid
-AlterRole(AlterRoleStmt *stmt)
+AlterRole(ParseState *pstate, AlterRoleStmt *stmt)
 {
 	Datum		new_record[Natts_pg_authid];
 	bool		new_record_nulls[Natts_pg_authid];
@@ -564,6 +527,7 @@ AlterRole(AlterRoleStmt *stmt)
 	DefElem    *drolemembers = NULL;
 	DefElem    *dvalidUntil = NULL;
 	DefElem    *dbypassRLS = NULL;
+	DefElem    *defel;
 	Oid			roleid;
 
 	check_rolespec_name(stmt->role,
@@ -572,95 +536,73 @@ AlterRole(AlterRoleStmt *stmt)
 	/* Extract options from the statement node tree */
 	foreach(option, stmt->options)
 	{
-		DefElem    *defel = (DefElem *) lfirst(option);
+		defel = (DefElem *) lfirst(option);
 
 		if (strcmp(defel->defname, "password") == 0)
 		{
 			if (dpassword)
-				ereport(ERROR,
-						(errcode(ERRCODE_SYNTAX_ERROR),
-						 errmsg("conflicting or redundant options")));
+				ReportDuplicateOptionError(defel, pstate);
 			dpassword = defel;
 		}
 		else if (strcmp(defel->defname, "superuser") == 0)
 		{
 			if (dissuper)
-				ereport(ERROR,
-						(errcode(ERRCODE_SYNTAX_ERROR),
-						 errmsg("conflicting or redundant options")));
+				ReportDuplicateOptionError(defel, pstate);
 			dissuper = defel;
 		}
 		else if (strcmp(defel->defname, "inherit") == 0)
 		{
 			if (dinherit)
-				ereport(ERROR,
-						(errcode(ERRCODE_SYNTAX_ERROR),
-						 errmsg("conflicting or redundant options")));
+				ReportDuplicateOptionError(defel, pstate);
 			dinherit = defel;
 		}
 		else if (strcmp(defel->defname, "createrole") == 0)
 		{
 			if (dcreaterole)
-				ereport(ERROR,
-						(errcode(ERRCODE_SYNTAX_ERROR),
-						 errmsg("conflicting or redundant options")));
+				ReportDuplicateOptionError(defel, pstate);
 			dcreaterole = defel;
 		}
 		else if (strcmp(defel->defname, "createdb") == 0)
 		{
 			if (dcreatedb)
-				ereport(ERROR,
-						(errcode(ERRCODE_SYNTAX_ERROR),
-						 errmsg("conflicting or redundant options")));
+				ReportDuplicateOptionError(defel, pstate);
 			dcreatedb = defel;
 		}
 		else if (strcmp(defel->defname, "canlogin") == 0)
 		{
 			if (dcanlogin)
-				ereport(ERROR,
-						(errcode(ERRCODE_SYNTAX_ERROR),
-						 errmsg("conflicting or redundant options")));
+				ReportDuplicateOptionError(defel, pstate);
 			dcanlogin = defel;
 		}
 		else if (strcmp(defel->defname, "isreplication") == 0)
 		{
 			if (disreplication)
-				ereport(ERROR,
-						(errcode(ERRCODE_SYNTAX_ERROR),
-						 errmsg("conflicting or redundant options")));
+				ReportDuplicateOptionError(defel, pstate);
 			disreplication = defel;
 		}
 		else if (strcmp(defel->defname, "connectionlimit") == 0)
 		{
 			if (dconnlimit)
-				ereport(ERROR,
-						(errcode(ERRCODE_SYNTAX_ERROR),
-						 errmsg("conflicting or redundant options")));
+				ReportDuplicateOptionError(defel, pstate);
 			dconnlimit = defel;
 		}
 		else if (strcmp(defel->defname, "rolemembers") == 0 &&
 				 stmt->action != 0)
 		{
 			if (drolemembers)
-				ereport(ERROR,
-						(errcode(ERRCODE_SYNTAX_ERROR),
-						 errmsg("conflicting or redundant options")));
+				ReportDuplicateOptionError(defel, pstate);
 			drolemembers = defel;
 		}
 		else if (strcmp(defel->defname, "validUntil") == 0)
 		{
 			if (dvalidUntil)
-				ereport(ERROR,
-						(errcode(ERRCODE_SYNTAX_ERROR),
-						 errmsg("conflicting or redundant options")));
+				ReportDuplicateOptionError(defel, pstate);
 			dvalidUntil = defel;
 		}
 		else if (strcmp(defel->defname, "bypassrls") == 0)
 		{
 			if (dbypassRLS)
-				ereport(ERROR,
-						(errcode(ERRCODE_SYNTAX_ERROR),
-						 errmsg("conflicting or redundant options")));
+				ReportDuplicateOptionError(defel, pstate);
 			dbypassRLS = defel;
 		}
 		else
diff --git a/src/backend/parser/parse_utilcmd.c b/src/backend/parser/parse_utilcmd.c
index 81d3e7990c..9bf0c9ad53 100644
--- a/src/backend/parser/parse_utilcmd.c
+++ b/src/backend/parser/parse_utilcmd.c
@@ -392,9 +392,7 @@ generateSerialExtraStmts(CreateStmtContext *cxt, ColumnDef *column,
 		if (strcmp(defel->defname, "sequence_name") == 0)
 		{
 			if (nameEl)
-				ereport(ERROR,
-						(errcode(ERRCODE_SYNTAX_ERROR),
-						 errmsg("conflicting or redundant options")));
+				ReportDuplicateOptionError(defel, NULL);
 			nameEl = defel;
 			nameEl_idx = foreach_current_index(option);
 		}
diff --git a/src/backend/replication/pgoutput/pgoutput.c b/src/backend/replication/pgoutput/pgoutput.c
index abd5217ab1..e6becc7a17 100644
--- a/src/backend/replication/pgoutput/pgoutput.c
+++ b/src/backend/replication/pgoutput/pgoutput.c
@@ -162,6 +162,7 @@ static void
 parse_output_parameters(List *options, PGOutputData *data)
 {
 	ListCell   *lc;
+	DefElem    *defel;
 	bool		protocol_version_given = false;
 	bool		publication_names_given = false;
 	bool		binary_option_given = false;
@@ -174,7 +175,7 @@ parse_output_parameters(List *options, PGOutputData *data)
 
 	foreach(lc, options)
 	{
-		DefElem    *defel = (DefElem *) lfirst(lc);
+		defel = (DefElem *) lfirst(lc);
 
 		Assert(defel->arg == NULL || IsA(defel->arg, String));
 
@@ -184,9 +185,7 @@ parse_output_parameters(List *options, PGOutputData *data)
 			int64		parsed;
 
 			if (protocol_version_given)
-				ereport(ERROR,
-						(errcode(ERRCODE_SYNTAX_ERROR),
-						 errmsg("conflicting or redundant options")));
+				ReportDuplicateOptionError(defel, NULL);
 			protocol_version_given = true;
 
 			if (!scanint8(strVal(defel->arg), true, &parsed))
@@ -205,9 +204,7 @@ parse_output_parameters(List *options, PGOutputData *data)
 		else if (strcmp(defel->defname, "publication_names") == 0)
 		{
 			if (publication_names_given)
-				ereport(ERROR,
-						(errcode(ERRCODE_SYNTAX_ERROR),
-						 errmsg("conflicting or redundant options")));
+				ReportDuplicateOptionError(defel, NULL);
 			publication_names_given = true;
 
 			if (!SplitIdentifierString(strVal(defel->arg), ',',
@@ -219,9 +216,7 @@ parse_output_parameters(List *options, PGOutputData *data)
 		else if (strcmp(defel->defname, "binary") == 0)
 		{
 			if (binary_option_given)
-				ereport(ERROR,
-						(errcode(ERRCODE_SYNTAX_ERROR),
-						 errmsg("conflicting or redundant options")));
+				ReportDuplicateOptionError(defel, NULL);
 			binary_option_given = true;
 
 			data->binary = defGetBoolean(defel);
@@ -229,9 +224,7 @@ parse_output_parameters(List *options, PGOutputData *data)
 		else if (strcmp(defel->defname, "messages") == 0)
 		{
 			if (messages_option_given)
-				ereport(ERROR,
-						(errcode(ERRCODE_SYNTAX_ERROR),
-						 errmsg("conflicting or redundant options")));
+				ReportDuplicateOptionError(defel, NULL);
 			messages_option_given = true;
 
 			data->messages = defGetBoolean(defel);
@@ -239,9 +232,7 @@ parse_output_parameters(List *options, PGOutputData *data)
 		else if (strcmp(defel->defname, "streaming") == 0)
 		{
 			if (streaming_given)
-				ereport(ERROR,
-						(errcode(ERRCODE_SYNTAX_ERROR),
-						 errmsg("conflicting or redundant options")));
+				ReportDuplicateOptionError(defel, NULL);
 			streaming_given = true;
 
 			data->streaming = defGetBoolean(defel);
diff --git a/src/backend/replication/walsender.c b/src/backend/replication/walsender.c
index 92c755f346..3ca75f6fec 100644
--- a/src/backend/replication/walsender.c
+++ b/src/backend/replication/walsender.c
@@ -870,18 +870,17 @@ parseCreateReplSlotOptions(CreateReplicationSlotCmd *cmd,
 	bool		snapshot_action_given = false;
 	bool		reserve_wal_given = false;
 	bool		two_phase_given = false;
+	DefElem    *defel;
 
 	/* Parse options */
 	foreach(lc, cmd->options)
 	{
-		DefElem    *defel = (DefElem *) lfirst(lc);
+		defel = (DefElem *) lfirst(lc);
 
 		if (strcmp(defel->defname, "export_snapshot") == 0)
 		{
 			if (snapshot_action_given || cmd->kind != REPLICATION_KIND_LOGICAL)
-				ereport(ERROR,
-						(errcode(ERRCODE_SYNTAX_ERROR),
-						 errmsg("conflicting or redundant options")));
+				ReportDuplicateOptionError(defel, NULL);
 
 			snapshot_action_given = true;
 			*snapshot_action = defGetBoolean(defel) ? CRS_EXPORT_SNAPSHOT :
@@ -890,9 +889,7 @@ parseCreateReplSlotOptions(CreateReplicationSlotCmd *cmd,
 		else if (strcmp(defel->defname, "use_snapshot") == 0)
 		{
 			if (snapshot_action_given || cmd->kind != REPLICATION_KIND_LOGICAL)
-				ereport(ERROR,
-						(errcode(ERRCODE_SYNTAX_ERROR),
-						 errmsg("conflicting or redundant options")));
+				ReportDuplicateOptionError(defel, NULL);
 
 			snapshot_action_given = true;
 			*snapshot_action = CRS_USE_SNAPSHOT;
@@ -900,9 +897,7 @@ parseCreateReplSlotOptions(CreateReplicationSlotCmd *cmd,
 		else if (strcmp(defel->defname, "reserve_wal") == 0)
 		{
 			if (reserve_wal_given || cmd->kind != REPLICATION_KIND_PHYSICAL)
-				ereport(ERROR,
-						(errcode(ERRCODE_SYNTAX_ERROR),
-						 errmsg("conflicting or redundant options")));
+				ReportDuplicateOptionError(defel, NULL);
 
 			reserve_wal_given = true;
 			*reserve_wal = true;
diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c
index 7a2da9dab4..27fbf1f3aa 100644
--- a/src/backend/tcop/utility.c
+++ b/src/backend/tcop/utility.c
@@ -708,7 +708,7 @@ standard_ProcessUtility(PlannedStmt *pstmt,
 			break;
 
 		case T_DoStmt:
-			ExecuteDoStmt((DoStmt *) parsetree, isAtomicContext);
+			ExecuteDoStmt(pstate, (DoStmt *) parsetree, isAtomicContext);
 			break;
 
 		case T_CreateTableSpaceStmt:
@@ -888,7 +888,7 @@ standard_ProcessUtility(PlannedStmt *pstmt,
 
 		case T_AlterRoleStmt:
 			/* no event triggers for global objects */
-			AlterRole((AlterRoleStmt *) parsetree);
+			AlterRole(pstate, (AlterRoleStmt *) parsetree);
 			break;
 
 		case T_AlterRoleSetStmt:
@@ -1552,11 +1552,11 @@ ProcessUtilitySlow(ParseState *pstate,
 				break;
 
 			case T_CreateFdwStmt:
-				address = CreateForeignDataWrapper((CreateFdwStmt *) parsetree);
+				address = CreateForeignDataWrapper(pstate, (CreateFdwStmt *) parsetree);
 				break;
 
 			case T_AlterFdwStmt:
-				address = AlterForeignDataWrapper((AlterFdwStmt *) parsetree);
+				address = AlterForeignDataWrapper(pstate, (AlterFdwStmt *) parsetree);
 				break;
 
 			case T_CreateForeignServerStmt:
@@ -1601,7 +1601,7 @@ ProcessUtilitySlow(ParseState *pstate,
 				break;
 
 			case T_CreateRangeStmt: /* CREATE TYPE AS RANGE */
-				address = DefineRange((CreateRangeStmt *) parsetree);
+				address = DefineRange(pstate, (CreateRangeStmt *) parsetree);
 				break;
 
 			case T_AlterEnumStmt:	/* ALTER TYPE (enum) */
@@ -1802,11 +1802,11 @@ ProcessUtilitySlow(ParseState *pstate,
 				break;
 
 			case T_CreatePublicationStmt:
-				address = CreatePublication((CreatePublicationStmt *) parsetree);
+				address = CreatePublication(pstate, (CreatePublicationStmt *) parsetree);
 				break;
 
 			case T_AlterPublicationStmt:
-				AlterPublication((AlterPublicationStmt *) parsetree);
+				AlterPublication(pstate, (AlterPublicationStmt *) parsetree);
 
 				/*
 				 * AlterPublication calls EventTriggerCollectSimpleCommand
@@ -1816,12 +1816,14 @@ ProcessUtilitySlow(ParseState *pstate,
 				break;
 
 			case T_CreateSubscriptionStmt:
-				address = CreateSubscription((CreateSubscriptionStmt *) parsetree,
+				address = CreateSubscription(pstate,
+											 (CreateSubscriptionStmt *) parsetree,
 											 isTopLevel);
 				break;
 
 			case T_AlterSubscriptionStmt:
-				address = AlterSubscription((AlterSubscriptionStmt *) parsetree,
+				address = AlterSubscription(pstate,
+											(AlterSubscriptionStmt *) parsetree,
 											isTopLevel);
 				break;
 
diff --git a/src/include/commands/defrem.h b/src/include/commands/defrem.h
index 42bf1c7519..0791444682 100644
--- a/src/include/commands/defrem.h
+++ b/src/include/commands/defrem.h
@@ -56,7 +56,7 @@ extern ObjectAddress CreateCast(CreateCastStmt *stmt);
 extern ObjectAddress CreateTransform(CreateTransformStmt *stmt);
 extern void IsThereFunctionInNamespace(const char *proname, int pronargs,
 									   oidvector *proargtypes, Oid nspOid);
-extern void ExecuteDoStmt(DoStmt *stmt, bool atomic);
+extern void ExecuteDoStmt(ParseState *pstate, DoStmt *stmt, bool atomic);
 extern void ExecuteCallStmt(CallStmt *stmt, ParamListInfo params, bool atomic, DestReceiver *dest);
 extern TupleDesc CallStmtResultDesc(CallStmt *stmt);
 extern Oid	get_transform_oid(Oid type_id, Oid lang_id, bool missing_ok);
@@ -121,8 +121,8 @@ extern ObjectAddress AlterForeignServerOwner(const char *name, Oid newOwnerId);
 extern void AlterForeignServerOwner_oid(Oid, Oid newOwnerId);
 extern ObjectAddress AlterForeignDataWrapperOwner(const char *name, Oid newOwnerId);
 extern void AlterForeignDataWrapperOwner_oid(Oid fwdId, Oid newOwnerId);
-extern ObjectAddress CreateForeignDataWrapper(CreateFdwStmt *stmt);
-extern ObjectAddress AlterForeignDataWrapper(AlterFdwStmt *stmt);
+extern ObjectAddress CreateForeignDataWrapper(ParseState *pstate, CreateFdwStmt *stmt);
+extern ObjectAddress AlterForeignDataWrapper(ParseState *pstate, AlterFdwStmt *stmt);
 extern ObjectAddress CreateForeignServer(CreateForeignServerStmt *stmt);
 extern ObjectAddress AlterForeignServer(AlterForeignServerStmt *stmt);
 extern ObjectAddress CreateUserMapping(CreateUserMappingStmt *stmt);
@@ -154,4 +154,14 @@ extern TypeName *defGetTypeName(DefElem *def);
 extern int	defGetTypeLength(DefElem *def);
 extern List *defGetStringList(DefElem *def);
 
+static inline void
+pg_attribute_noreturn()
+ReportDuplicateOptionError(DefElem *defel, ParseState *pstate)
+{
+	ereport(ERROR,
+			errcode(ERRCODE_SYNTAX_ERROR),
+			errmsg("option \"%s\" specified more than once", defel->defname),
+			pstate ? parser_errposition(pstate, defel->location) : 0);
+}
+
 #endif							/* DEFREM_H */
diff --git a/src/include/commands/publicationcmds.h b/src/include/commands/publicationcmds.h
index 00e2e626e6..efea01f2a9 100644
--- a/src/include/commands/publicationcmds.h
+++ b/src/include/commands/publicationcmds.h
@@ -18,8 +18,8 @@
 #include "catalog/objectaddress.h"
 #include "nodes/parsenodes.h"
 
-extern ObjectAddress CreatePublication(CreatePublicationStmt *stmt);
-extern void AlterPublication(AlterPublicationStmt *stmt);
+extern ObjectAddress CreatePublication(ParseState *pstate, CreatePublicationStmt *stmt);
+extern void AlterPublication(ParseState *pstate, AlterPublicationStmt *stmt);
 extern void RemovePublicationRelById(Oid proid);
 
 extern ObjectAddress AlterPublicationOwner(const char *name, Oid newOwnerId);
diff --git a/src/include/commands/subscriptioncmds.h b/src/include/commands/subscriptioncmds.h
index 3b926f35d7..8bf25ee66c 100644
--- a/src/include/commands/subscriptioncmds.h
+++ b/src/include/commands/subscriptioncmds.h
@@ -18,9 +18,9 @@
 #include "catalog/objectaddress.h"
 #include "nodes/parsenodes.h"
 
-extern ObjectAddress CreateSubscription(CreateSubscriptionStmt *stmt,
+extern ObjectAddress CreateSubscription(ParseState *pstate, CreateSubscriptionStmt *stmt,
 										bool isTopLevel);
-extern ObjectAddress AlterSubscription(AlterSubscriptionStmt *stmt, bool isTopLevel);
+extern ObjectAddress AlterSubscription(ParseState *pstate, AlterSubscriptionStmt *stmt, bool isTopLevel);
 extern void DropSubscription(DropSubscriptionStmt *stmt, bool isTopLevel);
 
 extern ObjectAddress AlterSubscriptionOwner(const char *name, Oid newOwnerId);
diff --git a/src/include/commands/typecmds.h b/src/include/commands/typecmds.h
index 880679127b..d5e22811d0 100644
--- a/src/include/commands/typecmds.h
+++ b/src/include/commands/typecmds.h
@@ -25,7 +25,7 @@ extern ObjectAddress DefineType(ParseState *pstate, List *names, List *parameter
 extern void RemoveTypeById(Oid typeOid);
 extern ObjectAddress DefineDomain(CreateDomainStmt *stmt);
 extern ObjectAddress DefineEnum(CreateEnumStmt *stmt);
-extern ObjectAddress DefineRange(CreateRangeStmt *stmt);
+extern ObjectAddress DefineRange(ParseState *pstate, CreateRangeStmt *stmt);
 extern ObjectAddress AlterEnum(AlterEnumStmt *stmt);
 extern ObjectAddress DefineCompositeType(RangeVar *typevar, List *coldeflist);
 extern Oid	AssignTypeArrayOid(void);
diff --git a/src/include/commands/user.h b/src/include/commands/user.h
index 028e0dde56..0b7a3cd65f 100644
--- a/src/include/commands/user.h
+++ b/src/include/commands/user.h
@@ -25,7 +25,7 @@ typedef void (*check_password_hook_type) (const char *username, const char *shad
 extern PGDLLIMPORT check_password_hook_type check_password_hook;
 
 extern Oid	CreateRole(ParseState *pstate, CreateRoleStmt *stmt);
-extern Oid	AlterRole(AlterRoleStmt *stmt);
+extern Oid	AlterRole(ParseState *pstate, AlterRoleStmt *stmt);
 extern Oid	AlterRoleSet(AlterRoleSetStmt *stmt);
 extern void DropRole(DropRoleStmt *stmt);
 extern void GrantRole(GrantRoleStmt *stmt);
diff --git a/src/test/regress/expected/copy2.out b/src/test/regress/expected/copy2.out
index c64f0719e7..92fe8a121a 100644
--- a/src/test/regress/expected/copy2.out
+++ b/src/test/regress/expected/copy2.out
@@ -30,31 +30,31 @@ COPY x (xyz) from stdin;
 ERROR:  column "xyz" of relation "x" does not exist
 -- redundant options
 COPY x from stdin (format CSV, FORMAT CSV);
-ERROR:  conflicting or redundant options
+ERROR:  option "format" specified more than once
 LINE 1: COPY x from stdin (format CSV, FORMAT CSV);
                                        ^
 COPY x from stdin (freeze off, freeze on);
-ERROR:  conflicting or redundant options
+ERROR:  option "freeze" specified more than once
 LINE 1: COPY x from stdin (freeze off, freeze on);
                                        ^
 COPY x from stdin (delimiter ',', delimiter ',');
-ERROR:  conflicting or redundant options
+ERROR:  option "delimiter" specified more than once
 LINE 1: COPY x from stdin (delimiter ',', delimiter ',');
                                           ^
 COPY x from stdin (null ' ', null ' ');
-ERROR:  conflicting or redundant options
+ERROR:  option "null" specified more than once
 LINE 1: COPY x from stdin (null ' ', null ' ');
                                      ^
 COPY x from stdin (header off, header on);
-ERROR:  conflicting or redundant options
+ERROR:  option "header" specified more than once
 LINE 1: COPY x from stdin (header off, header on);
                                        ^
 COPY x from stdin (quote ':', quote ':');
-ERROR:  conflicting or redundant options
+ERROR:  option "quote" specified more than once
 LINE 1: COPY x from stdin (quote ':', quote ':');
                                       ^
 COPY x from stdin (escape ':', escape ':');
-ERROR:  conflicting or redundant options
+ERROR:  option "escape" specified more than once
 LINE 1: COPY x from stdin (escape ':', escape ':');
                                        ^
 COPY x from stdin (force_quote (a), force_quote *);
@@ -62,17 +62,19 @@ ERROR:  conflicting or redundant options
 LINE 1: COPY x from stdin (force_quote (a), force_quote *);
                                             ^
 COPY x from stdin (force_not_null (a), force_not_null (b));
-ERROR:  conflicting or redundant options
+ERROR:  option "force_not_null" specified more than once
 LINE 1: COPY x from stdin (force_not_null (a), force_not_null (b));
                                                ^
 COPY x from stdin (force_null (a), force_null (b));
-ERROR:  conflicting or redundant options
+ERROR:  option "force_null" specified more than once
+LINE 1: COPY x from stdin (force_null (a), force_null (b));
+                                           ^
 COPY x from stdin (convert_selectively (a), convert_selectively (b));
-ERROR:  conflicting or redundant options
+ERROR:  option "convert_selectively" specified more than once
 LINE 1: COPY x from stdin (convert_selectively (a), convert_selectiv...
                                                     ^
 COPY x from stdin (encoding 'sql_ascii', encoding 'sql_ascii');
-ERROR:  conflicting or redundant options
+ERROR:  option "encoding" specified more than once
 LINE 1: COPY x from stdin (encoding 'sql_ascii', encoding 'sql_ascii...
                                                  ^
 -- too many columns in column list: should fail
diff --git a/src/test/regress/expected/foreign_data.out b/src/test/regress/expected/foreign_data.out
index 5385f98a0f..03d6eca747 100644
--- a/src/test/regress/expected/foreign_data.out
+++ b/src/test/regress/expected/foreign_data.out
@@ -94,7 +94,9 @@ CREATE FUNCTION invalid_fdw_handler() RETURNS int LANGUAGE SQL AS 'SELECT 1;';
 CREATE FOREIGN DATA WRAPPER test_fdw HANDLER invalid_fdw_handler;  -- ERROR
 ERROR:  function invalid_fdw_handler must return type fdw_handler
 CREATE FOREIGN DATA WRAPPER test_fdw HANDLER test_fdw_handler HANDLER invalid_fdw_handler;  -- ERROR
-ERROR:  conflicting or redundant options
+ERROR:  option "handler" specified more than once
+LINE 1: ...GN DATA WRAPPER test_fdw HANDLER test_fdw_handler HANDLER in...
+                                                             ^
 CREATE FOREIGN DATA WRAPPER test_fdw HANDLER test_fdw_handler;
 DROP FOREIGN DATA WRAPPER test_fdw;
 -- ALTER FOREIGN DATA WRAPPER
@@ -200,7 +202,9 @@ ALTER FOREIGN DATA WRAPPER foo1 RENAME TO foo;
 ALTER FOREIGN DATA WRAPPER foo HANDLER invalid_fdw_handler;  -- ERROR
 ERROR:  function invalid_fdw_handler must return type fdw_handler
 ALTER FOREIGN DATA WRAPPER foo HANDLER test_fdw_handler HANDLER anything;  -- ERROR
-ERROR:  conflicting or redundant options
+ERROR:  option "handler" specified more than once
+LINE 1: ...FOREIGN DATA WRAPPER foo HANDLER test_fdw_handler HANDLER an...
+                                                             ^
 ALTER FOREIGN DATA WRAPPER foo HANDLER test_fdw_handler;
 WARNING:  changing the foreign-data wrapper handler can change behavior of existing foreign tables
 DROP FUNCTION invalid_fdw_handler();
diff --git a/src/test/regress/expected/publication.out b/src/test/regress/expected/publication.out
index 63d6ab7a4e..0f5cbe2e99 100644
--- a/src/test/regress/expected/publication.out
+++ b/src/test/regress/expected/publication.out
@@ -26,7 +26,9 @@ ERROR:  unrecognized publication parameter: "foo"
 CREATE PUBLICATION testpub_xxx WITH (publish = 'cluster, vacuum');
 ERROR:  unrecognized "publish" value: "cluster"
 CREATE PUBLICATION testpub_xxx WITH (publish_via_partition_root = 'true', publish_via_partition_root = '0');
-ERROR:  conflicting or redundant options
+ERROR:  option "publish_via_partition_root" specified more than once
+LINE 1: ...ub_xxx WITH (publish_via_partition_root = 'true', publish_vi...
+                                                             ^
 \dRp
                                               List of publications
         Name        |          Owner           | All tables | Inserts | Updates | Deletes | Truncates | Via root 
-- 
2.25.1

Reply via email to