Fix tab completion in psql for ALTER DEFAULT PRIVILEGES
authorStephen Frost <[email protected]>
Sat, 24 Dec 2016 02:01:40 +0000 (21:01 -0500)
committerStephen Frost <[email protected]>
Sat, 24 Dec 2016 02:01:40 +0000 (21:01 -0500)
When providing tab completion for ALTER DEFAULT PRIVILEGES, we are
including the list of roles as possible options for completion after the
GRANT or REVOKE.  Further, we accept FOR ROLE/IN SCHEMA at the same time
and in either order, but the tab completion was only working for one or
the other.  Lastly, we weren't using the actual list of allowed kinds of
objects for default privileges for completion after the 'GRANT X ON' but
instead were completeing to what 'GRANT X ON' supports, which isn't the
ssame at all.

Address these issues by improving the forward tab-completion for ALTER
DEFAULT PRIVILEGES and then constrain and correct how the tail
completion is done when it is for ALTER DEFAULT PRIVILEGES.

Back-patch the forward/tail tab-completion to 9.6, where we made it easy
to handle such cases.

For 9.5 and earlier, correct the initial tab-completion to at least be
correct as far as it goes and then add a check for GRANT/REVOKE to only
tab-complete when the GRANT/REVOKE is the start of the command, so we
don't try to do tab-completion after we get to the GRANT/REVOKE part of
the ALTER DEFAULT PRIVILEGES command, which is better than providing
incorrect completions.

Initial patch for master and 9.6 by Gilles Darold, though I cleaned it
up and added a few comments.  All bugs in the 9.5 and earlier patch are
mine.

Discussion: https://www.postgresql.org/message-id/1614593c-e356-5b27-6dba-66320a9bc68b@dalibo.com

src/bin/psql/tab-complete.c

index e46367252fed2c181ce717b27b784ee934333495..4cb2c49be97a967b9fb14b9781753cf33339a90b 100644 (file)
@@ -1288,7 +1288,7 @@ psql_completion(const char *text, int start, int end)
                         pg_strcasecmp(prev_wd, "PRIVILEGES") == 0)
        {
                static const char *const list_ALTER_DEFAULT_PRIVILEGES[] =
-               {"FOR ROLE", "FOR USER", "IN SCHEMA", NULL};
+               {"FOR ROLE", "IN SCHEMA", NULL};
 
                COMPLETE_WITH_LIST(list_ALTER_DEFAULT_PRIVILEGES);
        }
@@ -1298,19 +1298,26 @@ psql_completion(const char *text, int start, int end)
                         pg_strcasecmp(prev2_wd, "PRIVILEGES") == 0 &&
                         pg_strcasecmp(prev_wd, "FOR") == 0)
        {
-               static const char *const list_ALTER_DEFAULT_PRIVILEGES_FOR[] =
-               {"ROLE", "USER", NULL};
+               COMPLETE_WITH_CONST("ROLE");
+       }
+       /* ALTER DEFAULT PRIVILEGES FOR ROLE ... } */
+       else if (pg_strcasecmp(prev5_wd, "DEFAULT") == 0 &&
+                        pg_strcasecmp(prev4_wd, "PRIVILEGES") == 0 &&
+                        pg_strcasecmp(prev3_wd, "FOR") == 0)
+       {
+               static const char *const list_ALTER_DEFAULT_PRIVILEGES_REST[] =
+               {"GRANT", "REVOKE", "IN SCHEMA", NULL};
 
-               COMPLETE_WITH_LIST(list_ALTER_DEFAULT_PRIVILEGES_FOR);
+               COMPLETE_WITH_LIST(list_ALTER_DEFAULT_PRIVILEGES_REST);
        }
-       /* ALTER DEFAULT PRIVILEGES { FOR ROLE ... | IN SCHEMA ... } */
+       /* ALTER DEFAULT PRIVILEGES IN SCHEMA ... } */
        else if (pg_strcasecmp(prev5_wd, "DEFAULT") == 0 &&
                         pg_strcasecmp(prev4_wd, "PRIVILEGES") == 0 &&
-                        (pg_strcasecmp(prev3_wd, "FOR") == 0 ||
-                         pg_strcasecmp(prev3_wd, "IN") == 0))
+                        pg_strcasecmp(prev3_wd, "IN") == 0 &&
+                        pg_strcasecmp(prev2_wd, "SCHEMA") == 0)
        {
                static const char *const list_ALTER_DEFAULT_PRIVILEGES_REST[] =
-               {"GRANT", "REVOKE", NULL};
+               {"GRANT", "REVOKE", "FOR ROLE", NULL};
 
                COMPLETE_WITH_LIST(list_ALTER_DEFAULT_PRIVILEGES_REST);
        }
@@ -3053,8 +3060,9 @@ psql_completion(const char *text, int start, int end)
 
 /* GRANT && REVOKE */
        /* Complete GRANT/REVOKE with a list of roles and privileges */
-       else if (pg_strcasecmp(prev_wd, "GRANT") == 0 ||
-                        pg_strcasecmp(prev_wd, "REVOKE") == 0)
+       else if (prev2_wd[0] == '\0' &&
+                        (pg_strcasecmp(prev_wd, "GRANT") == 0 ||
+                         pg_strcasecmp(prev_wd, "REVOKE") == 0))
        {
                COMPLETE_WITH_QUERY(Query_for_list_of_roles
                                                        " UNION SELECT 'SELECT'"