]> 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 dfc46fdf5987ce9f031cae23bffc7cf62b143b69..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-2002, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-misc.c,v 1.89 2003/04/19 00:02:30 tgl Exp $
+ *       src/interfaces/libpq/fe-misc.c
  *
  *-------------------------------------------------------------------------
  */
 
 #include "postgres_fe.h"
 
-#include <errno.h>
 #include <signal.h>
 #include <time.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
 
 #ifdef WIN32
 #include "win32.h"
 #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"
-
-#define DONOTICE(conn,message) \
-       ((*(conn)->noticeHook) ((conn)->noticeArg, (message)))
+#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);
@@ -67,6 +59,28 @@ 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
@@ -107,14 +121,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;
@@ -130,7 +144,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;
@@ -142,6 +158,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
@@ -153,7 +181,7 @@ pqPuts(const char *s, PGconn *conn)
                return EOF;
 
        if (conn->Pfdebug)
-               fprintf(conn->Pfdebug, "To backend> '%s'\n", s);
+               fprintf(conn->Pfdebug, "To backend> \"%s\"\n", s);
 
        return 0;
 }
@@ -165,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);
@@ -174,7 +202,37 @@ pqGetnchar(char *s, size_t len, PGconn *conn)
        conn->inCursor += len;
 
        if (conn->Pfdebug)
-               fprintf(conn->Pfdebug, "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;
 }
@@ -190,13 +248,17 @@ pqPutnchar(const char *s, size_t len, PGconn *conn)
                return EOF;
 
        if (conn->Pfdebug)
-               fprintf(conn->Pfdebug, "To backend> %.*s\n", (int) len, s);
+       {
+               fprintf(conn->Pfdebug, "To backend> ");
+               fputnbytes(conn->Pfdebug, s, len);
+               fprintf(conn->Pfdebug, "\n");
+       }
 
        return 0;
 }
 
 /*
- * pgGetInt
+ * pqGetInt
  *     read a 2 or 4 byte integer and convert from network byte order
  *     to local byte order
  */
@@ -205,7 +267,6 @@ pqGetInt(int *result, size_t bytes, PGconn *conn)
 {
        uint16          tmp2;
        uint32          tmp4;
-       char            noticeBuf[64];
 
        switch (bytes)
        {
@@ -214,20 +275,19 @@ 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:
-                       snprintf(noticeBuf, sizeof(noticeBuf),
-                                        libpq_gettext("integer of size %lu not supported by pqGetInt\n"),
-                                        (unsigned long) bytes);
-                       DONOTICE(conn, noticeBuf);
+                       pqInternalNotice(&conn->noticeHooks,
+                                                        "integer of size %lu not supported by pqGetInt",
+                                                        (unsigned long) bytes);
                        return EOF;
        }
 
@@ -238,7 +298,7 @@ pqGetInt(int *result, size_t bytes, PGconn *conn)
 }
 
 /*
- * pgPutInt
+ * pqPutInt
  * write an integer of 2 or 4 bytes, converting from host byte order
  * to network byte order.
  */
@@ -247,25 +307,23 @@ pqPutInt(int value, size_t bytes, PGconn *conn)
 {
        uint16          tmp2;
        uint32          tmp4;
-       char            noticeBuf[64];
 
        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:
-                       snprintf(noticeBuf, sizeof(noticeBuf),
-                                        libpq_gettext("integer of size %lu not supported by pqPutInt\n"),
-                                        (unsigned long) bytes);
-                       DONOTICE(conn, noticeBuf);
+                       pqInternalNotice(&conn->noticeHooks,
+                                                        "integer of size %lu not supported by pqPutInt",
+                                                        (unsigned long) bytes);
                        return EOF;
        }
 
@@ -277,30 +335,33 @@ pqPutInt(int value, size_t bytes, PGconn *conn)
 
 /*
  * Make sure conn's output buffer can hold bytes_needed bytes (caller must
- * include existing outCount into the value!)
+ * include already-stored data into the value!)
  *
- * Returns 0 on success, EOF on error
+ * Returns 0 on success, EOF if failed to enlarge buffer
  */
-static int
-checkOutBufferSpace(int bytes_needed, PGconn *conn)
+int
+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 {
+       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)
@@ -313,11 +374,12 @@ checkOutBufferSpace(int bytes_needed, PGconn *conn)
        }
 
        newsize = conn->outBufSize;
-       do {
+       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)
@@ -335,44 +397,155 @@ checkOutBufferSpace(int bytes_needed, PGconn *conn)
        return EOF;
 }
 
