diff --git a/src/bin/psql/command.c b/src/bin/psql/command.c
index 971ad0c8161..28d5cef0536 100644
--- a/src/bin/psql/command.c
+++ b/src/bin/psql/command.c
@@ -3,7 +3,7 @@
*
* Copyright (c) 2000-2006, PostgreSQL Global Development Group
*
- * $PostgreSQL: pgsql/src/bin/psql/command.c,v 1.171 2006/07/18 17:42:01 momjian Exp $
+ * $PostgreSQL: pgsql/src/bin/psql/command.c,v 1.172 2006/08/29 15:19:50 tgl Exp $
*/
#include "postgres_fe.h"
#include "command.h"
@@ -55,8 +55,6 @@ static backslashResult exec_command(const char *cmd,
static bool do_edit(const char *filename_arg, PQExpBuffer query_buf);
static bool do_connect(char *dbname, char *user, char *host, char *port);
static bool do_shell(const char *command);
-static void SyncVerbosityVariable(void);
-
/*----------
@@ -196,7 +194,6 @@ exec_command(const char *cmd,
{
bool success = true; /* indicate here if the command ran ok or
* failed */
- bool quiet = QUIET();
backslashResult status = PSQL_CMD_SKIP_LINE;
/*
@@ -206,9 +203,9 @@ exec_command(const char *cmd,
if (strcmp(cmd, "a") == 0)
{
if (pset.popt.topt.format != PRINT_ALIGNED)
- success = do_pset("format", "aligned", &pset.popt, quiet);
+ success = do_pset("format", "aligned", &pset.popt, pset.quiet);
else
- success = do_pset("format", "unaligned", &pset.popt, quiet);
+ success = do_pset("format", "unaligned", &pset.popt, pset.quiet);
}
/* \C -- override table title (formerly change HTML caption) */
@@ -217,7 +214,7 @@ exec_command(const char *cmd,
char *opt = psql_scan_slash_option(scan_state,
OT_NORMAL, NULL, true);
- success = do_pset("title", opt, &pset.popt, quiet);
+ success = do_pset("title", opt, &pset.popt, pset.quiet);
free(opt);
}
@@ -493,7 +490,7 @@ exec_command(const char *cmd,
char *fname = psql_scan_slash_option(scan_state,
OT_NORMAL, NULL, false);
- success = do_pset("fieldsep", fname, &pset.popt, quiet);
+ success = do_pset("fieldsep", fname, &pset.popt, pset.quiet);
free(fname);
}
@@ -528,9 +525,9 @@ exec_command(const char *cmd,
else if (strcmp(cmd, "H") == 0 || strcmp(cmd, "html") == 0)
{
if (pset.popt.topt.format != PRINT_HTML)
- success = do_pset("format", "html", &pset.popt, quiet);
+ success = do_pset("format", "html", &pset.popt, pset.quiet);
else
- success = do_pset("format", "aligned", &pset.popt, quiet);
+ success = do_pset("format", "aligned", &pset.popt, pset.quiet);
}
@@ -638,7 +635,7 @@ exec_command(const char *cmd,
{
if (query_buf && query_buf->len > 0)
puts(query_buf->data);
- else if (!quiet)
+ else if (!pset.quiet)
puts(_("Query buffer is empty."));
fflush(stdout);
}
@@ -712,7 +709,7 @@ exec_command(const char *cmd,
success = false;
}
else
- success = do_pset(opt0, opt1, &pset.popt, quiet);
+ success = do_pset(opt0, opt1, &pset.popt, pset.quiet);
free(opt0);
free(opt1);
@@ -727,7 +724,7 @@ exec_command(const char *cmd,
{
resetPQExpBuffer(query_buf);
psql_scan_reset(scan_state);
- if (!quiet)
+ if (!pset.quiet)
puts(_("Query buffer reset (cleared)."));
}
@@ -740,7 +737,7 @@ exec_command(const char *cmd,
expand_tilde(&fname);
/* This scrolls off the screen when using /dev/tty */
success = saveHistory(fname ? fname : DEVTTY, false);
- if (success && !quiet && fname)
+ if (success && !pset.quiet && fname)
printf(gettext("Wrote history to file \"%s/%s\".\n"),
pset.dirname ? pset.dirname : ".", fname);
if (!fname)
@@ -786,13 +783,7 @@ exec_command(const char *cmd,
free(opt);
}
- if (SetVariable(pset.vars, opt0, newval))
- {
- /* Check for special variables */
- if (strcmp(opt0, "VERBOSITY") == 0)
- SyncVerbosityVariable();
- }
- else
+ if (!SetVariable(pset.vars, opt0, newval))
{
psql_error("\\%s: error\n", cmd);
success = false;
@@ -804,7 +795,7 @@ exec_command(const char *cmd,
/* \t -- turn off headers and row count */
else if (strcmp(cmd, "t") == 0)
- success = do_pset("tuples_only", NULL, &pset.popt, quiet);
+ success = do_pset("tuples_only", NULL, &pset.popt, pset.quiet);
/* \T -- define html
attributes */
@@ -813,7 +804,7 @@ exec_command(const char *cmd,
char *value = psql_scan_slash_option(scan_state,
OT_NORMAL, NULL, false);
- success = do_pset("tableattr", value, &pset.popt, quiet);
+ success = do_pset("tableattr", value, &pset.popt, pset.quiet);
free(value);
}
@@ -821,7 +812,7 @@ exec_command(const char *cmd,
else if (strcmp(cmd, "timing") == 0)
{
pset.timing = !pset.timing;
- if (!quiet)
+ if (!pset.quiet)
{
if (pset.timing)
puts(_("Timing is on."));
@@ -916,7 +907,7 @@ exec_command(const char *cmd,
/* \x -- toggle expanded table representation */
else if (strcmp(cmd, "x") == 0)
- success = do_pset("expanded", NULL, &pset.popt, quiet);
+ success = do_pset("expanded", NULL, &pset.popt, pset.quiet);
/* \z -- list table rights (equivalent to \dp) */
else if (strcmp(cmd, "z") == 0)
@@ -1114,7 +1105,7 @@ do_connect(char *dbname, char *user, char *host, char *port)
SyncVariables();
/* Tell the user about the new connection */
- if (!QUIET())
+ if (!pset.quiet)
{
printf(_("You are now connected to database \"%s\""), PQdb(pset.db));
@@ -1148,6 +1139,7 @@ SyncVariables(void)
/* get stuff from connection */
pset.encoding = PQclientEncoding(pset.db);
pset.popt.topt.encoding = pset.encoding;
+ pset.sversion = PQserverVersion(pset.db);
SetVariable(pset.vars, "DBNAME", PQdb(pset.db));
SetVariable(pset.vars, "USER", PQuser(pset.db));
@@ -1156,7 +1148,7 @@ SyncVariables(void)
SetVariable(pset.vars, "ENCODING", pg_encoding_to_char(pset.encoding));
/* send stuff to it, too */
- SyncVerbosityVariable();
+ PQsetErrorVerbosity(pset.db, pset.verbosity);
}
/*
@@ -1174,32 +1166,6 @@ UnsyncVariables(void)
SetVariable(pset.vars, "ENCODING", NULL);
}
-/*
- * Update connection state from VERBOSITY variable
- */
-static void
-SyncVerbosityVariable(void)
-{
- switch (SwitchVariable(pset.vars, "VERBOSITY",
- "default", "terse", "verbose", NULL))
- {
- case 1: /* default */
- pset.verbosity = PQERRORS_DEFAULT;
- break;
- case 2: /* terse */
- pset.verbosity = PQERRORS_TERSE;
- break;
- case 3: /* verbose */
- pset.verbosity = PQERRORS_VERBOSE;
- break;
- default: /* not set or unrecognized value */
- pset.verbosity = PQERRORS_DEFAULT;
- break;
- }
-
- PQsetErrorVerbosity(pset.db, pset.verbosity);
-}
-
/*
* do_edit -- handler for \e
diff --git a/src/bin/psql/common.c b/src/bin/psql/common.c
index 7bdf6d15dcf..3e9d23d1956 100644
--- a/src/bin/psql/common.c
+++ b/src/bin/psql/common.c
@@ -3,7 +3,7 @@
*
* Copyright (c) 2000-2006, PostgreSQL Global Development Group
*
- * $PostgreSQL: pgsql/src/bin/psql/common.c,v 1.125 2006/08/25 04:06:54 tgl Exp $
+ * $PostgreSQL: pgsql/src/bin/psql/common.c,v 1.126 2006/08/29 15:19:50 tgl Exp $
*/
#include "postgres_fe.h"
#include "common.h"
@@ -515,7 +515,6 @@ PGresult *
PSQLexec(const char *query, bool start_xact)
{
PGresult *res;
- int echo_hidden;
if (!pset.db)
{
@@ -523,8 +522,7 @@ PSQLexec(const char *query, bool start_xact)
return NULL;
}
- echo_hidden = SwitchVariable(pset.vars, "ECHO_HIDDEN", "noexec", NULL);
- if (echo_hidden != VAR_NOTSET)
+ if (pset.echo_hidden != PSQL_ECHO_HIDDEN_OFF)
{
printf(_("********* QUERY **********\n"
"%s\n"
@@ -539,14 +537,15 @@ PSQLexec(const char *query, bool start_xact)
fflush(pset.logfile);
}
- if (echo_hidden == 1) /* noexec? */
+ if (pset.echo_hidden == PSQL_ECHO_HIDDEN_NOEXEC)
return NULL;
}
SetCancelConn();
- if (start_xact && PQtransactionStatus(pset.db) == PQTRANS_IDLE &&
- !GetVariableBool(pset.vars, "AUTOCOMMIT"))
+ if (start_xact &&
+ !pset.autocommit &&
+ PQtransactionStatus(pset.db) == PQTRANS_IDLE)
{
res = PQexec(pset.db, "BEGIN");
if (PQresultStatus(res) != PGRES_COMMAND_OK)
@@ -693,7 +692,7 @@ PrintQueryStatus(PGresult *results)
{
char buf[16];
- if (!QUIET())
+ if (!pset.quiet)
{
if (pset.popt.topt.format == PRINT_HTML)
{
@@ -789,7 +788,6 @@ SendQuery(const char *query)
on_error_rollback_savepoint = false;
PGTransactionStatusType transaction_status;
static bool on_error_rollback_warning = false;
- const char *rollback_str;
if (!pset.db)
{
@@ -797,7 +795,7 @@ SendQuery(const char *query)
return false;
}
- if (GetVariableBool(pset.vars, "SINGLESTEP"))
+ if (pset.singlestep)
{
char buf[3];
@@ -810,7 +808,7 @@ SendQuery(const char *query)
if (buf[0] == 'x')
return false;
}
- else if (VariableEquals(pset.vars, "ECHO", "queries"))
+ else if (pset.echo == PSQL_ECHO_QUERIES)
{
puts(query);
fflush(stdout);
@@ -830,7 +828,7 @@ SendQuery(const char *query)
transaction_status = PQtransactionStatus(pset.db);
if (transaction_status == PQTRANS_IDLE &&
- !GetVariableBool(pset.vars, "AUTOCOMMIT") &&
+ !pset.autocommit &&
!command_no_begin(query))
{
results = PQexec(pset.db, "BEGIN");
@@ -846,11 +844,9 @@ SendQuery(const char *query)
}
if (transaction_status == PQTRANS_INTRANS &&
- (rollback_str = GetVariable(pset.vars, "ON_ERROR_ROLLBACK")) != NULL &&
- /* !off and !interactive is 'on' */
- pg_strcasecmp(rollback_str, "off") != 0 &&
+ pset.on_error_rollback != PSQL_ERROR_ROLLBACK_OFF &&
(pset.cur_cmd_interactive ||
- pg_strcasecmp(rollback_str, "interactive") != 0))
+ pset.on_error_rollback == PSQL_ERROR_ROLLBACK_ON))
{
if (on_error_rollback_warning == false && pset.sversion < 80000)
{
diff --git a/src/bin/psql/copy.c b/src/bin/psql/copy.c
index 2ec01af186b..0d7cb5b4e00 100644
--- a/src/bin/psql/copy.c
+++ b/src/bin/psql/copy.c
@@ -3,7 +3,7 @@
*
* Copyright (c) 2000-2006, PostgreSQL Global Development Group
*
- * $PostgreSQL: pgsql/src/bin/psql/copy.c,v 1.66 2006/06/14 16:49:02 tgl Exp $
+ * $PostgreSQL: pgsql/src/bin/psql/copy.c,v 1.67 2006/08/29 15:19:50 tgl Exp $
*/
#include "postgres_fe.h"
#include "copy.h"
@@ -704,7 +704,7 @@ handleCopyIn(PGconn *conn, FILE *copystream, bool isbinary)
/* Prompt if interactive input */
if (isatty(fileno(copystream)))
{
- if (!QUIET())
+ if (!pset.quiet)
puts(_("Enter data to be copied followed by a newline.\n"
"End with a backslash and a period on a line by itself."));
prompt = get_prompt(PROMPT_COPY);
diff --git a/src/bin/psql/describe.c b/src/bin/psql/describe.c
index 49db39074d1..b6fbc135806 100644
--- a/src/bin/psql/describe.c
+++ b/src/bin/psql/describe.c
@@ -3,7 +3,7 @@
*
* Copyright (c) 2000-2006, PostgreSQL Global Development Group
*
- * $PostgreSQL: pgsql/src/bin/psql/describe.c,v 1.143 2006/08/25 04:06:54 tgl Exp $
+ * $PostgreSQL: pgsql/src/bin/psql/describe.c,v 1.144 2006/08/29 15:19:51 tgl Exp $
*/
#include "postgres_fe.h"
#include "describe.h"
@@ -673,7 +673,7 @@ describeTableDetails(const char *pattern, bool verbose)
if (PQntuples(res) == 0)
{
- if (!QUIET())
+ if (!pset.quiet)
fprintf(stderr, _("Did not find any relation named \"%s\".\n"),
pattern);
PQclear(res);
@@ -768,7 +768,7 @@ describeOneTableDetails(const char *schemaname,
/* Did we get anything? */
if (PQntuples(res) == 0)
{
- if (!QUIET())
+ if (!pset.quiet)
fprintf(stderr, _("Did not find any relation with OID %s.\n"),
oid);
goto error_return;
@@ -1582,7 +1582,7 @@ listTables(const char *tabtypes, const char *pattern, bool verbose)
if (!res)
return false;
- if (PQntuples(res) == 0 && !QUIET())
+ if (PQntuples(res) == 0 && !pset.quiet)
{
if (pattern)
fprintf(pset.queryFout, _("No matching relations found.\n"));
diff --git a/src/bin/psql/input.c b/src/bin/psql/input.c
index 3441d7813e2..323ef573b40 100644
--- a/src/bin/psql/input.c
+++ b/src/bin/psql/input.c
@@ -3,7 +3,7 @@
*
* Copyright (c) 2000-2006, PostgreSQL Global Development Group
*
- * $PostgreSQL: pgsql/src/bin/psql/input.c,v 1.58 2006/08/27 15:05:20 tgl Exp $
+ * $PostgreSQL: pgsql/src/bin/psql/input.c,v 1.59 2006/08/29 15:19:51 tgl Exp $
*/
#include "postgres_fe.h"
@@ -34,14 +34,6 @@ char *psql_history;
* for this purpose.
*/
#define NL_IN_HISTORY 0x01
-
-enum histcontrol
-{
- hctl_none = 0,
- hctl_ignorespace = 1,
- hctl_ignoredups = 2,
- hctl_ignoreboth = hctl_ignorespace | hctl_ignoredups
-};
#endif
#ifdef HAVE_ATEXIT
@@ -52,31 +44,6 @@ static void finishInput(int, void *);
#endif
-#ifdef USE_READLINE
-static enum histcontrol
-GetHistControlConfig(void)
-{
- enum histcontrol HC;
- const char *var;
-
- var = GetVariable(pset.vars, "HISTCONTROL");
-
- if (!var)
- HC = hctl_none;
- else if (strcmp(var, "ignorespace") == 0)
- HC = hctl_ignorespace;
- else if (strcmp(var, "ignoredups") == 0)
- HC = hctl_ignoredups;
- else if (strcmp(var, "ignoreboth") == 0)
- HC = hctl_ignoreboth;
- else
- HC = hctl_none;
-
- return HC;
-}
-#endif
-
-
/*
* gets_interactive()
*
@@ -147,10 +114,10 @@ pg_send_history(PQExpBuffer history_buf)
if (useHistory && s[0])
{
- enum histcontrol HC = GetHistControlConfig();
-
- if (((HC & hctl_ignorespace) && s[0] == ' ') ||
- ((HC & hctl_ignoredups) && prev_hist && strcmp(s, prev_hist) == 0))
+ if (((pset.histcontrol & hctl_ignorespace) &&
+ s[0] == ' ') ||
+ ((pset.histcontrol & hctl_ignoredups) &&
+ prev_hist && strcmp(s, prev_hist) == 0))
{
/* Ignore this line as far as history is concerned */
}
@@ -287,17 +254,17 @@ initializeInput(int flags)
#ifdef USE_READLINE
if (flags & 1)
{
+ const char *histfile;
char home[MAXPGPATH];
useReadline = true;
initialize_readline();
useHistory = true;
- if (GetVariable(pset.vars, "HISTSIZE") == NULL)
- SetVariable(pset.vars, "HISTSIZE", "500");
using_history();
- if (GetVariable(pset.vars, "HISTFILE") == NULL)
+ histfile = GetVariable(pset.vars, "HISTFILE");
+ if (histfile == NULL)
{
if (get_home_path(home))
{
@@ -308,7 +275,7 @@ initializeInput(int flags)
}
else
{
- psql_history = pg_strdup(GetVariable(pset.vars, "HISTFILE"));
+ psql_history = pg_strdup(histfile);
expand_tilde(&psql_history);
}
@@ -386,7 +353,7 @@ finishInput(int exitstatus, void *arg)
{
int hist_size;
- hist_size = GetVariableNum(pset.vars, "HISTSIZE", -1, -1, true);
+ hist_size = GetVariableNum(pset.vars, "HISTSIZE", 500, -1, true);
if (hist_size >= 0)
stifle_history(hist_size);
diff --git a/src/bin/psql/large_obj.c b/src/bin/psql/large_obj.c
index 778606c5f0e..48d8931e9fc 100644
--- a/src/bin/psql/large_obj.c
+++ b/src/bin/psql/large_obj.c
@@ -3,7 +3,7 @@
*
* Copyright (c) 2000-2006, PostgreSQL Global Development Group
*
- * $PostgreSQL: pgsql/src/bin/psql/large_obj.c,v 1.45 2006/07/14 14:52:26 momjian Exp $
+ * $PostgreSQL: pgsql/src/bin/psql/large_obj.c,v 1.46 2006/08/29 15:19:51 tgl Exp $
*/
#include "postgres_fe.h"
#include "large_obj.h"
@@ -67,8 +67,7 @@ finish_lo_xact(const char *operation, bool own_transaction)
{
PGresult *res;
- if (own_transaction &&
- GetVariableBool(pset.vars, "AUTOCOMMIT"))
+ if (own_transaction && pset.autocommit)
{
/* close out our own xact */
if (!(res = PSQLexec("COMMIT", false)))
@@ -91,8 +90,7 @@ fail_lo_xact(const char *operation, bool own_transaction)
{
PGresult *res;
- if (own_transaction &&
- GetVariableBool(pset.vars, "AUTOCOMMIT"))
+ if (own_transaction && pset.autocommit)
{
/* close out our own xact */
res = PSQLexec("ROLLBACK", false);
diff --git a/src/bin/psql/mainloop.c b/src/bin/psql/mainloop.c
index 730210b20c9..519230b28ac 100644
--- a/src/bin/psql/mainloop.c
+++ b/src/bin/psql/mainloop.c
@@ -3,7 +3,7 @@
*
* Copyright (c) 2000-2006, PostgreSQL Global Development Group
*
- * $PostgreSQL: pgsql/src/bin/psql/mainloop.c,v 1.82 2006/08/11 19:20:59 momjian Exp $
+ * $PostgreSQL: pgsql/src/bin/psql/mainloop.c,v 1.83 2006/08/29 15:19:51 tgl Exp $
*/
#include "postgres_fe.h"
#include "mainloop.h"
@@ -146,12 +146,12 @@ MainLoop(FILE *source)
if (count_eof < GetVariableNum(pset.vars, "IGNOREEOF", 0, 10, false))
{
- if (!QUIET())
+ if (!pset.quiet)
printf(_("Use \"\\q\" to leave %s.\n"), pset.progname);
continue;
}
- puts(QUIET() ? "" : "\\q");
+ puts(pset.quiet ? "" : "\\q");
}
break;
}
@@ -168,8 +168,7 @@ MainLoop(FILE *source)
}
/* echo back if flag is set */
- if (!pset.cur_cmd_interactive &&
- VariableEquals(pset.vars, "ECHO", "all"))
+ if (pset.echo == PSQL_ECHO_ALL && !pset.cur_cmd_interactive)
puts(line);
fflush(stdout);
@@ -183,7 +182,7 @@ MainLoop(FILE *source)
added_nl_pos = -1; /* flag we didn't add one */
/* Setting this will not have effect until next line. */
- die_on_error = GetVariableBool(pset.vars, "ON_ERROR_STOP");
+ die_on_error = pset.on_error_stop;
/*
* Parse line, looking for command separators.
@@ -205,8 +204,7 @@ MainLoop(FILE *source)
* single-line mode.
*/
if (scan_result == PSCAN_SEMICOLON ||
- (scan_result == PSCAN_EOL &&
- GetVariableBool(pset.vars, "SINGLELINE")))
+ (scan_result == PSCAN_EOL && pset.singleline))
{
/*
* Save query in history. We use history_buf to accumulate
diff --git a/src/bin/psql/prompt.c b/src/bin/psql/prompt.c
index 981e8b6b58e..6bf86d1108c 100644
--- a/src/bin/psql/prompt.c
+++ b/src/bin/psql/prompt.c
@@ -3,7 +3,7 @@
*
* Copyright (c) 2000-2006, PostgreSQL Global Development Group
*
- * $PostgreSQL: pgsql/src/bin/psql/prompt.c,v 1.47 2006/07/15 03:35:21 tgl Exp $
+ * $PostgreSQL: pgsql/src/bin/psql/prompt.c,v 1.48 2006/08/29 15:19:51 tgl Exp $
*/
#include "postgres_fe.h"
@@ -72,12 +72,11 @@ get_prompt(promptStatus_t status)
bool esc = false;
const char *p;
const char *prompt_string = "? ";
- const char *prompt_name = NULL;
switch (status)
{
case PROMPT_READY:
- prompt_name = "PROMPT1";
+ prompt_string = pset.prompt1;
break;
case PROMPT_CONTINUE:
@@ -86,21 +85,18 @@ get_prompt(promptStatus_t status)
case PROMPT_DOLLARQUOTE:
case PROMPT_COMMENT:
case PROMPT_PAREN:
- prompt_name = "PROMPT2";
+ prompt_string = pset.prompt2;
break;
case PROMPT_COPY:
- prompt_name = "PROMPT3";
+ prompt_string = pset.prompt3;
break;
}
- if (prompt_name)
- prompt_string = GetVariable(pset.vars, prompt_name);
-
destination[0] = '\0';
for (p = prompt_string;
- p && *p && strlen(destination) < MAX_PROMPT_SIZE;
+ *p && strlen(destination) < MAX_PROMPT_SIZE;
p++)
{
memset(buf, 0, MAX_PROMPT_SIZE + 1);
@@ -182,7 +178,7 @@ get_prompt(promptStatus_t status)
case PROMPT_READY:
if (!pset.db)
buf[0] = '!';
- else if (!GetVariableBool(pset.vars, "SINGLELINE"))
+ else if (!pset.singleline)
buf[0] = '=';
else
buf[0] = '^';
diff --git a/src/bin/psql/settings.h b/src/bin/psql/settings.h
index a5c4a02be9e..9dc41e3bdfb 100644
--- a/src/bin/psql/settings.h
+++ b/src/bin/psql/settings.h
@@ -3,7 +3,7 @@
*
* Copyright (c) 2000-2006, PostgreSQL Global Development Group
*
- * $PostgreSQL: pgsql/src/bin/psql/settings.h,v 1.28 2006/08/11 19:20:59 momjian Exp $
+ * $PostgreSQL: pgsql/src/bin/psql/settings.h,v 1.29 2006/08/29 15:19:51 tgl Exp $
*/
#ifndef SETTINGS_H
#define SETTINGS_H
@@ -26,16 +26,44 @@
#define DEFAULT_PROMPT2 "%/%R%# "
#define DEFAULT_PROMPT3 ">> "
+typedef enum
+{
+ PSQL_ECHO_NONE,
+ PSQL_ECHO_QUERIES,
+ PSQL_ECHO_ALL
+} PSQL_ECHO;
+
+typedef enum
+{
+ PSQL_ECHO_HIDDEN_OFF,
+ PSQL_ECHO_HIDDEN_ON,
+ PSQL_ECHO_HIDDEN_NOEXEC
+} PSQL_ECHO_HIDDEN;
+
+typedef enum
+{
+ PSQL_ERROR_ROLLBACK_OFF,
+ PSQL_ERROR_ROLLBACK_INTERACTIVE,
+ PSQL_ERROR_ROLLBACK_ON
+} PSQL_ERROR_ROLLBACK;
+
+typedef enum
+{
+ hctl_none = 0,
+ hctl_ignorespace = 1,
+ hctl_ignoredups = 2,
+ hctl_ignoreboth = hctl_ignorespace | hctl_ignoredups
+} HistControl;
+
typedef struct _psqlSettings
{
PGconn *db; /* connection to backend */
- int encoding;
+ int encoding; /* client_encoding */
FILE *queryFout; /* where to send the query results */
bool queryFoutPipe; /* queryFout is from a popen() */
printQueryOpt popt;
- VariableSpace vars; /* "shell variable" repository */
char *gfname; /* one-shot file output argument for \g */
@@ -54,16 +82,33 @@ typedef struct _psqlSettings
bool timing; /* enable timing of all queries */
- PGVerbosity verbosity; /* current error verbosity level */
FILE *logfile; /* session log file handle */
+
+ VariableSpace vars; /* "shell variable" repository */
+
+ /*
+ * The remaining fields are set by assign hooks associated with
+ * entries in "vars". They should not be set directly except by
+ * those hook functions.
+ */
+ bool autocommit;
+ bool on_error_stop;
+ bool quiet;
+ bool singleline;
+ bool singlestep;
+ PSQL_ECHO echo;
+ PSQL_ECHO_HIDDEN echo_hidden;
+ PSQL_ERROR_ROLLBACK on_error_rollback;
+ HistControl histcontrol;
+ const char *prompt1;
+ const char *prompt2;
+ const char *prompt3;
+ PGVerbosity verbosity; /* current error verbosity level */
} PsqlSettings;
extern PsqlSettings pset;
-#define QUIET() (GetVariableBool(pset.vars, "QUIET"))
-
-
#ifndef EXIT_SUCCESS
#define EXIT_SUCCESS 0
#endif
diff --git a/src/bin/psql/startup.c b/src/bin/psql/startup.c
index 1a937e1eb47..8d3409bd194 100644
--- a/src/bin/psql/startup.c
+++ b/src/bin/psql/startup.c
@@ -3,7 +3,7 @@
*
* Copyright (c) 2000-2006, PostgreSQL Global Development Group
*
- * $PostgreSQL: pgsql/src/bin/psql/startup.c,v 1.135 2006/07/14 14:52:26 momjian Exp $
+ * $PostgreSQL: pgsql/src/bin/psql/startup.c,v 1.136 2006/08/29 15:19:51 tgl Exp $
*/
#include "postgres_fe.h"
@@ -84,14 +84,14 @@ static void parse_psql_options(int argc, char *argv[],
static void process_psqlrc(char *argv0);
static void process_psqlrc_file(char *filename);
static void showVersion(void);
+static void EstablishVariableSpace(void);
#ifdef USE_SSL
static void printSSLInfo(void);
#endif
#ifdef WIN32
-static void
- checkWin32Codepage(void);
+static void checkWin32Codepage(void);
#endif
/*
@@ -134,34 +134,19 @@ main(int argc, char *argv[])
pset.progname = get_progname(argv[0]);
+ pset.db = NULL;
setDecimalLocale();
+ pset.encoding = PQenv2encoding();
+ pset.queryFout = stdout;
+ pset.queryFoutPipe = false;
pset.cur_cmd_source = stdin;
pset.cur_cmd_interactive = false;
- pset.encoding = PQenv2encoding();
- pset.vars = CreateVariableSpace();
- if (!pset.vars)
- {
- fprintf(stderr, _("%s: out of memory\n"), pset.progname);
- exit(EXIT_FAILURE);
- }
pset.popt.topt.format = PRINT_ALIGNED;
- pset.queryFout = stdout;
pset.popt.topt.border = 1;
pset.popt.topt.pager = 1;
pset.popt.default_footer = true;
- SetVariable(pset.vars, "VERSION", PG_VERSION_STR);
-
- /* Default values for variables */
- SetVariableBool(pset.vars, "AUTOCOMMIT");
- SetVariable(pset.vars, "VERBOSITY", "default");
- SetVariable(pset.vars, "PROMPT1", DEFAULT_PROMPT1);
- SetVariable(pset.vars, "PROMPT2", DEFAULT_PROMPT2);
- SetVariable(pset.vars, "PROMPT3", DEFAULT_PROMPT3);
-
- pset.verbosity = PQERRORS_DEFAULT;
-
pset.notty = (!isatty(fileno(stdin)) || !isatty(fileno(stdout)));
/* This is obsolete and should be removed sometime. */
@@ -171,6 +156,17 @@ main(int argc, char *argv[])
pset.getPassword = false;
#endif
+ EstablishVariableSpace();
+
+ SetVariable(pset.vars, "VERSION", PG_VERSION_STR);
+
+ /* Default values for variables */
+ SetVariableBool(pset.vars, "AUTOCOMMIT");
+ SetVariable(pset.vars, "VERBOSITY", "default");
+ 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 (!pset.popt.topt.fieldSep)
@@ -239,9 +235,6 @@ main(int argc, char *argv[])
SyncVariables();
- /* Grab the backend server version */
- pset.sversion = PQserverVersion(pset.db);
-
if (options.action == ACT_LIST_DB)
{
int success = listAllDbs(false);
@@ -280,7 +273,7 @@ main(int argc, char *argv[])
{
PsqlScanState scan_state;
- if (VariableEquals(pset.vars, "ECHO", "all"))
+ if (pset.echo == PSQL_ECHO_ALL)
puts(options.action_string);
scan_state = psql_scan_create();
@@ -299,7 +292,7 @@ main(int argc, char *argv[])
*/
else if (options.action == ACT_SINGLE_QUERY)
{
- if (VariableEquals(pset.vars, "ECHO", "all"))
+ if (pset.echo == PSQL_ECHO_ALL)
puts(options.action_string);
successResult = SendQuery(options.action_string)
@@ -314,7 +307,7 @@ main(int argc, char *argv[])
if (!options.no_psqlrc)
process_psqlrc(argv[0]);
- if (!QUIET() && !pset.notty)
+ if (!pset.quiet && !pset.notty)
{
int client_ver = parse_version(PG_VERSION);
@@ -644,14 +637,14 @@ parse_psql_options(int argc, char *argv[], struct adhoc_opts * options)
options->dbname = argv[optind];
else if (!options->username)
options->username = argv[optind];
- else if (!QUIET())
+ else if (!pset.quiet)
fprintf(stderr, _("%s: warning: extra command-line argument \"%s\" ignored\n"),
pset.progname, argv[optind]);
optind++;
}
- if (used_old_u_option && !QUIET())
+ if (used_old_u_option && !pset.quiet)
fprintf(stderr, _("%s: Warning: The -u option is deprecated. Use -U.\n"), pset.progname);
}
@@ -743,7 +736,6 @@ printSSLInfo(void)
#endif
-
/*
* checkWin32Codepage
*
@@ -768,3 +760,151 @@ checkWin32Codepage(void)
}
#endif
+
+
+/*
+ * Assign hooks for psql variables.
+ *
+ * This isn't an amazingly good place for them, but neither is anywhere else.
+ */
+
+static void
+autocommit_hook(const char *newval)
+{
+ pset.autocommit = ParseVariableBool(newval);
+}
+
+static void
+on_error_stop_hook(const char *newval)
+{
+ pset.on_error_stop = ParseVariableBool(newval);
+}
+
+static void
+quiet_hook(const char *newval)
+{
+ pset.quiet = ParseVariableBool(newval);
+}
+
+static void
+singleline_hook(const char *newval)
+{
+ pset.singleline = ParseVariableBool(newval);
+}
+
+static void
+singlestep_hook(const char *newval)
+{
+ pset.singlestep = ParseVariableBool(newval);
+}
+
+static void
+echo_hook(const char *newval)
+{
+ if (newval == NULL)
+ pset.echo = PSQL_ECHO_NONE;
+ else if (strcmp(newval, "queries") == 0)
+ pset.echo = PSQL_ECHO_QUERIES;
+ else if (strcmp(newval, "all") == 0)
+ pset.echo = PSQL_ECHO_ALL;
+ else
+ pset.echo = PSQL_ECHO_NONE;
+}
+
+static void
+echo_hidden_hook(const char *newval)
+{
+ if (newval == NULL)
+ pset.echo_hidden = PSQL_ECHO_HIDDEN_OFF;
+ else if (strcmp(newval, "noexec") == 0)
+ pset.echo_hidden = PSQL_ECHO_HIDDEN_NOEXEC;
+ else if (pg_strcasecmp(newval, "off") == 0)
+ pset.echo_hidden = PSQL_ECHO_HIDDEN_OFF;
+ else
+ pset.echo_hidden = PSQL_ECHO_HIDDEN_ON;
+}
+
+static void
+on_error_rollback_hook(const char *newval)
+{
+ if (newval == NULL)
+ pset.on_error_rollback = PSQL_ERROR_ROLLBACK_OFF;
+ else if (pg_strcasecmp(newval, "interactive") == 0)
+ pset.on_error_rollback = PSQL_ERROR_ROLLBACK_INTERACTIVE;
+ else if (pg_strcasecmp(newval, "off") == 0)
+ pset.on_error_rollback = PSQL_ERROR_ROLLBACK_OFF;
+ else
+ pset.on_error_rollback = PSQL_ERROR_ROLLBACK_ON;
+}
+
+static void
+histcontrol_hook(const char *newval)
+{
+ if (newval == NULL)
+ pset.histcontrol = hctl_none;
+ else if (strcmp(newval, "ignorespace") == 0)
+ pset.histcontrol = hctl_ignorespace;
+ else if (strcmp(newval, "ignoredups") == 0)
+ pset.histcontrol = hctl_ignoredups;
+ else if (strcmp(newval, "ignoreboth") == 0)
+ pset.histcontrol = hctl_ignoreboth;
+ else
+ pset.histcontrol = hctl_none;
+}
+
+static void
+prompt1_hook(const char *newval)
+{
+ pset.prompt1 = newval ? newval : "";
+}
+
+static void
+prompt2_hook(const char *newval)
+{
+ pset.prompt2 = newval ? newval : "";
+}
+
+static void
+prompt3_hook(const char *newval)
+{
+ pset.prompt3 = newval ? newval : "";
+}
+
+static void
+verbosity_hook(const char *newval)
+{
+ if (newval == NULL)
+ pset.verbosity = PQERRORS_DEFAULT;
+ else if (strcmp(newval, "default") == 0)
+ pset.verbosity = PQERRORS_DEFAULT;
+ else if (strcmp(newval, "terse") == 0)
+ pset.verbosity = PQERRORS_TERSE;
+ else if (strcmp(newval, "verbose") == 0)
+ pset.verbosity = PQERRORS_VERBOSE;
+ else
+ pset.verbosity = PQERRORS_DEFAULT;
+
+ if (pset.db)
+ PQsetErrorVerbosity(pset.db, pset.verbosity);
+}
+
+
+static void
+EstablishVariableSpace(void)
+{
+ pset.vars = CreateVariableSpace();
+
+ SetVariableAssignHook(pset.vars, "AUTOCOMMIT", autocommit_hook);
+ SetVariableAssignHook(pset.vars, "ON_ERROR_STOP", on_error_stop_hook);
+ SetVariableAssignHook(pset.vars, "QUIET", quiet_hook);
+ SetVariableAssignHook(pset.vars, "SINGLELINE", singleline_hook);
+ SetVariableAssignHook(pset.vars, "SINGLESTEP", singlestep_hook);
+ SetVariableAssignHook(pset.vars, "ECHO", echo_hook);
+ SetVariableAssignHook(pset.vars, "ECHO_HIDDEN", echo_hidden_hook);
+ SetVariableAssignHook(pset.vars, "ON_ERROR_ROLLBACK", on_error_rollback_hook);
+ SetVariableAssignHook(pset.vars, "HISTCONTROL", histcontrol_hook);
+ SetVariableAssignHook(pset.vars, "PROMPT1", prompt1_hook);
+ SetVariableAssignHook(pset.vars, "PROMPT2", prompt2_hook);
+ SetVariableAssignHook(pset.vars, "PROMPT3", prompt3_hook);
+ SetVariableAssignHook(pset.vars, "VERBOSITY", verbosity_hook);
+}
diff --git a/src/bin/psql/variables.c b/src/bin/psql/variables.c
index e0e416e9e5a..cac638e0393 100644
--- a/src/bin/psql/variables.c
+++ b/src/bin/psql/variables.c
@@ -3,20 +3,27 @@
*
* Copyright (c) 2000-2006, PostgreSQL Global Development Group
*
- * $PostgreSQL: pgsql/src/bin/psql/variables.c,v 1.25 2006/06/21 16:05:11 tgl Exp $
+ * $PostgreSQL: pgsql/src/bin/psql/variables.c,v 1.26 2006/08/29 15:19:51 tgl Exp $
*/
#include "postgres_fe.h"
#include "common.h"
#include "variables.h"
+
+/*
+ * A "variable space" is represented by an otherwise-unused struct _variable
+ * that serves as list header.
+ */
VariableSpace
CreateVariableSpace(void)
{
struct _variable *ptr;
- ptr = pg_calloc(1, sizeof *ptr);
- ptr->name = pg_strdup("@");
- ptr->value = pg_strdup("");
+ ptr = pg_malloc(sizeof *ptr);
+ ptr->name = NULL;
+ ptr->value = NULL;
+ ptr->assign_hook = NULL;
+ ptr->next = NULL;
return ptr;
}
@@ -33,7 +40,7 @@ GetVariable(VariableSpace space, const char *name)
{
if (strcmp(current->name, name) == 0)
{
- psql_assert(current->value);
+ /* this is correct answer when value is NULL, too */
return current->value;
}
}
@@ -42,11 +49,8 @@ GetVariable(VariableSpace space, const char *name)
}
bool
-GetVariableBool(VariableSpace space, const char *name)
+ParseVariableBool(const char *val)
{
- const char *val;
-
- val = GetVariable(space, name);
if (val == NULL)
return false; /* not set -> assume "off" */
if (pg_strcasecmp(val, "off") == 0)
@@ -59,35 +63,28 @@ GetVariableBool(VariableSpace space, const char *name)
return true;
}
-bool
-VariableEquals(VariableSpace space, const char name[], const char value[])
-{
- const char *var;
-
- var = GetVariable(space, name);
- return var && (strcmp(var, value) == 0);
-}
-
+/*
+ * Read numeric variable, or defaultval if it is not set, or faultval if its
+ * value is not a valid numeric string. If allowtrail is false, this will
+ * include the case where there are trailing characters after the number.
+ */
int
-GetVariableNum(VariableSpace space,
- const char name[],
- int defaultval,
- int faultval,
- bool allowtrail)
+ParseVariableNum(const char *val,
+ int defaultval,
+ int faultval,
+ bool allowtrail)
{
- const char *var;
int result;
- var = GetVariable(space, name);
- if (!var)
+ if (!val)
result = defaultval;
- else if (!var[0])
+ else if (!val[0])
result = faultval;
else
{
char *end;
- result = strtol(var, &end, 0);
+ result = strtol(val, &end, 0);
if (!allowtrail && *end)
result = faultval;
}
@@ -96,27 +93,16 @@ GetVariableNum(VariableSpace space,
}
int
-SwitchVariable(VariableSpace space, const char name[], const char *opt,...)
+GetVariableNum(VariableSpace space,
+ const char *name,
+ int defaultval,
+ int faultval,
+ bool allowtrail)
{
- int result;
- const char *var;
+ const char *val;
- var = GetVariable(space, name);
- if (var)
- {
- va_list args;
-
- va_start(args, opt);
- for (result = 1; opt && (strcmp(var, opt) != 0); result++)
- opt = va_arg(args, const char *);
- if (!opt)
- result = VAR_NOTFOUND;
- va_end(args);
- }
- else
- result = VAR_NOTSET;
-
- return result;
+ val = GetVariable(space, name);
+ return ParseVariableNum(val, defaultval, faultval, allowtrail);
}
void
@@ -129,7 +115,8 @@ PrintVariables(VariableSpace space)
for (ptr = space->next; ptr; ptr = ptr->next)
{
- printf("%s = '%s'\n", ptr->name, ptr->value);
+ if (ptr->value)
+ printf("%s = '%s'\n", ptr->name, ptr->value);
if (cancel_pressed)
break;
}
@@ -156,16 +143,62 @@ SetVariable(VariableSpace space, const char *name, const char *value)
{
if (strcmp(current->name, name) == 0)
{
- psql_assert(current->value);
- free(current->value);
+ /* found entry, so update */
+ if (current->value)
+ free(current->value);
current->value = pg_strdup(value);
+ if (current->assign_hook)
+ (*current->assign_hook) (current->value);
return true;
}
}
- previous->next = pg_calloc(1, sizeof *(previous->next));
- previous->next->name = pg_strdup(name);
- previous->next->value = pg_strdup(value);
+ /* not present, make new entry */
+ current = pg_malloc(sizeof *current);
+ current->name = pg_strdup(name);
+ current->value = pg_strdup(value);
+ current->assign_hook = NULL;
+ current->next = NULL;
+ previous->next = current;
+ return true;
+}
+
+/*
+ * This both sets a hook function, and calls it on the current value (if any)
+ */
+bool
+SetVariableAssignHook(VariableSpace space, const char *name, VariableAssignHook hook)
+{
+ struct _variable *current,
+ *previous;
+
+ if (!space)
+ return false;
+
+ if (strspn(name, VALID_VARIABLE_CHARS) != strlen(name))
+ return false;
+
+ for (previous = space, current = space->next;
+ current;
+ previous = current, current = current->next)
+ {
+ if (strcmp(current->name, name) == 0)
+ {
+ /* found entry, so update */
+ current->assign_hook = hook;
+ (*hook) (current->value);
+ return true;
+ }
+ }
+
+ /* not present, make new entry */
+ current = pg_malloc(sizeof *current);
+ current->name = pg_strdup(name);
+ current->value = NULL;
+ current->assign_hook = hook;
+ current->next = NULL;
+ previous->next = current;
+ (*hook) (NULL);
return true;
}
@@ -190,11 +223,18 @@ DeleteVariable(VariableSpace space, const char *name)
{
if (strcmp(current->name, name) == 0)
{
- psql_assert(current->value);
- previous->next = current->next;
- free(current->name);
- free(current->value);
- free(current);
+ if (current->value)
+ free(current->value);
+ current->value = NULL;
+ /* Physically delete only if no hook function to remember */
+ if (current->assign_hook)
+ (*current->assign_hook) (NULL);
+ else
+ {
+ previous->next = current->next;
+ free(current->name);
+ free(current);
+ }
return true;
}
}
diff --git a/src/bin/psql/variables.h b/src/bin/psql/variables.h
index 37abadb66ca..e4dce97a0a7 100644
--- a/src/bin/psql/variables.h
+++ b/src/bin/psql/variables.h
@@ -3,62 +3,57 @@
*
* Copyright (c) 2000-2006, PostgreSQL Global Development Group
*
- * $PostgreSQL: pgsql/src/bin/psql/variables.h,v 1.18 2006/03/05 15:58:52 momjian Exp $
+ * $PostgreSQL: pgsql/src/bin/psql/variables.h,v 1.19 2006/08/29 15:19:51 tgl Exp $
*/
-
-/*
- * This implements a sort of variable repository. One could also think of it
- * as cheap version of an associative array. In each one of these
- * datastructures you can store name/value pairs.
- */
-
#ifndef VARIABLES_H
#define VARIABLES_H
-#define VALID_VARIABLE_CHARS "abcdefghijklmnopqrstuvwxyz"\
- "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "0123456789_"
+/*
+ * This implements a sort of variable repository. One could also think of it
+ * as a cheap version of an associative array. In each one of these
+ * datastructures you can store name/value pairs. There can also be an
+ * "assign hook" function that is called whenever the variable's value is
+ * changed.
+ *
+ * An "unset" operation causes the hook to be called with newval == NULL.
+ *
+ * Note: if value == NULL then the variable is logically unset, but we are
+ * keeping the struct around so as not to forget about its hook function.
+ */
+typedef void (*VariableAssignHook) (const char *newval);
struct _variable
{
char *name;
char *value;
+ VariableAssignHook assign_hook;
struct _variable *next;
};
typedef struct _variable *VariableSpace;
+/* Allowed chars in a variable's name */
+#define VALID_VARIABLE_CHARS "abcdefghijklmnopqrstuvwxyz"\
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "0123456789_"
VariableSpace CreateVariableSpace(void);
const char *GetVariable(VariableSpace space, const char *name);
-bool GetVariableBool(VariableSpace space, const char *name);
-bool VariableEquals(VariableSpace space, const char name[], const char *opt);
-/* Read numeric variable, or defaultval if it is not set, or faultval if its
- * value is not a valid numeric string. If allowtrail is false, this will
- * include the case where there are trailing characters after the number.
- */
+bool ParseVariableBool(const char *val);
+int ParseVariableNum(const char *val,
+ int defaultval,
+ int faultval,
+ bool allowtrail);
int GetVariableNum(VariableSpace space,
- const char name[],
+ const char *name,
int defaultval,
int faultval,
bool allowtrail);
-
-/* Find value of variable among NULL-terminated list of alternative
- * options. Returns VAR_NOTSET if the variable was not set, VAR_NOTFOUND
- * if its value did not occur in the list of options, or the number of the
- * matching option. The first option is 1, the second is 2 and so on.
- */
-enum
-{
-VAR_NOTSET = 0, VAR_NOTFOUND = -1};
-int
-SwitchVariable(VariableSpace space, const char name[],
- const char *opt,...);
-
void PrintVariables(VariableSpace space);
bool SetVariable(VariableSpace space, const char *name, const char *value);
+bool SetVariableAssignHook(VariableSpace space, const char *name, VariableAssignHook hook);
bool SetVariableBool(VariableSpace space, const char *name);
bool DeleteVariable(VariableSpace space, const char *name);