You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
postgres/src/bin/psql/startup.c

1170 lines
27 KiB

/*
* psql - the PostgreSQL interactive terminal
*
* Copyright (c) 2000-2017, PostgreSQL Global Development Group
*
* src/bin/psql/startup.c
*/
#include "postgres_fe.h"
#ifndef WIN32
#include <unistd.h>
23 years ago
#else /* WIN32 */
#include <io.h>
#include <win32.h>
#endif /* WIN32 */
#include "getopt_long.h"
#include "command.h"
#include "common.h"
#include "describe.h"
#include "help.h"
#include "input.h"
#include "mainloop.h"
#include "fe_utils/print.h"
#include "settings.h"
/*
* Global psql options
*/
PsqlSettings pset;
#ifndef WIN32
#define SYSPSQLRC "psqlrc"
#define PSQLRC ".psqlrc"
#else
#define SYSPSQLRC "psqlrc"
#define PSQLRC "psqlrc.conf"
#endif
/*
* Structures to pass information between the option parsing routine
* and the main function
*/
26 years ago
enum _actions
{
ACT_SINGLE_QUERY,
ACT_SINGLE_SLASH,
ACT_FILE
};
typedef struct SimpleActionListCell
{
struct SimpleActionListCell *next;
enum _actions action;
char *val;
} SimpleActionListCell;
typedef struct SimpleActionList
{
SimpleActionListCell *head;
SimpleActionListCell *tail;
} SimpleActionList;
26 years ago
struct adhoc_opts
{
char *dbname;
char *host;
char *port;
char *username;
char *logfilename;
26 years ago
bool no_readline;
bool no_psqlrc;
bool single_txn;
bool list_dbs;
SimpleActionList actions;
};
static void parse_psql_options(int argc, char *argv[],
22 years ago
struct adhoc_opts * options);
static void simple_action_list_append(SimpleActionList *list,
enum _actions action, const char *val);
static void process_psqlrc(char *argv0);
static void process_psqlrc_file(char *filename);
static void showVersion(void);
static void EstablishVariableSpace(void);
#define NOPAGER 0
/*
*
* main
*
*/
int
main(int argc, char *argv[])
{
26 years ago
struct adhoc_opts options;
int successResult;
Simplify correct use of simple_prompt(). The previous API for this function had it returning a malloc'd string. That meant that callers had to check for NULL return, which few of them were doing, and it also meant that callers had to remember to free() the string later, which required extra logic in most cases. Instead, make simple_prompt() write into a buffer supplied by the caller. Anywhere that the maximum required input length is reasonably small, which is almost all of the callers, we can just use a local or static array as the buffer instead of dealing with malloc/free. A fair number of callers used "pointer == NULL" as a proxy for "haven't requested the password yet". Maintaining the same behavior requires adding a separate boolean flag for that, which adds back some of the complexity we save by removing free()s. Nonetheless, this nets out at a small reduction in overall code size, and considerably less code than we would have had if we'd added the missing NULL-return checks everywhere they were needed. In passing, clean up the API comment for simple_prompt() and get rid of a very-unnecessary malloc/free in its Windows code path. This is nominally a bug fix, but it does not seem worth back-patching, because the actual risk of an OOM failure in any of these places seems pretty tiny, and all of them are client-side not server-side anyway. This patch is by me, but it owes a great deal to Michael Paquier who identified the problem and drafted a patch for fixing it the other way. Discussion: <CAB7nPqRu07Ot6iht9i9KRfYLpDaF2ZuUv5y_+72uP23ZAGysRg@mail.gmail.com>
9 years ago
bool have_password = false;
char password[100];
char *password_prompt = NULL;
bool new_pass;
set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("psql"));
if (argc > 1)
{
if ((strcmp(argv[1], "-?") == 0) || (argc == 2 && (strcmp(argv[1], "--help") == 0)))
{
usage(NOPAGER);
exit(EXIT_SUCCESS);
}
if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)
{
showVersion();
exit(EXIT_SUCCESS);
}
}
#ifdef WIN32
setvbuf(stderr, NULL, _IONBF, 0);
#endif
pset.progname = get_progname(argv[0]);
pset.db = NULL;
setDecimalLocale();
pset.encoding = PQenv2encoding();
pset.queryFout = stdout;
pset.queryFoutPipe = false;
pset.copyStream = NULL;
pset.last_error_result = NULL;
pset.cur_cmd_source = stdin;
pset.cur_cmd_interactive = false;
/* We rely on unmentioned fields of pset.popt to start out 0/false/NULL */
pset.popt.topt.format = PRINT_ALIGNED;
pset.popt.topt.border = 1;
pset.popt.topt.pager = 1;
pset.popt.topt.pager_min_lines = 0;
pset.popt.topt.start_table = true;
pset.popt.topt.stop_table = true;
pset.popt.topt.default_footer = true;
pset.popt.topt.unicode_border_linestyle = UNICODE_LINESTYLE_SINGLE;
pset.popt.topt.unicode_column_linestyle = UNICODE_LINESTYLE_SINGLE;
pset.popt.topt.unicode_header_linestyle = UNICODE_LINESTYLE_SINGLE;
refresh_utf8format(&(pset.popt.topt));
/* We must get COLUMNS here before readline() sets it */
pset.popt.topt.env_columns = getenv("COLUMNS") ? atoi(getenv("COLUMNS")) : 0;
pset.notty = (!isatty(fileno(stdin)) || !isatty(fileno(stdout)));
pset.getPassword = TRI_DEFAULT;
EstablishVariableSpace();
SetVariable(pset.vars, "VERSION", PG_VERSION_STR);
Improve psql's behavior for \set and \unset of its control variables. This commit improves on the results of commit 511ae628f in two ways: 1. It restores the historical behavior that "\set FOO" is interpreted as setting FOO to "on", if FOO is a boolean control variable. We already found one test script that was expecting that behavior, and the psql documentation certainly does nothing to discourage people from assuming that would work, since it often says just "if FOO is set" when describing the effects of a boolean variable. However, now this case will result in actually setting FOO to "on", not an empty string. 2. It arranges for an "\unset" of a control variable to set the value back to its default value, rather than becoming apparently undefined. The control variables are also initialized that way at psql startup. In combination, these things guarantee that a control variable always has a displayable value that reflects what psql is actually doing. That is a pretty substantial usability improvement. The implementation involves adding a second type of variable hook function that is able to replace a proposed new value (including NULL) with another one. We could alternatively have complicated the API of the assign hook, but this way seems better since many variables can share the same substitution hook function. Also document the actual behavior of these variables more fully, including covering assorted behaviors that were there before but never documented. This patch also includes some minor cleanup that should have been in 511ae628f but was missed. Patch by me, but it owes a lot to discussions with Daniel Vérité. Discussion: https://postgr.es/m/9572.1485821620@sss.pgh.pa.us
9 years ago
/* Default values for variables (that don't match the result of \unset) */
SetVariableBool(pset.vars, "AUTOCOMMIT");
SetVariable(pset.vars, "PROMPT1", DEFAULT_PROMPT1);
SetVariable(pset.vars, "PROMPT2", DEFAULT_PROMPT2);
SetVariable(pset.vars, "PROMPT3", DEFAULT_PROMPT3);
parse_psql_options(argc, argv, &options);
/*
* If no action was specified and we're in non-interactive mode, treat it
* as if the user had specified "-f -". This lets single-transaction mode
* work in this case.
*/
if (options.actions.head == NULL && pset.notty)
simple_action_list_append(&options.actions, ACT_FILE, NULL);
/* Bail out if -1 was specified but will be ignored. */
if (options.single_txn && options.actions.head == NULL)
{
fprintf(stderr, _("%s: -1 can only be used in non-interactive mode\n"), pset.progname);
exit(EXIT_FAILURE);
}
if (!pset.popt.topt.fieldSep.separator &&
!pset.popt.topt.fieldSep.separator_zero)
{
pset.popt.topt.fieldSep.separator = pg_strdup(DEFAULT_FIELD_SEP);
pset.popt.topt.fieldSep.separator_zero = false;
}
if (!pset.popt.topt.recordSep.separator &&
!pset.popt.topt.recordSep.separator_zero)
{
pset.popt.topt.recordSep.separator = pg_strdup(DEFAULT_RECORD_SEP);
pset.popt.topt.recordSep.separator_zero = false;
}
if (options.username == NULL)
password_prompt = pg_strdup(_("Password: "));
else
password_prompt = psprintf(_("Password for user %s: "),
options.username);
if (pset.getPassword == TRI_YES)
Simplify correct use of simple_prompt(). The previous API for this function had it returning a malloc'd string. That meant that callers had to check for NULL return, which few of them were doing, and it also meant that callers had to remember to free() the string later, which required extra logic in most cases. Instead, make simple_prompt() write into a buffer supplied by the caller. Anywhere that the maximum required input length is reasonably small, which is almost all of the callers, we can just use a local or static array as the buffer instead of dealing with malloc/free. A fair number of callers used "pointer == NULL" as a proxy for "haven't requested the password yet". Maintaining the same behavior requires adding a separate boolean flag for that, which adds back some of the complexity we save by removing free()s. Nonetheless, this nets out at a small reduction in overall code size, and considerably less code than we would have had if we'd added the missing NULL-return checks everywhere they were needed. In passing, clean up the API comment for simple_prompt() and get rid of a very-unnecessary malloc/free in its Windows code path. This is nominally a bug fix, but it does not seem worth back-patching, because the actual risk of an OOM failure in any of these places seems pretty tiny, and all of them are client-side not server-side anyway. This patch is by me, but it owes a great deal to Michael Paquier who identified the problem and drafted a patch for fixing it the other way. Discussion: <CAB7nPqRu07Ot6iht9i9KRfYLpDaF2ZuUv5y_+72uP23ZAGysRg@mail.gmail.com>
9 years ago
{
simple_prompt(password_prompt, password, sizeof(password), false);
have_password = true;
}
26 years ago
/* loop until we have a password if requested by backend */
do
{
#define PARAMS_ARRAY_SIZE 8
const char **keywords = pg_malloc(PARAMS_ARRAY_SIZE * sizeof(*keywords));
const char **values = pg_malloc(PARAMS_ARRAY_SIZE * sizeof(*values));
keywords[0] = "host";
values[0] = options.host;
keywords[1] = "port";
values[1] = options.port;
keywords[2] = "user";
values[2] = options.username;
keywords[3] = "password";
Simplify correct use of simple_prompt(). The previous API for this function had it returning a malloc'd string. That meant that callers had to check for NULL return, which few of them were doing, and it also meant that callers had to remember to free() the string later, which required extra logic in most cases. Instead, make simple_prompt() write into a buffer supplied by the caller. Anywhere that the maximum required input length is reasonably small, which is almost all of the callers, we can just use a local or static array as the buffer instead of dealing with malloc/free. A fair number of callers used "pointer == NULL" as a proxy for "haven't requested the password yet". Maintaining the same behavior requires adding a separate boolean flag for that, which adds back some of the complexity we save by removing free()s. Nonetheless, this nets out at a small reduction in overall code size, and considerably less code than we would have had if we'd added the missing NULL-return checks everywhere they were needed. In passing, clean up the API comment for simple_prompt() and get rid of a very-unnecessary malloc/free in its Windows code path. This is nominally a bug fix, but it does not seem worth back-patching, because the actual risk of an OOM failure in any of these places seems pretty tiny, and all of them are client-side not server-side anyway. This patch is by me, but it owes a great deal to Michael Paquier who identified the problem and drafted a patch for fixing it the other way. Discussion: <CAB7nPqRu07Ot6iht9i9KRfYLpDaF2ZuUv5y_+72uP23ZAGysRg@mail.gmail.com>
9 years ago
values[3] = have_password ? password : NULL;
keywords[4] = "dbname"; /* see do_connect() */
values[4] = (options.list_dbs && options.dbname == NULL) ?
"postgres" : options.dbname;
keywords[5] = "fallback_application_name";
values[5] = pset.progname;
keywords[6] = "client_encoding";
values[6] = (pset.notty || getenv("PGCLIENTENCODING")) ? NULL : "auto";
keywords[7] = NULL;
values[7] = NULL;
new_pass = false;
pset.db = PQconnectdbParams(keywords, values, true);
free(keywords);
free(values);
26 years ago
if (PQstatus(pset.db) == CONNECTION_BAD &&
PQconnectionNeedsPassword(pset.db) &&
Simplify correct use of simple_prompt(). The previous API for this function had it returning a malloc'd string. That meant that callers had to check for NULL return, which few of them were doing, and it also meant that callers had to remember to free() the string later, which required extra logic in most cases. Instead, make simple_prompt() write into a buffer supplied by the caller. Anywhere that the maximum required input length is reasonably small, which is almost all of the callers, we can just use a local or static array as the buffer instead of dealing with malloc/free. A fair number of callers used "pointer == NULL" as a proxy for "haven't requested the password yet". Maintaining the same behavior requires adding a separate boolean flag for that, which adds back some of the complexity we save by removing free()s. Nonetheless, this nets out at a small reduction in overall code size, and considerably less code than we would have had if we'd added the missing NULL-return checks everywhere they were needed. In passing, clean up the API comment for simple_prompt() and get rid of a very-unnecessary malloc/free in its Windows code path. This is nominally a bug fix, but it does not seem worth back-patching, because the actual risk of an OOM failure in any of these places seems pretty tiny, and all of them are client-side not server-side anyway. This patch is by me, but it owes a great deal to Michael Paquier who identified the problem and drafted a patch for fixing it the other way. Discussion: <CAB7nPqRu07Ot6iht9i9KRfYLpDaF2ZuUv5y_+72uP23ZAGysRg@mail.gmail.com>
9 years ago
!have_password &&
pset.getPassword != TRI_NO)
26 years ago
{
PQfinish(pset.db);
Simplify correct use of simple_prompt(). The previous API for this function had it returning a malloc'd string. That meant that callers had to check for NULL return, which few of them were doing, and it also meant that callers had to remember to free() the string later, which required extra logic in most cases. Instead, make simple_prompt() write into a buffer supplied by the caller. Anywhere that the maximum required input length is reasonably small, which is almost all of the callers, we can just use a local or static array as the buffer instead of dealing with malloc/free. A fair number of callers used "pointer == NULL" as a proxy for "haven't requested the password yet". Maintaining the same behavior requires adding a separate boolean flag for that, which adds back some of the complexity we save by removing free()s. Nonetheless, this nets out at a small reduction in overall code size, and considerably less code than we would have had if we'd added the missing NULL-return checks everywhere they were needed. In passing, clean up the API comment for simple_prompt() and get rid of a very-unnecessary malloc/free in its Windows code path. This is nominally a bug fix, but it does not seem worth back-patching, because the actual risk of an OOM failure in any of these places seems pretty tiny, and all of them are client-side not server-side anyway. This patch is by me, but it owes a great deal to Michael Paquier who identified the problem and drafted a patch for fixing it the other way. Discussion: <CAB7nPqRu07Ot6iht9i9KRfYLpDaF2ZuUv5y_+72uP23ZAGysRg@mail.gmail.com>
9 years ago
simple_prompt(password_prompt, password, sizeof(password), false);
have_password = true;
new_pass = true;
26 years ago
}
} while (new_pass);
free(password_prompt);
26 years ago
if (PQstatus(pset.db) == CONNECTION_BAD)
26 years ago
{
fprintf(stderr, "%s: %s", pset.progname, PQerrorMessage(pset.db));
PQfinish(pset.db);
26 years ago
exit(EXIT_BADCONN);
}
setup_cancel_handler();
PQsetNoticeProcessor(pset.db, NoticeProcessor, NULL);
SyncVariables();
if (options.list_dbs)
26 years ago
{
int success;
26 years ago
if (!options.no_psqlrc)
process_psqlrc(argv[0]);
success = listAllDbs(NULL, false);
PQfinish(pset.db);
exit(success ? EXIT_SUCCESS : EXIT_FAILURE);
26 years ago
}
if (options.logfilename)
{
pset.logfile = fopen(options.logfilename, "a");
if (!pset.logfile)
{
fprintf(stderr, _("%s: could not open log file \"%s\": %s\n"),
pset.progname, options.logfilename, strerror(errno));
exit(EXIT_FAILURE);
}
}
if (!options.no_psqlrc)
process_psqlrc(argv[0]);
26 years ago
/*
* If any actions were given by user, process them in the order in which
* they were specified. Note single_txn is only effective in this mode.
*/
if (options.actions.head != NULL)
{
PGresult *res;
SimpleActionListCell *cell;
successResult = EXIT_SUCCESS; /* silence compiler */
if (options.single_txn)
{
if ((res = PSQLexec("BEGIN")) == NULL)
{
if (pset.on_error_stop)
{
successResult = EXIT_USER;
goto error;
}
}
else
PQclear(res);
}
for (cell = options.actions.head; cell; cell = cell->next)
{
if (cell->action == ACT_SINGLE_QUERY)
{
if (pset.echo == PSQL_ECHO_ALL)
puts(cell->val);
successResult = SendQuery(cell->val)
? EXIT_SUCCESS : EXIT_FAILURE;
}
else if (cell->action == ACT_SINGLE_SLASH)
{
PsqlScanState scan_state;
Support \if ... \elif ... \else ... \endif in psql scripting. This patch adds nestable conditional blocks to psql. The control structure feature per se is complete, but the boolean expressions understood by \if and \elif are pretty primitive; basically, after variable substitution and backtick expansion, the result has to be "true" or "false" or one of the other standard spellings of a boolean value. But that's enough for many purposes, since you can always do the heavy lifting on the server side; and we can extend it later. Along the way, pay down some of the technical debt that had built up around psql/command.c: * Refactor exec_command() into a function per command, instead of being a 1500-line monstrosity. This makes the file noticeably longer because of repetitive function header/trailer overhead, but it seems much more readable. * Teach psql_get_variable() and psqlscanslash.l to suppress variable substitution and backtick expansion on the basis of the conditional stack state, thereby allowing removal of the OT_NO_EVAL kluge. * Fix the no-doubt-once-expedient hack of sometimes silently substituting mainloop.c's previous_buf for query_buf when calling HandleSlashCmds. (It's a bit remarkable that commands like \r worked at all with that.) Recall of a previous query is now done explicitly in the slash commands where that should happen. Corey Huinker, reviewed by Fabien Coelho, further hacking by me Discussion: https://postgr.es/m/CADkLM=c94OSRTnat=LX0ivNq4pxDNeoomFfYvBKM5N_xfmLtAA@mail.gmail.com
9 years ago
ConditionalStack cond_stack;
if (pset.echo == PSQL_ECHO_ALL)
puts(cell->val);
scan_state = psql_scan_create(&psqlscan_callbacks);
psql_scan_setup(scan_state,
cell->val, strlen(cell->val),
pset.encoding, standard_strings());
Support \if ... \elif ... \else ... \endif in psql scripting. This patch adds nestable conditional blocks to psql. The control structure feature per se is complete, but the boolean expressions understood by \if and \elif are pretty primitive; basically, after variable substitution and backtick expansion, the result has to be "true" or "false" or one of the other standard spellings of a boolean value. But that's enough for many purposes, since you can always do the heavy lifting on the server side; and we can extend it later. Along the way, pay down some of the technical debt that had built up around psql/command.c: * Refactor exec_command() into a function per command, instead of being a 1500-line monstrosity. This makes the file noticeably longer because of repetitive function header/trailer overhead, but it seems much more readable. * Teach psql_get_variable() and psqlscanslash.l to suppress variable substitution and backtick expansion on the basis of the conditional stack state, thereby allowing removal of the OT_NO_EVAL kluge. * Fix the no-doubt-once-expedient hack of sometimes silently substituting mainloop.c's previous_buf for query_buf when calling HandleSlashCmds. (It's a bit remarkable that commands like \r worked at all with that.) Recall of a previous query is now done explicitly in the slash commands where that should happen. Corey Huinker, reviewed by Fabien Coelho, further hacking by me Discussion: https://postgr.es/m/CADkLM=c94OSRTnat=LX0ivNq4pxDNeoomFfYvBKM5N_xfmLtAA@mail.gmail.com
9 years ago
cond_stack = conditional_stack_create();
psql_scan_set_passthrough(scan_state, (void *) cond_stack);
Support \if ... \elif ... \else ... \endif in psql scripting. This patch adds nestable conditional blocks to psql. The control structure feature per se is complete, but the boolean expressions understood by \if and \elif are pretty primitive; basically, after variable substitution and backtick expansion, the result has to be "true" or "false" or one of the other standard spellings of a boolean value. But that's enough for many purposes, since you can always do the heavy lifting on the server side; and we can extend it later. Along the way, pay down some of the technical debt that had built up around psql/command.c: * Refactor exec_command() into a function per command, instead of being a 1500-line monstrosity. This makes the file noticeably longer because of repetitive function header/trailer overhead, but it seems much more readable. * Teach psql_get_variable() and psqlscanslash.l to suppress variable substitution and backtick expansion on the basis of the conditional stack state, thereby allowing removal of the OT_NO_EVAL kluge. * Fix the no-doubt-once-expedient hack of sometimes silently substituting mainloop.c's previous_buf for query_buf when calling HandleSlashCmds. (It's a bit remarkable that commands like \r worked at all with that.) Recall of a previous query is now done explicitly in the slash commands where that should happen. Corey Huinker, reviewed by Fabien Coelho, further hacking by me Discussion: https://postgr.es/m/CADkLM=c94OSRTnat=LX0ivNq4pxDNeoomFfYvBKM5N_xfmLtAA@mail.gmail.com
9 years ago
successResult = HandleSlashCmds(scan_state,
cond_stack,
NULL,
NULL) != PSQL_CMD_ERROR
? EXIT_SUCCESS : EXIT_FAILURE;
psql_scan_destroy(scan_state);
Support \if ... \elif ... \else ... \endif in psql scripting. This patch adds nestable conditional blocks to psql. The control structure feature per se is complete, but the boolean expressions understood by \if and \elif are pretty primitive; basically, after variable substitution and backtick expansion, the result has to be "true" or "false" or one of the other standard spellings of a boolean value. But that's enough for many purposes, since you can always do the heavy lifting on the server side; and we can extend it later. Along the way, pay down some of the technical debt that had built up around psql/command.c: * Refactor exec_command() into a function per command, instead of being a 1500-line monstrosity. This makes the file noticeably longer because of repetitive function header/trailer overhead, but it seems much more readable. * Teach psql_get_variable() and psqlscanslash.l to suppress variable substitution and backtick expansion on the basis of the conditional stack state, thereby allowing removal of the OT_NO_EVAL kluge. * Fix the no-doubt-once-expedient hack of sometimes silently substituting mainloop.c's previous_buf for query_buf when calling HandleSlashCmds. (It's a bit remarkable that commands like \r worked at all with that.) Recall of a previous query is now done explicitly in the slash commands where that should happen. Corey Huinker, reviewed by Fabien Coelho, further hacking by me Discussion: https://postgr.es/m/CADkLM=c94OSRTnat=LX0ivNq4pxDNeoomFfYvBKM5N_xfmLtAA@mail.gmail.com
9 years ago
conditional_stack_destroy(cond_stack);
}
else if (cell->action == ACT_FILE)
{
successResult = process_file(cell->val, false);
}
else
{
/* should never come here */
Assert(false);
}
if (successResult != EXIT_SUCCESS && pset.on_error_stop)
break;
}
if (options.single_txn)
{
if ((res = PSQLexec("COMMIT")) == NULL)
{
if (pset.on_error_stop)
{
successResult = EXIT_USER;
goto error;
}
}
else
PQclear(res);
}
error:
;
}
/*
* or otherwise enter interactive main loop
*/
26 years ago
else
{
connection_warnings(true);
if (!pset.quiet)
printf(_("Type \"help\" for help.\n\n"));
initializeInput(options.no_readline ? 0 : 1);
successResult = MainLoop(stdin);
}
26 years ago
/* clean up */
if (pset.logfile)
fclose(pset.logfile);
PQfinish(pset.db);
setQFout(NULL);
26 years ago
return successResult;
}
/*
* Parse command line options
*/
static void
parse_psql_options(int argc, char *argv[], struct adhoc_opts * options)
{
static struct option long_options[] =
{
{"echo-all", no_argument, NULL, 'a'},
26 years ago
{"no-align", no_argument, NULL, 'A'},
{"command", required_argument, NULL, 'c'},
{"dbname", required_argument, NULL, 'd'},
{"echo-queries", no_argument, NULL, 'e'},
{"echo-errors", no_argument, NULL, 'b'},
{"echo-hidden", no_argument, NULL, 'E'},
26 years ago
{"file", required_argument, NULL, 'f'},
{"field-separator", required_argument, NULL, 'F'},
{"field-separator-zero", no_argument, NULL, 'z'},
26 years ago
{"host", required_argument, NULL, 'h'},
{"html", no_argument, NULL, 'H'},
{"list", no_argument, NULL, 'l'},
{"log-file", required_argument, NULL, 'L'},
{"no-readline", no_argument, NULL, 'n'},
{"single-transaction", no_argument, NULL, '1'},
{"output", required_argument, NULL, 'o'},
26 years ago
{"port", required_argument, NULL, 'p'},
{"pset", required_argument, NULL, 'P'},
{"quiet", no_argument, NULL, 'q'},
{"record-separator", required_argument, NULL, 'R'},
{"record-separator-zero", no_argument, NULL, '0'},
26 years ago
{"single-step", no_argument, NULL, 's'},
{"single-line", no_argument, NULL, 'S'},
{"tuples-only", no_argument, NULL, 't'},
{"table-attr", required_argument, NULL, 'T'},
{"username", required_argument, NULL, 'U'},
{"set", required_argument, NULL, 'v'},
{"variable", required_argument, NULL, 'v'},
{"version", no_argument, NULL, 'V'},
{"no-password", no_argument, NULL, 'w'},
26 years ago
{"password", no_argument, NULL, 'W'},
{"expanded", no_argument, NULL, 'x'},
{"no-psqlrc", no_argument, NULL, 'X'},
{"help", optional_argument, NULL, 1},
{NULL, 0, NULL, 0}
26 years ago
};
int optindex;
int c;
memset(options, 0, sizeof *options);
while ((c = getopt_long(argc, argv, "aAbc:d:eEf:F:h:HlL:no:p:P:qR:sStT:U:v:VwWxXz?01",
long_options, &optindex)) != -1)
{
26 years ago
switch (c)
{
case 'a':
SetVariable(pset.vars, "ECHO", "all");
break;
26 years ago
case 'A':
pset.popt.topt.format = PRINT_UNALIGNED;
26 years ago
break;
case 'b':
SetVariable(pset.vars, "ECHO", "errors");
break;
26 years ago
case 'c':
if (optarg[0] == '\\')
simple_action_list_append(&options->actions,
ACT_SINGLE_SLASH,
optarg + 1);
26 years ago
else
simple_action_list_append(&options->actions,
ACT_SINGLE_QUERY,
optarg);
26 years ago
break;
case 'd':
options->dbname = pg_strdup(optarg);
26 years ago
break;
case 'e':
SetVariable(pset.vars, "ECHO", "queries");
26 years ago
break;
case 'E':
SetVariableBool(pset.vars, "ECHO_HIDDEN");
26 years ago
break;
case 'f':
simple_action_list_append(&options->actions,
ACT_FILE,
optarg);
26 years ago
break;
case 'F':
pset.popt.topt.fieldSep.separator = pg_strdup(optarg);
pset.popt.topt.fieldSep.separator_zero = false;
26 years ago
break;
case 'h':
options->host = pg_strdup(optarg);
26 years ago
break;
case 'H':
pset.popt.topt.format = PRINT_HTML;
26 years ago
break;
case 'l':
options->list_dbs = true;
26 years ago
break;
case 'L':
options->logfilename = pg_strdup(optarg);
break;
26 years ago
case 'n':
options->no_readline = true;
break;
case 'o':
if (!setQFout(optarg))
exit(EXIT_FAILURE);
26 years ago
break;
case 'p':
options->port = pg_strdup(optarg);
26 years ago
break;
case 'P':
{
char *value;
char *equal_loc;
bool result;
value = pg_strdup(optarg);
26 years ago
equal_loc = strchr(value, '=');
if (!equal_loc)
result = do_pset(value, NULL, &pset.popt, true);
26 years ago
else
{
*equal_loc = '\0';
result = do_pset(value, equal_loc + 1, &pset.popt, true);
26 years ago
}
if (!result)
{
fprintf(stderr, _("%s: could not set printing parameter \"%s\"\n"), pset.progname, value);
26 years ago
exit(EXIT_FAILURE);
}
free(value);
break;
}
case 'q':
SetVariableBool(pset.vars, "QUIET");
26 years ago
break;
case 'R':
pset.popt.topt.recordSep.separator = pg_strdup(optarg);
pset.popt.topt.recordSep.separator_zero = false;
break;
26 years ago
case 's':
SetVariableBool(pset.vars, "SINGLESTEP");
26 years ago
break;
case 'S':
SetVariableBool(pset.vars, "SINGLELINE");
26 years ago
break;
case 't':
pset.popt.topt.tuples_only = true;
26 years ago
break;
case 'T':
pset.popt.topt.tableAttr = pg_strdup(optarg);
26 years ago
break;
case 'U':
options->username = pg_strdup(optarg);
26 years ago
break;
case 'v':
{
char *value;
char *equal_loc;
value = pg_strdup(optarg);
26 years ago
equal_loc = strchr(value, '=');
if (!equal_loc)
{
if (!DeleteVariable(pset.vars, value))
Improve psql's behavior for \set and \unset of its control variables. This commit improves on the results of commit 511ae628f in two ways: 1. It restores the historical behavior that "\set FOO" is interpreted as setting FOO to "on", if FOO is a boolean control variable. We already found one test script that was expecting that behavior, and the psql documentation certainly does nothing to discourage people from assuming that would work, since it often says just "if FOO is set" when describing the effects of a boolean variable. However, now this case will result in actually setting FOO to "on", not an empty string. 2. It arranges for an "\unset" of a control variable to set the value back to its default value, rather than becoming apparently undefined. The control variables are also initialized that way at psql startup. In combination, these things guarantee that a control variable always has a displayable value that reflects what psql is actually doing. That is a pretty substantial usability improvement. The implementation involves adding a second type of variable hook function that is able to replace a proposed new value (including NULL) with another one. We could alternatively have complicated the API of the assign hook, but this way seems better since many variables can share the same substitution hook function. Also document the actual behavior of these variables more fully, including covering assorted behaviors that were there before but never documented. This patch also includes some minor cleanup that should have been in 511ae628f but was missed. Patch by me, but it owes a lot to discussions with Daniel Vérité. Discussion: https://postgr.es/m/9572.1485821620@sss.pgh.pa.us
9 years ago
exit(EXIT_FAILURE); /* error already printed */
26 years ago
}
else
{
*equal_loc = '\0';
if (!SetVariable(pset.vars, value, equal_loc + 1))
Improve psql's behavior for \set and \unset of its control variables. This commit improves on the results of commit 511ae628f in two ways: 1. It restores the historical behavior that "\set FOO" is interpreted as setting FOO to "on", if FOO is a boolean control variable. We already found one test script that was expecting that behavior, and the psql documentation certainly does nothing to discourage people from assuming that would work, since it often says just "if FOO is set" when describing the effects of a boolean variable. However, now this case will result in actually setting FOO to "on", not an empty string. 2. It arranges for an "\unset" of a control variable to set the value back to its default value, rather than becoming apparently undefined. The control variables are also initialized that way at psql startup. In combination, these things guarantee that a control variable always has a displayable value that reflects what psql is actually doing. That is a pretty substantial usability improvement. The implementation involves adding a second type of variable hook function that is able to replace a proposed new value (including NULL) with another one. We could alternatively have complicated the API of the assign hook, but this way seems better since many variables can share the same substitution hook function. Also document the actual behavior of these variables more fully, including covering assorted behaviors that were there before but never documented. This patch also includes some minor cleanup that should have been in 511ae628f but was missed. Patch by me, but it owes a lot to discussions with Daniel Vérité. Discussion: https://postgr.es/m/9572.1485821620@sss.pgh.pa.us
9 years ago
exit(EXIT_FAILURE); /* error already printed */
26 years ago
}
free(value);
break;
}
case 'V':
showVersion();
exit(EXIT_SUCCESS);
case 'w':
pset.getPassword = TRI_NO;
break;
26 years ago
case 'W':
pset.getPassword = TRI_YES;
26 years ago
break;
case 'x':
pset.popt.topt.expanded = true;
break;
case 'X':
options->no_psqlrc = true;
break;
case 'z':
pset.popt.topt.fieldSep.separator_zero = true;
break;
case '0':
pset.popt.topt.recordSep.separator_zero = true;
break;
case '1':
options->single_txn = true;
break;
26 years ago
case '?':
/* Actual help option given */
if (strcmp(argv[optind - 1], "-?") == 0)
{
usage(NOPAGER);
exit(EXIT_SUCCESS);
}
/* unknown option reported by getopt */
else
goto unknown_option;
break;
case 1:
{
if (!optarg || strcmp(optarg, "options") == 0)
usage(NOPAGER);
else if (optarg && strcmp(optarg, "commands") == 0)
slashUsage(NOPAGER);
else if (optarg && strcmp(optarg, "variables") == 0)
helpVariables(NOPAGER);
else
goto unknown_option;
exit(EXIT_SUCCESS);
}
26 years ago
break;
default:
unknown_option:
fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
pset.progname);
exit(EXIT_FAILURE);
26 years ago
break;
}
}
26 years ago
/*
* if we still have arguments, use it as the database name and username
26 years ago
*/
while (argc - optind >= 1)
{
if (!options->dbname)
options->dbname = argv[optind];
else if (!options->username)
options->username = argv[optind];
else if (!pset.quiet)
fprintf(stderr, _("%s: warning: extra command-line argument \"%s\" ignored\n"),
pset.progname, argv[optind]);
26 years ago
optind++;
}
}
/*
* Append a new item to the end of the SimpleActionList.
* Note that "val" is copied if it's not NULL.
*/
static void
simple_action_list_append(SimpleActionList *list,
enum _actions action, const char *val)
{
SimpleActionListCell *cell;
cell = (SimpleActionListCell *) pg_malloc(sizeof(SimpleActionListCell));
cell->next = NULL;
cell->action = action;
if (val)
cell->val = pg_strdup(val);
else
cell->val = NULL;
if (list->tail)
list->tail->next = cell;
else
list->head = cell;
list->tail = cell;
}
/*
* Load .psqlrc file, if found.
*/
static void
process_psqlrc(char *argv0)
{
char home[MAXPGPATH];
char rc_file[MAXPGPATH];
char my_exec_path[MAXPGPATH];
char etc_path[MAXPGPATH];
char *envrc = getenv("PSQLRC");
if (find_my_exec(argv0, my_exec_path) < 0)
{
fprintf(stderr, _("%s: could not find own program executable\n"), argv0);
exit(EXIT_FAILURE);
}
get_etc_path(my_exec_path, etc_path);
snprintf(rc_file, MAXPGPATH, "%s/%s", etc_path, SYSPSQLRC);
process_psqlrc_file(rc_file);
if (envrc != NULL && strlen(envrc) > 0)
{
/* might need to free() this */
char *envrc_alloc = pstrdup(envrc);
expand_tilde(&envrc_alloc);
process_psqlrc_file(envrc_alloc);
}
else if (get_home_path(home))
{
snprintf(rc_file, MAXPGPATH, "%s/%s", home, PSQLRC);
process_psqlrc_file(rc_file);
}
}
static void
process_psqlrc_file(char *filename)
{
char *psqlrc_minor,
*psqlrc_major;
#if defined(WIN32) && (!defined(__MINGW32__))
#define R_OK 4
#endif
psqlrc_minor = psprintf("%s-%s", filename, PG_VERSION);
psqlrc_major = psprintf("%s-%s", filename, PG_MAJORVERSION);
/* check for minor version first, then major, then no version */
if (access(psqlrc_minor, R_OK) == 0)
(void) process_file(psqlrc_minor, false);
else if (access(psqlrc_major, R_OK) == 0)
(void) process_file(psqlrc_major, false);
else if (access(filename, R_OK) == 0)
(void) process_file(filename, false);
free(psqlrc_minor);
free(psqlrc_major);
}
/* showVersion
*
* This output format is intended to match GNU standards.
*/
static void
showVersion(void)
{
puts("psql (PostgreSQL) " PG_VERSION);
}
/*
Improve psql's behavior for \set and \unset of its control variables. This commit improves on the results of commit 511ae628f in two ways: 1. It restores the historical behavior that "\set FOO" is interpreted as setting FOO to "on", if FOO is a boolean control variable. We already found one test script that was expecting that behavior, and the psql documentation certainly does nothing to discourage people from assuming that would work, since it often says just "if FOO is set" when describing the effects of a boolean variable. However, now this case will result in actually setting FOO to "on", not an empty string. 2. It arranges for an "\unset" of a control variable to set the value back to its default value, rather than becoming apparently undefined. The control variables are also initialized that way at psql startup. In combination, these things guarantee that a control variable always has a displayable value that reflects what psql is actually doing. That is a pretty substantial usability improvement. The implementation involves adding a second type of variable hook function that is able to replace a proposed new value (including NULL) with another one. We could alternatively have complicated the API of the assign hook, but this way seems better since many variables can share the same substitution hook function. Also document the actual behavior of these variables more fully, including covering assorted behaviors that were there before but never documented. This patch also includes some minor cleanup that should have been in 511ae628f but was missed. Patch by me, but it owes a lot to discussions with Daniel Vérité. Discussion: https://postgr.es/m/9572.1485821620@sss.pgh.pa.us
9 years ago
* Substitute hooks and assign hooks for psql variables.
*
* This isn't an amazingly good place for them, but neither is anywhere else.
Clean up psql's behavior for a few more control variables. Modify FETCH_COUNT to always have a defined value, like other control variables, mainly so it will always appear in "\set" output. Add hooks to force HISTSIZE to be defined and require it to have an integer value. (I don't see any point in allowing it to be set to non-integral values.) Add hooks to force IGNOREEOF to be defined and require it to have an integer value. Unlike the other cases, here we're trying to be bug-compatible with a rather bogus externally-defined behavior, so I think we need to continue to allow "\set IGNOREEOF whatever". Fix it so that the substitution hook silently replace non-numeric values with "10", so that the stored value always reflects what we're really doing. Add a dummy assign hook for HISTFILE, just so it's always in variables.c's list. We can't require it to be defined always, because that would break the interaction with the PSQL_HISTORY environment variable, so there isn't any change in visible behavior here. Remove tab-complete.c's private list of known variable names, since that's really a maintenance nuisance. Given the preceding changes, there are no control variables it won't show anyway. This does mean that if for some reason you've unset one of the status variables (DBNAME, HOST, etc), that variable would not appear in tab completion for \set. But I think that's fine, for at least two reasons: we shouldn't be encouraging people to use those variables as regular variables, and if someone does do so anyway, why shouldn't it act just like a regular variable? Remove ugly and no-longer-used-anywhere GetVariableNum(). In general, future additions of integer-valued control variables should follow the paradigm of adding an assign hook using ParseVariableNum(), so there's no reason to expect we'd need this again later. Discussion: https://postgr.es/m/17516.1485973973@sss.pgh.pa.us
9 years ago
*
* 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.
*/
Improve psql's behavior for \set and \unset of its control variables. This commit improves on the results of commit 511ae628f in two ways: 1. It restores the historical behavior that "\set FOO" is interpreted as setting FOO to "on", if FOO is a boolean control variable. We already found one test script that was expecting that behavior, and the psql documentation certainly does nothing to discourage people from assuming that would work, since it often says just "if FOO is set" when describing the effects of a boolean variable. However, now this case will result in actually setting FOO to "on", not an empty string. 2. It arranges for an "\unset" of a control variable to set the value back to its default value, rather than becoming apparently undefined. The control variables are also initialized that way at psql startup. In combination, these things guarantee that a control variable always has a displayable value that reflects what psql is actually doing. That is a pretty substantial usability improvement. The implementation involves adding a second type of variable hook function that is able to replace a proposed new value (including NULL) with another one. We could alternatively have complicated the API of the assign hook, but this way seems better since many variables can share the same substitution hook function. Also document the actual behavior of these variables more fully, including covering assorted behaviors that were there before but never documented. This patch also includes some minor cleanup that should have been in 511ae628f but was missed. Patch by me, but it owes a lot to discussions with Daniel Vérité. Discussion: https://postgr.es/m/9572.1485821620@sss.pgh.pa.us
9 years ago
static char *
bool_substitute_hook(char *newval)
{
if (newval == NULL)
{
/* "\unset FOO" becomes "\set FOO off" */
newval = pg_strdup("off");
}
else if (newval[0] == '\0')
{
/* "\set FOO" becomes "\set FOO on" */
pg_free(newval);
newval = pg_strdup("on");
}
return newval;
}
static bool
autocommit_hook(const char *newval)
{
return ParseVariableBool(newval, "AUTOCOMMIT", &pset.autocommit);
}
static bool
on_error_stop_hook(const char *newval)
{
return ParseVariableBool(newval, "ON_ERROR_STOP", &pset.on_error_stop);
}
static bool
quiet_hook(const char *newval)
{
return ParseVariableBool(newval, "QUIET", &pset.quiet);
}
static bool
singleline_hook(const char *newval)
{
return ParseVariableBool(newval, "SINGLELINE", &pset.singleline);
}
static bool
singlestep_hook(const char *newval)
{
return ParseVariableBool(newval, "SINGLESTEP", &pset.singlestep);
}
Clean up psql's behavior for a few more control variables. Modify FETCH_COUNT to always have a defined value, like other control variables, mainly so it will always appear in "\set" output. Add hooks to force HISTSIZE to be defined and require it to have an integer value. (I don't see any point in allowing it to be set to non-integral values.) Add hooks to force IGNOREEOF to be defined and require it to have an integer value. Unlike the other cases, here we're trying to be bug-compatible with a rather bogus externally-defined behavior, so I think we need to continue to allow "\set IGNOREEOF whatever". Fix it so that the substitution hook silently replace non-numeric values with "10", so that the stored value always reflects what we're really doing. Add a dummy assign hook for HISTFILE, just so it's always in variables.c's list. We can't require it to be defined always, because that would break the interaction with the PSQL_HISTORY environment variable, so there isn't any change in visible behavior here. Remove tab-complete.c's private list of known variable names, since that's really a maintenance nuisance. Given the preceding changes, there are no control variables it won't show anyway. This does mean that if for some reason you've unset one of the status variables (DBNAME, HOST, etc), that variable would not appear in tab completion for \set. But I think that's fine, for at least two reasons: we shouldn't be encouraging people to use those variables as regular variables, and if someone does do so anyway, why shouldn't it act just like a regular variable? Remove ugly and no-longer-used-anywhere GetVariableNum(). In general, future additions of integer-valued control variables should follow the paradigm of adding an assign hook using ParseVariableNum(), so there's no reason to expect we'd need this again later. Discussion: https://postgr.es/m/17516.1485973973@sss.pgh.pa.us
9 years ago
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)
{
Clean up psql's behavior for a few more control variables. Modify FETCH_COUNT to always have a defined value, like other control variables, mainly so it will always appear in "\set" output. Add hooks to force HISTSIZE to be defined and require it to have an integer value. (I don't see any point in allowing it to be set to non-integral values.) Add hooks to force IGNOREEOF to be defined and require it to have an integer value. Unlike the other cases, here we're trying to be bug-compatible with a rather bogus externally-defined behavior, so I think we need to continue to allow "\set IGNOREEOF whatever". Fix it so that the substitution hook silently replace non-numeric values with "10", so that the stored value always reflects what we're really doing. Add a dummy assign hook for HISTFILE, just so it's always in variables.c's list. We can't require it to be defined always, because that would break the interaction with the PSQL_HISTORY environment variable, so there isn't any change in visible behavior here. Remove tab-complete.c's private list of known variable names, since that's really a maintenance nuisance. Given the preceding changes, there are no control variables it won't show anyway. This does mean that if for some reason you've unset one of the status variables (DBNAME, HOST, etc), that variable would not appear in tab completion for \set. But I think that's fine, for at least two reasons: we shouldn't be encouraging people to use those variables as regular variables, and if someone does do so anyway, why shouldn't it act just like a regular variable? Remove ugly and no-longer-used-anywhere GetVariableNum(). In general, future additions of integer-valued control variables should follow the paradigm of adding an assign hook using ParseVariableNum(), so there's no reason to expect we'd need this again later. Discussion: https://postgr.es/m/17516.1485973973@sss.pgh.pa.us
9 years ago
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;
}
Clean up psql's behavior for a few more control variables. Modify FETCH_COUNT to always have a defined value, like other control variables, mainly so it will always appear in "\set" output. Add hooks to force HISTSIZE to be defined and require it to have an integer value. (I don't see any point in allowing it to be set to non-integral values.) Add hooks to force IGNOREEOF to be defined and require it to have an integer value. Unlike the other cases, here we're trying to be bug-compatible with a rather bogus externally-defined behavior, so I think we need to continue to allow "\set IGNOREEOF whatever". Fix it so that the substitution hook silently replace non-numeric values with "10", so that the stored value always reflects what we're really doing. Add a dummy assign hook for HISTFILE, just so it's always in variables.c's list. We can't require it to be defined always, because that would break the interaction with the PSQL_HISTORY environment variable, so there isn't any change in visible behavior here. Remove tab-complete.c's private list of known variable names, since that's really a maintenance nuisance. Given the preceding changes, there are no control variables it won't show anyway. This does mean that if for some reason you've unset one of the status variables (DBNAME, HOST, etc), that variable would not appear in tab completion for \set. But I think that's fine, for at least two reasons: we shouldn't be encouraging people to use those variables as regular variables, and if someone does do so anyway, why shouldn't it act just like a regular variable? Remove ugly and no-longer-used-anywhere GetVariableNum(). In general, future additions of integer-valued control variables should follow the paradigm of adding an assign hook using ParseVariableNum(), so there's no reason to expect we'd need this again later. Discussion: https://postgr.es/m/17516.1485973973@sss.pgh.pa.us
9 years ago
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);
}
Improve psql's behavior for \set and \unset of its control variables. This commit improves on the results of commit 511ae628f in two ways: 1. It restores the historical behavior that "\set FOO" is interpreted as setting FOO to "on", if FOO is a boolean control variable. We already found one test script that was expecting that behavior, and the psql documentation certainly does nothing to discourage people from assuming that would work, since it often says just "if FOO is set" when describing the effects of a boolean variable. However, now this case will result in actually setting FOO to "on", not an empty string. 2. It arranges for an "\unset" of a control variable to set the value back to its default value, rather than becoming apparently undefined. The control variables are also initialized that way at psql startup. In combination, these things guarantee that a control variable always has a displayable value that reflects what psql is actually doing. That is a pretty substantial usability improvement. The implementation involves adding a second type of variable hook function that is able to replace a proposed new value (including NULL) with another one. We could alternatively have complicated the API of the assign hook, but this way seems better since many variables can share the same substitution hook function. Also document the actual behavior of these variables more fully, including covering assorted behaviors that were there before but never documented. This patch also includes some minor cleanup that should have been in 511ae628f but was missed. Patch by me, but it owes a lot to discussions with Daniel Vérité. Discussion: https://postgr.es/m/9572.1485821620@sss.pgh.pa.us
9 years ago
static char *
echo_substitute_hook(char *newval)
{
if (newval == NULL)
newval = pg_strdup("none");
return newval;
}
static bool
echo_hook(const char *newval)
{
Improve psql's behavior for \set and \unset of its control variables. This commit improves on the results of commit 511ae628f in two ways: 1. It restores the historical behavior that "\set FOO" is interpreted as setting FOO to "on", if FOO is a boolean control variable. We already found one test script that was expecting that behavior, and the psql documentation certainly does nothing to discourage people from assuming that would work, since it often says just "if FOO is set" when describing the effects of a boolean variable. However, now this case will result in actually setting FOO to "on", not an empty string. 2. It arranges for an "\unset" of a control variable to set the value back to its default value, rather than becoming apparently undefined. The control variables are also initialized that way at psql startup. In combination, these things guarantee that a control variable always has a displayable value that reflects what psql is actually doing. That is a pretty substantial usability improvement. The implementation involves adding a second type of variable hook function that is able to replace a proposed new value (including NULL) with another one. We could alternatively have complicated the API of the assign hook, but this way seems better since many variables can share the same substitution hook function. Also document the actual behavior of these variables more fully, including covering assorted behaviors that were there before but never documented. This patch also includes some minor cleanup that should have been in 511ae628f but was missed. Patch by me, but it owes a lot to discussions with Daniel Vérité. Discussion: https://postgr.es/m/9572.1485821620@sss.pgh.pa.us
9 years ago
Assert(newval != NULL); /* else substitute hook messed up */
if (pg_strcasecmp(newval, "queries") == 0)
pset.echo = PSQL_ECHO_QUERIES;
else if (pg_strcasecmp(newval, "errors") == 0)
pset.echo = PSQL_ECHO_ERRORS;
else if (pg_strcasecmp(newval, "all") == 0)
pset.echo = PSQL_ECHO_ALL;
else if (pg_strcasecmp(newval, "none") == 0)
pset.echo = PSQL_ECHO_NONE;
else
{
PsqlVarEnumError("ECHO", newval, "none, errors, queries, all");
return false;
}
return true;
}
static bool
echo_hidden_hook(const char *newval)
{
Improve psql's behavior for \set and \unset of its control variables. This commit improves on the results of commit 511ae628f in two ways: 1. It restores the historical behavior that "\set FOO" is interpreted as setting FOO to "on", if FOO is a boolean control variable. We already found one test script that was expecting that behavior, and the psql documentation certainly does nothing to discourage people from assuming that would work, since it often says just "if FOO is set" when describing the effects of a boolean variable. However, now this case will result in actually setting FOO to "on", not an empty string. 2. It arranges for an "\unset" of a control variable to set the value back to its default value, rather than becoming apparently undefined. The control variables are also initialized that way at psql startup. In combination, these things guarantee that a control variable always has a displayable value that reflects what psql is actually doing. That is a pretty substantial usability improvement. The implementation involves adding a second type of variable hook function that is able to replace a proposed new value (including NULL) with another one. We could alternatively have complicated the API of the assign hook, but this way seems better since many variables can share the same substitution hook function. Also document the actual behavior of these variables more fully, including covering assorted behaviors that were there before but never documented. This patch also includes some minor cleanup that should have been in 511ae628f but was missed. Patch by me, but it owes a lot to discussions with Daniel Vérité. Discussion: https://postgr.es/m/9572.1485821620@sss.pgh.pa.us
9 years ago
Assert(newval != NULL); /* else substitute hook messed up */
if (pg_strcasecmp(newval, "noexec") == 0)
pset.echo_hidden = PSQL_ECHO_HIDDEN_NOEXEC;
else
{
bool on_off;
if (ParseVariableBool(newval, NULL, &on_off))
pset.echo_hidden = on_off ? PSQL_ECHO_HIDDEN_ON : PSQL_ECHO_HIDDEN_OFF;
else
{
PsqlVarEnumError("ECHO_HIDDEN", newval, "on, off, noexec");
return false;
}
}
return true;
}
static bool
on_error_rollback_hook(const char *newval)
{
Improve psql's behavior for \set and \unset of its control variables. This commit improves on the results of commit 511ae628f in two ways: 1. It restores the historical behavior that "\set FOO" is interpreted as setting FOO to "on", if FOO is a boolean control variable. We already found one test script that was expecting that behavior, and the psql documentation certainly does nothing to discourage people from assuming that would work, since it often says just "if FOO is set" when describing the effects of a boolean variable. However, now this case will result in actually setting FOO to "on", not an empty string. 2. It arranges for an "\unset" of a control variable to set the value back to its default value, rather than becoming apparently undefined. The control variables are also initialized that way at psql startup. In combination, these things guarantee that a control variable always has a displayable value that reflects what psql is actually doing. That is a pretty substantial usability improvement. The implementation involves adding a second type of variable hook function that is able to replace a proposed new value (including NULL) with another one. We could alternatively have complicated the API of the assign hook, but this way seems better since many variables can share the same substitution hook function. Also document the actual behavior of these variables more fully, including covering assorted behaviors that were there before but never documented. This patch also includes some minor cleanup that should have been in 511ae628f but was missed. Patch by me, but it owes a lot to discussions with Daniel Vérité. Discussion: https://postgr.es/m/9572.1485821620@sss.pgh.pa.us
9 years ago
Assert(newval != NULL); /* else substitute hook messed up */
if (pg_strcasecmp(newval, "interactive") == 0)
pset.on_error_rollback = PSQL_ERROR_ROLLBACK_INTERACTIVE;
else
{
bool on_off;
if (ParseVariableBool(newval, NULL, &on_off))
pset.on_error_rollback = on_off ? PSQL_ERROR_ROLLBACK_ON : PSQL_ERROR_ROLLBACK_OFF;
else
{
PsqlVarEnumError("ON_ERROR_ROLLBACK", newval, "on, off, interactive");
return false;
}
}
return true;
}
Improve psql's behavior for \set and \unset of its control variables. This commit improves on the results of commit 511ae628f in two ways: 1. It restores the historical behavior that "\set FOO" is interpreted as setting FOO to "on", if FOO is a boolean control variable. We already found one test script that was expecting that behavior, and the psql documentation certainly does nothing to discourage people from assuming that would work, since it often says just "if FOO is set" when describing the effects of a boolean variable. However, now this case will result in actually setting FOO to "on", not an empty string. 2. It arranges for an "\unset" of a control variable to set the value back to its default value, rather than becoming apparently undefined. The control variables are also initialized that way at psql startup. In combination, these things guarantee that a control variable always has a displayable value that reflects what psql is actually doing. That is a pretty substantial usability improvement. The implementation involves adding a second type of variable hook function that is able to replace a proposed new value (including NULL) with another one. We could alternatively have complicated the API of the assign hook, but this way seems better since many variables can share the same substitution hook function. Also document the actual behavior of these variables more fully, including covering assorted behaviors that were there before but never documented. This patch also includes some minor cleanup that should have been in 511ae628f but was missed. Patch by me, but it owes a lot to discussions with Daniel Vérité. Discussion: https://postgr.es/m/9572.1485821620@sss.pgh.pa.us
9 years ago
static char *
comp_keyword_case_substitute_hook(char *newval)
{
if (newval == NULL)
newval = pg_strdup("preserve-upper");
return newval;
}
static bool
comp_keyword_case_hook(const char *newval)
{
Improve psql's behavior for \set and \unset of its control variables. This commit improves on the results of commit 511ae628f in two ways: 1. It restores the historical behavior that "\set FOO" is interpreted as setting FOO to "on", if FOO is a boolean control variable. We already found one test script that was expecting that behavior, and the psql documentation certainly does nothing to discourage people from assuming that would work, since it often says just "if FOO is set" when describing the effects of a boolean variable. However, now this case will result in actually setting FOO to "on", not an empty string. 2. It arranges for an "\unset" of a control variable to set the value back to its default value, rather than becoming apparently undefined. The control variables are also initialized that way at psql startup. In combination, these things guarantee that a control variable always has a displayable value that reflects what psql is actually doing. That is a pretty substantial usability improvement. The implementation involves adding a second type of variable hook function that is able to replace a proposed new value (including NULL) with another one. We could alternatively have complicated the API of the assign hook, but this way seems better since many variables can share the same substitution hook function. Also document the actual behavior of these variables more fully, including covering assorted behaviors that were there before but never documented. This patch also includes some minor cleanup that should have been in 511ae628f but was missed. Patch by me, but it owes a lot to discussions with Daniel Vérité. Discussion: https://postgr.es/m/9572.1485821620@sss.pgh.pa.us
9 years ago
Assert(newval != NULL); /* else substitute hook messed up */
if (pg_strcasecmp(newval, "preserve-upper") == 0)
pset.comp_case = PSQL_COMP_CASE_PRESERVE_UPPER;
else if (pg_strcasecmp(newval, "preserve-lower") == 0)
pset.comp_case = PSQL_COMP_CASE_PRESERVE_LOWER;
else if (pg_strcasecmp(newval, "upper") == 0)
pset.comp_case = PSQL_COMP_CASE_UPPER;
else if (pg_strcasecmp(newval, "lower") == 0)
pset.comp_case = PSQL_COMP_CASE_LOWER;
else
{
PsqlVarEnumError("COMP_KEYWORD_CASE", newval,
"lower, upper, preserve-lower, preserve-upper");
return false;
}
return true;
}
Improve psql's behavior for \set and \unset of its control variables. This commit improves on the results of commit 511ae628f in two ways: 1. It restores the historical behavior that "\set FOO" is interpreted as setting FOO to "on", if FOO is a boolean control variable. We already found one test script that was expecting that behavior, and the psql documentation certainly does nothing to discourage people from assuming that would work, since it often says just "if FOO is set" when describing the effects of a boolean variable. However, now this case will result in actually setting FOO to "on", not an empty string. 2. It arranges for an "\unset" of a control variable to set the value back to its default value, rather than becoming apparently undefined. The control variables are also initialized that way at psql startup. In combination, these things guarantee that a control variable always has a displayable value that reflects what psql is actually doing. That is a pretty substantial usability improvement. The implementation involves adding a second type of variable hook function that is able to replace a proposed new value (including NULL) with another one. We could alternatively have complicated the API of the assign hook, but this way seems better since many variables can share the same substitution hook function. Also document the actual behavior of these variables more fully, including covering assorted behaviors that were there before but never documented. This patch also includes some minor cleanup that should have been in 511ae628f but was missed. Patch by me, but it owes a lot to discussions with Daniel Vérité. Discussion: https://postgr.es/m/9572.1485821620@sss.pgh.pa.us
9 years ago
static char *
histcontrol_substitute_hook(char *newval)
{
if (newval == NULL)
newval = pg_strdup("none");
return newval;
}
static bool
histcontrol_hook(const char *newval)
{
Improve psql's behavior for \set and \unset of its control variables. This commit improves on the results of commit 511ae628f in two ways: 1. It restores the historical behavior that "\set FOO" is interpreted as setting FOO to "on", if FOO is a boolean control variable. We already found one test script that was expecting that behavior, and the psql documentation certainly does nothing to discourage people from assuming that would work, since it often says just "if FOO is set" when describing the effects of a boolean variable. However, now this case will result in actually setting FOO to "on", not an empty string. 2. It arranges for an "\unset" of a control variable to set the value back to its default value, rather than becoming apparently undefined. The control variables are also initialized that way at psql startup. In combination, these things guarantee that a control variable always has a displayable value that reflects what psql is actually doing. That is a pretty substantial usability improvement. The implementation involves adding a second type of variable hook function that is able to replace a proposed new value (including NULL) with another one. We could alternatively have complicated the API of the assign hook, but this way seems better since many variables can share the same substitution hook function. Also document the actual behavior of these variables more fully, including covering assorted behaviors that were there before but never documented. This patch also includes some minor cleanup that should have been in 511ae628f but was missed. Patch by me, but it owes a lot to discussions with Daniel Vérité. Discussion: https://postgr.es/m/9572.1485821620@sss.pgh.pa.us
9 years ago
Assert(newval != NULL); /* else substitute hook messed up */
if (pg_strcasecmp(newval, "ignorespace") == 0)
pset.histcontrol = hctl_ignorespace;
else if (pg_strcasecmp(newval, "ignoredups") == 0)
pset.histcontrol = hctl_ignoredups;
else if (pg_strcasecmp(newval, "ignoreboth") == 0)
pset.histcontrol = hctl_ignoreboth;
else if (pg_strcasecmp(newval, "none") == 0)
pset.histcontrol = hctl_none;
else
{
PsqlVarEnumError("HISTCONTROL", newval,
"none, ignorespace, ignoredups, ignoreboth");
return false;
}
return true;
}
static bool
prompt1_hook(const char *newval)
{
pset.prompt1 = newval ? newval : "";
return true;
}
static bool
prompt2_hook(const char *newval)
{
pset.prompt2 = newval ? newval : "";
return true;
}
static bool
prompt3_hook(const char *newval)
{
pset.prompt3 = newval ? newval : "";
return true;
}
Improve psql's behavior for \set and \unset of its control variables. This commit improves on the results of commit 511ae628f in two ways: 1. It restores the historical behavior that "\set FOO" is interpreted as setting FOO to "on", if FOO is a boolean control variable. We already found one test script that was expecting that behavior, and the psql documentation certainly does nothing to discourage people from assuming that would work, since it often says just "if FOO is set" when describing the effects of a boolean variable. However, now this case will result in actually setting FOO to "on", not an empty string. 2. It arranges for an "\unset" of a control variable to set the value back to its default value, rather than becoming apparently undefined. The control variables are also initialized that way at psql startup. In combination, these things guarantee that a control variable always has a displayable value that reflects what psql is actually doing. That is a pretty substantial usability improvement. The implementation involves adding a second type of variable hook function that is able to replace a proposed new value (including NULL) with another one. We could alternatively have complicated the API of the assign hook, but this way seems better since many variables can share the same substitution hook function. Also document the actual behavior of these variables more fully, including covering assorted behaviors that were there before but never documented. This patch also includes some minor cleanup that should have been in 511ae628f but was missed. Patch by me, but it owes a lot to discussions with Daniel Vérité. Discussion: https://postgr.es/m/9572.1485821620@sss.pgh.pa.us
9 years ago
static char *
verbosity_substitute_hook(char *newval)
{
if (newval == NULL)
newval = pg_strdup("default");
return newval;
}
static bool
verbosity_hook(const char *newval)
{
Improve psql's behavior for \set and \unset of its control variables. This commit improves on the results of commit 511ae628f in two ways: 1. It restores the historical behavior that "\set FOO" is interpreted as setting FOO to "on", if FOO is a boolean control variable. We already found one test script that was expecting that behavior, and the psql documentation certainly does nothing to discourage people from assuming that would work, since it often says just "if FOO is set" when describing the effects of a boolean variable. However, now this case will result in actually setting FOO to "on", not an empty string. 2. It arranges for an "\unset" of a control variable to set the value back to its default value, rather than becoming apparently undefined. The control variables are also initialized that way at psql startup. In combination, these things guarantee that a control variable always has a displayable value that reflects what psql is actually doing. That is a pretty substantial usability improvement. The implementation involves adding a second type of variable hook function that is able to replace a proposed new value (including NULL) with another one. We could alternatively have complicated the API of the assign hook, but this way seems better since many variables can share the same substitution hook function. Also document the actual behavior of these variables more fully, including covering assorted behaviors that were there before but never documented. This patch also includes some minor cleanup that should have been in 511ae628f but was missed. Patch by me, but it owes a lot to discussions with Daniel Vérité. Discussion: https://postgr.es/m/9572.1485821620@sss.pgh.pa.us
9 years ago
Assert(newval != NULL); /* else substitute hook messed up */
if (pg_strcasecmp(newval, "default") == 0)
pset.verbosity = PQERRORS_DEFAULT;
else if (pg_strcasecmp(newval, "terse") == 0)
pset.verbosity = PQERRORS_TERSE;
else if (pg_strcasecmp(newval, "verbose") == 0)
pset.verbosity = PQERRORS_VERBOSE;
else
{
PsqlVarEnumError("VERBOSITY", newval, "default, terse, verbose");
return false;
}
if (pset.db)
PQsetErrorVerbosity(pset.db, pset.verbosity);
return true;
}
Improve psql's behavior for \set and \unset of its control variables. This commit improves on the results of commit 511ae628f in two ways: 1. It restores the historical behavior that "\set FOO" is interpreted as setting FOO to "on", if FOO is a boolean control variable. We already found one test script that was expecting that behavior, and the psql documentation certainly does nothing to discourage people from assuming that would work, since it often says just "if FOO is set" when describing the effects of a boolean variable. However, now this case will result in actually setting FOO to "on", not an empty string. 2. It arranges for an "\unset" of a control variable to set the value back to its default value, rather than becoming apparently undefined. The control variables are also initialized that way at psql startup. In combination, these things guarantee that a control variable always has a displayable value that reflects what psql is actually doing. That is a pretty substantial usability improvement. The implementation involves adding a second type of variable hook function that is able to replace a proposed new value (including NULL) with another one. We could alternatively have complicated the API of the assign hook, but this way seems better since many variables can share the same substitution hook function. Also document the actual behavior of these variables more fully, including covering assorted behaviors that were there before but never documented. This patch also includes some minor cleanup that should have been in 511ae628f but was missed. Patch by me, but it owes a lot to discussions with Daniel Vérité. Discussion: https://postgr.es/m/9572.1485821620@sss.pgh.pa.us
9 years ago
static char *
show_context_substitute_hook(char *newval)
{
if (newval == NULL)
newval = pg_strdup("errors");
return newval;
}
static bool
show_context_hook(const char *newval)
{
Improve psql's behavior for \set and \unset of its control variables. This commit improves on the results of commit 511ae628f in two ways: 1. It restores the historical behavior that "\set FOO" is interpreted as setting FOO to "on", if FOO is a boolean control variable. We already found one test script that was expecting that behavior, and the psql documentation certainly does nothing to discourage people from assuming that would work, since it often says just "if FOO is set" when describing the effects of a boolean variable. However, now this case will result in actually setting FOO to "on", not an empty string. 2. It arranges for an "\unset" of a control variable to set the value back to its default value, rather than becoming apparently undefined. The control variables are also initialized that way at psql startup. In combination, these things guarantee that a control variable always has a displayable value that reflects what psql is actually doing. That is a pretty substantial usability improvement. The implementation involves adding a second type of variable hook function that is able to replace a proposed new value (including NULL) with another one. We could alternatively have complicated the API of the assign hook, but this way seems better since many variables can share the same substitution hook function. Also document the actual behavior of these variables more fully, including covering assorted behaviors that were there before but never documented. This patch also includes some minor cleanup that should have been in 511ae628f but was missed. Patch by me, but it owes a lot to discussions with Daniel Vérité. Discussion: https://postgr.es/m/9572.1485821620@sss.pgh.pa.us
9 years ago
Assert(newval != NULL); /* else substitute hook messed up */
if (pg_strcasecmp(newval, "never") == 0)
pset.show_context = PQSHOW_CONTEXT_NEVER;
else if (pg_strcasecmp(newval, "errors") == 0)
pset.show_context = PQSHOW_CONTEXT_ERRORS;
else if (pg_strcasecmp(newval, "always") == 0)
pset.show_context = PQSHOW_CONTEXT_ALWAYS;
else
{
PsqlVarEnumError("SHOW_CONTEXT", newval, "never, errors, always");
return false;
}
if (pset.db)
PQsetErrorContextVisibility(pset.db, pset.show_context);
return true;
}
static void
EstablishVariableSpace(void)
{
pset.vars = CreateVariableSpace();
Improve psql's behavior for \set and \unset of its control variables. This commit improves on the results of commit 511ae628f in two ways: 1. It restores the historical behavior that "\set FOO" is interpreted as setting FOO to "on", if FOO is a boolean control variable. We already found one test script that was expecting that behavior, and the psql documentation certainly does nothing to discourage people from assuming that would work, since it often says just "if FOO is set" when describing the effects of a boolean variable. However, now this case will result in actually setting FOO to "on", not an empty string. 2. It arranges for an "\unset" of a control variable to set the value back to its default value, rather than becoming apparently undefined. The control variables are also initialized that way at psql startup. In combination, these things guarantee that a control variable always has a displayable value that reflects what psql is actually doing. That is a pretty substantial usability improvement. The implementation involves adding a second type of variable hook function that is able to replace a proposed new value (including NULL) with another one. We could alternatively have complicated the API of the assign hook, but this way seems better since many variables can share the same substitution hook function. Also document the actual behavior of these variables more fully, including covering assorted behaviors that were there before but never documented. This patch also includes some minor cleanup that should have been in 511ae628f but was missed. Patch by me, but it owes a lot to discussions with Daniel Vérité. Discussion: https://postgr.es/m/9572.1485821620@sss.pgh.pa.us
9 years ago
SetVariableHooks(pset.vars, "AUTOCOMMIT",
bool_substitute_hook,
autocommit_hook);
SetVariableHooks(pset.vars, "ON_ERROR_STOP",
bool_substitute_hook,
on_error_stop_hook);
SetVariableHooks(pset.vars, "QUIET",
bool_substitute_hook,
quiet_hook);
SetVariableHooks(pset.vars, "SINGLELINE",
bool_substitute_hook,
singleline_hook);
SetVariableHooks(pset.vars, "SINGLESTEP",
bool_substitute_hook,
singlestep_hook);
SetVariableHooks(pset.vars, "FETCH_COUNT",
Clean up psql's behavior for a few more control variables. Modify FETCH_COUNT to always have a defined value, like other control variables, mainly so it will always appear in "\set" output. Add hooks to force HISTSIZE to be defined and require it to have an integer value. (I don't see any point in allowing it to be set to non-integral values.) Add hooks to force IGNOREEOF to be defined and require it to have an integer value. Unlike the other cases, here we're trying to be bug-compatible with a rather bogus externally-defined behavior, so I think we need to continue to allow "\set IGNOREEOF whatever". Fix it so that the substitution hook silently replace non-numeric values with "10", so that the stored value always reflects what we're really doing. Add a dummy assign hook for HISTFILE, just so it's always in variables.c's list. We can't require it to be defined always, because that would break the interaction with the PSQL_HISTORY environment variable, so there isn't any change in visible behavior here. Remove tab-complete.c's private list of known variable names, since that's really a maintenance nuisance. Given the preceding changes, there are no control variables it won't show anyway. This does mean that if for some reason you've unset one of the status variables (DBNAME, HOST, etc), that variable would not appear in tab completion for \set. But I think that's fine, for at least two reasons: we shouldn't be encouraging people to use those variables as regular variables, and if someone does do so anyway, why shouldn't it act just like a regular variable? Remove ugly and no-longer-used-anywhere GetVariableNum(). In general, future additions of integer-valued control variables should follow the paradigm of adding an assign hook using ParseVariableNum(), so there's no reason to expect we'd need this again later. Discussion: https://postgr.es/m/17516.1485973973@sss.pgh.pa.us
9 years ago
fetch_count_substitute_hook,
Improve psql's behavior for \set and \unset of its control variables. This commit improves on the results of commit 511ae628f in two ways: 1. It restores the historical behavior that "\set FOO" is interpreted as setting FOO to "on", if FOO is a boolean control variable. We already found one test script that was expecting that behavior, and the psql documentation certainly does nothing to discourage people from assuming that would work, since it often says just "if FOO is set" when describing the effects of a boolean variable. However, now this case will result in actually setting FOO to "on", not an empty string. 2. It arranges for an "\unset" of a control variable to set the value back to its default value, rather than becoming apparently undefined. The control variables are also initialized that way at psql startup. In combination, these things guarantee that a control variable always has a displayable value that reflects what psql is actually doing. That is a pretty substantial usability improvement. The implementation involves adding a second type of variable hook function that is able to replace a proposed new value (including NULL) with another one. We could alternatively have complicated the API of the assign hook, but this way seems better since many variables can share the same substitution hook function. Also document the actual behavior of these variables more fully, including covering assorted behaviors that were there before but never documented. This patch also includes some minor cleanup that should have been in 511ae628f but was missed. Patch by me, but it owes a lot to discussions with Daniel Vérité. Discussion: https://postgr.es/m/9572.1485821620@sss.pgh.pa.us
9 years ago
fetch_count_hook);
Clean up psql's behavior for a few more control variables. Modify FETCH_COUNT to always have a defined value, like other control variables, mainly so it will always appear in "\set" output. Add hooks to force HISTSIZE to be defined and require it to have an integer value. (I don't see any point in allowing it to be set to non-integral values.) Add hooks to force IGNOREEOF to be defined and require it to have an integer value. Unlike the other cases, here we're trying to be bug-compatible with a rather bogus externally-defined behavior, so I think we need to continue to allow "\set IGNOREEOF whatever". Fix it so that the substitution hook silently replace non-numeric values with "10", so that the stored value always reflects what we're really doing. Add a dummy assign hook for HISTFILE, just so it's always in variables.c's list. We can't require it to be defined always, because that would break the interaction with the PSQL_HISTORY environment variable, so there isn't any change in visible behavior here. Remove tab-complete.c's private list of known variable names, since that's really a maintenance nuisance. Given the preceding changes, there are no control variables it won't show anyway. This does mean that if for some reason you've unset one of the status variables (DBNAME, HOST, etc), that variable would not appear in tab completion for \set. But I think that's fine, for at least two reasons: we shouldn't be encouraging people to use those variables as regular variables, and if someone does do so anyway, why shouldn't it act just like a regular variable? Remove ugly and no-longer-used-anywhere GetVariableNum(). In general, future additions of integer-valued control variables should follow the paradigm of adding an assign hook using ParseVariableNum(), so there's no reason to expect we'd need this again later. Discussion: https://postgr.es/m/17516.1485973973@sss.pgh.pa.us
9 years ago
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);
Improve psql's behavior for \set and \unset of its control variables. This commit improves on the results of commit 511ae628f in two ways: 1. It restores the historical behavior that "\set FOO" is interpreted as setting FOO to "on", if FOO is a boolean control variable. We already found one test script that was expecting that behavior, and the psql documentation certainly does nothing to discourage people from assuming that would work, since it often says just "if FOO is set" when describing the effects of a boolean variable. However, now this case will result in actually setting FOO to "on", not an empty string. 2. It arranges for an "\unset" of a control variable to set the value back to its default value, rather than becoming apparently undefined. The control variables are also initialized that way at psql startup. In combination, these things guarantee that a control variable always has a displayable value that reflects what psql is actually doing. That is a pretty substantial usability improvement. The implementation involves adding a second type of variable hook function that is able to replace a proposed new value (including NULL) with another one. We could alternatively have complicated the API of the assign hook, but this way seems better since many variables can share the same substitution hook function. Also document the actual behavior of these variables more fully, including covering assorted behaviors that were there before but never documented. This patch also includes some minor cleanup that should have been in 511ae628f but was missed. Patch by me, but it owes a lot to discussions with Daniel Vérité. Discussion: https://postgr.es/m/9572.1485821620@sss.pgh.pa.us
9 years ago
SetVariableHooks(pset.vars, "ECHO",
echo_substitute_hook,
echo_hook);
SetVariableHooks(pset.vars, "ECHO_HIDDEN",
bool_substitute_hook,
echo_hidden_hook);
SetVariableHooks(pset.vars, "ON_ERROR_ROLLBACK",
bool_substitute_hook,
on_error_rollback_hook);
SetVariableHooks(pset.vars, "COMP_KEYWORD_CASE",
comp_keyword_case_substitute_hook,
comp_keyword_case_hook);
SetVariableHooks(pset.vars, "HISTCONTROL",
histcontrol_substitute_hook,
histcontrol_hook);
SetVariableHooks(pset.vars, "PROMPT1",
NULL,
prompt1_hook);
SetVariableHooks(pset.vars, "PROMPT2",
NULL,
prompt2_hook);
SetVariableHooks(pset.vars, "PROMPT3",
NULL,
prompt3_hook);
SetVariableHooks(pset.vars, "VERBOSITY",
verbosity_substitute_hook,
verbosity_hook);
SetVariableHooks(pset.vars, "SHOW_CONTEXT",
show_context_substitute_hook,
show_context_hook);
}