Support new syntax and improve handling of parentheses in psql tab-completion.
Newly supported syntax are: - ALTER {TABLE|INDEX|TABLESPACE} {SET|RESET} with options - ALTER TABLE ALTER COLUMN {SET|RESET} with options - ALTER TABLE ALTER COLUMN SET STORAGE - CREATE INDEX CONCURRENTLY - CREATE INDEX ON (without name) - CREATE INDEX ... USING with pg_am.amname instead of hard-corded names - CREATE TRIGGER with events - DROP AGGREGATE function with arguments
This commit is contained in:
parent
c64339face
commit
37ec19a15c
@ -3,7 +3,7 @@
|
|||||||
*
|
*
|
||||||
* Copyright (c) 2000-2010, PostgreSQL Global Development Group
|
* Copyright (c) 2000-2010, PostgreSQL Global Development Group
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/src/bin/psql/tab-complete.c,v 1.194 2010/02/16 22:34:50 tgl Exp $
|
* $PostgreSQL: pgsql/src/bin/psql/tab-complete.c,v 1.195 2010/02/17 04:09:40 itagaki Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*----------------------------------------------------------------------
|
/*----------------------------------------------------------------------
|
||||||
@ -66,6 +66,8 @@ extern char *filename_completion_function();
|
|||||||
#define completion_matches rl_completion_matches
|
#define completion_matches rl_completion_matches
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* word break characters */
|
||||||
|
#define WORD_BREAKS "\t\n@$><=;|&{() "
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This struct is used to define "schema queries", which are custom-built
|
* This struct is used to define "schema queries", which are custom-built
|
||||||
@ -500,6 +502,11 @@ static const SchemaQuery Query_for_list_of_views = {
|
|||||||
" FROM pg_catalog.pg_user_mappings "\
|
" FROM pg_catalog.pg_user_mappings "\
|
||||||
" WHERE substring(pg_catalog.quote_ident(usename),1,%d)='%s'"
|
" WHERE substring(pg_catalog.quote_ident(usename),1,%d)='%s'"
|
||||||
|
|
||||||
|
#define Query_for_list_of_access_methods \
|
||||||
|
" SELECT pg_catalog.quote_ident(amname) "\
|
||||||
|
" FROM pg_catalog.pg_am "\
|
||||||
|
" WHERE substring(pg_catalog.quote_ident(amname),1,%d)='%s'"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This is a list of all "things" in Pgsql, which can show up after CREATE or
|
* This is a list of all "things" in Pgsql, which can show up after CREATE or
|
||||||
* DROP; and there is also a query to get a list of them.
|
* DROP; and there is also a query to get a list of them.
|
||||||
@ -571,8 +578,6 @@ static PGresult *exec_query(const char *query);
|
|||||||
|
|
||||||
static char *previous_word(int point, int skip);
|
static char *previous_word(int point, int skip);
|
||||||
|
|
||||||
static int find_open_parenthesis(int end);
|
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
static char *quote_file_name(char *text, int match_type, char *quote_pointer);
|
static char *quote_file_name(char *text, int match_type, char *quote_pointer);
|
||||||
static char *dequote_file_name(char *text, char quote_char);
|
static char *dequote_file_name(char *text, char quote_char);
|
||||||
@ -586,7 +591,7 @@ initialize_readline(void)
|
|||||||
rl_readline_name = (char *) pset.progname;
|
rl_readline_name = (char *) pset.progname;
|
||||||
rl_attempted_completion_function = (void *) psql_completion;
|
rl_attempted_completion_function = (void *) psql_completion;
|
||||||
|
|
||||||
rl_basic_word_break_characters = "\t\n@$><=;|&{( ";
|
rl_basic_word_break_characters = WORD_BREAKS;
|
||||||
|
|
||||||
completion_max_records = 1000;
|
completion_max_records = 1000;
|
||||||
|
|
||||||
@ -749,6 +754,33 @@ psql_completion(char *text, int start, int end)
|
|||||||
|
|
||||||
COMPLETE_WITH_LIST(list_ALTERINDEX);
|
COMPLETE_WITH_LIST(list_ALTERINDEX);
|
||||||
}
|
}
|
||||||
|
/* ALTER INDEX <name> SET */
|
||||||
|
else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
|
||||||
|
pg_strcasecmp(prev3_wd, "INDEX") == 0 &&
|
||||||
|
pg_strcasecmp(prev_wd, "SET") == 0)
|
||||||
|
{
|
||||||
|
static const char *const list_ALTERINDEXSET[] =
|
||||||
|
{"(", "TABLESPACE", NULL};
|
||||||
|
|
||||||
|
COMPLETE_WITH_LIST(list_ALTERINDEXSET);
|
||||||
|
}
|
||||||
|
/* ALTER INDEX <name> RESET */
|
||||||
|
else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
|
||||||
|
pg_strcasecmp(prev3_wd, "INDEX") == 0 &&
|
||||||
|
pg_strcasecmp(prev_wd, "RESET") == 0)
|
||||||
|
COMPLETE_WITH_CONST("(");
|
||||||
|
/* ALTER INDEX <foo> SET|RESET ( */
|
||||||
|
else if (pg_strcasecmp(prev5_wd, "ALTER") == 0 &&
|
||||||
|
pg_strcasecmp(prev4_wd, "INDEX") == 0 &&
|
||||||
|
(pg_strcasecmp(prev2_wd, "SET") == 0 ||
|
||||||
|
pg_strcasecmp(prev2_wd, "RESET") == 0) &&
|
||||||
|
pg_strcasecmp(prev_wd, "(") == 0)
|
||||||
|
{
|
||||||
|
static const char *const list_INDEXOPTIONS[] =
|
||||||
|
{"fillfactor", "fastupdate", NULL};
|
||||||
|
|
||||||
|
COMPLETE_WITH_LIST(list_INDEXOPTIONS);
|
||||||
|
}
|
||||||
|
|
||||||
/* ALTER LANGUAGE <name> */
|
/* ALTER LANGUAGE <name> */
|
||||||
else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
|
else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
|
||||||
@ -977,10 +1009,11 @@ psql_completion(char *text, int start, int end)
|
|||||||
pg_strcasecmp(prev2_wd, "ALTER") == 0))
|
pg_strcasecmp(prev2_wd, "ALTER") == 0))
|
||||||
{
|
{
|
||||||
static const char *const list_COLUMNALTER[] =
|
static const char *const list_COLUMNALTER[] =
|
||||||
{"TYPE", "SET", "DROP", NULL};
|
{"TYPE", "SET", "RESET", "DROP", NULL};
|
||||||
|
|
||||||
COMPLETE_WITH_LIST(list_COLUMNALTER);
|
COMPLETE_WITH_LIST(list_COLUMNALTER);
|
||||||
}
|
}
|
||||||
|
/* ALTER TABLE ALTER [COLUMN] <foo> SET */
|
||||||
else if (((pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
|
else if (((pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
|
||||||
pg_strcasecmp(prev3_wd, "COLUMN") == 0) ||
|
pg_strcasecmp(prev3_wd, "COLUMN") == 0) ||
|
||||||
(pg_strcasecmp(prev5_wd, "TABLE") == 0 &&
|
(pg_strcasecmp(prev5_wd, "TABLE") == 0 &&
|
||||||
@ -988,10 +1021,35 @@ psql_completion(char *text, int start, int end)
|
|||||||
pg_strcasecmp(prev_wd, "SET") == 0)
|
pg_strcasecmp(prev_wd, "SET") == 0)
|
||||||
{
|
{
|
||||||
static const char *const list_COLUMNSET[] =
|
static const char *const list_COLUMNSET[] =
|
||||||
{"DEFAULT", "NOT NULL", "STATISTICS", "STORAGE", NULL};
|
{"(", "DEFAULT", "NOT NULL", "STATISTICS", "STORAGE", NULL};
|
||||||
|
|
||||||
COMPLETE_WITH_LIST(list_COLUMNSET);
|
COMPLETE_WITH_LIST(list_COLUMNSET);
|
||||||
}
|
}
|
||||||
|
/* ALTER TABLE ALTER [COLUMN] <foo> SET ( */
|
||||||
|
else if (((pg_strcasecmp(prev5_wd, "ALTER") == 0 &&
|
||||||
|
pg_strcasecmp(prev4_wd, "COLUMN") == 0) ||
|
||||||
|
pg_strcasecmp(prev4_wd, "ALTER") == 0) &&
|
||||||
|
pg_strcasecmp(prev2_wd, "SET") == 0 &&
|
||||||
|
pg_strcasecmp(prev_wd, "(") == 0)
|
||||||
|
{
|
||||||
|
static const char *const list_COLUMNOPTIONS[] =
|
||||||
|
{"n_distinct", "n_distinct_inherited", NULL};
|
||||||
|
|
||||||
|
COMPLETE_WITH_LIST(list_COLUMNOPTIONS);
|
||||||
|
}
|
||||||
|
/* ALTER TABLE ALTER [COLUMN] <foo> SET STORAGE */
|
||||||
|
else if (((pg_strcasecmp(prev5_wd, "ALTER") == 0 &&
|
||||||
|
pg_strcasecmp(prev4_wd, "COLUMN") == 0) ||
|
||||||
|
pg_strcasecmp(prev4_wd, "ALTER") == 0) &&
|
||||||
|
pg_strcasecmp(prev2_wd, "SET") == 0 &&
|
||||||
|
pg_strcasecmp(prev_wd, "STORAGE") == 0)
|
||||||
|
{
|
||||||
|
static const char *const list_COLUMNSTORAGE[] =
|
||||||
|
{"PLAIN", "EXTERNAL", "EXTENDED", "MAIN", NULL};
|
||||||
|
|
||||||
|
COMPLETE_WITH_LIST(list_COLUMNSTORAGE);
|
||||||
|
}
|
||||||
|
/* ALTER TABLE ALTER [COLUMN] <foo> DROP */
|
||||||
else if (((pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
|
else if (((pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
|
||||||
pg_strcasecmp(prev3_wd, "COLUMN") == 0) ||
|
pg_strcasecmp(prev3_wd, "COLUMN") == 0) ||
|
||||||
(pg_strcasecmp(prev5_wd, "TABLE") == 0 &&
|
(pg_strcasecmp(prev5_wd, "TABLE") == 0 &&
|
||||||
@ -1018,7 +1076,7 @@ psql_completion(char *text, int start, int end)
|
|||||||
pg_strcasecmp(prev_wd, "SET") == 0)
|
pg_strcasecmp(prev_wd, "SET") == 0)
|
||||||
{
|
{
|
||||||
static const char *const list_TABLESET[] =
|
static const char *const list_TABLESET[] =
|
||||||
{"WITHOUT", "TABLESPACE", "SCHEMA", NULL};
|
{"(", "WITHOUT", "TABLESPACE", "SCHEMA", NULL};
|
||||||
|
|
||||||
COMPLETE_WITH_LIST(list_TABLESET);
|
COMPLETE_WITH_LIST(list_TABLESET);
|
||||||
}
|
}
|
||||||
@ -1037,15 +1095,73 @@ psql_completion(char *text, int start, int end)
|
|||||||
|
|
||||||
COMPLETE_WITH_LIST(list_TABLESET2);
|
COMPLETE_WITH_LIST(list_TABLESET2);
|
||||||
}
|
}
|
||||||
/* we have ALTER TABLESPACE, so suggest RENAME TO, OWNER TO */
|
/* ALTER TABLE <foo> RESET */
|
||||||
|
else if (pg_strcasecmp(prev3_wd, "TABLE") == 0 &&
|
||||||
|
pg_strcasecmp(prev_wd, "RESET") == 0)
|
||||||
|
COMPLETE_WITH_CONST("(");
|
||||||
|
/* ALTER TABLE <foo> SET|RESET ( */
|
||||||
|
else if (pg_strcasecmp(prev4_wd, "TABLE") == 0 &&
|
||||||
|
(pg_strcasecmp(prev2_wd, "SET") == 0 ||
|
||||||
|
pg_strcasecmp(prev2_wd, "RESET") == 0) &&
|
||||||
|
pg_strcasecmp(prev_wd, "(") == 0)
|
||||||
|
{
|
||||||
|
static const char *const list_TABLEOPTIONS[] =
|
||||||
|
{
|
||||||
|
"autovacuum_analyze_scale_factor",
|
||||||
|
"autovacuum_analyze_threshold",
|
||||||
|
"autovacuum_enabled",
|
||||||
|
"autovacuum_freeze_max_age",
|
||||||
|
"autovacuum_freeze_min_age",
|
||||||
|
"autovacuum_freeze_table_age",
|
||||||
|
"autovacuum_vacuum_cost_delay",
|
||||||
|
"autovacuum_vacuum_cost_limit",
|
||||||
|
"autovacuum_vacuum_scale_factor",
|
||||||
|
"autovacuum_vacuum_threshold",
|
||||||
|
"fillfactor",
|
||||||
|
"toast.autovacuum_analyze_scale_factor",
|
||||||
|
"toast.autovacuum_analyze_threshold",
|
||||||
|
"toast.autovacuum_enabled",
|
||||||
|
"toast.autovacuum_freeze_max_age",
|
||||||
|
"toast.autovacuum_freeze_min_age",
|
||||||
|
"toast.autovacuum_freeze_table_age",
|
||||||
|
"toast.autovacuum_vacuum_cost_delay",
|
||||||
|
"toast.autovacuum_vacuum_cost_limit",
|
||||||
|
"toast.autovacuum_vacuum_scale_factor",
|
||||||
|
"toast.autovacuum_vacuum_threshold",
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
COMPLETE_WITH_LIST(list_TABLEOPTIONS);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ALTER TABLESPACE <foo> with RENAME TO, OWNER TO, SET, RESET */
|
||||||
else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
|
else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
|
||||||
pg_strcasecmp(prev2_wd, "TABLESPACE") == 0)
|
pg_strcasecmp(prev2_wd, "TABLESPACE") == 0)
|
||||||
{
|
{
|
||||||
static const char *const list_ALTERTSPC[] =
|
static const char *const list_ALTERTSPC[] =
|
||||||
{"RENAME TO", "OWNER TO", NULL};
|
{"RENAME TO", "OWNER TO", "SET", "RESET", NULL};
|
||||||
|
|
||||||
COMPLETE_WITH_LIST(list_ALTERTSPC);
|
COMPLETE_WITH_LIST(list_ALTERTSPC);
|
||||||
}
|
}
|
||||||
|
/* ALTER TABLESPACE <foo> SET|RESET */
|
||||||
|
else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
|
||||||
|
pg_strcasecmp(prev3_wd, "TABLESPACE") == 0 &&
|
||||||
|
(pg_strcasecmp(prev_wd, "SET") == 0 ||
|
||||||
|
pg_strcasecmp(prev_wd, "RESET") == 0))
|
||||||
|
COMPLETE_WITH_CONST("(");
|
||||||
|
/* ALTER TABLESPACE <foo> SET|RESET ( */
|
||||||
|
else if (pg_strcasecmp(prev5_wd, "ALTER") == 0 &&
|
||||||
|
pg_strcasecmp(prev4_wd, "TABLESPACE") == 0 &&
|
||||||
|
(pg_strcasecmp(prev2_wd, "SET") == 0 ||
|
||||||
|
pg_strcasecmp(prev2_wd, "RESET") == 0) &&
|
||||||
|
pg_strcasecmp(prev_wd, "(") == 0)
|
||||||
|
{
|
||||||
|
static const char *const list_TABLESPACEOPTIONS[] =
|
||||||
|
{"seq_page_cost", "random_page_cost", NULL};
|
||||||
|
|
||||||
|
COMPLETE_WITH_LIST(list_TABLESPACEOPTIONS);
|
||||||
|
}
|
||||||
|
|
||||||
/* ALTER TEXT SEARCH */
|
/* ALTER TEXT SEARCH */
|
||||||
else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
|
else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
|
||||||
pg_strcasecmp(prev2_wd, "TEXT") == 0 &&
|
pg_strcasecmp(prev2_wd, "TEXT") == 0 &&
|
||||||
@ -1282,44 +1398,66 @@ psql_completion(char *text, int start, int end)
|
|||||||
else if (pg_strcasecmp(prev2_wd, "CREATE") == 0 &&
|
else if (pg_strcasecmp(prev2_wd, "CREATE") == 0 &&
|
||||||
pg_strcasecmp(prev_wd, "UNIQUE") == 0)
|
pg_strcasecmp(prev_wd, "UNIQUE") == 0)
|
||||||
COMPLETE_WITH_CONST("INDEX");
|
COMPLETE_WITH_CONST("INDEX");
|
||||||
/* If we have CREATE|UNIQUE INDEX <sth>, then add "ON" */
|
/* If we have CREATE|UNIQUE INDEX, then add "ON" and existing indexes */
|
||||||
else if (pg_strcasecmp(prev2_wd, "INDEX") == 0 &&
|
else if (pg_strcasecmp(prev_wd, "INDEX") == 0 &&
|
||||||
(pg_strcasecmp(prev3_wd, "CREATE") == 0 ||
|
(pg_strcasecmp(prev2_wd, "CREATE") == 0 ||
|
||||||
pg_strcasecmp(prev3_wd, "UNIQUE") == 0))
|
pg_strcasecmp(prev2_wd, "UNIQUE") == 0))
|
||||||
COMPLETE_WITH_CONST("ON");
|
COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_indexes,
|
||||||
/* Complete ... INDEX <name> ON with a list of tables */
|
" UNION SELECT 'ON'"
|
||||||
else if (pg_strcasecmp(prev3_wd, "INDEX") == 0 &&
|
" UNION SELECT 'CONCURRENTLY'");
|
||||||
|
/* Complete ... INDEX [<name>] ON with a list of tables */
|
||||||
|
else if ((pg_strcasecmp(prev3_wd, "INDEX") == 0 ||
|
||||||
|
pg_strcasecmp(prev2_wd, "INDEX") == 0 ||
|
||||||
|
pg_strcasecmp(prev2_wd, "CONCURRENTLY") == 0) &&
|
||||||
pg_strcasecmp(prev_wd, "ON") == 0)
|
pg_strcasecmp(prev_wd, "ON") == 0)
|
||||||
COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
|
COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
|
||||||
|
/* If we have CREATE|UNIQUE INDEX <sth> CONCURRENTLY, then add "ON" */
|
||||||
|
else if ((pg_strcasecmp(prev3_wd, "INDEX") == 0 ||
|
||||||
|
pg_strcasecmp(prev2_wd, "INDEX") == 0) &&
|
||||||
|
pg_strcasecmp(prev_wd, "CONCURRENTLY") == 0)
|
||||||
|
COMPLETE_WITH_CONST("ON");
|
||||||
|
/* If we have CREATE|UNIQUE INDEX <sth>, then add "ON" or "CONCURRENTLY" */
|
||||||
|
else if ((pg_strcasecmp(prev3_wd, "CREATE") == 0 ||
|
||||||
|
pg_strcasecmp(prev3_wd, "UNIQUE") == 0) &&
|
||||||
|
pg_strcasecmp(prev2_wd, "INDEX") == 0)
|
||||||
|
{
|
||||||
|
static const char *const list_CREATE_INDEX[] =
|
||||||
|
{"CONCURRENTLY", "ON", NULL};
|
||||||
|
|
||||||
|
COMPLETE_WITH_LIST(list_CREATE_INDEX);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Complete INDEX <name> ON <table> with a list of table columns (which
|
* Complete INDEX <name> ON <table> with a list of table columns (which
|
||||||
* should really be in parens)
|
* should really be in parens)
|
||||||
*/
|
*/
|
||||||
else if (pg_strcasecmp(prev4_wd, "INDEX") == 0 &&
|
else if ((pg_strcasecmp(prev4_wd, "INDEX") == 0 ||
|
||||||
|
pg_strcasecmp(prev3_wd, "INDEX") == 0 ||
|
||||||
|
pg_strcasecmp(prev3_wd, "CONCURRENTLY") == 0) &&
|
||||||
pg_strcasecmp(prev2_wd, "ON") == 0)
|
pg_strcasecmp(prev2_wd, "ON") == 0)
|
||||||
{
|
{
|
||||||
if (find_open_parenthesis(end))
|
static const char *const list_CREATE_INDEX2[] =
|
||||||
COMPLETE_WITH_ATTR(prev_wd, "");
|
{"(", "USING", NULL};
|
||||||
else
|
|
||||||
COMPLETE_WITH_CONST("(");
|
COMPLETE_WITH_LIST(list_CREATE_INDEX2);
|
||||||
}
|
}
|
||||||
else if (pg_strcasecmp(prev5_wd, "INDEX") == 0 &&
|
else if ((pg_strcasecmp(prev5_wd, "INDEX") == 0 ||
|
||||||
|
pg_strcasecmp(prev4_wd, "INDEX") == 0 ||
|
||||||
|
pg_strcasecmp(prev4_wd, "CONCURRENTLY") == 0) &&
|
||||||
pg_strcasecmp(prev3_wd, "ON") == 0 &&
|
pg_strcasecmp(prev3_wd, "ON") == 0 &&
|
||||||
pg_strcasecmp(prev_wd, "(") == 0)
|
pg_strcasecmp(prev_wd, "(") == 0)
|
||||||
COMPLETE_WITH_ATTR(prev2_wd, "");
|
COMPLETE_WITH_ATTR(prev2_wd, "");
|
||||||
/* same if you put in USING */
|
/* same if you put in USING */
|
||||||
else if (pg_strcasecmp(prev4_wd, "ON") == 0 &&
|
else if (pg_strcasecmp(prev5_wd, "ON") == 0 &&
|
||||||
pg_strcasecmp(prev2_wd, "USING") == 0)
|
pg_strcasecmp(prev3_wd, "USING") == 0 &&
|
||||||
COMPLETE_WITH_ATTR(prev3_wd, "");
|
pg_strcasecmp(prev_wd, "(") == 0)
|
||||||
|
COMPLETE_WITH_ATTR(prev4_wd, "");
|
||||||
/* Complete USING with an index method */
|
/* Complete USING with an index method */
|
||||||
else if (pg_strcasecmp(prev_wd, "USING") == 0)
|
else if (pg_strcasecmp(prev_wd, "USING") == 0)
|
||||||
{
|
COMPLETE_WITH_QUERY(Query_for_list_of_access_methods);
|
||||||
static const char *const index_mth[] =
|
else if (pg_strcasecmp(prev4_wd, "ON") == 0 &&
|
||||||
{"BTREE", "HASH", "GIN", "GIST", NULL};
|
pg_strcasecmp(prev2_wd, "USING") == 0)
|
||||||
|
COMPLETE_WITH_CONST("(");
|
||||||
COMPLETE_WITH_LIST(index_mth);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* CREATE RULE */
|
/* CREATE RULE */
|
||||||
/* Complete "CREATE RULE <sth>" with "AS" */
|
/* Complete "CREATE RULE <sth>" with "AS" */
|
||||||
@ -1417,6 +1555,17 @@ psql_completion(char *text, int start, int end)
|
|||||||
|
|
||||||
COMPLETE_WITH_LIST(list_CREATETRIGGER);
|
COMPLETE_WITH_LIST(list_CREATETRIGGER);
|
||||||
}
|
}
|
||||||
|
/* complete CREATE TRIGGER <name> BEFORE,AFTER with an event */
|
||||||
|
else if (pg_strcasecmp(prev4_wd, "CREATE") == 0 &&
|
||||||
|
pg_strcasecmp(prev3_wd, "TRIGGER") == 0 &&
|
||||||
|
(pg_strcasecmp(prev_wd, "BEFORE") == 0 ||
|
||||||
|
pg_strcasecmp(prev_wd, "AFTER") == 0))
|
||||||
|
{
|
||||||
|
static const char *const list_CREATETRIGGER_EVENTS[] =
|
||||||
|
{"INSERT", "DELETE", "UPDATE", "TRUNCATE", NULL};
|
||||||
|
|
||||||
|
COMPLETE_WITH_LIST(list_CREATETRIGGER_EVENTS);
|
||||||
|
}
|
||||||
/* complete CREATE TRIGGER <name> BEFORE,AFTER sth with OR,ON */
|
/* complete CREATE TRIGGER <name> BEFORE,AFTER sth with OR,ON */
|
||||||
else if (pg_strcasecmp(prev5_wd, "CREATE") == 0 &&
|
else if (pg_strcasecmp(prev5_wd, "CREATE") == 0 &&
|
||||||
pg_strcasecmp(prev4_wd, "TRIGGER") == 0 &&
|
pg_strcasecmp(prev4_wd, "TRIGGER") == 0 &&
|
||||||
@ -1428,6 +1577,15 @@ psql_completion(char *text, int start, int end)
|
|||||||
|
|
||||||
COMPLETE_WITH_LIST(list_CREATETRIGGER2);
|
COMPLETE_WITH_LIST(list_CREATETRIGGER2);
|
||||||
}
|
}
|
||||||
|
/* complete CREATE TRIGGER <name> BEFORE,AFTER event ON with a list of tables */
|
||||||
|
else if (pg_strcasecmp(prev5_wd, "TRIGGER") == 0 &&
|
||||||
|
(pg_strcasecmp(prev3_wd, "BEFORE") == 0 ||
|
||||||
|
pg_strcasecmp(prev3_wd, "AFTER") == 0) &&
|
||||||
|
pg_strcasecmp(prev_wd, "ON") == 0)
|
||||||
|
COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
|
||||||
|
/* complete CREATE TRIGGER ... EXECUTE with PROCEDURE */
|
||||||
|
else if (pg_strcasecmp(prev_wd, "EXECUTE") == 0)
|
||||||
|
COMPLETE_WITH_CONST("PROCEDURE");
|
||||||
|
|
||||||
/* CREATE ROLE,USER,GROUP */
|
/* CREATE ROLE,USER,GROUP */
|
||||||
else if (pg_strcasecmp(prev3_wd, "CREATE") == 0 &&
|
else if (pg_strcasecmp(prev3_wd, "CREATE") == 0 &&
|
||||||
@ -1487,6 +1645,7 @@ psql_completion(char *text, int start, int end)
|
|||||||
COMPLETE_WITH_LIST(list_DECLARE);
|
COMPLETE_WITH_LIST(list_DECLARE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* CURSOR */
|
||||||
else if (pg_strcasecmp(prev_wd, "CURSOR") == 0)
|
else if (pg_strcasecmp(prev_wd, "CURSOR") == 0)
|
||||||
{
|
{
|
||||||
static const char *const list_DECLARECURSOR[] =
|
static const char *const list_DECLARECURSOR[] =
|
||||||
@ -1579,21 +1738,10 @@ psql_completion(char *text, int start, int end)
|
|||||||
pg_strcasecmp(prev2_wd, "TEMPLATE") == 0))
|
pg_strcasecmp(prev2_wd, "TEMPLATE") == 0))
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
if ((pg_strcasecmp(prev3_wd, "DROP") == 0) && (pg_strcasecmp(prev2_wd, "FUNCTION") == 0))
|
if (pg_strcasecmp(prev3_wd, "DROP") == 0 &&
|
||||||
|
pg_strcasecmp(prev2_wd, "FUNCTION") == 0)
|
||||||
{
|
{
|
||||||
if (find_open_parenthesis(end))
|
COMPLETE_WITH_CONST("(");
|
||||||
{
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
COMPLETE_WITH_CONST("(");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -1604,7 +1752,8 @@ psql_completion(char *text, int start, int end)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (pg_strcasecmp(prev4_wd, "DROP") == 0 &&
|
else if (pg_strcasecmp(prev4_wd, "DROP") == 0 &&
|
||||||
pg_strcasecmp(prev3_wd, "FUNCTION") == 0 &&
|
(pg_strcasecmp(prev3_wd, "AGGREGATE") == 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'";
|
static const char func_args_query[] = "select pg_catalog.oidvectortypes(proargtypes)||')' from pg_proc where proname='%s'";
|
||||||
@ -1712,12 +1861,12 @@ psql_completion(char *text, int start, int end)
|
|||||||
else if (pg_strcasecmp(prev_wd, "GRANT") == 0 ||
|
else if (pg_strcasecmp(prev_wd, "GRANT") == 0 ||
|
||||||
pg_strcasecmp(prev_wd, "REVOKE") == 0)
|
pg_strcasecmp(prev_wd, "REVOKE") == 0)
|
||||||
{
|
{
|
||||||
static const char *const list_privileg[] =
|
static const char *const list_privilege[] =
|
||||||
{"SELECT", "INSERT", "UPDATE", "DELETE", "TRUNCATE", "REFERENCES",
|
{"SELECT", "INSERT", "UPDATE", "DELETE", "TRUNCATE", "REFERENCES",
|
||||||
"TRIGGER", "CREATE", "CONNECT", "TEMPORARY", "EXECUTE", "USAGE",
|
"TRIGGER", "CREATE", "CONNECT", "TEMPORARY", "EXECUTE", "USAGE",
|
||||||
"ALL", NULL};
|
"ALL", NULL};
|
||||||
|
|
||||||
COMPLETE_WITH_LIST(list_privileg);
|
COMPLETE_WITH_LIST(list_privilege);
|
||||||
}
|
}
|
||||||
/* Complete GRANT/REVOKE <sth> with "ON" */
|
/* Complete GRANT/REVOKE <sth> with "ON" */
|
||||||
else if (pg_strcasecmp(prev2_wd, "GRANT") == 0 ||
|
else if (pg_strcasecmp(prev2_wd, "GRANT") == 0 ||
|
||||||
@ -1747,8 +1896,18 @@ psql_completion(char *text, int start, int end)
|
|||||||
" UNION SELECT 'LARGE OBJECT'"
|
" UNION SELECT 'LARGE OBJECT'"
|
||||||
" UNION SELECT 'SCHEMA'"
|
" UNION SELECT 'SCHEMA'"
|
||||||
" UNION SELECT 'TABLESPACE'");
|
" UNION SELECT 'TABLESPACE'");
|
||||||
|
else if ((pg_strcasecmp(prev4_wd, "GRANT") == 0 ||
|
||||||
|
pg_strcasecmp(prev4_wd, "REVOKE") == 0) &&
|
||||||
|
pg_strcasecmp(prev2_wd, "ON") == 0 &&
|
||||||
|
pg_strcasecmp(prev_wd, "FOREIGN") == 0)
|
||||||
|
{
|
||||||
|
static const char *const list_privilege_foreign[] =
|
||||||
|
{"DATA WRAPPER", "SERVER", NULL};
|
||||||
|
|
||||||
/* Complete "GRANT/REVOKE * ON * " with "TO" */
|
COMPLETE_WITH_LIST(list_privilege_foreign);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Complete "GRANT/REVOKE * ON * " with "TO/FROM" */
|
||||||
else if ((pg_strcasecmp(prev4_wd, "GRANT") == 0 ||
|
else if ((pg_strcasecmp(prev4_wd, "GRANT") == 0 ||
|
||||||
pg_strcasecmp(prev4_wd, "REVOKE") == 0) &&
|
pg_strcasecmp(prev4_wd, "REVOKE") == 0) &&
|
||||||
pg_strcasecmp(prev2_wd, "ON") == 0)
|
pg_strcasecmp(prev2_wd, "ON") == 0)
|
||||||
@ -1770,12 +1929,22 @@ psql_completion(char *text, int start, int end)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Complete "GRANT/REVOKE * ON * TO/FROM" with username, GROUP, or PUBLIC */
|
/* Complete "GRANT/REVOKE * ON * TO/FROM" with username, GROUP, or PUBLIC */
|
||||||
else if (pg_strcasecmp(prev3_wd, "ON") == 0 &&
|
else if (pg_strcasecmp(prev5_wd, "GRANT") == 0 &&
|
||||||
((pg_strcasecmp(prev5_wd, "GRANT") == 0 &&
|
pg_strcasecmp(prev3_wd, "ON") == 0)
|
||||||
pg_strcasecmp(prev_wd, "TO") == 0) ||
|
{
|
||||||
(pg_strcasecmp(prev5_wd, "REVOKE") == 0 &&
|
if (pg_strcasecmp(prev_wd, "TO") == 0)
|
||||||
pg_strcasecmp(prev_wd, "FROM") == 0)))
|
COMPLETE_WITH_QUERY(Query_for_list_of_grant_roles);
|
||||||
COMPLETE_WITH_QUERY(Query_for_list_of_grant_roles);
|
else
|
||||||
|
COMPLETE_WITH_CONST("TO");
|
||||||
|
}
|
||||||
|
else if (pg_strcasecmp(prev5_wd, "REVOKE") == 0 &&
|
||||||
|
pg_strcasecmp(prev3_wd, "ON") == 0)
|
||||||
|
{
|
||||||
|
if (pg_strcasecmp(prev_wd, "FROM") == 0)
|
||||||
|
COMPLETE_WITH_QUERY(Query_for_list_of_grant_roles);
|
||||||
|
else
|
||||||
|
COMPLETE_WITH_CONST("FROM");
|
||||||
|
}
|
||||||
|
|
||||||
/* GROUP BY */
|
/* GROUP BY */
|
||||||
else if (pg_strcasecmp(prev3_wd, "FROM") == 0 &&
|
else if (pg_strcasecmp(prev3_wd, "FROM") == 0 &&
|
||||||
@ -1791,20 +1960,20 @@ psql_completion(char *text, int start, int end)
|
|||||||
pg_strcasecmp(prev_wd, "INTO") == 0)
|
pg_strcasecmp(prev_wd, "INTO") == 0)
|
||||||
COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
|
COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
|
||||||
/* Complete "INSERT INTO <table> (" with attribute names */
|
/* Complete "INSERT INTO <table> (" with attribute names */
|
||||||
else if (rl_line_buffer[start - 1] == '(' &&
|
else if (pg_strcasecmp(prev4_wd, "INSERT") == 0 &&
|
||||||
pg_strcasecmp(prev3_wd, "INSERT") == 0 &&
|
pg_strcasecmp(prev3_wd, "INTO") == 0 &&
|
||||||
pg_strcasecmp(prev2_wd, "INTO") == 0)
|
pg_strcasecmp(prev_wd, "(") == 0)
|
||||||
COMPLETE_WITH_ATTR(prev_wd, "");
|
COMPLETE_WITH_ATTR(prev2_wd, "");
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Complete INSERT INTO <table> with "VALUES" or "SELECT" or "TABLE" or
|
* Complete INSERT INTO <table> with "(" or "VALUES" or "SELECT" or "TABLE"
|
||||||
* "DEFAULT VALUES"
|
* or "DEFAULT VALUES"
|
||||||
*/
|
*/
|
||||||
else if (pg_strcasecmp(prev3_wd, "INSERT") == 0 &&
|
else if (pg_strcasecmp(prev3_wd, "INSERT") == 0 &&
|
||||||
pg_strcasecmp(prev2_wd, "INTO") == 0)
|
pg_strcasecmp(prev2_wd, "INTO") == 0)
|
||||||
{
|
{
|
||||||
static const char *const list_INSERT[] =
|
static const char *const list_INSERT[] =
|
||||||
{"DEFAULT VALUES", "SELECT", "TABLE", "VALUES", NULL};
|
{"(", "DEFAULT VALUES", "SELECT", "TABLE", "VALUES", NULL};
|
||||||
|
|
||||||
COMPLETE_WITH_LIST(list_INSERT);
|
COMPLETE_WITH_LIST(list_INSERT);
|
||||||
}
|
}
|
||||||
@ -2056,6 +2225,7 @@ psql_completion(char *text, int start, int end)
|
|||||||
else if (pg_strcasecmp(prev2_wd, "SET") == 0 &&
|
else if (pg_strcasecmp(prev2_wd, "SET") == 0 &&
|
||||||
pg_strcasecmp(prev4_wd, "UPDATE") != 0 &&
|
pg_strcasecmp(prev4_wd, "UPDATE") != 0 &&
|
||||||
pg_strcasecmp(prev_wd, "TABLESPACE") != 0 &&
|
pg_strcasecmp(prev_wd, "TABLESPACE") != 0 &&
|
||||||
|
prev_wd[strlen(prev_wd) - 1] != ')' &&
|
||||||
pg_strcasecmp(prev4_wd, "DOMAIN") != 0)
|
pg_strcasecmp(prev4_wd, "DOMAIN") != 0)
|
||||||
COMPLETE_WITH_CONST("TO");
|
COMPLETE_WITH_CONST("TO");
|
||||||
/* Suggest possible variable values */
|
/* Suggest possible variable values */
|
||||||
@ -2775,17 +2945,21 @@ previous_word(int point, int skip)
|
|||||||
end = -1,
|
end = -1,
|
||||||
inquotes = 0;
|
inquotes = 0;
|
||||||
char *s;
|
char *s;
|
||||||
|
const char *buf = rl_line_buffer; /* alias */
|
||||||
|
|
||||||
|
/* first we look for a space or a parenthesis before the current word */
|
||||||
|
for (i = point - 1; i >= 0; i--)
|
||||||
|
if (strchr(WORD_BREAKS, buf[i]))
|
||||||
|
break;
|
||||||
|
point = i;
|
||||||
|
|
||||||
while (skip-- >= 0)
|
while (skip-- >= 0)
|
||||||
{
|
{
|
||||||
/* first we look for a space before the current word */
|
int parentheses = 0;
|
||||||
for (i = point; i >= 0; i--)
|
|
||||||
if (rl_line_buffer[i] == ' ')
|
|
||||||
break;
|
|
||||||
|
|
||||||
/* now find the first non-space which then constitutes the end */
|
/* now find the first non-space which then constitutes the end */
|
||||||
for (; i >= 0; i--)
|
for (i = point; i >= 0; i--)
|
||||||
if (rl_line_buffer[i] != ' ')
|
if (buf[i] != ' ')
|
||||||
{
|
{
|
||||||
end = i;
|
end = i;
|
||||||
break;
|
break;
|
||||||
@ -2801,52 +2975,37 @@ previous_word(int point, int skip)
|
|||||||
/*
|
/*
|
||||||
* Otherwise we now look for the start. The start is either the last
|
* Otherwise we now look for the start. The start is either the last
|
||||||
* character before any space going backwards from the end, or it's
|
* character before any space going backwards from the end, or it's
|
||||||
* simply character 0
|
* simply character 0. We also handle open quotes and parentheses.
|
||||||
*/
|
*/
|
||||||
for (start = end; start > 0; start--)
|
for (start = end; start > 0; start--)
|
||||||
{
|
{
|
||||||
if (rl_line_buffer[start] == '"')
|
if (buf[start] == '"')
|
||||||
inquotes = !inquotes;
|
inquotes = !inquotes;
|
||||||
if ((rl_line_buffer[start - 1] == ' ') && inquotes == 0)
|
if (inquotes == 0)
|
||||||
break;
|
{
|
||||||
|
if (buf[start] == ')')
|
||||||
|
parentheses++;
|
||||||
|
else if (buf[start] == '(')
|
||||||
|
{
|
||||||
|
if (--parentheses <= 0)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else if (parentheses == 0 &&
|
||||||
|
strchr(WORD_BREAKS, buf[start - 1]))
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
point = start;
|
point = start - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* make a copy */
|
/* make a copy */
|
||||||
s = pg_malloc(end - start + 2);
|
s = pg_malloc(end - start + 2);
|
||||||
strlcpy(s, &rl_line_buffer[start], end - start + 2);
|
strlcpy(s, &buf[start], end - start + 2);
|
||||||
|
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Find the parenthesis after the last word */
|
|
||||||
|
|
||||||
|
|
||||||
static int
|
|
||||||
find_open_parenthesis(int end)
|
|
||||||
{
|
|
||||||
int i = end - 1;
|
|
||||||
|
|
||||||
while ((rl_line_buffer[i] != ' ') && (i >= 0))
|
|
||||||
{
|
|
||||||
if (rl_line_buffer[i] == '(')
|
|
||||||
return 1;
|
|
||||||
i--;
|
|
||||||
}
|
|
||||||
while ((rl_line_buffer[i] == ' ') && (i >= 0))
|
|
||||||
{
|
|
||||||
i--;
|
|
||||||
}
|
|
||||||
if (rl_line_buffer[i] == '(')
|
|
||||||
{
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
Loading…
x
Reference in New Issue
Block a user