*** a/doc/src/sgml/ref/psql-ref.sgml --- b/doc/src/sgml/ref/psql-ref.sgml *************** *** 2827,2833 **** bar they are sent to the server. The switch for this is . If set to errors then only failed queries are displayed on standard error output. The switch ! for this is . --- 2827,2835 ---- they are sent to the server. The switch for this is . If set to errors then only failed queries are displayed on standard error output. The switch ! for this is . If unset, or if set to ! none (or any other value than those above) then ! no queries are displayed. *************** *** 2892,2899 **** bar list. If set to a value of ignoredups, lines matching the previous history line are not entered. A value of ignoreboth combines the two options. If ! unset, or if set to any other value than those above, all lines ! read in interactive mode are saved on the history list. --- 2894,2902 ---- list. If set to a value of ignoredups, lines matching the previous history line are not entered. A value of ignoreboth combines the two options. If ! unset, or if set to none (or any other value ! than those above), all lines read in interactive mode are ! saved on the history list. *** a/src/bin/psql/tab-complete.c --- b/src/bin/psql/tab-complete.c *************** *** 813,820 **** static char *_complete_from_query(int is_schema_query, const char *text, int state); static char *complete_from_list(const char *text, int state); static char *complete_from_const(const char *text, int state); static char **complete_from_variables(const char *text, ! const char *prefix, const char *suffix); static char *complete_from_files(const char *text, int state); static char *pg_strdup_keyword_case(const char *s, const char *ref); --- 813,823 ---- const char *text, int state); static char *complete_from_list(const char *text, int state); static char *complete_from_const(const char *text, int state); + static void append_variable_names(char ***varnames, int *nvars, + int *maxvars, const char *varname, + const char *prefix, const char *suffix); static char **complete_from_variables(const char *text, ! const char *prefix, const char *suffix, bool need_value); static char *complete_from_files(const char *text, int state); static char *pg_strdup_keyword_case(const char *s, const char *ref); *************** *** 925,935 **** psql_completion(const char *text, int start, int end) else if (text[0] == ':' && text[1] != ':') { if (text[1] == '\'') ! matches = complete_from_variables(text, ":'", "'"); else if (text[1] == '"') ! matches = complete_from_variables(text, ":\"", "\""); else ! matches = complete_from_variables(text, ":", ""); } /* If no previous word, suggest one of the basic sql commands */ --- 928,938 ---- else if (text[0] == ':' && text[1] != ':') { if (text[1] == '\'') ! matches = complete_from_variables(text, ":'", "'", true); else if (text[1] == '"') ! matches = complete_from_variables(text, ":\"", "\"", true); else ! matches = complete_from_variables(text, ":", "", true); } /* If no previous word, suggest one of the basic sql commands */ *************** *** 3604,3612 **** psql_completion(const char *text, int start, int end) COMPLETE_WITH_LIST_CS(my_list); } } else if (strcmp(prev_wd, "\\set") == 0) { ! matches = complete_from_variables(text, "", ""); } else if (strcmp(prev_wd, "\\sf") == 0 || strcmp(prev_wd, "\\sf+") == 0) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_functions, NULL); --- 3607,3677 ---- COMPLETE_WITH_LIST_CS(my_list); } } + else if (strcmp(prev_wd, "\\unset") == 0) + { + matches = complete_from_variables(text, "", "", true); + } else if (strcmp(prev_wd, "\\set") == 0) { ! matches = complete_from_variables(text, "", "", false); ! } ! else if (strcmp(prev2_wd, "\\set") == 0) ! { ! static const char *const boolean_value_list[] = ! {"on", "off", NULL}; ! ! if (strcmp(prev_wd, "AUTOCOMMIT") == 0) ! COMPLETE_WITH_LIST_CS(boolean_value_list); ! else if (strcmp(prev_wd, "COMP_KEYWORD_CASE") == 0) ! { ! static const char *const my_list[] = ! {"lower", "upper", "preserve-lower", "preserve-upper", NULL}; ! ! COMPLETE_WITH_LIST_CS(my_list); ! } ! else if (strcmp(prev_wd, "ECHO") == 0) ! { ! static const char *const my_list[] = ! {"errors", "queries", "all", "none", NULL}; ! ! COMPLETE_WITH_LIST_CS(my_list); ! } ! else if (strcmp(prev_wd, "ECHO_HIDDEN") == 0) ! { ! static const char *const my_list[] = ! {"noexec", "off", "on", NULL}; ! ! COMPLETE_WITH_LIST_CS(my_list); ! } ! else if (strcmp(prev_wd, "HISTCONTROL") == 0) ! { ! static const char *const my_list[] = ! {"ignorespace", "ignoredups", "ignoreboth", "none", NULL}; ! ! COMPLETE_WITH_LIST_CS(my_list); ! } ! else if (strcmp(prev_wd, "ON_ERROR_ROLLBACK") == 0) ! { ! static const char *const my_list[] = ! {"on", "off", "interactive", NULL}; ! ! COMPLETE_WITH_LIST_CS(my_list); ! } ! else if (strcmp(prev_wd, "ON_ERROR_STOP") == 0) ! COMPLETE_WITH_LIST_CS(boolean_value_list); ! else if (strcmp(prev_wd, "QUIET") == 0) ! COMPLETE_WITH_LIST_CS(boolean_value_list); ! else if (strcmp(prev_wd, "SINGLELINE") == 0) ! COMPLETE_WITH_LIST_CS(boolean_value_list); ! else if (strcmp(prev_wd, "SINGLESTEP") == 0) ! COMPLETE_WITH_LIST_CS(boolean_value_list); ! else if (strcmp(prev_wd, "VERBOSITY") == 0) ! { ! static const char *const my_list[] = ! {"default", "verbose", "terse", NULL}; ! ! COMPLETE_WITH_LIST_CS(my_list); ! } } else if (strcmp(prev_wd, "\\sf") == 0 || strcmp(prev_wd, "\\sf+") == 0) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_functions, NULL); *************** *** 4053,4064 **** complete_from_const(const char *text, int state) /* * This function supports completion with the name of a psql variable. * The variable names can be prefixed and suffixed with additional text ! * to support quoting usages. */ static char ** ! complete_from_variables(const char *text, const char *prefix, const char *suffix) { char **matches; char **varnames; --- 4118,4156 ---- /* + * This function appends the variable name with prefix and suffix to + * the variable names array. + */ + static void + append_variable_names(char ***varnames, int *nvars, + int *maxvars, const char *varname, + const char *prefix, const char *suffix) + { + if (*nvars >= *maxvars) + { + *maxvars *= 2; + *varnames = (char **) realloc(*varnames, + ((*maxvars) + 1) * sizeof(char *)); + if (!(*varnames)) + { + psql_error("out of memory\n"); + exit(EXIT_FAILURE); + } + } + + (*varnames)[(*nvars)++] = psprintf("%s%s%s", prefix, varname, suffix); + } + + + /* * This function supports completion with the name of a psql variable. * The variable names can be prefixed and suffixed with additional text ! * to support quoting usages. If need_value is true, only the variables ! * that have the set values are picked up. */ static char ** ! complete_from_variables(const char *text, const char *prefix, const char *suffix, ! bool need_value) { char **matches; char **varnames; *************** *** 4067,4089 **** complete_from_variables(const char *text, const char *prefix, const char *suffix int i; struct _variable *ptr; varnames = (char **) pg_malloc((maxvars + 1) * sizeof(char *)); for (ptr = pset.vars->next; ptr; ptr = ptr->next) { ! if (nvars >= maxvars) { ! maxvars *= 2; ! varnames = (char **) realloc(varnames, ! (maxvars + 1) * sizeof(char *)); ! if (!varnames) ! { ! psql_error("out of memory\n"); ! exit(EXIT_FAILURE); ! } } ! ! varnames[nvars++] = psprintf("%s%s%s", prefix, ptr->name, suffix); } varnames[nvars] = NULL; --- 4159,4192 ---- int i; struct _variable *ptr; + static const char *const known_varnames[] = { + "AUTOCOMMIT", "COMP_KEYWORD_CASE", "DBNAME", "ECHO", "ECHO_HIDDEN", + "ENCODING", "FETCH_COUNT", "HISTCONTROL", "HISTFILE", "HISTSIZE", + "HOST", "IGNOREEOF", "LASTOID", "ON_ERROR_ROLLBACK", "ON_ERROR_STOP", + "PORT", "PROMPT1", "PROMPT2", "PROMPT3", "QUIET", "SINGLELINE", + "SINGLESTEP", "USER", "VERBOSITY", NULL + }; + varnames = (char **) pg_malloc((maxvars + 1) * sizeof(char *)); + if (!need_value) + { + for (i = 0; known_varnames[i] && nvars < maxvars; i++) + append_variable_names(&varnames, &nvars, &maxvars, + known_varnames[i], prefix, suffix); + } + for (ptr = pset.vars->next; ptr; ptr = ptr->next) { ! if (need_value && !(ptr->value)) ! continue; ! for (i = 0; known_varnames[i]; i++) /* remove duplicate entry */ { ! if (strcmp(ptr->name, known_varnames[i]) == 0) ! continue; } ! append_variable_names(&varnames, &nvars, &maxvars, ptr->name, ! prefix, suffix); } varnames[nvars] = NULL;