]> granicus.if.org Git - postgresql/blobdiff - src/interfaces/libpq/fe-misc.c
Make the order of the header file includes consistent in non-backend modules.
[postgresql] / src / interfaces / libpq / fe-misc.c
index f4ae2ca2d936a5f9c240fb771e63d347b2b58785..a7c08c5c88a4b4329466ddc39f509b3551bab90e 100644 (file)
@@ -7,7 +7,7 @@
  *              miscellaneous useful functions
  *
  * The communication routines here are analogous to the ones in
- * backend/libpq/pqcomm.c and backend/libpq/pqcomprim.c, but operate
+ * backend/libpq/pqcomm.c and backend/libpq/pqformat.c, but operate
  * in the considerably different environment of the frontend libpq.
  * In particular, we work with a bare nonblock-mode socket, rather than
  * a stdio stream, so that we can avoid unwanted blocking of the application.
  * routines.
  *
  *
- * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/interfaces/libpq/fe-misc.c,v 1.118 2005/08/23 20:48:47 momjian Exp $
+ *       src/interfaces/libpq/fe-misc.c
  *
  *-------------------------------------------------------------------------
  */
 
 #include "postgres_fe.h"
 
-#include <errno.h>
 #include <signal.h>
 #include <time.h>
 
-#ifndef WIN32_CLIENT_ONLY
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#endif
-
 #ifdef WIN32
 #include "win32.h"
 #else
 #ifdef HAVE_POLL_H
 #include <poll.h>
 #endif
-#ifdef HAVE_SYS_POLL_H
-#include <sys/poll.h>
-#endif
 #ifdef HAVE_SYS_SELECT_H
 #include <sys/select.h>
 #endif
 
 #include "libpq-fe.h"
 #include "libpq-int.h"
-#include "pqsignal.h"
 #include "mb/pg_wchar.h"
-
+#include "pg_config_paths.h"
+#include "port/pg_bswap.h"
 
 static int     pqPutMsgBytes(const void *buf, size_t len, PGconn *conn);
 static int     pqSendSome(PGconn *conn, int len);
-static int pqSocketCheck(PGconn *conn, int forRead, int forWrite,
-                         time_t end_time);
+static int     pqSocketCheck(PGconn *conn, int forRead, int forWrite,
+                                                 time_t end_time);
 static int     pqSocketPoll(int sock, int forRead, int forWrite, time_t end_time);
 
+/*
+ * PQlibVersion: return the libpq version number
+ */
+int
+PQlibVersion(void)
+{
+       return PG_VERSION_NUM;
+}
+
+/*
+ * fputnbytes: print exactly N bytes to a file
+ *
+ * We avoid using %.*s here because it can misbehave if the data
+ * is not valid in what libc thinks is the prevailing encoding.
+ */
+static void
+fputnbytes(FILE *f, const char *str, size_t n)
+{
+       while (n-- > 0)
+               fputc(*str++, f);
+}
+
 
 /*
  * pqGetc: get 1 character from the connection
@@ -85,7 +98,7 @@ pqGetc(char *result, PGconn *conn)
        *result = conn->inBuffer[conn->inCursor++];
 
        if (conn->Pfdebug)
-               fprintf(conn->Pfdebug, libpq_gettext("From backend> %c\n"), *result);
+               fprintf(conn->Pfdebug, "From backend> %c\n", *result);
 
        return 0;
 }
@@ -101,21 +114,21 @@ pqPutc(char c, PGconn *conn)
                return EOF;
 
        if (conn->Pfdebug)
-               fprintf(conn->Pfdebug, libpq_gettext("To backend> %c\n"), c);
+               fprintf(conn->Pfdebug, "To backend> %c\n", c);
 
        return 0;
 }
 
 
 /*
- * 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;
@@ -131,18 +144,32 @@ pqGets(PQExpBuffer buf, PGconn *conn)
 
        slen = inCursor - conn->inCursor;
 
-       resetPQExpBuffer(buf);
+       if (resetbuffer)
+               resetPQExpBuffer(buf);
+
        appendBinaryPQExpBuffer(buf, inBuffer + conn->inCursor, slen);
 
        conn->inCursor = ++inCursor;
 
        if (conn->Pfdebug)
-               fprintf(conn->Pfdebug, libpq_gettext("From backend> \"%s\"\n"),
+               fprintf(conn->Pfdebug, "From backend> \"%s\"\n",
                                buf->data);
 
        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
@@ -154,7 +181,7 @@ pqPuts(const char *s, PGconn *conn)
                return EOF;
 
        if (conn->Pfdebug)
-               fprintf(conn->Pfdebug, libpq_gettext("To backend> '%s'\n"), s);
+               fprintf(conn->Pfdebug, "To backend> \"%s\"\n", s);
 
        return 0;
 }
@@ -166,7 +193,7 @@ pqPuts(const char *s, PGconn *conn)
 int
 pqGetnchar(char *s, size_t len, PGconn *conn)
 {
-       if (len < 0 || len > (size_t) (conn->inEnd - conn->inCursor))
+       if (len > (size_t) (conn->inEnd - conn->inCursor))
                return EOF;
 
        memcpy(s, conn->inBuffer + conn->inCursor, len);
@@ -175,8 +202,37 @@ pqGetnchar(char *s, size_t len, PGconn *conn)
        conn->inCursor += len;
 
        if (conn->Pfdebug)
-               fprintf(conn->Pfdebug, libpq_gettext("From backend (%lu)> %.*s\n"),
-                               (unsigned long) len, (int) len, s);
+       {
+               fprintf(conn->Pfdebug, "From backend (%lu)> ", (unsigned long) len);
+               fputnbytes(conn->Pfdebug, s, len);
+               fprintf(conn->Pfdebug, "\n");
+       }
+
+       return 0;
+}
+
+/*
+ * pqSkipnchar:
+ *     skip over len bytes in input buffer.
+ *
+ * Note: this is primarily useful for its debug output, which should
+ * be exactly the same as for pqGetnchar.  We assume the data in question
+ * will actually be used, but just isn't getting copied anywhere as yet.
+ */
+int
+pqSkipnchar(size_t len, PGconn *conn)
+{
+       if (len > (size_t) (conn->inEnd - conn->inCursor))
+               return EOF;
+
+       if (conn->Pfdebug)
+       {
+               fprintf(conn->Pfdebug, "From backend (%lu)> ", (unsigned long) len);
+               fputnbytes(conn->Pfdebug, conn->inBuffer + conn->inCursor, len);
+               fprintf(conn->Pfdebug, "\n");
+       }
+
+       conn->inCursor += len;
 
        return 0;
 }
