diff --git a/doc/src/sgml/ref/psql-ref.sgml b/doc/src/sgml/ref/psql-ref.sgml index b9c8fccde43235b390614c107b64f304b662780d..ae58708aaeafbc1db1c561d7b355c09f91567cfe 100644 --- a/doc/src/sgml/ref/psql-ref.sgml +++ b/doc/src/sgml/ref/psql-ref.sgml @@ -3247,12 +3247,6 @@ bar fail after having already displayed some rows. </para> - <para> - <varname>FETCH_COUNT</varname> is ignored if it is unset or does not - have a positive value. It cannot be set to a value that is not - syntactically an integer. - </para> - <tip> <para> Although you can use any output format with this feature, @@ -3316,10 +3310,8 @@ bar <term><varname>HISTSIZE</varname></term> <listitem> <para> - The maximum number of commands to store in the command history. - If unset, at most 500 commands are stored by default. - If set to a value that is negative or not an integer, no limit is - applied. + The maximum number of commands to store in the command history + (default 500). If set to a negative value, no limit is applied. </para> <note> <para> @@ -3345,13 +3337,13 @@ bar <term><varname>IGNOREEOF</varname></term> <listitem> <para> - If unset, sending an <acronym>EOF</> character (usually + If set to 1 or less, sending an <acronym>EOF</> character (usually <keycombo action="simul"><keycap>Control</><keycap>D</></>) to an interactive session of <application>psql</application> - will terminate the application. If set to a numeric value, - that many <acronym>EOF</> characters are ignored before the - application terminates. If the variable is set but not to a - numeric value, the default is 10. + will terminate the application. If set to a larger numeric value, + that many consecutive <acronym>EOF</> characters must be typed to + make an interactive session terminate. If the variable is set to a + non-numeric value, it is interpreted as 10. </para> <note> <para> diff --git a/src/bin/psql/help.c b/src/bin/psql/help.c index 53656294da4a006e5a6201bf7f668edd88609640..3e3cab49418a9e75fd3a6d70d80739dd50fb30ea 100644 --- a/src/bin/psql/help.c +++ b/src/bin/psql/help.c @@ -348,9 +348,9 @@ helpVariables(unsigned short int pager) " (default: 0=unlimited)\n")); fprintf(output, _(" HISTCONTROL controls command history [ignorespace, ignoredups, ignoreboth]\n")); fprintf(output, _(" HISTFILE file name used to store the command history\n")); - fprintf(output, _(" HISTSIZE the number of commands to store in the command history\n")); + fprintf(output, _(" HISTSIZE max number of commands to store in the command history\n")); fprintf(output, _(" HOST the currently connected database server host\n")); - fprintf(output, _(" IGNOREEOF if unset, sending an EOF to interactive session terminates application\n")); + fprintf(output, _(" IGNOREEOF number of EOFs needed to terminate an interactive session\n")); fprintf(output, _(" LASTOID value of the last affected OID\n")); fprintf(output, _(" ON_ERROR_ROLLBACK if set, an error doesn't stop a transaction (uses implicit savepoints)\n")); fprintf(output, _(" ON_ERROR_STOP stop batch execution after error\n")); diff --git a/src/bin/psql/input.c b/src/bin/psql/input.c index 3e3e97ad0d22bf5db1671657c1e17de712947a7f..b8c9a00b099885b07eaa22b52b51bf858919945d 100644 --- a/src/bin/psql/input.c +++ b/src/bin/psql/input.c @@ -539,10 +539,7 @@ finishInput(void) #ifdef USE_READLINE if (useHistory && psql_history) { - int hist_size; - - hist_size = GetVariableNum(pset.vars, "HISTSIZE", 500, -1); - (void) saveHistory(psql_history, hist_size); + (void) saveHistory(psql_history, pset.histsize); free(psql_history); psql_history = NULL; } diff --git a/src/bin/psql/mainloop.c b/src/bin/psql/mainloop.c index dc25b4babc5a32f85d457cf082c8bf5382a923e8..6e358e2e1b8470d69b83126864f31d7eea2295c8 100644 --- a/src/bin/psql/mainloop.c +++ b/src/bin/psql/mainloop.c @@ -162,7 +162,7 @@ MainLoop(FILE *source) /* This tries to mimic bash's IGNOREEOF feature. */ count_eof++; - if (count_eof < GetVariableNum(pset.vars, "IGNOREEOF", 0, 10)) + if (count_eof < pset.ignoreeof) { if (!pset.quiet) printf(_("Use \"\\q\" to leave %s.\n"), pset.progname); diff --git a/src/bin/psql/settings.h b/src/bin/psql/settings.h index 4c7c3b1fa37a0261e5228ece7c8021fac6e1af57..195f5a118438b4a2e8d02df5ed38c56e60bd827a 100644 --- a/src/bin/psql/settings.h +++ b/src/bin/psql/settings.h @@ -125,6 +125,8 @@ typedef struct _psqlSettings bool singleline; bool singlestep; int fetch_count; + int histsize; + int ignoreeof; PSQL_ECHO echo; PSQL_ECHO_HIDDEN echo_hidden; PSQL_ERROR_ROLLBACK on_error_rollback; diff --git a/src/bin/psql/startup.c b/src/bin/psql/startup.c index a3654e62722cc4201f76078287982f3396b88e96..88d686a5b74e6a81dc53427fd0bc253b9a94559a 100644 --- a/src/bin/psql/startup.c +++ b/src/bin/psql/startup.c @@ -774,6 +774,11 @@ showVersion(void) * Substitute hooks and assign hooks for psql variables. * * This isn't an amazingly good place for them, but neither is anywhere else. + * + * By policy, every special variable that controls any psql behavior should + * have one or both hooks, even if they're just no-ops. This ensures that + * the variable will remain present in variables.c's list even when unset, + * which ensures that it's known to tab completion. */ static char * @@ -823,16 +828,71 @@ singlestep_hook(const char *newval) return ParseVariableBool(newval, "SINGLESTEP", &pset.singlestep); } +static char * +fetch_count_substitute_hook(char *newval) +{ + if (newval == NULL) + newval = pg_strdup("0"); + return newval; +} + static bool fetch_count_hook(const char *newval) { - if (newval == NULL) - pset.fetch_count = -1; /* default value */ - else if (!ParseVariableNum(newval, "FETCH_COUNT", &pset.fetch_count)) - return false; + return ParseVariableNum(newval, "FETCH_COUNT", &pset.fetch_count); +} + +static bool +histfile_hook(const char *newval) +{ + /* + * Someday we might try to validate the filename, but for now, this is + * just a placeholder to ensure HISTFILE is known to tab completion. + */ return true; } +static char * +histsize_substitute_hook(char *newval) +{ + if (newval == NULL) + newval = pg_strdup("500"); + return newval; +} + +static bool +histsize_hook(const char *newval) +{ + return ParseVariableNum(newval, "HISTSIZE", &pset.histsize); +} + +static char * +ignoreeof_substitute_hook(char *newval) +{ + int dummy; + + /* + * This tries to mimic the behavior of bash, to wit "If set, the value is + * the number of consecutive EOF characters which must be typed as the + * first characters on an input line before bash exits. If the variable + * exists but does not have a numeric value, or has no value, the default + * value is 10. If it does not exist, EOF signifies the end of input to + * the shell." Unlike bash, however, we insist on the stored value + * actually being a valid integer. + */ + if (newval == NULL) + newval = pg_strdup("0"); + else if (!ParseVariableNum(newval, NULL, &dummy)) + newval = pg_strdup("10"); + return newval; +} + +static bool +ignoreeof_hook(const char *newval) +{ + return ParseVariableNum(newval, "IGNOREEOF", &pset.ignoreeof); +} + static char * echo_substitute_hook(char *newval) { @@ -1062,8 +1122,17 @@ EstablishVariableSpace(void) bool_substitute_hook, singlestep_hook); SetVariableHooks(pset.vars, "FETCH_COUNT", - NULL, + fetch_count_substitute_hook, fetch_count_hook); + SetVariableHooks(pset.vars, "HISTFILE", + NULL, + histfile_hook); + SetVariableHooks(pset.vars, "HISTSIZE", + histsize_substitute_hook, + histsize_hook); + SetVariableHooks(pset.vars, "IGNOREEOF", + ignoreeof_substitute_hook, + ignoreeof_hook); SetVariableHooks(pset.vars, "ECHO", echo_substitute_hook, echo_hook); diff --git a/src/bin/psql/tab-complete.c b/src/bin/psql/tab-complete.c index d6fffcf42f1802f26b12ea2a08242bd6e54e3ae9..6e759d0b76fdf01e84088254160b3297f1b87a1d 100644 --- a/src/bin/psql/tab-complete.c +++ b/src/bin/psql/tab-complete.c @@ -3775,8 +3775,9 @@ append_variable_names(char ***varnames, int *nvars, /* * 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. + * to support quoting usages. If need_value is true, only variables + * that are currently set are included; otherwise, special variables + * (those that have hooks) are included even if currently unset. */ static char ** complete_from_variables(const char *text, const char *prefix, const char *suffix, @@ -3789,33 +3790,12 @@ complete_from_variables(const char *text, const char *prefix, const char *suffix 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", - "SHOW_CONTEXT", "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); } diff --git a/src/bin/psql/variables.c b/src/bin/psql/variables.c index 9ca100095f6324bd5ececac9ef335b5bfff0c1a7..d9d07631a59a3730ff31490b4263396ea4ec1119 100644 --- a/src/bin/psql/variables.c +++ b/src/bin/psql/variables.c @@ -179,31 +179,6 @@ ParseVariableNum(const char *value, const char *name, int *result) } } -/* - * Read integer value of the numeric variable named "name". - * - * Return defaultval if it is not set, or faultval if its value is not a - * valid integer. (No error message is issued.) - */ -int -GetVariableNum(VariableSpace space, - const char *name, - int defaultval, - int faultval) -{ - const char *val; - int result; - - val = GetVariable(space, name); - if (!val) - return defaultval; - - if (ParseVariableNum(val, NULL, &result)) - return result; - else - return faultval; -} - /* * Print values of all variables. */ diff --git a/src/bin/psql/variables.h b/src/bin/psql/variables.h index 84be7805098b996ac7eaa27b720099b39a2fc9d3..19257937c7cba98c8dc9e3453e35e84a7da89f91 100644 --- a/src/bin/psql/variables.h +++ b/src/bin/psql/variables.h @@ -81,11 +81,6 @@ bool ParseVariableBool(const char *value, const char *name, bool ParseVariableNum(const char *value, const char *name, int *result); -int GetVariableNum(VariableSpace space, - const char *name, - int defaultval, - int faultval); - void PrintVariables(VariableSpace space); bool SetVariable(VariableSpace space, const char *name, const char *value);