Add tab-completion for REASSIGN OWNED BY and DROP OWNED BY. Also fix some

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.
This commit is contained in:
Alvaro Herrera 2006-04-02 09:02:41 +00:00
parent d73336f8f4
commit 643b022bed
1 changed files with 106 additions and 27 deletions

View 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 */