Commit f9ebf369 authored by Tom Lane's avatar Tom Lane

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.
parent ea20397b
This diff is collapsed.
<!-- <!--
$Header: /cvsroot/pgsql/doc/src/sgml/release.sgml,v 1.194 2003/06/19 23:22:40 tgl Exp $ $Header: /cvsroot/pgsql/doc/src/sgml/release.sgml,v 1.195 2003/06/28 00:12:40 tgl Exp $
--> -->
<appendix id="release"> <appendix id="release">
...@@ -31,7 +31,7 @@ Functional indexes have been generalized into expressional indexes ...@@ -31,7 +31,7 @@ Functional indexes have been generalized into expressional indexes
CHAR(n) to TEXT conversion automatically strips trailing blanks CHAR(n) to TEXT conversion automatically strips trailing blanks
Pattern matching operations can use indexes regardless of locale Pattern matching operations can use indexes regardless of locale
New frontend/backend protocol supports many long-requested features New frontend/backend protocol supports many long-requested features
SET AUTOCOMMIT TO OFF is no longer supported SET AUTOCOMMIT TO OFF is no longer supported; psql has an AUTOCOMMIT variable
Reimplementation of NUMERIC datatype for more speed Reimplementation of NUMERIC datatype for more speed
New regular expression package, many more regexp features (most of Perl5) New regular expression package, many more regexp features (most of Perl5)
Can now do EXPLAIN ... EXECUTE to see plan used for a prepared query Can now do EXPLAIN ... EXECUTE to see plan used for a prepared query
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
* *
* Copyright 2000-2002 by PostgreSQL Global Development Group * Copyright 2000-2002 by PostgreSQL Global Development Group
* *
* $Header: /cvsroot/pgsql/src/bin/psql/command.c,v 1.96 2003/05/14 03:26:02 tgl Exp $ * $Header: /cvsroot/pgsql/src/bin/psql/command.c,v 1.97 2003/06/28 00:12:40 tgl Exp $
*/ */
#include "postgres_fe.h" #include "postgres_fe.h"
#include "command.h" #include "command.h"
...@@ -457,20 +457,30 @@ exec_command(const char *cmd, ...@@ -457,20 +457,30 @@ exec_command(const char *cmd,
char *encoding = scan_option(&string, OT_NORMAL, NULL, false); char *encoding = scan_option(&string, OT_NORMAL, NULL, false);
if (!encoding) if (!encoding)
/* show encoding */ {
/* show encoding --- first check for change sent from server */
if (pset.encoding != PQclientEncoding(pset.db) &&
PQclientEncoding(pset.db) >= 0)
{
pset.encoding = PQclientEncoding(pset.db);
pset.popt.topt.encoding = pset.encoding;
SetVariable(pset.vars, "ENCODING",
pg_encoding_to_char(pset.encoding));
}
puts(pg_encoding_to_char(pset.encoding)); puts(pg_encoding_to_char(pset.encoding));
}
else else
{ {
/* set encoding */ /* set encoding */
if (PQsetClientEncoding(pset.db, encoding) == -1) if (PQsetClientEncoding(pset.db, encoding) == -1)
psql_error("%s: invalid encoding name or conversion procedure not found\n", encoding); psql_error("%s: invalid encoding name or conversion procedure not found\n", encoding);
else else
{ {
/* save encoding info into psql internal data */ /* save encoding info into psql internal data */
pset.encoding = PQclientEncoding(pset.db); pset.encoding = PQclientEncoding(pset.db);
pset.popt.topt.encoding = PQclientEncoding(pset.db); pset.popt.topt.encoding = pset.encoding;
SetVariable(pset.vars, "ENCODING", pg_encoding_to_char(pset.encoding)); SetVariable(pset.vars, "ENCODING",
pg_encoding_to_char(pset.encoding));
} }
free(encoding); free(encoding);
} }
...@@ -694,7 +704,13 @@ exec_command(const char *cmd, ...@@ -694,7 +704,13 @@ exec_command(const char *cmd,
free(opt); free(opt);
} }
if (!SetVariable(pset.vars, opt0, newval)) if (SetVariable(pset.vars, opt0, newval))
{
/* Check for special variables */
if (strcmp(opt0, "VERBOSE") == 0)
SyncVerboseVariable();
}
else
{ {
psql_error("\\%s: error\n", cmd); psql_error("\\%s: error\n", cmd);
success = false; success = false;
...@@ -1327,11 +1343,7 @@ do_connect(const char *new_dbname, const char *new_user) ...@@ -1327,11 +1343,7 @@ do_connect(const char *new_dbname, const char *new_user)
bool success = false; bool success = false;
/* Delete variables (in case we fail before setting them anew) */ /* Delete variables (in case we fail before setting them anew) */
SetVariable(pset.vars, "DBNAME", NULL); UnsyncVariables();
SetVariable(pset.vars, "USER", NULL);
SetVariable(pset.vars, "HOST", NULL);
SetVariable(pset.vars, "PORT", NULL);
SetVariable(pset.vars, "ENCODING", NULL);
/* If dbname is "" then use old name, else new one (even if NULL) */ /* If dbname is "" then use old name, else new one (even if NULL) */
if (oldconn && new_dbname && PQdb(oldconn) && strcmp(new_dbname, "") == 0) if (oldconn && new_dbname && PQdb(oldconn) && strcmp(new_dbname, "") == 0)
...@@ -1429,51 +1441,75 @@ do_connect(const char *new_dbname, const char *new_user) ...@@ -1429,51 +1441,75 @@ do_connect(const char *new_dbname, const char *new_user)
} }
PQsetNoticeProcessor(pset.db, NoticeProcessor, NULL); PQsetNoticeProcessor(pset.db, NoticeProcessor, NULL);
pset.encoding = PQclientEncoding(pset.db);
pset.popt.topt.encoding = PQclientEncoding(pset.db);
/* Update variables */ /* Update variables */
SyncVariables();
return success;
}
/*
* SyncVariables
*
* Make psql's internal variables agree with connection state upon
* establishing a new connection.
*/
void
SyncVariables(void)
{
/* get stuff from connection */
pset.encoding = PQclientEncoding(pset.db);
pset.popt.topt.encoding = pset.encoding;
SetVariable(pset.vars, "DBNAME", PQdb(pset.db)); SetVariable(pset.vars, "DBNAME", PQdb(pset.db));
SetVariable(pset.vars, "USER", PQuser(pset.db)); SetVariable(pset.vars, "USER", PQuser(pset.db));
SetVariable(pset.vars, "HOST", PQhost(pset.db)); SetVariable(pset.vars, "HOST", PQhost(pset.db));
SetVariable(pset.vars, "PORT", PQport(pset.db)); SetVariable(pset.vars, "PORT", PQport(pset.db));
SetVariable(pset.vars, "ENCODING", pg_encoding_to_char(pset.encoding)); SetVariable(pset.vars, "ENCODING", pg_encoding_to_char(pset.encoding));
pset.issuper = test_superuser(PQuser(pset.db)); /* send stuff to it, too */
SyncVerboseVariable();
return success;
} }
/* /*
* Test if the given user is a database superuser. * UnsyncVariables
* (Is used to set up the prompt right.) *
* Clear variables that should be not be set when there is no connection.
*/ */
bool void
test_superuser(const char *username) UnsyncVariables(void)
{ {
PGresult *res; SetVariable(pset.vars, "DBNAME", NULL);
PQExpBufferData buf; SetVariable(pset.vars, "USER", NULL);
bool answer; SetVariable(pset.vars, "HOST", NULL);
SetVariable(pset.vars, "PORT", NULL);
if (!username) SetVariable(pset.vars, "ENCODING", NULL);
return false;
initPQExpBuffer(&buf);
printfPQExpBuffer(&buf, "SELECT usesuper FROM pg_catalog.pg_user WHERE usename = '%s'", username);
res = PSQLexec(buf.data, true);
termPQExpBuffer(&buf);
answer =
(res && PQntuples(res) > 0 && PQnfields(res) > 0
&& !PQgetisnull(res, 0, 0)
&& PQgetvalue(res, 0, 0)
&& strcmp(PQgetvalue(res, 0, 0), "t") == 0);
PQclear(res);
return answer;
} }
/*
* Update connection state from VERBOSE variable
*/
void
SyncVerboseVariable(void)
{
switch (SwitchVariable(pset.vars, "VERBOSE",
"default", "terse", "verbose", NULL))
{
case 1: /* default */
PQsetErrorVerbosity(pset.db, PQERRORS_DEFAULT);
break;
case 2: /* terse */
PQsetErrorVerbosity(pset.db, PQERRORS_TERSE);
break;
case 3: /* verbose */
PQsetErrorVerbosity(pset.db, PQERRORS_VERBOSE);
break;
default: /* not set or unrecognized value */
PQsetErrorVerbosity(pset.db, PQERRORS_DEFAULT);
break;
}
}
/* /*
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
* *
* Copyright 2000 by PostgreSQL Global Development Group * Copyright 2000 by PostgreSQL Global Development Group
* *
* $Header: /cvsroot/pgsql/src/bin/psql/command.h,v 1.14 2002/03/27 19:16:13 petere Exp $ * $Header: /cvsroot/pgsql/src/bin/psql/command.h,v 1.15 2003/06/28 00:12:40 tgl Exp $
*/ */
#ifndef COMMAND_H #ifndef COMMAND_H
#define COMMAND_H #define COMMAND_H
...@@ -26,20 +26,22 @@ typedef enum _backslashResult ...@@ -26,20 +26,22 @@ typedef enum _backslashResult
} backslashResult; } backslashResult;
backslashResult HandleSlashCmds(const char *line, extern backslashResult HandleSlashCmds(const char *line,
PQExpBuffer query_buf, PQExpBuffer query_buf,
const char **end_of_cmd, const char **end_of_cmd,
volatile int *paren_level); volatile int *paren_level);
int extern int process_file(char *filename);
process_file(char *filename);
bool extern bool do_pset(const char *param,
test_superuser(const char *username);
bool do_pset(const char *param,
const char *value, const char *value,
printQueryOpt *popt, printQueryOpt *popt,
bool quiet); bool quiet);
extern void SyncVariables(void);
extern void UnsyncVariables(void);
extern void SyncVerboseVariable(void);
#endif /* COMMAND_H */ #endif /* COMMAND_H */
...@@ -3,11 +3,12 @@ ...@@ -3,11 +3,12 @@
* *
* Copyright 2000 by PostgreSQL Global Development Group * Copyright 2000 by PostgreSQL Global Development Group
* *
* $Header: /cvsroot/pgsql/src/bin/psql/common.c,v 1.64 2003/06/12 08:15:28 momjian Exp $ * $Header: /cvsroot/pgsql/src/bin/psql/common.c,v 1.65 2003/06/28 00:12:40 tgl Exp $
*/ */
#include "postgres_fe.h" #include "postgres_fe.h"
#include "common.h" #include "common.h"
#include <ctype.h>
#include <errno.h> #include <errno.h>
#include <stdarg.h> #include <stdarg.h>
#ifndef HAVE_STRDUP #ifndef HAVE_STRDUP
...@@ -29,6 +30,7 @@ ...@@ -29,6 +30,7 @@
#include "settings.h" #include "settings.h"
#include "variables.h" #include "variables.h"
#include "command.h"
#include "copy.h" #include "copy.h"
#include "prompt.h" #include "prompt.h"
#include "print.h" #include "print.h"
...@@ -55,6 +57,10 @@ typedef struct _timeb TimevalStruct; ...@@ -55,6 +57,10 @@ typedef struct _timeb TimevalStruct;
extern bool prompt_state; extern bool prompt_state;
static bool is_transact_command(const char *query);
/* /*
* "Safe" wrapper around strdup() * "Safe" wrapper around strdup()
*/ */
...@@ -195,8 +201,8 @@ handle_sigint(SIGNAL_ARGS) ...@@ -195,8 +201,8 @@ handle_sigint(SIGNAL_ARGS)
{ {
int save_errno = errno; int save_errno = errno;
/* Don't muck around if copying in or prompting for a password. */ /* Don't muck around if prompting for a password. */
if ((copy_in_state && pset.cur_cmd_interactive) || prompt_state) if (prompt_state)
return; return;
if (cancelConn == NULL) if (cancelConn == NULL)
...@@ -262,11 +268,7 @@ CheckConnection() ...@@ -262,11 +268,7 @@ CheckConnection()
PQfinish(pset.db); PQfinish(pset.db);
pset.db = NULL; pset.db = NULL;
ResetCancelConn(); ResetCancelConn();
SetVariable(pset.vars, "DBNAME", NULL); UnsyncVariables();
SetVariable(pset.vars, "HOST", NULL);
SetVariable(pset.vars, "PORT", NULL);
SetVariable(pset.vars, "USER", NULL);
SetVariable(pset.vars, "ENCODING", NULL);
} }
else else
fputs(gettext("Succeeded.\n"), stderr); fputs(gettext("Succeeded.\n"), stderr);
...@@ -304,8 +306,8 @@ void ResetCancelConn(void) ...@@ -304,8 +306,8 @@ void ResetCancelConn(void)
* AcceptResult * AcceptResult
* *
* Checks whether a result is valid, giving an error message if necessary; * Checks whether a result is valid, giving an error message if necessary;
* (re)sets copy_in_state and cancelConn as needed, and ensures that the * resets cancelConn as needed, and ensures that the connection to the backend
* connection to the backend is still up. * is still up.
* *
* Returns true for valid result, false for error state. * Returns true for valid result, false for error state.
*/ */
...@@ -322,12 +324,9 @@ AcceptResult(const PGresult *result) ...@@ -322,12 +324,9 @@ AcceptResult(const PGresult *result)
} }
else switch (PQresultStatus(result)) else switch (PQresultStatus(result))
{ {
case PGRES_COPY_IN:
copy_in_state = true;
break;
case PGRES_COMMAND_OK: case PGRES_COMMAND_OK:
case PGRES_TUPLES_OK: case PGRES_TUPLES_OK:
case PGRES_COPY_IN:
/* Fine, do nothing */ /* Fine, do nothing */
break; break;
...@@ -358,18 +357,15 @@ AcceptResult(const PGresult *result) ...@@ -358,18 +357,15 @@ AcceptResult(const PGresult *result)
* This is the way to send "backdoor" queries (those not directly entered * This is the way to send "backdoor" queries (those not directly entered
* by the user). It is subject to -E but not -e. * by the user). It is subject to -E but not -e.
* *
* If the given querystring generates multiple PGresults, normally the last * In autocommit-off mode, a new transaction block is started if start_xact
* one is returned to the caller. However, if ignore_command_ok is TRUE, * is true; nothing special is done when start_xact is false. Typically,
* then PGresults with status PGRES_COMMAND_OK are ignored. This is intended * start_xact = false is used for SELECTs and explicit BEGIN/COMMIT commands.
* mainly to allow locutions such as "begin; select ...; commit".
*/ */
PGresult * PGresult *
PSQLexec(const char *query, bool ignore_command_ok) PSQLexec(const char *query, bool start_xact)
{ {
PGresult *res = NULL; PGresult *res;
PGresult *newres;
int echo_hidden; int echo_hidden;
ExecStatusType rstatus;
if (!pset.db) if (!pset.db)
{ {
...@@ -378,50 +374,40 @@ PSQLexec(const char *query, bool ignore_command_ok) ...@@ -378,50 +374,40 @@ PSQLexec(const char *query, bool ignore_command_ok)
} }
echo_hidden = SwitchVariable(pset.vars, "ECHO_HIDDEN", "noexec", NULL); echo_hidden = SwitchVariable(pset.vars, "ECHO_HIDDEN", "noexec", NULL);
if (echo_hidden != var_notset) if (echo_hidden != VAR_NOTSET)
{ {
printf("********* QUERY **********\n" printf("********* QUERY **********\n"
"%s\n" "%s\n"
"**************************\n\n", query); "**************************\n\n", query);
fflush(stdout); fflush(stdout);
if (echo_hidden == 1) if (echo_hidden == 1) /* noexec? */
return NULL; return NULL;
} }
/* discard any uneaten results of past queries */
while ((newres = PQgetResult(pset.db)) != NULL)
PQclear(newres);
SetCancelConn(); SetCancelConn();
if (!PQsendQuery(pset.db, query))
{
psql_error("%s", PQerrorMessage(pset.db));
ResetCancelConn();
return NULL;
}
rstatus = PGRES_EMPTY_QUERY;
while (rstatus != PGRES_COPY_IN && if (start_xact && PQtransactionStatus(pset.db) == PQTRANS_IDLE &&
rstatus != PGRES_COPY_OUT && !GetVariableBool(pset.vars, "AUTOCOMMIT"))
(newres = PQgetResult(pset.db))) {
res = PQexec(pset.db, "BEGIN");
if (PQresultStatus(res) != PGRES_COMMAND_OK)
{ {
rstatus = PQresultStatus(newres); psql_error("%s", PQerrorMessage(pset.db));
if (!ignore_command_ok || rstatus != PGRES_COMMAND_OK) PQclear(res);
{ ResetCancelConn();
PGresult *tempRes = res; return NULL;
res = newres;
newres = tempRes;
} }
PQclear(newres); PQclear(res);
} }
res = PQexec(pset.db, query);
if (!AcceptResult(res) && res) if (!AcceptResult(res) && res)
{ {
PQclear(res); PQclear(res);
res = NULL; res = NULL;
} }
return res; return res;
} }
...@@ -613,6 +599,21 @@ SendQuery(const char *query) ...@@ -613,6 +599,21 @@ SendQuery(const char *query)
SetCancelConn(); SetCancelConn();
if (PQtransactionStatus(pset.db) == PQTRANS_IDLE &&
!GetVariableBool(pset.vars, "AUTOCOMMIT") &&
!is_transact_command(query))
{
results = PQexec(pset.db, "BEGIN");
if (PQresultStatus(results) != PGRES_COMMAND_OK)
{
psql_error("%s", PQerrorMessage(pset.db));
PQclear(results);
ResetCancelConn();
return false;
}
PQclear(results);
}
if (pset.timing) if (pset.timing)
GETTIMEOFDAY(&before); GETTIMEOFDAY(&before);
results = PQexec(pset.db, query); results = PQexec(pset.db, query);
...@@ -626,6 +627,68 @@ SendQuery(const char *query) ...@@ -626,6 +627,68 @@ SendQuery(const char *query)
return OK; return OK;
} }
/*
* check whether a query string begins with BEGIN/COMMIT/ROLLBACK/START XACT
*/
static bool
is_transact_command(const char *query)
{
int wordlen;
/*
* First we must advance over any whitespace and comments.
*/
while (*query)
{
if (isspace((unsigned char) *query))
query++;
else if (query[0] == '-' && query[1] == '-')
{
query += 2;
while (*query && *query != '\n')
query++;
}
else if (query[0] == '/' && query[1] == '*')
{
query += 2;
while (*query)
{
if (query[0] == '*' && query[1] == '/')
{
query += 2;
break;
}
else
query++;
}
}
else
break; /* found first token */
}
/*
* Check word length ("beginx" is not "begin").
*/
wordlen = 0;
while (isalpha((unsigned char) query[wordlen]))
wordlen++;
if (wordlen == 5 && strncasecmp(query, "begin", 5) == 0)
return true;
if (wordlen == 6 && strncasecmp(query, "commit", 6) == 0)
return true;
if (wordlen == 8 && strncasecmp(query, "rollback", 8) == 0)
return true;
if (wordlen == 5 && strncasecmp(query, "abort", 5) == 0)
return true;
if (wordlen == 3 && strncasecmp(query, "end", 3) == 0)
return true;
if (wordlen == 5 && strncasecmp(query, "start", 5) == 0)
return true;
return false;
}
char parse_char(char **buf) char parse_char(char **buf)
{ {
...@@ -637,3 +700,24 @@ char parse_char(char **buf) ...@@ -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 @@ ...@@ -3,7 +3,7 @@
* *
* Copyright 2000 by PostgreSQL Global Development Group * Copyright 2000 by PostgreSQL Global Development Group
* *
* $Header: /cvsroot/pgsql/src/bin/psql/common.h,v 1.25 2003/03/20 15:44:17 momjian Exp $ * $Header: /cvsroot/pgsql/src/bin/psql/common.h,v 1.26 2003/06/28 00:12:40 tgl Exp $
*/ */
#ifndef COMMON_H #ifndef COMMON_H
#define COMMON_H #define COMMON_H
...@@ -34,10 +34,12 @@ extern void ResetCancelConn(void); ...@@ -34,10 +34,12 @@ extern void ResetCancelConn(void);
extern void handle_sigint(SIGNAL_ARGS); extern void handle_sigint(SIGNAL_ARGS);
#endif /* not WIN32 */ #endif /* not WIN32 */
extern PGresult *PSQLexec(const char *query, bool ignore_command_ok); extern PGresult *PSQLexec(const char *query, bool start_xact);
extern bool SendQuery(const char *query); extern bool SendQuery(const char *query);
extern bool is_superuser(void);
/* sprompt.h */ /* sprompt.h */
extern char *simple_prompt(const char *prompt, int maxlen, bool echo); extern char *simple_prompt(const char *prompt, int maxlen, bool echo);
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
* *
* Copyright 2000 by PostgreSQL Global Development Group * Copyright 2000 by PostgreSQL Global Development Group
* *
* $Header: /cvsroot/pgsql/src/bin/psql/copy.c,v 1.29 2003/03/20 06:00:12 momjian Exp $ * $Header: /cvsroot/pgsql/src/bin/psql/copy.c,v 1.30 2003/06/28 00:12:40 tgl Exp $
*/ */
#include "postgres_fe.h" #include "postgres_fe.h"
#include "copy.h" #include "copy.h"
...@@ -32,8 +32,6 @@ ...@@ -32,8 +32,6 @@
#define S_ISDIR(mode) __S_ISTYPE((mode), S_IFDIR) #define S_ISDIR(mode) __S_ISTYPE((mode), S_IFDIR)
#endif #endif
bool copy_in_state;
/* /*
* parse_slash_copy * parse_slash_copy
* -- parses \copy command line * -- parses \copy command line
...@@ -395,7 +393,7 @@ do_copy(const char *args) ...@@ -395,7 +393,7 @@ do_copy(const char *args)
return false; return false;
} }
result = PSQLexec(query.data, false); result = PSQLexec(query.data, true);
termPQExpBuffer(&query); termPQExpBuffer(&query);
switch (PQresultStatus(result)) switch (PQresultStatus(result))
...@@ -506,10 +504,6 @@ handleCopyIn(PGconn *conn, FILE *copystream, const char *prompt) ...@@ -506,10 +504,6 @@ handleCopyIn(PGconn *conn, FILE *copystream, const char *prompt)
int ret; int ret;
unsigned int linecount = 0; unsigned int linecount = 0;
#ifdef USE_ASSERT_CHECKING
assert(copy_in_state);
#endif
if (prompt) /* disable prompt if not interactive */ if (prompt) /* disable prompt if not interactive */
{ {
if (!isatty(fileno(copystream))) if (!isatty(fileno(copystream)))
...@@ -563,7 +557,6 @@ handleCopyIn(PGconn *conn, FILE *copystream, const char *prompt) ...@@ -563,7 +557,6 @@ handleCopyIn(PGconn *conn, FILE *copystream, const char *prompt)
linecount++; linecount++;
} }
ret = !PQendcopy(conn); ret = !PQendcopy(conn);
copy_in_state = false;
pset.lineno += linecount; pset.lineno += linecount;
return ret; return ret;
} }
...@@ -3,14 +3,13 @@ ...@@ -3,14 +3,13 @@
* *
* Copyright 2000 by PostgreSQL Global Development Group * Copyright 2000 by PostgreSQL Global Development Group
* *
* $Header: /cvsroot/pgsql/src/bin/psql/copy.h,v 1.11 2001/10/28 06:25:58 momjian Exp $ * $Header: /cvsroot/pgsql/src/bin/psql/copy.h,v 1.12 2003/06/28 00:12:40 tgl Exp $
*/ */
#ifndef COPY_H #ifndef COPY_H
#define COPY_H #define COPY_H
#include "libpq-fe.h" #include "libpq-fe.h"
extern bool copy_in_state;
/* handler for \copy */ /* handler for \copy */
bool do_copy(const char *args); bool do_copy(const char *args);
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
* *
* Copyright 2000-2002 by PostgreSQL Global Development Group * Copyright 2000-2002 by PostgreSQL Global Development Group
* *
* $Header: /cvsroot/pgsql/src/bin/psql/large_obj.c,v 1.26 2003/06/27 16:55:23 tgl Exp $ * $Header: /cvsroot/pgsql/src/bin/psql/large_obj.c,v 1.27 2003/06/28 00:12:40 tgl Exp $
*/ */
#include "postgres_fe.h" #include "postgres_fe.h"
#include "large_obj.h" #include "large_obj.h"
...@@ -20,70 +20,95 @@ ...@@ -20,70 +20,95 @@
/* /*
* Since all large object ops must be in a transaction, we must do some magic * Prepare to do a large-object operation. We *must* be inside a transaction
* here. You can set the variable lo_transaction to one of commit|rollback| * block for all these operations, so start one if needed.
* nothing to get your favourite behaviour regarding any transaction in *
* progress. Rollback is default. * Returns TRUE if okay, FALSE if failed. *own_transaction is set to indicate
* if we started our own transaction or not.
*/ */
static bool
start_lo_xact(const char *operation, bool *own_transaction)
{
PGTransactionStatusType tstatus;
PGresult *res;
static char notice[80]; *own_transaction = false;
static void if (!pset.db)
_my_notice_handler(void *arg, const char *message) {
{ psql_error("%s: not connected to a database\n", operation);
(void) arg; return false;
strncpy(notice, message, 79); }
notice[79] = '\0';
} tstatus = PQtransactionStatus(pset.db);
switch (tstatus)
{
case PQTRANS_IDLE:
/* need to start our own xact */
if (!(res = PSQLexec("BEGIN", false)))
return false;
PQclear(res);
*own_transaction = true;
break;
case PQTRANS_INTRANS:
/* use the existing xact */
break;
case PQTRANS_INERROR:
psql_error("%s: current transaction is aborted\n", operation);
return false;
default:
psql_error("%s: unknown transaction status\n", operation);
return false;
}
return true;
}
/*
* Clean up after a successful LO operation
*/
static bool static bool
handle_transaction(void) finish_lo_xact(const char *operation, bool own_transaction)
{ {
PGresult *res; PGresult *res;
bool commit = false;
PQnoticeProcessor old_notice_hook;
switch (SwitchVariable(pset.vars, "LO_TRANSACTION", if (own_transaction &&
"nothing", GetVariableBool(pset.vars, "AUTOCOMMIT"))
"commit",
NULL))
{ {
case 1: /* nothing */ /* close out our own xact */
return true; if (!(res = PSQLexec("COMMIT", false)))
case 2: /* commit */ {
commit = true; res = PSQLexec("ROLLBACK", false);
break; PQclear(res);
return false;
}
PQclear(res);
} }
notice[0] = '\0'; return true;
old_notice_hook = PQsetNoticeProcessor(pset.db, _my_notice_handler, NULL); }
res = PSQLexec(commit ? "COMMIT" : "ROLLBACK", false); /*
if (!res) * Clean up after a failed LO operation
return false; */
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) || /* close out our own xact */
(commit && strcmp(notice, "WARNING: COMMIT: no transaction in progress\n") != 0)) res = PSQLexec("ROLLBACK", false);
fputs(notice, stderr); PQclear(res);
}
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); return false; /* always */
PQclear(res);
return true;
} }
/* /*
* do_lo_export() * do_lo_export()
* *
...@@ -92,53 +117,22 @@ handle_transaction(void) ...@@ -92,53 +117,22 @@ handle_transaction(void)
bool bool
do_lo_export(const char *loid_arg, const char *filename_arg) do_lo_export(const char *loid_arg, const char *filename_arg)
{ {
PGresult *res;
int status; int status;
bool own_transaction; bool own_transaction;
own_transaction = !VariableEquals(pset.vars, "LO_TRANSACTION", "nothing"); if (!start_lo_xact("\\lo_export", &own_transaction))
if (!pset.db)
{
psql_error("\\lo_export: not connected to a database\n");
return false; return false;
}
if (own_transaction)
{
if (!handle_transaction())
return false;
if (!(res = PSQLexec("BEGIN", false)))
return false;
PQclear(res);
}
status = lo_export(pset.db, atooid(loid_arg), filename_arg); status = lo_export(pset.db, atooid(loid_arg), filename_arg);
if (status != 1) if (status != 1)
{ /* of course this status is documented { /* of course this status is documented
* nowhere :( */ * nowhere :( */
fputs(PQerrorMessage(pset.db), stderr); fputs(PQerrorMessage(pset.db), stderr);
if (own_transaction) return fail_lo_xact("\\lo_export", own_transaction);
{
res = PQexec(pset.db, "ROLLBACK");
PQclear(res);
}
return false;
} }
if (own_transaction) if (!finish_lo_xact("\\lo_export", own_transaction))
{ return false;
if (!(res = PSQLexec("COMMIT", false)))
{
res = PQexec(pset.db, "ROLLBACK");
PQclear(res);
return false;
}
PQclear(res);
}
fprintf(pset.queryFout, "lo_export\n"); fprintf(pset.queryFout, "lo_export\n");
...@@ -146,7 +140,6 @@ do_lo_export(const char *loid_arg, const char *filename_arg) ...@@ -146,7 +140,6 @@ do_lo_export(const char *loid_arg, const char *filename_arg)
} }
/* /*
* do_lo_import() * do_lo_import()
* *
...@@ -161,41 +154,20 @@ do_lo_import(const char *filename_arg, const char *comment_arg) ...@@ -161,41 +154,20 @@ do_lo_import(const char *filename_arg, const char *comment_arg)
unsigned int i; unsigned int i;
bool own_transaction; bool own_transaction;
own_transaction = !VariableEquals(pset.vars, "LO_TRANSACTION", "nothing"); if (!start_lo_xact("\\lo_import", &own_transaction))
if (!pset.db)
{
psql_error("\\lo_import: not connected to a database\n");
return false; return false;
}
if (own_transaction)
{
if (!handle_transaction())
return false;
if (!(res = PSQLexec("BEGIN", false)))
return false;
PQclear(res);
}
loid = lo_import(pset.db, filename_arg); loid = lo_import(pset.db, filename_arg);
if (loid == InvalidOid) if (loid == InvalidOid)
{ {
fputs(PQerrorMessage(pset.db), stderr); fputs(PQerrorMessage(pset.db), stderr);
if (own_transaction) return fail_lo_xact("\\lo_import", own_transaction);
{
res = PQexec(pset.db, "ROLLBACK");
PQclear(res);
}
return false;
} }
/* insert description if given */ /* insert description if given */
/* XXX don't try to hack pg_description if not superuser */ /* XXX don't try to hack pg_description if not superuser */
/* XXX ought to replace this with some kind of COMMENT command */ /* XXX ought to replace this with some kind of COMMENT command */
if (comment_arg && pset.issuper) if (comment_arg && is_superuser())
{ {
char *cmdbuf; char *cmdbuf;
char *bufptr; char *bufptr;
...@@ -203,14 +175,7 @@ do_lo_import(const char *filename_arg, const char *comment_arg) ...@@ -203,14 +175,7 @@ do_lo_import(const char *filename_arg, const char *comment_arg)
cmdbuf = malloc(slen * 2 + 256); cmdbuf = malloc(slen * 2 + 256);
if (!cmdbuf) if (!cmdbuf)
{ return fail_lo_xact("\\lo_import", own_transaction);
if (own_transaction)
{
res = PQexec(pset.db, "ROLLBACK");
PQclear(res);
}
return false;
}
sprintf(cmdbuf, sprintf(cmdbuf,
"INSERT INTO pg_catalog.pg_description VALUES ('%u', " "INSERT INTO pg_catalog.pg_description VALUES ('%u', "
"'pg_catalog.pg_largeobject'::regclass, " "'pg_catalog.pg_largeobject'::regclass, "
...@@ -227,31 +192,16 @@ do_lo_import(const char *filename_arg, const char *comment_arg) ...@@ -227,31 +192,16 @@ do_lo_import(const char *filename_arg, const char *comment_arg)
if (!(res = PSQLexec(cmdbuf, false))) if (!(res = PSQLexec(cmdbuf, false)))
{ {
if (own_transaction)
{
res = PQexec(pset.db, "ROLLBACK");
PQclear(res);
}
free(cmdbuf); free(cmdbuf);
return false; return fail_lo_xact("\\lo_import", own_transaction);
} }
PQclear(res); PQclear(res);
free(cmdbuf); free(cmdbuf);
} }
if (own_transaction) if (!finish_lo_xact("\\lo_import", own_transaction))
{ return false;
if (!(res = PSQLexec("COMMIT", false)))
{
res = PQexec(pset.db, "ROLLBACK");
PQclear(res);
return false;
}
PQclear(res);
}
fprintf(pset.queryFout, "lo_import %u\n", loid); fprintf(pset.queryFout, "lo_import %u\n", loid);
sprintf(oidbuf, "%u", loid); sprintf(oidbuf, "%u", loid);
...@@ -261,7 +211,6 @@ do_lo_import(const char *filename_arg, const char *comment_arg) ...@@ -261,7 +211,6 @@ do_lo_import(const char *filename_arg, const char *comment_arg)
} }
/* /*
* do_lo_unlink() * do_lo_unlink()
* *
...@@ -276,69 +225,32 @@ do_lo_unlink(const char *loid_arg) ...@@ -276,69 +225,32 @@ do_lo_unlink(const char *loid_arg)
char buf[256]; char buf[256];
bool own_transaction; bool own_transaction;
own_transaction = !VariableEquals(pset.vars, "LO_TRANSACTION", "nothing"); if (!start_lo_xact("\\lo_unlink", &own_transaction))
if (!pset.db)
{
psql_error("\\lo_unlink: not connected to a database\n");
return false; return false;
}
if (own_transaction)
{
if (!handle_transaction())
return false;
if (!(res = PSQLexec("BEGIN", false)))
return false;
PQclear(res);
}
status = lo_unlink(pset.db, loid); status = lo_unlink(pset.db, loid);
if (status == -1) if (status == -1)
{ {
fputs(PQerrorMessage(pset.db), stderr); fputs(PQerrorMessage(pset.db), stderr);
if (own_transaction) return fail_lo_xact("\\lo_unlink", own_transaction);
{
res = PQexec(pset.db, "ROLLBACK");
PQclear(res);
}
return false;
} }
/* remove the comment as well */ /* remove the comment as well */
/* XXX don't try to hack pg_description if not superuser */ /* XXX don't try to hack pg_description if not superuser */
/* XXX ought to replace this with some kind of COMMENT command */ /* XXX ought to replace this with some kind of COMMENT command */
if (pset.issuper) if (is_superuser())
{ {
snprintf(buf, sizeof(buf), snprintf(buf, sizeof(buf),
"DELETE FROM pg_catalog.pg_description WHERE objoid = '%u' " "DELETE FROM pg_catalog.pg_description WHERE objoid = '%u' "
"AND classoid = 'pg_catalog.pg_largeobject'::regclass", "AND classoid = 'pg_catalog.pg_largeobject'::regclass",
loid); loid);
if (!(res = PSQLexec(buf, false))) if (!(res = PSQLexec(buf, false)))
{ return fail_lo_xact("\\lo_unlink", own_transaction);
if (own_transaction)
{
res = PQexec(pset.db, "ROLLBACK");
PQclear(res);
}
return false;
}
PQclear(res);
}
if (own_transaction)
{
if (!(res = PSQLexec("COMMIT", false)))
{
res = PQexec(pset.db, "ROLLBACK");
PQclear(res);
return false;
}
PQclear(res); PQclear(res);
} }
if (!finish_lo_xact("\\lo_unlink", own_transaction))
return false;
fprintf(pset.queryFout, "lo_unlink %u\n", loid); fprintf(pset.queryFout, "lo_unlink %u\n", loid);
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
* *
* Copyright 2000 by PostgreSQL Global Development Group * Copyright 2000 by PostgreSQL Global Development Group
* *
* $Header: /cvsroot/pgsql/src/bin/psql/prompt.c,v 1.25 2003/04/04 20:42:13 momjian Exp $ * $Header: /cvsroot/pgsql/src/bin/psql/prompt.c,v 1.26 2003/06/28 00:12:40 tgl Exp $
*/ */
#include "postgres_fe.h" #include "postgres_fe.h"
#include "prompt.h" #include "prompt.h"
...@@ -44,6 +44,7 @@ ...@@ -44,6 +44,7 @@
* or a ! if session is not connected to a database; * or a ! if session is not connected to a database;
* in prompt2 -, *, ', or "; * in prompt2 -, *, ', or ";
* in prompt3 nothing * in prompt3 nothing
* %T - transaction status: empty, *, !, ? (unknown or no connection)
* %? - the error code of the last query (not yet implemented) * %? - the error code of the last query (not yet implemented)
* %% - a percent sign * %% - a percent sign
* *
...@@ -172,7 +173,7 @@ get_prompt(promptStatus_t status) ...@@ -172,7 +173,7 @@ get_prompt(promptStatus_t status)
case '8': case '8':
case '9': case '9':
*buf = parse_char((char **)&p); *buf = parse_char((char **)&p);
break; break;
case 'R': case 'R':
switch (status) switch (status)
...@@ -204,20 +205,39 @@ get_prompt(promptStatus_t status) ...@@ -204,20 +205,39 @@ get_prompt(promptStatus_t status)
buf[0] = '\0'; buf[0] = '\0';
break; break;
} }
break;
case 'T':
if (!pset.db)
buf[0] = '?';
else switch (PQtransactionStatus(pset.db))
{
case PQTRANS_IDLE:
buf[0] = '\0';
break;
case PQTRANS_ACTIVE:
case PQTRANS_INTRANS:
buf[0] = '*';
break;
case PQTRANS_INERROR:
buf[0] = '!';
break;
default:
buf[0] = '?';
break;
}
break;
case '?': case '?':
/* not here yet */ /* not here yet */
break; break;
case '#': case '#':
{ if (is_superuser())
if (pset.issuper) buf[0] = '#';
buf[0] = '#'; else
else buf[0] = '>';
buf[0] = '>'; break;
break;
}
/* execute command */ /* execute command */
case '`': case '`':
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
* *
* Copyright 2000 by PostgreSQL Global Development Group * Copyright 2000 by PostgreSQL Global Development Group
* *
* $Header: /cvsroot/pgsql/src/bin/psql/settings.h,v 1.13 2002/03/05 00:01:02 momjian Exp $ * $Header: /cvsroot/pgsql/src/bin/psql/settings.h,v 1.14 2003/06/28 00:12:40 tgl Exp $
*/ */
#ifndef SETTINGS_H #ifndef SETTINGS_H
#define SETTINGS_H #define SETTINGS_H
...@@ -48,9 +48,7 @@ typedef struct _psqlSettings ...@@ -48,9 +48,7 @@ typedef struct _psqlSettings
char *inputfile; /* for error reporting */ char *inputfile; /* for error reporting */
unsigned lineno; /* also for error reporting */ unsigned lineno; /* also for error reporting */
bool issuper; /* is the current user a superuser? (used bool timing; /* enable timing of all queries */
* to form the prompt) */
bool timing; /* timing of all queries */
} PsqlSettings; } PsqlSettings;
extern PsqlSettings pset; extern PsqlSettings pset;
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
* *
* Copyright 2000 by PostgreSQL Global Development Group * Copyright 2000 by PostgreSQL Global Development Group
* *
* $Header: /cvsroot/pgsql/src/bin/psql/startup.c,v 1.73 2003/04/04 20:42:13 momjian Exp $ * $Header: /cvsroot/pgsql/src/bin/psql/startup.c,v 1.74 2003/06/28 00:12:40 tgl Exp $
*/ */
#include "postgres_fe.h" #include "postgres_fe.h"
...@@ -74,18 +74,13 @@ struct adhoc_opts ...@@ -74,18 +74,13 @@ struct adhoc_opts
bool no_psqlrc; bool no_psqlrc;
}; };
static void static void parse_psql_options(int argc, char *argv[],
parse_psql_options(int argc, char *argv[], struct adhoc_opts * options); struct adhoc_opts * options);
static void process_psqlrc(void);
static void static void showVersion(void);
process_psqlrc(void);
static void
showVersion(void);
#ifdef USE_SSL #ifdef USE_SSL
static void static void printSSLInfo(void);
printSSLInfo(void);
#endif #endif
...@@ -144,6 +139,10 @@ main(int argc, char *argv[]) ...@@ -144,6 +139,10 @@ main(int argc, char *argv[])
SetVariable(pset.vars, "VERSION", PG_VERSION_STR); SetVariable(pset.vars, "VERSION", PG_VERSION_STR);
/* Default values for variables that are used in noninteractive cases */
SetVariableBool(pset.vars, "AUTOCOMMIT");
SetVariable(pset.vars, "VERBOSE", "default");
pset.notty = (!isatty(fileno(stdin)) || !isatty(fileno(stdout))); pset.notty = (!isatty(fileno(stdin)) || !isatty(fileno(stdout)));
/* This is obsolete and should be removed sometime. */ /* This is obsolete and should be removed sometime. */
...@@ -208,11 +207,7 @@ main(int argc, char *argv[]) ...@@ -208,11 +207,7 @@ main(int argc, char *argv[])
PQsetNoticeProcessor(pset.db, NoticeProcessor, NULL); PQsetNoticeProcessor(pset.db, NoticeProcessor, NULL);
/* SyncVariables();
* We need to save the encoding because we want to have it available
* even if the database connection goes bad.
*/
pset.encoding = PQclientEncoding(pset.db);
if (options.action == ACT_LIST_DB) if (options.action == ACT_LIST_DB)
{ {
...@@ -222,14 +217,6 @@ main(int argc, char *argv[]) ...@@ -222,14 +217,6 @@ main(int argc, char *argv[])
exit(success ? EXIT_SUCCESS : EXIT_FAILURE); exit(success ? EXIT_SUCCESS : EXIT_FAILURE);
} }
SetVariable(pset.vars, "DBNAME", PQdb(pset.db));
SetVariable(pset.vars, "USER", PQuser(pset.db));
SetVariable(pset.vars, "HOST", PQhost(pset.db));
SetVariable(pset.vars, "PORT", PQport(pset.db));
SetVariable(pset.vars, "ENCODING", pg_encoding_to_char(pset.encoding));
pset.popt.topt.encoding = pset.encoding;
/* /*
* Now find something to do * Now find something to do
*/ */
...@@ -274,7 +261,6 @@ main(int argc, char *argv[]) ...@@ -274,7 +261,6 @@ main(int argc, char *argv[])
*/ */
else else
{ {
pset.issuper = test_superuser(PQuser(pset.db));
if (!QUIET() && !pset.notty) if (!QUIET() && !pset.notty)
{ {
printf(gettext("Welcome to %s %s, the PostgreSQL interactive terminal.\n\n" printf(gettext("Welcome to %s %s, the PostgreSQL interactive terminal.\n\n"
...@@ -289,15 +275,18 @@ main(int argc, char *argv[]) ...@@ -289,15 +275,18 @@ main(int argc, char *argv[])
#endif #endif
} }
/* Default values for variables that are used in interactive case */
SetVariable(pset.vars, "PROMPT1", DEFAULT_PROMPT1); SetVariable(pset.vars, "PROMPT1", DEFAULT_PROMPT1);
SetVariable(pset.vars, "PROMPT2", DEFAULT_PROMPT2); SetVariable(pset.vars, "PROMPT2", DEFAULT_PROMPT2);
SetVariable(pset.vars, "PROMPT3", DEFAULT_PROMPT3); SetVariable(pset.vars, "PROMPT3", DEFAULT_PROMPT3);
if (!options.no_psqlrc) if (!options.no_psqlrc)
process_psqlrc(); process_psqlrc();
if (!pset.notty) if (!pset.notty)
initializeInput(options.no_readline ? 0 : 1); initializeInput(options.no_readline ? 0 : 1);
if (options.action_string) /* -f - was used */ if (options.action_string) /* -f - was used */
pset.inputfile = "<stdin>"; pset.inputfile = "<stdin>";
successResult = MainLoop(stdin); successResult = MainLoop(stdin);
} }
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
* *
* Copyright 2000 by PostgreSQL Global Development Group * Copyright 2000 by PostgreSQL Global Development Group
* *
* $Header: /cvsroot/pgsql/src/bin/psql/variables.c,v 1.10 2003/03/20 06:43:35 momjian Exp $ * $Header: /cvsroot/pgsql/src/bin/psql/variables.c,v 1.11 2003/06/28 00:12:40 tgl Exp $
*/ */
#include "postgres_fe.h" #include "postgres_fe.h"
#include "variables.h" #include "variables.h"
...@@ -33,8 +33,6 @@ CreateVariableSpace(void) ...@@ -33,8 +33,6 @@ CreateVariableSpace(void)
return ptr; return ptr;
} }
const char * const char *
GetVariable(VariableSpace space, const char *name) GetVariable(VariableSpace space, const char *name)
{ {
...@@ -59,14 +57,19 @@ GetVariable(VariableSpace space, const char *name) ...@@ -59,14 +57,19 @@ GetVariable(VariableSpace space, const char *name)
return NULL; return NULL;
} }
bool bool
GetVariableBool(VariableSpace space, const char *name) GetVariableBool(VariableSpace space, const char *name)
{ {
return GetVariable(space, name) != NULL ? true : false; const char *val;
}
val = GetVariable(space, name);
if (val == NULL)
return false; /* not set -> assume "off" */
if (strcmp(val, "off") == 0)
return false;
/* for backwards compatibility, anything except "off" is taken as "true" */
return true;
}
bool bool
VariableEquals(VariableSpace space, const char name[], const char value[]) VariableEquals(VariableSpace space, const char name[], const char value[])
...@@ -76,7 +79,6 @@ VariableEquals(VariableSpace space, const char name[], const char value[]) ...@@ -76,7 +79,6 @@ VariableEquals(VariableSpace space, const char name[], const char value[])
return var && (strcmp(var, value) == 0); return var && (strcmp(var, value) == 0);
} }
int int
GetVariableNum(VariableSpace space, GetVariableNum(VariableSpace space,
const char name[], const char name[],
...@@ -103,7 +105,6 @@ GetVariableNum(VariableSpace space, ...@@ -103,7 +105,6 @@ GetVariableNum(VariableSpace space,
return result; return result;
} }
int int
SwitchVariable(VariableSpace space, const char name[], const char *opt, ...) SwitchVariable(VariableSpace space, const char name[], const char *opt, ...)
{ {
...@@ -117,17 +118,16 @@ SwitchVariable(VariableSpace space, const char name[], const char *opt, ...) ...@@ -117,17 +118,16 @@ SwitchVariable(VariableSpace space, const char name[], const char *opt, ...)
va_start(args, opt); va_start(args, opt);
for (result=1; opt && (strcmp(var, opt) != 0); result++) for (result=1; opt && (strcmp(var, opt) != 0); result++)
opt = va_arg(args,const char *); opt = va_arg(args,const char *);
if (!opt)
if (!opt) result = var_notfound; result = VAR_NOTFOUND;
va_end(args); va_end(args);
} }
else else
result = var_notset; result = VAR_NOTSET;
return result; return result;
} }
void void
PrintVariables(VariableSpace space) PrintVariables(VariableSpace space)
{ {
...@@ -136,7 +136,6 @@ PrintVariables(VariableSpace space) ...@@ -136,7 +136,6 @@ PrintVariables(VariableSpace space)
printf("%s = '%s'\n", ptr->name, ptr->value); printf("%s = '%s'\n", ptr->name, ptr->value);
} }
bool bool
SetVariable(VariableSpace space, const char *name, const char *value) SetVariable(VariableSpace space, const char *name, const char *value)
{ {
...@@ -176,16 +175,12 @@ SetVariable(VariableSpace space, const char *name, const char *value) ...@@ -176,16 +175,12 @@ SetVariable(VariableSpace space, const char *name, const char *value)
return previous->next->value ? true : false; return previous->next->value ? true : false;
} }
bool bool
SetVariableBool(VariableSpace space, const char *name) SetVariableBool(VariableSpace space, const char *name)
{ {
return SetVariable(space, name, ""); return SetVariable(space, name, "on");
} }
bool bool
DeleteVariable(VariableSpace space, const char *name) DeleteVariable(VariableSpace space, const char *name)
{ {
...@@ -217,15 +212,3 @@ DeleteVariable(VariableSpace space, const char *name) ...@@ -217,15 +212,3 @@ DeleteVariable(VariableSpace space, const char *name)
return true; return true;
} }
void
DestroyVariableSpace(VariableSpace space)
{
if (!space)
return;
DestroyVariableSpace(space->next);
free(space);
}
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
* *
* Copyright 2000 by PostgreSQL Global Development Group * Copyright 2000 by PostgreSQL Global Development Group
* *
* $Header: /cvsroot/pgsql/src/bin/psql/variables.h,v 1.11 2003/03/20 06:43:35 momjian Exp $ * $Header: /cvsroot/pgsql/src/bin/psql/variables.h,v 1.12 2003/06/28 00:12:40 tgl Exp $
*/ */
/* /*
...@@ -45,18 +45,18 @@ int GetVariableNum(VariableSpace space, ...@@ -45,18 +45,18 @@ int GetVariableNum(VariableSpace space,
/* Find value of variable <name> among NULL-terminated list of alternative /* Find value of variable <name> among NULL-terminated list of alternative
* options. Returns var_notset if the variable was not set, var_notfound if its * options. Returns VAR_NOTSET if the variable was not set, VAR_NOTFOUND
* value did not occur in the list of options, or the number of the matching * if its value did not occur in the list of options, or the number of the
* option. The first option is 1, the second is 2 and so on. * matching option. The first option is 1, the second is 2 and so on.
*/ */
enum { var_notset = 0, var_notfound = -1 }; enum { VAR_NOTSET = 0, VAR_NOTFOUND = -1 };
int SwitchVariable(VariableSpace space, const char name[], const char *opt,...); int SwitchVariable(VariableSpace space, const char name[],
const char *opt, ...);
void PrintVariables(VariableSpace space); void PrintVariables(VariableSpace space);
bool SetVariable(VariableSpace space, const char *name, const char *value); bool SetVariable(VariableSpace space, const char *name, const char *value);
bool SetVariableBool(VariableSpace space, const char *name); bool SetVariableBool(VariableSpace space, const char *name);
bool DeleteVariable(VariableSpace space, const char *name); bool DeleteVariable(VariableSpace space, const char *name);
void DestroyVariableSpace(VariableSpace space);
#endif /* VARIABLES_H */ #endif /* VARIABLES_H */
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment