On Sat, May 1, 2021 at 10:54 PM Alvaro Herrera <alvhe...@alvh.no-ip.org> wrote:
>
> On 2021-May-01, vignesh C wrote:
>
> > On Thu, Apr 29, 2021 at 10:44 PM Alvaro Herrera <alvhe...@alvh.no-ip.org> 
> > wrote:
> > >
> > > On 2021-Apr-29, vignesh C wrote:
> > >
> > > > Thanks for the comments, please find the attached v3 patch which has
> > > > the change for the first part.
> > >
> > > Looks good to me.  I would only add parser_errposition() to the few
> > > error sites missing that.
> >
> > I have not included parser_errposition as ParseState was not available
> > for these errors.
>
> Yeah, it's tough to do that in a few of those such as validator
> functions, and I don't think we'd want to do that.  However there are
> some cases where we can easily add the parsestate as an argument -- for
> example CreatePublication can get it in ProcessUtilitySlow and pass it
> down to parse_publication_options; likewise for ExecuteDoStmt.  I didn't
> check other places.

Thanks for the comments. I have changed in most of the places except
for a few places like plugin functions, internal commands and changes
that required changing more levels of function callers. Attached patch
has the changes for the same.
Thoughts?

Regards,
Vignesh
From 7c56cea92947b82107e2298f6d48d934df6fd7d8 Mon Sep 17 00:00:00 2001
From: vignesh <vignes...@gmail.com>
Date: Mon, 26 Apr 2021 18:40:36 +0530
Subject: [PATCH v5] Enhance error message.

Enhanced error message, so that the user can easily identify the error.
---
 contrib/file_fdw/file_fdw.c                 |  20 +--
 src/backend/catalog/aclchk.c                |  22 ++--
 src/backend/commands/copy.c                 |  66 ++++------
 src/backend/commands/dbcommands.c           |  90 +++++---------
 src/backend/commands/extension.c            |  27 ++--
 src/backend/commands/foreigncmds.c          |  30 +++--
 src/backend/commands/functioncmds.c         |  55 ++++----
 src/backend/commands/publicationcmds.c      |  39 +++---
 src/backend/commands/sequence.c             |  57 +++------
 src/backend/commands/subscriptioncmds.c     |  75 +++++------
 src/backend/commands/tablecmds.c            |   2 +-
 src/backend/commands/typecmds.c             |  38 +++---
 src/backend/commands/user.c                 | 131 +++++++-------------
 src/backend/parser/parse_utilcmd.c          |   2 +-
 src/backend/replication/pgoutput/pgoutput.c |  31 +++--
 src/backend/replication/walsender.c         |  23 ++--
 src/backend/tcop/utility.c                  |  20 +--
 src/include/commands/defrem.h               |   6 +-
 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, 352 insertions(+), 430 deletions(-)

diff --git a/contrib/file_fdw/file_fdw.c b/contrib/file_fdw/file_fdw.c
index 2c2f149fb0..f857d5af97 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.")));
+				goto duplicate_error;
 			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.")));
+				goto duplicate_error;
 			force_null = def;
 			(void) defGetBoolean(def);
 		}
@@ -328,6 +323,13 @@ file_fdw_validator(PG_FUNCTION_ARGS)
 				 errmsg("either filename or program is required for file_fdw foreign tables")));
 
 	PG_RETURN_VOID();
+
+duplicate_error:
+	ereport(ERROR,
+			(errcode(ERRCODE_SYNTAX_ERROR),
+			 errmsg("option \"%s\" specified more than once", def->defname)));
+	PG_RETURN_VOID();				/* keep compiler quiet */
+
 }
 
 /*
diff --git a/src/backend/catalog/aclchk.c b/src/backend/catalog/aclchk.c
index e1573eb398..be38488934 100644
--- a/src/backend/catalog/aclchk.c
+++ b/src/backend/catalog/aclchk.c
@@ -910,30 +910,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)));
+				goto duplicate_error;
 			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)));
+				goto duplicate_error;
 			drolespecs = defel;
 		}
 		else
@@ -1087,6 +1082,15 @@ ExecAlterDefaultPrivilegesStmt(ParseState *pstate, AlterDefaultPrivilegesStmt *s
 			SetDefaultACLsInSchemas(&iacls, nspnames);
 		}
 	}
+
+	return;
+
+duplicate_error:
+	ereport(ERROR,
+			(errcode(ERRCODE_SYNTAX_ERROR),
+			 errmsg("option \"%s\" specified more than once", defel->defname),
+			 parser_errposition(pstate, defel->location)));
+	return;				/* keep compiler quiet */
 }
 
 /*
diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index 8265b981eb..77fd923f2a 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)));
+				goto duplicate_error;
 			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)));
+				goto duplicate_error;
 			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)));
+				goto duplicate_error;
 			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)));
+				goto duplicate_error;
 			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)));
+				goto duplicate_error;
 			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)));
+				goto duplicate_error;
 			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)));
+				goto duplicate_error;
 			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)));
+				goto duplicate_error;
 			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")));
+				goto duplicate_error;
 			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)));
+				goto duplicate_error;
 			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)));
+				goto duplicate_error;
 			opts_out->file_encoding = pg_char_to_encoding(defGetString(defel));
 			if (opts_out->file_encoding < 0)
 				ereport(ERROR,
@@ -666,6 +635,15 @@ ProcessCopyOptions(ParseState *pstate,
 		ereport(ERROR,
 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 				 errmsg("CSV quote character must not appear in the NULL specification")));
+
+	return;
+
+duplicate_error:
+	ereport(ERROR,
+			(errcode(ERRCODE_SYNTAX_ERROR),
+			 errmsg("option \"%s\" specified more than once", defel->defname),
+			 parser_errposition(pstate, defel->location)));
+	return;				/* keep compiler quiet */
 }
 
 /*
diff --git a/src/backend/commands/dbcommands.c b/src/backend/commands/dbcommands.c
index 2b159b60eb..8ad61a219e 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)));
+				goto duplicate_error;
 			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)));
+				goto duplicate_error;
 			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)));
+				goto duplicate_error;
 			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)));
+				goto duplicate_error;
 			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)));
+				goto duplicate_error;
 			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)));
+				goto duplicate_error;
 			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)));
+				goto duplicate_error;
 			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)));
+				goto duplicate_error;
 			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)));
+				goto duplicate_error;
 			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)));
+				goto duplicate_error;
 			dconnlimit = defel;
 		}
 		else if (strcmp(defel->defname, "location") == 0)
@@ -727,6 +698,13 @@ createdb(ParseState *pstate, const CreatedbStmt *stmt)
 								PointerGetDatum(&fparms));
 
 	return dboid;
+
+duplicate_error:
+	ereport(ERROR,
+			(errcode(ERRCODE_SYNTAX_ERROR),
+			 errmsg("option \"%s\" specified more than once", defel->defname),
+			 parser_errposition(pstate, defel->location)));
+	return InvalidOid;				/* keep compiler quiet */
 }
 
 /*
@@ -1488,46 +1466,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)));
+				goto duplicate_error;
 			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)));
+				goto duplicate_error;
 			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)));
+				goto duplicate_error;
 			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)));
+				goto duplicate_error;
 			dtablespace = defel;
 		}
 		else
@@ -1640,6 +1607,13 @@ AlterDatabase(ParseState *pstate, AlterDatabaseStmt *stmt, bool isTopLevel)
 	table_close(rel, NoLock);
 
 	return dboid;
+
+duplicate_error:
+	ereport(ERROR,
+			(errcode(ERRCODE_SYNTAX_ERROR),
+			 errmsg("option \"%s\" specified more than once", defel->defname),
+			 parser_errposition(pstate, defel->location)));
+	return InvalidOid;				/* keep compiler quiet */
 }
 
 
diff --git a/src/backend/commands/extension.c b/src/backend/commands/extension.c
index 19db329fe6..0a462c1caa 100644
--- a/src/backend/commands/extension.c
+++ b/src/backend/commands/extension.c
@@ -1682,6 +1682,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;
@@ -1725,35 +1726,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)));
+				goto duplicate_error;
 			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)));
+				goto duplicate_error;
 			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)));
+				goto duplicate_error;
 			d_cascade = defel;
 			cascade = defGetBoolean(d_cascade);
 		}
@@ -1768,6 +1760,13 @@ CreateExtension(ParseState *pstate, CreateExtensionStmt *stmt)
 								   cascade,
 								   NIL,
 								   true);