@@ -192,7 +248,11 @@ pqPutnchar(const char *s, size_t len, PGconn *conn)
                return EOF;
 
        if (conn->Pfdebug)
-               fprintf(conn->Pfdebug, libpq_gettext("To backend> %.*s\n"), (int) len, s);
+       {
+               fprintf(conn->Pfdebug, "To backend> ");
+               fputnbytes(conn->Pfdebug, s, len);
+               fprintf(conn->Pfdebug, "\n");
+       }
 
        return 0;
 }
@@ -215,24 +275,24 @@ pqGetInt(int *result, size_t bytes, PGconn *conn)
                                return EOF;
                        memcpy(&tmp2, conn->inBuffer + conn->inCursor, 2);
                        conn->inCursor += 2;
-                       *result = (int) ntohs(tmp2);
+                       *result = (int) pg_ntoh16(tmp2);
                        break;
                case 4:
                        if (conn->inCursor + 4 > conn->inEnd)
                                return EOF;
                        memcpy(&tmp4, conn->inBuffer + conn->inCursor, 4);
                        conn->inCursor += 4;
-                       *result = (int) ntohl(tmp4);
+                       *result = (int) pg_ntoh32(tmp4);
                        break;
                default:
                        pqInternalNotice(&conn->noticeHooks,
-                                                "integer of size %lu not supported by pqGetInt",
+                                                        "integer of size %lu not supported by pqGetInt",
                                                         (unsigned long) bytes);
                        return EOF;
        }
 
        if (conn->Pfdebug)
-               fprintf(conn->Pfdebug, libpq_gettext("From backend (#%lu)> %d\n"), (unsigned long) bytes, *result);
+               fprintf(conn->Pfdebug, "From backend (#%lu)> %d\n", (unsigned long) bytes, *result);
 
        return 0;
 }
@@ -251,24 +311,24 @@ pqPutInt(int value, size_t bytes, PGconn *conn)
        switch (bytes)
        {
                case 2:
-                       tmp2 = htons((uint16) value);
+                       tmp2 = pg_hton16((uint16) value);
                        if (pqPutMsgBytes((const char *) &tmp2, 2, conn))
                                return EOF;
                        break;
                case 4:
-                       tmp4 = htonl((uint32) value);
+                       tmp4 = pg_hton32((uint32) value);
                        if (pqPutMsgBytes((const char *) &tmp4, 4, conn))
                                return EOF;
                        break;
                default:
                        pqInternalNotice(&conn->noticeHooks,
-                                                "integer of size %lu not supported by pqPutInt",
+                                                        "integer of size %lu not supported by pqPutInt",
                                                         (unsigned long) bytes);
                        return EOF;
        }
 
        if (conn->Pfdebug)
