Update psql for some features of new FE/BE protocol. There is a
authorTom Lane
Sat, 28 Jun 2003 00:12:40 +0000 (00:12 +0000)
committerTom Lane
Sat, 28 Jun 2003 00:12:40 +0000 (00:12 +0000)
client-side AUTOCOMMIT mode now: '\set AUTOCOMMIT off' supports
SQL-spec commit behavior.  Get rid of LO_TRANSACTION hack --- the
LO operations just work now, using libpq's ability to track the
transaction status.  Add a VERBOSE variable to control verboseness
of error message display, and add a %T prompt-string code to show
current transaction-block status.  Superuser state display in the
prompt string correctly follows SET SESSION AUTHORIZATION commands.
Control-C works to get out of COPY IN state.

14 files changed:
doc/src/sgml/ref/psql-ref.sgml
doc/src/sgml/release.sgml
src/bin/psql/command.c
src/bin/psql/command.h
src/bin/psql/common.c
src/bin/psql/common.h
src/bin/psql/copy.c
src/bin/psql/copy.h
src/bin/psql/large_obj.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 8dd25d572e42fc77db3fc950b3765e6627142505..a3501e0bdab864d2387bf205b5a228e3c0e56ab3 100644 (file)
@@ -1,5 +1,5 @@
 
 
@@ -1200,13 +1200,6 @@ Tue Oct 26 21:40:57 CEST 1999
    OID.
    
    
-   
-   
-   See the description of the LO_TRANSACTION
-   variable for important information concerning all large object
-   operations.
-   
-   
    
       
 
@@ -1236,14 +1229,6 @@ lo_import 152801
    on the local file system, rather than the server's user and file
    system.
    
-
-   
-   
-   See the description of the LO_TRANSACTION
-   variable for important information concerning all large object
-   operations.
-   
-   
    
       
 
@@ -1274,13 +1259,6 @@ lo_import 152801
    OID.
    
    
-   
-   
-   See the description of the LO_TRANSACTION
-   variable for important information concerning all large object
-   operations.
-   
-   
    
       
 
@@ -1809,14 +1787,14 @@ bar
 
     
     If you call \set without a second argument, the
-    variable is simply set, but has no value. To unset (or delete) a
+    variable is set, with an empty string as value. To unset (or delete) a
     variable, use the command \unset.
     
 
     
     psql's internal variable names can
     consist of letters, numbers, and underscores in any order and any
-    number of them. A number of regular variables are treated specially
+    number of them. A number of these variables are treated specially
     by psql. They indicate certain option
     settings that can be changed at run time by altering the value of
     the variable or represent some state of the application. Although
@@ -1825,10 +1803,47 @@ bar
     really quickly. By convention, all specially treated variables
     consist of all upper-case letters (and possibly numbers and
     underscores). To ensure maximum compatibility in the future, avoid
-    such variables. A list of all specially treated variables follows.
+    using such variable names for your own purposes. A list of all specially
+    treated variables follows.
    
 
     
+      
+        AUTOCOMMIT
+   
+   
+   When on (the default), each SQL command is automatically
+   committed upon successful completion.  To postpone commit in this
+   mode, you must enter a BEGIN or START
+   TRANSACTION SQL command.  When off or unset, SQL
+   commands are not committed until you explicitly issue
+   COMMIT or END.  The autocommit-off
+   mode works by issuing an implicit BEGIN for you, just
+   before any command that is not already in a transaction block and
+   is not itself a BEGIN or other transaction-control
+   command.
+   
+
+   
+   
+    In autocommit-off mode, you must explicitly abandon any failed
+    transaction by entering ABORT or ROLLBACK.
+    Also keep in mind that if you exit the session
+    without committing, your work will be lost.
+   
+   
+
+   
+   
+    The autocommit-on mode is PostgreSQL's traditional
+    behavior, but autocommit-off is closer to the SQL spec.  If you
+    prefer autocommit-off, you may wish to set it in
+    your .psqlrc file.
+   
+   
+   
+      
+
       
         DBNAME
    
@@ -1846,11 +1861,11 @@ bar
    
    If set to all, all lines
    entered or from a script are written to the standard output
-   before they are parsed or executed. To specify this on program
+   before they are parsed or executed. To select this behavior on program
    start-up, use the switch . If set to
    queries,
    psql merely prints all queries as
-   they are sent to the server. The option for this is
+   they are sent to the server. The switch for this is
    .
    
    
@@ -1863,10 +1878,10 @@ bar
    When this variable is set and a backslash command queries the
    database, the query is first shown. This way you can study the
    PostgreSQL internals and provide
-   similar functionality in your own programs. If you set the
-   variable to the value noexec, the queries are
-   just shown but are not actually sent to the server and
-   executed.
+   similar functionality in your own programs. (To select this behavior
+   on program start-up, use the switch .)  If you set
+   the variable to the value noexec, the queries are
+   just shown but are not actually sent to the server and executed.
    
    
       
@@ -1962,39 +1977,6 @@ bar
    
       
 