+
+duplicate_error:
+	ereport(ERROR,
+			(errcode(ERRCODE_SYNTAX_ERROR),
+			 errmsg("option \"%s\" specified more than once", defel->defname),
+			 parser_errposition(pstate, defel->location)));
+	return InvalidObjectAddress;				/* keep compiler quiet */
 }
 
 /*
@@ -3052,7 +3051,7 @@ ExecAlterExtensionStmt(ParseState *pstate, AlterExtensionStmt *stmt)
 			if (d_new_version)
 				ereport(ERROR,
 						(errcode(ERRCODE_SYNTAX_ERROR),
-						 errmsg("conflicting or redundant options"),
+						 errmsg("option \"%s\" specified more than once", defel->defname),
 						 parser_errposition(pstate, defel->location)));
 			d_new_version = defel;
 		}
diff --git a/src/backend/commands/foreigncmds.c b/src/backend/commands/foreigncmds.c
index eb7103fd3b..8923093db9 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")));
+				goto duplicate_error;
 			*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")));
+				goto duplicate_error;
 			*validator_given = true;
 			*fdwvalidator = lookup_fdw_validator_func(def);
 		}
@@ -553,13 +550,22 @@ parse_func_options(List *func_options,
 			elog(ERROR, "option \"%s\" not recognized",
 				 def->defname);
 	}
+
+	return;
+
+duplicate_error:
+	ereport(ERROR,
+			(errcode(ERRCODE_SYNTAX_ERROR),
+			 errmsg("option \"%s\" specified more than once", def->defname),
+			 parser_errposition(pstate, def->location)));
+	return;				/* keep compiler quiet */
 }
 
 /*
  * 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 +617,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 +681,7 @@ CreateForeignDataWrapper(CreateFdwStmt *stmt)
  * Alter foreign-data wrapper
  */
 ObjectAddress
-AlterForeignDataWrapper(AlterFdwStmt *stmt)
+AlterForeignDataWrapper(ParseState *pstate, AlterFdwStmt *stmt)
 {
 	Relation	rel;
 	HeapTuple	tp;
@@ -717,7 +723,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 9548287217..1a8d23d4c6 100644
--- a/src/backend/commands/functioncmds.c
+++ b/src/backend/commands/functioncmds.c
@@ -575,7 +575,7 @@ compute_common_attribute(ParseState *pstate,
 duplicate_error:
 	ereport(ERROR,
 			(errcode(ERRCODE_SYNTAX_ERROR),
-			 errmsg("conflicting or redundant options"),
+			 errmsg("option \"%s\" specified more than once", defel->defname),
 			 parser_errposition(pstate, defel->location)));
 	return false;				/* keep compiler quiet */
 
@@ -731,45 +731,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)));
+				goto duplicate_error;
 			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)));
+				goto duplicate_error;
 			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)));
+				goto duplicate_error;
 			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)));
+				goto duplicate_error;
 			if (is_procedure)
 				ereport(ERROR,
 						(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
@@ -836,6 +825,15 @@ compute_function_attributes(ParseState *pstate,
 		*prosupport = interpret_func_support(support_item);
 	if (parallel_item)
 		*parallel_p = interpret_func_parallel(parallel_item);
+
+	return;
+
+duplicate_error:
+	ereport(ERROR,
+			(errcode(ERRCODE_SYNTAX_ERROR),
+			 errmsg("option \"%s\" specified more than once", defel->defname),
+			 parser_errposition(pstate, defel->location)));
+	return;				/* keep compiler quiet */
 }
 
 
@@ -2044,12 +2042,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;
@@ -2058,22 +2057,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")));
+				goto duplicate_error;
 			as_item = defel;
 		}
 		else if (strcmp(defel->defname, "language") == 0)
 		{
 			if (language_item)
-				ereport(ERROR,
-						(errcode(ERRCODE_SYNTAX_ERROR),
-						 errmsg("conflicting or redundant options")));
+				goto duplicate_error;
 			language_item = defel;
 		}
 		else
@@ -2139,6 +2134,14 @@ ExecuteDoStmt(DoStmt *stmt, bool atomic)
 
 	/* execute the inline handler */
 	OidFunctionCall1(laninline, PointerGetDatum(codeblock));
+	return;
+
+duplicate_error:
+	ereport(ERROR,
+			(errcode(ERRCODE_SYNTAX_ERROR),
+			 errmsg("option \"%s\" specified more than once", defel->defname),
+			 parser_errposition(pstate, defel->location)));
+	return;				/* keep compiler quiet */
 }
 
 /*
diff --git a/src/backend/commands/publicationcmds.c b/src/backend/commands/publicationcmds.c
index 95c253c8e0..3c58548fca 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")));
+				goto duplicate_error;
 
 			/*
 			 * 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")));
+				goto duplicate_error;
 			*publish_via_partition_root_given = true;
 			*publish_via_partition_root = defGetBoolean(defel);
 		}
@@ -139,13 +137,22 @@ parse_publication_options(List *options,
 					(errcode(ERRCODE_SYNTAX_ERROR),
 					 errmsg("unrecognized publication parameter: \"%s\"", defel->defname)));
 	}
+
+	return;
+
+duplicate_error:
+	ereport(ERROR,
+			(errcode(ERRCODE_SYNTAX_ERROR),
+			 errmsg("option \"%s\" specified more than once", defel->defname),
+			 parser_errposition(pstate, defel->location)));
+	return;				/* keep compiler quiet */
 }
 
 /*
  * Create new publication.
  */
 ObjectAddress