-               fprintf(conn->Pfdebug, libpq_gettext("To backend (%lu#)> %d\n"), (unsigned long) bytes, value);
+               fprintf(conn->Pfdebug, "To backend (%lu#)> %d\n", (unsigned long) bytes, value);
 
        return 0;
 }
@@ -280,27 +340,28 @@ pqPutInt(int value, size_t bytes, PGconn *conn)
  * Returns 0 on success, EOF if failed to enlarge buffer
  */
 int
-pqCheckOutBufferSpace(int bytes_needed, PGconn *conn)
+pqCheckOutBufferSpace(size_t bytes_needed, PGconn *conn)
 {
        int                     newsize = conn->outBufSize;
        char       *newbuf;
 
-       if (bytes_needed <= newsize)
+       /* Quick exit if we have enough space */
+       if (bytes_needed <= (size_t) newsize)
                return 0;
 
        /*
-        * If we need to enlarge the buffer, we first try to double it in
-        * size; if that doesn't work, enlarge in multiples of 8K.  This
-        * avoids thrashing the malloc pool by repeated small enlargements.
+        * If we need to enlarge the buffer, we first try to double it in size; if
+        * that doesn't work, enlarge in multiples of 8K.  This avoids thrashing
+        * the malloc pool by repeated small enlargements.
         *
         * Note: tests for newsize > 0 are to catch integer overflow.
         */
        do
        {
                newsize *= 2;
-       } while (bytes_needed > newsize && newsize > 0);
+       } while (newsize > 0 && bytes_needed > (size_t) newsize);
 
-       if (bytes_needed <= newsize)
+       if (newsize > 0 && bytes_needed <= (size_t) newsize)
        {
                newbuf = realloc(conn->outBuffer, newsize);
                if (newbuf)
@@ -316,9 +377,9 @@ pqCheckOutBufferSpace(int bytes_needed, PGconn *conn)
        do
        {
                newsize += 8192;
-       } while (bytes_needed > newsize && newsize > 0);
+       } while (newsize > 0 && bytes_needed > (size_t) newsize);
 
