From: Itagaki Takahiro Date: Wed, 17 Feb 2010 04:09:40 +0000 (+0000) Subject: Support new syntax and improve handling of parentheses in psql tab-completion. X-Git-Tag: REL9_0_ALPHA4~24 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=37ec19a15ce452ee94f32ebc3d6a9a45868e82fd;p=postgresql 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 --- diff --git a/src/bin/psql/tab-complete.c b/src/bin/psql/tab-complete.c index 0b10472c12..b3dbfb2021 100644 --- a/src/bin/psql/tab-complete.c +++ b/src/bin/psql/tab-complete.c @@ -3,7 +3,7 @@ * * 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 #endif +/* word break characters */ +#define WORD_BREAKS "\t\n@$><=;|&{() " /* * 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 "\ " 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 * 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 int find_open_parenthesis(int end); - #if 0 static char *quote_file_name(char *text, int match_type, char *quote_pointer); static char *dequote_file_name(char *text, char quote_char); @@ -586,7 +591,7 @@ initialize_readline(void) rl_readline_name = (char *) pset.progname; 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; @@ -749,6 +754,33 @@ psql_completion(char *text, int start, int end) COMPLETE_WITH_LIST(list_ALTERINDEX); } + /* ALTER INDEX 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 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 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 */ 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)) { static const char *const list_COLUMNALTER[] = - {"TYPE", "SET", "DROP", NULL}; + {"TYPE", "SET", "RESET", "DROP", NULL}; COMPLETE_WITH_LIST(list_COLUMNALTER); } + /* ALTER TABLE ALTER [COLUMN] SET */ else if (((pg_strcasecmp(prev4_wd, "ALTER") == 0 && pg_strcasecmp(prev3_wd, "COLUMN") == 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) { static const char *const list_COLUMNSET[] = - {"DEFAULT", "NOT NULL", "STATISTICS", "STORAGE", NULL}; + {"(", "DEFAULT", "NOT NULL", "STATISTICS", "STORAGE", NULL}; COMPLETE_WITH_LIST(list_COLUMNSET); } + /* ALTER TABLE ALTER [COLUMN] 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] 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] DROP */ else if (((pg_strcasecmp(prev4_wd, "ALTER") == 0 && pg_strcasecmp(prev3_wd, "COLUMN") == 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) { static const char *const list_TABLESET[] = - {"WITHOUT", "TABLESPACE", "SCHEMA", NULL}; + {"(", "WITHOUT", "TABLESPACE", "SCHEMA", NULL}; COMPLETE_WITH_LIST(list_TABLESET); } @@ -1037,15 +1095,73 @@ psql_completion(char *text, int start, int end) COMPLETE_WITH_LIST(list_TABLESET2); } - /* we have ALTER TABLESPACE, so suggest RENAME TO, OWNER TO */ + /* ALTER TABLE RESET */ + else if (pg_strcasecmp(prev3_wd, "TABLE") == 0 && + pg_strcasecmp(prev_wd, "RESET") == 0) + COMPLETE_WITH_CONST("("); + /* ALTER TABLE 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 with RENAME TO, OWNER TO, SET, RESET */ else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 && pg_strcasecmp(prev2_wd, "TABLESPACE") == 0) { static const char *const list_ALTERTSPC[] = - {"RENAME TO", "OWNER TO", NULL}; + {"RENAME TO", "OWNER TO", "SET", "RESET", NULL}; COMPLETE_WITH_LIST(list_ALTERTSPC); } + /* ALTER TABLESPACE 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 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 */ else if (pg_strcasecmp(prev3_wd, "ALTER") == 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 && pg_strcasecmp(prev_wd, "UNIQUE") == 0) COMPLETE_WITH_CONST("INDEX"); - /* If we have CREATE|UNIQUE INDEX , then add "ON" */ - else if (pg_strcasecmp(prev2_wd, "INDEX") == 0 && - (pg_strcasecmp(prev3_wd, "CREATE") == 0 || - pg_strcasecmp(prev3_wd, "UNIQUE") == 0)) - COMPLETE_WITH_CONST("ON"); - /* Complete ... INDEX ON with a list of tables */ - else if (pg_strcasecmp(prev3_wd, "INDEX") == 0 && + /* If we have CREATE|UNIQUE INDEX, then add "ON" and existing indexes */ + else if (pg_strcasecmp(prev_wd, "INDEX") == 0 && + (pg_strcasecmp(prev2_wd, "CREATE") == 0 || + pg_strcasecmp(prev2_wd, "UNIQUE") == 0)) + COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_indexes, + " UNION SELECT 'ON'" + " UNION SELECT 'CONCURRENTLY'"); + /* Complete ... INDEX [] 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) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL); + /* If we have CREATE|UNIQUE INDEX 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 , 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 ON with a list of table columns (which * 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) { - if (find_open_parenthesis(end)) - COMPLETE_WITH_ATTR(prev_wd, ""); - else - COMPLETE_WITH_CONST("("); + static const char *const list_CREATE_INDEX2[] = + {"(", "USING", NULL}; + + 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(prev_wd, "(") == 0) COMPLETE_WITH_ATTR(prev2_wd, ""); /* same if you put in USING */ - else if (pg_strcasecmp(prev4_wd, "ON") == 0 && - pg_strcasecmp(prev2_wd, "USING") == 0) - COMPLETE_WITH_ATTR(prev3_wd, ""); + else if (pg_strcasecmp(prev5_wd, "ON") == 0 && + pg_strcasecmp(prev3_wd, "USING") == 0 && + pg_strcasecmp(prev_wd, "(") == 0) + COMPLETE_WITH_ATTR(prev4_wd, ""); /* Complete USING with an index method */ else if (pg_strcasecmp(prev_wd, "USING") == 0) - { - static const char *const index_mth[] = - {"BTREE", "HASH", "GIN", "GIST", NULL}; - - COMPLETE_WITH_LIST(index_mth); - } + COMPLETE_WITH_QUERY(Query_for_list_of_access_methods); + else if (pg_strcasecmp(prev4_wd, "ON") == 0 && + pg_strcasecmp(prev2_wd, "USING") == 0) + COMPLETE_WITH_CONST("("); /* CREATE RULE */ /* Complete "CREATE RULE " with "AS" */ @@ -1417,6 +1555,17 @@ psql_completion(char *text, int start, int end) COMPLETE_WITH_LIST(list_CREATETRIGGER); } + /* complete CREATE TRIGGER 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 BEFORE,AFTER sth with OR,ON */ else if (pg_strcasecmp(prev5_wd, "CREATE") == 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 CREATE TRIGGER 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 */ 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); } +/* CURSOR */ else if (pg_strcasecmp(prev_wd, "CURSOR") == 0) { static const char *const list_DECLARECURSOR[] = @@ -1579,21 +1738,10 @@ psql_completion(char *text, int start, int end) 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)) - { - 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("("); - } + COMPLETE_WITH_CONST("("); } else { @@ -1604,7 +1752,8 @@ psql_completion(char *text, int start, int end) } } 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) { 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 || pg_strcasecmp(prev_wd, "REVOKE") == 0) { - static const char *const list_privileg[] = + static const char *const list_privilege[] = {"SELECT", "INSERT", "UPDATE", "DELETE", "TRUNCATE", "REFERENCES", "TRIGGER", "CREATE", "CONNECT", "TEMPORARY", "EXECUTE", "USAGE", "ALL", NULL}; - COMPLETE_WITH_LIST(list_privileg); + COMPLETE_WITH_LIST(list_privilege); } /* Complete GRANT/REVOKE with "ON" */ 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 'SCHEMA'" " 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_WITH_LIST(list_privilege_foreign); + } - /* Complete "GRANT/REVOKE * ON * " with "TO" */ + /* Complete "GRANT/REVOKE * ON * " with "TO/FROM" */ else if ((pg_strcasecmp(prev4_wd, "GRANT") == 0 || pg_strcasecmp(prev4_wd, "REVOKE") == 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 */ - else if (pg_strcasecmp(prev3_wd, "ON") == 0 && - ((pg_strcasecmp(prev5_wd, "GRANT") == 0 && - pg_strcasecmp(prev_wd, "TO") == 0) || - (pg_strcasecmp(prev5_wd, "REVOKE") == 0 && - pg_strcasecmp(prev_wd, "FROM") == 0))) - COMPLETE_WITH_QUERY(Query_for_list_of_grant_roles); + else if (pg_strcasecmp(prev5_wd, "GRANT") == 0 && + pg_strcasecmp(prev3_wd, "ON") == 0) + { + if (pg_strcasecmp(prev_wd, "TO") == 0) + 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 */ 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) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL); /* Complete "INSERT INTO
(" with attribute names */ - else if (rl_line_buffer[start - 1] == '(' && - pg_strcasecmp(prev3_wd, "INSERT") == 0 && - pg_strcasecmp(prev2_wd, "INTO") == 0) - COMPLETE_WITH_ATTR(prev_wd, ""); + else if (pg_strcasecmp(prev4_wd, "INSERT") == 0 && + pg_strcasecmp(prev3_wd, "INTO") == 0 && + pg_strcasecmp(prev_wd, "(") == 0) + COMPLETE_WITH_ATTR(prev2_wd, ""); /* - * Complete INSERT INTO
with "VALUES" or "SELECT" or "TABLE" or - * "DEFAULT VALUES" + * Complete INSERT INTO
with "(" or "VALUES" or "SELECT" or "TABLE" + * or "DEFAULT VALUES" */ else if (pg_strcasecmp(prev3_wd, "INSERT") == 0 && pg_strcasecmp(prev2_wd, "INTO") == 0) { static const char *const list_INSERT[] = - {"DEFAULT VALUES", "SELECT", "TABLE", "VALUES", NULL}; + {"(", "DEFAULT VALUES", "SELECT", "TABLE", "VALUES", NULL}; 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 && pg_strcasecmp(prev4_wd, "UPDATE") != 0 && pg_strcasecmp(prev_wd, "TABLESPACE") != 0 && + prev_wd[strlen(prev_wd) - 1] != ')' && pg_strcasecmp(prev4_wd, "DOMAIN") != 0) COMPLETE_WITH_CONST("TO"); /* Suggest possible variable values */ @@ -2775,17 +2945,21 @@ previous_word(int point, int skip) end = -1, inquotes = 0; 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) { - /* first we look for a space before the current word */ - for (i = point; i >= 0; i--) - if (rl_line_buffer[i] == ' ') - break; + int parentheses = 0; /* now find the first non-space which then constitutes the end */ - for (; i >= 0; i--) - if (rl_line_buffer[i] != ' ') + for (i = point; i >= 0; i--) + if (buf[i] != ' ') { end = i; break; @@ -2801,52 +2975,37 @@ previous_word(int point, int skip) /* * 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 - * simply character 0 + * simply character 0. We also handle open quotes and parentheses. */ for (start = end; start > 0; start--) { - if (rl_line_buffer[start] == '"') + if (buf[start] == '"') inquotes = !inquotes; - if ((rl_line_buffer[start - 1] == ' ') && inquotes == 0) - break; + if (inquotes == 0) + { + 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 */ s = pg_malloc(end - start + 2); - strlcpy(s, &rl_line_buffer[start], end - start + 2); + strlcpy(s, &buf[start], end - start + 2); 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 /*