Invent an assign-hook mechanism for psql variables similar to the one
authorTom Lane <tgl@sss.pgh.pa.us>
Tue, 29 Aug 2006 15:19:51 +0000 (15:19 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Tue, 29 Aug 2006 15:19:51 +0000 (15:19 +0000)
existing for backend GUC variables, and use this to eliminate repeated
fetching/parsing of psql variables in psql's inner loops.  In a trivial
test with lots of 'select 1;' commands, psql's CPU time went down almost
10%, although of course the effect on total elapsed time was much less.
Per discussion about how to ensure the upcoming FETCH_COUNT patch doesn't
cost any performance when not being used.

12 files changed:
src/bin/psql/command.c
src/bin/psql/common.c
src/bin/psql/copy.c
src/bin/psql/describe.c
src/bin/psql/input.c
src/bin/psql/large_obj.c
src/bin/psql/mainloop.c
src/bin/psql/prompt.c
src/bin/psql/settings.h
src/bin/psql/startup.c
src/bin/psql/variables.c
src/bin/psql/variables.h

index 971ad0c81613d6c77a7fd7094c41c91bc17fbd4e..28d5cef053604b84f7e141b59978776a6f5562d0 100644 (file)
@@ -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 <table ...> 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
index 7bdf6d15dcf170197e4d889b3e24cb6bd70130d3..3e9d23d1956be60df762e7e02e2d9ccd64873cbb 100644 (file)
@@ -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)
                {
index 2ec01af186bd82188c1bc7d7bfbb09ae7cccaa14..0d7cb5b4e004a328783464668b99be8166775110 100644 (file)
@@ -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);
index 49db39074d134193f55be8d7658fa47ba1da8339..b6fbc135806c3aa64720eef847dd94bf78fd7f50 100644 (file)
@@ -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"));
index 3441d7813e2729cb9fc28bda7a32740cc64a73d1..323ef573b4070bce5b405ec200410123b2ebacd0 100644 (file)
@@ -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);
 
index 778606c5f0eeecf55971383dd0852def6b0197d0..48d8931e9fcc928eee1d4d33cce7c074edacc923 100644 (file)
@@ -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);
index 730210b20c9e13c0950ac3a9b0dbe0f5a3f89f1f..519230b28aca263aaa73661bbeb0bb8da008279c 100644 (file)
@@ -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
index 981e8b6b58e3f2729aa408f31e8f541182ecf027..6bf86d1108c48bb865df4a501e4caa1f59eae62f 100644 (file)
@@ -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] = '^';
index a5c4a02be9e21984e85bcb1b2e64d06d00fa5ff7..9dc41e3bdfb5b206c086bb0d3d7cedcd6a5875c7 100644 (file)
@@ -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
 #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,14 +82,31 @@ typedef struct _psqlSettings
 
        bool            timing;                 /* enable timing of all queries */
 
-       PGVerbosity verbosity;          /* current error verbosity level */
        FILE       *logfile;            /* session log file handle */
-} PsqlSettings;
 
-extern PsqlSettings pset;
+       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;
 
-#define QUIET() (GetVariableBool(pset.vars, "QUIET"))
+extern PsqlSettings pset;
 
 
 #ifndef EXIT_SUCCESS
index 1a937e1eb47e63187af0c097feef721c07920224..8d3409bd19441ffa33d30656bf5cf3a1f74e3aee 100644 (file)
@@ -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);
+}
index e0e416e9e5a888ae9583dcc898e2fc4bd5d9e709..cac638e03935474039f84a89fdb7688b25def632 100644 (file)
@@ -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;
-
-       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;
+       const char *val;
 
-       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;
+               }
+       }
+
+       /* 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;
                }
        }
 
-       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 = 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;
                }
        }
index 37abadb66ca7bc423721d5a616203adc4019128a..e4dce97a0a7307a9add0d7af2fe65fda9dbfb76d 100644 (file)
@@ -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 $
  */
+#ifndef VARIABLES_H
+#define VARIABLES_H
 
 /*
  * 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.
+ * 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.
  */
-
-#ifndef VARIABLES_H
-#define VARIABLES_H
-
-#define VALID_VARIABLE_CHARS "abcdefghijklmnopqrstuvwxyz"\
-                                                        "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "0123456789_"
+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 <name> 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);