-CreatePublication(CreatePublicationStmt *stmt)
+CreatePublication(ParseState *pstate, CreatePublicationStmt *stmt)
 {
 	Relation	rel;
 	ObjectAddress myself;
@@ -192,7 +199,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 +264,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 +277,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 +443,7 @@ AlterPublicationTables(AlterPublicationStmt *stmt, Relation rel,
  * AlterPublicationTables.
  */
 void
-AlterPublication(AlterPublicationStmt *stmt)
+AlterPublication(ParseState *pstate, AlterPublicationStmt *stmt)
 {
 	Relation	rel;
 	HeapTuple	tup;
@@ -459,7 +468,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..d815f95b11 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)));
+				goto duplicate_error;
 			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)));
+				goto duplicate_error;
 			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)));
+				goto duplicate_error;
 			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)));
+				goto duplicate_error;
 			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)));
+				goto duplicate_error;
 			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)));
+				goto duplicate_error;
 			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)));
+				goto duplicate_error;
 			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)));
+				goto duplicate_error;
 			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)));
+				goto duplicate_error;
 			*owned_by = defGetQualifiedName(defel);
 		}
 		else if (strcmp(defel->defname, "sequence_name") == 0)
@@ -1626,6 +1600,15 @@ init_params(ParseState *pstate, List *options, bool for_identity,
 	{
 		seqform->seqcache = 1;
 	}
+
+	return;
+
+duplicate_error:
+	ereport(ERROR,
+			(errcode(ERRCODE_SYNTAX_ERROR),
+			 errmsg("option \"%s\" specified more than once", defel->defname),
+			 parser_errposition(pstate, defel->location)));
+	return;
 }
 
 /*
diff --git a/src/backend/commands/subscriptioncmds.c b/src/backend/commands/subscriptioncmds.c
index 517c8edd3b..dd6cb75236 100644
--- a/src/backend/commands/subscriptioncmds.c
+++ b/src/backend/commands/subscriptioncmds.c
@@ -60,7 +60,8 @@ static void ReportSlotConnectionError(List *rstates, Oid subid, char *slotname,
  * accommodate that.
  */
 static void
