OSDN Git Service

Add tab-completion for REASSIGN OWNED BY and DROP OWNED BY. Also fix some
authorAlvaro Herrera <alvherre@alvh.no-ip.org>
Sun, 2 Apr 2006 09:02:41 +0000 (09:02 +0000)
committerAlvaro Herrera <alvherre@alvh.no-ip.org>
Sun, 2 Apr 2006 09:02:41 +0000 (09:02 +0000)
whitespace issues nearby.

DROP OWNED BY is actually a bit kludgy, but it seems better to do it this way
rather than duplicating the words_after_create list just to add a single
element.

src/bin/psql/tab-complete.c

index fca3aa3..a90d7eb 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright (c) 2000-2006, PostgreSQL Global Development Group
  *
- * $PostgreSQL: pgsql/src/bin/psql/tab-complete.c,v 1.149 2006/03/05 15:58:52 momjian Exp $
+ * $PostgreSQL: pgsql/src/bin/psql/tab-complete.c,v 1.150 2006/04/02 09:02:41 alvherre Exp $
  */
 
 /*----------------------------------------------------------------------
@@ -465,6 +465,7 @@ static const pgsql_thing_t words_after_create[] = {
 /* Forward declaration of functions */
 static char **psql_completion(char *text, int start, int end);
 static char *create_command_generator(const char *text, int state);