+/*
+ * Make sure conn's input buffer can hold bytes_needed bytes (caller must
+ * include already-stored data into the value!)
+ *
+ * Returns 0 on success, EOF if failed to enlarge buffer
+ */
+int
+pqCheckInBufferSpace(size_t bytes_needed, PGconn *conn)
+{
+       int                     newsize = conn->inBufSize;
+       char       *newbuf;
+
+       /* Quick exit if we have enough space */
+       if (bytes_needed <= (size_t) newsize)
+               return 0;
+
+       /*
+        * 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 (newsize > 0 && bytes_needed > (size_t) newsize);
+
+       if (newsize > 0 && bytes_needed <= (size_t) newsize)
+       {
+               newbuf = realloc(conn->inBuffer, newsize);
+               if (newbuf)
+               {
+                       /* realloc succeeded */
+                       conn->inBuffer = newbuf;
+                       conn->inBufSize = newsize;
+                       return 0;
+               }
+       }
+
+       newsize = conn->inBufSize;
+       do
+       {
+               newsize += 8192;
+       } while (newsize > 0 && bytes_needed > (size_t) newsize);
+
+       if (newsize > 0 && bytes_needed <= (size_t) newsize)
+       {
+               newbuf = realloc(conn->inBuffer, newsize);
+               if (newbuf)
+               {
+                       /* realloc succeeded */
+                       conn->inBuffer = newbuf;
+                       conn->inBufSize = newsize;
+                       return 0;
+               }
+       }
+
+       /* realloc failed. Probably out of memory */
+       printfPQExpBuffer(&conn->errorMessage,
+                                         "cannot allocate memory for input buffer\n");
+       return EOF;
+}
+
 /*
  * pqPutMsgStart: begin construction of a message to the server
  *
  * msg_type is the message type byte, or 0 for a message without type byte
  * (only startup messages have no type byte)
  *
+ * force_len forces the message to have a length word; otherwise, we add
+ * a length word if protocol 3.
+ *
  * Returns 0 on success, EOF on error
  *
  * The idea here is that we construct the message in conn->outBuffer,
  * beginning just past any data already in outBuffer (ie, at
  * outBuffer+outCount).  We enlarge the buffer as needed to hold the message.
- * When the message is complete, we fill in the length word and then advance
- * outCount past the message, making it eligible to send.  The state
- * variable conn->outMsgStart points to the incomplete message's length word
- * (it is either outCount or outCount+1 depending on whether there is a
- * type byte).  The state variable conn->outMsgEnd is the end of the data
- * collected so far.
+ * When the message is complete, we fill in the length word (if needed) and
+ * then advance outCount past the message, making it eligible to send.
+ *
+ * The state variable conn->outMsgStart points to the incomplete message's
+ * length word: it is either outCount or outCount+1 depending on whether
+ * there is a type byte.  If we are sending a message without length word
+ * (pre protocol 3.0 only), then outMsgStart is -1.  The state variable
+ * conn->outMsgEnd is the end of the data collected so far.
  */
 int
