📄 fe-misc.c
字号:
/* * We don't insist that the enlarge worked, but we need some room */ if (conn->inBufSize - conn->inEnd < 100) return -1; /* errorMessage already set */ } } /* OK, try to read some data */retry3: nread = pqsecure_read(conn, conn->inBuffer + conn->inEnd, conn->inBufSize - conn->inEnd); if (nread < 0) { if (SOCK_ERRNO == EINTR) goto retry3; /* Some systems return EAGAIN/EWOULDBLOCK for no data */#ifdef EAGAIN if (SOCK_ERRNO == EAGAIN) return someread;#endif#if defined(EWOULDBLOCK) && (!defined(EAGAIN) || (EWOULDBLOCK != EAGAIN)) if (SOCK_ERRNO == EWOULDBLOCK) return someread;#endif /* We might get ECONNRESET here if using TCP and backend died */#ifdef ECONNRESET 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))); return -1; } if (nread > 0) { 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. * * 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 ... */ if (conn->inEnd > 32768 && (conn->inBufSize - conn->inEnd) >= 8192) { someread = 1; goto retry3; } return 1; } if (someread) 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. * * 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. */#ifdef USE_SSL if (conn->ssl) return 0;#endif switch (pqReadReady(conn)) { case 0: /* definitely no data available */ return 0; case 1: /* ready for read */ break; default: goto definitelyFailed; } /* * Still not sure that it's EOF, because some data could have just * arrived. */retry4: nread = pqsecure_read(conn, conn->inBuffer + conn->inEnd, conn->inBufSize - conn->inEnd); if (nread < 0) { if (SOCK_ERRNO == EINTR) goto retry4; /* Some systems return EAGAIN/EWOULDBLOCK for no data */#ifdef EAGAIN if (SOCK_ERRNO == EAGAIN) return 0;#endif#if defined(EWOULDBLOCK) && (!defined(EAGAIN) || (EWOULDBLOCK != EAGAIN)) if (SOCK_ERRNO == EWOULDBLOCK) return 0;#endif /* We might get ECONNRESET here if using TCP and backend died */#ifdef ECONNRESET 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))); return -1; } if (nread > 0) { conn->inEnd += nread; return 1; } /* * OK, we are getting a zero read even though select() says ready. This * means the connection has been closed. Cope. */definitelyFailed: 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; return -1;}/* * pqSendSome: send data waiting in the output buffer. * * len is how much to try to send (typically equal to outCount, but may * be less). * * 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. */static intpqSendSome(PGconn *conn, int len){ char *ptr = conn->outBuffer; int remaining = conn->outCount; int result = 0; if (conn->sock < 0) { printfPQExpBuffer(&conn->errorMessage, libpq_gettext("connection not open\n")); return -1; } /* while there's still data to send */ while (len > 0) { int sent; char sebuf[256]; sent = pqsecure_write(conn, ptr, len); if (sent < 0) { /* * Anything except EAGAIN/EWOULDBLOCK/EINTR is trouble. If it's * EPIPE or ECONNRESET, assume we've lost the backend connection * permanently. */ switch (SOCK_ERRNO) {#ifdef EAGAIN case EAGAIN: break;#endif#if defined(EWOULDBLOCK) && (!defined(EAGAIN) || (EWOULDBLOCK != EAGAIN)) case EWOULDBLOCK: break;#endif 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")); /* * 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. */ conn->outCount = 0; return -1; 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... */ conn->outCount = 0; return -1; } } else { ptr += sent; len -= sent; remaining -= sent; } if (len > 0) { /* * 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. */ if (pqIsnonblocking(conn)) { result = 1; 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) { result = -1; /* error message already set up */ break; } if (pqWait(TRUE, TRUE, conn)) { result = -1; break; } } } /* shift the remaining contents of the buffer */ if (remaining > 0) memmove(conn->outBuffer, ptr, remaining); conn->outCount = remaining; return result;}/* * pqFlush: send any data waiting in the output buffer * * 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. */intpqFlush(PGconn *conn){ if (conn->Pfdebug) fflush(conn->Pfdebug); if (conn->outCount > 0) return pqSendSome(conn, conn->outCount); return 0;}/* * pqWait: wait until we can read or write the connection socket * * JAB: If SSL enabled and used and forRead, buffered bytes short-circuit the * call to select(). * * We also stop waiting and return if the kernel flags an exception condition * on the socket. The actual error condition will be detected and reported * when the caller tries to read or write the socket. */intpqWait(int forRead, int forWrite, PGconn *conn){ return pqWaitTimed(forRead, forWrite, conn, (time_t) -1);}/* * 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. */intpqWaitTimed(int forRead, int forWrite, PGconn *conn, time_t finish_time){ int result; result = pqSocketCheck(conn, forRead, forWrite, finish_time); if (result < 0) return EOF; /* errorMessage is already set */ if (result == 0) { printfPQExpBuffer(&conn->errorMessage, libpq_gettext("timeout expired\n")); return EOF; } return 0;}/* * pqReadReady: is select() saying the file is ready to read? * Returns -1 on failure, 0 if not ready, 1 if ready. */intpqReadReady(PGconn *conn){ return pqSocketCheck(conn, 1, 0, (time_t) 0);}/* * pqWriteReady: is select() saying the file is ready to write? * Returns -1 on failure, 0 if not ready, 1 if ready. */intpqWriteReady(PGconn *conn){ return pqSocketCheck(conn, 0, 1, (time_t) 0);}/* * Checks a socket, using poll or select, for data to be read, written, * or both. Returns >0 if one or more conditions are met, 0 if it timed * out, -1 if an error occurred. * * If SSL is in use, the SSL buffer is checked prior to checking the socket * for read data directly. */static intpqSocketCheck(PGconn *conn, int forRead, int forWrite, time_t end_time){ int result; if (!conn) return -1; if (conn->sock < 0) { printfPQExpBuffer(&conn->errorMessage, libpq_gettext("socket not open\n")); return -1; }#ifdef USE_SSL /* Check for SSL library buffering read bytes */ if (forRead && conn->ssl && SSL_pending(conn->ssl) > 0) { /* short-circuit the select */ return 1; }#endif /* 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[256]; printfPQExpBuffer(&conn->errorMessage, libpq_gettext("select() failed: %s\n"), SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf))); } return result;}/* * Check a file descriptor for read and/or write data, possibly waiting. * If neither forRead nor forWrite are set, immediately return a timeout * condition (without waiting). Return >0 if condition is met, 0 * if a timeout occurred, -1 if an error or interrupt occurred. * * Timeout is infinite if end_time is -1. Timeout is immediate (no blocking) * if end_time is 0 (or indeed, any time before now). */static intpqSocketPoll(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; if (!forRead && !forWrite) return 0; input_fd.fd = sock; input_fd.events = POLLERR; input_fd.revents = 0; if (forRead) input_fd.events |= POLLIN; if (forWrite) input_fd.events |= POLLOUT; /* Compute appropriate timeout interval */ if (end_time == ((time_t) -1)) timeout_ms = -1; else { time_t now = time(NULL); if (end_time > now) timeout_ms = (end_time - now) * 1000; else timeout_ms = 0; } return poll(&input_fd, 1, timeout_ms);#else /* !HAVE_POLL */ fd_set input_mask; fd_set output_mask; fd_set except_mask; struct timeval timeout; struct timeval *ptr_timeout; if (!forRead && !forWrite) return 0; FD_ZERO(&input_mask); FD_ZERO(&output_mask); 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); if (end_time > now) timeout.tv_sec = end_time - now; else timeout.tv_sec = 0; timeout.tv_usec = 0; ptr_timeout = &timeout; } return select(sock + 1, &input_mask, &output_mask, &except_mask, ptr_timeout);#endif /* HAVE_POLL */}/* * A couple of "miscellaneous" multibyte related functions. They used * to be in fe-print.c but that file is doomed. *//* * returns the byte length of the word beginning s, using the * specified encoding. */intPQmblen(const char *s, int encoding){ return (pg_encoding_mblen(encoding, s));}/* * returns the display length of the word beginning s, using the * specified encoding. */intPQdsplen(const char *s, int encoding){ return (pg_encoding_dsplen(encoding, s));}/* * Get encoding id from environment variable PGCLIENTENCODING. */intPQenv2encoding(void){ char *str; int encoding = PG_SQL_ASCII; str = getenv("PGCLIENTENCODING"); if (str && *str != '\0') encoding = pg_char_to_encoding(str); return (encoding);}#ifdef ENABLE_NLSchar *libpq_gettext(const char *msgid){ static bool already_bound = false; if (!already_bound) { /* dgettext() preserves errno, but bindtextdomain() doesn't */#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("libpq", ldir);#ifdef WIN32 SetLastError(save_errno);#else errno = save_errno;#endif } return dgettext("libpq", msgid);}#endif /* ENABLE_NLS */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -