Tom Lane wrote:
> Magnus Hagander <magnus@hagander.net> writes:
>> Here's an ugly attempt towards this. Though I'm unsure if we can change
>> the "const" on the PQerrorMessage parameter without messing with library
>> versions and such?
>
> That's a bad idea in any case --- PQerrorMessage shouldn't be changing
> the state of anything. The merging needs to happen earlier.
That was my general thought, but since I'd written it, I just threw it
out there..
>> Another option could be to change all the calls that set the error
>> message to *append* to the error message instead. Thoughts on that?
>
> That might work ... but we'd probably have to add some "clear the
> message" calls in places. It might be worth trying to restrict this
> convention to the connection-startup code.
How about something like this?
//Magnus
*** a/src/interfaces/libpq/fe-connect.c
--- b/src/interfaces/libpq/fe-connect.c
***************
*** 699,705 **** connectNoDelay(PGconn *conn)
{
char sebuf[256];
! printfPQExpBuffer(&conn->errorMessage,
libpq_gettext("could not set socket to TCP no delay mode: %s\n"),
SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf)));
return 0;
--- 699,705 ----
{
char sebuf[256];
! 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,735 **** connectFailureMessage(PGconn *conn, int errorno)
NULL, 0,
service, sizeof(service),
NI_NUMERICSERV);
! printfPQExpBuffer(&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"),
--- 729,735 ----
NULL, 0,
service, sizeof(service),
NI_NUMERICSERV);
! 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,745 **** connectFailureMessage(PGconn *conn, int errorno)
else
#endif /* HAVE_UNIX_SOCKETS */
{
! printfPQExpBuffer(&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"),
--- 739,745 ----
else
#endif /* HAVE_UNIX_SOCKETS */
{
! 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,839 **** connectDBStart(PGconn *conn)
if (ret || !addrs)
{
if (node)
! printfPQExpBuffer(&conn->errorMessage,
libpq_gettext("could not translate host name \"%s\" to address: %s\n"),
node, gai_strerror(ret));
else
! printfPQExpBuffer(&conn->errorMessage,
libpq_gettext("could not translate Unix-domain socket path \"%s\" to address: %s\n"),
portstr, gai_strerror(ret));
if (addrs)
--- 829,839 ----
if (ret || !addrs)
{
if (node)
! appendPQExpBuffer(&conn->errorMessage,
libpq_gettext("could not translate host name \"%s\" to address: %s\n"),
node, gai_strerror(ret));
else
! appendPQExpBuffer(&conn->errorMessage,
libpq_gettext("could not translate Unix-domain socket path \"%s\" to address: %s\n"),
portstr, gai_strerror(ret));
if (addrs)
***************
*** 924,929 **** connectDBComplete(PGconn *conn)
--- 924,931 ----
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,1039 **** PQconnectPoll(PGconn *conn)
break;
default:
! printfPQExpBuffer(&conn->errorMessage,
libpq_gettext(
"invalid connection state, "
"probably indicative of memory corruption\n"
--- 1035,1041 ----
break;
default:
! appendPQExpBuffer(&conn->errorMessage,
libpq_gettext(
"invalid connection state, "
"probably indicative of memory corruption\n"
***************
*** 1077,1083 **** keep_going: /* We will come back to here until there is
conn->addr_cur = addr_cur->ai_next;
continue;
}
! printfPQExpBuffer(&conn->errorMessage,
libpq_gettext("could not create socket: %s\n"),
SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf)));
break;
--- 1079,1085 ----
conn->addr_cur = addr_cur->ai_next;
continue;
}
! appendPQExpBuffer(&conn->errorMessage,
libpq_gettext("could not create socket: %s\n"),
SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf)));
break;
***************
*** 1100,1106 **** keep_going: /* We will come back to here until there is
}
if (!pg_set_noblock(conn->sock))
{
! printfPQExpBuffer(&conn->errorMessage,
libpq_gettext("could not set socket to non-blocking mode: %s\n"),
SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf)));
closesocket(conn->sock);
--- 1102,1108 ----
}
if (!pg_set_noblock(conn->sock))
{
! 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,1118 **** 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,
libpq_gettext("could not set socket to close-on-exec mode: %s\n"),
SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf)));
closesocket(conn->sock);
--- 1114,1120 ----
#ifdef F_SETFD
if (fcntl(conn->sock, F_SETFD, FD_CLOEXEC) == -1)
{
! 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,1205 **** 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,
libpq_gettext("could not get socket error status: %s\n"),
SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf)));
goto error_return;
--- 1201,1207 ----
if (getsockopt(conn->sock, SOL_SOCKET, SO_ERROR,
(char *) &optval, &optlen) == -1)
{
! appendPQExpBuffer(&conn->errorMessage,
libpq_gettext("could not get socket error status: %s\n"),
SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf)));
goto error_return;
***************
*** 1237,1243 **** keep_going: /* We will come back to here until there is
(struct sockaddr *) & conn->laddr.addr,
&conn->laddr.salen) < 0)
{
! printfPQExpBuffer(&conn->errorMessage,
libpq_gettext("could not get client address from socket: %s\n"),
SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf)));
goto error_return;
--- 1239,1245 ----
(struct sockaddr *) & conn->laddr.addr,
&conn->laddr.salen) < 0)
{
! 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,1287 **** 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,
libpq_gettext("could not send SSL negotiation packet: %s\n"),
SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf)));
goto error_return;
--- 1283,1289 ----
pv = htonl(NEGOTIATE_SSL_CODE);
if (pqPacketSend(conn, 0, &pv, sizeof(pv)) != STATUS_OK)
{
! appendPQExpBuffer(&conn->errorMessage,
libpq_gettext("could not send SSL negotiation packet: %s\n"),
SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf)));
goto error_return;
***************
*** 1303,1308 **** keep_going: /* We will come back to here until there is
--- 1305,1311 ----
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,1322 **** keep_going: /* We will come back to here until there is
*/
if (pqPacketSend(conn, 0, startpacket, packetlen) != STATUS_OK)
{
! printfPQExpBuffer(&conn->errorMessage,
libpq_gettext("could not send startup packet: %s\n"),
SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf)));
free(startpacket);
--- 1319,1325 ----
*/
if (pqPacketSend(conn, 0, startpacket, packetlen) != STATUS_OK)
{
! appendPQExpBuffer(&conn->errorMessage,
libpq_gettext("could not send startup packet: %s\n"),
SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf)));
free(startpacket);
***************
*** 1381,1387 **** 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,
libpq_gettext("server does not support SSL, but SSL was required\n"));
goto error_return;
}
--- 1384,1390 ----
if (conn->sslmode[0] == 'r') /* "require" */
{
/* Require SSL, but server does not want it */
! appendPQExpBuffer(&conn->errorMessage,
libpq_gettext("server does not support SSL, but SSL was required\n"));
goto error_return;
}
***************
*** 1398,1404 **** 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,
libpq_gettext("server does not support SSL, but SSL was required\n"));
goto error_return;
}
--- 1401,1407 ----
if (conn->sslmode[0] == 'r') /* "require" */
{
/* Require SSL, but server is too old */
! appendPQExpBuffer(&conn->errorMessage,
libpq_gettext("server does not support SSL, but SSL was required\n"));
goto error_return;
}
***************
*** 1414,1420 **** keep_going: /* We will come back to here until there is
}
else
{
! printfPQExpBuffer(&conn->errorMessage,
libpq_gettext("received invalid response to SSL negotiation: %c\n"),
SSLok);
goto error_return;
--- 1417,1423 ----
}
else
{
! appendPQExpBuffer(&conn->errorMessage,
libpq_gettext("received invalid response to SSL negotiation: %c\n"),
SSLok);
goto error_return;
***************
*** 1489,1495 **** keep_going: /* We will come back to here until there is
*/
if (!(beresp == 'R' || beresp == 'E'))
{
! printfPQExpBuffer(&conn->errorMessage,
libpq_gettext(
"expected authentication request from "
"server, but received %c\n"),
--- 1492,1498 ----
*/
if (!(beresp == 'R' || beresp == 'E'))
{
! appendPQExpBuffer(&conn->errorMessage,
libpq_gettext(
"expected authentication request from "
"server, but received %c\n"),
***************
*** 1522,1528 **** keep_going: /* We will come back to here until there is
*/
if (beresp == 'R' && (msgLength < 8 || msgLength > 2000))
{
! printfPQExpBuffer(&conn->errorMessage,
libpq_gettext(
"expected authentication request from "
"server, but received %c\n"),
--- 1525,1531 ----
*/
if (beresp == 'R' && (msgLength < 8 || msgLength > 2000))
{
! appendPQExpBuffer(&conn->errorMessage,
libpq_gettext(
"expected authentication request from "
"server, but received %c\n"),
***************
*** 1534,1540 **** 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))
{
/* We'll come back when there is more data */
return PGRES_POLLING_READING;
--- 1537,1543 ----
{
/* Handle error from a pre-3.0 server */
conn->inCursor = conn->inStart + 1; /* reread data */
! if (pqGets_append(&conn->errorMessage, conn))
{
/* We'll come back when there is more data */
return PGRES_POLLING_READING;
***************
*** 1601,1607 **** keep_going: /* We will come back to here until there is
}
else
{
! if (pqGets(&conn->errorMessage, conn))
{
/* We'll come back when there is more data */
return PGRES_POLLING_READING;
--- 1604,1610 ----
}
else
{
! if (pqGets_append(&conn->errorMessage, conn))
{
/* We'll come back when there is more data */
return PGRES_POLLING_READING;
***************
*** 1788,1794 **** keep_going: /* We will come back to here until there is
if (res)
{
if (res->resultStatus != PGRES_FATAL_ERROR)
! printfPQExpBuffer(&conn->errorMessage,
libpq_gettext("unexpected message from server during startup\n"));
/*
--- 1791,1797 ----
if (res)
{
if (res->resultStatus != PGRES_FATAL_ERROR)
! appendPQExpBuffer(&conn->errorMessage,
libpq_gettext("unexpected message from server during startup\n"));
/*
***************
*** 1855,1861 **** keep_going: /* We will come back to here until there is
return PGRES_POLLING_OK;
default:
! printfPQExpBuffer(&conn->errorMessage,
libpq_gettext(
"invalid connection state %c, "
"probably indicative of memory corruption\n"
--- 1858,1864 ----
return PGRES_POLLING_OK;
default:
! appendPQExpBuffer(&conn->errorMessage,
libpq_gettext(
"invalid connection state %c, "
"probably indicative of memory corruption\n"
*** a/src/interfaces/libpq/fe-misc.c
--- b/src/interfaces/libpq/fe-misc.c
***************
*** 106,119 **** pqPutc(char c, PGconn *conn)
/*
! * pqGets:
* 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)
{
/* Copy conn data to locals for faster search loop */
char *inBuffer = conn->inBuffer;
--- 106,119 ----
/*
! * 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.
*/
! static int
! pqGets_internal(PQExpBuffer buf, PGconn *conn, bool resetbuffer)
{
/* Copy conn data to locals for faster search loop */
char *inBuffer = conn->inBuffer;
***************
*** 129,135 **** pqGets(PQExpBuffer buf, PGconn *conn)
slen = inCursor - conn->inCursor;
! resetPQExpBuffer(buf);
appendBinaryPQExpBuffer(buf, inBuffer + conn->inCursor, slen);
conn->inCursor = ++inCursor;
--- 129,137 ----
slen = inCursor - conn->inCursor;
! if (resetbuffer)
! resetPQExpBuffer(buf);
!
appendBinaryPQExpBuffer(buf, inBuffer + conn->inCursor, slen);
conn->inCursor = ++inCursor;
***************
*** 141,146 **** pqGets(PQExpBuffer buf, PGconn *conn)
--- 143,160 ----
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
*** a/src/interfaces/libpq/fe-protocol3.c
--- b/src/interfaces/libpq/fe-protocol3.c
***************
*** 853,859 **** pqGetErrorNotice3(PGconn *conn, bool isError)
goto fail;
pqClearAsyncResult(conn);
conn->result = res;
- resetPQExpBuffer(&conn->errorMessage);
appendPQExpBufferStr(&conn->errorMessage, workBuf.data);
}
else
--- 853,858 ----
*** a/src/interfaces/libpq/libpq-int.h
--- b/src/interfaces/libpq/libpq-int.h
***************
*** 519,524 **** extern int pqCheckInBufferSpace(size_t bytes_needed, PGconn *conn);
--- 519,525 ----
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);