-      
-        LO_TRANSACTION
-   
-   
-   If you use the PostgreSQL large
-   object interface to specially store data that does not fit into
-   one row, all the operations must be contained in a transaction
-   block. (See the documentation of the large object interface for
-   more information.) Since psql has no
-   way to tell if you already have a transaction in progress when
-   you call one of its internal commands
-   (\lo_export\lo_import,
-   \lo_unlink) it must take some arbitrary
-   action. This action could either be to roll back any transaction
-   that might already be in progress, or to commit any such
-   transaction, or to do nothing at all. In the last case you must
-   provide your own BEGIN/COMMIT block or the
-   results will be unpredictable (usually resulting in the desired
-   action's not being performed in any case).
-   
-
-   
-   To choose what you want to do you set this variable to one of
-   rollbackcommit, or
-   nothing. The default is to roll back the
-   transaction. If you just want to load one or a few objects this
-   is fine. However, if you intend to transfer many large objects,
-   it might be advisable to provide one explicit transaction block
-   around all commands.
-   
-   
-      
-
       
         ON_ERROR_STOP
    
@@ -2032,8 +2014,8 @@ bar
         PROMPT3
    
    
-   These specify what the prompt psql
-   issues is supposed to look like. See 
+   These specify what the prompts psql
+   issues should look like. See 
    linkend="APP-PSQL-prompting"
    endterm="APP-PSQL-prompting-title"> below.
    
@@ -2055,8 +2037,8 @@ bar
         SINGLELINE
    
    
-   This variable is set by the command line option
-   . You can unset or reset it at run time.
+   This variable is equivalent to the command line option
+   .
    
    
       
@@ -2082,6 +2064,17 @@ bar
    
       
 
+      
+        VERBOSE
+   
+   
+   This variable can be set to the values default,
+   verbose, or terse to control the verbosity
+   of error reports.
+   
+   
+      
+
     
 
    
@@ -2123,7 +2116,7 @@ testdb=> INSERT INTO my_table VALUES (:content);
 
 testdb=> \set content '\'' `sed -e "s/'/\\\\\\'/g" < my_file.txt` '\''
 
-    Observe the correct number of backslashes (6)! You can resolve it
+    Observe the correct number of backslashes (6)! It works
     this way: After psql has parsed this
     line, it passes sed -e "s/'/\\\'/g" < my_file.txt
     to the shell. The shell will do its own thing inside the double
@@ -2141,9 +2134,10 @@ testdb=> \set content '\'' `sed -e "s/'/\\\\\\'/g" < my_file.txt` '\'
 
     
     Since colons may legally appear in SQL commands, the following rule
-    applies: If the variable is not set, the character sequence
-    colon+name is not changed. In any case you can escape
-    a colon with a backslash to protect it from interpretation. (The
+    applies: the character sequence
+    :name is not changed unless name is the name
+    of a variable that is currently set. In any case you can escape
+    a colon with a backslash to protect it from substitution. (The
     colon syntax for variables is standard SQL for
     embedded query languages, such as ECPG.
     The colon syntax for array slices and type casts are
@@ -2171,7 +2165,7 @@ testdb=> \set content '\'' `sed -e "s/'/\\\\\\'/g" < my_file.txt` '\'
     
 
     
-    The value of the respective prompt variable is printed literally,
+    The value of the selected prompt variable is printed literally,
     except where a percent sign (%) is encountered.
     Depending on the next character, certain other text is substituted
     instead. Defined substitutions are:
@@ -2243,7 +2237,20 @@ testdb=> \set content '\'' `sed -e "s/'/\\\\\\'/g" < my_file.txt` '\'
    psql expects more input because the
    command wasn't terminated yet, because you are inside a
    /* ... */ comment, or because you are inside
-   a quote. In prompt 3 the sequence doesn't resolve to anything.
+   a quote. In prompt 3 the sequence doesn't produce anything.
+   
+   
+      
+
+      
+        %T
+   
+   
+   Transaction status: an empty string when not in a transaction
+   block, or * when in a transaction block, or
+   ! when in a failed transaction block, or ?
+   when the transaction state is indeterminate (for example, because
+   there is no connection).
    
    
       
@@ -2252,13 +2259,12 @@ testdb=> \set content '\'' `sed -e "s/'/\\\\\\'/g" < my_file.txt` '\'
         %digits
    
    
+   The character with the indicated numeric code is substituted.
    If digits starts
    with 0x the rest of the characters are
-   interpreted as a hexadecimal digit and the character with the
-   corresponding code is substituted. If the first digit is
-   0 the characters are interpreted as on octal
-   number and the corresponding character is substituted. Otherwise
-   a decimal number is assumed.
+   interpreted as hexadecimal; otherwise if the first digit is
+   0 the digits are interpreted as octal;
+   otherwise the digits are read as a decimal number.
    
    
       
@@ -2289,7 +2295,7 @@ testdb=> \set content '\'' `sed -e "s/'/\\\\\\'/g" < my_file.txt` '\'
     
 
     To insert a percent sign into your prompt, write
-    %%. The default prompts are equivalent to
+    %%. The default prompts are
     '%/%R%# ' for prompts 1 and 2, and
     '>> ' for prompt 3.
     
@@ -2473,17 +2479,6 @@ Field separator is "oo".
       
       
 
-      
-      
-      Pressing ControlC
-      during a copy in (data sent to
-      the server) doesn't show the most ideal of behaviors. If you get a
-      message such as COPY state must be terminated
-      first, simply reset the connection by entering \c
-      - -.
-      
-      
-
     
  
 
index cc03ae9cbe3a11ee2978ac1dbc9525cbbca2791b..188f2c8341b1ca9b716624bf84cad7e8139ce34d 100644 (file)
@@ -1,5 +1,5 @@
 
 
 
@@ -31,7 +31,7 @@ Functional indexes have been generalized into expressional indexes
 CHAR(n) to TEXT conversion automatically strips trailing blanks
 Pattern matching operations can use indexes regardless of locale
 New frontend/backend protocol supports many long-requested features
-SET AUTOCOMMIT TO OFF is no longer supported
+SET AUTOCOMMIT TO OFF is no longer supported; psql has an AUTOCOMMIT variable
 Reimplementation of NUMERIC datatype for more speed
 New regular expression package, many more regexp features (most of Perl5)
 Can now do EXPLAIN ... EXECUTE to see plan used for a prepared query
index fd6193dd2438dd8ec9295f3cf65abddd340897ac..c105f0bd9d84885837d69e7391d14728f0f2190e 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright 2000-2002 by PostgreSQL Global Development Group
  *
- * $Header: /cvsroot/pgsql/src/bin/psql/command.c,v 1.96 2003/05/14 03:26:02 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/bin/psql/command.c,v 1.97 2003/06/28 00:12:40 tgl Exp $
  */
 #include "postgres_fe.h"
 #include "command.h"
@@ -457,20 +457,30 @@ exec_command(const char *cmd,
        char       *encoding = scan_option(&string, OT_NORMAL, NULL, false);
 
        if (!encoding)
-           /* show encoding */
+       {
+           /* show encoding --- first check for change sent from server */
+           if (pset.encoding != PQclientEncoding(pset.db) &&
+               PQclientEncoding(pset.db) >= 0)
+           {
+               pset.encoding = PQclientEncoding(pset.db);
+               pset.popt.topt.encoding = pset.encoding;
+               SetVariable(pset.vars, "ENCODING",
+                           pg_encoding_to_char(pset.encoding));
+           }
            puts(pg_encoding_to_char(pset.encoding));
+       }
        else
        {
            /* set encoding */
            if (PQsetClientEncoding(pset.db, encoding) == -1)
                psql_error("%s: invalid encoding name or conversion procedure not found\n", encoding);
-
            else
            {
                /* save encoding info into psql internal data */
                pset.encoding = PQclientEncoding(pset.db);
-               pset.popt.topt.encoding = PQclientEncoding(pset.db);
-               SetVariable(pset.vars, "ENCODING", pg_encoding_to_char(pset.encoding));
+               pset.popt.topt.encoding = pset.encoding;
+               SetVariable(pset.vars, "ENCODING",
+                           pg_encoding_to_char(pset.encoding));
            }
            free(encoding);
        }
@@ -694,7 +704,13 @@ exec_command(const char *cmd,
                free(opt);
            }
 
-           if (!SetVariable(pset.vars, opt0, newval))
+           if (SetVariable(pset.vars, opt0, newval))
+           {
+               /* Check for special variables */
+               if (strcmp(opt0, "VERBOSE") == 0)
+                   SyncVerboseVariable();
+           }
+           else
            {
                psql_error("\\%s: error\n", cmd);
                success = false;
@@ -1327,11 +1343,7 @@ do_connect(const char *new_dbname, const char *new_user)
    bool        success = false;
 
    /* Delete variables (in case we fail before setting them anew) */
-   SetVariable(pset.vars, "DBNAME", NULL);
-   SetVariable(pset.vars, "USER", NULL);
-   SetVariable(pset.vars, "HOST", NULL);
-   SetVariable(pset.vars, "PORT", NULL);
-   SetVariable(pset.vars, "ENCODING", NULL);
+   UnsyncVariables();
 
    /* If dbname is "" then use old name, else new one (even if NULL) */
    if (oldconn && new_dbname && PQdb(oldconn) && strcmp(new_dbname, "") == 0)
@@ -1429,51 +1441,75 @@ do_connect(const char *new_dbname, const char *new_user)
    }
 
    PQsetNoticeProcessor(pset.db, NoticeProcessor, NULL);
-   pset.encoding = PQclientEncoding(pset.db);
-   pset.popt.topt.encoding = PQclientEncoding(pset.db);
 
    /* Update variables */
+   SyncVariables();
+
+   return success;
+}
+
+
+/*
+ * SyncVariables
+ *
+ * Make psql's internal variables agree with connection state upon
+ * establishing a new connection.
+ */
+void
+SyncVariables(void)
+{
+   /* get stuff from connection */
+   pset.encoding = PQclientEncoding(pset.db);
+   pset.popt.topt.encoding = pset.encoding;
+
    SetVariable(pset.vars, "DBNAME", PQdb(pset.db));
    SetVariable(pset.vars, "USER", PQuser(pset.db));
    SetVariable(pset.vars, "HOST", PQhost(pset.db));
    SetVariable(pset.vars, "PORT", PQport(pset.db));
    SetVariable(pset.vars, "ENCODING", pg_encoding_to_char(pset.encoding));
 
-   pset.issuper = test_superuser(PQuser(pset.db));
-
-   return success;
+   /* send stuff to it, too */
+   SyncVerboseVariable();
 }
 
-
-
 /*
- * Test if the given user is a database superuser.
- * (Is used to set up the prompt right.)
+ * UnsyncVariables
+ *
+ * Clear variables that should be not be set when there is no connection.
  */
-bool
-test_superuser(const char *username)
+void
+UnsyncVariables(void)
 {
-   PGresult   *res;
-   PQExpBufferData buf;
-   bool        answer;
-
-   if (!username)
-       return false;
-
-   initPQExpBuffer(&buf);
-   printfPQExpBuffer(&buf, "SELECT usesuper FROM pg_catalog.pg_user WHERE usename = '%s'", username);
-   res = PSQLexec(buf.data, true);
-   termPQExpBuffer(&buf);
-
-   answer =
-       (res && PQntuples(res) > 0 && PQnfields(res) > 0
-        && !PQgetisnull(res, 0, 0)
-        && PQgetvalue(res, 0, 0)
-        && strcmp(PQgetvalue(res, 0, 0), "t") == 0);
-   PQclear(res);
-   return answer;
+   SetVariable(pset.vars, "DBNAME", NULL);
+   SetVariable(pset.vars, "USER", NULL);
+   SetVariable(pset.vars, "HOST", NULL);
+   SetVariable(pset.vars, "PORT", NULL);
+   SetVariable(pset.vars, "ENCODING", NULL);
 }
 
+/*
+ * Update connection state from VERBOSE variable
+ */
+void
+SyncVerboseVariable(void)
+{
+   switch (SwitchVariable(pset.vars, "VERBOSE",
+                          "default", "terse", "verbose", NULL))
+   {
+       case 1:                 /* default */
+           PQsetErrorVerbosity(pset.db, PQERRORS_DEFAULT);
+           break;
+       case 2:                 /* terse */
+           PQsetErrorVerbosity(pset.db, PQERRORS_TERSE);
+           break;
+       case 3:                 /* verbose */
+           PQsetErrorVerbosity(pset.db, PQERRORS_VERBOSE);
+           break;
+       default:                /* not set or unrecognized value */
+           PQsetErrorVerbosity(pset.db, PQERRORS_DEFAULT);
+           break;
+   }
+}
 
 
 /*
index f74be3a851094d885bffc0bcc4354f4a2d7cbb3c..ead859cd32c83d2d49940d35da47b87e2e9e4a3d 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright 2000 by PostgreSQL Global Development Group
  *
- * $Header: /cvsroot/pgsql/src/bin/psql/command.h,v 1.14 2002/03/27 19:16:13 petere Exp $
+ * $Header: /cvsroot/pgsql/src/bin/psql/command.h,v 1.15 2003/06/28 00:12:40 tgl Exp $
  */
 #ifndef COMMAND_H
 #define COMMAND_H
@@ -26,20 +26,22 @@ typedef enum _backslashResult
 } backslashResult;
 
 
-backslashResult HandleSlashCmds(const char *line,
+extern backslashResult HandleSlashCmds(const char *line,
                PQExpBuffer query_buf,
                const char **end_of_cmd,
                volatile int *paren_level);
 
-int
-           process_file(char *filename);
+extern int process_file(char *filename);
 
-bool
-           test_superuser(const char *username);
-
-bool do_pset(const char *param,
+extern bool do_pset(const char *param,
        const char *value,
        printQueryOpt *popt,
        bool quiet);
 
+extern void SyncVariables(void);
+
+extern void UnsyncVariables(void);
+
+extern void SyncVerboseVariable(void);
+
 #endif   /* COMMAND_H */
index 84dc32bd5ca8e6fe6b45bf7d38689368b5032660..96f3c2810075b16ff975880943931509759a95ca 100644 (file)
@@ -3,11 +3,12 @@
  *
  * Copyright 2000 by PostgreSQL Global Development Group
  *
- * $Header: /cvsroot/pgsql/src/bin/psql/common.c,v 1.64 2003/06/12 08:15:28 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/bin/psql/common.c,v 1.65 2003/06/28 00:12:40 tgl Exp $
  */
 #include "postgres_fe.h"
 #include "common.h"
 
+#include 
 #include 
 #include 
 #ifndef HAVE_STRDUP
@@ -29,6 +30,7 @@
 
 #include "settings.h"
 #include "variables.h"
+#include "command.h"
 #include "copy.h"
 #include "prompt.h"
 #include "print.h"
@@ -55,6 +57,10 @@ typedef struct _timeb TimevalStruct;
 
 extern bool prompt_state;
 
+
+static bool is_transact_command(const char *query);
+
+
 /*
  * "Safe" wrapper around strdup()
  */
@@ -195,8 +201,8 @@ handle_sigint(SIGNAL_ARGS)
 {
    int         save_errno = errno;
 
-   /* Don't muck around if copying in or prompting for a password. */
-   if ((copy_in_state && pset.cur_cmd_interactive) || prompt_state)
+   /* Don't muck around if prompting for a password. */
+   if (prompt_state)
        return;
 
    if (cancelConn == NULL)
@@ -262,11 +268,7 @@ CheckConnection()
            PQfinish(pset.db);
            pset.db = NULL;
            ResetCancelConn();
-           SetVariable(pset.vars, "DBNAME", NULL);
-           SetVariable(pset.vars, "HOST", NULL);
-           SetVariable(pset.vars, "PORT", NULL);
-           SetVariable(pset.vars, "USER", NULL);
-           SetVariable(pset.vars, "ENCODING", NULL);
+           UnsyncVariables();
        }
        else
            fputs(gettext("Succeeded.\n"), stderr);
@@ -304,8 +306,8 @@ void ResetCancelConn(void)
  * AcceptResult
  *
  * Checks whether a result is valid, giving an error message if necessary;
- * (re)sets copy_in_state and cancelConn as needed, and ensures that the
- * connection to the backend is still up.
+ * resets cancelConn as needed, and ensures that the connection to the backend
+ * is still up.
  *
  * Returns true for valid result, false for error state.
  */
@@ -322,12 +324,9 @@ AcceptResult(const PGresult *result)
    }
    else switch (PQresultStatus(result))
    {
-     case PGRES_COPY_IN:
-        copy_in_state = true;
-        break;
-
      case PGRES_COMMAND_OK:
      case PGRES_TUPLES_OK:
+     case PGRES_COPY_IN:
         /* Fine, do nothing */
         break;
 
@@ -358,18 +357,15 @@ AcceptResult(const PGresult *result)
  * This is the way to send "backdoor" queries (those not directly entered
  * by the user). It is subject to -E but not -e.
  *
- * If the given querystring generates multiple PGresults, normally the last
- * one is returned to the caller.  However, if ignore_command_ok is TRUE,
- * then PGresults with status PGRES_COMMAND_OK are ignored.  This is intended
- * mainly to allow locutions such as "begin; select ...; commit".
+ * In autocommit-off mode, a new transaction block is started if start_xact
+ * is true; nothing special is done when start_xact is false.  Typically,
+ * start_xact = false is used for SELECTs and explicit BEGIN/COMMIT commands.
  */
 PGresult *
-PSQLexec(const char *query, bool ignore_command_ok)
+PSQLexec(const char *query, bool start_xact)
 {
-   PGresult   *res = NULL;
-   PGresult   *newres;
+   PGresult   *res;
    int echo_hidden;
-   ExecStatusType rstatus;
 
    if (!pset.db)
    {
@@ -378,50 +374,40 @@ PSQLexec(const char *query, bool ignore_command_ok)
    }
 
    echo_hidden = SwitchVariable(pset.vars, "ECHO_HIDDEN", "noexec", NULL);
-   if (echo_hidden != var_notset)
+   if (echo_hidden != VAR_NOTSET)
    {
        printf("********* QUERY **********\n"
               "%s\n"
               "**************************\n\n", query);
        fflush(stdout);
 
-       if (echo_hidden == 1)
-       return NULL;
+       if (echo_hidden == 1)   /* noexec? */
+           return NULL;
    }
 
-   /* discard any uneaten results of past queries */
-   while ((newres = PQgetResult(pset.db)) != NULL)
-       PQclear(newres);
-
    SetCancelConn();
-   if (!PQsendQuery(pset.db, query))
-   {
-     psql_error("%s", PQerrorMessage(pset.db));
-     ResetCancelConn();
-     return NULL;
-   }
-
-   rstatus = PGRES_EMPTY_QUERY;
 
-   while (rstatus != PGRES_COPY_IN &&
-            rstatus != PGRES_COPY_OUT &&
-            (newres = PQgetResult(pset.db)))
+   if (start_xact && PQtransactionStatus(pset.db) == PQTRANS_IDLE &&
+       !GetVariableBool(pset.vars, "AUTOCOMMIT"))
+   {
+       res = PQexec(pset.db, "BEGIN");
+       if (PQresultStatus(res) != PGRES_COMMAND_OK)
        {
-           rstatus = PQresultStatus(newres);
-       if (!ignore_command_ok || rstatus != PGRES_COMMAND_OK)
-           {
-         PGresult *tempRes = res;
-           res = newres;
-         newres = tempRes;
+           psql_error("%s", PQerrorMessage(pset.db));
+           PQclear(res);
+           ResetCancelConn();
+           return NULL;
        }
-       PQclear(newres);
+       PQclear(res);
    }
 
+   res = PQexec(pset.db, query);
+
    if (!AcceptResult(res) && res)
    {
        PQclear(res);
        res = NULL;
-       }
+   }
 
    return res;
 }
@@ -613,6 +599,21 @@ SendQuery(const char *query)
 
    SetCancelConn();
 
+   if (PQtransactionStatus(pset.db) == PQTRANS_IDLE &&
+       !GetVariableBool(pset.vars, "AUTOCOMMIT") &&
+       !is_transact_command(query))
+   {
+       results = PQexec(pset.db, "BEGIN");
+       if (PQresultStatus(results) != PGRES_COMMAND_OK)
+       {
+           psql_error("%s", PQerrorMessage(pset.db));
+           PQclear(results);
+           ResetCancelConn();
+           return false;
+       }
+       PQclear(results);
+   }
+
    if (pset.timing)
        GETTIMEOFDAY(&before);
    results = PQexec(pset.db, query);
@@ -626,6 +627,68 @@ SendQuery(const char *query)
    return OK;
 }
 
+/*
+ * check whether a query string begins with BEGIN/COMMIT/ROLLBACK/START XACT
+ */
+static bool
+is_transact_command(const char *query)
+{
+   int     wordlen;
+
+   /*
+    * First we must advance over any whitespace and comments.
+    */
+   while (*query)
+   {
+       if (isspace((unsigned char) *query))
+           query++;
+       else if (query[0] == '-' && query[1] == '-')
+       {
+           query += 2;
+           while (*query && *query != '\n')
+               query++;
+       }
+       else if (query[0] == '/' && query[1] == '*')
+       {
+           query += 2;
+           while (*query)
+           {
+               if (query[0] == '*' && query[1] == '/')
+               {
+                   query += 2;
+                   break;
+               }
+               else
+                   query++;
+           }
+       }
+       else
+           break;              /* found first token */
+   }
+
+   /*
+    * Check word length ("beginx" is not "begin").
+    */
+   wordlen = 0;
+   while (isalpha((unsigned char) query[wordlen]))
+       wordlen++;
+
+   if (wordlen == 5 && strncasecmp(query, "begin", 5) == 0)
+       return true;
+   if (wordlen == 6 && strncasecmp(query, "commit", 6) == 0)
+       return true;
+   if (wordlen == 8 && strncasecmp(query, "rollback", 8) == 0)
+       return true;
+   if (wordlen == 5 && strncasecmp(query, "abort", 5) == 0)
+       return true;
+   if (wordlen == 3 && strncasecmp(query, "end", 3) == 0)
+       return true;
+   if (wordlen == 5 && strncasecmp(query, "start", 5) == 0)
+       return true;
+
+   return false;
+}
+
 
 char parse_char(char **buf)
 {
@@ -637,3 +700,24 @@ char parse_char(char **buf)
 }
 
 
+/*
+ * Test if the current user is a database superuser.
+ *
+ * Note: this will correctly detect superuserness only with a protocol-3.0
+ * or newer backend; otherwise it will always say "false".
+ */
+bool
+is_superuser(void)
+{
+   const char *val;
+
+   if (!pset.db)
+       return false;
+
+   val = PQparameterStatus(pset.db, "is_superuser");
+
+   if (val && strcmp(val, "on") == 0)
+       return true;
+
+   return false;
+}
index d29b317d23a53583dccddce96cc07688b76209d3..2f38ea371b0932fe9ea3e532aeb0ee81136d315b 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright 2000 by PostgreSQL Global Development Group
  *
- * $Header: /cvsroot/pgsql/src/bin/psql/common.h,v 1.25 2003/03/20 15:44:17 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/bin/psql/common.h,v 1.26 2003/06/28 00:12:40 tgl Exp $
  */
 #ifndef COMMON_H
 #define COMMON_H
@@ -34,10 +34,12 @@ extern void ResetCancelConn(void);
 extern void handle_sigint(SIGNAL_ARGS);
 #endif   /* not WIN32 */
 
-extern PGresult *PSQLexec(const char *query, bool ignore_command_ok);
+extern PGresult *PSQLexec(const char *query, bool start_xact);
 
 extern bool SendQuery(const char *query);
 
+extern bool is_superuser(void);
+
 /* sprompt.h */
 extern char *simple_prompt(const char *prompt, int maxlen, bool echo);
 
index 00664ea05d05a379e4f1ea9865c98c061864ace5..11f66c6897857aee36888f296aad202d92f04fce 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright 2000 by PostgreSQL Global Development Group
  *
- * $Header: /cvsroot/pgsql/src/bin/psql/copy.c,v 1.29 2003/03/20 06:00:12 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/bin/psql/copy.c,v 1.30 2003/06/28 00:12:40 tgl Exp $
  */
 #include "postgres_fe.h"
 #include "copy.h"
@@ -32,8 +32,6 @@
 #define    S_ISDIR(mode)    __S_ISTYPE((mode), S_IFDIR)
 #endif
 
-bool       copy_in_state;
-
 /*
  * parse_slash_copy
  * -- parses \copy command line
@@ -395,7 +393,7 @@ do_copy(const char *args)
        return false;
    }
 
-   result = PSQLexec(query.data, false);
+   result = PSQLexec(query.data, true);
    termPQExpBuffer(&query);
 
    switch (PQresultStatus(result))
@@ -506,10 +504,6 @@ handleCopyIn(PGconn *conn, FILE *copystream, const char *prompt)
    int         ret;
    unsigned int linecount = 0;
 
-#ifdef USE_ASSERT_CHECKING
-   assert(copy_in_state);
-#endif
-
    if (prompt)                 /* disable prompt if not interactive */
    {
        if (!isatty(fileno(copystream)))
@@ -563,7 +557,6 @@ handleCopyIn(PGconn *conn, FILE *copystream, const char *prompt)
        linecount++;
    }
    ret = !PQendcopy(conn);
-   copy_in_state = false;
    pset.lineno += linecount;
    return ret;
 }
index c22146707ae099453baba9413464057c9e84b11a..8f5c70d43c08d492a65591c50bae269ebae7b53a 100644 (file)
@@ -3,14 +3,13 @@
  *
  * Copyright 2000 by PostgreSQL Global Development Group
  *
- * $Header: /cvsroot/pgsql/src/bin/psql/copy.h,v 1.11 2001/10/28 06:25:58 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/bin/psql/copy.h,v 1.12 2003/06/28 00:12:40 tgl Exp $
  */
 #ifndef COPY_H
 #define COPY_H
 
 #include "libpq-fe.h"
 
-extern bool copy_in_state;
 
 /* handler for \copy */
 bool       do_copy(const char *args);
index 3d0b3a6eb96f31567427a092d4884f12ed515f77..a565d20478479e7ff3e2e6496c99c43df4794068 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright 2000-2002 by PostgreSQL Global Development Group
  *
- * $Header: /cvsroot/pgsql/src/bin/psql/large_obj.c,v 1.26 2003/06/27 16:55:23 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/bin/psql/large_obj.c,v 1.27 2003/06/28 00:12:40 tgl Exp $
  */
 #include "postgres_fe.h"
 #include "large_obj.h"
 
 
 /*
- * Since all large object ops must be in a transaction, we must do some magic
- * here. You can set the variable lo_transaction to one of commit|rollback|
- * nothing to get your favourite behaviour regarding any transaction in
- * progress. Rollback is default.
+ * Prepare to do a large-object operation.  We *must* be inside a transaction
+ * block for all these operations, so start one if needed.
+ *
+ * Returns TRUE if okay, FALSE if failed.  *own_transaction is set to indicate
+ * if we started our own transaction or not.
  */
+static bool
+start_lo_xact(const char *operation, bool *own_transaction)
+{
+   PGTransactionStatusType tstatus;
+   PGresult   *res;
 
-static char notice[80];
+   *own_transaction = false;
 
-static void
-_my_notice_handler(void *arg, const char *message)
-{
-   (void) arg;
-   strncpy(notice, message, 79);
-   notice[79] = '\0';
-}
+   if (!pset.db)
+   {
+       psql_error("%s: not connected to a database\n", operation);
+       return false;
+   }
+
+   tstatus = PQtransactionStatus(pset.db);
+
+   switch (tstatus)
+   {
+       case PQTRANS_IDLE:
+           /* need to start our own xact */
+           if (!(res = PSQLexec("BEGIN", false)))
+               return false;
+           PQclear(res);
+           *own_transaction = true;
+           break;
+       case PQTRANS_INTRANS:
+           /* use the existing xact */
+           break;
+       case PQTRANS_INERROR:
+           psql_error("%s: current transaction is aborted\n", operation);
+           return false;
+       default:
+           psql_error("%s: unknown transaction status\n", operation);
+           return false;
+   }
 
+   return true;
+}
 
+/*
+ * Clean up after a successful LO operation
+ */
 static bool
-handle_transaction(void)
+finish_lo_xact(const char *operation, bool own_transaction)
 {
    PGresult   *res;
-   bool        commit = false;
-   PQnoticeProcessor old_notice_hook;
 
-   switch (SwitchVariable(pset.vars, "LO_TRANSACTION", 
-                          "nothing", 
-                          "commit", 
-                          NULL))
+   if (own_transaction &&
+       GetVariableBool(pset.vars, "AUTOCOMMIT"))
    {
-       case 1:                 /* nothing */
-           return true;
-       case 2:                 /* commit */
-           commit = true;
-           break;
+       /* close out our own xact */
+       if (!(res = PSQLexec("COMMIT", false)))
+       {
+           res = PSQLexec("ROLLBACK", false);
+           PQclear(res);
+           return false;
+       }
+       PQclear(res);
    }
 
-   notice[0] = '\0';
-   old_notice_hook = PQsetNoticeProcessor(pset.db, _my_notice_handler, NULL);
+   return true;
+}
 
-   res = PSQLexec(commit ? "COMMIT" : "ROLLBACK", false);
-   if (!res)
-       return false;
+/*
+ * Clean up after a failed LO operation
+ */
+static bool
+fail_lo_xact(const char *operation, bool own_transaction)
+{
+   PGresult   *res;
 
-   if (notice[0])
+   if (own_transaction &&
+       GetVariableBool(pset.vars, "AUTOCOMMIT"))
    {
-       if ((!commit && strcmp(notice, "WARNING:  ROLLBACK: no transaction in progress\n") != 0) ||
-           (commit && strcmp(notice, "WARNING:  COMMIT: no transaction in progress\n") != 0))
-           fputs(notice, stderr);
-   }
-   else if (!QUIET())
-   {
-       if (commit)
-           puts(gettext("Warning: Your transaction in progress has been committed."));
-       else
-           puts(gettext("Warning: Your transaction in progress has been rolled back."));
+       /* close out our own xact */
+       res = PSQLexec("ROLLBACK", false);
+       PQclear(res);
    }
 
-   PQsetNoticeProcessor(pset.db, old_notice_hook, NULL);
-   PQclear(res);
-   return true;
+   return false;               /* always */
 }
 
 
-
 /*
  * do_lo_export()
  *
@@ -92,53 +117,22 @@ handle_transaction(void)
 bool
 do_lo_export(const char *loid_arg, const char *filename_arg)
 {
-   PGresult   *res;
    int         status;
    bool        own_transaction;
 
-   own_transaction = !VariableEquals(pset.vars, "LO_TRANSACTION", "nothing");
-
-   if (!pset.db)
-   {
-       psql_error("\\lo_export: not connected to a database\n");
+   if (!start_lo_xact("\\lo_export", &own_transaction))
        return false;
-   }
-
-   if (own_transaction)
-   {
-       if (!handle_transaction())
-           return false;
-
-       if (!(res = PSQLexec("BEGIN", false)))
-           return false;
-
-       PQclear(res);
-   }
 
    status = lo_export(pset.db, atooid(loid_arg), filename_arg);
    if (status != 1)
    {                           /* of course this status is documented
                                 * nowhere :( */
        fputs(PQerrorMessage(pset.db), stderr);
-       if (own_transaction)
-       {
-           res = PQexec(pset.db, "ROLLBACK");
-           PQclear(res);
-       }
-       return false;
+       return fail_lo_xact("\\lo_export", own_transaction);
    }
 
-   if (own_transaction)
-   {
-       if (!(res = PSQLexec("COMMIT", false)))
-       {
-           res = PQexec(pset.db, "ROLLBACK");
-           PQclear(res);
-           return false;
-       }
-
-       PQclear(res);
-   }
+   if (!finish_lo_xact("\\lo_export", own_transaction))
+       return false;
 
    fprintf(pset.queryFout, "lo_export\n");
 
@@ -146,7 +140,6 @@ do_lo_export(const char *loid_arg, const char *filename_arg)
 }
 
 
