summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMagnus Hagander2008-10-27 09:42:31 +0000
committerMagnus Hagander2008-10-27 09:42:31 +0000
commit7b4cf0a097ca1e9439a5881b2cdd6a8f7f9d8f5b (patch)
tree87419494be346f2cf9b069808707379e32ca85fe
parentb29e5e43ff0ed5d32550cddb5e0340de693233e9 (diff)
Add support for multiple error messages from libpq, by simply appending them
after each other (since we already add a newline on each, this makes them multiline). Previously a new error would just overwrite the old one, so for example any error caused when trying to connect with SSL enabled would be overwritten by the error message form the non-SSL connection when using sslmode=prefer.
-rw-r--r--doc/src/sgml/libpq.sgml9
-rw-r--r--src/interfaces/libpq/fe-connect.c47
-rw-r--r--src/interfaces/libpq/fe-misc.c22
-rw-r--r--src/interfaces/libpq/fe-protocol3.c1
-rw-r--r--src/interfaces/libpq/libpq-int.h1
5 files changed, 49 insertions, 31 deletions
diff --git a/doc/src/sgml/libpq.sgml b/doc/src/sgml/libpq.sgml
index 4e7a7081c9..b1bfad05a9 100644
--- a/doc/src/sgml/libpq.sgml
+++ b/doc/src/sgml/libpq.sgml
@@ -1137,10 +1137,11 @@ PQconninfoOption *PQconninfoParse(const char *conninfo, char **errmsg);
Nearly all <application>libpq</> functions will set a message for
<function>PQerrorMessage</function> if they fail. Note that by
<application>libpq</application> convention, a nonempty
- <function>PQerrorMessage</function> result will include a trailing
- newline. The caller should not free the result directly. It will
- be freed when the associated <structname>PGconn</> handle is passed
- to <function>PQfinish</function>. The result string should not be
+ <function>PQerrorMessage</function> result can be multiple lines,
+ and will include a trailing newline. The caller should not free
+ the result directly. It will be freed when the associated
+ <structname>PGconn</> handle is passed to
+ <function>PQfinish</function>. The result string should not be
expected to remain the same across operations on the
<literal>PGconn</> structure.
</para>
diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index e23cbfd8c2..17642d8b59 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -699,7 +699,7 @@ connectNoDelay(PGconn *conn)
{
char sebuf[256];
- printfPQExpBuffer(&conn->errorMessage,
+ appendPQExpBuffer(&conn->errorMessage,
libpq_gettext("could not set socket to TCP no delay mode: %s\n"),
SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf)));
return 0;
@@ -729,7 +729,7 @@ connectFailureMessage(PGconn *conn, int errorno)
NULL, 0,
service, sizeof(service),
NI_NUMERICSERV);
- printfPQExpBuffer(&conn->errorMessage,
+ appendPQExpBuffer(&conn->errorMessage,
libpq_gettext("could not connect to server: %s\n"
"\tIs the server running locally and accepting\n"
"\tconnections on Unix domain socket \"%s\"?\n"),
@@ -739,7 +739,7 @@ connectFailureMessage(PGconn *conn, int errorno)
else
#endif /* HAVE_UNIX_SOCKETS */
{
- printfPQExpBuffer(&conn->errorMessage,
+ appendPQExpBuffer(&conn->errorMessage,
libpq_gettext("could not connect to server: %s\n"
"\tIs the server running on host \"%s\" and accepting\n"
"\tTCP/IP connections on port %s?\n"),
@@ -829,11 +829,11 @@ connectDBStart(PGconn *conn)
if (ret || !addrs)
{
if (node)
- printfPQExpBuffer(&conn->errorMessage,
+ appendPQExpBuffer(&conn->errorMessage,
libpq_gettext("could not translate host name \"%s\" to address: %s\n"),
node, gai_strerror(ret));
else
- printfPQExpBuffer(&conn->errorMessage,
+ appendPQExpBuffer(&conn->errorMessage,
libpq_gettext("could not translate Unix-domain socket path \"%s\" to address: %s\n"),
portstr, gai_strerror(ret));
if (addrs)
@@ -924,6 +924,8 @@ connectDBComplete(PGconn *conn)
switch (flag)
{
case PGRES_POLLING_OK:
+ /* Reset stored error messages since we now have a working connection */
+ resetPQExpBuffer(&conn->errorMessage);
return 1; /* success! */
case PGRES_POLLING_READING:
@@ -1033,7 +1035,7 @@ PQconnectPoll(PGconn *conn)
break;
default:
- printfPQExpBuffer(&conn->errorMessage,
+ appendPQExpBuffer(&conn->errorMessage,
libpq_gettext(
"invalid connection state, "
"probably indicative of memory corruption\n"
@@ -1077,7 +1079,7 @@ keep_going: /* We will come back to here until there is
conn->addr_cur = addr_cur->ai_next;
continue;
}
- printfPQExpBuffer(&conn->errorMessage,
+ appendPQExpBuffer(&conn->errorMessage,
libpq_gettext("could not create socket: %s\n"),
SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf)));
break;
@@ -1100,7 +1102,7 @@ keep_going: /* We will come back to here until there is
}
if (!pg_set_noblock(conn->sock))
{
- printfPQExpBuffer(&conn->errorMessage,
+ appendPQExpBuffer(&conn->errorMessage,
libpq_gettext("could not set socket to non-blocking mode: %s\n"),
SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf)));
closesocket(conn->sock);
@@ -1112,7 +1114,7 @@ keep_going: /* We will come back to here until there is
#ifdef F_SETFD
if (fcntl(conn->sock, F_SETFD, FD_CLOEXEC) == -1)
{
- printfPQExpBuffer(&conn->errorMessage,
+ appendPQExpBuffer(&conn->errorMessage,
libpq_gettext("could not set socket to close-on-exec mode: %s\n"),
SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf)));
closesocket(conn->sock);
@@ -1199,7 +1201,7 @@ keep_going: /* We will come back to here until there is
if (getsockopt(conn->sock, SOL_SOCKET, SO_ERROR,
(char *) &optval, &optlen) == -1)
{
- printfPQExpBuffer(&conn->errorMessage,
+ appendPQExpBuffer(&conn->errorMessage,
libpq_gettext("could not get socket error status: %s\n"),
SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf)));
goto error_return;
@@ -1237,7 +1239,7 @@ keep_going: /* We will come back to here until there is
(struct sockaddr *) & conn->laddr.addr,
&conn->laddr.salen) < 0)
{
- printfPQExpBuffer(&conn->errorMessage,
+ appendPQExpBuffer(&conn->errorMessage,
libpq_gettext("could not get client address from socket: %s\n"),
SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf)));
goto error_return;
@@ -1281,7 +1283,7 @@ keep_going: /* We will come back to here until there is
pv = htonl(NEGOTIATE_SSL_CODE);
if (pqPacketSend(conn, 0, &pv, sizeof(pv)) != STATUS_OK)
{
- printfPQExpBuffer(&conn->errorMessage,
+ appendPQExpBuffer(&conn->errorMessage,
libpq_gettext("could not send SSL negotiation packet: %s\n"),
SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf)));
goto error_return;
@@ -1303,6 +1305,7 @@ keep_going: /* We will come back to here until there is
EnvironmentOptions);
if (!startpacket)
{
+ /* will not appendbuffer here, since it's likely to also run out of memory */
printfPQExpBuffer(&conn->errorMessage,
libpq_gettext("out of memory\n"));
goto error_return;
@@ -1316,7 +1319,7 @@ keep_going: /* We will come back to here until there is
*/
if (pqPacketSend(conn, 0, startpacket, packetlen) != STATUS_OK)
{
- printfPQExpBuffer(&conn->errorMessage,
+ appendPQExpBuffer(&conn->errorMessage,
libpq_gettext("could not send startup packet: %s\n"),
SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf)));
free(startpacket);
@@ -1381,7 +1384,7 @@ keep_going: /* We will come back to here until there is
if (conn->sslmode[0] == 'r') /* "require" */
{
/* Require SSL, but server does not want it */
- printfPQExpBuffer(&conn->errorMessage,
+ appendPQExpBuffer(&conn->errorMessage,
libpq_gettext("server does not support SSL, but SSL was required\n"));
goto error_return;
}
@@ -1398,7 +1401,7 @@ keep_going: /* We will come back to here until there is
if (conn->sslmode[0] == 'r') /* "require" */
{
/* Require SSL, but server is too old */
- printfPQExpBuffer(&conn->errorMessage,
+ appendPQExpBuffer(&conn->errorMessage,
libpq_gettext("server does not support SSL, but SSL was required\n"));
goto error_return;
}
@@ -1414,7 +1417,7 @@ keep_going: /* We will come back to here until there is
}
else
{
- printfPQExpBuffer(&conn->errorMessage,
+ appendPQExpBuffer(&conn->errorMessage,
libpq_gettext("received invalid response to SSL negotiation: %c\n"),
SSLok);
goto error_return;
@@ -1489,7 +1492,7 @@ keep_going: /* We will come back to here until there is
*/
if (!(beresp == 'R' || beresp == 'E'))
{
- printfPQExpBuffer(&conn->errorMessage,
+ appendPQExpBuffer(&conn->errorMessage,
libpq_gettext(
"expected authentication request from "
"server, but received %c\n"),
@@ -1522,7 +1525,7 @@ keep_going: /* We will come back to here until there is
*/
if (beresp == 'R' && (msgLength < 8 || msgLength > 2000))
{
- printfPQExpBuffer(&conn->errorMessage,
+ appendPQExpBuffer(&conn->errorMessage,
libpq_gettext(
"expected authentication request from "
"server, but received %c\n"),
@@ -1534,7 +1537,7 @@ keep_going: /* We will come back to here until there is
{
/* Handle error from a pre-3.0 server */
conn->inCursor = conn->inStart + 1; /* reread data */
- if (pqGets(&conn->errorMessage, conn))
+ if (pqGets_append(&conn->errorMessage, conn))
{
/* We'll come back when there is more data */
return PGRES_POLLING_READING;
@@ -1601,7 +1604,7 @@ keep_going: /* We will come back to here until there is
}
else
{
- if (pqGets(&conn->errorMessage, conn))
+ if (pqGets_append(&conn->errorMessage, conn))
{
/* We'll come back when there is more data */
return PGRES_POLLING_READING;
@@ -1788,7 +1791,7 @@ keep_going: /* We will come back to here until there is
if (res)
{
if (res->resultStatus != PGRES_FATAL_ERROR)
- printfPQExpBuffer(&conn->errorMessage,
+ appendPQExpBuffer(&conn->errorMessage,
libpq_gettext("unexpected message from server during startup\n"));
/*
@@ -1855,7 +1858,7 @@ keep_going: /* We will come back to here until there is
return PGRES_POLLING_OK;
default:
- printfPQExpBuffer(&conn->errorMessage,
+ appendPQExpBuffer(&conn->errorMessage,
libpq_gettext(
"invalid connection state %c, "
"probably indicative of memory corruption\n"
diff --git a/src/interfaces/libpq/fe-misc.c b/src/interfaces/libpq/fe-misc.c
index a7f9379d97..b21528f18e 100644
--- a/src/interfaces/libpq/fe-misc.c
+++ b/src/interfaces/libpq/fe-misc.c
@@ -106,14 +106,14 @@ pqPutc(char c, PGconn *conn)
/*
- * pqGets:
+ * pqGets[_append]:
* get a null-terminated string from the connection,
* and store it in an expansible PQExpBuffer.
* If we run out of memory, all of the string is still read,
* but the excess characters are silently discarded.
*/
-int
-pqGets(PQExpBuffer buf, PGconn *conn)
+static int
+pqGets_internal(PQExpBuffer buf, PGconn *conn, bool resetbuffer)
{
/* Copy conn data to locals for faster search loop */
char *inBuffer = conn->inBuffer;
@@ -129,7 +129,9 @@ pqGets(PQExpBuffer buf, PGconn *conn)
slen = inCursor - conn->inCursor;
- resetPQExpBuffer(buf);
+ if (resetbuffer)
+ resetPQExpBuffer(buf);
+
appendBinaryPQExpBuffer(buf, inBuffer + conn->inCursor, slen);
conn->inCursor = ++inCursor;
@@ -141,6 +143,18 @@ pqGets(PQExpBuffer buf, PGconn *conn)
return 0;
}
+int
+pqGets(PQExpBuffer buf, PGconn *conn)
+{
+ return pqGets_internal(buf, conn, true);
+}
+
+int
+pqGets_append(PQExpBuffer buf, PGconn *conn)
+{
+ return pqGets_internal(buf, conn, false);
+}
+
/*
* pqPuts: write a null-terminated string to the current message
diff --git a/src/interfaces/libpq/fe-protocol3.c b/src/interfaces/libpq/fe-protocol3.c
index c07a827a1a..63702066d0 100644
--- a/src/interfaces/libpq/fe-protocol3.c
+++ b/src/interfaces/libpq/fe-protocol3.c
@@ -853,7 +853,6 @@ pqGetErrorNotice3(PGconn *conn, bool isError)
goto fail;
pqClearAsyncResult(conn);
conn->result = res;
- resetPQExpBuffer(&conn->errorMessage);
appendPQExpBufferStr(&conn->errorMessage, workBuf.data);
}
else
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index e5d21b39a2..272d3b1dc7 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -519,6 +519,7 @@ extern int pqCheckInBufferSpace(size_t bytes_needed, PGconn *conn);
extern int pqGetc(char *result, PGconn *conn);
extern int pqPutc(char c, PGconn *conn);
extern int pqGets(PQExpBuffer buf, PGconn *conn);
+extern int pqGets_append(PQExpBuffer buf, PGconn *conn);
extern int pqPuts(const char *s, PGconn *conn);
extern int pqGetnchar(char *s, size_t len, PGconn *conn);
extern int pqPutnchar(const char *s, size_t len, PGconn *conn);