-pqPutMsgStart(char msg_type, PGconn *conn)
+pqPutMsgStart(char msg_type, bool force_len, PGconn *conn)
 {
        int                     lenPos;
+       int                     endPos;
 
-       /* where the message length word will go */
+       /* allow room for message type byte */
        if (msg_type)
-               lenPos = conn->outCount + 1;
+               endPos = conn->outCount + 1;
        else
-               lenPos = conn->outCount;
-       /* make sure there is room for it */
-       if (checkOutBufferSpace(lenPos + 4, conn))
+               endPos = conn->outCount;
+
+       /* do we want a length word? */
+       if (force_len || PG_PROTOCOL_MAJOR(conn->pversion) >= 3)
+       {
+               lenPos = endPos;
+               /* allow room for message length */
+               endPos += 4;
+       }
+       else
+               lenPos = -1;
+
+       /* make sure there is room for message header */
+       if (pqCheckOutBufferSpace(endPos, conn))
                return EOF;
        /* okay, save the message type byte if any */
        if (msg_type)
                conn->outBuffer[conn->outCount] = msg_type;
        /* set up the message pointers */
        conn->outMsgStart = lenPos;
-       conn->outMsgEnd = lenPos + 4;
-       /* length word will be filled in by pqPutMsgEnd */
+       conn->outMsgEnd = endPos;
+       /* length word, if needed, will be filled in by pqPutMsgEnd */
 
        if (conn->Pfdebug)
                fprintf(conn->Pfdebug, "To backend> Msg %c\n",
@@ -390,7 +563,7 @@ static int
 pqPutMsgBytes(const void *buf, size_t len, PGconn *conn)
 {
        /* make sure there is room for it */
-       if (checkOutBufferSpace(conn->outMsgEnd + len, conn))
+       if (pqCheckOutBufferSpace(conn->outMsgEnd + len, conn))
                return EOF;
        /* okay, save the data */
        memcpy(conn->outBuffer + conn->outMsgEnd, buf, len);
@@ -412,19 +585,25 @@ pqPutMsgBytes(const void *buf, size_t len, PGconn *conn)
 int
 pqPutMsgEnd(PGconn *conn)
 {
-       uint32          msgLen = conn->outMsgEnd - conn->outMsgStart;
-
        if (conn->Pfdebug)
                fprintf(conn->Pfdebug, "To backend> Msg complete, length %u\n",
-                               msgLen);
+                               conn->outMsgEnd - conn->outCount);
+
+       /* Fill in length word if needed */
+       if (conn->outMsgStart >= 0)
+       {
+               uint32          msgLen = conn->outMsgEnd - conn->outMsgStart;
+
+               msgLen = pg_hton32(msgLen);
+               memcpy(conn->outBuffer + conn->outMsgStart, &msgLen, 4);
+       }
 
-       msgLen = htonl(msgLen);
-       memcpy(conn->outBuffer + conn->outMsgStart, &msgLen, 4);
+       /* Make message eligible to send */
        conn->outCount = conn->outMsgEnd;
 
        if (conn->outCount >= 8192)
        {
-               int             toSend = conn->outCount - (conn->outCount % 8192);
+               int                     toSend = conn->outCount - (conn->outCount % 8192);
 
                if (pqSendSome(conn, toSend) < 0)
                        return EOF;
@@ -451,7 +630,7 @@ pqReadData(PGconn *conn)
        int                     someread = 0;
        int                     nread;
 
-       if (conn->sock < 0)
+       if (conn->sock == PGINVALID_SOCKET)
        {
                printfPQExpBuffer(&conn->errorMessage,
                                                  libpq_gettext("connection not open\n"));
@@ -477,22 +656,22 @@ 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)
        {
-               int                     newSize = conn->inBufSize * 2;
-               char       *newBuf = (char *) realloc(conn->inBuffer, newSize);
-
-               if (newBuf)
+               if (pqCheckInBufferSpace(conn->inEnd + (size_t) 8192, conn))
                {
-                       conn->inBuffer = newBuf;
-                       conn->inBufSize = newSize;
+                       /*
+                        * We don't insist that the enlarge worked, but we need some room
+                        */
+                       if (conn->inBufSize - conn->inEnd < 100)
+                               return -1;              /* errorMessage already set */
                }
        }
 
@@ -518,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));
+               /* pqsecure_read set the error message for us */
                return -1;
        }
        if (nread > 0)
@@ -528,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)
@@ -553,14 +729,26 @@ 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, 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_in_use)
+               return 0;
+#endif
+
        switch (pqReadReady(conn))
        {
                case 0:
@@ -570,7 +758,8 @@ retry3:
                        /* ready for read */
                        break;
                default:
-                       goto definitelyFailed;
+                       /* we override pqReadReady's message with something more useful */
+                       goto definitelyEOF;
        }
 
        /*
@@ -598,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));
+               /* pqsecure_read set the error message for us */
                return -1;
        }
        if (nread > 0)
@@ -610,24 +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);
-#ifdef WIN32
-       closesocket(conn->sock);
-#else
-       close(conn->sock);
-#endif
-       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;
 }
 
@@ -639,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)
@@ -647,11 +838,32 @@ 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 */
@@ -659,15 +871,21 @@ pqSendSome(PGconn *conn, int len)
        {
                int                     sent;
 
+#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 or EWOULDBLOCK 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
@@ -681,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));
-                                       /* 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
@@ -720,27 +930,46 @@ pqSendSome(PGconn *conn, int len)
 
                if (len > 0)
                {
-                       /* We didn't send it all, wait till we can send more */
-
                        /*
-                        * if the socket is in non-blocking mode we may need to abort
-                        * here and return 1 to indicate that data is still pending.
+                        * We didn't send it all, wait till we can send more.
+                        *
+                        * 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.
                         */
-#ifdef USE_SSL
-                       /* can't do anything for our SSL users yet */
-                       if (conn->ssl == NULL)
+                       if (pqReadData(conn) < 0)
                        {
-#endif
-                               if (pqIsnonblocking(conn))
-                               {
-                                       result = 1;
-                                       break;
-                               }
-#ifdef USE_SSL
+                               result = -1;    /* error message already set up */
+                               break;
                        }
-#endif
 