+static char *drop_command_generator(const char *text, int state);
 static char *complete_from_query(const char *text, int state);
 static char *complete_from_schema_query(const char *text, int state);
 static char *_complete_from_query(int is_schema_query,
@@ -521,11 +522,13 @@ psql_completion(char *text, int start, int end)
                           *prev5_wd;
 
        static const char *const sql_commands[] = {
-               "ABORT", "ALTER", "ANALYZE", "BEGIN", "CHECKPOINT", "CLOSE", "CLUSTER", "COMMENT",
-               "COMMIT", "COPY", "CREATE", "DEALLOCATE", "DECLARE", "DELETE FROM", "DROP", "END", "EXECUTE",
-               "EXPLAIN", "FETCH", "GRANT", "INSERT", "LISTEN", "LOAD", "LOCK", "MOVE", "NOTIFY",
-               "PREPARE", "REINDEX", "RELEASE", "RESET", "REVOKE", "ROLLBACK", "SAVEPOINT",
-               "SELECT", "SET", "SHOW", "START", "TRUNCATE", "UNLISTEN", "UPDATE", "VACUUM", NULL
+               "ABORT", "ALTER", "ANALYZE", "BEGIN", "CHECKPOINT", "CLOSE", "CLUSTER",
+               "COMMENT", "COMMIT", "COPY", "CREATE", "DEALLOCATE", "DECLARE",
+               "DELETE FROM", "DROP", "END", "EXECUTE", "EXPLAIN", "FETCH", "GRANT",
+               "INSERT", "LISTEN", "LOAD", "LOCK", "MOVE", "NOTIFY", "PREPARE",
+               "REASSIGN", "REINDEX", "RELEASE", "RESET", "REVOKE", "ROLLBACK",
+               "SAVEPOINT", "SELECT", "SET", "SHOW", "START", "TRUNCATE", "UNLISTEN",
+               "UPDATE", "VACUUM", NULL
        };
 
        static const char *const backslash_commands[] = {
@@ -536,7 +539,8 @@ psql_completion(char *text, int start, int end)
                "\\e", "\\echo", "\\encoding",
                "\\f", "\\g", "\\h", "\\help", "\\H", "\\i", "\\l",
                "\\lo_import", "\\lo_export", "\\lo_list", "\\lo_unlink",
-               "\\o", "\\p", "\\password", "\\pset", "\\q", "\\qecho", "\\r", "\\set", "\\t", "\\T",
+               "\\o", "\\p", "\\password", "\\pset", "\\q", "\\qecho", "\\r",
+               "\\set", "\\t", "\\T",
                "\\timing", "\\unset", "\\x", "\\w", "\\z", "\\!", NULL
        };
 
@@ -570,15 +574,19 @@ psql_completion(char *text, int start, int end)
        else if (!prev_wd)
                COMPLETE_WITH_LIST(sql_commands);
 
-/* CREATE or DROP but not ALTER (TABLE|DOMAIN|GROUP) sth DROP */
-       /* complete with something you can create or drop */
-       else if (pg_strcasecmp(prev_wd, "CREATE") == 0 ||
-                        (pg_strcasecmp(prev_wd, "DROP") == 0 &&
-                         pg_strcasecmp(prev3_wd, "TABLE") != 0 &&
-                         pg_strcasecmp(prev3_wd, "DOMAIN") != 0 &&
-                         pg_strcasecmp(prev3_wd, "GROUP") != 0))
+/* CREATE */
+       /* complete with something you can create */
+       else if (pg_strcasecmp(prev_wd, "CREATE") == 0)
                matches = completion_matches(text, create_command_generator);
 
+/* DROP, except ALTER (TABLE|DOMAIN|GROUP) sth DROP */
+       /* complete with something you can drop */
+       else if (pg_strcasecmp(prev_wd, "DROP") == 0 &&
+                        pg_strcasecmp(prev3_wd, "TABLE") != 0 &&
+                        pg_strcasecmp(prev3_wd, "DOMAIN") != 0 &&
+                        pg_strcasecmp(prev3_wd, "GROUP") != 0)
+               matches = completion_matches(text, drop_command_generator);
+
 /* ALTER */
 
        /*
@@ -1248,23 +1256,22 @@ psql_completion(char *text, int start, int end)
                          pg_strcasecmp(prev3_wd, "AGGREGATE") == 0 &&
                          prev_wd[strlen(prev_wd) - 1] == ')'))
        {
-               
                if ((pg_strcasecmp(prev3_wd, "DROP") == 0) && (pg_strcasecmp(prev2_wd, "FUNCTION") == 0))
-                {
-                        if (find_open_parenthesis(end))
+               {
+                       if (find_open_parenthesis(end))
                        {
                                static const char func_args_query[] = "select pg_catalog.oidvectortypes(proargtypes)||')' from pg_proc where proname='%s'";
-                               char *tmp_buf = malloc(strlen(func_args_query) + strlen(prev_wd));
-                               sprintf(tmp_buf, func_args_query, prev_wd);
-                               COMPLETE_WITH_QUERY(tmp_buf);
-                               free(tmp_buf);
+                               char *tmp_buf = malloc(strlen(func_args_query) + strlen(prev_wd));
+                               sprintf(tmp_buf, func_args_query, prev_wd);
+                               COMPLETE_WITH_QUERY(tmp_buf);
+                               free(tmp_buf);
                        }
                        else
                        {
-                               COMPLETE_WITH_CONST("(");
+                               COMPLETE_WITH_CONST("(");
                        }
-                }
-                else
+               }
+               else
                {
                        static const char *const list_DROPCR[] =
                        {"CASCADE", "RESTRICT", NULL};
@@ -1274,7 +1281,7 @@ psql_completion(char *text, int start, int end)
        }
        else if (pg_strcasecmp(prev4_wd, "DROP") == 0 &&
                        pg_strcasecmp(prev3_wd, "FUNCTION") == 0 &&
-                       pg_strcasecmp(prev_wd, "(") == 0 )
+                       pg_strcasecmp(prev_wd, "(") == 0)
        {
                static const char func_args_query[] = "select pg_catalog.oidvectortypes(proargtypes)||')' from pg_proc where proname='%s'";
                char *tmp_buf = malloc(strlen(func_args_query) + strlen(prev2_wd));
@@ -1282,6 +1289,14 @@ psql_completion(char *text, int start, int end)
                COMPLETE_WITH_QUERY(tmp_buf);
                free(tmp_buf);
        }
+       /* DROP OWNED BY */
+       else if (pg_strcasecmp(prev2_wd, "DROP") == 0 &&
+                        pg_strcasecmp(prev_wd, "OWNED") == 0)
+               COMPLETE_WITH_CONST("BY");
+       else if (pg_strcasecmp(prev3_wd, "DROP") == 0 &&
+                        pg_strcasecmp(prev2_wd, "OWNED") == 0 &&
+                        pg_strcasecmp(prev_wd, "BY") == 0)
+               COMPLETE_WITH_QUERY(Query_for_list_of_roles);
 
 
 
@@ -1502,7 +1517,7 @@ psql_completion(char *text, int start, int end)
        else if (pg_strcasecmp(prev_wd, "NOTIFY") == 0)
                COMPLETE_WITH_QUERY("SELECT pg_catalog.quote_ident(relname) FROM pg_catalog.pg_listener WHERE substring(pg_catalog.quote_ident(relname),1,%d)='%s'");
 
-/* OWNER TO  - complete with available roles*/
+/* OWNER TO  - complete with available roles */
        else if (pg_strcasecmp(prev2_wd, "OWNER") == 0 &&
                         pg_strcasecmp(prev_wd, "TO") == 0)
                COMPLETE_WITH_QUERY(Query_for_list_of_roles);
@@ -1526,6 +1541,25 @@ psql_completion(char *text, int start, int end)
                COMPLETE_WITH_LIST(list_PREPARE);
        }
 