-
 /*
  * do_lo_import()
  *
@@ -161,41 +154,20 @@ do_lo_import(const char *filename_arg, const char *comment_arg)
    unsigned int i;
    bool        own_transaction;
 
-   own_transaction = !VariableEquals(pset.vars, "LO_TRANSACTION", "nothing");
-
-   if (!pset.db)
-   {
-       psql_error("\\lo_import: not connected to a database\n");
+   if (!start_lo_xact("\\lo_import", &own_transaction))
        return false;
-   }
-
-   if (own_transaction)
-   {
-       if (!handle_transaction())
-           return false;
-
-       if (!(res = PSQLexec("BEGIN", false)))
-           return false;
-
-       PQclear(res);
-   }
 
    loid = lo_import(pset.db, filename_arg);
    if (loid == InvalidOid)
    {
        fputs(PQerrorMessage(pset.db), stderr);
-       if (own_transaction)
-       {
-           res = PQexec(pset.db, "ROLLBACK");
-           PQclear(res);
-       }
-       return false;
+       return fail_lo_xact("\\lo_import", own_transaction);
    }
 
    /* insert description if given */
    /* XXX don't try to hack pg_description if not superuser */
    /* XXX ought to replace this with some kind of COMMENT command */
-   if (comment_arg && pset.issuper)
+   if (comment_arg && is_superuser())
    {
        char       *cmdbuf;
        char       *bufptr;
@@ -203,14 +175,7 @@ do_lo_import(const char *filename_arg, const char *comment_arg)
 
        cmdbuf = malloc(slen * 2 + 256);
        if (!cmdbuf)
-       {
-           if (own_transaction)
-           {
-               res = PQexec(pset.db, "ROLLBACK");
-               PQclear(res);
-           }
-           return false;
-       }
+           return fail_lo_xact("\\lo_import", own_transaction);
        sprintf(cmdbuf,
                "INSERT INTO pg_catalog.pg_description VALUES ('%u', "
                "'pg_catalog.pg_largeobject'::regclass, "
@@ -227,31 +192,16 @@ do_lo_import(const char *filename_arg, const char *comment_arg)
 
        if (!(res = PSQLexec(cmdbuf, false)))
        {
-           if (own_transaction)
-           {
-               res = PQexec(pset.db, "ROLLBACK");
-               PQclear(res);
-           }
            free(cmdbuf);
-           return false;
+           return fail_lo_xact("\\lo_import", own_transaction);
        }
 
        PQclear(res);
        free(cmdbuf);
    }
 
-   if (own_transaction)
-   {
-       if (!(res = PSQLexec("COMMIT", false)))
-       {
-           res = PQexec(pset.db, "ROLLBACK");
-           PQclear(res);
-           return false;
-       }
-
-       PQclear(res);
-   }
-
+   if (!finish_lo_xact("\\lo_import", own_transaction))
+       return false;
 
    fprintf(pset.queryFout, "lo_import %u\n", loid);
    sprintf(oidbuf, "%u", loid);
@@ -261,7 +211,6 @@ do_lo_import(const char *filename_arg, const char *comment_arg)
 }
 
 