-parse_subscription_options(List *options,
+parse_subscription_options(ParseState *pstate,
+						   List *options,
 						   bool *connect,
 						   bool *enabled_given, bool *enabled,
 						   bool *create_slot,
@@ -76,6 +77,7 @@ parse_subscription_options(List *options,
 	bool		create_slot_given = false;
 	bool		copy_data_given = false;
 	bool		refresh_given = false;
+	DefElem    *defel;
 
 	/* If connect is specified, the others also need to be. */
 	Assert(!connect || (enabled && create_slot && copy_data));
@@ -114,14 +116,12 @@ parse_subscription_options(List *options,
 	/* Parse options */
 	foreach(lc, options)
 	{
-		DefElem    *defel = (DefElem *) lfirst(lc);
+		defel = (DefElem *) lfirst(lc);
 
 		if (strcmp(defel->defname, "connect") == 0 && connect)
 		{
 			if (connect_given)
-				ereport(ERROR,
-						(errcode(ERRCODE_SYNTAX_ERROR),
-						 errmsg("conflicting or redundant options")));
+				goto duplicate_error;
 
 			connect_given = true;
 			*connect = defGetBoolean(defel);
@@ -129,9 +129,7 @@ parse_subscription_options(List *options,
 		else if (strcmp(defel->defname, "enabled") == 0 && enabled)
 		{
 			if (*enabled_given)
-				ereport(ERROR,
-						(errcode(ERRCODE_SYNTAX_ERROR),
-						 errmsg("conflicting or redundant options")));
+				goto duplicate_error;
 
 			*enabled_given = true;
 			*enabled = defGetBoolean(defel);
@@ -139,9 +137,7 @@ parse_subscription_options(List *options,
 		else if (strcmp(defel->defname, "create_slot") == 0 && create_slot)
 		{
 			if (create_slot_given)
-				ereport(ERROR,
-						(errcode(ERRCODE_SYNTAX_ERROR),
-						 errmsg("conflicting or redundant options")));
+				goto duplicate_error;
 
 			create_slot_given = true;
 			*create_slot = defGetBoolean(defel);
@@ -149,9 +145,7 @@ parse_subscription_options(List *options,
 		else if (strcmp(defel->defname, "slot_name") == 0 && slot_name)
 		{
 			if (*slot_name_given)
-				ereport(ERROR,
-						(errcode(ERRCODE_SYNTAX_ERROR),
-						 errmsg("conflicting or redundant options")));
+				goto duplicate_error;
 
 			*slot_name_given = true;
 			*slot_name = defGetString(defel);
@@ -163,9 +157,7 @@ parse_subscription_options(List *options,
 		else if (strcmp(defel->defname, "copy_data") == 0 && copy_data)
 		{
 			if (copy_data_given)
-				ereport(ERROR,
-						(errcode(ERRCODE_SYNTAX_ERROR),
-						 errmsg("conflicting or redundant options")));
+				goto duplicate_error;
 
 			copy_data_given = true;
 			*copy_data = defGetBoolean(defel);
@@ -174,9 +166,7 @@ parse_subscription_options(List *options,
 				 synchronous_commit)
 		{
 			if (*synchronous_commit)
-				ereport(ERROR,
-						(errcode(ERRCODE_SYNTAX_ERROR),
-						 errmsg("conflicting or redundant options")));
+				goto duplicate_error;
 
 			*synchronous_commit = defGetString(defel);
 
@@ -188,9 +178,7 @@ parse_subscription_options(List *options,
 		else if (strcmp(defel->defname, "refresh") == 0 && refresh)
 		{
 			if (refresh_given)
-				ereport(ERROR,
-						(errcode(ERRCODE_SYNTAX_ERROR),
-						 errmsg("conflicting or redundant options")));
+				goto duplicate_error;
 
 			refresh_given = true;
 			*refresh = defGetBoolean(defel);
@@ -198,9 +186,7 @@ parse_subscription_options(List *options,
 		else if (strcmp(defel->defname, "binary") == 0 && binary)
 		{
 			if (*binary_given)
-				ereport(ERROR,
-						(errcode(ERRCODE_SYNTAX_ERROR),
-						 errmsg("conflicting or redundant options")));
+				goto duplicate_error;
 
 			*binary_given = true;
 			*binary = defGetBoolean(defel);
@@ -208,9 +194,7 @@ parse_subscription_options(List *options,
 		else if (strcmp(defel->defname, "streaming") == 0 && streaming)
 		{
 			if (*streaming_given)
-				ereport(ERROR,
-						(errcode(ERRCODE_SYNTAX_ERROR),
-						 errmsg("conflicting or redundant options")));
+				goto duplicate_error;
 
 			*streaming_given = true;
 			*streaming = defGetBoolean(defel);
@@ -285,6 +269,15 @@ parse_subscription_options(List *options,
 					 errmsg("subscription with %s must also set %s",
 							"slot_name = NONE", "create_slot = false")));
 	}
+
+	return;
+
+duplicate_error:
+	ereport(ERROR,
+			(errcode(ERRCODE_SYNTAX_ERROR),
+			 errmsg("option \"%s\" specified more than once", defel->defname),
+			 parser_errposition(pstate, defel->location)));
+	return;				/* keep compiler quiet */
 }
 
 /*
@@ -322,7 +315,8 @@ publicationListToArray(List *publist)
  * Create new subscription.
  */
 ObjectAddress
-CreateSubscription(CreateSubscriptionStmt *stmt, bool isTopLevel)
+CreateSubscription(ParseState *pstate, CreateSubscriptionStmt *stmt,
+				   bool isTopLevel)
 {
 	Relation	rel;
 	ObjectAddress myself;
@@ -352,7 +346,8 @@ CreateSubscription(CreateSubscriptionStmt *stmt, bool isTopLevel)
 	 *
 	 * Connection and publication should not be specified here.
 	 */
-	parse_subscription_options(stmt->options,
+	parse_subscription_options(pstate,
+							   stmt->options,
 							   &connect,
 							   &enabled_given, &enabled,
 							   &create_slot,
@@ -750,7 +745,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;
@@ -805,7 +801,8 @@ AlterSubscription(AlterSubscriptionStmt *stmt, bool isTopLevel)
 				bool		streaming_given;
 				bool		streaming;
 
-				parse_subscription_options(stmt->options,
+				parse_subscription_options(pstate,
+										   stmt->options,
 										   NULL,	/* no "connect" */
 										   NULL, NULL,	/* no "enabled" */
 										   NULL,	/* no "create_slot" */
@@ -862,7 +859,8 @@ AlterSubscription(AlterSubscriptionStmt *stmt, bool isTopLevel)
 				bool		enabled,
 							enabled_given;
 
-				parse_subscription_options(stmt->options,
+				parse_subscription_options(pstate,
+										   stmt->options,
 										   NULL,	/* no "connect" */
 										   &enabled_given, &enabled,
 										   NULL,	/* no "create_slot" */
@@ -907,7 +905,8 @@ AlterSubscription(AlterSubscriptionStmt *stmt, bool isTopLevel)
 				bool		copy_data;
 				bool		refresh;
 
-				parse_subscription_options(stmt->options,
+				parse_subscription_options(pstate,
+										   stmt->options,
 										   NULL,	/* no "connect" */
 										   NULL, NULL,	/* no "enabled" */
 										   NULL,	/* no "create_slot" */
@@ -953,7 +952,8 @@ AlterSubscription(AlterSubscriptionStmt *stmt, bool isTopLevel)
 
 				publist = merge_publications(sub->publications, stmt->publication, isadd, stmt->subname);
 
-				parse_subscription_options(stmt->options,
+				parse_subscription_options(pstate,
+										   stmt->options,
 										   NULL,	/* no "connect" */
 										   NULL, NULL,	/* no "enabled" */
 										   NULL,	/* no "create_slot" */
@@ -1000,7 +1000,8 @@ AlterSubscription(AlterSubscriptionStmt *stmt, bool isTopLevel)
 							(errcode(ERRCODE_SYNTAX_ERROR),
 							 errmsg("ALTER SUBSCRIPTION ... REFRESH is not allowed for disabled subscriptions")));
 
-				parse_subscription_options(stmt->options,
+				parse_subscription_options(pstate,
+										   stmt->options,
 										   NULL,	/* no "connect" */
 										   NULL, NULL,	/* no "enabled" */
 										   NULL,	/* no "create_slot" */
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index d9ba87a2a3..26a1f16271 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -7524,7 +7524,7 @@ ATExecSetIdentity(Relation rel, const char *colName, Node *def, LOCKMODE lockmod
 			if (generatedEl)
 				ereport(ERROR,
 						(errcode(ERRCODE_SYNTAX_ERROR),
-						 errmsg("conflicting or redundant options")));
+						 errmsg("option \"%s\" specified more than once", defel->defname)));
 			generatedEl = defel;
 		}
 		else
diff --git a/src/backend/commands/typecmds.c b/src/backend/commands/typecmds.c
index 036fa69d17..f4a2678ffe 100644
--- a/src/backend/commands/typecmds.c
+++ b/src/backend/commands/typecmds.c
@@ -332,7 +332,7 @@ DefineType(ParseState *pstate, List *names, List *parameters)
 		if (*defelp != NULL)
 			ereport(ERROR,
 					(errcode(ERRCODE_SYNTAX_ERROR),
-					 errmsg("conflicting or redundant options"),
+					 errmsg("option \"%s\" specified more than once", defel->defname),
 					 parser_errposition(pstate, defel->location)));
 		*defelp = defel;
 	}
@@ -1336,7 +1336,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 +1366,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 +1407,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")));
+				goto duplicate_error;
 			/* 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")));
+				goto duplicate_error;
 			rangeSubOpclassName = defGetQualifiedName(defel);
 		}
 		else if (strcmp(defel->defname, "collation") == 0)
 		{
 			if (rangeCollationName != NIL)
-				ereport(ERROR,
-						(errcode(ERRCODE_SYNTAX_ERROR),
-						 errmsg("conflicting or redundant options")));
+				goto duplicate_error;
 			rangeCollationName = defGetQualifiedName(defel);
 		}
 		else if (strcmp(defel->defname, "canonical") == 0)
 		{
 			if (rangeCanonicalName != NIL)
-				ereport(ERROR,
-						(errcode(ERRCODE_SYNTAX_ERROR),
-						 errmsg("conflicting or redundant options")));
+				goto duplicate_error;
 			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")));
+				goto duplicate_error;
 			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")));
+				goto duplicate_error;
 			/* we can look up the subtype name immediately */
 			multirangeNamespace = QualifiedNameGetCreationNamespace(defGetQualifiedName(defel),
 																	&multirangeTypeName);
@@ -1726,6 +1715,13 @@ DefineRange(CreateRangeStmt *stmt)
 	pfree(multirangeArrayName);
 
 	return address;
+
+duplicate_error:
+	ereport(ERROR,
+			(errcode(ERRCODE_SYNTAX_ERROR),
+			 errmsg("option \"%s\" specified more than once", defel->defname),
+			 parser_errposition(pstate, defel->location)));
+	return InvalidObjectAddress;				/* keep compiler quiet */
 }
 
 /*
diff --git a/src/backend/commands/user.c b/src/backend/commands/user.c
index 65bb733958..f1fad6caa1 100644
--- a/src/backend/commands/user.c
+++ b/src/backend/commands/user.c
@@ -106,6 +106,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 +124,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)));
+				goto duplicate_error;
 			dpassword = defel;
 		}
 		else if (strcmp(defel->defname, "sysid") == 0)
@@ -142,109 +140,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)));
+				goto duplicate_error;
 			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)));
+				goto duplicate_error;
 			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)));
+				goto duplicate_error;
 			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)));
+				goto duplicate_error;
 			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)));
+				goto duplicate_error;
 			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)));
+				goto duplicate_error;
 			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)));
+				goto duplicate_error;
 			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)));
+				goto duplicate_error;
 			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)));
+				goto duplicate_error;
 			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)));
+				goto duplicate_error;
 			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)));
+				goto duplicate_error;
 			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)));
+				goto duplicate_error;
 			dbypassRLS = defel;
 		}
 		else
@@ -517,6 +479,13 @@ CreateRole(ParseState *pstate, CreateRoleStmt *stmt)
 	table_close(pg_authid_rel, NoLock);
 
 	return roleid;
+
+duplicate_error:
+	ereport(ERROR,
+			(errcode(ERRCODE_SYNTAX_ERROR),
+			 errmsg("option \"%s\" specified more than once", defel->defname),
+			 parser_errposition(pstate, defel->location)));
+	return InvalidOid;				/* keep compiler quiet */
 }
 
 
@@ -528,7 +497,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 +533,7 @@ AlterRole(AlterRoleStmt *stmt)
 	DefElem    *drolemembers = NULL;
 	DefElem    *dvalidUntil = NULL;
 	DefElem    *dbypassRLS = NULL;
+	DefElem    *defel;
 	Oid			roleid;
 
 	check_rolespec_name(stmt->role,
@@ -572,95 +542,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")));
+				goto duplicate_error;
 			dpassword = defel;
 		}
 		else if (strcmp(defel->defname, "superuser") == 0)
 		{
 			if (dissuper)
-				ereport(ERROR,
-						(errcode(ERRCODE_SYNTAX_ERROR),
-						 errmsg("conflicting or redundant options")));
+				goto duplicate_error;
 			dissuper = defel;
 		}
 		else if (strcmp(defel->defname, "inherit") == 0)
 		{
 			if (dinherit)
-				ereport(ERROR,
-						(errcode(ERRCODE_SYNTAX_ERROR),
-						 errmsg("conflicting or redundant options")));
+				goto duplicate_error;
 			dinherit = defel;
 		}
 		else if (strcmp(defel->defname, "createrole") == 0)
 		{
 			if (dcreaterole)
-				ereport(ERROR,
-						(errcode(ERRCODE_SYNTAX_ERROR),
-						 errmsg("conflicting or redundant options")));
+				goto duplicate_error;
 			dcreaterole = defel;
 		}
 		else if (strcmp(defel->defname, "createdb") == 0)
 		{
 			if (dcreatedb)
-				ereport(ERROR,
-						(errcode(ERRCODE_SYNTAX_ERROR),
-						 errmsg("conflicting or redundant options")));
+				goto duplicate_error;
 			dcreatedb = defel;
 		}
 		else if (strcmp(defel->defname, "canlogin") == 0)
 		{
 			if (dcanlogin)
-				ereport(ERROR,
-						(errcode(ERRCODE_SYNTAX_ERROR),
-						 errmsg("conflicting or redundant options")));
+				goto duplicate_error;
 			dcanlogin = defel;
 		}
 		else if (strcmp(defel->defname, "isreplication") == 0)
 		{
 			if (disreplication)
-				ereport(ERROR,
-						(errcode(ERRCODE_SYNTAX_ERROR),
-						 errmsg("conflicting or redundant options")));
+				goto duplicate_error;
 			disreplication = defel;
 		}
 		else if (strcmp(defel->defname, "connectionlimit") == 0)
 		{
 			if (dconnlimit)
-				ereport(ERROR,
-						(errcode(ERRCODE_SYNTAX_ERROR),
-						 errmsg("conflicting or redundant options")));
+				goto duplicate_error;
 			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")));
+				goto duplicate_error;
 			drolemembers = defel;
 		}
 		else if (strcmp(defel->defname, "validUntil") == 0)
 		{
 			if (dvalidUntil)
-				ereport(ERROR,
-						(errcode(ERRCODE_SYNTAX_ERROR),
-						 errmsg("conflicting or redundant options")));
+				goto duplicate_error;
 			dvalidUntil = defel;
 		}
 		else if (strcmp(defel->defname, "bypassrls") == 0)
 		{
 			if (dbypassRLS)
-				ereport(ERROR,
-						(errcode(ERRCODE_SYNTAX_ERROR),
-						 errmsg("conflicting or redundant options")));
+				goto duplicate_error;
 			dbypassRLS = defel;
 		}
 		else
@@ -905,6 +853,13 @@ AlterRole(AlterRoleStmt *stmt)
 	table_close(pg_authid_rel, NoLock);
 
 	return roleid;
+
+duplicate_error:
+	ereport(ERROR,
+			(errcode(ERRCODE_SYNTAX_ERROR),
+			 errmsg("option \"%s\" specified more than once", defel->defname),
+			 parser_errposition(pstate, defel->location)));
+	return InvalidOid;				/* keep compiler quiet */
 }
 
 
diff --git a/src/backend/parser/parse_utilcmd.c b/src/backend/parser/parse_utilcmd.c
index 9dd30370da..9e44885146 100644
--- a/src/backend/parser/parse_utilcmd.c
+++ b/src/backend/parser/parse_utilcmd.c
@@ -402,7 +402,7 @@ generateSerialExtraStmts(CreateStmtContext *cxt, ColumnDef *column,
 			if (nameEl)
 				ereport(ERROR,
 						(errcode(ERRCODE_SYNTAX_ERROR),
-						 errmsg("conflicting or redundant options")));
+						 errmsg("option \"%s\" specified more than once", defel->defname)));
 			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 f68348dcf4..9acfc3046b 100644
--- a/src/backend/replication/pgoutput/pgoutput.c
+++ b/src/backend/replication/pgoutput/pgoutput.c
@@ -165,6 +165,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;
@@ -177,7 +178,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));
 
@@ -187,9 +188,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")));
+				goto duplicate_error;
 			protocol_version_given = true;
 
 			if (!scanint8(strVal(defel->arg), true, &parsed))
@@ -208,9 +207,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")));
+				goto duplicate_error;
 			publication_names_given = true;
 
 			if (!SplitIdentifierString(strVal(defel->arg), ',',
@@ -222,9 +219,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")));
+				goto duplicate_error;
 			binary_option_given = true;
 
 			data->binary = defGetBoolean(defel);
@@ -232,9 +227,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")));
+				goto duplicate_error;
 			messages_option_given = true;
 
 			data->messages = defGetBoolean(defel);
@@ -242,9 +235,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")));
+				goto duplicate_error;
 			streaming_given = true;
 
 			data->streaming = defGetBoolean(defel);
@@ -252,6 +243,14 @@ parse_output_parameters(List *options, PGOutputData *data)
 		else
 			elog(ERROR, "unrecognized pgoutput option: %s", defel->defname);
 	}
+
+	return;
+
+duplicate_error:
+	ereport(ERROR,
+			(errcode(ERRCODE_SYNTAX_ERROR),
+			 errmsg("option \"%s\" specified more than once", defel->defname)));
+	return;				/* keep compiler quiet */
 }
 
 /*
diff --git a/src/backend/replication/walsender.c b/src/backend/replication/walsender.c
index 6fefc3bedc..1b50cdf8a6 100644
--- a/src/backend/replication/walsender.c
+++ b/src/backend/replication/walsender.c
@@ -871,18 +871,17 @@ parseCreateReplSlotOptions(CreateReplicationSlotCmd *cmd,
 	ListCell   *lc;
 	bool		snapshot_action_given = false;
 	bool		reserve_wal_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")));
+				goto duplicate_error;
 
 			snapshot_action_given = true;
 			*snapshot_action = defGetBoolean(defel) ? CRS_EXPORT_SNAPSHOT :
@@ -891,9 +890,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")));
+				goto duplicate_error;
 
 			snapshot_action_given = true;
 			*snapshot_action = CRS_USE_SNAPSHOT;
@@ -901,9 +898,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")));
+				goto duplicate_error;
 
 			reserve_wal_given = true;
 			*reserve_wal = true;
@@ -911,6 +906,14 @@ parseCreateReplSlotOptions(CreateReplicationSlotCmd *cmd,
 		else
 			elog(ERROR, "unrecognized option: %s", defel->defname);
 	}
+
+	return;
+
+duplicate_error:
+	ereport(ERROR,
+			(errcode(ERRCODE_SYNTAX_ERROR),
+			 errmsg("option \"%s\" specified more than once", defel->defname)));
+	return;				/* keep compiler quiet */
 }
 
 /*
diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c
index 16c6f17e23..2668ff26f9 100644
--- a/src/backend/tcop/utility.c
+++ b/src/backend/tcop/utility.c
@@ -693,7 +693,7 @@ standard_ProcessUtility(PlannedStmt *pstmt,
 			break;
 
 		case T_DoStmt:
-			ExecuteDoStmt((DoStmt *) parsetree, isAtomicContext);
+			ExecuteDoStmt(pstate, (DoStmt *) parsetree, isAtomicContext);
 			break;
 
 		case T_CreateTableSpaceStmt:
@@ -873,7 +873,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:
@@ -1536,11 +1536,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:
@@ -1585,7 +1585,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) */
@@ -1786,11 +1786,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
@@ -1800,12 +1800,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 6bce4d76fe..2a317257ea 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);
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