-       if (bytes_needed <= newsize)
+       if (newsize > 0 && bytes_needed <= (size_t) newsize)
        {
                newbuf = realloc(conn->outBuffer, newsize);
                if (newbuf)
@@ -343,27 +404,58 @@ pqCheckOutBufferSpace(int bytes_needed, PGconn *conn)
  * Returns 0 on success, EOF if failed to enlarge buffer
  */
 int
-pqCheckInBufferSpace(int bytes_needed, PGconn *conn)
+pqCheckInBufferSpace(size_t bytes_needed, PGconn *conn)
 {
        int                     newsize = conn->inBufSize;
        char       *newbuf;
 
-       if (bytes_needed <= newsize)
+       /* Quick exit if we have enough space */
+       if (bytes_needed <= (size_t) newsize)
                return 0;
 
        /*
-        * If we need to enlarge the buffer, we first try to double it in
-        * size; if that doesn't work, enlarge in multiples of 8K.  This
-        * avoids thrashing the malloc pool by repeated small enlargements.
+        * Before concluding that we need to enlarge the buffer, left-justify
+        * whatever is in it and recheck.  The caller's value of bytes_needed
+        * includes any data to the left of inStart, but we can delete that in
+        * preference to enlarging the buffer.  It's slightly ugly to have this
+        * function do this, but it's better than making callers worry about it.
+        */
+       bytes_needed -= conn->inStart;
+
+       if (conn->inStart < conn->inEnd)
+       {
+               if (conn->inStart > 0)
+               {
+                       memmove(conn->inBuffer, conn->inBuffer + conn->inStart,
+                                       conn->inEnd - conn->inStart);
+                       conn->inEnd -= conn->inStart;
+                       conn->inCursor -= conn->inStart;
+                       conn->inStart = 0;
+               }
+       }
+       else
+       {
+               /* buffer is logically empty, reset it */
+               conn->inStart = conn->inCursor = conn->inEnd = 0;
+       }
+
+       /* Recheck whether we have enough space */
+       if (bytes_needed <= (size_t) newsize)
+               return 0;
+
+       /*
+        * If we need to enlarge the buffer, we first try to double it in size; if
+        * that doesn't work, enlarge in multiples of 8K.  This avoids thrashing
+        * the malloc pool by repeated small enlargements.
         *
         * Note: tests for newsize > 0 are to catch integer overflow.
         */
        do
        {
                newsize *= 2;
-       } while (bytes_needed > newsize && newsize > 0);
+       } while (newsize > 0 && bytes_needed > (size_t) newsize);
 
-       if (bytes_needed <= newsize)
+       if (newsize > 0 && bytes_needed <= (size_t) newsize)
        {
                newbuf = realloc(conn->inBuffer, newsize);
                if (newbuf)
@@ -379,9 +471,9 @@ pqCheckInBufferSpace(int bytes_needed, PGconn *conn)
        do
        {
                newsize += 8192;
-       } while (bytes_needed > newsize && newsize > 0);
+       } while (newsize > 0 && bytes_needed > (size_t) newsize);
 
-       if (bytes_needed <= newsize)
+       if (newsize > 0 && bytes_needed <= (size_t) newsize)
        {
                newbuf = realloc(conn->inBuffer, newsize);
                if (newbuf)
@@ -456,7 +548,7 @@ pqPutMsgStart(char msg_type, bool force_len, PGconn *conn)
        /* length word, if needed, will be filled in by pqPutMsgEnd */
 
        if (conn->Pfdebug)
-               fprintf(conn->Pfdebug, libpq_gettext("To backend> Msg %c\n"),
+               fprintf(conn->Pfdebug, "To backend> Msg %c\n",
                                msg_type ? msg_type : ' ');
 
        return 0;
@@ -494,7 +586,7 @@ int
 pqPutMsgEnd(PGconn *conn)
 {
        if (conn->Pfdebug)
-               fprintf(conn->Pfdebug, libpq_gettext("To backend> Msg complete, length %u\n"),
+               fprintf(conn->Pfdebug, "To backend> Msg complete, length %u\n",
                                conn->outMsgEnd - conn->outCount);
 
        /* Fill in length word if needed */
@@ -502,7 +594,7 @@ pqPutMsgEnd(PGconn *conn)
        {
                uint32          msgLen = conn->outMsgEnd - conn->outMsgStart;
 
-               msgLen = htonl(msgLen);
+               msgLen = pg_hton32(msgLen);
                memcpy(conn->outBuffer + conn->outMsgStart, &msgLen, 4);
        }
 
@@ -537,9 +629,8 @@ pqReadData(PGconn *conn)
 {
        int                     someread = 0;
        int                     nread;
-       char            sebuf[256];
 
-       if (conn->sock < 0)
+       if (conn->sock == PGINVALID_SOCKET)
        {
                printfPQExpBuffer(&conn->errorMessage,
                                                  libpq_gettext("connection not open\n"));
@@ -565,20 +656,19 @@ pqReadData(PGconn *conn)
        }
 
        /*
-        * If the buffer is fairly full, enlarge it. We need to be able to
-        * enlarge the buffer in case a single message exceeds the initial
-        * buffer size.  We enlarge before filling the buffer entirely so as
-        * to avoid asking the kernel for a partial packet. The magic constant
-        * here should be large enough for a TCP packet or Unix pipe
-        * bufferload.  8K is the usual pipe buffer size, so...
+        * If the buffer is fairly full, enlarge it. We need to be able to enlarge
+        * the buffer in case a single message exceeds the initial buffer size. We
+        * enlarge before filling the buffer entirely so as to avoid asking the
+        * kernel for a partial packet. The magic constant here should be large
+        * enough for a TCP packet or Unix pipe bufferload.  8K is the usual pipe
+        * buffer size, so...
         */
        if (conn->inBufSize - conn->inEnd < 8192)
        {
-               if (pqCheckInBufferSpace(conn->inEnd + 8192, conn))
+               if (pqCheckInBufferSpace(conn->inEnd + (size_t) 8192, conn))
                {
                        /*
-                        * We don't insist that the enlarge worked, but we need some
-                        * room
+                        * We don't insist that the enlarge worked, but we need some room
                         */
                        if (conn->inBufSize - conn->inEnd < 100)
                                return -1;              /* errorMessage already set */
@@ -607,9 +697,7 @@ retry3:
                if (SOCK_ERRNO == ECONNRESET)
                        goto definitelyFailed;
 #endif
-               printfPQExpBuffer(&conn->errorMessage,
-                          libpq_gettext("could not receive data from server: %s\n"),
-                                               SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf)));
+               /* pqsecure_read set the error message for us */
                return -1;
        }
        if (nread > 0)
@@ -617,17 +705,16 @@ retry3:
                conn->inEnd += nread;
 
                /*
-                * Hack to deal with the fact that some kernels will only give us
-                * back 1 packet per recv() call, even if we asked for more and
-                * there is more available.  If it looks like we are reading a
-                * long message, loop back to recv() again immediately, until we
-                * run out of data or buffer space.  Without this, the
-                * block-and-restart behavior of libpq's higher levels leads to
-                * O(N^2) performance on long messages.
+                * Hack to deal with the fact that some kernels will only give us back
+                * 1 packet per recv() call, even if we asked for more and there is
+                * more available.  If it looks like we are reading a long message,
+                * loop back to recv() again immediately, until we run out of data or
+                * buffer space.  Without this, the block-and-restart behavior of
+                * libpq's higher levels leads to O(N^2) performance on long messages.
                 *
                 * Since we left-justified the data above, conn->inEnd gives the
-                * amount of data already read in the current message.  We
-                * consider the message "long" once we have acquired 32k ...
+                * amount of data already read in the current message.  We consider
+                * the message "long" once we have acquired 32k ...
                 */
                if (conn->inEnd > 32768 &&
                        (conn->inBufSize - conn->inEnd) >= 8192)
@@ -642,22 +729,23 @@ retry3:
                return 1;                               /* got a zero read after successful tries */
 
        /*
-        * A return value of 0 could mean just that no data is now available,
-        * or it could mean EOF --- that is, the server has closed the
-        * connection. Since we have the socket in nonblock mode, the only way
-        * to tell the difference is to see if select() is saying that the
-        * file is ready. Grumble.      Fortunately, we don't expect this path to
-        * be taken much, since in normal practice we should not be trying to
-        * read data unless the file selected for reading already.
+        * A return value of 0 could mean just that no data is now available, or
+        * it could mean EOF --- that is, the server has closed the connection.
+        * Since we have the socket in nonblock mode, the only way to tell the
+        * difference is to see if select() is saying that the file is ready.
+        * Grumble.  Fortunately, we don't expect this path to be taken much,
+        * since in normal practice we should not be trying to read data unless
+        * the file selected for reading already.
         *
         * In SSL mode it's even worse: SSL_read() could say WANT_READ and then
-        * data could arrive before we make the pqReadReady() test.  So we
-        * must play dumb and assume there is more data, relying on the SSL
-        * layer to detect true EOF.
+        * data could arrive before we make the pqReadReady() test, but the second
+        * SSL_read() could still say WANT_READ because the data received was not
+        * a complete SSL record.  So we must play dumb and assume there is more
+        * data, relying on the SSL layer to detect true EOF.
         */
 
 #ifdef USE_SSL
-       if (conn->ssl)
+       if (conn->ssl_in_use)
                return 0;
 #endif
 
@@ -670,7 +758,8 @@ retry3:
                        /* ready for read */
                        break;
                default:
-                       goto definitelyFailed;
+                       /* we override pqReadReady's message with something more useful */
+                       goto definitelyEOF;
        }
 
        /*
@@ -698,9 +787,7 @@ retry4:
                if (SOCK_ERRNO == ECONNRESET)
                        goto definitelyFailed;
 #endif
-               printfPQExpBuffer(&conn->errorMessage,
-                          libpq_gettext("could not receive data from server: %s\n"),
-                                               SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf)));
+               /* pqsecure_read set the error message for us */
                return -1;
        }
        if (nread > 0)
@@ -710,20 +797,21 @@ retry4:
        }
 
        /*
-        * OK, we are getting a zero read even though select() says ready.
-        * This means the connection has been closed.  Cope.
+        * OK, we are getting a zero read even though select() says ready. This
+        * means the connection has been closed.  Cope.
         */
-definitelyFailed:
+definitelyEOF:
        printfPQExpBuffer(&conn->errorMessage,
                                          libpq_gettext(
-                                                       "server closed the connection unexpectedly\n"
-                          "\tThis probably means the server terminated abnormally\n"
-                                                "\tbefore or while processing the request.\n"));
-       conn->status = CONNECTION_BAD;          /* No more connection to backend */
-       pqsecure_close(conn);
-       closesocket(conn->sock);
-       conn->sock = -1;
+                                                                       "server closed the connection unexpectedly\n"
+                                                                       "\tThis probably means the server terminated abnormally\n"
+                                                                       "\tbefore or while processing the request.\n"));
 