-
 /*
  * do_lo_unlink()
  *
@@ -276,69 +225,32 @@ do_lo_unlink(const char *loid_arg)
    char        buf[256];
    bool        own_transaction;
 
-   own_transaction = !VariableEquals(pset.vars, "LO_TRANSACTION", "nothing");
-
-   if (!pset.db)
-   {
-       psql_error("\\lo_unlink: not connected to a database\n");
+   if (!start_lo_xact("\\lo_unlink", &own_transaction))
        return false;
-   }
-
-   if (own_transaction)
-   {
-       if (!handle_transaction())
-           return false;
-
-       if (!(res = PSQLexec("BEGIN", false)))
-           return false;
-
-       PQclear(res);
-   }
 
    status = lo_unlink(pset.db, loid);
    if (status == -1)
    {
        fputs(PQerrorMessage(pset.db), stderr);
-       if (own_transaction)
-       {
-           res = PQexec(pset.db, "ROLLBACK");
-           PQclear(res);
-       }
-       return false;
+       return fail_lo_xact("\\lo_unlink", own_transaction);
    }
 
    /* remove the comment as well */
    /* XXX don't try to hack pg_description if not superuser */
    /* XXX ought to replace this with some kind of COMMENT command */
-   if (pset.issuper)
+   if (is_superuser())
    {
        snprintf(buf, sizeof(buf),
                 "DELETE FROM pg_catalog.pg_description WHERE objoid = '%u' "
                 "AND classoid = 'pg_catalog.pg_largeobject'::regclass",
                 loid);
        if (!(res = PSQLexec(buf, false)))
-       {
-           if (own_transaction)
-           {
-               res = PQexec(pset.db, "ROLLBACK");
-               PQclear(res);
-           }
-           return false;
-       }
-       PQclear(res);
-   }
-
-   if (own_transaction)
-   {
-       if (!(res = PSQLexec("COMMIT", false)))
-       {
-           res = PQexec(pset.db, "ROLLBACK");
-           PQclear(res);
-           return false;
-       }
+           return fail_lo_xact("\\lo_unlink", own_transaction);
        PQclear(res);
    }
 
