diff --git a/doc/src/sgml/ref/psql-ref.sgml b/doc/src/sgml/ref/psql-ref.sgml
index b9c8fcc..ae58708 100644
*** a/doc/src/sgml/ref/psql-ref.sgml
--- b/doc/src/sgml/ref/psql-ref.sgml
*************** bar
*** 3247,3258 ****
fail after having already displayed some rows.
-
- FETCH_COUNT 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.
-
-
Although you can use any output format with this feature,
--- 3247,3252 ----
*************** bar
*** 3316,3325 ****
HISTSIZE
! 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.
--- 3310,3317 ----
HISTSIZE
! The maximum number of commands to store in the command history
! (default 500). If set to a negative value, no limit is applied.
*************** bar
*** 3345,3357 ****
IGNOREEOF
! If unset, sending an EOF> character (usually
Control>D>>)
to an interactive session of psql
! will terminate the application. If set to a numeric value,
! that many EOF> characters are ignored before the
! application terminates. If the variable is set but not to a
! numeric value, the default is 10.
--- 3337,3349 ----
IGNOREEOF
! If set to 1 or less, sending an EOF> character (usually
Control>D>>)
to an interactive session of psql
! will terminate the application. If set to a larger numeric value,
! that many consecutive 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.
diff --git a/src/bin/psql/help.c b/src/bin/psql/help.c
index 5365629..3e3cab4 100644
*** a/src/bin/psql/help.c
--- b/src/bin/psql/help.c
*************** helpVariables(unsigned short int pager)
*** 348,356 ****
" (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, _(" HOST the currently connected database server host\n"));
! fprintf(output, _(" IGNOREEOF if unset, sending an EOF to interactive session terminates application\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"));
--- 348,356 ----
" (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 max number of commands to store in the command history\n"));
fprintf(output, _(" HOST the currently connected database server host\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 3e3e97a..b8c9a00 100644
*** a/src/bin/psql/input.c
--- b/src/bin/psql/input.c
*************** finishInput(void)
*** 539,548 ****
#ifdef USE_READLINE
if (useHistory && psql_history)
{
! int hist_size;
!
! hist_size = GetVariableNum(pset.vars, "HISTSIZE", 500, -1);
! (void) saveHistory(psql_history, hist_size);
free(psql_history);
psql_history = NULL;
}
--- 539,545 ----
#ifdef USE_READLINE
if (useHistory && psql_history)
{
! (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 dc25b4b..6e358e2 100644
*** a/src/bin/psql/mainloop.c
--- b/src/bin/psql/mainloop.c
*************** MainLoop(FILE *source)
*** 162,168 ****
/* This tries to mimic bash's IGNOREEOF feature. */
count_eof++;
! if (count_eof < GetVariableNum(pset.vars, "IGNOREEOF", 0, 10))
{
if (!pset.quiet)
printf(_("Use \"\\q\" to leave %s.\n"), pset.progname);
--- 162,168 ----
/* This tries to mimic bash's IGNOREEOF feature. */
count_eof++;
! 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 4c7c3b1..195f5a1 100644
*** a/src/bin/psql/settings.h
--- b/src/bin/psql/settings.h
*************** typedef struct _psqlSettings
*** 125,130 ****
--- 125,132 ----
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 a3654e6..88d686a 100644
*** a/src/bin/psql/startup.c
--- b/src/bin/psql/startup.c
*************** showVersion(void)
*** 774,779 ****
--- 774,784 ----
* 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 *
*************** singlestep_hook(const char *newval)
*** 823,839 ****
return ParseVariableBool(newval, "SINGLESTEP", &pset.singlestep);
}
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 true;
}
static char *
echo_substitute_hook(char *newval)
{
if (newval == NULL)
--- 828,899 ----
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)
{
! 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)
{
if (newval == NULL)
*************** EstablishVariableSpace(void)
*** 1062,1069 ****
bool_substitute_hook,
singlestep_hook);
SetVariableHooks(pset.vars, "FETCH_COUNT",
! NULL,
fetch_count_hook);
SetVariableHooks(pset.vars, "ECHO",
echo_substitute_hook,
echo_hook);
--- 1122,1138 ----
bool_substitute_hook,
singlestep_hook);
SetVariableHooks(pset.vars, "FETCH_COUNT",
! 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 d6fffcf..6e759d0 100644
*** a/src/bin/psql/tab-complete.c
--- b/src/bin/psql/tab-complete.c
*************** append_variable_names(char ***varnames,
*** 3775,3782 ****
/*
* 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,
--- 3775,3783 ----
/*
* 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 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,
*************** complete_from_variables(const char *text
*** 3789,3821 ****
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);
}
--- 3790,3801 ----
diff --git a/src/bin/psql/variables.c b/src/bin/psql/variables.c
index 9ca1000..d9d0763 100644
*** a/src/bin/psql/variables.c
--- b/src/bin/psql/variables.c
*************** ParseVariableNum(const char *value, cons
*** 180,210 ****
}
/*
- * 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.
*/
void
--- 180,185 ----
diff --git a/src/bin/psql/variables.h b/src/bin/psql/variables.h
index 84be780..1925793 100644
*** a/src/bin/psql/variables.h
--- b/src/bin/psql/variables.h
*************** bool ParseVariableBool(const char *value
*** 81,91 ****
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);
--- 81,86 ----