-                       if (pqWait(FALSE, TRUE, conn))
+                       if (pqIsnonblocking(conn))
+                       {
+                               result = 1;
+                               break;
+                       }
+
+                       if (pqWait(true, true, conn))
                        {
                                result = -1;
                                break;
@@ -762,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)
@@ -795,27 +1025,25 @@ 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)
 {
-       int result;
+       int                     result;
 
        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;
@@ -852,20 +1080,20 @@ pqWriteReady(PGconn *conn)
 static int
 pqSocketCheck(PGconn *conn, int forRead, int forWrite, time_t end_time)
 {
-       int result;
+       int                     result;
 
        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;
@@ -874,16 +1102,16 @@ pqSocketCheck(PGconn *conn, int forRead, int forWrite, time_t end_time)
 
        /* We will retry as long as we get EINTR */
        do
-       {
                result = pqSocketPoll(conn->sock, forRead, forWrite, end_time);
-       }
        while (result < 0 && SOCK_ERRNO == EINTR);
 
        if (result < 0)
        {
+               char            sebuf[PG_STRERROR_R_BUFLEN];
+
                printfPQExpBuffer(&conn->errorMessage,
-                                 libpq_gettext("select() failed: %s\n"),
-                                 SOCK_STRERROR(SOCK_ERRNO));
+                                                 libpq_gettext("select() failed: %s\n"),
+                                                 SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf)));
        }
 
        return result;
@@ -905,13 +1133,13 @@ pqSocketPoll(int sock, int forRead, int forWrite, time_t end_time)
        /* We use poll(2) if available, otherwise select(2) */
 #ifdef HAVE_POLL
        struct pollfd input_fd;
-       int           timeout_ms;
+       int                     timeout_ms;
 
        if (!forRead && !forWrite)
                return 0;
 
-       input_fd.fd      = sock;
-       input_fd.events  = POLLERR;
+       input_fd.fd = sock;
+       input_fd.events = POLLERR;
        input_fd.revents = 0;
 
        if (forRead)
@@ -921,12 +1149,10 @@ pqSocketPoll(int sock, int forRead, int forWrite, time_t end_time)
 
        /* Compute appropriate timeout interval */
        if (end_time == ((time_t) -1))
-       {
                timeout_ms = -1;
-       }
        else
        {
-               time_t now = time(NULL);
+               time_t          now = time(NULL);
 
                if (end_time > now)
                        timeout_ms = (end_time - now) * 1000;
@@ -935,13 +1161,12 @@ pqSocketPoll(int sock, int forRead, int forWrite, time_t end_time)
        }
 
        return poll(&input_fd, 1, timeout_ms);
+#else                                                  /* !HAVE_POLL */
 
-#else /* !HAVE_POLL */
-
-       fd_set          input_mask;
-       fd_set          output_mask;
-       fd_set          except_mask;
-       struct timeval  timeout;
+       fd_set          input_mask;
+       fd_set          output_mask;
+       fd_set          except_mask;
+       struct timeval timeout;
        struct timeval *ptr_timeout;
 
        if (!forRead && !forWrite)
@@ -952,18 +1177,17 @@ 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);
 
        /* Compute appropriate timeout interval */
        if (end_time == ((time_t) -1))
-       {
                ptr_timeout = NULL;
-       }
        else
        {
-               time_t  now = time(NULL);
+               time_t          now = time(NULL);
 
                if (end_time > now)
                        timeout.tv_sec = end_time - now;
@@ -975,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 */
 }
 
 
@@ -985,13 +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 char *s, int encoding)
+{
+       return pg_encoding_mblen(encoding, s);
+}
+
+/*
+ * returns the display length of the character beginning at s, using the
  * specified encoding.
  */
 int
-PQmblen(const unsigned char *s, int encoding)
+PQdsplen(const char *s, int encoding)
 {
-       return (pg_encoding_mblen(encoding, s));
+       return pg_encoding_dsplen(encoding, s);
 }
 
 /*
@@ -1005,25 +1239,58 @@ 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 int      already_bound = 0;
+       static bool already_bound = false;
 
        if (!already_bound)
        {
-               already_bound = 1;
-               bindtextdomain("libpq", LOCALEDIR);
+               /* bindtextdomain() does not preserve errno */
+#ifdef WIN32
+               int                     save_errno = GetLastError();
+#else
+               int                     save_errno = errno;
+#endif
+               const char *ldir;
+
+               already_bound = true;
+               /* No relocatable lookup here because the binary could be anywhere */
+               ldir = getenv("PGLOCALEDIR");
+               if (!ldir)
+                       ldir = LOCALEDIR;
+               bindtextdomain(PG_TEXTDOMAIN("libpq"), ldir);
+#ifdef WIN32
+               SetLastError(save_errno);
+#else
+               errno = save_errno;
+#endif
        }
+}
 
-       return dgettext("libpq", msgid);
+char *
+libpq_gettext(const char *msgid)
+{
+       libpq_binddomain();
+       return dgettext(PG_TEXTDOMAIN("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 */