+   if (!finish_lo_xact("\\lo_unlink", own_transaction))
+       return false;
 
    fprintf(pset.queryFout, "lo_unlink %u\n", loid);
 
index f9d66b752ecd7f9b1dba18d1de04198e8193107d..0df16d4b0c6b3a86eb73ad57fd6bf6bc0785f3fd 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright 2000 by PostgreSQL Global Development Group
  *
- * $Header: /cvsroot/pgsql/src/bin/psql/prompt.c,v 1.25 2003/04/04 20:42:13 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/bin/psql/prompt.c,v 1.26 2003/06/28 00:12:40 tgl Exp $
  */
 #include "postgres_fe.h"
 #include "prompt.h"
@@ -44,6 +44,7 @@
  *         or a ! if session is not connected to a database;
  *     in prompt2 -, *, ', or ";
  *     in prompt3 nothing
+ * %T - transaction status: empty, *, !, ? (unknown or no connection)
  * %? - the error code of the last query (not yet implemented)
  * %% - a percent sign
  *
@@ -172,7 +173,7 @@ get_prompt(promptStatus_t status)
                case '8':
                case '9':
                    *buf = parse_char((char **)&p);
-                       break;
+                   break;
 
                case 'R':
                    switch (status)
@@ -204,20 +205,39 @@ get_prompt(promptStatus_t status)
                            buf[0] = '\0';
                            break;
                    }