+       /* Come here if lower-level code already set a suitable errorMessage */
+definitelyFailed:
+       /* Do *not* drop any already-read data; caller still wants it */
+       pqDropConnection(conn, false);
+       conn->status = CONNECTION_BAD;  /* No more connection to backend */
        return -1;
 }
 
@@ -735,6 +823,13 @@ definitelyFailed:
  *
  * Return 0 on success, -1 on failure and 1 when not all data could be sent
  * because the socket would block and the connection is non-blocking.
+ *
+ * Upon write failure, conn->write_failed is set and the error message is
+ * saved in conn->write_err_msg, but we clear the output buffer and return
+ * zero anyway; this is because callers should soldier on until it's possible
+ * to read from the server and check for an error message.  write_err_msg
+ * should be reported only when we are unable to obtain a server error first.
+ * (Thus, a -1 result is returned only for an internal *read* failure.)
  */
 static int
 pqSendSome(PGconn *conn, int len)
@@ -743,28 +838,54 @@ pqSendSome(PGconn *conn, int len)
        int                     remaining = conn->outCount;
        int                     result = 0;
 
-       if (conn->sock < 0)
+       /*
+        * If we already had a write failure, we will never again try to send data
+        * on that connection.  Even if the kernel would let us, we've probably
+        * lost message boundary sync with the server.  conn->write_failed
+        * therefore persists until the connection is reset, and we just discard
+        * all data presented to be written.
+        */
+       if (conn->write_failed)
+       {
+               /* conn->write_err_msg should be set up already */
+               conn->outCount = 0;
+               return 0;
+       }
+
+       if (conn->sock == PGINVALID_SOCKET)
        {
                printfPQExpBuffer(&conn->errorMessage,
                                                  libpq_gettext("connection not open\n"));
-               return -1;
+               conn->write_failed = true;
+               /* Transfer error message to conn->write_err_msg, if possible */
+               /* (strdup failure is OK, we'll cope later) */
+               conn->write_err_msg = strdup(conn->errorMessage.data);
+               resetPQExpBuffer(&conn->errorMessage);
+               /* Discard queued data; no chance it'll ever be sent */
+               conn->outCount = 0;
+               return 0;
        }
 
        /* while there's still data to send */
        while (len > 0)
        {
                int                     sent;
-               char            sebuf[256];
 
+#ifndef WIN32
                sent = pqsecure_write(conn, ptr, len);
+#else
+
+               /*
+                * Windows can fail on large sends, per KB article Q201213. The
+                * failure-point appears to be different in different versions of
+                * Windows, but 64k should always be safe.
+                */
+               sent = pqsecure_write(conn, ptr, Min(len, 65536));
+#endif
 
                if (sent < 0)
                {
-                       /*
-                        * Anything except EAGAIN/EWOULDBLOCK/EINTR is trouble. If
-                        * it's EPIPE or ECONNRESET, assume we've lost the backend
-                        * connection permanently.
-                        */
+                       /* Anything except EAGAIN/EWOULDBLOCK/EINTR is trouble */
                        switch (SOCK_ERRNO)
                        {
 #ifdef EAGAIN
@@ -778,34 +899,26 @@ pqSendSome(PGconn *conn, int len)
                                case EINTR:
                                        continue;
 
-                               case EPIPE:
-#ifdef ECONNRESET
-                               case ECONNRESET:
-#endif
-                                       printfPQExpBuffer(&conn->errorMessage,
-                                                                         libpq_gettext(
-                                                       "server closed the connection unexpectedly\n"
-                                                                                                       "\tThis probably means the server terminated abnormally\n"
-                                                "\tbefore or while processing the request.\n"));
+                               default:
+                                       /* pqsecure_write set the error message for us */
+                                       conn->write_failed = true;
 
                                        /*
-                                        * We used to close the socket here, but that's a bad
-                                        * idea since there might be unread data waiting
-                                        * (typically, a NOTICE message from the backend
-                                        * telling us it's committing hara-kiri...).  Leave
-                                        * the socket open until pqReadData finds no more data
-                                        * can be read.  But abandon attempt to send data.
+                                        * Transfer error message to conn->write_err_msg, if
+                                        * possible (strdup failure is OK, we'll cope later).
+                                        *
+                                        * Note: this assumes that pqsecure_write and its children
+                                        * will overwrite not append to conn->errorMessage.  If
+                                        * that's ever changed, we could remember the length of
+                                        * conn->errorMessage at entry to this routine, and then
+                                        * save and delete just what was appended.
                                         */
-                                       conn->outCount = 0;
-                                       return -1;
+                                       conn->write_err_msg = strdup(conn->errorMessage.data);
+                                       resetPQExpBuffer(&conn->errorMessage);
 
-                               default:
-                                       printfPQExpBuffer(&conn->errorMessage,
-                                       libpq_gettext("could not send data to server: %s\n"),
-                                               SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf)));
-                                       /* We don't assume it's a fatal error... */
+                                       /* Discard queued data; no chance it'll ever be sent */
                                        conn->outCount = 0;
-                                       return -1;
+                                       return 0;
                        }
                }
                else
