]> granicus.if.org Git - postgresql/commitdiff
Fixed psql variables vs array syntax, as well as minor psql enhancements
authorPeter Eisentraut <peter_e@gmx.net>
Fri, 14 Jan 2000 22:18:03 +0000 (22:18 +0000)
committerPeter Eisentraut <peter_e@gmx.net>
Fri, 14 Jan 2000 22:18:03 +0000 (22:18 +0000)
21 files changed:
doc/src/sgml/ref/psql-ref.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/describe.c
src/bin/psql/describe.h
src/bin/psql/help.c
src/bin/psql/help.h
src/bin/psql/input.c
src/bin/psql/input.h
src/bin/psql/large_obj.c
src/bin/psql/large_obj.h
src/bin/psql/mainloop.c
src/bin/psql/mainloop.h
src/bin/psql/prompt.c
src/bin/psql/prompt.h
src/bin/psql/settings.h
src/bin/psql/startup.c

index 5c92e5fbd1b0382343480f80a6f71260e8aff0ce..88a15fe631e92fa56e01d1a2adc6718887f25b7d 100644 (file)
@@ -1,5 +1,5 @@
 <!--
-$Header: /cvsroot/pgsql/doc/src/sgml/ref/psql-ref.sgml,v 1.19 2000/01/12 19:36:34 petere Exp $
+$Header: /cvsroot/pgsql/doc/src/sgml/ref/psql-ref.sgml,v 1.20 2000/01/14 22:18:01 petere Exp $
 Postgres documentation
 -->
 
@@ -32,27 +32,20 @@ Postgres documentation
       <date>1998-09-26</date>
     </refsect2info>
 
-    <title>Input</title>
-    <para>
-    <application>psql</application> accepts many command-line arguments,
-    a rich set of meta-commands, and the full <acronym>SQL</acronym> language
-    supported by <productname>PostgreSQL</productname>.
-    </para>
-  </refsect2>
+    <title>Summary</title>
 
-  <refsect2 id="R2-APP-PSQL-2">
-    <refsect2info>
-      <date>1998-10-26</date>
-     </refsect2info>
-   
-    <title>Output</title>
     <para>
-    <application>psql</application> returns 0 to the shell on successful
-    completion of all queries, 1 for fatal errors, 2 for abrupt disconnection
-    from the backend, and 3 if a non-interactive script stopped because an <acronym>SQL</acronym>
-    command or psql meta-command resulted in an error.
+     <application>psql</application> is a terminal-based front-end to 
+     <productname>PostgreSQL</productname>. It enables you to type in queries
+     interactively, issue them to <productname>PostgreSQL</productname>, and see
+     the query results. Alternatively, input can be from a file.
+     In addition, it provides a number of meta-commands and
+     various shell-like features to facilitate writing scripts and automating a wide
+     variety of tasks.
     </para>
+
   </refsect2>
+
 </refsynopsisdiv>
 
 <refsect1 id="R1-APP-PSQL-1">
@@ -62,58 +55,31 @@ Postgres documentation
 
   <title>Description</title>
 
-  <para>
-  <application>psql</application> is a character-based front-end to 
-  <productname>PostgreSQL</productname>. It enables you to type in queries
-  interactively, issue them to <productname>PostgreSQL</productname>, and see
-  the query results. In addition, it provides a number of meta-commands and
-  various shell-like features to facilitate writing scripts and automating a wide
-  variety of tasks.
-  </para>
-
-  <para>
-  <application>psql</application> is a regular
-  <productname>PostgreSQL</productname> client application. Hence, a
-  <application>postmaster</application> process must be running on the database
-  server host before <application>psql</application> is executed.  In addition,
-  the correct parameters to identify the database server, such as the
-  <application>postmaster</application> host name, may need to be specified as
-  described below.
-  </para>
-
-  <para>
-  When <application>psql</application> starts, it reads <acronym>SQL</acronym> and psql commands
-  from <filename>/etc/psqlrc</filename> and then from
-  <filename>$<envar>HOME</envar>/.psqlrc</filename>
-  This allows commands like <command>\set</command> or the <acronym>SQL</acronym> command
-  <xref linkend="SQL-SET" endterm="SQL-SET-title">, which can be used to set a variety of options,
-  to be run at the start of every session.
-  </para>
-
-  <para>
-  <application>psql</application> can be used in a pipe sequence, and
-  automatically detects when it is not used interactively.
-  </para>
-
-  <refsect2 id="R2-APP-PSQL-3">
+  <refsect2 id="R2-APP-PSQL-connecting">
     <refsect2info>
-      <date>1998-09-26</date>
+      <date>2000-01-14</date>
     </refsect2info>
    
     <title>Connecting To A Database</title>
 
     <para>
-    <application>psql</application> attempts to make a connection to the
-    database name at the hostname and port number, and with the user name
-    specified on the command line. If any of these are omitted, the
-    <application>libpq</application> client library, upon which
-    <application>psql</application> is built, will choose defaults.
-    (This will usually mean the environment variables <envar>PGDATABASE</envar>,
+    <application>psql</application> is a regular <productname>PostgreSQL</productname>
+    client application. In order to connect to a database you need to determine
+    name of you target database, the hostname and port number of the server
+    and what user name you want to connect as. <application>psql</application> can be
+    told about those parameters via command line options, namely <option>-d</option>,
+    <option>-h</option>, <option>-p</option>, and <option>-U</option> respectively.
+    If an argument is found that does not belong to any option it will be interpreted
+    as database name as well. Not all these options are required, defaults do apply.
+    If you omit the host name psql will connect via domain sockets to a server on the
+    local host. The default port number is compile-time determined. Since the database
+    server uses the same default, chances are you don't have to specify the port in most
+    settings. The default user name is your Unix username, the same with the database.
+    Note that you can't just connect to any database under any username. Your database
+    administrator should have informed you about your access rights. To save you some typing
+    you can also set the environment variables <envar>PGDATABASE</envar>,
     <envar>PGHOST</envar>, <envar>PGPORT</envar>, <envar>PGUSER</envar>,
-    respectively, if they are set. Otherwise the default host is the local host
-    via Unix domain sockets, the default port is decided at compile time,
-    the default user is the system user name, and the default database is
-    the one with the same name as the user.)
+    respectively to appropriate values.
     </para>
 
     <para>
@@ -151,8 +117,9 @@ testdb=>
     <para>
     At the prompt, the user may type in <acronym>SQL</acronym> queries.  
     Ordinarily, input lines are sent to the backend when a query-terminating
-    semicolon is reached. If the database server reports success, the query
-    results are displayed on the screen.
+    semicolon is reached. An end of line does not terminate a query! Thus queries
+    can be spread over serveral lines for clarity. If the query was sent and without
+    error the query results are displayed on the screen.
     </para>
 
     <para>
@@ -173,12 +140,11 @@ testdb=>
 
     <para>
     Anything you enter in <application>psql</application> that begins with an
-    unquoted backslash is a <application>psql</application> meta-command.
-    Anything else is <acronym>SQL</acronym> and simply goes into the current
-    query buffer (and once you have at least one complete query, it gets
-    automatically submitted to the backend). For this reason,
-    <application>psql</application> meta-commands are more commonly called
-    slash or backslash commands.
+    unquoted backslash is a <application>psql</application> meta-command that is
+    processes by <application>psql</application> itself.
+    These commands are what makes
+    <application>psql</application> interesting for administration or scripting.
+    Meta-commands are more commonly called slash or backslash commands.
     </para>
 
     <para>
@@ -268,11 +234,8 @@ testdb=>
        </para>
 
        <para>
-       If <replaceable class="parameter">username</replaceable> is omitted or
-       <literal>-</literal> the current user name is assumed. If
-       <replaceable class="parameter">username</replaceable> is <literal>?</literal>
-       <application>psql</application> will prompt for the new user name
-       interactively.
+       If <replaceable class="parameter">username</replaceable> is omitted
+        the current user name is assumed.
        </para>
 
        <para>
@@ -293,10 +256,11 @@ testdb=>
       </varlistentry>
 
       <varlistentry>
-        <term><literal>\copy</literal> [ <literal>binary</literal> ] <replaceable class="parameter">table</replaceable>
+        <term><literal>\copy</literal> <replaceable class="parameter">table</replaceable>
         [ <literal>with oids</literal> ] { <literal>from</literal> | <literal>to</literal> }
-       <replaceable class="parameter">filename</replaceable> [ <literal>with delimiters</literal>
-       '<replaceable class="parameter">character</replaceable>' ]
+       <replaceable class="parameter">filename</replaceable> | stdin | stdout
+        [ <literal>with delimiters</literal> '<replaceable class="parameter">characters</replaceable>' ]
+        [ <literal>with null as</literal> '<replaceable class="parameter">string</replaceable>' ]
         </term>
 
         <listitem>
@@ -326,6 +290,18 @@ testdb=>
        technique may be preferable.
         </para>
         </tip>
+
+        <note>
+        <para>
+        Note the difference in interpretation of <literal>stdin</literal> and <literal>stdout</literal>
+        between frontend and backend copies: In a frontend copy these always refer
+        to <application>psql</application>'s input and output stream. On a backend
+        copy <literal>stdin</literal> comes from whereever the <command>COPY</command>
+        itself came from (for example, a script ran with the <option>-f</option>) option,
+        and <literal>stdout</literal> refers to the query output stream (see
+        <command>\o</command> meta-command below).
+        </para>
+        </note>
         </listitem>
       </varlistentry>
 
@@ -666,7 +642,7 @@ Tue Oct 26 21:40:57 CEST 1999
        </tip>
        <note>
        <para>
-       See the description of the <envar>lo_transaction</envar> variable for
+       See the description of the <envar>LO_TRANSACTION</envar> variable for
        important information concerning all large object operations.
        </para>
        </note>
@@ -689,7 +665,7 @@ lo_import 152801
        which one ought to remember if one wants to access the object ever again.
        For that reason it is recommended to always associate a human-readable
        comment with every object. Those can then be seen with the
-       <command>\lo_list?</command> command.
+       <command>\lo_list</command> command.
        </para>
 
        <para>
@@ -700,7 +676,7 @@ lo_import 152801
 
        <note>
        <para>
-       See the description of the <envar>lo_transaction</envar> variable for
+       See the description of the <envar>LO_TRANSACTION</envar> variable for
        important information concerning all large object operations.
        </para>
        </note>
@@ -733,7 +709,7 @@ lo_import 152801
        </tip>
        <note>
        <para>
-       See the description of the <envar>lo_transaction</envar> variable for
+       See the description of the <envar>LO_TRANSACTION</envar> variable for
        important information concerning all large object operations.
        </para>
        </note>
@@ -755,9 +731,11 @@ lo_import 152801
         </para>
 
        <para>
-       <quote>Query results</quote> includes all tables and notices obtained
+       <quote>Query results</quote> includes all tables, command responses,
+        and notices obtained
        from the database server, as well as output of various backslash
-       commands that query the database (such as <command>\d</command>).
+       commands that query the database (such as <command>\d</command>),
+        but not error messages.
        </para>
 
        <tip>
@@ -922,7 +900,7 @@ lo_import 152801
          <para>
          Toggles the list of a pager to do table output. If the environment variable
          <envar>PAGER</envar> is set, the output is piped to the specified program.
-         Otherwise <filename>/bin/more</filename> is assumed.
+         Otherwise <filename>more</filename> is used.
          </para>
 
          <para>
@@ -1024,10 +1002,8 @@ lo_import 152801
        <para>
        Sets the internal variable <replaceable class="parameter">name</replaceable>
        to <replaceable class="parameter">value</replaceable>. If no second argument
-       is given, the variable is unset (which is different from setting it to,
-       for example, an empty string: <literal>\set foo ''</literal>). If no
-       arguments are given, all currently defined variables are listed with their
-       values.
+       is given, the variable is just set with not value. To unset a variable, use
+        the <command>\unset</command> command.
        </para>
 
        <para>
@@ -1192,14 +1168,7 @@ Access permissions for database "test"
   <para>
   If so configured, <application>psql</application> understands both standard
   Unix short options, and <acronym>GNU</acronym>-style long options. The latter
-  are not available on all systems, so you are advised to consider carefully
-  whether to use them.
-  </para>
-
-  <para>
-  Many command line options are equivalent to an internal slash command or to
-  setting some variable. Those will not be explained in detail here. Instead,
-  you are asked to look them up in the respective section.
+  are not available on all systems.
   </para>
 
   <para>
@@ -1221,8 +1190,7 @@ Access permissions for database "test"
       <para>
       Specifies that <application>psql</application>
       is to execute one query string, <replaceable class="parameter">query</replaceable>,
-      and then exit.  This is useful for shell scripts, typically in
-      conjunction with the <option>-q</option> option.
+      and then exit.  This is useful for shell scripts.
       </para>
       <para>
       <replaceable class="parameter">query</replaceable> must be either a query string
@@ -1254,20 +1222,20 @@ Access permissions for database "test"
       <listitem>
       <para>
       In non-interactive mode, all lines are printed to the screen as they are read.
-      This is equivalent to setting the variable <envar>echo</envar>.
+      This is equivalent to setting the variable <envar>ECHO</envar> to <literal>full</literal>.
       </para>
       </listitem>
     </varlistentry>
 
 
     <varlistentry>
-      <term>-E, --echo-all</term>
+      <term>-E, --echo-hidden</term>
       <listitem>
       <para>
       Echos the actual queries generated by \d and other backslash commands.
       You can use this if you wish to include similar functionality into
       your own programs. This is equivalent to setting the variable
-      <envar>echo_secret</envar> from within <application>psql</application>.
+      <envar>ECHO_HIDDEN</envar> from within <application>psql</application>.
       </para>
       </listitem>
     </varlistentry>
@@ -1337,7 +1305,7 @@ Access permissions for database "test"
       <term>-n, --no-readline</term>
       <listitem>
       <para>
-      Do not use the readline library for input line editing and command history.
+      Do not use readline for line editing and do not use the history.
       </para>
       </listitem>
     </varlistentry>
@@ -1389,7 +1357,7 @@ Access permissions for database "test"
       By default, it prints welcome messages and various informational output.
       If this option is used, none of this happens. This is useful with the
       <option>-c</option> option. Within <application>psql</application> you can
-      also set the <envar>quiet</envar> variable to achieve the same effect.
+      also set the <envar>QUIET</envar> variable to achieve the same effect.
       </para>
       </listitem>
     </varlistentry>
@@ -1411,7 +1379,7 @@ Access permissions for database "test"
       <term>-S, --single-line</term>
       <listitem>
       <para>
-      Runs in single-line mode where a newline sends a query, in addition to a semicolon.
+      Runs in single-line mode where a newline terminates a query, like a semicolon would do.
       </para>
 
       <note>
@@ -1419,8 +1387,7 @@ Access permissions for database "test"
       This mode is provided for those who insist on it, but you are not necessarily
       encouraged to use it. In particular, if you mix <acronym>SQL</acronym> and
       meta-commands on a line the order of execution might not always be clear to
-      the unexperienced user. Moral: Unless you exclusively type short queries,
-      avoid using this mode.
+      the unexperienced user.
       </para>
       </note>
       </listitem>
@@ -1472,9 +1439,7 @@ Access permissions for database "test"
       <listitem>
       <para>
       Connects to the database as the user <replaceable class="parameter">username</replaceable>
-      instead of the default. (You must have permission to do so, of course.) If
-      <replaceable class="parameter">username</replaceable> is <quote>?</quote>, <application>psql</application>
-      issues an interactive prompt for the user name.
+      instead of the default. (You must have permission to do so, of course.)
       </para> 
       </listitem>
     </varlistentry>
@@ -1486,7 +1451,9 @@ Access permissions for database "test"
       <para>
       Performs a variable assignment, like the <command>\set</command> internal command.
       Note that you must separate name and value, if any, by an equal sign on the command
-      line.
+      line. To unset a variable, leave off the equal sign. These assignments are done
+      during a very early state of startup, so variables reserved for internal purposes
+      might get overwritten again.
       </para>
       </listitem>
     </varlistentry>
@@ -1503,7 +1470,7 @@ Access permissions for database "test"
 
 
     <varlistentry>
-      <term>-W</term>
+      <term>-W, --password</term>
       <listitem>
       <para>
       Requests that <application>psql</application> should prompt for a password
@@ -1518,26 +1485,28 @@ Access permissions for database "test"
       Because this is currently based on a <quote>hack</quote> the automatic
       recognition might mysteriously fail, hence this option to force a prompt.
       If no password prompt is issued and the backend requires password authentication
-      the content of the environment variable <envar>PGPASSWORD</envar> is
-      taken. If this is not set, the connection attempt will fail.
+      the connection attempt will fail.
       </para>
+      </listitem>
+    </varlistentry>
+
 
-      <caution>
+    <varlistentry>
+      <term>-x, --expanded</term>
+      <listitem>
       <para>
-      If you are considering setting the variable <envar>PGPASSWORD</envar> to do
-      authentication, you have a problem.
+      Turns on extended row format mode. This is equivalent to the command
+      <command>\x</command>.
       </para>
-      </caution>
       </listitem>
     </varlistentry>
 
 
     <varlistentry>
-      <term>-x</term>
+      <term>-?, --help</term>
       <listitem>
       <para>
-      Turns on extended row format mode. This is equivalent to the command
-      <command>\x</command>.
+      Shows help about <application>psql</application> command line arguments.
       </para>
       </listitem>
     </varlistentry>
@@ -1545,12 +1514,6 @@ Access permissions for database "test"
   </variablelist>
   </para>
 
-  <para>
-  You may set environment variables to avoid typing some of the above
-  options.  See the section <quote>Connection To A Database</quote> above
-  and in particular the documentation of the <application>libpq</application>
-  client library.
-  </para>
 </refsect1>
 
 
@@ -1585,7 +1548,7 @@ bar
 testdb=> <userinput>\echo "foo is now ${foo}."</userinput>
 foo is now bar.
 </programlisting>
-    (The curly braces are required. This is not <productname>Perl</productname>.) No variable substitution
+    (The curly braces are required.) No variable substitution
     will be performed in single-quoted strings or in any of the backslash commands
     that have special parsing rules (e.g., <command>\copy</command>).
     </para>
@@ -1605,52 +1568,70 @@ foo is now bar.
     </note>
 
     <para>
-    <application>psql</application>'s internal variable names can consist of
-    letters, numbers, and underscores in any order and any number of them.
-    It is recommended, however, that you stick to lower-case letters and do not
-    begin with a digit. The partial rationale for this follows.
-    </para>
-
-    <para>
-    If you attempt to refer to a variable that is not set,
-    <application>psql</application> first checks if it is the name of one of
-    several defined <quote>magic</quote> variables. Those variables are
-    maintained internally and always have a value (at least when their semantics
-    permit it). By convention they all start with an upper-case letter. You can
-    set those variables manually, but that will <quote>shadow</quote> their
-    special meaning, until you unset your personal copy. Finally, if no match is
-    found that way, the value of the respective environment variable is
-    substituted.
-    </para>
-
-    <para>
-    Currently, the following <quote>magic</quote> variables are defined:
-    <envar>Version</envar> which contains a string with the version of
-    <application>psql</application>; <envar>Database</envar>, <envar>Host</envar>,
-    <envar>Port</envar>, <envar>User</envar> are the currently active
-    connection options. <envar>LastOid</envar> contains the oid that was the
-    result of the last <command>INSERT</command> or <command>\lo_import</command>
-    command. If the last command was not one of those two, the value
-    is undefined.
+    If you call <command>\set</command> without an argument, the variable is simply
+    set, but has no value. To unset (or delete) a variable, use the command
+    <command>\unset</command>.
     </para>
 
     <para>