+                   break;
+
+               case 'T':
+                   if (!pset.db)
+                       buf[0] = '?';
+                   else switch (PQtransactionStatus(pset.db))
+                   {
+                       case PQTRANS_IDLE:
+                           buf[0] = '\0';
+                           break;
+                       case PQTRANS_ACTIVE:
+                       case PQTRANS_INTRANS:
+                           buf[0] = '*';
+                           break;
+                       case PQTRANS_INERROR:
+                           buf[0] = '!';
+                           break;
+                       default:
+                           buf[0] = '?';
+                           break;
+                   }
+                   break;
 
                case '?':
                    /* not here yet */
                    break;
 
                case '#':
-                   {
-                       if (pset.issuper)
-                           buf[0] = '#';
-                       else
-                           buf[0] = '>';
-
-                       break;
-                   }
+                   if (is_superuser())
+                       buf[0] = '#';
+                   else
+                       buf[0] = '>';
+                   break;
 
                    /* execute command */
                case '`':
index cb41920eb9de0a81573cbee15a9f7e8681f4ba2a..a471184fb2113af6cebe639da987929f97990ed4 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright 2000 by PostgreSQL Global Development Group
  *
- * $Header: /cvsroot/pgsql/src/bin/psql/settings.h,v 1.13 2002/03/05 00:01:02 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/bin/psql/settings.h,v 1.14 2003/06/28 00:12:40 tgl Exp $
  */
 #ifndef SETTINGS_H
 #define SETTINGS_H
