diff --git a/doc/src/sgml/libpq.sgml b/doc/src/sgml/libpq.sgml index 2e13e1daa4..0aa134f4cd 100644 --- a/doc/src/sgml/libpq.sgml +++ b/doc/src/sgml/libpq.sgml @@ -1,4 +1,4 @@ - + <application>libpq</application> - C Library @@ -1137,10 +1137,11 @@ PQconninfoOption *PQconninfoParse(const char *conninfo, char **errmsg); Nearly all libpq functions will set a message for PQerrorMessage if they fail. Note that by libpq convention, a nonempty - PQerrorMessage result will include a trailing - newline. The caller should not free the result directly. It will - be freed when the associated PGconn handle is passed - to PQfinish. The result string should not be + PQerrorMessage 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 + PGconn handle is passed to + PQfinish. The result string should not be expected to remain the same across operations on the PGconn structure. diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c index 54aa710397..c611c0de1c 100644 --- a/src/interfaces/libpq/fe-connect.c +++ b/src/interfaces/libpq/fe-connect.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/interfaces/libpq/fe-connect.c,v 1.363 2008/10/23 16:17:19 mha Exp $ + * $PostgreSQL: pgsql/src/interfaces/libpq/fe-connect.c,v 1.364 2008/10/27 09:42:31 mha Exp $ * *------------------------------------------------------------------------- */ @@ -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 cc3e758ef2..691262cf8a 100644 --- a/src/interfaces/libpq/fe-misc.c +++ b/src/interfaces/libpq/fe-misc.c @@ -23,7 +23,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $PostgreSQL: pgsql/src/interfaces/libpq/fe-misc.c,v 1.135 2008/08/20 11:53:45 mha Exp $ + * $PostgreSQL: pgsql/src/interfaces/libpq/fe-misc.c,v 1.136 2008/10/27 09:42:31 mha Exp $ * *------------------------------------------------------------------------- */ @@ -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 66059493bb..ba2798234f 100644 --- a/src/interfaces/libpq/fe-protocol3.c +++ b/src/interfaces/libpq/fe-protocol3.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/interfaces/libpq/fe-protocol3.c,v 1.35 2008/05/29 22:02:44 tgl Exp $ + * $PostgreSQL: pgsql/src/interfaces/libpq/fe-protocol3.c,v 1.36 2008/10/27 09:42:31 mha Exp $ * *------------------------------------------------------------------------- */ @@ -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 9702c61682..8525fb15f0 100644 --- a/src/interfaces/libpq/libpq-int.h +++ b/src/interfaces/libpq/libpq-int.h @@ -12,7 +12,7 @@ * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/interfaces/libpq/libpq-int.h,v 1.134 2008/09/22 14:21:44 tgl Exp $ + * $PostgreSQL: pgsql/src/interfaces/libpq/libpq-int.h,v 1.135 2008/10/27 09:42:31 mha Exp $ * *------------------------------------------------------------------------- */ @@ -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);