Improve parsing of options of CREATE/ALTER SUBSCRIPTION
authorMichael Paquier <michael@paquier.xyz>
Wed, 8 Dec 2021 03:36:31 +0000 (12:36 +0900)
committerMichael Paquier <michael@paquier.xyz>
Wed, 8 Dec 2021 03:36:31 +0000 (12:36 +0900)
This simplifies the code so as it is not necessary anymore for the
caller of parse_subscription_options() to zero SubOpts, holding a
bitmaps of the provided options as well as the default/parsed option
values.  This also simplifies some checks related to the options
supported by a command when checking for incompatibilities.

While on it, the errors generated for unsupported combinations with
"slot_name = NONE" are reordered.  This may generate a different errors
compared to the previous major versions, but users have to go through
all those errors to get a correct command in this case when using
incorrect values for options "enabled" and "create\slot", so at the end
the resulting command would remain the same.

Author: Peter Smith
Reviewed-by: Nathan Bossart
Discussion: https://postgr.es/m/CAHut+PtXHfLgLHDDJ8ZN5f5Be_37mJoxpEsRg8LNmm4XCr06Rw@mail.gmail.com

src/backend/commands/subscriptioncmds.c
src/test/regress/expected/subscription.out
src/test/regress/sql/subscription.sql

index 9427e86fee1088940b39ec5611e17e58d4d2da3a..2b658080fee52457a3df8fb241fa3c4abbc6489a 100644 (file)
@@ -95,8 +95,6 @@ static void ReportSlotConnectionError(List *rstates, Oid subid, char *slotname,
  *
  * Since not all options can be specified in both commands, this function
  * will report an error if mutually exclusive options are specified.
- *
- * Caller is expected to have cleared 'opts'.
  */
 static void
 parse_subscription_options(ParseState *pstate, List *stmt_options,
@@ -104,6 +102,9 @@ parse_subscription_options(ParseState *pstate, List *stmt_options,
 {
        ListCell   *lc;
 
+       /* Start out with cleared opts. */
+       memset(opts, 0, sizeof(SubOpts));
+
        /* caller must expect some option */
        Assert(supported_opts != 0);
 
@@ -262,7 +263,6 @@ parse_subscription_options(ParseState *pstate, List *stmt_options,
        {
                /* Check for incompatible options from the user. */
                if (opts->enabled &&
-                       IsSet(supported_opts, SUBOPT_ENABLED) &&
                        IsSet(opts->specified_opts, SUBOPT_ENABLED))
                        ereport(ERROR,
                                        (errcode(ERRCODE_SYNTAX_ERROR),
@@ -271,7 +271,6 @@ parse_subscription_options(ParseState *pstate, List *stmt_options,
                                                        "connect = false", "enabled = true")));
 
                if (opts->create_slot &&
-                       IsSet(supported_opts, SUBOPT_CREATE_SLOT) &&
                        IsSet(opts->specified_opts, SUBOPT_CREATE_SLOT))
                        ereport(ERROR,
                                        (errcode(ERRCODE_SYNTAX_ERROR),
@@ -279,7 +278,6 @@ parse_subscription_options(ParseState *pstate, List *stmt_options,
                                                        "connect = false", "create_slot = true")));
 
                if (opts->copy_data &&
-                       IsSet(supported_opts, SUBOPT_COPY_DATA) &&
                        IsSet(opts->specified_opts, SUBOPT_COPY_DATA))
                        ereport(ERROR,
                                        (errcode(ERRCODE_SYNTAX_ERROR),
@@ -297,44 +295,39 @@ parse_subscription_options(ParseState *pstate, List *stmt_options,
         * was used.
         */
        if (!opts->slot_name &&
-               IsSet(supported_opts, SUBOPT_SLOT_NAME) &&
                IsSet(opts->specified_opts, SUBOPT_SLOT_NAME))
        {
-               if (opts->enabled &&
-                       IsSet(supported_opts, SUBOPT_ENABLED) &&
-                       IsSet(opts->specified_opts, SUBOPT_ENABLED))
-                       ereport(ERROR,
-                                       (errcode(ERRCODE_SYNTAX_ERROR),
-                       /*- translator: both %s are strings of the form "option = value" */
-                                        errmsg("%s and %s are mutually exclusive options",
-                                                       "slot_name = NONE", "enabled = true")));
-
-               if (opts->create_slot &&
-                       IsSet(supported_opts, SUBOPT_CREATE_SLOT) &&
-                       IsSet(opts->specified_opts, SUBOPT_CREATE_SLOT))
-                       ereport(ERROR,
-                                       (errcode(ERRCODE_SYNTAX_ERROR),
-                       /*- translator: both %s are strings of the form "option = value" */
-                                        errmsg("%s and %s are mutually exclusive options",
-                                                       "slot_name = NONE", "create_slot = true")));
-
-               if (opts->enabled &&
-                       IsSet(supported_opts, SUBOPT_ENABLED) &&
-                       !IsSet(opts->specified_opts, SUBOPT_ENABLED))
-                       ereport(ERROR,
-                                       (errcode(ERRCODE_SYNTAX_ERROR),
-                       /*- translator: both %s are strings of the form "option = value" */
-                                        errmsg("subscription with %s must also set %s",
-                                                       "slot_name = NONE", "enabled = false")));
+               if (opts->enabled)
+               {
+                       if (IsSet(opts->specified_opts, SUBOPT_ENABLED))
+                               ereport(ERROR,
+                                               (errcode(ERRCODE_SYNTAX_ERROR),
+                               /*- translator: both %s are strings of the form "option = value" */
+                                                errmsg("%s and %s are mutually exclusive options",
+                                                               "slot_name = NONE", "enabled = true")));
+                       else
+                               ereport(ERROR,
+                                               (errcode(ERRCODE_SYNTAX_ERROR),
+                               /*- translator: both %s are strings of the form "option = value" */
+                                                errmsg("subscription with %s must also set %s",
+                                                               "slot_name = NONE", "enabled = false")));
+               }
 
-               if (opts->create_slot &&
-                       IsSet(supported_opts, SUBOPT_CREATE_SLOT) &&
-                       !IsSet(opts->specified_opts, SUBOPT_CREATE_SLOT))
-                       ereport(ERROR,
-                                       (errcode(ERRCODE_SYNTAX_ERROR),
-                       /*- translator: both %s are strings of the form "option = value" */
-                                        errmsg("subscription with %s must also set %s",
-                                                       "slot_name = NONE", "create_slot = false")));
+               if (opts->create_slot)
+               {
+                       if (IsSet(opts->specified_opts, SUBOPT_CREATE_SLOT))
+                               ereport(ERROR,
+                                               (errcode(ERRCODE_SYNTAX_ERROR),
+                               /*- translator: both %s are strings of the form "option = value" */
+                                                errmsg("%s and %s are mutually exclusive options",
+                                                               "slot_name = NONE", "create_slot = true")));
+                       else
+                               ereport(ERROR,
+                                               (errcode(ERRCODE_SYNTAX_ERROR),
+                               /*- translator: both %s are strings of the form "option = value" */
+                                                errmsg("subscription with %s must also set %s",
+                                                               "slot_name = NONE", "create_slot = false")));
+               }
        }
 }
 
index 15a1ac6398b0ffc468288ccb90c7930854a04b93..80aae83562cb213465b362acda29ceef2be6c59f 100644 (file)
@@ -54,7 +54,7 @@ CREATE SUBSCRIPTION regress_testsub2 CONNECTION 'dbname=regress_doesnotexist' PU
 ERROR:  connect = false and create_slot = true are mutually exclusive options
 CREATE SUBSCRIPTION regress_testsub2 CONNECTION 'dbname=regress_doesnotexist' PUBLICATION testpub WITH (slot_name = NONE, enabled = true);
 ERROR:  slot_name = NONE and enabled = true are mutually exclusive options
-CREATE SUBSCRIPTION regress_testsub2 CONNECTION 'dbname=regress_doesnotexist' PUBLICATION testpub WITH (slot_name = NONE, create_slot = true);
+CREATE SUBSCRIPTION regress_testsub2 CONNECTION 'dbname=regress_doesnotexist' PUBLICATION testpub WITH (slot_name = NONE, enabled = false, create_slot = true);
 ERROR:  slot_name = NONE and create_slot = true are mutually exclusive options
 CREATE SUBSCRIPTION regress_testsub2 CONNECTION 'dbname=regress_doesnotexist' PUBLICATION testpub WITH (slot_name = NONE);
 ERROR:  subscription with slot_name = NONE must also set enabled = false
index 7faa935a2a7575b57012b5d47a937ad63a2c9b59..bd0f4af1e490d9d392f00136b233dd93a6d12790 100644 (file)
@@ -43,7 +43,7 @@ CREATE SUBSCRIPTION regress_testsub2 CONNECTION 'dbname=regress_doesnotexist' PU
 CREATE SUBSCRIPTION regress_testsub2 CONNECTION 'dbname=regress_doesnotexist' PUBLICATION testpub WITH (connect = false, enabled = true);
 CREATE SUBSCRIPTION regress_testsub2 CONNECTION 'dbname=regress_doesnotexist' PUBLICATION testpub WITH (connect = false, create_slot = true);
 CREATE SUBSCRIPTION regress_testsub2 CONNECTION 'dbname=regress_doesnotexist' PUBLICATION testpub WITH (slot_name = NONE, enabled = true);
-CREATE SUBSCRIPTION regress_testsub2 CONNECTION 'dbname=regress_doesnotexist' PUBLICATION testpub WITH (slot_name = NONE, create_slot = true);
+CREATE SUBSCRIPTION regress_testsub2 CONNECTION 'dbname=regress_doesnotexist' PUBLICATION testpub WITH (slot_name = NONE, enabled = false, create_slot = true);
 CREATE SUBSCRIPTION regress_testsub2 CONNECTION 'dbname=regress_doesnotexist' PUBLICATION testpub WITH (slot_name = NONE);
 CREATE SUBSCRIPTION regress_testsub2 CONNECTION 'dbname=regress_doesnotexist' PUBLICATION testpub WITH (slot_name = NONE, enabled = false);
 CREATE SUBSCRIPTION regress_testsub2 CONNECTION 'dbname=regress_doesnotexist' PUBLICATION testpub WITH (slot_name = NONE, create_slot = false);