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