+    <application>psql</application>'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 by <application>psql</application>.
     They indicate certain option settings that can be changed at runtime
-    by altering the value of the variable. Although you can use these
+    by altering the value of the variable or represent some state of the application.
+    Although you can use these
     variables for any other purpose, this is not recommended, as the
-    program behavior might grow really strange really quickly. Note that the
-    majority variables are <quote>boolean</quote> variables, that is, they
-    only care whether or not are they set, not what to. A list of all specially
-    treated variables follows.
+    program behavior might grow really strange 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.
     <variablelist>
       <varlistentry>
-        <term><envar>die_on_error</envar></term>
+        <term><envar>DBNAME</envar></term>
+       <listitem>
+       <para>
+        The name of the database you are currently connected to. This is set everytime
+        you connect to a database (including program startup), but can be unset.
+       </para>
+       </listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term><envar>ECHO</envar></term>
+       <listitem>
+       <para>
+       If set to <quote><literal>full</literal></quote>, all lines entered or from a script
+        are written to the standard output before they
+       are parsed or executed. To specify this on program startup, in conjunction with the
+       <option>-f</option> option perhaps, use the switch <option>-e</option>.
+        If set to <quote><literal>brief</literal></quote>, <application>psql</application>
+        merely prints all queries as they are sent to the backend.
+       </para>
+       </listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term><envar>ECHO_HIDDEN</envar></term>
+       <listitem>
+       <para>
+       When this variable is set and a backslash command queries the database, the query
+       is first shown. This way you can study the <productname>PostgreSQL</productname>
+       internals and provide similar functionality in your own programs. If you set the
+       variable to the value <quote>noexec</quote>, the queries are just shown but are
+       not actually sent to the backend and executed.
+       </para>
+       </listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term><envar>EXIT_ON_ERROR</envar></term>
        <listitem>
        <para>
        By default, if non-interactive scripts encounter an error, such as a
        malformed <acronym>SQL</acronym> query or internal meta-command,
-       processing continues. This is often less than desirable. If this variable
+       processing continues. This is has been the traditional behaviour of
+        <application>psql</application>but is often less than desirable. If this variable
        is set, script processing will immediately terminate. If the script was
        called from another script it will terminate in the same fashion.
        If the outermost script was not called from an interactive <application>psql</application>
@@ -1662,31 +1643,80 @@ foo is now bar.
       </varlistentry>
 
       <varlistentry>
-        <term><envar>echo</envar></term>
+        <term><envar>HISTCONTROL</envar></term>
        <listitem>
        <para>
-       If set, all lines from a script are written to the standard output before they
-       are executed. To specify this on program startup, in conjunction with the
-       <option>-f</option> option perhaps, use the switch <option>-e</option>.
+         If  this variable is set  to  <literal>ignorespace</literal>, lines which begin with a
+         space are not entered into the history list. If set to a value of
+         <literal>ignoredups</literal>, lines matching the previous history line are not
+         entered. A value of <literal>ignoreboth</literal> combines the two
+         options.  If unset, or if set to any other value than those above, all lines read
+         in interactive mode are saved on the history list.
        </para>
+        <note>
+        <para>
+        This feature was shamelessly plagiarized from <application>bash</application>.
+        </para>
+        </note>
        </listitem>
       </varlistentry>
 
       <varlistentry>
-        <term><envar>echo_secret</envar></term>
+        <term><envar>HISTSIZE</envar></term>
        <listitem>
        <para>
-       When this variable is set and a backslash command queries the database, the query
-       is first shown. This way you can study the <productname>PostgreSQL</productname>
-       internals and provide similar functionality in your own programs. If you set the
-       variable to the value <quote>noexec</quote>, the queries are just shown but are
-       not actually sent to the backend and executed.
+        The number of commands to store in the command history.
+        The default value is 500.
+       </para>
+        <note>
+        <para>
+        This feature was shamelessly plagiarized from <application>bash</application>.
+        </para>
+        </note>
+       </listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term><envar>HOST</envar></term>
+       <listitem>
+       <para>
+        The database server host you are currently connected to. This is set everytime
+        you connect to a database (including program startup), but can be unset.
+       </para>
+       </listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term><envar>IGNOREEOF</envar></term>
+       <listitem>
+       <para>
+         If unset, sending an EOF character (usually Control-D) to an interactive session of
+         <application>psql</application> will terminate the application.
+         If set to a numeric value, that many EOF characters are ignored before the application
+         terminates. If the variable is set but has no numeric value, the default is 10.
+       </para>
+        <note>
+        <para>
+        This feature was shamelessly plagiarized from <application>bash</application>.
+        </para>
+        </note>
+       </listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term><envar>LASTOID</envar></term>
+       <listitem>
+       <para>
+        The value of the last affected oid, as returned from an <command>INSERT</command>
+        or <command>lo_insert</command> commmand. This variable is only guaranteed to be
+        valid until after the result of the next <acronym>SQL</acronym> command has been
+        displayed.
        </para>
        </listitem>
       </varlistentry>
 
       <varlistentry>
-        <term><envar>lo_transaction</envar></term>
+        <term><envar>LO_TRANSACTION</envar></term>
        <listitem>
        <para>
        If you use the <productname>PostgreSQL</productname> large object
@@ -1702,7 +1732,7 @@ foo is now bar.
         all. In the latter case you must provide you own
         <command>BEGIN TRANSACTION</command>/<command>COMMIT</command> block or
         the results will be unpredictable (usually resulting in the desired
-        action not being performed anyway).
+        action not being performed in any case).
        </para>
 
        <para>
@@ -1717,7 +1747,17 @@ foo is now bar.
       </varlistentry>
 
       <varlistentry>
-        <term><envar>prompt1</envar>, <envar>prompt2</envar>, <envar>prompt3</envar></term>
+        <term><envar>PORT</envar></term>
+       <listitem>
+       <para>
+        The database server port you are currently connected to. This is set everytime
+        you connect to a database (including program startup), but can be unset.
+       </para>
+       </listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term><envar>PROMPT1</envar>, <envar>PROMPT2</envar>, <envar>PROMPT3</envar></term>
        <listitem>
        <para>
        These specify what the prompt <application>psql</application> issues is
@@ -1729,7 +1769,7 @@ foo is now bar.
       </varlistentry>
 
       <varlistentry>
-        <term><envar>quiet</envar></term>
+        <term><envar>QUIET</envar></term>
        <listitem>
        <para>
        This variable is equivalent to the command line option <option>-q</option>.
@@ -1739,7 +1779,7 @@ foo is now bar.
       </varlistentry>
 
       <varlistentry>
-        <term><envar>singleline</envar></term>
+        <term><envar>SINGLELINE</envar></term>
        <listitem>
        <para>
        This variable is set be the command line options <option>-S</option>. You
@@ -1749,13 +1789,24 @@ foo is now bar.
       </varlistentry>
 
       <varlistentry>
-        <term><envar>singlestep</envar></term>
+        <term><envar>SINGLESTEP</envar></term>
        <listitem>
        <para>
        This variable is equivalent to the command line option <option>-s</option>.
        </para>
        </listitem>
       </varlistentry>
+
+      <varlistentry>
+        <term><envar>USER</envar></term>
+       <listitem>
+       <para>
+        The database user you are currently connected as. This is set everytime
+        you connect to a database (including program startup), but can be unset.
+       </para>
+       </listitem>
+      </varlistentry>
+
     </variablelist>
 
     </para>
@@ -1814,6 +1865,15 @@ testdb=> <userinput>\set content `sed -e "s/'/\\\\\\'/g" < my_file.txt`</userinp
     be better off preparing the file externally.
     </para>
 
+    <para>
+    Since colons may legally appear in queries, the following rule applies: If the variable
+    is not set, the character sequence <quote>colon-name</quote> is not changed. In any
+    case you can escape a colon with a backslash to protect it from interpretation.
+    (The colon syntax for variables is standard <acronym>SQL</acronym> for embedded
+    query languages, such as <application>ecpg</application>. The colon syntax for
+    array slices and type casts are <productname>PostgreSQL</productname> extensions.)
+    </para>
+
   </refsect2>
 
 
@@ -1822,8 +1882,8 @@ testdb=> <userinput>\set content `sed -e "s/'/\\\\\\'/g" < my_file.txt`</userinp
 
     <para>
     The prompts <application>psql</application> issues can be customized to
-    your preference. The three variables <envar>prompt1</envar>, <envar>prompt2</envar>,
-    and <envar>prompt3</envar> contain strings and special escape sequences
+    your preference. The three variables <envar>PROMPT1</envar>, <envar>PROMPT2</envar>,
+    and <envar>PROMPT3</envar> contain strings and special escape sequences
     that describe the appearance of the prompt. Prompt 1 is the normal prompt
     that is issued when <application>psql</application> requests a new query.
     Prompt 2 is issued when more input is expected during query input because
@@ -1924,8 +1984,75 @@ testdb=> <userinput>\set content `sed -e "s/'/\\\\\\'/g" < my_file.txt`</userinp
     and 2, and <literal>'&gt;&gt; '</literal> for prompt 3.
     </para>
 
+    <note>
+    <para>
+    This feature was shamelessly plagiarized from <application>tcsh</application>.
+    </para>
+    </note>
+
    </refsect2>
 
+  <refsect2 id="APP-PSQL-MISC">
+    <title id="APP-PSQL-MISC-title">Miscellaneous</title>
+
+    <para>
+    <application>psql</application> returns 0 to the shell if it finished normally,
+    1 if a fatal error of its own (out of memory, file not found) occurs, 2 if the
+    connection to the backend went bad and the session is not interactive, and 3 if
+    an error occurred in a script and the variable <envar>EXIT_ON_ERROR</envar> was
+    set.
+    </para>
+
+    <para>
+    Before starting up in interactive mode, <application>psql</application> attempts
+    to read and execute the files <filename>/etc/psqlrc</filename> and
+    <filename>$HOME/.psqlrc</filename>. They could be used to set up the client or
+    the server to taste (using the <command>\set</command> and <command>SET</command>
+    commands).
+    </para>
+
+  </refsect2>
+
+  <refsect2>
+    <title><acronym>GNU</acronym> readline</title>
+
+    <para>
+    <application>psql</application> supports the readline and history libraries for
+    convenienent line editing and retrieval. The command history is stored in a file
+    named <filename>.psqlrc</filename> in your home directory and is reloaded when
+    <application>psql</application> starts up.
+    Tab-completion is also supported, although
+    the completion logic makes no claim to be an <acronym>SQL</acronym> parser.
+    When available, <application>psql</application> is automatically built to use these
+    features.
+    </para>
+
+    <para>
+    If you have the readline library installed but <application>psql</application>
+    does not seem to use it, you must make sure that <productname>PostgreSQL</productname>'s
+    top-level <filename>configure</filename> script finds it. <filename>configure</filename>
+    needs to find both the library <filename>libreadline.a</filename>
+    (or <filename>libreadline.so</filename> on systems with shared libraries)
+    <emphasis>and</emphasis> the header files <filename>readline.h</filename> and
+    <filename>history.h</filename> (or <filename>readline/readline.h</filename> and
+    <filename>readline/history.h</filename>) in appropriate directories. If
+    you have the library and header files installed in an obscure place you
+    must tell <filename>configure</filename> about them, for example:
+<programlisting>
+$ ./configure --with-includes=/opt/gnu/include --with-libraries=/opt/gnu/lib  ...
+</programlisting>
+    Then you have to recompile <application>psql</application> (not necessarily
+    the entire code tree).
+    </para>
+
+    <para>
+    The <acronym>GNU</acronym> readline library can be obtained from the <acronym>GNU</acronym>
+    project's <acronym>FTP</acronym> server at <ulink URL="ftp://ftp.gnu.org">ftp://ftp.gnu.org</ulink>.
+    </para>
+  </refsect2>
+
+
+
 </refsect1>
 
 
@@ -2074,23 +2201,9 @@ Field separator is "oo".
 
       <listitem>
       <para>
-      There are about three different parsers in <application>psql</application>,
-      in addition to the backend <acronym>SQL</acronym> parser, all doing their own thing
-      and attempting to get along with each other. Sometimes they do, sometimes
-      they don't. An excellent example of this can be seen in section
-      <quote><xref linkend="APP-PSQL-sql-interpol" endterm="APP-PSQL-sql-interpol-title"></quote>.
-      There are vague dreams of using <application>flex</application> in the future,
-      but it won't happen soon.
-      </para>
-      </listitem>
-
-      <listitem>
-      <para>
-      Several string buffers are assigned fixed sizes at compile time. These
-      are usually based on certain settings about what the backend can accept
-      for a particular quantity. If you use <application>psql</application> with
-      a different backend than the one it was configured for, you might encounter
-      these limits sooner rather than later.
+      <application>psql</application> only works smootly with servers of the
+      same version. That does not mean other combinations will fail outright,
+      but subtle and not-so-subtle problems might come up.
       </para>
       </listitem>
 
@@ -2098,7 +2211,7 @@ Field separator is "oo".
       <para>
       The number of options for a backslash command is limited, probably to 16.
       You can easily change this in the source code, and perhaps I will get around
-      to fixing this one day (see previous item). Not that there is any command
+      to fixing this one day. Not that there is any command
       that actually uses that many options though.
       </para>
       </listitem>
@@ -2106,41 +2219,6 @@ Field separator is "oo".
 
   </refsect2>
 
-  <refsect2>
-    <title><acronym>GNU</acronym> readline</title>
-
-    <para>
-    A great deal of <application>psql</application>'s convenience is owed to it
-    using the <acronym>GNU</acronym> readline and history library for accepting
-    and storing user input. To verify whether your copy of <application>psql</application>
-    was compiled with readline support, execute <literal>psql -V</literal> and check the
-    output for the words <quote>readline</quote> and <quote>history</quote>.
-    </para>
-
-    <para>
-    If you have the readline library installed but <application>psql</application>
-    does not seem to use it, you must make sure that <productname>PostgreSQL</productname>'s
-    top-level <filename>configure</filename> script finds it. <filename>configure</filename>
-    needs to find both the library <filename>libreadline.a</filename>
-    (or <filename>libreadline.so</filename> on systems with shared libraries)
-    <emphasis>and</emphasis> the header files <filename>readline.h</filename> and
-    <filename>history.h</filename> (or <filename>readline/readline.h</filename> and
-    <filename>readline/history.h</filename>) in appropriate directories. If
-    you have the library and header files installed in an obscure place you
-    must tell <filename>configure</filename> about them, for example:
-<programlisting>
-$ ./configure --with-includes=/opt/gnu/include --with-libraries=/opt/gnu/lib  ...
-</programlisting>
-    Then you have to recompile <application>psql</application> (not necessarily
-    the entire code tree).
-    </para>
-
-    <para>
-    The <acronym>GNU</acronym> readline library can be obtained from the <acronym>GNU</acronym>
-    project's <acronym>FTP</acronym> server at <ulink URL="ftp://ftp.gnu.org">ftp://ftp.gnu.org</ulink>.
-    </para>
-  </refsect2>
-
 </refsect1>
 
 </refentry>
index ba0161205903f50885c78b578480d4100c14586b..d658df1e57229f05560545352f333b768b609a48 100644 (file)
@@ -1,4 +1,3 @@
-#include <config.h>
 #include <c.h>
 #include "command.h"
 
@@ -26,6 +25,7 @@
 #include "print.h"
 #include "describe.h"
 #include "input.h"
+#include "variables.h"
 
 #ifdef WIN32
 #define popen(x,y) _popen(x,y)
 static backslashResult exec_command(const char *cmd,
                         char *const * options,
                         const char *options_string,
-                        PQExpBuffer query_buf,
-                        PsqlSettings *pset);
+                        PQExpBuffer query_buf);
 
 static bool do_edit(const char *filename_arg, PQExpBuffer query_buf);
 
-static char * unescape(const char *source, PsqlSettings *pset);
+static char * unescape(const char *source);
 
 static bool do_connect(const char *new_dbname,
-                       const char *new_user,
-                       PsqlSettings *pset);
+                       const char *new_user);
 
 
 static bool do_shell(const char *command);
@@ -79,8 +77,7 @@ static bool do_shell(const char *command);
  */
 
 backslashResult
