diff -cprN head/src/bin/psql/tab-complete.c work/src/bin/psql/tab-complete.c *** head/src/bin/psql/tab-complete.c 2010-02-15 11:56:18.651089000 +0900 --- work/src/bin/psql/tab-complete.c 2010-02-16 14:23:09.274053000 +0900 *************** static const SchemaQuery Query_for_list_ *** 500,505 **** --- 500,510 ---- " 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. *************** static PGresult *exec_query(const char * *** 571,578 **** 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); --- 576,581 ---- *************** psql_completion(char *text, int start, i *** 638,645 **** "\\timing", "\\unset", "\\x", "\\w", "\\z", "\\!", NULL }; - (void) end; /* not used */ - #ifdef HAVE_RL_COMPLETION_APPEND_CHARACTER rl_completion_append_character = ' '; #endif --- 641,646 ---- *************** psql_completion(char *text, int start, i *** 749,754 **** --- 750,782 ---- 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 && *************** psql_completion(char *text, int start, i *** 977,986 **** pg_strcasecmp(prev2_wd, "ALTER") == 0)) { static const char *const list_COLUMNALTER[] = ! {"TYPE", "SET", "DROP", NULL}; COMPLETE_WITH_LIST(list_COLUMNALTER); } else if (((pg_strcasecmp(prev4_wd, "ALTER") == 0 && pg_strcasecmp(prev3_wd, "COLUMN") == 0) || (pg_strcasecmp(prev5_wd, "TABLE") == 0 && --- 1005,1015 ---- pg_strcasecmp(prev2_wd, "ALTER") == 0)) { static const char *const list_COLUMNALTER[] = ! {"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 && *************** psql_completion(char *text, int start, i *** 988,997 **** pg_strcasecmp(prev_wd, "SET") == 0) { static const char *const list_COLUMNSET[] = ! {"DEFAULT", "NOT NULL", "STATISTICS", "STORAGE", NULL}; COMPLETE_WITH_LIST(list_COLUMNSET); } else if (((pg_strcasecmp(prev4_wd, "ALTER") == 0 && pg_strcasecmp(prev3_wd, "COLUMN") == 0) || (pg_strcasecmp(prev5_wd, "TABLE") == 0 && --- 1017,1051 ---- pg_strcasecmp(prev_wd, "SET") == 0) { static const char *const list_COLUMNSET[] = ! {"(", "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 && *************** psql_completion(char *text, int start, i *** 1018,1024 **** pg_strcasecmp(prev_wd, "SET") == 0) { static const char *const list_TABLESET[] = ! {"WITHOUT", "TABLESPACE", "SCHEMA", NULL}; COMPLETE_WITH_LIST(list_TABLESET); } --- 1072,1078 ---- pg_strcasecmp(prev_wd, "SET") == 0) { static const char *const list_TABLESET[] = ! {"(", "WITHOUT", "TABLESPACE", "SCHEMA", NULL}; COMPLETE_WITH_LIST(list_TABLESET); } *************** psql_completion(char *text, int start, i *** 1037,1051 **** COMPLETE_WITH_LIST(list_TABLESET2); } ! /* we have ALTER TABLESPACE, so suggest RENAME TO, OWNER TO */ 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}; COMPLETE_WITH_LIST(list_ALTERTSPC); } /* ALTER TEXT SEARCH */ else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 && pg_strcasecmp(prev2_wd, "TEXT") == 0 && --- 1091,1163 ---- COMPLETE_WITH_LIST(list_TABLESET2); } ! /* 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", "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 && *************** psql_completion(char *text, int start, i *** 1282,1325 **** 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 && pg_strcasecmp(prev_wd, "ON") == 0) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL); /* * Complete INDEX ON with a list of table columns (which * should really be in parens) */ ! else if (pg_strcasecmp(prev4_wd, "INDEX") == 0 && pg_strcasecmp(prev2_wd, "ON") == 0) { ! if (find_open_parenthesis(end)) ! COMPLETE_WITH_ATTR(prev_wd, ""); ! else ! COMPLETE_WITH_CONST("("); } ! else if (pg_strcasecmp(prev5_wd, "INDEX") == 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, ""); /* 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); ! } /* CREATE RULE */ /* Complete "CREATE RULE " with "AS" */ --- 1394,1459 ---- 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" 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 || ! pg_strcasecmp(prev3_wd, "INDEX") == 0 || ! pg_strcasecmp(prev3_wd, "CONCURRENTLY") == 0) && pg_strcasecmp(prev2_wd, "ON") == 0) { ! static const char *const list_CREATE_INDEX2[] = ! {"(", "USING", NULL}; ! ! COMPLETE_WITH_LIST(list_CREATE_INDEX2); } ! 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(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) ! 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" */ *************** psql_completion(char *text, int start, i *** 1417,1422 **** --- 1551,1567 ---- 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 && *************** psql_completion(char *text, int start, i *** 1428,1433 **** --- 1573,1587 ---- 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 && *************** psql_completion(char *text, int start, i *** 1487,1492 **** --- 1641,1647 ---- COMPLETE_WITH_LIST(list_DECLARE); } + /* CURSOR */ else if (pg_strcasecmp(prev_wd, "CURSOR") == 0) { static const char *const list_DECLARECURSOR[] = *************** psql_completion(char *text, int start, i *** 1579,1599 **** pg_strcasecmp(prev2_wd, "TEMPLATE") == 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("("); ! } } else { --- 1734,1743 ---- pg_strcasecmp(prev2_wd, "TEMPLATE") == 0)) ) { ! if (pg_strcasecmp(prev3_wd, "DROP") == 0 && ! pg_strcasecmp(prev2_wd, "FUNCTION") == 0) { ! COMPLETE_WITH_CONST("("); } else { *************** psql_completion(char *text, int start, i *** 1712,1723 **** else if (pg_strcasecmp(prev_wd, "GRANT") == 0 || pg_strcasecmp(prev_wd, "REVOKE") == 0) { ! static const char *const list_privileg[] = {"SELECT", "INSERT", "UPDATE", "DELETE", "TRUNCATE", "REFERENCES", "TRIGGER", "CREATE", "CONNECT", "TEMPORARY", "EXECUTE", "USAGE", "ALL", NULL}; ! COMPLETE_WITH_LIST(list_privileg); } /* Complete GRANT/REVOKE with "ON" */ else if (pg_strcasecmp(prev2_wd, "GRANT") == 0 || --- 1856,1867 ---- else if (pg_strcasecmp(prev_wd, "GRANT") == 0 || pg_strcasecmp(prev_wd, "REVOKE") == 0) { ! static const char *const list_privilege[] = {"SELECT", "INSERT", "UPDATE", "DELETE", "TRUNCATE", "REFERENCES", "TRIGGER", "CREATE", "CONNECT", "TEMPORARY", "EXECUTE", "USAGE", "ALL", NULL}; ! COMPLETE_WITH_LIST(list_privilege); } /* Complete GRANT/REVOKE with "ON" */ else if (pg_strcasecmp(prev2_wd, "GRANT") == 0 || *************** psql_completion(char *text, int start, i *** 1747,1754 **** " UNION SELECT 'LARGE OBJECT'" " UNION SELECT 'SCHEMA'" " UNION SELECT 'TABLESPACE'"); ! /* Complete "GRANT/REVOKE * ON * " with "TO" */ else if ((pg_strcasecmp(prev4_wd, "GRANT") == 0 || pg_strcasecmp(prev4_wd, "REVOKE") == 0) && pg_strcasecmp(prev2_wd, "ON") == 0) --- 1891,1908 ---- " 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/FROM" */ else if ((pg_strcasecmp(prev4_wd, "GRANT") == 0 || pg_strcasecmp(prev4_wd, "REVOKE") == 0) && pg_strcasecmp(prev2_wd, "ON") == 0) *************** psql_completion(char *text, int start, i *** 1770,1781 **** } /* 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); /* GROUP BY */ else if (pg_strcasecmp(prev3_wd, "FROM") == 0 && --- 1924,1945 ---- } /* Complete "GRANT/REVOKE * ON * TO/FROM" with username, GROUP, or PUBLIC */ ! 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 && *************** psql_completion(char *text, int start, i *** 2056,2061 **** --- 2220,2226 ---- else if (pg_strcasecmp(prev2_wd, "SET") == 0 && pg_strcasecmp(prev4_wd, "UPDATE") != 0 && pg_strcasecmp(prev_wd, "TABLESPACE") != 0 && + pg_strcasecmp(prev_wd, "(") != 0 && pg_strcasecmp(prev4_wd, "DOMAIN") != 0) COMPLETE_WITH_CONST("TO"); /* Suggest possible variable values */ *************** exec_query(const char *query) *** 2767,2772 **** --- 2932,2940 ---- * skip that many words; e.g. skip=1 finds the word before the * previous one. Return value is NULL or a malloc'ed string. */ + #define issep(c) \ + (isspace((unsigned char) (c)) || (c) == '(' || (c) == ')') + static char * previous_word(int point, int skip) { *************** previous_word(int point, int skip) *** 2776,2791 **** inquotes = 0; char *s; 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; - /* now find the first non-space which then constitutes the end */ ! for (; i >= 0; i--) ! if (rl_line_buffer[i] != ' ') { end = i; break; --- 2944,2960 ---- inquotes = 0; char *s; + /* first we look for a space before the current word */ + for (i = point - 1; i >= 0; i--) + if (issep(rl_line_buffer[i])) + break; + point = i; + while (skip-- >= 0) { /* now find the first non-space which then constitutes the end */ ! for (i = point; i >= 0; i--) ! if (!isspace((unsigned char) rl_line_buffer[i])) { end = i; break; *************** previous_word(int point, int skip) *** 2798,2817 **** if (end == -1) return NULL; ! /* ! * 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 ! */ ! for (start = end; start > 0; start--) { ! if (rl_line_buffer[start] == '"') ! inquotes = !inquotes; ! if ((rl_line_buffer[start - 1] == ' ') && inquotes == 0) ! break; } ! ! point = start; } /* make a copy */ --- 2967,2994 ---- if (end == -1) return NULL; ! if (issep(rl_line_buffer[end])) { ! /* non-alphabet separator is a single-character word */ ! start = end; ! point = start - 1; } ! else ! { ! /* ! * 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 ! */ ! for (start = end; start > 0; start--) ! { ! if (rl_line_buffer[start] == '"') ! inquotes = !inquotes; ! if (inquotes == 0 && issep(rl_line_buffer[start - 1])) ! break; ! } ! } ! point = start - 1; } /* make a copy */ *************** previous_word(int point, int skip) *** 2821,2852 **** 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 /* --- 2998,3003 ----