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