-HandleSlashCmds(PsqlSettings *pset,
-                               const char *line,
+HandleSlashCmds(const char *line,
                                PQExpBuffer query_buf,
                                const char **end_of_cmd)
 {
@@ -95,6 +92,12 @@ HandleSlashCmds(PsqlSettings *pset,
        const char *continue_parse = NULL;      /* tell the mainloop where the
                                                                                 * backslash command ended */
 
+#ifdef USE_ASSERT_CHECKING
+    assert(line);
+    assert(query_buf);
+    assert(end_of_cmd);
+#endif
+
        my_line = xstrdup(line);
 
        /*
@@ -135,7 +138,7 @@ HandleSlashCmds(PsqlSettings *pset,
                        switch (quote)
                        {
                                case '"':
-                                       options[i] = unescape(token, pset);
+                                       options[i] = unescape(token);
                                        break;
                                case '\'':
                                        options[i] = xstrdup(token);
@@ -144,7 +147,7 @@ HandleSlashCmds(PsqlSettings *pset,
                                        {
                                                bool            error = false;
                                                FILE       *fd = NULL;
-                                               char       *file = unescape(token, pset);
+                                               char       *file = unescape(token);
                                                PQExpBufferData output;
                                                char            buf[512];
                                                size_t          result;
@@ -200,8 +203,13 @@ HandleSlashCmds(PsqlSettings *pset,
                                default:
                                        if (token[0] == '\\')
                                                continue_parse = options_string + pos;
-                                       else if (token[0] == '$')
-                                               options[i] = xstrdup(interpolate_var(token + 1, pset));
+                                       else if (token[0] == '$') 
+                    {
+                        const char * value = GetVariable(pset.vars, token+1);
+                        if (!value)
+                            value = "";
+                                               options[i] = xstrdup(value);
+                    }
                                        else
                                                options[i] = xstrdup(token);
                        }
@@ -216,7 +224,7 @@ HandleSlashCmds(PsqlSettings *pset,
        }
 
        cmd = my_line;
-       status = exec_command(cmd, options, options_string, query_buf, pset);
+       status = exec_command(cmd, options, options_string, query_buf);
 
        if (status == CMD_UNKNOWN)
        {
@@ -238,15 +246,15 @@ HandleSlashCmds(PsqlSettings *pset,
                new_cmd[0] = cmd[0];
                new_cmd[1] = '\0';
 
-               status = exec_command(new_cmd, (char *const *) new_options, my_line + 2, query_buf, pset);
+               status = exec_command(new_cmd, (char *const *) new_options, my_line + 2, query_buf);
        }
 
        if (status == CMD_UNKNOWN)
        {
-        if (pset->cur_cmd_interactive)
+        if (pset.cur_cmd_interactive)
             fprintf(stderr, "Invalid command \\%s. Try \\? for help.\n", cmd);
         else
-            fprintf(stderr, "%s: invalid command \\%s", pset->progname, cmd);
+            fprintf(stderr, "%s: invalid command \\%s", pset.progname, cmd);
                status = CMD_ERROR;
        }
 
@@ -254,13 +262,10 @@ HandleSlashCmds(PsqlSettings *pset,
                continue_parse += 2;
 
 
-       if (end_of_cmd)
-       {
-               if (continue_parse)
-                       *end_of_cmd = line + (continue_parse - my_line);
-               else
-                       *end_of_cmd = NULL;
-       }
+    if (continue_parse)
+        *end_of_cmd = line + (continue_parse - my_line);
+    else
+        *end_of_cmd = line + strlen(line);
 
        /* clean up */
        for (i = 0; i < NR_OPTIONS && options[i]; i++)
@@ -278,12 +283,11 @@ static backslashResult
 exec_command(const char *cmd,
                         char *const * options,
                         const char *options_string,
-                        PQExpBuffer query_buf,
-                        PsqlSettings *pset)
+                        PQExpBuffer query_buf)
 {
        bool            success = true; /* indicate here if the command ran ok or
                                                                 * failed */
-       bool            quiet = GetVariableBool(pset->vars, "quiet");
+       bool            quiet = QUIET();
 
        backslashResult status = CMD_SKIP_LINE;
 
@@ -291,16 +295,16 @@ exec_command(const char *cmd,
        /* \a -- toggle field alignment This makes little sense but we keep it around. */
        if (strcmp(cmd, "a") == 0)
        {
-               if (pset->popt.topt.format != PRINT_ALIGNED)
-                       success = do_pset("format", "aligned", &pset->popt, quiet);
+               if (pset.popt.topt.format != PRINT_ALIGNED)
+                       success = do_pset("format", "aligned", &pset.popt, quiet);
                else
-                       success = do_pset("format", "unaligned", &pset->popt, quiet);
+                       success = do_pset("format", "unaligned", &pset.popt, quiet);
        }
 
 
        /* \C -- override table title (formerly change HTML caption) */
        else if (strcmp(cmd, "C") == 0)
-               success = do_pset("title", options[0], &pset->popt, quiet);
+               success = do_pset("title", options[0], &pset.popt, quiet);
 
 
        /*----------
@@ -316,25 +320,25 @@ exec_command(const char *cmd,
        {
                if (options[1])
                        /* gave username */
-                       success = do_connect(options[0], options[1], pset);
+                       success = do_connect(options[0], options[1]);
                else
                {
                        if (options[0])
                                /* gave database name */
-                               success = do_connect(options[0], "", pset);             /* empty string is same
-                                                                                                                                * username as before,
-                                                                                                                                * NULL would mean libpq
-                                                                                                                                * default */
+                               success = do_connect(options[0], "");           /* empty string is same
+                                                             * username as before,
+                                                             * NULL would mean libpq
+                                                             * default */
                        else
                                /* connect to default db as default user */
-                               success = do_connect(NULL, NULL, pset);
+                               success = do_connect(NULL, NULL);
                }
        }
 
 
        /* \copy */
-       else if (strcmp(cmd, "copy") == 0)
-               success = do_copy(options_string, pset);
+       else if (strcasecmp(cmd, "copy") == 0)
+               success = do_copy(options_string);
 
        /* \copyright */
        else if (strcmp(cmd, "copyright") == 0)
@@ -350,31 +354,31 @@ exec_command(const char *cmd,
                        case '\0':
             case '?':
                                if (options[0])
-                                       success = describeTableDetails(options[0], pset, show_verbose);
+                                       success = describeTableDetails(options[0], show_verbose);
                                else
                     /* standard listing of interesting things */
-                                       success = listTables("tvs", NULL, pset, show_verbose);
+                                       success = listTables("tvs", NULL, show_verbose);
                                break;
                        case 'a':
-                               success = describeAggregates(options[0], pset);
+                               success = describeAggregates(options[0]);
                                break;
                        case 'd':
-                               success = objectDescription(options[0], pset);
+                               success = objectDescription(options[0]);
                                break;
                        case 'f':
-                               success = describeFunctions(options[0], pset, show_verbose);
+                               success = describeFunctions(options[0], show_verbose);
                                break;
                        case 'l':
-                               success = do_lo_list(pset);
+                               success = do_lo_list();
                                break;
                        case 'o':
-                               success = describeOperators(options[0], pset);
+                               success = describeOperators(options[0]);
                                break;
                        case 'p':
-                               success = permissionsList(options[0], pset);
+                               success = permissionsList(options[0]);
                                break;
                        case 'T':
-                               success = describeTypes(options[0], pset, show_verbose);
+                               success = describeTypes(options[0], show_verbose);
                                break;
                        case 't':
                        case 'v':
@@ -382,9 +386,9 @@ exec_command(const char *cmd,
                        case 's':
                        case 'S':
                                if (cmd[1] == 'S' && cmd[2] == '\0')
-                                       success = listTables("Stvs", NULL, pset, show_verbose);
+                                       success = listTables("Stvs", NULL, show_verbose);
                                else
-                                       success = listTables(&cmd[1], options[0], pset, show_verbose);
+                                       success = listTables(&cmd[1], options[0], show_verbose);
                                break;
                        default:
                                status = CMD_UNKNOWN;
@@ -412,15 +416,15 @@ exec_command(const char *cmd,
 
        /* \f -- change field separator */
        else if (strcmp(cmd, "f") == 0)
-               success = do_pset("fieldsep", options[0], &pset->popt, quiet);
+               success = do_pset("fieldsep", options[0], &pset.popt, quiet);
 
        /* \g means send query */
        else if (strcmp(cmd, "g") == 0)
        {
                if (!options[0])
-                       pset->gfname = NULL;
+                       pset.gfname = NULL;
                else
-                       pset->gfname = xstrdup(options[0]);
+                       pset.gfname = xstrdup(options[0]);
                status = CMD_SEND;
        }
 
@@ -442,10 +446,10 @@ exec_command(const char *cmd,
        /* HTML mode */
        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);
+               if (pset.popt.topt.format != PRINT_HTML)
+                       success = do_pset("format", "html", &pset.popt, quiet);
                else
-                       success = do_pset("format", "aligned", &pset->popt, quiet);
+                       success = do_pset("format", "aligned", &pset.popt, quiet);
     }
 
 
@@ -454,22 +458,22 @@ exec_command(const char *cmd,
        {
                if (!options[0])
                {
-            if (pset->cur_cmd_interactive)
+            if (pset.cur_cmd_interactive)
                 fprintf(stderr, "\\%s: missing required argument\n", cmd);
             else
-                fprintf(stderr, "%s: \\%s: missing required argument", pset->progname, cmd);
+                fprintf(stderr, "%s: \\%s: missing required argument", pset.progname, cmd);
                        success = false;
                }
                else
-                       success = process_file(options[0], pset);
+                       success = process_file(options[0]);
        }
 
 
        /* \l is list databases */
        else if (strcmp(cmd, "l") == 0 || strcmp(cmd, "list") == 0)
-               success = listAllDbs(pset, false);
+               success = listAllDbs(false);
        else if (strcmp(cmd, "l+") == 0 || strcmp(cmd, "list+") == 0)
-               success = listAllDbs(pset, true);
+               success = listAllDbs(true);
 
 
        /* large object things */
@@ -479,45 +483,45 @@ exec_command(const char *cmd,
                {
                        if (!options[1])
                        {
-                if (pset->cur_cmd_interactive)
+                if (pset.cur_cmd_interactive)
                     fprintf(stderr, "\\%s: missing required argument", cmd);
                 else
-                    fprintf(stderr, "%s: \\%s: missing required argument", pset->progname, cmd);
+                    fprintf(stderr, "%s: \\%s: missing required argument", pset.progname, cmd);
                                success = false;
                        }
                        else
-                               success = do_lo_export(pset, options[0], options[1]);
+                               success = do_lo_export(options[0], options[1]);
                }
 
                else if (strcmp(cmd + 3, "import") == 0)
                {
                        if (!options[0])
                        {
-                if (pset->cur_cmd_interactive)
+                if (pset.cur_cmd_interactive)
                     fprintf(stderr, "\\%s: missing required argument", cmd);
                 else
-                    fprintf(stderr, "%s: \\%s: missing required argument", pset->progname, cmd);
+                    fprintf(stderr, "%s: \\%s: missing required argument", pset.progname, cmd);
                                success = false;
                        }
                        else
-                               success = do_lo_import(pset, options[0], options[1]);
+                               success = do_lo_import(options[0], options[1]);
                }
 
                else if (strcmp(cmd + 3, "list") == 0)
-                       success = do_lo_list(pset);
+                       success = do_lo_list();
 
                else if (strcmp(cmd + 3, "unlink") == 0)
                {
                        if (!options[0])
                        {
-                if (pset->cur_cmd_interactive)
+                if (pset.cur_cmd_interactive)
                     fprintf(stderr, "\\%s: missing required argument", cmd);
                 else
-                    fprintf(stderr, "%s: \\%s: missing required argument", pset->progname, cmd);
+                    fprintf(stderr, "%s: \\%s: missing required argument", pset.progname, cmd);
                                success = false;
                        }
                        else
-                               success = do_lo_unlink(pset, options[0]);
+                               success = do_lo_unlink(options[0]);
                }
 
                else
@@ -526,7 +530,7 @@ exec_command(const char *cmd,
 
        /* \o -- set query output */
        else if (strcmp(cmd, "o") == 0 || strcmp(cmd, "out") == 0)
-               success = setQFout(options[0], pset);
+               success = setQFout(options[0]);
 
 
        /* \p prints the current query buffer */
@@ -544,14 +548,14 @@ exec_command(const char *cmd,
        {
                if (!options[0])
                {
-            if (pset->cur_cmd_interactive)
+            if (pset.cur_cmd_interactive)
                 fprintf(stderr, "\\%s: missing required argument", cmd);
             else
-                fprintf(stderr, "%s: \\%s: missing required argument", pset->progname, cmd);
+                fprintf(stderr, "%s: \\%s: missing required argument", pset.progname, cmd);
                        success = false;
                }
                else
-                       success = do_pset(options[0], options[1], &pset->popt, quiet);
+                       success = do_pset(options[0], options[1], &pset.popt, quiet);
        }
 
        /* \q or \quit */
@@ -564,8 +568,8 @@ exec_command(const char *cmd,
                int                     i;
 
                for (i = 0; i < 16 && options[i]; i++)
-                       fputs(options[i], pset->queryFout);
-               fputs("\n", pset->queryFout);
+                       fputs(options[i], pset.queryFout);
+               fputs("\n", pset.queryFout);
        }
 
        /* reset(clear) the buffer */
@@ -607,18 +611,21 @@ exec_command(const char *cmd,
                         */
                        struct _variable *ptr;
 
-                       for (ptr = pset->vars; ptr->next; ptr = ptr->next)
+                       for (ptr = pset.vars; ptr->next; ptr = ptr->next)
                                fprintf(stdout, "%s = '%s'\n", ptr->next->name, ptr->next->value);
                        success = true;
                }
                else
                {
-                       if (!SetVariable(pset->vars, options[0], options[1]))
+            const char * val = options[1];
+            if (!val)
+                val = "";
+                       if (!SetVariable(pset.vars, options[0], val))
                        {
-                if (pset->cur_cmd_interactive)
-                    fprintf(stderr, "\\%s: failed\n", cmd);
+                if (pset.cur_cmd_interactive)
+                    fprintf(stderr, "\\%s: error\n", cmd);
                 else
-                    fprintf(stderr, "%s: \\%s: failed\n", pset->progname, cmd);
+                    fprintf(stderr, "%s: \\%s: error\n", pset.progname, cmd);
 
                                success = false;
                        }
@@ -627,13 +634,26 @@ 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, quiet);
 
 
        /* \T -- define html <table ...> attributes */
        else if (strcmp(cmd, "T") == 0)
-               success = do_pset("tableattr", options[0], &pset->popt, quiet);
+               success = do_pset("tableattr", options[0], &pset.popt, quiet);
 
+    /* \unset */
+    else if (strcmp(cmd, "unset") == 0)
+    {
+        if (!SetVariable(pset.vars, options[0], NULL))
+        {
+            if (pset.cur_cmd_interactive)
+                fprintf(stderr, "\\%s: error\n", cmd);
+            else
+                fprintf(stderr, "%s: \\%s: error\n", pset.progname, cmd);
+
+            success = false;
+                       }
+    }
 
        /* \w -- write query buffer to file */
        else if (strcmp(cmd, "w") == 0 || strcmp(cmd, "write") == 0)
@@ -643,10 +663,10 @@ exec_command(const char *cmd,
 
                if (!options[0])
                {
-            if (pset->cur_cmd_interactive)
+            if (pset.cur_cmd_interactive)
                 fprintf(stderr, "\\%s: missing required argument", cmd);
             else
-                fprintf(stderr, "%s: \\%s: missing required argument", pset->progname, cmd);
+                fprintf(stderr, "%s: \\%s: missing required argument", pset.progname, cmd);
                        success = false;
                }
                else
@@ -698,19 +718,19 @@ 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, quiet);
 
 
        /* list table rights (grant/revoke) */
        else if (strcmp(cmd, "z") == 0)
-               success = permissionsList(options[0], pset);
+               success = permissionsList(options[0]);
 
 
        else if (strcmp(cmd, "!") == 0)
                success = do_shell(options_string);
 
        else if (strcmp(cmd, "?") == 0)
-               slashUsage(pset);
+               slashUsage();
 
 
 #ifdef NOT_USED
@@ -748,7 +768,7 @@ exec_command(const char *cmd,
  * The return value is malloc()'ed.
  */
 static char *
-unescape(const char *source, PsqlSettings *pset)
+unescape(const char *source)
 {
        unsigned char *p;
        bool            esc = false;    /* Last character we saw was the escape
@@ -831,8 +851,9 @@ unescape(const char *source, PsqlSettings *pset)
                                len = strcspn(p + 2, "}");
                                copy = xstrdup(p + 2);
                                copy[len] = '\0';
-                               value = interpolate_var(copy, pset);
-
+                               value = GetVariable(pset.vars, copy);
+                if (!value)
+                    value = "";
                                length += strlen(value) - (len + 3);
                                new = realloc(destination, length);
                                if (!new)
@@ -871,40 +892,42 @@ unescape(const char *source, PsqlSettings *pset)
  *
  * Connects to a database (new_dbname) as a certain user (new_user).
  * The new user can be NULL. A db name of "-" is the same as the old one.
- * (That is, the one currently in pset. But pset->db can also be NULL. A NULL
+ * (That is, the one currently in pset. But pset.db can also be NULL. A NULL
  * dbname is handled by libpq.)
  * Returns true if all ok, false if the new connection couldn't be established
  * but the old one was set back. Otherwise it terminates the program.
  */
 static bool
-do_connect(const char *new_dbname, const char *new_user, PsqlSettings *pset)
+do_connect(const char *new_dbname, const char *new_user)
 {
-       PGconn     *oldconn = pset->db;
+       PGconn     *oldconn = pset.db;
        const char *dbparam = NULL;
        const char *userparam = NULL;
        const char *pwparam = NULL;
        char       *prompted_password = NULL;
-       char       *prompted_user = NULL;
        bool            need_pass;
        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);
+
        /* If dbname is "-" then use old name, else new one (even if NULL) */
-       if (new_dbname && PQdb(oldconn) && (strcmp(new_dbname, "-") == 0 || strcmp(new_dbname, PQdb(oldconn)) == 0))
+       if (oldconn && new_dbname && PQdb(oldconn) && strcmp(new_dbname, "-") == 0)
                dbparam = PQdb(oldconn);
        else
                dbparam = new_dbname;
 
-       /* If user is "" or "-" then use the old one */
-       if (new_user && PQuser(oldconn) && (strcmp(new_user, "") == 0 || strcmp(new_user, "-") == 0 || strcmp(new_user, PQuser(oldconn)) == 0))
+       /* If user is "" then use the old one */
+       if (new_user && PQuser(oldconn) && strcmp(new_user, "")==0)
                userparam = PQuser(oldconn);
-       /* If username is "?" then prompt */
-       else if (new_user && strcmp(new_user, "?") == 0)
-               userparam = prompted_user = simple_prompt("Username: ", 100, true);             /* save for free() */
        else
                userparam = new_user;
 
        /* need to prompt for password? */
-       if (pset->getPassword)
+       if (pset.getPassword)
                pwparam = prompted_password = simple_prompt("Password: ", 100, false);  /* need to save for
                                                                                                                                                                 * free() */
 
@@ -912,7 +935,7 @@ do_connect(const char *new_dbname, const char *new_user, PsqlSettings *pset)
         * Use old password if no new one given (if you didn't have an old
         * one, fine)
         */
-       if (!pwparam)
+       if (!pwparam && oldconn)
                pwparam = PQpass(oldconn);
 
 
@@ -925,18 +948,18 @@ do_connect(const char *new_dbname, const char *new_user, PsqlSettings *pset)
         * the default PGCLIENTENCODING value. -- 1998/12/12 Tatsuo Ishii
         */
 
-       if (!pset->has_client_encoding)
+       if (!pset.has_client_encoding)
                putenv("PGCLIENTENCODING=");
 #endif
 
        do
        {
                need_pass = false;
-               pset->db = PQsetdbLogin(PQhost(oldconn), PQport(oldconn),
+               pset.db = PQsetdbLogin(PQhost(oldconn), PQport(oldconn),
                                                                NULL, NULL, dbparam, userparam, pwparam);
 
-               if (PQstatus(pset->db) == CONNECTION_BAD &&
-                       strcmp(PQerrorMessage(pset->db), "fe_sendauth: no password supplied\n") == 0)
+               if (PQstatus(pset.db) == CONNECTION_BAD &&
+                       strcmp(PQerrorMessage(pset.db), "fe_sendauth: no password supplied\n") == 0)
                {
                        need_pass = true;
                        free(prompted_password);
@@ -946,40 +969,39 @@ do_connect(const char *new_dbname, const char *new_user, PsqlSettings *pset)
        } while (need_pass);
 
        free(prompted_password);
-       free(prompted_user);
 
        /*
         * If connection failed, try at least keep the old one. That's
         * probably more convenient than just kicking you out of the program.
         */
-       if (!pset->db || PQstatus(pset->db) == CONNECTION_BAD)
+       if (!pset.db || PQstatus(pset.db) == CONNECTION_BAD)
        {
-        if (pset->cur_cmd_interactive)
+        if (pset.cur_cmd_interactive)
         {
-            fprintf(stderr, "\\connect: %s", PQerrorMessage(pset->db));
-            PQfinish(pset->db);
+            fprintf(stderr, "%s", PQerrorMessage(pset.db));
+            PQfinish(pset.db);
             if (oldconn)
             {
                 fputs("Previous connection kept\n", stderr);
-                pset->db = oldconn;
+                pset.db = oldconn;
             }
             else
-                pset->db = NULL;
+                pset.db = NULL;
         }
         else
         {
             /* we don't want unpredictable things to
              * happen in scripting mode */
-            fprintf(stderr, "%s: \\connect: %s", pset->progname, PQerrorMessage(pset->db));
-            PQfinish(pset->db);
+            fprintf(stderr, "%s: \\connect: %s", pset.progname, PQerrorMessage(pset.db));
+            PQfinish(pset.db);
                        if (oldconn)
                                PQfinish(oldconn);
-            pset->db = NULL;
+            pset.db = NULL;
                }
        }
        else
        {
-               if (!GetVariable(pset->vars, "quiet"))
+               if (!QUIET())
                {
                        if (userparam != new_user)      /* no new user */
                                printf("You are now connected to database %s.\n", dbparam);
@@ -987,7 +1009,7 @@ do_connect(const char *new_dbname, const char *new_user, PsqlSettings *pset)
                                printf("You are now connected as new user %s.\n", new_user);
                        else /* both new */
                                printf("You are now connected to database %s as user %s.\n",
-                                          PQdb(pset->db), PQuser(pset->db));
+                                          PQdb(pset.db), PQuser(pset.db));
                }
 
                if (oldconn)
@@ -996,6 +1018,12 @@ do_connect(const char *new_dbname, const char *new_user, PsqlSettings *pset)
                success = true;
        }
 
+    /* Update variables */
+    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));
+
        return success;
 }
 
@@ -1191,7 +1219,7 @@ do_edit(const char *filename_arg, PQExpBuffer query_buf)
  * Handler for \i, but can be used for other things as well.
  */
 bool
-process_file(const char *filename, PsqlSettings *pset)
+process_file(const char *filename)
 {
        FILE       *fd;
        int                     result;
@@ -1207,11 +1235,13 @@ process_file(const char *filename, PsqlSettings *pset)
 
        if (!fd)
        {
+        if (!pset.cur_cmd_interactive)
+            fprintf(stderr, "%s: ", pset.progname);
                perror(filename);
                return false;
        }
 
-       result = MainLoop(pset, fd);
+       result = MainLoop(fd);
        fclose(fd);
        return (result == EXIT_SUCCESS);
 }
index 029937e3371135d2decb6aab38173f7d55d419c9..a8cc220e7c939c9e1e9332c71951dd8d45d0f085 100644 (file)
@@ -24,19 +24,18 @@ typedef enum _backslashResult
 
 
 
-backslashResult HandleSlashCmds(PsqlSettings *pset,
-                               const char *line,
+backslashResult
+HandleSlashCmds(const char *line,
                                PQExpBuffer query_buf,
                                const char **end_of_cmd);
 
-bool process_file(const char *filename,
-                        PsqlSettings *pset);
+bool
+process_file(const char *filename);
 
-
-bool do_pset(const char *param,
+bool
+do_pset(const char *param,
                const char *value,
                printQueryOpt * popt,
                bool quiet);
 
-
 #endif
index 584a8bf1c2611c6101bad408250feb7291bc724e..8133faa467aab1128369affd18d4a8051f18b56d 100644 (file)
@@ -1,7 +1,7 @@
-#include <config.h>
 #include <c.h>
 #include "common.h"
 
+#include <errno.h>
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
@@ -12,7 +12,6 @@
 #include <strdup.h>
 #endif
 #include <signal.h>
-#include <assert.h>
 #ifndef WIN32
 #include <unistd.h>                            /* for write() */
 #else
@@ -73,64 +72,46 @@ xstrdup(const char *string)
  * Upon failure, sets stdout and returns false.
  */
 bool
-setQFout(const char *fname, PsqlSettings *pset)
+setQFout(const char *fname)
 {
        bool            status = true;
 
-#ifdef USE_ASSERT_CHECKING
-       assert(pset);
-#else
-       if (!pset)
-               return false;
-#endif
-
        /* Close old file/pipe */
-       if (pset->queryFout && pset->queryFout != stdout && pset->queryFout != stderr)
+       if (pset.queryFout && pset.queryFout != stdout && pset.queryFout != stderr)
        {
-               if (pset->queryFoutPipe)
-                       pclose(pset->queryFout);
+               if (pset.queryFoutPipe)
+                       pclose(pset.queryFout);
                else
-                       fclose(pset->queryFout);
+                       fclose(pset.queryFout);
        }
 
        /* If no filename, set stdout */
        if (!fname || fname[0] == '\0')
        {
-               pset->queryFout = stdout;
-               pset->queryFoutPipe = false;
+               pset.queryFout = stdout;
+               pset.queryFoutPipe = false;
        }
        else if (*fname == '|')
        {
-               const char *pipename = fname + 1;
-
-
-#ifndef __CYGWIN32__
-               pset->queryFout = popen(pipename, "w");
-#else
-               pset->queryFout = popen(pipename, "wb");
-#endif
-               pset->queryFoutPipe = true;
+               pset.queryFout = popen(fname + 1, "w");
+               pset.queryFoutPipe = true;
        }
        else
        {
-#ifndef __CYGWIN32__
-               pset->queryFout = fopen(fname, "w");
-#else
-               pset->queryFout = fopen(fname, "wb");
-#endif
-               pset->queryFoutPipe = false;
+               pset.queryFout = fopen(fname, "w");
+               pset.queryFoutPipe = false;
        }
 
-       if (!pset->queryFout)
+       if (!(pset.queryFout))
        {
-               perror(fname);
-               pset->queryFout = stdout;
-               pset->queryFoutPipe = false;
+               fprintf(stderr, "%s: %s: %s\n", pset.progname, fname, strerror(errno));
+               pset.queryFout = stdout;
+               pset.queryFoutPipe = false;
                status = false;
        }
 
        /* Direct signals */
-       if (pset->queryFoutPipe)
+       if (pset.queryFoutPipe)
                pqsignal(SIGPIPE, SIG_IGN);
        else
                pqsignal(SIGPIPE, SIG_DFL);
@@ -211,93 +192,6 @@ simple_prompt(const char *prompt, int maxlen, bool echo)
 
 
 
-/*
- * interpolate_var()
- *
- * The idea here is that certain variables have a "magic" meaning, such as
- * LastOid. However, you can assign to those variables, but that will shadow
- * the magic meaning, until you unset it. If nothing matches, the value of
- * the environment variable is used.
- *
- * This function only returns NULL if you feed in NULL's (don't do that).
- * Otherwise, the return value is ready for immediate consumption.
- */
-const char *
-interpolate_var(const char *name, PsqlSettings *pset)
-{
-       const char *var;
-
-#ifdef USE_ASSERT_CHECKING
-       assert(name);
-       assert(pset);
-#else
-       if (!name || !pset)
-               return NULL;
-#endif
-
-    var = GetVariable(pset->vars, name);
-    if (var)
-        return var;
-
-       /* otherwise return magic variable */
-
-       /*
-        * (by convention these should be capitalized (but not all caps), to
-        * not be shadowed by regular vars or to shadow env vars)
-        */
-       if (strcmp(name, "Version") == 0)
-               return PG_VERSION_STR;
-
-       if (strcmp(name, "Database") == 0)
-       {
-               if (PQdb(pset->db))
-                       return PQdb(pset->db);
-               else
-                       return "";
-       }
-
-       if (strcmp(name, "User") == 0)
-       {
-               if (PQuser(pset->db))
-                       return PQuser(pset->db);
-               else
-                       return "";
-       }
-
-       if (strcmp(name, "Host") == 0)
-       {
-               if (PQhost(pset->db))
-                       return PQhost(pset->db);
-               else
-                       return "";
-       }
-
-       if (strcmp(name, "Port") == 0)
-       {
-               if (PQport(pset->db))
-                       return PQport(pset->db);
-               else
-                       return "";
-       }
-
-    if (strcmp(name, "LastOid") == 0)
-    {
-        static char buf[24];
-        if (pset->lastOid == InvalidOid)
-            return "";
-        sprintf(buf, "%u", pset->lastOid);
-        return buf;
-    }
-
-       /* env vars */
-       if ((var = getenv(name)))
-               return var;
-
-       return "";
-}
-
-
-
 /*
  * Code to support query cancellation
  *
@@ -333,21 +227,21 @@ handle_sigint(SIGNAL_ARGS)
  * PSQLexec
  *
  * This is the way to send "backdoor" queries (those not directly entered
- * by the user). It is subject to -E (echo_secret) but not -e (echo).
+ * by the user). It is subject to -E but not -e.
  */
 PGresult   *
-PSQLexec(PsqlSettings *pset, const char *query)
+PSQLexec(const char *query)
 {
        PGresult   *res;
        const char *var;
 
-       if (!pset->db)
+       if (!pset.db)
        {
                fputs("You are currently not connected to a database.\n", stderr);
                return NULL;
        }
 
-       var = GetVariable(pset->vars, "echo_secret");
+       var = GetVariable(pset.vars, "ECHO_HIDDEN");
        if (var)
        {
                printf("********* QUERY *********\n%s\n*************************\n\n", query);
@@ -357,50 +251,50 @@ PSQLexec(PsqlSettings *pset, const char *query)
        if (var && strcmp(var, "noexec") == 0)
                return NULL;
 
-       cancelConn = pset->db;
+       cancelConn = pset.db;
        pqsignal(SIGINT, handle_sigint);        /* control-C => cancel */
 
-       res = PQexec(pset->db, query);
+       res = PQexec(pset.db, query);
 
        pqsignal(SIGINT, SIG_DFL);      /* now control-C is back to normal */
 
-       if (PQstatus(pset->db) == CONNECTION_OK)
+       if (PQstatus(pset.db) == CONNECTION_BAD)
        {
-               if (res && (PQresultStatus(res) == PGRES_COMMAND_OK ||
-                                       PQresultStatus(res) == PGRES_TUPLES_OK ||
-                                       PQresultStatus(res) == PGRES_COPY_IN ||
-                                       PQresultStatus(res) == PGRES_COPY_OUT)
-                       )
-                       return res;                     /* Normal success case... */
-               /* Normal failure case --- display error and return NULL */
-               fputs(PQerrorMessage(pset->db), pset->queryFout);
-               PQclear(res);
-               return NULL;
+        if (!pset.cur_cmd_interactive)
+        {
+            fprintf(stderr, "%s: connection to server was lost", pset.progname);
+            exit(EXIT_BADCONN);
+        }
+               fputs("The connection to the server was lost. Attempting reset: ", stderr);
+               PQreset(pset.db);
+               if (PQstatus(pset.db) == CONNECTION_BAD)
+               {
+                       fputs("Failed.\n", stderr);
+                       PQfinish(pset.db);
+                       PQclear(res);
+                       pset.db = NULL;
+            SetVariable(pset.vars, "DBNAME", NULL);
+            SetVariable(pset.vars, "HOST", NULL);
+            SetVariable(pset.vars, "PORT", NULL);
+            SetVariable(pset.vars, "USER", NULL);
+                       return NULL;
+               }
+               else
+                       fputs("Succeeded.\n", stderr);
        }
 
-       /* Lost connection.  Report whatever libpq has to say,
-        * then consider recovery.
-        */
-       fputs(PQerrorMessage(pset->db), pset->queryFout);
-       PQclear(res);
-       if (!pset->cur_cmd_interactive)
-       {
-               fprintf(stderr, "%s: connection to server was lost\n",
-                               pset->progname);
-               exit(EXIT_BADCONN);
-       }
-       fputs("The connection to the server was lost. Attempting reset: ", stderr);
-       fflush(stderr);
-       PQreset(pset->db);
-       if (PQstatus(pset->db) == CONNECTION_BAD)
+       if (res && (PQresultStatus(res) == PGRES_COMMAND_OK ||
+                               PQresultStatus(res) == PGRES_TUPLES_OK ||
+                               PQresultStatus(res) == PGRES_COPY_IN ||
+                               PQresultStatus(res) == PGRES_COPY_OUT)
+               )
+               return res;
+       else
        {
-               fputs("Failed.\n", stderr);
-               PQfinish(pset->db);
-               pset->db = NULL;
+               fputs(PQerrorMessage(pset.db), stderr);
+               PQclear(res);
+               return NULL;
        }
-       else
-               fputs("Succeeded.\n", stderr);
-       return NULL;
 }
 
 
@@ -418,19 +312,19 @@ PSQLexec(PsqlSettings *pset, const char *query)
  * Returns true if the query executed successfully, false otherwise.
  */
 bool
-SendQuery(PsqlSettings *pset, const char *query)
+SendQuery(const char *query)
 {
        bool            success = false;
        PGresult   *results;
        PGnotify   *notify;
 
-       if (!pset->db)
+       if (!pset.db)
        {
                fputs("You are currently not connected to a database.\n", stderr);
                return false;
        }
 
-       if (GetVariableBool(pset->vars, "singlestep"))
+       if (GetVariableBool(pset.vars, "SINGLESTEP"))
        {
                char            buf[3];
 
@@ -443,17 +337,23 @@ SendQuery(PsqlSettings *pset, const char *query)
                if (buf[0] == 'x')
                        return false;
        }
+    else
+    {
+        const char * var = GetVariable(pset.vars, "ECHO");
+        if (var && strcmp(var, "brief")==0)
+            puts(query);
+    }
 
-       cancelConn = pset->db;
+       cancelConn = pset.db;
        pqsignal(SIGINT, handle_sigint);
 
-       results = PQexec(pset->db, query);
+       results = PQexec(pset.db, query);
 
        pqsignal(SIGINT, SIG_DFL);
 
        if (results == NULL)
        {
-               fputs(PQerrorMessage(pset->db), pset->queryFout);
+               fputs(PQerrorMessage(pset.db), pset.queryFout);
                success = false;
        }
        else
@@ -461,24 +361,30 @@ SendQuery(PsqlSettings *pset, const char *query)
                switch (PQresultStatus(results))
                {
                        case PGRES_TUPLES_OK:
-                               if (pset->gfname)
+                /* write output to \g argument, if any */
+                               if (pset.gfname)
                                {
-                                       PsqlSettings settings_copy = *pset;
+                                       FILE * queryFout_copy = pset.queryFout;
+                    bool queryFoutPipe_copy = pset.queryFoutPipe;
+                    pset.queryFout = NULL; /* so it doesn't get closed */
 
-                                       settings_copy.queryFout = stdout;
-                                       if (!setQFout(pset->gfname, &settings_copy))
+                    /* open file/pipe */
+                                       if (!setQFout(pset.gfname))
                                        {
                                                success = false;
                                                break;
                                        }
 
-                                       printQuery(results, &settings_copy.popt, settings_copy.queryFout);
+                                       printQuery(results, &pset.popt, pset.queryFout);
 
                                        /* close file/pipe */
-                                       setQFout(NULL, &settings_copy);
+                                       setQFout(NULL);
 
-                                       free(pset->gfname);
-                                       pset->gfname = NULL;
+                                       free(pset.gfname);
+                                       pset.gfname = NULL;
+
+                                       pset.queryFout = queryFout_copy;
+                    pset.queryFoutPipe = queryFoutPipe_copy;
 
                                        success = true;
                                        break;
@@ -486,77 +392,83 @@ SendQuery(PsqlSettings *pset, const char *query)
                                else
                                {
                                        success = true;
-                                       printQuery(results, &pset->popt, pset->queryFout);
+                                       printQuery(results, &pset.popt, pset.queryFout);
                                }
                                break;
                        case PGRES_EMPTY_QUERY:
                                success = true;
                                break;
                        case PGRES_COMMAND_OK:
+            {
+                char buf[10];
+
                                success = true;
-                pset->lastOid = PQoidValue(results);
-                if (!GetVariableBool(pset->vars, "quiet"))
-                    fprintf(pset->queryFout, "%s\n", PQcmdStatus(results));
+                sprintf(buf, "%u", (unsigned int)PQoidValue(results));
+                if (!QUIET())
+                    fprintf(pset.queryFout, "%s\n", PQcmdStatus(results));
+                SetVariable(pset.vars, "LASTOID", buf);
                                break;
-
+            }
                        case PGRES_COPY_OUT:
-                               success = handleCopyOut(pset->db, pset->queryFout);
+                               success = handleCopyOut(pset.db, pset.queryFout);
                                break;
 
                        case PGRES_COPY_IN:
-                               if (pset->cur_cmd_interactive && !GetVariable(pset->vars, "quiet"))
+                               if (pset.cur_cmd_interactive && !QUIET())
                                        puts("Enter data to be copied followed by a newline.\n"
                                                 "End with a backslash and a period on a line by itself.");
 
-                               success = handleCopyIn(pset->db, pset->cur_cmd_source,
-                                                                          pset->cur_cmd_interactive ? get_prompt(pset, PROMPT_COPY) : NULL);
+                               success = handleCopyIn(pset.db, pset.cur_cmd_source,
+                                                                          pset.cur_cmd_interactive ? get_prompt(PROMPT_COPY) : NULL);
                                break;
 
                        case PGRES_NONFATAL_ERROR:
                        case PGRES_FATAL_ERROR:
                        case PGRES_BAD_RESPONSE:
                                success = false;
-                               fputs(PQerrorMessage(pset->db), stderr);
+                               fputs(PQerrorMessage(pset.db), stderr);
                                break;
                }
 
-        fflush(pset->queryFout);
+        fflush(pset.queryFout);
 
-               if (PQstatus(pset->db) == CONNECTION_BAD)
+               if (PQstatus(pset.db) == CONNECTION_BAD)
                {
-            if (!pset->cur_cmd_interactive)
+            if (!pset.cur_cmd_interactive)
             {
-                fprintf(stderr, "%s: connection to server was lost\n",
-                                               pset->progname);
+                fprintf(stderr, "%s: connection to server was lost", pset.progname);
                 exit(EXIT_BADCONN);
             }
                        fputs("The connection to the server was lost. Attempting reset: ", stderr);
-                       fflush(stderr);
-                       PQreset(pset->db);
-                       if (PQstatus(pset->db) == CONNECTION_BAD)
+                       PQreset(pset.db);
+                       if (PQstatus(pset.db) == CONNECTION_BAD)
                        {
                                fputs("Failed.\n", stderr);
-                               PQfinish(pset->db);
-                               pset->db = NULL;
+                               PQfinish(pset.db);
                                PQclear(results);
+                               pset.db = NULL;
+                SetVariable(pset.vars, "DBNAME", NULL);
+                SetVariable(pset.vars, "HOST", NULL);
+                SetVariable(pset.vars, "PORT", NULL);
+                SetVariable(pset.vars, "USER", NULL);
                                return false;
                        }
                        else
                                fputs("Succeeded.\n", stderr);
                }
-
+        
                /* check for asynchronous notification returns */
-               while ((notify = PQnotifies(pset->db)) != NULL)
+               while ((notify = PQnotifies(pset.db)) != NULL)
                {
-                       fprintf(pset->queryFout, "Asynchronous NOTIFY '%s' from backend with pid '%d' received.\n",
+                       fprintf(pset.queryFout, "Asynchronous NOTIFY '%s' from backend with pid '%d' received.\n",
                                        notify->relname, notify->be_pid);
                        free(notify);
-            fflush(pset->queryFout);
+            fflush(pset.queryFout);
                }
 
                if (results)
                        PQclear(results);
-       }
+    }
 
        return success;
 }
index e3924e9d92d99b2a66825e0c2e5a33265b89f2ae..7d285d01ccd64f8546452030f13f3a60eb8c75a1 100644 (file)
@@ -8,18 +8,15 @@ char *
                        xstrdup(const char *string);
 
 bool
-                       setQFout(const char *fname, PsqlSettings *pset);
+                       setQFout(const char *fname);
 
 char *
                        simple_prompt(const char *prompt, int maxlen, bool echo);
 
-const char *
-                       interpolate_var(const char *name, PsqlSettings *pset);
-
 PGresult   *
-                       PSQLexec(PsqlSettings *pset, const char *query);
+                       PSQLexec(const char *query);
 
 bool
-                       SendQuery(PsqlSettings *pset, const char *query);
+                       SendQuery(const char *query);
 
 #endif  /* COMMON_H */
index 800a8f41eda81de64f48a797cbdc1a21ec91af8b..66449873346100029b02b0b0fdcb477044f5a192 100644 (file)
@@ -1,4 +1,3 @@
-#include <config.h>
 #include <c.h>
 #include "copy.h"
 
@@ -36,7 +35,7 @@
 struct copy_options
 {
        char       *table;
-       char       *file;
+       char       *file;  /* NULL = stdin/stdout */
        bool            from;
        bool            binary;
        bool            oids;
@@ -59,7 +58,7 @@ free_copy_options(struct copy_options * ptr)
 
 
 static struct copy_options *
-parse_slash_copy(const char *args, PsqlSettings *pset)
+parse_slash_copy(const char *args)
 {
        struct copy_options *result;
        char       *line;
@@ -132,17 +131,15 @@ parse_slash_copy(const char *args, PsqlSettings *pset)
 
        if (!error)
        {
-               token = strtokx(NULL, " \t", "'", '\\', NULL, NULL);
+               token = strtokx(NULL, " \t", "'", '\\', &quote, NULL);
                if (!token)
                        error = true;
-               else
+               else if (!quote && (strcasecmp(token, "stdin")==0 || strcasecmp(token, "stdout")==0))
+            result->file = NULL;
+        else
                        result->file = xstrdup(token);
        }
 
-#ifdef USE_ASSERT_CHECKING
-       assert(error || result->file);
-#endif
-
        if (!error)
        {
                token = strtokx(NULL, " \t", NULL, '\\', NULL, NULL);
@@ -194,8 +191,8 @@ parse_slash_copy(const char *args, PsqlSettings *pset)
 
        if (error)
        {
-        if (!pset->cur_cmd_interactive)
-            fprintf(stderr, "%s: ", pset->progname);
+        if (!pset.cur_cmd_interactive)
+            fprintf(stderr, "%s: ", pset.progname);
         fputs("\\copy: parse error at ", stderr);
                if (!token)
                        fputs("end of line", stderr);
@@ -217,7 +214,7 @@ parse_slash_copy(const char *args, PsqlSettings *pset)
  * file or route its response into the file.
  */
 bool
-do_copy(const char *args, PsqlSettings *pset)
+do_copy(const char *args)
 {
        char            query[128 + NAMEDATALEN];
        FILE       *copystream;
@@ -226,7 +223,7 @@ do_copy(const char *args, PsqlSettings *pset)
        bool            success;
 
        /* parse options */
-       options = parse_slash_copy(args, pset);
+       options = parse_slash_copy(args);
 
        if (!options)
                return false;
@@ -242,9 +239,9 @@ do_copy(const char *args, PsqlSettings *pset)
                strcat(query, "WITH OIDS ");
 
        if (options->from)
-               strcat(query, "FROM stdin");
+               strcat(query, "FROM STDIN");
        else
-               strcat(query, "TO stdout");
+               strcat(query, "TO STDOUT");
 
 
        if (options->delim)
@@ -254,24 +251,32 @@ do_copy(const char *args, PsqlSettings *pset)
                strcat(query, "'");
        }
 
+    if (options->null)
+    {
+               strcat(query, " WITH NULL AS '");
+               strcat(query, options->null);
+               strcat(query, "'");
+       }
 
        if (options->from)
-#ifndef __CYGWIN32__
-               copystream = fopen(options->file, "r");
-#else
-               copystream = fopen(options->file, "rb");
-#endif
+    {
+        if (options->file)
+            copystream = fopen(options->file, "r");
+        else
+            copystream = stdin;
+    }
        else
-#ifndef __CYGWIN32__
-               copystream = fopen(options->file, "w");
-#else
-               copystream = fopen(options->file, "wb");
-#endif
+    {
+        if (options->file)
+            copystream = fopen(options->file, "w");
+        else
+            copystream = stdout;
+    }
 
        if (!copystream)
        {
-        if (!pset->cur_cmd_interactive)
-            fprintf(stderr, "%s: ", pset->progname);
+        if (!pset.cur_cmd_interactive)
+            fprintf(stderr, "%s: ", pset.progname);
                fprintf(stderr,
                                "unable to open file %s: %s\n",
                                options->file, strerror(errno));
@@ -279,40 +284,40 @@ do_copy(const char *args, PsqlSettings *pset)
                return false;
        }
 
-       result = PSQLexec(pset, query);
+       result = PSQLexec(query);
 
        switch (PQresultStatus(result))
        {
                case PGRES_COPY_OUT:
-                       success = handleCopyOut(pset->db, copystream);
+                       success = handleCopyOut(pset.db, copystream);
                        break;
                case PGRES_COPY_IN:
-                       success = handleCopyIn(pset->db, copystream, NULL);
+                       success = handleCopyIn(pset.db, copystream, NULL);
                        break;
                case PGRES_NONFATAL_ERROR:
                case PGRES_FATAL_ERROR:
                case PGRES_BAD_RESPONSE:
                        success = false;
-                       fputs(PQerrorMessage(pset->db), stderr);
+                       fputs(PQerrorMessage(pset.db), stderr);
                        break;
                default:
                        success = false;
-            if (!pset->cur_cmd_interactive)
-                fprintf(stderr, "%s: ", pset->progname);
+            if (!pset.cur_cmd_interactive)
+                fprintf(stderr, "%s: ", pset.progname);
                        fprintf(stderr, "\\copy: unexpected response (%d)\n", PQresultStatus(result));
        }
 
        PQclear(result);
 
-       if (!GetVariable(pset->vars, "quiet"))
+       if (!success)
        {
-               if (success)
-                       puts("Successfully copied");
-               else
-                       puts("Copy failed");
+        if (!pset.cur_cmd_interactive)
+            fprintf(stderr, "%s: ", pset.progname);
+        fprintf(stderr, "\\copy failed\n");
        }
 
-       fclose(copystream);
+    if (copystream != stdout && copystream != stdin)
+        fclose(copystream);
        free_copy_options(options);
        return success;
 }
@@ -396,7 +401,7 @@ handleCopyIn(PGconn *conn, FILE *copystream, const char *prompt)
 
        while (!copydone)
        {                                                       /* for each input line ... */
-               if (prompt && isatty(fileno(stdin)))
+               if (prompt && isatty(fileno(copystream)))
                {
                        fputs(prompt, stdout);
                        fflush(stdout);
index 6e01c5457d1f2487d69e66522d3a5f924779aa4d..840fb27fe12c8c2e843cf2f705d95896500c7198 100644 (file)
@@ -8,7 +8,7 @@
 
 /* handler for \copy */
 bool
-                       do_copy(const char *args, PsqlSettings *pset);
+                       do_copy(const char *args);
 
 
 /* lower level processors for copy in/out streams */
index f4ac7f1bcd36e1d07fe05e3b2c431ea49eebfc9c..1d544837546990ce7729b6349d742f7ccfec808a 100644 (file)
  * takes an optional regexp to match specific aggregates by name
  */
 bool
-describeAggregates(const char *name, PsqlSettings *pset)
+describeAggregates(const char *name)
 {
        char            buf[384 + 2 * REGEXP_CUTOFF];
        PGresult   *res;
-       printQueryOpt myopt = pset->popt;
+       printQueryOpt myopt = pset.popt;
 
        /*
         * There are two kinds of aggregates: ones that work on particular
@@ -72,14 +72,14 @@ describeAggregates(const char *name, PsqlSettings *pset)
 
        strcat(buf, "ORDER BY \"Name\", \"Type\"");
 
-       res = PSQLexec(pset, buf);
+       res = PSQLexec(buf);
        if (!res)
                return false;
 
        myopt.nullPrint = NULL;
        myopt.title = "List of aggregates";
 
-       printQuery(res, &myopt, pset->queryFout);
+       printQuery(res, &myopt, pset.queryFout);
 
        PQclear(res);
        return true;
@@ -90,11 +90,11 @@ describeAggregates(const char *name, PsqlSettings *pset)
  * Takes an optional regexp to narrow down the function name
  */
 bool
-describeFunctions(const char *name, PsqlSettings *pset, bool verbose)
+describeFunctions(const char *name, bool verbose)
 {
        char            buf[384 + REGEXP_CUTOFF];
        PGresult   *res;
-       printQueryOpt myopt = pset->popt;
+       printQueryOpt myopt = pset.popt;
 
        /*
         * we skip in/out funcs by excluding functions that take some
@@ -125,14 +125,14 @@ describeFunctions(const char *name, PsqlSettings *pset, bool verbose)
        }
        strcat(buf, "ORDER BY \"Function\", \"Result\", \"Arguments\"");
 
-       res = PSQLexec(pset, buf);
+       res = PSQLexec(buf);
        if (!res)
                return false;
 
        myopt.nullPrint = NULL;
        myopt.title = "List of functions";
 
-       printQuery(res, &myopt, pset->queryFout);
+       printQuery(res, &myopt, pset.queryFout);
 
        PQclear(res);
        return true;
@@ -145,11 +145,11 @@ describeFunctions(const char *name, PsqlSettings *pset, bool verbose)
  * describe types
  */
 bool
-describeTypes(const char *name, PsqlSettings *pset, bool verbose)
+describeTypes(const char *name, bool verbose)
 {
        char            buf[256 + REGEXP_CUTOFF];
        PGresult   *res;
-       printQueryOpt myopt = pset->popt;
+       printQueryOpt myopt = pset.popt;
 
        strcpy(buf, "SELECT t.typname AS \"Type\"");
     if (verbose)
@@ -169,14 +169,14 @@ describeTypes(const char *name, PsqlSettings *pset, bool verbose)
        }
        strcat(buf, "ORDER BY t.typname;");
 
-       res = PSQLexec(pset, buf);
+       res = PSQLexec(buf);
        if (!res)
                return false;
 
        myopt.nullPrint = NULL;
        myopt.title = "List of types";
 
-       printQuery(res, &myopt, pset->queryFout);
+       printQuery(res, &myopt, pset.queryFout);
 
        PQclear(res);
        return true;
@@ -187,11 +187,11 @@ describeTypes(const char *name, PsqlSettings *pset, bool verbose)
 /* \do
  */
 bool
-describeOperators(const char *name, PsqlSettings *pset)
+describeOperators(const char *name)
 {
        char            buf[1536 + 3 * REGEXP_CUTOFF];
        PGresult   *res;
-       printQueryOpt myopt = pset->popt;
+       printQueryOpt myopt = pset.popt;
 
        strcpy(buf,
            "SELECT o.oprname AS \"Op\",\n"
@@ -251,14 +251,14 @@ describeOperators(const char *name, PsqlSettings *pset)
        }
        strcat(buf, "\nORDER BY \"Op\", \"Left arg\", \"Right arg\", \"Result\"");
 
-       res = PSQLexec(pset, buf);
+       res = PSQLexec(buf);
        if (!res)
                return false;
 
        myopt.nullPrint = NULL;
        myopt.title = "List of operators";
 
-       printQuery(res, &myopt, pset->queryFout);
+       printQuery(res, &myopt, pset.queryFout);
 
        PQclear(res);
        return true;
@@ -271,11 +271,11 @@ describeOperators(const char *name, PsqlSettings *pset)
  * for \l, \list, and -l switch
  */
 bool
-listAllDbs(PsqlSettings *pset, bool desc)
+listAllDbs(bool desc)
 {
        PGresult   *res;
        char            buf[512];
-       printQueryOpt myopt = pset->popt;
+       printQueryOpt myopt = pset.popt;
 
        strcpy(buf,
            "SELECT pg_database.datname as \"Database\",\n"
@@ -306,14 +306,14 @@ listAllDbs(PsqlSettings *pset, bool desc)
 
     strcat(buf, "ORDER BY \"Database\"");
 
-       res = PSQLexec(pset, buf);
+       res = PSQLexec(buf);
        if (!res)
                return false;
 
        myopt.nullPrint = NULL;
        myopt.title = "List of databases";
 
-       printQuery(res, &myopt, pset->queryFout);
+       printQuery(res, &myopt, pset.queryFout);
 
        PQclear(res);
        return true;
@@ -325,11 +325,11 @@ listAllDbs(PsqlSettings *pset, bool desc)
  *
  */
 bool
-permissionsList(const char *name, PsqlSettings *pset)
+permissionsList(const char *name)
 {
        char            descbuf[256 + REGEXP_CUTOFF];
        PGresult   *res;
-       printQueryOpt myopt = pset->popt;
+       printQueryOpt myopt = pset.popt;
 
        descbuf[0] = '\0';
        /* Currently, we ignore indexes since they have no meaningful rights */
@@ -346,15 +346,15 @@ permissionsList(const char *name, PsqlSettings *pset)
        }
        strcat(descbuf, "ORDER BY relname");
 
-       res = PSQLexec(pset, descbuf);
+       res = PSQLexec(descbuf);
        if (!res)
                return false;
 
     myopt.nullPrint = NULL;
-    sprintf(descbuf, "Access permissions for database \"%s\"", PQdb(pset->db));
+    sprintf(descbuf, "Access permissions for database \"%s\"", PQdb(pset.db));
     myopt.title = descbuf;
 
-    printQuery(res, &myopt, pset->queryFout);
+    printQuery(res, &myopt, pset.queryFout);
 
        PQclear(res);
        return true;
@@ -371,11 +371,11 @@ permissionsList(const char *name, PsqlSettings *pset)
  * lists of things, there are other \d? commands.
  */
 bool
-objectDescription(const char *object, PsqlSettings *pset)
+objectDescription(const char *object)
 {
        char            descbuf[2048 + 7 * REGEXP_CUTOFF];
        PGresult   *res;
-       printQueryOpt myopt = pset->popt;
+       printQueryOpt myopt = pset.popt;
 
        descbuf[0] = '\0';
 
@@ -466,7 +466,7 @@ objectDescription(const char *object, PsqlSettings *pset)
        strcat(descbuf, "\nORDER BY \"Name\"");
 
 
-       res = PSQLexec(pset, descbuf);
+       res = PSQLexec(descbuf);
        if (!res)
                return false;
 
@@ -474,7 +474,7 @@ objectDescription(const char *object, PsqlSettings *pset)
        myopt.nullPrint = NULL;
        myopt.title = "Object descriptions";
 
-       printQuery(res, &myopt, pset->queryFout);
+       printQuery(res, &myopt, pset.queryFout);
 
        PQclear(res);
        return true;
@@ -507,11 +507,11 @@ xmalloc(size_t size)
 
 
 bool
-describeTableDetails(const char *name, PsqlSettings *pset, bool desc)
+describeTableDetails(const char *name, bool desc)
 {
        char            buf[512 + INDEX_MAX_KEYS * NAMEDATALEN];
        PGresult   *res = NULL;
-       printTableOpt myopt = pset->popt.topt;
+       printTableOpt myopt = pset.popt.topt;
        int                     i;
        const char *view_def = NULL;
        const char *headers[5];
@@ -536,14 +536,14 @@ describeTableDetails(const char *name, PsqlSettings *pset, bool desc)
            "SELECT relhasindex, relkind, relchecks, reltriggers, relhasrules\n"
            "FROM pg_class WHERE relname='%s'",
            name);
-    res = PSQLexec(pset, buf);
+    res = PSQLexec(buf);
     if (!res)
        return false;
 
        /* Did we get anything? */
        if (PQntuples(res) == 0)
        {
-               if (!GetVariableBool(pset->vars, "quiet"))
+               if (!QUIET())
                        fprintf(stderr, "Did not find any relation named \"%s\".\n", name);
                PQclear(res);
                return false;
@@ -587,7 +587,7 @@ describeTableDetails(const char *name, PsqlSettings *pset, bool desc)
        strcat(buf, "'\n  AND a.attnum > 0 AND a.attrelid = c.oid AND a.atttypid = t.oid\n"
                   "ORDER BY a.attnum");
 
-       res = PSQLexec(pset, buf);
+       res = PSQLexec(buf);
        if (!res)
                return false;
 
@@ -595,7 +595,7 @@ describeTableDetails(const char *name, PsqlSettings *pset, bool desc)
     if (tableinfo.hasrules) {
        PGresult *result;
        sprintf(buf, "SELECT definition FROM pg_views WHERE viewname = '%s'", name);
-       result = PSQLexec(pset, buf);
+       result = PSQLexec(buf);
        if (!result)
        {
            PQclear(res);
@@ -655,7 +655,7 @@ describeTableDetails(const char *name, PsqlSettings *pset, bool desc)
                        "WHERE c.relname = '%s' AND c.oid = d.adrelid AND d.adnum = %s",
                        name, PQgetvalue(res, i, 6));
 
-               result = PSQLexec(pset, buf);
+               result = PSQLexec(buf);
                if (!result)
                    error = true;
                else
@@ -710,7 +710,7 @@ describeTableDetails(const char *name, PsqlSettings *pset, bool desc)
                "WHERE i.indexrelid = c.oid AND c.relname = '%s' AND c.relam = a.oid",
                name);
 
-       result = PSQLexec(pset, buf);
+       result = PSQLexec(buf);
        if (!result)
            error = true;
        else
@@ -750,7 +750,7 @@ describeTableDetails(const char *name, PsqlSettings *pset, bool desc)
                    "WHERE c.relname = '%s' AND c.oid = i.indrelid AND i.indexrelid = c2.oid\n"
                    "ORDER BY c2.relname",
                    name);
-           result1 = PSQLexec(pset, buf);
+           result1 = PSQLexec(buf);
            if (!result1)
                error = true;
            else
@@ -764,7 +764,7 @@ describeTableDetails(const char *name, PsqlSettings *pset, bool desc)
                    "FROM pg_relcheck r, pg_class c\n"
                    "WHERE c.relname='%s' AND c.oid = r.rcrelid",
                    name);
-           result2 = PSQLexec(pset, buf);
+           result2 = PSQLexec(buf);
            if (!result2)
                error = true;
            else
@@ -779,7 +779,7 @@ describeTableDetails(const char *name, PsqlSettings *pset, bool desc)
                    "FROM pg_rewrite r, pg_class c\n"
                    "WHERE c.relname='%s' AND c.oid = r.ev_class",
                    name);
-           result3 = PSQLexec(pset, buf);
+           result3 = PSQLexec(buf);
            if (!result3)
                error = true;
            else
@@ -794,7 +794,7 @@ describeTableDetails(const char *name, PsqlSettings *pset, bool desc)
                    "FROM pg_trigger t, pg_class c\n"
                    "WHERE c.relname='%s' AND c.oid = t.tgrelid",
                    name);
-           result4 = PSQLexec(pset, buf);
+           result4 = PSQLexec(buf);
            if (!result4)
                error = true;
            else
@@ -863,7 +863,7 @@ describeTableDetails(const char *name, PsqlSettings *pset, bool desc)
 
     if (!error) {
        myopt.tuples_only = false;
-       printTable(title, headers, (const char**)cells, (const char**)footers, "llll", &myopt, pset->queryFout);
+       printTable(title, headers, (const char**)cells, (const char**)footers, "llll", &myopt, pset.queryFout);
     }
 
        /* clean up */
@@ -906,7 +906,7 @@ describeTableDetails(const char *name, PsqlSettings *pset, bool desc)
  * tries to fix this the painful way, hopefully outer joins will be done sometime.
  */
 bool
-listTables(const char *infotype, const char *name, PsqlSettings *pset, bool desc)
+listTables(const char *infotype, const char *name, bool desc)
 {
        bool            showTables = strchr(infotype, 't') != NULL;
        bool            showIndices = strchr(infotype, 'i') != NULL;
@@ -916,7 +916,7 @@ listTables(const char *infotype, const char *name, PsqlSettings *pset, bool desc
 
        char            buf[3072 + 8 * REGEXP_CUTOFF];
        PGresult   *res;
-       printQueryOpt myopt = pset->popt;
+       printQueryOpt myopt = pset.popt;
 
        buf[0] = '\0';
 
@@ -1093,20 +1093,24 @@ listTables(const char *infotype, const char *name, PsqlSettings *pset, bool desc
        strcat(buf, "\nORDER BY \"Name\"");
 
 
-       res = PSQLexec(pset, buf);
+       res = PSQLexec(buf);
        if (!res)
                return false;
 
-       if (PQntuples(res) == 0)
-               fprintf(pset->queryFout, "No matching relations found.\n");
-
+       if (PQntuples(res) == 0 && !QUIET())
+    {
+        if (name)
+            fprintf(pset.queryFout, "No matching relations found.\n");
+        else
+            fprintf(pset.queryFout, "No relations found.\n");
+    }
        else
        {
                myopt.topt.tuples_only = false;
                myopt.nullPrint = NULL;
                myopt.title = "List of relations";
 
-               printQuery(res, &myopt, pset->queryFout);
+               printQuery(res, &myopt, pset.queryFout);
        }
 
        PQclear(res);
index 960942f52ff584df3a56534978386bdfe7ed040b..834375b252fc9e35e4ff0d255ad2284a19e43323 100644 (file)
@@ -5,30 +5,30 @@
 #include "settings.h"
 
 /* \da */
-bool describeAggregates(const char *name, PsqlSettings *pset);
+bool describeAggregates(const char *name);
 
 /* \df */
-bool describeFunctions(const char *name, PsqlSettings *pset, bool verbose);
+bool describeFunctions(const char *name, bool verbose);
 
 /* \dT */
-bool describeTypes(const char *name, PsqlSettings *pset, bool verbose);
+bool describeTypes(const char *name, bool verbose);
 
 /* \do */
-bool describeOperators(const char *name, PsqlSettings *pset);
+bool describeOperators(const char *name);
 
 /* \z (or \dp) */
-bool permissionsList(const char *name, PsqlSettings *pset);
+bool permissionsList(const char *name);
 
 /* \dd */
-bool objectDescription(const char *object, PsqlSettings *pset);
+bool objectDescription(const char *object);
 
 /* \d foo */
-bool describeTableDetails(const char *name, PsqlSettings *pset, bool desc);
+bool describeTableDetails(const char *name, bool desc);
 
 /* \l */
-bool listAllDbs(PsqlSettings *pset, bool desc);
+bool listAllDbs(bool desc);
 
 /* \dt, \di, \ds, \dS, etc. */
-bool listTables(const char *infotype, const char *name, PsqlSettings *pset, bool desc);
+bool listTables(const char *infotype, const char *name, bool desc);
 
 #endif  /* DESCRIBE_H */
index c108743deb2ed63969cd5aade9f95715795f58fe..47fc0d8fc51da596f7f12f7843f6b3923628853c 100644 (file)
@@ -149,7 +149,7 @@ struct winsize
 #endif
 
 void
-slashUsage(PsqlSettings *pset)
+slashUsage(void)
 {
        bool            usePipe = false;
        const char *pagerenv;
@@ -157,7 +157,7 @@ slashUsage(PsqlSettings *pset)
        struct winsize screen_size;
 
 #ifdef TIOCGWINSZ
-       if (pset->notty == 0 &&
+       if (pset.notty == 0 &&
                (ioctl(fileno(stdout), TIOCGWINSZ, &screen_size) == -1 ||
                 screen_size.ws_col == 0 ||
                 screen_size.ws_row == 0))
@@ -169,7 +169,7 @@ slashUsage(PsqlSettings *pset)
        }
 #endif
 
-       if (pset->notty == 0 &&
+       if (pset.notty == 0 &&
                (pagerenv = getenv("PAGER")) &&
                (pagerenv[0] != '\0') &&
                screen_size.ws_row <= 36 &&
@@ -184,7 +184,7 @@ slashUsage(PsqlSettings *pset)
        /* if you add/remove a line here, change the row test above */
        fprintf(fout, " \\?             help\n");
        fprintf(fout, " \\c[onnect] [dbname|- [user|?]]\n"
-                  "                 connect to new database (currently '%s')\n", PQdb(pset->db));
+                  "                 connect to new database (currently '%s')\n", PQdb(pset.db));
        fprintf(fout, " \\copy ...      perform SQL COPY with data stream to the client machine");
        fprintf(fout, " \\copyright     show PostgreSQL usage and distribution terms\n");
        fprintf(fout, " \\d <table>     describe table (or view, index, sequence)\n");
@@ -209,9 +209,10 @@ slashUsage(PsqlSettings *pset)
        fprintf(fout, " \\qecho <text>  write text to query output stream (see \\o)\n");
        fprintf(fout, " \\r             reset (clear) the query buffer\n");
        fprintf(fout, " \\s [fname]     print history or save it in <fname>\n");
-       fprintf(fout, " \\set <var> [value]  set/unset internal variable\n");
-       fprintf(fout, " \\t             don't show table headers or footers (currently %s)\n", ON(pset->popt.topt.tuples_only));
-       fprintf(fout, " \\x             toggle expanded output (currently %s)\n", ON(pset->popt.topt.expanded));
+       fprintf(fout, " \\set <var> <value>  set internal variable\n");
+       fprintf(fout, " \\t             don't show table headers or footers (currently %s)\n", ON(pset.popt.topt.tuples_only));
+       fprintf(fout, " \\unset <var>   unset (delete) internal variable\n");
+       fprintf(fout, " \\x             toggle expanded output (currently %s)\n", ON(pset.popt.topt.expanded));
        fprintf(fout, " \\w <fname>     write current query buffer to a file\n");
        fprintf(fout, " \\z             list table access permissions\n");
        fprintf(fout, " \\! [cmd]       shell escape or command\n");
index 791e0313ca1033b56de71c5b500934efda11ee85..db709268568ce22f28552bf13b4b97da8f30ad04 100644 (file)
@@ -5,7 +5,7 @@
 
 void           usage(void);
 
-void           slashUsage(PsqlSettings *pset);
+void           slashUsage(void);
 
 void           helpSQL(const char *topic);
 
index 1775dffb8341a051756b93cfc16ce8f97c223e1e..6607d7f162bd0dc834666428fc50c263a60d2ee8 100644 (file)
@@ -29,6 +29,10 @@ char *
 gets_interactive(const char *prompt)
 {
        char       *s;
+#ifdef USE_HISTORY
+    const char *var;
+    static char * prev_hist = NULL;
+#endif
 
 #ifdef USE_READLINE
        if (useReadline)
@@ -44,8 +48,19 @@ gets_interactive(const char *prompt)
 #endif
 
 #ifdef USE_HISTORY
-       if (useHistory && s && s[0] != '\0')
-               add_history(s);
+    if (useHistory && s && s[0] != '\0')
+    {
+        var = GetVariable(pset.vars, "HISTCONTROL");
+        if (!var || (var
+            && !((strcmp(var, "ignorespace") == 0 || strcmp(var, "ignoreboth") ==0) && s[0] == ' ' )
+            && !((strcmp(var, "ignoredups") == 0 || strcmp(var, "ignoreboth") ==0) && prev_hist && strcmp(s, prev_hist) == 0)
+            ))
+        {
+            free(prev_hist);
+            prev_hist = strdup(s);
+            add_history(s);
+        }
+    }
 #endif
 
        return s;
@@ -93,14 +108,14 @@ gets_fromFile(FILE *source)
  * The only "flag" right now is 1 for use readline & history.
  */
 void
-initializeInput(int flags, PsqlSettings *pset)
+initializeInput(int flags)
 {
 #ifdef USE_READLINE
        if (flags == 1)
        {
                useReadline = true;
                rl_readline_name = "psql";
-        initialize_readline(&(pset->db));
+        initialize_readline(&(pset.db));
        }
 #endif
 
@@ -110,6 +125,7 @@ initializeInput(int flags, PsqlSettings *pset)
                const char *home;
 
                useHistory = true;
+        SetVariable(pset.vars, "HISTSIZE", "500");
                using_history();
                home = getenv("HOME");
                if (home)
@@ -166,6 +182,9 @@ finishInput(void)
                        psql_history = (char *) malloc(strlen(home) + 20);
                        if (psql_history)
                        {
+                const char * var = GetVariable(pset.vars, "HISTSIZE");
+                if (var)
+                    stifle_history(atoi(var));
                                sprintf(psql_history, "%s/.psql_history", home);
                                write_history(psql_history);
                                free(psql_history);
index 938170ee83bb7fea99c64853877136265c4dad78..675953efb4e6af411bde0e2d5d09c7bc7e60e57c 100644 (file)
@@ -42,7 +42,7 @@ char * gets_interactive(const char *prompt);
 char * gets_fromFile(FILE *source);
 
 
-void initializeInput(int flags, PsqlSettings *pset);
+void initializeInput(int flags);
 
 bool saveHistory(const char *fname);
 
index befa4c452c3e9739c5cc08282da0ee8d450bf742..d1b3af044f452c5d8ae7093a1474288fdd1c23b0 100644 (file)
@@ -1,4 +1,3 @@
-#include <config.h>
 #include <c.h>
 #include "large_obj.h"
 
@@ -33,9 +32,9 @@ _my_notice_handler(void *arg, const char *message)
 
 
 static bool
-handle_transaction(PsqlSettings *pset)
+handle_transaction(void)
 {
-       const char *var = GetVariable(pset->vars, "lo_transaction");
+       const char *var = GetVariable(pset.vars, "LO_TRANSACTION");
        PGresult   *res;
        bool            commit;
        PQnoticeProcessor old_notice_hook;
@@ -46,9 +45,9 @@ handle_transaction(PsqlSettings *pset)
        commit = (var && strcmp(var, "commit") == 0);
 
        notice[0] = '\0';
-       old_notice_hook = PQsetNoticeProcessor(pset->db, _my_notice_handler, NULL);
+       old_notice_hook = PQsetNoticeProcessor(pset.db, _my_notice_handler, NULL);
 
-       res = PSQLexec(pset, commit ? "COMMIT" : "ROLLBACK");
+       res = PSQLexec(commit ? "COMMIT" : "ROLLBACK");
        if (!res)
                return false;
 
@@ -58,7 +57,7 @@ handle_transaction(PsqlSettings *pset)
                        (commit && strcmp(notice, "NOTICE:  EndTransactionBlock and not inprogress/abort state\n") != 0))
                        fputs(notice, stderr);
        }
-       else if (!GetVariableBool(pset->vars, "quiet"))
+       else if (!QUIET())
        {
                if (commit)
                        puts("Warning: Your transaction in progress has been committed.");
@@ -66,7 +65,7 @@ handle_transaction(PsqlSettings *pset)
                        puts("Warning: Your transaction in progress has been rolled back.");
        }
 
-       PQsetNoticeProcessor(pset->db, old_notice_hook, NULL);
+       PQsetNoticeProcessor(pset.db, old_notice_hook, NULL);
        return true;
 }
 
@@ -78,43 +77,43 @@ handle_transaction(PsqlSettings *pset)
  * Write a large object to a file
  */
 bool
-do_lo_export(PsqlSettings *pset, const char *loid_arg, const char *filename_arg)
+do_lo_export(const char *loid_arg, const char *filename_arg)
 {
        PGresult   *res;
        int                     status;
        bool            own_transaction = true;
-       const char *var = GetVariable(pset->vars, "lo_transaction");
+       const char *var = GetVariable(pset.vars, "LO_TRANSACTION");
 
        if (var && strcmp(var, "nothing") == 0)
                own_transaction = false;
 
-       if (!pset->db)
+       if (!pset.db)
        {
-        if (!pset->cur_cmd_interactive)
-            fprintf(stderr, "%s: ", pset->progname);
+        if (!pset.cur_cmd_interactive)
+            fprintf(stderr, "%s: ", pset.progname);
                fputs("\\lo_export: not connected to a database\n", stderr);
                return false;
        }
 
        if (own_transaction)
        {
-               if (!handle_transaction(pset))
+               if (!handle_transaction())
                        return false;
 
-               if (!(res = PSQLexec(pset, "BEGIN")))
+               if (!(res = PSQLexec("BEGIN")))
                        return false;
 
                PQclear(res);
        }
 
-       status = lo_export(pset->db, atol(loid_arg), (char *) filename_arg);
+       status = lo_export(pset.db, atol(loid_arg), (char *) filename_arg);
        if (status != 1)
        {                                                       /* of course this status is documented
                                                                 * nowhere :( */
-               fputs(PQerrorMessage(pset->db), stderr);
+               fputs(PQerrorMessage(pset.db), stderr);
                if (own_transaction)
                {
-                       res = PQexec(pset->db, "ROLLBACK");
+                       res = PQexec(pset.db, "ROLLBACK");
                        PQclear(res);
                }
                return false;
@@ -122,9 +121,9 @@ do_lo_export(PsqlSettings *pset, const char *loid_arg, const char *filename_arg)
 
        if (own_transaction)
        {
-               if (!(res = PSQLexec(pset, "COMMIT")))
+               if (!(res = PSQLexec("COMMIT")))
                {
-                       res = PQexec(pset->db, "ROLLBACK");
+                       res = PQexec(pset.db, "ROLLBACK");
                        PQclear(res);
                        return false;
                }
@@ -132,7 +131,7 @@ do_lo_export(PsqlSettings *pset, const char *loid_arg, const char *filename_arg)
                PQclear(res);
        }
 
-       fprintf(pset->queryFout, "lo_export\n");
+       fprintf(pset.queryFout, "lo_export\n");
 
        return true;
 }
@@ -145,44 +144,44 @@ do_lo_export(PsqlSettings *pset, const char *loid_arg, const char *filename_arg)
  * Copy large object from file to database
  */
 bool
-do_lo_import(PsqlSettings *pset, const char *filename_arg, const char *comment_arg)
+do_lo_import(const char *filename_arg, const char *comment_arg)
 {
        PGresult   *res;
        Oid                     loid;
        char            buf[1024];
        unsigned int i;
        bool            own_transaction = true;
-       const char *var = GetVariable(pset->vars, "lo_transaction");
+       const char *var = GetVariable(pset.vars, "LO_TRANSACTION");
 
        if (var && strcmp(var, "nothing") == 0)
                own_transaction = false;
 
-       if (!pset->db)
+       if (!pset.db)
        {
-        if (!pset->cur_cmd_interactive)
-            fprintf(stderr, "%s: ", pset->progname);
+        if (!pset.cur_cmd_interactive)
+            fprintf(stderr, "%s: ", pset.progname);
                fputs("\\lo_import: not connected to a database\n", stderr);
                return false;
        }
 
        if (own_transaction)
        {
-               if (!handle_transaction(pset))
+               if (!handle_transaction())
                        return false;
 
-               if (!(res = PSQLexec(pset, "BEGIN")))
+               if (!(res = PSQLexec("BEGIN")))
                        return false;
 
                PQclear(res);
        }
 
-       loid = lo_import(pset->db, (char *) filename_arg);
+       loid = lo_import(pset.db, (char *) filename_arg);
        if (loid == InvalidOid)
        {
-               fputs(PQerrorMessage(pset->db), stderr);
+               fputs(PQerrorMessage(pset.db), stderr);
                if (own_transaction)
                {
-                       res = PQexec(pset->db, "ROLLBACK");
+                       res = PQexec(pset.db, "ROLLBACK");
                        PQclear(res);
                }
                return false;
@@ -199,11 +198,11 @@ do_lo_import(PsqlSettings *pset, const char *filename_arg, const char *comment_a
                                strncat(buf, &comment_arg[i], 1);
                strcat(buf, "')");
 
-               if (!(res = PSQLexec(pset, buf)))
+               if (!(res = PSQLexec(buf)))
                {
                        if (own_transaction)
                        {
-                               res = PQexec(pset->db, "ROLLBACK");
+                               res = PQexec(pset.db, "ROLLBACK");
                                PQclear(res);
                        }
                        return false;
@@ -212,9 +211,9 @@ do_lo_import(PsqlSettings *pset, const char *filename_arg, const char *comment_a
 
        if (own_transaction)
        {
-               if (!(res = PSQLexec(pset, "COMMIT")))
+               if (!(res = PSQLexec("COMMIT")))
                {
-                       res = PQexec(pset->db, "ROLLBACK");
+                       res = PQexec(pset.db, "ROLLBACK");
                        PQclear(res);
                        return false;
                }
@@ -223,8 +222,9 @@ do_lo_import(PsqlSettings *pset, const char *filename_arg, const char *comment_a
        }
 
 
-       fprintf(pset->queryFout, "lo_import %d\n", loid);
-    pset->lastOid = loid;
+       fprintf(pset.queryFout, "lo_import %d\n", loid);
+    sprintf(buf, "%u", (unsigned int)loid);
+    SetVariable(pset.vars, "LASTOID", buf);
 
        return true;
 }
@@ -237,44 +237,44 @@ do_lo_import(PsqlSettings *pset, const char *filename_arg, const char *comment_a
  * removes a large object out of the database
  */
 bool
-do_lo_unlink(PsqlSettings *pset, const char *loid_arg)
+do_lo_unlink(const char *loid_arg)
 {
        PGresult   *res;
        int                     status;
        Oid                     loid = (Oid) atol(loid_arg);
        char            buf[256];
        bool            own_transaction = true;
-       const char *var = GetVariable(pset->vars, "lo_transaction");
+       const char *var = GetVariable(pset.vars, "LO_TRANSACTION");
 
        if (var && strcmp(var, "nothing") == 0)
                own_transaction = false;
 
-       if (!pset->db)
+       if (!pset.db)
        {
-        if (!pset->cur_cmd_interactive)
-            fprintf(stderr, "%s: ", pset->progname);
+        if (!pset.cur_cmd_interactive)
+            fprintf(stderr, "%s: ", pset.progname);
                fputs("\\lo_unlink: not connected to a database\n", stderr);
                return false;
        }
 
        if (own_transaction)
        {
-               if (!handle_transaction(pset))
+               if (!handle_transaction())
                        return false;
 
-               if (!(res = PSQLexec(pset, "BEGIN")))
+               if (!(res = PSQLexec("BEGIN")))
                        return false;
 
                PQclear(res);
        }
 
-       status = lo_unlink(pset->db, loid);
+       status = lo_unlink(pset.db, loid);
        if (status == -1)
        {
-               fputs(PQerrorMessage(pset->db), stderr);
+               fputs(PQerrorMessage(pset.db), stderr);
                if (own_transaction)
                {
-                       res = PQexec(pset->db, "ROLLBACK");
+                       res = PQexec(pset.db, "ROLLBACK");
                        PQclear(res);
                }
                return false;
@@ -282,11 +282,11 @@ do_lo_unlink(PsqlSettings *pset, const char *loid_arg)
 
        /* remove the comment as well */
        sprintf(buf, "DELETE FROM pg_description WHERE objoid = %d", loid);
-       if (!(res = PSQLexec(pset, buf)))
+       if (!(res = PSQLexec(buf)))
        {
                if (own_transaction)
                {
-                       res = PQexec(pset->db, "ROLLBACK");
+                       res = PQexec(pset.db, "ROLLBACK");
                        PQclear(res);
                }
                return false;
@@ -295,9 +295,9 @@ do_lo_unlink(PsqlSettings *pset, const char *loid_arg)
 
        if (own_transaction)
        {
-               if (!(res = PSQLexec(pset, "COMMIT")))
+               if (!(res = PSQLexec("COMMIT")))
                {
-                       res = PQexec(pset->db, "ROLLBACK");
+                       res = PQexec(pset.db, "ROLLBACK");
                        PQclear(res);
                        return false;
                }
@@ -305,7 +305,7 @@ do_lo_unlink(PsqlSettings *pset, const char *loid_arg)
        }
 
 
-       fprintf(pset->queryFout, "lo_unlink %d\n", loid);
+       fprintf(pset.queryFout, "lo_unlink %d\n", loid);
 
        return true;
 }
@@ -318,11 +318,11 @@ do_lo_unlink(PsqlSettings *pset, const char *loid_arg)
  * Show all large objects in database with comments
  */
 bool
-do_lo_list(PsqlSettings *pset)
+do_lo_list(void)
 {
        PGresult   *res;
        char            buf[1024];
-       printQueryOpt myopt = pset->popt;
+       printQueryOpt myopt = pset.popt;
 
        strcpy(buf,
            "SELECT usename as \"Owner\", substring(relname from 5) as \"ID\",\n"
@@ -336,7 +336,7 @@ do_lo_list(PsqlSettings *pset)
                   "WHERE not exists (select 1 from pg_user where usesysid = relowner) AND relkind = 'l'\n"
                   "ORDER BY \"ID\"");
 
-       res = PSQLexec(pset, buf);
+       res = PSQLexec(buf);
        if (!res)
                return false;
 
@@ -344,7 +344,7 @@ do_lo_list(PsqlSettings *pset)
        myopt.nullPrint = NULL;
        myopt.title = "Large objects";
 
-       printQuery(res, &myopt, pset->queryFout);
+       printQuery(res, &myopt, pset.queryFout);
 
        PQclear(res);
        return true;
index 3ddb2206bbb48c4153b147d6817cbbb0120e1551..baf1222d8c754cd95fb4af5c9138434395ff02c0 100644 (file)
@@ -2,11 +2,10 @@
 #define LARGE_OBJ_H
 
 #include <c.h>
-#include "settings.h"
 
-bool           do_lo_export(PsqlSettings *pset, const char *loid_arg, const char *filename_arg);
-bool           do_lo_import(PsqlSettings *pset, const char *filename_arg, const char *comment_arg);
-bool           do_lo_unlink(PsqlSettings *pset, const char *loid_arg);
-bool           do_lo_list(PsqlSettings *pset);
+bool           do_lo_export(const char *loid_arg, const char *filename_arg);
+bool           do_lo_import(const char *filename_arg, const char *comment_arg);
+bool           do_lo_unlink(const char *loid_arg);
+bool           do_lo_list(void);
 
 #endif  /* LARGE_OBJ_H */
index cb9232d7147964da71941b18872636b1c73eebd2..919025cb5c467bc9faa42c98d37dde461a141812 100644 (file)
@@ -1,4 +1,3 @@
-#include <config.h>
 #include <c.h>
 #include "mainloop.h"
 
@@ -26,7 +25,7 @@
  * FIXME: rewrite this whole thing with flex
  */
 int
-MainLoop(PsqlSettings *pset, FILE *source)
+MainLoop(FILE *source)
 {
        PQExpBuffer query_buf;          /* buffer for query being accumulated */
     PQExpBuffer previous_buf;   /* if there isn't anything in the new buffer
@@ -36,13 +35,14 @@ MainLoop(PsqlSettings *pset, FILE *source)
        int                     successResult = EXIT_SUCCESS;
        backslashResult slashCmdStatus;
 
-       bool            eof = false;    /* end of our command input? */
        bool            success;
        char            in_quote;               /* == 0 for no in_quote */
        bool            was_bslash;             /* backslash */
        bool        xcomment;           /* in extended comment */
        int                     paren_level;
        unsigned int query_start;
+    int         count_eof;
+    const char *var;
 
        int                     i,
                                prevlen,
@@ -56,12 +56,12 @@ MainLoop(PsqlSettings *pset, FILE *source)
 
 
        /* Save old settings */
-       prev_cmd_source = pset->cur_cmd_source;
-       prev_cmd_interactive = pset->cur_cmd_interactive;
+       prev_cmd_source = pset.cur_cmd_source;
+       prev_cmd_interactive = pset.cur_cmd_interactive;
 
        /* Establish new source */
-       pset->cur_cmd_source = source;
-       pset->cur_cmd_interactive = ((source == stdin) && !pset->notty);
+       pset.cur_cmd_source = source;
+       pset.cur_cmd_interactive = ((source == stdin) && !pset.notty);
 
 
        query_buf = createPQExpBuffer();
@@ -79,7 +79,7 @@ MainLoop(PsqlSettings *pset, FILE *source)
 
 
        /* main loop to get queries and execute them */
-       while (!eof)
+       while (1)
        {
                if (slashCmdStatus == CMD_NEWEDIT)
                {
@@ -102,7 +102,7 @@ MainLoop(PsqlSettings *pset, FILE *source)
                         * otherwise, set interactive prompt if necessary and get
                         * another line
                         */
-                       if (pset->cur_cmd_interactive)
+                       if (pset.cur_cmd_interactive)
                        {
                                int                     prompt_status;
 
@@ -117,7 +117,7 @@ MainLoop(PsqlSettings *pset, FILE *source)
                                else
                                        prompt_status = PROMPT_READY;
 
-                               line = gets_interactive(get_prompt(pset, prompt_status));
+                               line = gets_interactive(get_prompt(prompt_status));
                        }
                        else
                                line = gets_fromFile(source);
@@ -125,7 +125,7 @@ MainLoop(PsqlSettings *pset, FILE *source)
 
 
                /* Setting this will not have effect until next line. */
-               die_on_error = GetVariableBool(pset->vars, "die_on_error");
+               die_on_error = GetVariableBool(pset.vars, "EXIT_ON_ERROR");
 
                /*
                 * query_buf holds query already accumulated.  line is the
@@ -137,14 +137,47 @@ MainLoop(PsqlSettings *pset, FILE *source)
                /* No more input.  Time to quit, or \i done */
                if (line == NULL)
                {
-                       if (GetVariableBool(pset->vars, "echo") && !GetVariableBool(pset->vars, "quiet"))
-                               puts("EOF");
-                       else if (pset->cur_cmd_interactive)
-                               putc('\n', stdout); /* just newline */
+                       if (pset.cur_cmd_interactive)
+            {
+                bool getout = true;
+
+                /* This tries to mimic bash's IGNOREEOF feature. */
+                const char * val = GetVariable(pset.vars, "IGNOREEOF");
+                if (val)
+                {
+                    long int maxeof;
+                    char * endptr;
+
+                    if (*val == '\0')
+                        maxeof = 10;
+                    else
+                    {
+                        maxeof = strtol(val, &endptr, 0);
+                        if (*endptr != '\0') /* string not valid as a number */
+                            maxeof = 10;
+                    }
+
+                    if (count_eof++ != maxeof)
+                        getout = false; /* not quite there yet */
+                }
 
-                       eof = true;
-                       continue;
+                if (getout)
+                {
+                    putc('\n', stdout); /* just newline */
+                    break;
+                }
+                else
+                {
+                    if (!QUIET())
+                        printf("Use \"\\q\" to leave %s.\n", pset.progname);
+                    continue;
+                }
+            }
+            else /* not interactive */
+                break;
                }
+        else
+            count_eof = 0;
 
                /* strip trailing backslashes, they don't have a clear meaning */
                while (1)
@@ -164,11 +197,11 @@ MainLoop(PsqlSettings *pset, FILE *source)
                        continue;
                }
 
-
-               /* echo back if input is from file and flag is set */
-               if (!pset->cur_cmd_interactive && GetVariableBool(pset->vars, "echo"))
-                       puts(line);
-
+               /* echo back if flag is set */
+        var = GetVariable(pset.vars, "ECHO");
+        if (var && strcmp(var, "full")==0)
+            puts(line);
+       fflush(stdout);
 
                len = strlen(line);
                query_start = 0;
@@ -236,8 +269,7 @@ MainLoop(PsqlSettings *pset, FILE *source)
             /* colon -> substitute variable */
             /* we need to be on the watch for the '::' operator */
             else if (line[i] == ':' && !was_bslash &&
-                     strspn(line+i+thislen, VALID_VARIABLE_CHARS)>0 &&
-                     (prevlen > 0 && line[i-prevlen]!=':')
+                     strspn(line+i+thislen, VALID_VARIABLE_CHARS)>0
                 )
             {
                                size_t          in_length,
@@ -250,24 +282,35 @@ MainLoop(PsqlSettings *pset, FILE *source)
                                in_length = strspn(&line[i + thislen], VALID_VARIABLE_CHARS);
                                after = line[i + thislen + in_length];
                                line[i + thislen + in_length] = '\0';
-                               value = interpolate_var(&line[i + thislen], pset);
-                               out_length = strlen(value);
-
-                               new = malloc(len + out_length - (1 + in_length) + 1);
-                               if (!new)
-                               {
-                                       perror("malloc");
-                                       exit(EXIT_FAILURE);
-                               }
-
-                sprintf(new, "%.*s%s%c", i, line, value, after);
-                if (after)
-                    strcat(new, line + i + 1 + in_length + 1);
 
-                               free(line);
-                               line = new;
-                len = strlen(new);
-                continue; /* reparse the just substituted */
+                /* if the variable doesn't exist we'll leave the string as is */
+                               value = GetVariable(pset.vars, &line[i + thislen]);
+                if (value)
+                {
+                    out_length = strlen(value);
+
+                    new = malloc(len + out_length - (1 + in_length) + 1);
+                    if (!new)
+                    {
+                        perror("malloc");
+                        exit(EXIT_FAILURE);
+                    }
+
+                    sprintf(new, "%.*s%s%c", i, line, value, after);
+                    if (after)
+                        strcat(new, line + i + 1 + in_length + 1);
+
+                    free(line);
+                    line = new;
+                    len = strlen(new);
+                    continue; /* reparse the just substituted */
+                }
+                else
+                {
+                    /* restore overwritten character */
+                    line[i + thislen + in_length] = after;
+                    /* move on ... */
+                }
             }
 
                        /* semicolon? then send query */
@@ -288,7 +331,7 @@ MainLoop(PsqlSettings *pset, FILE *source)
                                }
 
                                /* execute query */
-                               success = SendQuery(pset, query_buf->data);
+                               success = SendQuery(query_buf->data);
                 slashCmdStatus = success ? CMD_SEND : CMD_ERROR;
 
                 resetPQExpBuffer(previous_buf);
@@ -314,7 +357,7 @@ MainLoop(PsqlSettings *pset, FILE *source)
                                paren_level = 0;
                                line[i - prevlen] = '\0';               /* overwrites backslash */
 
-                               /* is there anything else on the line? */
+                               /* is there anything else on the line for the command? */
                                if (line[query_start + strspn(line + query_start, " \t")] != '\0')
                                {
                                        /*
@@ -328,7 +371,7 @@ MainLoop(PsqlSettings *pset, FILE *source)
                                }
 
                 /* handle backslash command */
-                slashCmdStatus = HandleSlashCmds(pset, &line[i], 
+                slashCmdStatus = HandleSlashCmds(&line[i], 
                                                  query_buf->len>0 ? query_buf : previous_buf,
                                                  &end_of_cmd);
 
@@ -342,7 +385,7 @@ MainLoop(PsqlSettings *pset, FILE *source)
 
                                if (slashCmdStatus == CMD_SEND)
                                {
-                                       success = SendQuery(pset, query_buf->data);
+                                       success = SendQuery(query_buf->data);
                                        query_start = i + thislen;
 
                     resetPQExpBuffer(previous_buf);
@@ -350,14 +393,9 @@ MainLoop(PsqlSettings *pset, FILE *source)
                     resetPQExpBuffer(query_buf);
                                }
 
-                               /* is there anything left after the backslash command? */
-                               if (end_of_cmd)
-                               {
-                                       i += end_of_cmd - &line[i];
-                                       query_start = i;
-                               }
-                               else
-                                       break;
+                               /* process anything left after the backslash command */
+                i += end_of_cmd - &line[i];
+                query_start = i;
                        }
 
 
@@ -387,9 +425,9 @@ MainLoop(PsqlSettings *pset, FILE *source)
 
 
                /* In single line mode, send off the query if any */
-               if (query_buf->data[0] != '\0' && GetVariableBool(pset->vars, "singleline"))
+               if (query_buf->data[0] != '\0' && GetVariableBool(pset.vars, "SINGLELINE"))
                {
-                       success = SendQuery(pset, query_buf->data);
+                       success = SendQuery(query_buf->data);
             slashCmdStatus = success ? CMD_SEND : CMD_ERROR;
             resetPQExpBuffer(previous_buf);
             appendPQExpBufferStr(previous_buf, query_buf->data);
@@ -397,7 +435,7 @@ MainLoop(PsqlSettings *pset, FILE *source)
                }
 
 
-               if (!success && die_on_error && !pset->cur_cmd_interactive)
+               if (!success && die_on_error && !pset.cur_cmd_interactive)
                {
                        successResult = EXIT_USER;
                        break;
@@ -405,18 +443,18 @@ MainLoop(PsqlSettings *pset, FILE *source)
 
 
                /* Have we lost the db connection? */
-               if (pset->db == NULL && !pset->cur_cmd_interactive)
+               if (pset.db == NULL && !pset.cur_cmd_interactive)
                {
                        successResult = EXIT_BADCONN;
                        break;
                }
-       } /* while !EOF */
+       } /* while !endofprogram */
 
        destroyPQExpBuffer(query_buf);
        destroyPQExpBuffer(previous_buf);
 
-       pset->cur_cmd_source = prev_cmd_source;
-       pset->cur_cmd_interactive = prev_cmd_interactive;
+       pset.cur_cmd_source = prev_cmd_source;
+       pset.cur_cmd_interactive = prev_cmd_interactive;
 
        return successResult;
 }      /* MainLoop() */
index b2b05d7d11b6d60c387a9cc311f877a56553c50d..439703d04040a29c7e2db8d95c13567283889ef9 100644 (file)
@@ -2,9 +2,7 @@
 #define MAINLOOP_H
 
 #include <stdio.h>
-#include "settings.h"
 
-int
-                       MainLoop(PsqlSettings *pset, FILE *source);
+int MainLoop(FILE *source);
 
 #endif  /* MAINLOOP_H */
index dd41ba54015bba41024939fd8a0e5ccff0496de0..d93f5611ced475943ff1c1db7d7541407f02c413 100644 (file)
@@ -1,4 +1,3 @@
-#include <config.h>
 #include <c.h>
 #include "prompt.h"
 
@@ -10,6 +9,7 @@
 
 #include "settings.h"
 #include "common.h"
+#include "variables.h"
 
 #ifdef WIN32
 #define popen(x,y) _popen(x,y)
@@ -22,7 +22,7 @@
  * get_prompt
  *
  * Returns a statically allocated prompt made by interpolating certain
- * tcsh style escape sequences into pset->vars "prompt1|2|3".
+ * tcsh style escape sequences into pset->vars "PROMPT1|2|3".
  * (might not be completely multibyte safe)
  *
  * Defined interpolations are:
@@ -46,8 +46,7 @@
  *
  * %`command`     - The result of executing command in /bin/sh with trailing
  *                                      newline stripped.
- * %$name$                - The value of the psql/environment/magic varible 'name'
- *                                      (same rules as for, e.g., \echo $foo)
+ * %$name$                - The value of the psql variable 'name'
  * (those will not be rescanned for more escape sequences!)
  *
  *
@@ -56,7 +55,7 @@
  *--------------------------
  */
 const char *
-get_prompt(PsqlSettings *pset, promptStatus_t status)
+get_prompt(promptStatus_t status)
 {
 #define MAX_PROMPT_SIZE 256
        static char destination[MAX_PROMPT_SIZE + 1];
@@ -66,11 +65,11 @@ get_prompt(PsqlSettings *pset, promptStatus_t status)
        const char *prompt_string;
 
        if (status == PROMPT_READY)
-               prompt_string = GetVariable(pset->vars, "prompt1");
+               prompt_string = GetVariable(pset.vars, "PROMPT1");
        else if (status == PROMPT_CONTINUE || status == PROMPT_SINGLEQUOTE || status == PROMPT_DOUBLEQUOTE || status == PROMPT_COMMENT)
-               prompt_string = GetVariable(pset->vars, "prompt2");
+               prompt_string = GetVariable(pset.vars, "PROMPT2");
        else if (status == PROMPT_COPY)
-               prompt_string = GetVariable(pset->vars, "prompt3");
+               prompt_string = GetVariable(pset.vars, "PROMPT3");
        else
                prompt_string = "? ";
 
@@ -92,31 +91,31 @@ get_prompt(PsqlSettings *pset, promptStatus_t status)
 
                                        /* Current database */
                                case '/':
-                                       if (pset->db)
-                                               strncpy(buf, PQdb(pset->db), MAX_PROMPT_SIZE);
+                                       if (pset.db)
+                                               strncpy(buf, PQdb(pset.db), MAX_PROMPT_SIZE);
                                        break;
                                case '~':
                                        {
                                                const char *var;
 
-                                               if (pset->db)
+                                               if (pset.db)
                                                {
-                                                       if (strcmp(PQdb(pset->db), PQuser(pset->db)) == 0 ||
-                                                               ((var = getenv("PGDATABASE")) && strcmp(var, PQdb(pset->db)) == 0))
+                                                       if (strcmp(PQdb(pset.db), PQuser(pset.db)) == 0 ||
+                                                               ((var = getenv("PGDATABASE")) && strcmp(var, PQdb(pset.db)) == 0))
                                                                strcpy(buf, "~");
                                                        else
-                                                               strncpy(buf, PQdb(pset->db), MAX_PROMPT_SIZE);
+                                                               strncpy(buf, PQdb(pset.db), MAX_PROMPT_SIZE);
                                                }
                                                break;
                                        }
                                        /* DB server hostname (long/short) */
                                case 'M':
                                case 'm':
-                                       if (pset->db)
+                                       if (pset.db)
                                        {
-                                               if (PQhost(pset->db))
+                                               if (PQhost(pset.db))
                                                {
-                                                       strncpy(buf, PQhost(pset->db), MAX_PROMPT_SIZE);
+                                                       strncpy(buf, PQhost(pset.db), MAX_PROMPT_SIZE);
                                                        if (*p == 'm')
                                                                buf[strcspn(buf, ".")] = '\0';
                                                }
@@ -126,13 +125,13 @@ get_prompt(PsqlSettings *pset, promptStatus_t status)
                                        break;
                                        /* DB server port number */
                                case '>':
-                                       if (pset->db && PQport(pset->db))
-                        strncpy(buf, PQport(pset->db), MAX_PROMPT_SIZE);
+                                       if (pset.db && PQport(pset.db))
+                        strncpy(buf, PQport(pset.db), MAX_PROMPT_SIZE);
                                        break;
                                        /* DB server user name */
                                case 'n':
-                                       if (pset->db)
-                                               strncpy(buf, PQuser(pset->db), MAX_PROMPT_SIZE);
+                                       if (pset.db)
+                                               strncpy(buf, PQuser(pset.db), MAX_PROMPT_SIZE);
                                        break;
 
                                case '0':
@@ -159,9 +158,9 @@ get_prompt(PsqlSettings *pset, promptStatus_t status)
                                        switch (status)
                                        {
                                                case PROMPT_READY:
-                                                       if (!pset->db)
+                                                       if (!pset.db)
                                                                buf[0] = '!';
-                                                       else if (!GetVariableBool(pset->vars, "singleline"))
+                                                       else if (!GetVariableBool(pset.vars, "SINGLELINE"))
                                                                buf[0] = '=';
                                                        else
                                                                buf[0] = '^';
@@ -189,7 +188,7 @@ get_prompt(PsqlSettings *pset, promptStatus_t status)
 
                                case '#':
                                        {
-                                               if (pset->db && strcmp(PQuser(pset->db), "postgres") == 0)
+                                               if (pset.db && strcmp(PQuser(pset.db), "postgres") == 0)
                                                        buf[0] = '#';
                                                else
                                                        buf[0] = '>';
@@ -230,7 +229,7 @@ get_prompt(PsqlSettings *pset, promptStatus_t status)
                                                name = strdup(p + 1);
                                                nameend = strcspn(name, "$");
                                                name[nameend] = '\0';
-                                               val = interpolate_var(name, pset);
+                                               val = GetVariable(pset.vars, name);
                                                if (val)
                                                        strncpy(buf, val, MAX_PROMPT_SIZE);
                                                free(name);
index e4c1242deb7a02aaec58bdf5a3bf1d5665904a1d..d98116395ad80baef98187989d8d928d51caca5f 100644 (file)
@@ -14,7 +14,7 @@ typedef enum _promptStatus
 }                      promptStatus_t;
 
 const char *
-                       get_prompt(PsqlSettings *pset, promptStatus_t status);
+                       get_prompt(promptStatus_t status);
 
 
 #endif  /* PROMPT_H */
index 774c54b45947d9b34787f459ee0e09891007f451..21f138bd37d1e89798dd22fe7cb5788bd59a8bef 100644 (file)
@@ -43,11 +43,13 @@ typedef struct _psqlSettings
 
        bool            has_client_encoding;    /* was PGCLIENTENCODING set on
                                                                                 * startup? */
-    Oid         lastOid;        /* saves oid from insert command
-                                   because people want it so badly */
     char       *progname;       /* in case you renamed psql */
 } PsqlSettings;
 
+extern PsqlSettings pset;
+
+
+#define QUIET() (GetVariableBool(pset.vars, "QUIET"))
 
 
 #ifndef EXIT_SUCCESS
index 35f4ddce05cdee21b2e0ceac23691562d70353b8..2599a42199a6b9b7bfdceb0b9f637290f6b7b113 100644 (file)
@@ -1,4 +1,3 @@
-#include <config.h>
 #include <c.h>
 
 #include <signal.h>
 #include "print.h"
 #include "describe.h"
 
-
+PsqlSettings pset;
 
 static void
-process_psqlrc(PsqlSettings *pset);
+process_psqlrc(void);
 
 static void
 showVersion(void);
@@ -67,7 +66,7 @@ struct adhoc_opts
 };
 
 static void
-parse_options(int argc, char *argv[], PsqlSettings *pset, struct adhoc_opts * options);
+parse_options(int argc, char *argv[], struct adhoc_opts * options);
 
 
 
@@ -79,7 +78,6 @@ parse_options(int argc, char *argv[], PsqlSettings *pset, struct adhoc_opts * op
 int
 main(int argc, char **argv)
 {
-       PsqlSettings settings;
        struct adhoc_opts options;
        int                     successResult;
 
@@ -87,64 +85,65 @@ main(int argc, char **argv)
        char       *password = NULL;
        bool            need_pass;
 
-       memset(&settings, 0, sizeof settings);
+       memset(&pset, 0, sizeof pset);
 
     if (!strrchr(argv[0], SEP_CHAR))
-        settings.progname = argv[0];
+        pset.progname = argv[0];
     else
-        settings.progname = strrchr(argv[0], SEP_CHAR) + 1;
+        pset.progname = strrchr(argv[0], SEP_CHAR) + 1;
 
-       settings.cur_cmd_source = stdin;
-       settings.cur_cmd_interactive = false;
+       pset.cur_cmd_source = stdin;
+       pset.cur_cmd_interactive = false;
 
-       settings.vars = CreateVariableSpace();
-       settings.popt.topt.format = PRINT_ALIGNED;
-       settings.queryFout = stdout;
-       settings.popt.topt.fieldSep = strdup(DEFAULT_FIELD_SEP);
-       settings.popt.topt.border = 1;
-       settings.popt.topt.pager = 1;
+       pset.vars = CreateVariableSpace();
+       pset.popt.topt.format = PRINT_ALIGNED;
+       pset.queryFout = stdout;
+       pset.popt.topt.fieldSep = strdup(DEFAULT_FIELD_SEP);
+       pset.popt.topt.border = 1;
+       pset.popt.topt.pager = 1;
 
-       SetVariable(settings.vars, "prompt1", DEFAULT_PROMPT1);
-       SetVariable(settings.vars, "prompt2", DEFAULT_PROMPT2);
-       SetVariable(settings.vars, "prompt3", DEFAULT_PROMPT3);
+       SetVariable(pset.vars, "PROMPT1", DEFAULT_PROMPT1);
+       SetVariable(pset.vars, "PROMPT2", DEFAULT_PROMPT2);
+       SetVariable(pset.vars, "PROMPT3", DEFAULT_PROMPT3);
+    SetVariable(pset.vars, "VERSION", PG_VERSION_STR);
 
-       settings.notty = (!isatty(fileno(stdin)) || !isatty(fileno(stdout)));
+       pset.notty = (!isatty(fileno(stdin)) || !isatty(fileno(stdout)));
 
        /* This is obsolete and will be removed very soon. */
 #ifdef PSQL_ALWAYS_GET_PASSWORDS
-       settings.getPassword = true;
+       pset.getPassword = true;
 #else
-       settings.getPassword = false;
+       pset.getPassword = false;
 #endif
 
 #ifdef MULTIBYTE
-       settings.has_client_encoding = (getenv("PGCLIENTENCODING") != NULL);
+       pset.has_client_encoding = (getenv("PGCLIENTENCODING") != NULL);
 #endif
 
-       parse_options(argc, argv, &settings, &options);
+       parse_options(argc, argv, &options);
 
        if (options.action == ACT_LIST_DB)
                options.dbname = "template1";
 
        if (options.username)
        {
-               if (strcmp(options.username, "?") == 0)
+               if (strcmp(options.username, "\001") == 0)
                        username = simple_prompt("Username: ", 100, true);
                else
                        username = strdup(options.username);
        }
 
-       if (settings.getPassword)
+       if (pset.getPassword)
                password = simple_prompt("Password: ", 100, false);
 
        /* loop until we have a password if requested by backend */
        do
        {
                need_pass = false;
-               settings.db = PQsetdbLogin(options.host, options.port, NULL, NULL, options.dbname, username, password);
+               pset.db = PQsetdbLogin(options.host, options.port, NULL, NULL, options.dbname, username, password);
 
-               if (PQstatus(settings.db) == CONNECTION_BAD &&
-                       strcmp(PQerrorMessage(settings.db), "fe_sendauth: no password supplied\n") == 0)
+               if (PQstatus(pset.db) == CONNECTION_BAD &&
+                       strcmp(PQerrorMessage(pset.db), "fe_sendauth: no password supplied\n") == 0)
                {
                        need_pass = true;
                        free(password);
@@ -156,58 +155,61 @@ main(int argc, char **argv)
        free(username);
        free(password);
 
-       if (PQstatus(settings.db) == CONNECTION_BAD)
+       if (PQstatus(pset.db) == CONNECTION_BAD)
        {
-               fprintf(stderr, "%s: connection to database '%s' failed.\n%s",
-                settings.progname, PQdb(settings.db),
-                               PQerrorMessage(settings.db));
-               PQfinish(settings.db);
+               fprintf(stderr, "%s: connection to database '%s' failed - %s",
+                pset.progname, PQdb(pset.db), PQerrorMessage(pset.db));
+               PQfinish(pset.db);
                exit(EXIT_BADCONN);
        }
 
        if (options.action == ACT_LIST_DB)
        {
-               int                     success = listAllDbs(&settings, false);
+               int                     success = listAllDbs(false);
 
-               PQfinish(settings.db);
+               PQfinish(pset.db);
                exit(!success);
        }
 
+    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));
 
-       if (!GetVariable(settings.vars, "quiet") && !settings.notty && !options.action)
+       if (!QUIET() && !pset.notty && !options.action)
        {
                printf("Welcome to %s, the PostgreSQL interactive terminal.\n\n"
                "Type:  \\copyright for distribution terms\n"
                "       \\h for help with SQL commands\n"
                "       \\? for help on internal slash commands\n"
                "       \\g or terminate with semicolon to execute query\n"
-               "       \\q to quit\n", settings.progname);
+               "       \\q to quit\n", pset.progname);
        }
 
-       process_psqlrc(&settings);
-
-       initializeInput(options.no_readline ? 0 : 1, &settings);
-
        /* Now find something to do */
 
        /* process file given by -f */
        if (options.action == ACT_FILE)
-               successResult = process_file(options.action_string, &settings) ? 0 : 1;
+               successResult = process_file(options.action_string) ? 0 : 1;
        /* process slash command if one was given to -c */
        else if (options.action == ACT_SINGLE_SLASH)
-               successResult = HandleSlashCmds(&settings, options.action_string, NULL, NULL) != CMD_ERROR ? 0 : 1;
+               successResult = HandleSlashCmds(options.action_string, NULL, NULL) != CMD_ERROR ? 0 : 1;
        /* If the query given to -c was a normal one, send it */
        else if (options.action == ACT_SINGLE_QUERY)
-               successResult = SendQuery(&settings, options.action_string) ? 0 : 1;
+               successResult = SendQuery( options.action_string) ? 0 : 1;
        /* or otherwise enter interactive main loop */
        else
-               successResult = MainLoop(&settings, stdin);
+    {
+        process_psqlrc();
+        initializeInput(options.no_readline ? 0 : 1);
+               successResult = MainLoop(stdin);
+        finishInput();
+    }
 
        /* clean up */
-       finishInput();
-       PQfinish(settings.db);
-       setQFout(NULL, &settings);
-       DestroyVariableSpace(settings.vars);
+       PQfinish(pset.db);
+       setQFout(NULL);
+       DestroyVariableSpace(pset.vars);
 
        return successResult;
 }
@@ -225,7 +227,7 @@ int                 getopt(int, char *const[], const char *);
 #endif
 
 static void
-parse_options(int argc, char *argv[], PsqlSettings *pset, struct adhoc_opts * options)
+parse_options(int argc, char *argv[], struct adhoc_opts * options)
 {
 #ifdef HAVE_GETOPT_LONG
        static struct option long_options[] = {
@@ -234,9 +236,7 @@ parse_options(int argc, char *argv[], PsqlSettings *pset, struct adhoc_opts * op
                {"database", required_argument, NULL, 'd'},
                {"dbname", required_argument, NULL, 'd'},
                {"echo", no_argument, NULL, 'e'},
-               {"echo-queries", no_argument, NULL, 'e'},
-               {"echo-all", no_argument, NULL, 'E'},
-               {"echo-all-queries", no_argument, NULL, 'E'},
+               {"echo-hidden", no_argument, NULL, 'E'},
                {"file", required_argument, NULL, 'f'},
                {"field-separator", required_argument, NULL, 'F'},
                {"host", required_argument, NULL, 'h'},
@@ -261,12 +261,12 @@ parse_options(int argc, char *argv[], PsqlSettings *pset, struct adhoc_opts * op
        };
 
        int                     optindex;
-
 #endif
 
        extern char *optarg;
        extern int      optind;
        int                     c;
+    bool        used_old_u_option = false;
 
        memset(options, 0, sizeof *options);
 
@@ -284,7 +284,7 @@ parse_options(int argc, char *argv[], PsqlSettings *pset, struct adhoc_opts * op
                switch (c)
                {
                        case 'A':
-                               pset->popt.topt.format = PRINT_UNALIGNED;
+                               pset.popt.topt.format = PRINT_UNALIGNED;
                                break;
                        case 'c':
                                options->action_string = optarg;
@@ -297,23 +297,23 @@ parse_options(int argc, char *argv[], PsqlSettings *pset, struct adhoc_opts * op
                                options->dbname = optarg;
                                break;
                        case 'e':
-                               SetVariable(pset->vars, "echo", "");
+                               SetVariable(pset.vars, "ECHO", "full");
                                break;
                        case 'E':
-                               SetVariable(pset->vars, "echo_secret", "");
+                               SetVariable(pset.vars, "ECHO_HIDDEN", "");
                                break;
                        case 'f':
                                options->action = ACT_FILE;
                                options->action_string = optarg;
                                break;
                        case 'F':
-                               pset->popt.topt.fieldSep = strdup(optarg);
+                               pset.popt.topt.fieldSep = strdup(optarg);
                                break;
                        case 'h':
                                options->host = optarg;
                                break;
                        case 'H':
-                               pset->popt.topt.format = PRINT_HTML;
+                               pset.popt.topt.format = PRINT_HTML;
                                break;
                        case 'l':
                                options->action = ACT_LIST_DB;
@@ -322,7 +322,7 @@ parse_options(int argc, char *argv[], PsqlSettings *pset, struct adhoc_opts * op
                                options->no_readline = true;
                                break;
                        case 'o':
-                               setQFout(optarg, pset);
+                               setQFout(optarg);
                                break;
                        case 'p':
                                options->port = optarg;
@@ -336,16 +336,16 @@ parse_options(int argc, char *argv[], PsqlSettings *pset, struct adhoc_opts * op
                                        value = xstrdup(optarg);
                                        equal_loc = strchr(value, '=');
                                        if (!equal_loc)
-                                               result = do_pset(value, NULL, &pset->popt, true);
+                                               result = do_pset(value, NULL, &pset.popt, true);
                                        else
                                        {
                                                *equal_loc = '\0';
-                                               result = do_pset(value, equal_loc + 1, &pset->popt, true);
+                                               result = do_pset(value, equal_loc + 1, &pset.popt, true);
                                        }
 
                                        if (!result)
                                        {
-                                               fprintf(stderr, "Couldn't set printing paramter %s.\n", value);
+                                               fprintf(stderr, "%s: couldn't set printing parameter %s\n", pset.progname, value);
                                                exit(EXIT_FAILURE);
                                        }
 
@@ -353,29 +353,31 @@ parse_options(int argc, char *argv[], PsqlSettings *pset, struct adhoc_opts * op
                                        break;
                                }
                        case 'q':
-                               SetVariable(pset->vars, "quiet", "");
+                               SetVariable(pset.vars, "QUIET", "");
                                break;
                        case 's':
-                               SetVariable(pset->vars, "singlestep", "");
+                               SetVariable(pset.vars, "SINGLESTEP", "");
                                break;
                        case 'S':
-                               SetVariable(pset->vars, "singleline", "");
+                               SetVariable(pset.vars, "SINGLELINE", "");
                                break;
                        case 't':
-                               pset->popt.topt.tuples_only = true;
+                               pset.popt.topt.tuples_only = true;
                                break;
                        case 'T':
-                               pset->popt.topt.tableAttr = xstrdup(optarg);
+                               pset.popt.topt.tableAttr = xstrdup(optarg);
                                break;
                        case 'u':
-                               pset->getPassword = true;
-                               options->username = "?";
+                               pset.getPassword = true;
+                               options->username = "\001"; /* hopefully nobody has that username */
+                /* this option is out */
+                used_old_u_option = true;
                                break;
                        case 'U':
                                options->username = optarg;
                                break;
                        case 'x':
-                               pset->popt.topt.expanded = true;
+                               pset.popt.topt.expanded = true;
                                break;
                        case 'v':
                                {
@@ -386,20 +388,20 @@ parse_options(int argc, char *argv[], PsqlSettings *pset, struct adhoc_opts * op
                                        equal_loc = strchr(value, '=');
                                        if (!equal_loc)
                                        {
-                                               if (!DeleteVariable(pset->vars, value))
+                                               if (!DeleteVariable(pset.vars, value))
                                                {
                                                        fprintf(stderr, "%s: could not delete variable %s\n",
-                                    pset->progname, value);
+                                    pset.progname, value);
                                                        exit(EXIT_FAILURE);
                                                }
                                        }
                                        else
                                        {
                                                *equal_loc = '\0';
-                                               if (!SetVariable(pset->vars, value, equal_loc + 1))
+                                               if (!SetVariable(pset.vars, value, equal_loc + 1))
                                                {
-                                                       fprintf(stderr, "%s: Couldn't set variable %s to %s\n",
-                                    pset->progname, value, equal_loc);
+                                                       fprintf(stderr, "%s: could not set variable %s\n",
+                                    pset.progname, value);
                                                        exit(EXIT_FAILURE);
                                                }
                                        }
@@ -411,7 +413,7 @@ parse_options(int argc, char *argv[], PsqlSettings *pset, struct adhoc_opts * op
                                showVersion();
                                exit(EXIT_SUCCESS);
                        case 'W':
-                               pset->getPassword = true;
+                               pset.getPassword = true;
                                break;
                        case '?':
                                usage();
@@ -420,7 +422,7 @@ parse_options(int argc, char *argv[], PsqlSettings *pset, struct adhoc_opts * op
 #ifndef HAVE_GETOPT_LONG
                        case '-':
                                fprintf(stderr, "%s was compiled without support for long options.\n"
-                                               "Use -? for help on invocation options.\n", pset->progname);
+                                               "Use -? for help on invocation options.\n", pset.progname);
                                exit(EXIT_FAILURE);
                                break;
 #endif
@@ -441,12 +443,16 @@ parse_options(int argc, char *argv[], PsqlSettings *pset, struct adhoc_opts * op
                        options->dbname = argv[optind];
                else if (!options->username)
                        options->username = argv[optind];
-               else
+               else if (!QUIET())
                        fprintf(stderr, "%s: warning: extra option %s ignored\n",
-                    pset->progname, argv[optind]);
+                    pset.progname, argv[optind]);
 
                optind++;
        }
+
+    if (used_old_u_option && !QUIET())
+        fprintf(stderr, "%s: Warning: The -u option is deprecated. Use -U.\n", pset.progname);
+
 }
 
 
@@ -455,7 +461,7 @@ parse_options(int argc, char *argv[], PsqlSettings *pset, struct adhoc_opts * op
  * Load /etc/psqlrc or .psqlrc file, if found.
  */
 static void
-process_psqlrc(PsqlSettings *pset)
+process_psqlrc(void)
 {
        char       *psqlrc;
        char       *home;
@@ -466,9 +472,9 @@ process_psqlrc(PsqlSettings *pset)
 
        /* System-wide startup file */
        if (access("/etc/psqlrc-" PG_RELEASE "." PG_VERSION "." PG_SUBVERSION, R_OK) == 0)
-               process_file("/etc/psqlrc-" PG_RELEASE "." PG_VERSION "." PG_SUBVERSION, pset);
+               process_file("/etc/psqlrc-" PG_RELEASE "." PG_VERSION "." PG_SUBVERSION);
        else if (access("/etc/psqlrc", R_OK) == 0)
-               process_file("/etc/psqlrc", pset);
+               process_file("/etc/psqlrc");
 
        /* Look for one in the home dir */
        home = getenv("HOME");
@@ -484,12 +490,12 @@ process_psqlrc(PsqlSettings *pset)
 
                sprintf(psqlrc, "%s/.psqlrc-" PG_RELEASE "." PG_VERSION "." PG_SUBVERSION, home);
                if (access(psqlrc, R_OK) == 0)
-                       process_file(psqlrc, pset);
+                       process_file(psqlrc);
                else
                {
                        sprintf(psqlrc, "%s/.psqlrc", home);
                        if (access(psqlrc, R_OK) == 0)
-                               process_file(psqlrc, pset);
+                               process_file(psqlrc);
                }
                free(psqlrc);
        }
@@ -529,7 +535,7 @@ showVersion(void)
 #else
 #define _Feature
 #endif
-    fputs("multibyte");
+    fputs("multibyte", stdout);
 #endif
     
 #undef _Feature