*
* 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 $
*/
/*----------------------------------------------------------------------
/* 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,
*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[] = {
"\\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
};
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 */
/*
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};
}
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));
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);
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);
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)
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 *
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 */