@@ -48,9 +48,7 @@ typedef struct _psqlSettings
    char       *inputfile;      /* for error reporting */
    unsigned    lineno;         /* also for error reporting */
 
-   bool        issuper;        /* is the current user a superuser? (used
-                                * to form the prompt) */
-   bool        timing;         /* timing of all queries */
+   bool        timing;         /* enable timing of all queries */
 } PsqlSettings;
 
 extern PsqlSettings pset;
index 74d79fc5078745d7260de65a59be9d697e589f2e..b36aaa3476d1f1d78ee5d9ade06555ea6ef74ec7 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright 2000 by PostgreSQL Global Development Group
  *
- * $Header: /cvsroot/pgsql/src/bin/psql/startup.c,v 1.73 2003/04/04 20:42:13 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/bin/psql/startup.c,v 1.74 2003/06/28 00:12:40 tgl Exp $
  */
 #include "postgres_fe.h"
 
@@ -74,18 +74,13 @@ struct adhoc_opts
    bool        no_psqlrc;
 };
 
-static void
-           parse_psql_options(int argc, char *argv[], struct adhoc_opts * options);
-
-static void
-           process_psqlrc(void);
-
-static void
-           showVersion(void);
+static void parse_psql_options(int argc, char *argv[],
+                              struct adhoc_opts * options);
+static void process_psqlrc(void);
+static void showVersion(void);
 
 #ifdef USE_SSL
-static void
-           printSSLInfo(void);
+static void printSSLInfo(void);
 #endif
 
 