@@ -820,34 +933,43 @@ pqSendSome(PGconn *conn, int len)
                        /*
                         * We didn't send it all, wait till we can send more.
                         *
-                        * If the connection is in non-blocking mode we don't wait, but
-                        * return 1 to indicate that data is still pending.
+                        * There are scenarios in which we can't send data because the
+                        * communications channel is full, but we cannot expect the server
+                        * to clear the channel eventually because it's blocked trying to
+                        * send data to us.  (This can happen when we are sending a large
+                        * amount of COPY data, and the server has generated lots of
+                        * NOTICE responses.)  To avoid a deadlock situation, we must be
+                        * prepared to accept and buffer incoming data before we try
+                        * again.  Furthermore, it is possible that such incoming data
+                        * might not arrive until after we've gone to sleep.  Therefore,
+                        * we wait for either read ready or write ready.
+                        *
+                        * In non-blocking mode, we don't wait here directly, but return 1
+                        * to indicate that data is still pending.  The caller should wait
+                        * for both read and write ready conditions, and call
+                        * PQconsumeInput() on read ready, but just in case it doesn't, we
+                        * call pqReadData() ourselves before returning.  That's not
+                        * enough if the data has not arrived yet, but it's the best we
+                        * can do, and works pretty well in practice.  (The documentation
+                        * used to say that you only need to wait for write-ready, so
+                        * there are still plenty of applications like that out there.)
+                        *
+                        * Note that errors here don't result in write_failed becoming
+                        * set.
                         */
