+ These specify what the prompt
s psql
+ issues
should look like. See
linkend="APP-PSQL-prompting"
endterm="APP-PSQL-prompting-title"> below.
SINGLELINE
- This variable is set by the command line option
- -S . You can unset or reset it at run time.
+ This variable is equivalent to the command line option
+ -S .
+
+ VERBOSE
+
+ This variable can be set to the values default>,
+ verbose>, or terse> to control the verbosity
+ of error reports.
+
+
+
+
testdb=> \set content '\'' `sed -e "s/'/\\\\\\'/g" < my_file.txt` '\''
- Observe the correct number of backslashes (6)! You can resolve it
+ Observe the correct number of backslashes (6)! It works
this way: After
psql has parsed this
line, it passes sed -e "s/'/\\\'/g" < my_file.txt
to the shell. The shell will do its own thing inside the double
Since colons may legally appear in SQL commands, the following rule
- applies: If the variable is not set, the character sequence
- colon+name
is not changed. In any case you can escape
- a colon with a backslash to protect it from interpretation. (The
+ applies: the character sequence
+ :name
is not changed unless name> is the name
+ of a variable that is currently set. In any case you can escape
+ a colon with a backslash to protect it from substitution. (The
colon syntax for variables is standard
SQL for
embedded query languages, such as
ECPG .
The colon syntax for array slices and type casts are
- The value of the respective prompt variable is printed literally,
+ The value of the selected prompt variable is printed literally,
except where a percent sign (% ) is encountered.
Depending on the next character, certain other text is substituted
instead. Defined substitutions are:
psql expects more input because the
command wasn't terminated yet, because you are inside a
/* ... */ comment, or because you are inside
- a quote. In prompt 3 the sequence doesn't resolve to anything.
+ a quote. In prompt 3 the sequence doesn't produce anything.
+
+
+
+
+
+ %T
+
+ Transaction status: an empty string when not in a transaction
+ block, or *> when in a transaction block, or
+ !> when in a failed transaction block, or ?>
+ when the transaction state is indeterminate (for example, because
+ there is no connection).
% digits
+ The character with the indicated numeric code is substituted.
If digits starts
with 0x the rest of the characters are
- interpreted as a hexadecimal digit and the character with the
- corresponding code is substituted. If the first digit is
- 0 the characters are interpreted as on octal
- number and the corresponding character is substituted. Otherwise
- a decimal number is assumed.
+ interpreted as hexadecimal; otherwise if the first digit is
+ 0 the digits are interpreted as octal;
+ otherwise the digits are read as a decimal number.
To insert a percent sign into your prompt, write
- %% . The default prompts are equivalent to
+ %% . The default prompts are
'%/%R%# ' for prompts 1 and 2, and
'>> ' for prompt 3.
-
- Pressing Control>C>>
- during a copy in
(data sent to
- the server) doesn't show the most ideal of behaviors. If you get a
- message such as COPY state must be terminated
- first, simply reset the connection by entering \c
- - -.
-
-
-
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
*
* 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"
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);
}
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;
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)
}
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;
+ }
+}
/*
*
* 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
} 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 */
*
* Copyright 2000 by PostgreSQL Global Development Group
*
- * $Header: /cvsroot/pgsql/src/bin/psql/common.c,v 1.64 2003/06/12 08:15:28 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/bin/psql/common.c,v 1.65 2003/06/28 00:12:40 tgl Exp $
*/
#include "postgres_fe.h"
#include "common.h"
+#include
#include
#include
#ifndef HAVE_STRDUP
#include "settings.h"
#include "variables.h"
+#include "command.h"
#include "copy.h"
#include "prompt.h"
#include "print.h"
extern bool prompt_state;
+
+static bool is_transact_command(const char *query);
+
+
/*
* "Safe" wrapper around strdup()
*/
{
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)
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);
* 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.
*/
}
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;
* 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)
{
}
echo_hidden = SwitchVariable(pset.vars, "ECHO_HIDDEN", "noexec", NULL);
- if (echo_hidden != var_notset )
+ if (echo_hidden != VAR_NOTSET )
{
printf("********* QUERY **********\n"
"%s\n"
"**************************\n\n", query);
fflush(stdout);
- if (echo_hidden == 1)
- return NULL;
+ if (echo_hidden == 1) /* noexec? */
+ return NULL;
}
- /* discard any uneaten results of past queries */
- while ((newres = PQgetResult(pset.db)) != NULL)
- PQclear(newres);
-
SetCancelConn();
- if (!PQsendQuery(pset.db, query))
- {
- psql_error("%s", PQerrorMessage(pset.db));
- ResetCancelConn();
- return NULL;
- }
-
- rstatus = PGRES_EMPTY_QUERY;
- while (rstatus != PGRES_COPY_IN &&
- rstatus != PGRES_COPY_OUT &&
- (newres = PQgetResult(pset.db)))
+ if (start_xact && PQtransactionStatus(pset.db) == PQTRANS_IDLE &&
+ !GetVariableBool(pset.vars, "AUTOCOMMIT"))
+ {
+ res = PQexec(pset.db, "BEGIN");
+ if (PQresultStatus(res) != PGRES_COMMAND_OK)
{
- rstatus = PQresultStatus(newres);
- if (!ignore_command_ok || rstatus != PGRES_COMMAND_OK)
- {
- PGresult *tempRes = res;
- res = newres;
- newres = tempRes;
+ psql_error("%s", PQerrorMessage(pset.db));
+ PQclear(res);
+ ResetCancelConn();
+ return NULL;
}
- PQclear(new res);
+ PQclear(res);
}
+ res = PQexec(pset.db, query);
+
if (!AcceptResult(res) && res)
{
PQclear(res);
res = NULL;
- }
+ }
return res;
}
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);
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)
{
}
+/*
+ * 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;
+}
*
* 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
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);
*
* 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"
#define S_ISDIR(mode) __S_ISTYPE((mode), S_IFDIR)
#endif
-bool copy_in_state;
-
/*
* parse_slash_copy
* -- parses \copy command line
return false;
}
- result = PSQLexec(query.data, fals e);
+ result = PSQLexec(query.data, tru e);
termPQExpBuffer(&query);
switch (PQresultStatus(result))
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)))
linecount++;
}
ret = !PQendcopy(conn);
- copy_in_state = false;
pset.lineno += linecount;
return ret;
}
*
* 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);
*
* Copyright 2000-2002 by PostgreSQL Global Development Group
*
- * $Header: /cvsroot/pgsql/src/bin/psql/large_obj.c,v 1.26 2003/06/27 16:55:23 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/bin/psql/large_obj.c,v 1.27 2003/06/28 00:12:40 tgl Exp $
*/
#include "postgres_fe.h"
#include "large_obj.h"
/*
- * Since all large object ops must be in a transaction, we must do some magic
- * here. You can set the variable lo_transaction to one of commit|rollback|
- * nothing to get your favourite behaviour regarding any transaction in
- * progress. Rollback is default.
+ * Prepare to do a large-object operation. We *must* be inside a transaction
+ * block for all these operations, so start one if needed.
+ *
+ * Returns TRUE if okay, FALSE if failed. *own_transaction is set to indicate
+ * if we started our own transaction or not.
*/
+static bool
+start_lo_xact(const char *operation, bool *own_transaction)
+{
+ PGTransactionStatusType tstatus;
+ PGresult *res;
-static char notice[80] ;
+ *own_transaction = false ;
-static void
-_my_notice_handler(void *arg, const char *message)
-{
- (void) arg;
- strncpy(notice, message, 79);
- notice[79] = '\0';
-}
+ if (!pset.db)
+ {
+ psql_error("%s: not connected to a database\n", operation);
+ return false;
+ }
+
+ tstatus = PQtransactionStatus(pset.db);
+
+ switch (tstatus)
+ {
+ case PQTRANS_IDLE:
+ /* need to start our own xact */
+ if (!(res = PSQLexec("BEGIN", false)))
+ return false;
+ PQclear(res);
+ *own_transaction = true;
+ break;
+ case PQTRANS_INTRANS:
+ /* use the existing xact */
+ break;
+ case PQTRANS_INERROR:
+ psql_error("%s: current transaction is aborted\n", operation);
+ return false;
+ default:
+ psql_error("%s: unknown transaction status\n", operation);
+ return false;
+ }
+ return true;
+}
+/*
+ * Clean up after a successful LO operation
+ */
static bool
-handle_transaction(void )
+finish_lo_xact(const char *operation, bool own_transaction )
{
PGresult *res;
- bool commit = false;
- PQnoticeProcessor old_notice_hook;
- switch (SwitchVariable(pset.vars, "LO_TRANSACTION",
- "nothing",
- "commit",
- NULL))
+ if (own_transaction &&
+ GetVariableBool(pset.vars, "AUTOCOMMIT"))
{
- case 1: /* nothing */
- return true;
- case 2: /* commit */
- commit = true;
- break;
+ /* close out our own xact */
+ if (!(res = PSQLexec("COMMIT", false)))
+ {
+ res = PSQLexec("ROLLBACK", false);
+ PQclear(res);
+ return false;
+ }
+ PQclear(res);
}
- notice[0] = '\0' ;
- old_notice_hook = PQsetNoticeProcessor(pset.db, _my_notice_handler, NULL);
+ return true ;
+}
- res = PSQLexec(commit ? "COMMIT" : "ROLLBACK", false);
- if (!res)
- return false;
+/*
+ * Clean up after a failed LO operation
+ */
+static bool
+fail_lo_xact(const char *operation, bool own_transaction)
+{
+ PGresult *res;
- if (notice[0])
+ if (own_transaction &&
+ GetVariableBool(pset.vars, "AUTOCOMMIT"))
{
- if ((!commit && strcmp(notice, "WARNING: ROLLBACK: no transaction in progress\n") != 0) ||
- (commit && strcmp(notice, "WARNING: COMMIT: no transaction in progress\n") != 0))
- fputs(notice, stderr);
- }
- else if (!QUIET())
- {
- if (commit)
- puts(gettext("Warning: Your transaction in progress has been committed."));
- else
- puts(gettext("Warning: Your transaction in progress has been rolled back."));
+ /* close out our own xact */
+ res = PSQLexec("ROLLBACK", false);
+ PQclear(res);
}
- PQsetNoticeProcessor(pset.db, old_notice_hook, NULL);
- PQclear(res);
- return true;
+ return false; /* always */
}
-
/*
* do_lo_export()
*
bool
do_lo_export(const char *loid_arg, const char *filename_arg)
{
- PGresult *res;
int status;
bool own_transaction;
- own_transaction = !VariableEquals(pset.vars, "LO_TRANSACTION", "nothing");
-
- if (!pset.db)
- {
- psql_error("\\lo_export: not connected to a database\n");
+ if (!start_lo_xact("\\lo_export", &own_transaction))
return false;
- }
-
- if (own_transaction)
- {
- if (!handle_transaction())
- return false;
-
- if (!(res = PSQLexec("BEGIN", false)))
- return false;
-
- PQclear(res);
- }
status = lo_export(pset.db, atooid(loid_arg), filename_arg);
if (status != 1)
{ /* of course this status is documented
* nowhere :( */
fputs(PQerrorMessage(pset.db), stderr);
- if (own_transaction)
- {
- res = PQexec(pset.db, "ROLLBACK");
- PQclear(res);
- }
- return false;
+ return fail_lo_xact("\\lo_export", own_transaction);
}
- if (own_transaction)
- {
- if (!(res = PSQLexec("COMMIT", false)))
- {
- res = PQexec(pset.db, "ROLLBACK");
- PQclear(res);
- return false;
- }
-
- PQclear(res);
- }
+ if (!finish_lo_xact("\\lo_export", own_transaction))
+ return false;
fprintf(pset.queryFout, "lo_export\n");
}
-
/*
* do_lo_import()
*
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;
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, "
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);
}
-
/*
* do_lo_unlink()
*
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);
*
* 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"
* 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
*
case '8':
case '9':
*buf = parse_char((char **)&p);
- break;
+ break;
case 'R':
switch (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 '`':
*
* 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
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;
*
* 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"
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
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. */
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)
{
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
*/
*/
else
{
- pset.issuper = test_superuser(PQuser(pset.db));
if (!QUIET() && !pset.notty)
{
printf(gettext("Welcome to %s %s, the PostgreSQL interactive terminal.\n\n"
#endif
}
+ /* Default values for variables that are used in interactive case */
SetVariable(pset.vars, "PROMPT1", DEFAULT_PROMPT1);
SetVariable(pset.vars, "PROMPT2", DEFAULT_PROMPT2);
SetVariable(pset.vars, "PROMPT3", DEFAULT_PROMPT3);
+
if (!options.no_psqlrc)
process_psqlrc();
if (!pset.notty)
initializeInput(options.no_readline ? 0 : 1);
if (options.action_string) /* -f - was used */
pset.inputfile = "";
+
successResult = MainLoop(stdin);
}
*
* 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"
return ptr;
}
-
-
const char *
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[])
return var && (strcmp(var, value) == 0);
}
-
int
GetVariableNum(VariableSpace space,
const char name[],
return result;
}
-
int
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)
{
printf("%s = '%s'\n", ptr->name, ptr->value);
}
-
bool
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)
{
return true;
}
-
-
-
-void
-DestroyVariableSpace(VariableSpace space)
-{
- if (!space)
- return;
-
- DestroyVariableSpace(space->next);
- free(space);
-}
*
* 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 $
*/
/*
/* Find value of variable among NULL-terminated list of alternative
- * options. Returns var_notset if the variable was not set, var_notfound if its
- * value did not occur in the list of options, or the number of the matching
- * option. The first option is 1, the second is 2 and so on.
+ * options. Returns VAR_NOTSET if the variable was not set, VAR_NOTFOUND
+ * if its value did not occur in the list of options, or the number of the
+ * matching option. The first option is 1, the second is 2 and so on.
*/
-enum { var_notset = 0, var_notfound = -1 };
-int SwitchVariable(VariableSpace space, const char name[], const char *opt,...);
+enum { VAR_NOTSET = 0, VAR_NOTFOUND = -1 };
+int SwitchVariable(VariableSpace space, const char name[],
+ const char *opt, ...);
void PrintVariables(VariableSpace space);
bool SetVariable(VariableSpace space, const char *name, const char *value);
bool SetVariableBool(VariableSpace space, const char *name);
bool DeleteVariable(VariableSpace space, const char *name);
-void DestroyVariableSpace(VariableSpace space);
#endif /* VARIABLES_H */