+/* REASSIGN OWNED BY xxx TO yyy */
+       else if (pg_strcasecmp(prev_wd, "REASSIGN") == 0)
+               COMPLETE_WITH_CONST("OWNED");
+       else if (pg_strcasecmp(prev_wd, "OWNED") == 0 &&
+                        pg_strcasecmp(prev2_wd, "REASSIGN") == 0)
+               COMPLETE_WITH_CONST("BY");
+       else if (pg_strcasecmp(prev_wd, "BY") == 0 &&
+                        pg_strcasecmp(prev2_wd, "OWNED") == 0 &&
+                        pg_strcasecmp(prev3_wd, "REASSIGN") == 0)
+               COMPLETE_WITH_QUERY(Query_for_list_of_roles);
+       else if (pg_strcasecmp(prev2_wd, "BY") == 0 &&
+                        pg_strcasecmp(prev3_wd, "OWNED") == 0 &&
+                        pg_strcasecmp(prev4_wd, "REASSIGN") == 0)
+               COMPLETE_WITH_CONST("TO");
+       else if (pg_strcasecmp(prev_wd, "TO") == 0 &&
+                        pg_strcasecmp(prev3_wd, "BY") == 0 &&
+                        pg_strcasecmp(prev4_wd, "OWNED") == 0 &&
+                        pg_strcasecmp(prev5_wd, "REASSIGN") == 0)
+               COMPLETE_WITH_QUERY(Query_for_list_of_roles);
 
 /* REINDEX */
        else if (pg_strcasecmp(prev_wd, "REINDEX") == 0)
@@ -1909,7 +1943,7 @@ psql_completion(char *text, int start, int end)
    something of that sort.
 */
 
-/* This one gives you one from a list of things you can put after CREATE or DROP
+/* This one gives you one from a list of things you can put after CREATE
    as defined above.
 */
 static char *
@@ -1935,6 +1969,51 @@ create_command_generator(const char *text, int state)
        return NULL;
 }
 
+/*
+ * This function gives you a list of things you can put after a DROP command.
+ * Very similar to create_command_generator, but has an additional entry for
+ * OWNED BY.  (We do it this way in order not to duplicate the
+ * words_after_create list.)
+ */
+static char *
+drop_command_generator(const char *text, int state)
+{
+       static int      list_index,
+                               string_length;
+       const char *name;
+
+       if (state == 0)
+       {
+               /* If this is the first time for this completion, init some values */
+               list_index = 0;
+               string_length = strlen(text);
+
+               /*
+                * DROP can be followed by "OWNED BY", which is not found in the list
+                * for CREATE matches, so make it the first state. (We do not make it
+                * the last state because it would be more difficult to detect when we
+                * have to return NULL instead.)
+                *
+                * Make sure we advance to the next state.
+                */
+               list_index++;
+               if (pg_strncasecmp("OWNED", text, string_length) == 0)
+                       return pg_strdup("OWNED");
+       }
+
+       /*
+        * In subsequent attempts, try to complete with the same items we use for
+        * CREATE
+        */
+       while ((name = words_after_create[list_index++ - 1].name))
+       {
+               if (pg_strncasecmp(name, text, string_length) == 0)
+                       return pg_strdup(name);
+       }
+
+       /* if nothing matches, return NULL */
+       return NULL;
+}
 
 /* The following two functions are wrappers for _complete_from_query */