-                       if (pqIsnonblocking(conn))
+                       if (pqReadData(conn) < 0)
                        {
-                               result = 1;
+                               result = -1;    /* error message already set up */
                                break;
                        }
 
-                       /*
-                        * There are scenarios in which we can't send data because the
-                        * communications channel is full, but we cannot expect the
-                        * server to clear the channel eventually because it's blocked
-                        * trying to send data to us.  (This can happen when we are
-                        * sending a large amount of COPY data, and the server has
-                        * generated lots of NOTICE responses.)  To avoid a deadlock
-                        * situation, we must be prepared to accept and buffer
-                        * incoming data before we try again.  Furthermore, it is
-                        * possible that such incoming data might not arrive until
-                        * after we've gone to sleep.  Therefore, we wait for either
-                        * read ready or write ready.
-                        */
-                       if (pqReadData(conn) < 0)
+                       if (pqIsnonblocking(conn))
                        {
-                               result = -1;    /* error message already set up */
+                               result = 1;
                                break;
                        }
-                       if (pqWait(TRUE, TRUE, conn))
+
+                       if (pqWait(true, true, conn))
                        {
                                result = -1;
                                break;
@@ -869,6 +991,7 @@ pqSendSome(PGconn *conn, int len)
  *
  * Return 0 on success, -1 on failure and 1 when not all data could be sent
  * because the socket would block and the connection is non-blocking.
+ * (See pqSendSome comments about how failure should be handled.)
  */
 int
 pqFlush(PGconn *conn)
@@ -902,11 +1025,9 @@ pqWait(int forRead, int forWrite, PGconn *conn)
 /*
  * pqWaitTimed: wait, but not past finish_time.
  *
- * If finish_time is exceeded then we return failure (EOF).  This is like
- * the response for a kernel exception because we don't want the caller
- * to try to read/write in that case.
- *
  * finish_time = ((time_t) -1) disables the wait limit.
+ *
+ * Returns -1 on failure, 0 if the socket is readable/writable, 1 if it timed out.
  */
 int
 pqWaitTimed(int forRead, int forWrite, PGconn *conn, time_t finish_time)
@@ -916,13 +1037,13 @@ pqWaitTimed(int forRead, int forWrite, PGconn *conn, time_t finish_time)
        result = pqSocketCheck(conn, forRead, forWrite, finish_time);
 
        if (result < 0)
-               return EOF;                             /* errorMessage is already set */
+               return -1;                              /* errorMessage is already set */
 
        if (result == 0)
        {
                printfPQExpBuffer(&conn->errorMessage,
                                                  libpq_gettext("timeout expired\n"));
-               return EOF;
+               return 1;
        }
 
        return 0;
@@ -963,16 +1084,16 @@ pqSocketCheck(PGconn *conn, int forRead, int forWrite, time_t end_time)
 
        if (!conn)
                return -1;
-       if (conn->sock < 0)
+       if (conn->sock == PGINVALID_SOCKET)
        {
                printfPQExpBuffer(&conn->errorMessage,
-                                                 libpq_gettext("socket not open\n"));
+                                                 libpq_gettext("invalid socket\n"));
                return -1;
        }
 
 #ifdef USE_SSL
        /* Check for SSL library buffering read bytes */