@@ -144,6 +139,10 @@ main(int argc, char *argv[])
 
    SetVariable(pset.vars, "VERSION", PG_VERSION_STR);
 
+   /* Default values for variables that are used in noninteractive cases */
+   SetVariableBool(pset.vars, "AUTOCOMMIT");
+   SetVariable(pset.vars, "VERBOSE", "default");
+
    pset.notty = (!isatty(fileno(stdin)) || !isatty(fileno(stdout)));
 
    /* This is obsolete and should be removed sometime. */
@@ -208,11 +207,7 @@ main(int argc, char *argv[])
 
    PQsetNoticeProcessor(pset.db, NoticeProcessor, NULL);
 
-   /*
-    * We need to save the encoding because we want to have it available
-    * even if the database connection goes bad.
-    */
-   pset.encoding = PQclientEncoding(pset.db);
+   SyncVariables();
 
    if (options.action == ACT_LIST_DB)
    {
@@ -222,14 +217,6 @@ main(int argc, char *argv[])
        exit(success ? EXIT_SUCCESS : EXIT_FAILURE);
    }
 
-   SetVariable(pset.vars, "DBNAME", PQdb(pset.db));
-   SetVariable(pset.vars, "USER", PQuser(pset.db));
-   SetVariable(pset.vars, "HOST", PQhost(pset.db));
-   SetVariable(pset.vars, "PORT", PQport(pset.db));
-   SetVariable(pset.vars, "ENCODING", pg_encoding_to_char(pset.encoding));
-
-   pset.popt.topt.encoding = pset.encoding;
-
    /*
     * Now find something to do
     */
@@ -274,7 +261,6 @@ main(int argc, char *argv[])
     */
    else
    {
-       pset.issuper = test_superuser(PQuser(pset.db));
        if (!QUIET() && !pset.notty)
        {
            printf(gettext("Welcome to %s %s, the PostgreSQL interactive terminal.\n\n"
@@ -289,15 +275,18 @@ main(int argc, char *argv[])
 #endif
        }
 
+       /* Default values for variables that are used in interactive case */
        SetVariable(pset.vars, "PROMPT1", DEFAULT_PROMPT1);
        SetVariable(pset.vars, "PROMPT2", DEFAULT_PROMPT2);
        SetVariable(pset.vars, "PROMPT3", DEFAULT_PROMPT3);
+
        if (!options.no_psqlrc)
            process_psqlrc();
        if (!pset.notty)
            initializeInput(options.no_readline ? 0 : 1);
        if (options.action_string)      /* -f - was used */
            pset.inputfile = "";
+
        successResult = MainLoop(stdin);
    }
 
index 35f84aefdcc4965eaef26cd3830308265f8cf5b4..6b4c42786e76bbbecabe336e5f3903fc83c4be4f 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright 2000 by PostgreSQL Global Development Group
  *
- * $Header: /cvsroot/pgsql/src/bin/psql/variables.c,v 1.10 2003/03/20 06:43:35 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/bin/psql/variables.c,v 1.11 2003/06/28 00:12:40 tgl Exp $
  */
 #include "postgres_fe.h"
 #include "variables.h"
@@ -33,8 +33,6 @@ CreateVariableSpace(void)
    return ptr;
 }
 
-
-
 const char *
 GetVariable(VariableSpace space, const char *name)
 {
@@ -59,14 +57,19 @@ GetVariable(VariableSpace space, const char *name)
    return NULL;
 }
 
-
-
 bool
 GetVariableBool(VariableSpace space, const char *name)
 {
-   return GetVariable(space, name) != NULL ? true : false;
-}
+   const char *val;
 
+   val = GetVariable(space, name);
+   if (val == NULL)
+       return false;           /* not set -> assume "off" */
+   if (strcmp(val, "off") == 0)
+       return false;
+   /* for backwards compatibility, anything except "off" is taken as "true" */
+   return true;
+}
 
 bool
 VariableEquals(VariableSpace space, const char name[], const char value[])
@@ -76,7 +79,6 @@ VariableEquals(VariableSpace space, const char name[], const char value[])
    return var && (strcmp(var, value) == 0);
 }
 
-
 int 
 GetVariableNum(VariableSpace space, 
                    const char name[], 
@@ -103,7 +105,6 @@ GetVariableNum(VariableSpace space,
    return result;
 }
 
-
 int
 SwitchVariable(VariableSpace space, const char name[], const char *opt, ...)
 {
@@ -117,17 +118,16 @@ SwitchVariable(VariableSpace space, const char name[], const char *opt, ...)
        va_start(args, opt);
        for (result=1; opt && (strcmp(var, opt) != 0); result++)
            opt = va_arg(args,const char *);
-
-       if (!opt) result = var_notfound;
+       if (!opt)
+           result = VAR_NOTFOUND;
        va_end(args);
    }
    else
-     result = var_notset;
+     result = VAR_NOTSET;
 
    return result;
 }
 
-
 void 
 PrintVariables(VariableSpace space)
 {
@@ -136,7 +136,6 @@ PrintVariables(VariableSpace space)
     printf("%s = '%s'\n", ptr->name, ptr->value);
 }
 
-
 bool
 SetVariable(VariableSpace space, const char *name, const char *value)
 {
@@ -176,16 +175,12 @@ SetVariable(VariableSpace space, const char *name, const char *value)
    return previous->next->value ? true : false;
 }
 
-
-
 bool
 SetVariableBool(VariableSpace space, const char *name)
 {
-   return SetVariable(space, name, "");
+   return SetVariable(space, name, "on");
 }
 
-
-
 bool
 DeleteVariable(VariableSpace space, const char *name)
 {
@@ -217,15 +212,3 @@ DeleteVariable(VariableSpace space, const char *name)
 
    return true;
 }
-
-
-
-void
-DestroyVariableSpace(VariableSpace space)
-{
-   if (!space)
-       return;
-
-   DestroyVariableSpace(space->next);
-   free(space);
-}
index d297b5a4efa220ef518cead39516334a459b3057..ce239975ef3681259a0836c97487ca0cf666791f 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright 2000 by PostgreSQL Global Development Group
  *
- * $Header: /cvsroot/pgsql/src/bin/psql/variables.h,v 1.11 2003/03/20 06:43:35 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/bin/psql/variables.h,v 1.12 2003/06/28 00:12:40 tgl Exp $
  */
 
 /*
@@ -45,18 +45,18 @@ int GetVariableNum(VariableSpace space,
 
 
 /* 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.
+ * 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,...);
+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   SetVariableBool(VariableSpace space, const char *name);
 bool   DeleteVariable(VariableSpace space, const char *name);
-void   DestroyVariableSpace(VariableSpace space);
 
 #endif   /* VARIABLES_H */