aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/bin/psql/command.c118
-rw-r--r--src/bin/psql/command.h18
-rw-r--r--src/bin/psql/common.c180
-rw-r--r--src/bin/psql/common.h6
-rw-r--r--src/bin/psql/copy.c11
-rw-r--r--src/bin/psql/copy.h3
-rw-r--r--src/bin/psql/large_obj.c262
-rw-r--r--src/bin/psql/prompt.c40
-rw-r--r--src/bin/psql/settings.h6
-rw-r--r--src/bin/psql/startup.c39
-rw-r--r--src/bin/psql/variables.c45
-rw-r--r--src/bin/psql/variables.h14
12 files changed, 380 insertions, 362 deletions
diff --git a/src/bin/psql/command.c b/src/bin/psql/command.c
index fd6193dd243..c105f0bd9d8 100644
--- a/src/bin/psql/command.c
+++ b/src/bin/psql/command.c
@@ -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;
+ }
+}
/*
diff --git a/src/bin/psql/command.h b/src/bin/psql/command.h
index f74be3a8510..ead859cd32c 100644
--- a/src/bin/psql/command.h
+++ b/src/bin/psql/command.h
@@ -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 */
diff --git a/src/bin/psql/common.c b/src/bin/psql/common.c
index 84dc32bd5ca..96f3c281007 100644
--- a/src/bin/psql/common.c
+++ b/src/bin/psql/common.c
@@ -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))
- {
- psql_error("%s", PQerrorMessage(pset.db));
- ResetCancelConn();
- return NULL;
- }
-
- rstatus = PGRES_EMPTY_QUERY;
- while (rstatus != PGRES_COPY_IN &&
- rstatus != PGRES_COPY_OUT &&
- (newres = PQgetResult(pset.db)))
+ if (start_xact && PQtransactionStatus(pset.db) == PQTRANS_IDLE &&
+ !GetVariableBool(pset.vars, "AUTOCOMMIT"))
+ {
+ res = PQexec(pset.db, "BEGIN");
+ if (PQresultStatus(res) != PGRES_COMMAND_OK)
{
- rstatus = PQresultStatus(newres);
- if (!ignore_command_ok || rstatus != PGRES_COMMAND_OK)
- {
- PGresult *tempRes = res;
- res = newres;
- newres = tempRes;
+ psql_error("%s", PQerrorMessage(pset.db));
+ PQclear(res);
+ ResetCancelConn();
+ return NULL;
}
- PQclear(newres);
+ PQclear(res);
}
+ res = PQexec(pset.db, query);
+
if (!AcceptResult(res) && res)
{
PQclear(res);
res = NULL;
- }
+ }
return res;
}
@@ -613,6 +599,21 @@ SendQuery(const char *query)
SetCancelConn();
+ if (PQtransactionStatus(pset.db) == PQTRANS_IDLE &&
+ !GetVariableBool(pset.vars, "AUTOCOMMIT") &&
+ !is_transact_command(query))
+ {
+ results = PQexec(pset.db, "BEGIN");
+ if (PQresultStatus(results) != PGRES_COMMAND_OK)
+ {
+ psql_error("%s", PQerrorMessage(pset.db));
+ PQclear(results);
+ ResetCancelConn();
+ return false;
+ }
+ PQclear(results);
+ }
+
if (pset.timing)
GETTIMEOFDAY(&before);
results = PQexec(pset.db, query);
@@ -626,6 +627,68 @@ SendQuery(const char *query)
return OK;
}
+/*
+ * check whether a query string begins with BEGIN/COMMIT/ROLLBACK/START XACT
+ */
+static bool
+is_transact_command(const char *query)
+{
+ int wordlen;
+
+ /*
+ * First we must advance over any whitespace and comments.
+ */
+ while (*query)
+ {
+ if (isspace((unsigned char) *query))
+ query++;
+ else if (query[0] == '-' && query[1] == '-')
+ {
+ query += 2;
+ while (*query && *query != '\n')
+ query++;
+ }
+ else if (query[0] == '/' && query[1] == '*')
+ {
+ query += 2;
+ while (*query)
+ {
+ if (query[0] == '*' && query[1] == '/')
+ {
+ query += 2;
+ break;
+ }
+ else
+ query++;
+ }
+ }
+ else
+ break; /* found first token */
+ }
+
+ /*
+ * Check word length ("beginx" is not "begin").
+ */
+ wordlen = 0;
+ while (isalpha((unsigned char) query[wordlen]))
+ wordlen++;
+
+ if (wordlen == 5 && strncasecmp(query, "begin", 5) == 0)
+ return true;
+ if (wordlen == 6 && strncasecmp(query, "commit", 6) == 0)
+ return true;
+ if (wordlen == 8 && strncasecmp(query, "rollback", 8) == 0)
+ return true;
+ if (wordlen == 5 && strncasecmp(query, "abort", 5) == 0)
+ return true;
+ if (wordlen == 3 && strncasecmp(query, "end", 3) == 0)
+ return true;
+ if (wordlen == 5 && strncasecmp(query, "start", 5) == 0)
+ return true;
+
+ return false;
+}
+
char parse_char(char **buf)
{
@@ -637,3 +700,24 @@ char parse_char(char **buf)
}
+/*
+ * Test if the current user is a database superuser.
+ *
+ * Note: this will correctly detect superuserness only with a protocol-3.0
+ * or newer backend; otherwise it will always say "false".
+ */
+bool
+is_superuser(void)
+{
+ const char *val;
+
+ if (!pset.db)
+ return false;
+
+ val = PQparameterStatus(pset.db, "is_superuser");
+
+ if (val && strcmp(val, "on") == 0)
+ return true;
+
+ return false;
+}
diff --git a/src/bin/psql/common.h b/src/bin/psql/common.h
index d29b317d23a..2f38ea371b0 100644
--- a/src/bin/psql/common.h
+++ b/src/bin/psql/common.h
@@ -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);
diff --git a/src/bin/psql/copy.c b/src/bin/psql/copy.c
index 00664ea05d0..11f66c68978 100644
--- a/src/bin/psql/copy.c
+++ b/src/bin/psql/copy.c
@@ -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;
}
diff --git a/src/bin/psql/copy.h b/src/bin/psql/copy.h
index c22146707ae..8f5c70d43c0 100644
--- a/src/bin/psql/copy.h
+++ b/src/bin/psql/copy.h
@@ -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);
diff --git a/src/bin/psql/large_obj.c b/src/bin/psql/large_obj.c
index 3d0b3a6eb96..a565d204784 100644
--- a/src/bin/psql/large_obj.c
+++ b/src/bin/psql/large_obj.c
@@ -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,70 +20,95 @@
/*
- * Since all large object ops must be in a transaction, we must do some magic
- * here. You can set the variable lo_transaction to one of commit|rollback|
- * nothing to get your favourite behaviour regarding any transaction in
- * progress. Rollback is default.
+ * Prepare to do a large-object operation. We *must* be inside a transaction
+ * block for all these operations, so start one if needed.
+ *
+ * Returns TRUE if okay, FALSE if failed. *own_transaction is set to indicate
+ * if we started our own transaction or not.
*/
+static bool
+start_lo_xact(const char *operation, bool *own_transaction)
+{
+ PGTransactionStatusType tstatus;
+ PGresult *res;
-static char notice[80];
+ *own_transaction = false;
-static void
-_my_notice_handler(void *arg, const char *message)
-{
- (void) arg;
- strncpy(notice, message, 79);
- notice[79] = '\0';
-}
+ if (!pset.db)
+ {
+ psql_error("%s: not connected to a database\n", operation);
+ return false;
+ }
+
+ tstatus = PQtransactionStatus(pset.db);
+
+ switch (tstatus)
+ {
+ case PQTRANS_IDLE:
+ /* need to start our own xact */
+ if (!(res = PSQLexec("BEGIN", false)))
+ return false;
+ PQclear(res);
+ *own_transaction = true;
+ break;
+ case PQTRANS_INTRANS:
+ /* use the existing xact */
+ break;
+ case PQTRANS_INERROR:
+ psql_error("%s: current transaction is aborted\n", operation);
+ return false;
+ default:
+ psql_error("%s: unknown transaction status\n", operation);
+ return false;
+ }
+ return true;
+}
+/*
+ * Clean up after a successful LO operation
+ */
static bool
-handle_transaction(void)
+finish_lo_xact(const char *operation, bool own_transaction)
{
PGresult *res;
- bool commit = false;
- PQnoticeProcessor old_notice_hook;
- switch (SwitchVariable(pset.vars, "LO_TRANSACTION",
- "nothing",
- "commit",
- NULL))
+ if (own_transaction &&
+ GetVariableBool(pset.vars, "AUTOCOMMIT"))
{
- case 1: /* nothing */
- return true;
- case 2: /* commit */
- commit = true;
- break;
+ /* close out our own xact */
+ if (!(res = PSQLexec("COMMIT", false)))
+ {
+ res = PSQLexec("ROLLBACK", false);
+ PQclear(res);
+ return false;
+ }
+ PQclear(res);
}
- notice[0] = '\0';
- old_notice_hook = PQsetNoticeProcessor(pset.db, _my_notice_handler, NULL);
+ return true;
+}
- res = PSQLexec(commit ? "COMMIT" : "ROLLBACK", false);
- if (!res)
- return false;
+/*
+ * Clean up after a failed LO operation
+ */
+static bool
+fail_lo_xact(const char *operation, bool own_transaction)
+{
+ PGresult *res;
- if (notice[0])
+ if (own_transaction &&
+ GetVariableBool(pset.vars, "AUTOCOMMIT"))
{
- if ((!commit && strcmp(notice, "WARNING: ROLLBACK: no transaction in progress\n") != 0) ||
- (commit && strcmp(notice, "WARNING: COMMIT: no transaction in progress\n") != 0))
- fputs(notice, stderr);
- }
- else if (!QUIET())
- {
- if (commit)
- puts(gettext("Warning: Your transaction in progress has been committed."));
- else
- puts(gettext("Warning: Your transaction in progress has been rolled back."));
+ /* close out our own xact */
+ res = PSQLexec("ROLLBACK", false);
+ PQclear(res);
}
- PQsetNoticeProcessor(pset.db, old_notice_hook, NULL);
- PQclear(res);
- return true;
+ return false; /* always */
}
-
/*
* do_lo_export()
*
@@ -92,53 +117,22 @@ handle_transaction(void)
bool
do_lo_export(const char *loid_arg, const char *filename_arg)
{
- PGresult *res;
int status;
bool own_transaction;
- own_transaction = !VariableEquals(pset.vars, "LO_TRANSACTION", "nothing");
-
- if (!pset.db)
- {
- psql_error("\\lo_export: not connected to a database\n");
+ if (!start_lo_xact("\\lo_export", &own_transaction))
return false;
- }
-
- if (own_transaction)
- {
- if (!handle_transaction())
- return false;
-
- if (!(res = PSQLexec("BEGIN", false)))
- return false;
-
- PQclear(res);
- }
status = lo_export(pset.db, atooid(loid_arg), filename_arg);
if (status != 1)
{ /* of course this status is documented
* nowhere :( */
fputs(PQerrorMessage(pset.db), stderr);
- if (own_transaction)
- {
- res = PQexec(pset.db, "ROLLBACK");
- PQclear(res);
- }
- return false;
+ return fail_lo_xact("\\lo_export", own_transaction);
}
- if (own_transaction)
- {
- if (!(res = PSQLexec("COMMIT", false)))
- {
- res = PQexec(pset.db, "ROLLBACK");
- PQclear(res);
- return false;
- }
-
- PQclear(res);
- }
+ if (!finish_lo_xact("\\lo_export", own_transaction))
+ return false;
fprintf(pset.queryFout, "lo_export\n");
@@ -146,7 +140,6 @@ do_lo_export(const char *loid_arg, const char *filename_arg)
}
-
/*
* do_lo_import()
*
@@ -161,41 +154,20 @@ do_lo_import(const char *filename_arg, const char *comment_arg)
unsigned int i;
bool own_transaction;
- own_transaction = !VariableEquals(pset.vars, "LO_TRANSACTION", "nothing");
-
- if (!pset.db)
- {
- psql_error("\\lo_import: not connected to a database\n");
+ if (!start_lo_xact("\\lo_import", &own_transaction))
return false;
- }
-
- if (own_transaction)
- {
- if (!handle_transaction())
- return false;
-
- if (!(res = PSQLexec("BEGIN", false)))
- return false;
-
- PQclear(res);
- }
loid = lo_import(pset.db, filename_arg);
if (loid == InvalidOid)
{
fputs(PQerrorMessage(pset.db), stderr);
- if (own_transaction)
- {
- res = PQexec(pset.db, "ROLLBACK");
- PQclear(res);
- }
- return false;
+ return fail_lo_xact("\\lo_import", own_transaction);
}
/* insert description if given */
/* XXX don't try to hack pg_description if not superuser */
/* XXX ought to replace this with some kind of COMMENT command */
- if (comment_arg && pset.issuper)
+ if (comment_arg && is_superuser())
{
char *cmdbuf;
char *bufptr;
@@ -203,14 +175,7 @@ do_lo_import(const char *filename_arg, const char *comment_arg)
cmdbuf = malloc(slen * 2 + 256);
if (!cmdbuf)
- {
- if (own_transaction)
- {
- res = PQexec(pset.db, "ROLLBACK");
- PQclear(res);
- }
- return false;
- }
+ return fail_lo_xact("\\lo_import", own_transaction);
sprintf(cmdbuf,
"INSERT INTO pg_catalog.pg_description VALUES ('%u', "
"'pg_catalog.pg_largeobject'::regclass, "
@@ -227,31 +192,16 @@ do_lo_import(const char *filename_arg, const char *comment_arg)
if (!(res = PSQLexec(cmdbuf, false)))
{
- if (own_transaction)
- {
- res = PQexec(pset.db, "ROLLBACK");
- PQclear(res);
- }
free(cmdbuf);
- return false;
+ return fail_lo_xact("\\lo_import", own_transaction);
}
PQclear(res);
free(cmdbuf);
}
- if (own_transaction)
- {
- if (!(res = PSQLexec("COMMIT", false)))
- {
- res = PQexec(pset.db, "ROLLBACK");
- PQclear(res);
- return false;
- }
-
- PQclear(res);
- }
-
+ if (!finish_lo_xact("\\lo_import", own_transaction))
+ return false;
fprintf(pset.queryFout, "lo_import %u\n", loid);
sprintf(oidbuf, "%u", loid);
@@ -261,7 +211,6 @@ do_lo_import(const char *filename_arg, const char *comment_arg)
}
-
/*
* do_lo_unlink()
*
@@ -276,69 +225,32 @@ do_lo_unlink(const char *loid_arg)
char buf[256];
bool own_transaction;
- own_transaction = !VariableEquals(pset.vars, "LO_TRANSACTION", "nothing");
-
- if (!pset.db)
- {
- psql_error("\\lo_unlink: not connected to a database\n");
+ if (!start_lo_xact("\\lo_unlink", &own_transaction))
return false;
- }
-
- if (own_transaction)
- {
- if (!handle_transaction())
- return false;
-
- if (!(res = PSQLexec("BEGIN", false)))
- return false;
-
- PQclear(res);
- }
status = lo_unlink(pset.db, loid);
if (status == -1)
{
fputs(PQerrorMessage(pset.db), stderr);
- if (own_transaction)
- {
- res = PQexec(pset.db, "ROLLBACK");
- PQclear(res);
- }
- return false;
+ return fail_lo_xact("\\lo_unlink", own_transaction);
}
/* remove the comment as well */
/* XXX don't try to hack pg_description if not superuser */
/* XXX ought to replace this with some kind of COMMENT command */
- if (pset.issuper)
+ if (is_superuser())
{
snprintf(buf, sizeof(buf),
"DELETE FROM pg_catalog.pg_description WHERE objoid = '%u' "
"AND classoid = 'pg_catalog.pg_largeobject'::regclass",
loid);
if (!(res = PSQLexec(buf, false)))
- {
- if (own_transaction)
- {
- res = PQexec(pset.db, "ROLLBACK");
- PQclear(res);
- }
- return false;
- }
- PQclear(res);
- }
-
- if (own_transaction)
- {
- if (!(res = PSQLexec("COMMIT", false)))
- {
- res = PQexec(pset.db, "ROLLBACK");
- PQclear(res);
- return false;
- }
+ return fail_lo_xact("\\lo_unlink", own_transaction);
PQclear(res);
}
+ if (!finish_lo_xact("\\lo_unlink", own_transaction))
+ return false;
fprintf(pset.queryFout, "lo_unlink %u\n", loid);
diff --git a/src/bin/psql/prompt.c b/src/bin/psql/prompt.c
index f9d66b752ec..0df16d4b0c6 100644
--- a/src/bin/psql/prompt.c
+++ b/src/bin/psql/prompt.c
@@ -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 '`':
diff --git a/src/bin/psql/settings.h b/src/bin/psql/settings.h
index cb41920eb9d..a471184fb21 100644
--- a/src/bin/psql/settings.h
+++ b/src/bin/psql/settings.h
@@ -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;
diff --git a/src/bin/psql/startup.c b/src/bin/psql/startup.c
index 74d79fc5078..b36aaa3476d 100644
--- a/src/bin/psql/startup.c
+++ b/src/bin/psql/startup.c
@@ -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);
}
diff --git a/src/bin/psql/variables.c b/src/bin/psql/variables.c
index 35f84aefdcc..6b4c42786e7 100644
--- a/src/bin/psql/variables.c
+++ b/src/bin/psql/variables.c
@@ -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);
-}
diff --git a/src/bin/psql/variables.h b/src/bin/psql/variables.h
index d297b5a4efa..ce239975ef3 100644
--- a/src/bin/psql/variables.h
+++ b/src/bin/psql/variables.h
@@ -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 */