-       if (forRead && conn->ssl && SSL_pending(conn->ssl) > 0)
+       if (forRead && conn->ssl_in_use && pgtls_read_pending(conn))
        {
                /* short-circuit the select */
                return 1;
@@ -986,11 +1107,11 @@ pqSocketCheck(PGconn *conn, int forRead, int forWrite, time_t end_time)
 
        if (result < 0)
        {
-               char            sebuf[256];
+               char            sebuf[PG_STRERROR_R_BUFLEN];
 
                printfPQExpBuffer(&conn->errorMessage,
                                                  libpq_gettext("select() failed: %s\n"),
-                                               SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf)));
+                                                 SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf)));
        }
 
        return result;
@@ -1040,7 +1161,6 @@ pqSocketPoll(int sock, int forRead, int forWrite, time_t end_time)
        }
 
        return poll(&input_fd, 1, timeout_ms);
-
 #else                                                  /* !HAVE_POLL */
 
        fd_set          input_mask;
@@ -1057,6 +1177,7 @@ pqSocketPoll(int sock, int forRead, int forWrite, time_t end_time)
        FD_ZERO(&except_mask);
        if (forRead)
                FD_SET(sock, &input_mask);
+
        if (forWrite)
                FD_SET(sock, &output_mask);
        FD_SET(sock, &except_mask);
@@ -1078,7 +1199,7 @@ pqSocketPoll(int sock, int forRead, int forWrite, time_t end_time)
 
        return select(sock + 1, &input_mask, &output_mask,
                                  &except_mask, ptr_timeout);
-#endif   /* HAVE_POLL */
+#endif                                                 /* HAVE_POLL */
 }
 
 
@@ -1088,23 +1209,23 @@ pqSocketPoll(int sock, int forRead, int forWrite, time_t end_time)
  */
 
 /*
- * returns the byte length of the word beginning s, using the
+ * returns the byte length of the character beginning at s, using the
  * specified encoding.
  */
 int
-PQmblen(const unsigned char *s, int encoding)
+PQmblen(const char *s, int encoding)
 {
-       return (pg_encoding_mblen(encoding, s));
+       return pg_encoding_mblen(encoding, s);
 }
 
 /*
- * returns the display length of the word beginning s, using the
+ * returns the display length of the character beginning at s, using the
  * specified encoding.
  */
 int
-PQdsplen(const unsigned char *s, int encoding)
+PQdsplen(const char *s, int encoding)
 {
-       return (pg_encoding_dsplen(encoding, s));
+       return pg_encoding_dsplen(encoding, s);
 }
 
 /*
@@ -1118,22 +1239,30 @@ PQenv2encoding(void)
 
        str = getenv("PGCLIENTENCODING");
        if (str && *str != '\0')
+       {
                encoding = pg_char_to_encoding(str);
-       return (encoding);
+               if (encoding < 0)
+                       encoding = PG_SQL_ASCII;
+       }
+       return encoding;
 }
 
 
 #ifdef ENABLE_NLS
 
-char *
-libpq_gettext(const char *msgid)
+static void
+libpq_binddomain()
 {
        static bool already_bound = false;
 
        if (!already_bound)
        {
-               /* dgettext() preserves errno, but bindtextdomain() doesn't */
-               int             save_errno = errno;
+               /* bindtextdomain() does not preserve errno */
+#ifdef WIN32
+               int                     save_errno = GetLastError();
+#else
+               int                     save_errno = errno;
+#endif
                const char *ldir;
 
                already_bound = true;
@@ -1141,15 +1270,27 @@ libpq_gettext(const char *msgid)
                ldir = getenv("PGLOCALEDIR");
                if (!ldir)
                        ldir = LOCALEDIR;
-               bindtextdomain("libpq", ldir);
+               bindtextdomain(PG_TEXTDOMAIN("libpq"), ldir);
 #ifdef WIN32
                SetLastError(save_errno);
 #else
                errno = save_errno;
 #endif
        }
+}
+
+char *
+libpq_gettext(const char *msgid)
+{
+       libpq_binddomain();
+       return dgettext(PG_TEXTDOMAIN("libpq"), msgid);
+}
 
-       return dgettext("libpq", msgid);
+char *
+libpq_ngettext(const char *msgid, const char *msgid_plural, unsigned long n)
+{
+       libpq_binddomain();
+       return dngettext(PG_TEXTDOMAIN("libpq"), msgid, msgid_plural, n);
 }
 
-#endif   /* ENABLE_NLS */
+#endif                                                 /* ENABLE_NLS */