diff options
author | Bruce Momjian <bruce@momjian.us> | 1998-08-09 02:59:33 +0000 |
---|---|---|
committer | Bruce Momjian <bruce@momjian.us> | 1998-08-09 02:59:33 +0000 |
commit | e6311b4ad0f5c6eb52fd90a9ed51862b8f2d3869 (patch) | |
tree | c96017785851169c24a64e3eff2d4caba395ddbe /src/interfaces/libpq/fe-connect.c | |
parent | e46df2ff6e190e748d33e3c6c6ca60cc13b5959b (diff) | |
download | postgresql-e6311b4ad0f5c6eb52fd90a9ed51862b8f2d3869.tar.gz postgresql-e6311b4ad0f5c6eb52fd90a9ed51862b8f2d3869.zip |
The attached patch implements some changes that were discussed a
couple weeks ago on the hackers and interfaces lists:
1. When the backend sends a NOTICE message and closes the connection
(typically, because it was told to by the postmaster after
another backend coredumped), libpq will now print the notice
and close the connection cleanly. Formerly, the frontend app
would usually terminate ungracefully due to a SIGPIPE. (I am
not sure if 6.3.2 behaved that way, but the current cvs sources
do...)
2. libpq's various printouts to stderr are now fed through a single
"notice processor" routine, which can be overridden by the
application to direct notices someplace else. This should ease
porting libpq to Windows.
I also noticed and fixed a problem in PQprint: when sending output
to a pager subprocess, it would disable SIGPIPE in case the pager
terminates early (this is good) --- but afterwards it reset SIGPIPE
to SIG_DFL, rather than restoring the application's prior setting
(bad).
regards, tom lane
Diffstat (limited to 'src/interfaces/libpq/fe-connect.c')
-rw-r--r-- | src/interfaces/libpq/fe-connect.c | 116 |
1 files changed, 43 insertions, 73 deletions
diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c index 1e306ee7dd2..cc8af6d6acf 100644 --- a/src/interfaces/libpq/fe-connect.c +++ b/src/interfaces/libpq/fe-connect.c @@ -7,7 +7,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-connect.c,v 1.77 1998/07/26 04:31:36 scrappy Exp $ + * $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-connect.c,v 1.78 1998/08/09 02:59:26 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -29,7 +29,6 @@ #include <ctype.h> #include <string.h> #include <errno.h> -#include <signal.h> #include <ctype.h> /* for isspace() */ #include "postgres.h" @@ -55,6 +54,7 @@ static void closePGconn(PGconn *conn); static int conninfo_parse(const char *conninfo, char *errorMessage); static char *conninfo_getval(char *keyword); static void conninfo_free(void); +static void defaultNoticeProcessor(void * arg, const char * message); /* XXX Why is this not static? */ void PQsetenv(PGconn *conn); @@ -181,11 +181,7 @@ PQconnectdb(const char *conninfo) */ conn = makeEmptyPGconn(); if (conn == NULL) - { - fprintf(stderr, - "FATAL: PQconnectdb() -- unable to allocate memory for a PGconn"); return (PGconn *) NULL; - } /* ---------- * Parse the conninfo string and save settings in conn structure @@ -297,11 +293,7 @@ PQsetdbLogin(const char *pghost, const char *pgport, const char *pgoptions, cons conn = makeEmptyPGconn(); if (conn == NULL) - { - fprintf(stderr, - "FATAL: PQsetdbLogin() -- unable to allocate memory for a PGconn"); return (PGconn *) NULL; - } if ((pghost == NULL) || pghost[0] == '\0') { @@ -856,6 +848,7 @@ makeEmptyPGconn(void) /* Zero all pointers */ MemSet((char *) conn, 0, sizeof(PGconn)); + conn->noticeHook = defaultNoticeProcessor; conn->status = CONNECTION_BAD; conn->asyncStatus = PGASYNC_IDLE; conn->notifyList = DLNewList(); @@ -925,35 +918,20 @@ closePGconn(PGconn *conn) if (conn->sock >= 0) { /* - * Try to send close message. - * If connection is already gone, that's cool. No reason for kernel - * to kill us when we try to write to it. So ignore SIGPIPE signals. + * Try to send "close connection" message to backend. + * BUT: backend might have already closed connection. + * To avoid being killed by SIGPIPE, we need to detect this before + * writing. Check for "read ready" condition which indicates EOF. */ -#ifndef WIN32 -#if defined(USE_POSIX_SIGNALS) - struct sigaction ignore_action; - struct sigaction oldaction; - - ignore_action.sa_handler = SIG_IGN; - sigemptyset(&ignore_action.sa_mask); - ignore_action.sa_flags = 0; - sigaction(SIGPIPE, (struct sigaction *) & ignore_action, &oldaction); - - (void) pqPuts("X", conn); - (void) pqFlush(conn); - - sigaction(SIGPIPE, &oldaction, NULL); -#else - void (*oldsignal)(int); - - oldsignal = signal(SIGPIPE, SIG_IGN); - - (void) pqPuts("X", conn); - (void) pqFlush(conn); - - signal(SIGPIPE, oldsignal); -#endif -#endif /* Win32 uses no signals at all */ + while (pqReadReady(conn)) { + if (pqReadData(conn) < 0) + break; + } + if (conn->sock >= 0) { + /* Should be safe now... */ + (void) pqPuts("X", conn); + (void) pqFlush(conn); + } } /* @@ -987,9 +965,7 @@ closePGconn(PGconn *conn) void PQfinish(PGconn *conn) { - if (!conn) - fprintf(stderr, "PQfinish() -- pointer to PGconn is null\n"); - else + if (conn) { closePGconn(conn); freePGconn(conn); @@ -1003,9 +979,7 @@ PQfinish(PGconn *conn) void PQreset(PGconn *conn) { - if (!conn) - fprintf(stderr, "PQreset() -- pointer to PGconn is null\n"); - else + if (conn) { closePGconn(conn); conn->status = connectDB(conn); @@ -1383,10 +1357,7 @@ char * PQdb(PGconn *conn) { if (!conn) - { - fprintf(stderr, "PQdb() -- pointer to PGconn is null\n"); return (char *) NULL; - } return conn->dbName; } @@ -1394,10 +1365,7 @@ char * PQuser(PGconn *conn) { if (!conn) - { - fprintf(stderr, "PQuser() -- pointer to PGconn is null\n"); return (char *) NULL; - } return conn->pguser; } @@ -1405,11 +1373,7 @@ char * PQhost(PGconn *conn) { if (!conn) - { - fprintf(stderr, "PQhost() -- pointer to PGconn is null\n"); return (char *) NULL; - } - return conn->pghost; } @@ -1417,10 +1381,7 @@ char * PQoptions(PGconn *conn) { if (!conn) - { - fprintf(stderr, "PQoptions() -- pointer to PGconn is null\n"); return (char *) NULL; - } return conn->pgoptions; } @@ -1428,10 +1389,7 @@ char * PQtty(PGconn *conn) { if (!conn) - { - fprintf(stderr, "PQtty() -- pointer to PGconn is null\n"); return (char *) NULL; - } return conn->pgtty; } @@ -1439,10 +1397,7 @@ char * PQport(PGconn *conn) { if (!conn) - { - fprintf(stderr, "PQport() -- pointer to PGconn is null\n"); return (char *) NULL; - } return conn->pgport; } @@ -1450,21 +1405,16 @@ ConnStatusType PQstatus(PGconn *conn) { if (!conn) - { - fprintf(stderr, "PQstatus() -- pointer to PGconn is null\n"); return CONNECTION_BAD; - } return conn->status; } char * PQerrorMessage(PGconn *conn) { + static char noConn[] = "PQerrorMessage: conn pointer is NULL\n"; if (!conn) - { - fprintf(stderr, "PQerrorMessage() -- pointer to PGconn is null\n"); - return (char *) NULL; - } + return noConn; return conn->errorMessage; } @@ -1472,10 +1422,7 @@ int PQsocket(PGconn *conn) { if (!conn) - { - fprintf(stderr, "PQsocket() -- pointer to PGconn is null\n"); return -1; - } return conn->sock; } @@ -1501,3 +1448,26 @@ PQuntrace(PGconn *conn) conn->Pfdebug = NULL; } } + +void +PQsetNoticeProcessor (PGconn *conn, PQnoticeProcessor proc, void *arg) +{ + if (conn == NULL) + return; + conn->noticeHook = proc; + conn->noticeArg = arg; +} + +/* + * The default notice/error message processor just prints the + * message on stderr. Applications can override this if they + * want the messages to go elsewhere (a window, for example). + * Note that simply discarding notices is probably a bad idea. + */ + +static void +defaultNoticeProcessor(void * arg, const char * message) +{ + /* Note: we expect the supplied string to end with a newline already. */ + fprintf(stderr, "%s", message); +} |