fe-misc.c
上传用户:blenddy
上传日期:2007-01-07
资源大小:6495k
文件大小:14k
源码类别:

数据库系统

开发平台:

Unix_Linux

  1. /*-------------------------------------------------------------------------
  2.  *
  3.  *  FILE
  4.  * fe-misc.c
  5.  *
  6.  *  DESCRIPTION
  7.  *  miscellaneous useful functions
  8.  *
  9.  * The communication routines here are analogous to the ones in
  10.  * backend/libpq/pqcomm.c and backend/libpq/pqcomprim.c, but operate
  11.  * in the considerably different environment of the frontend libpq.
  12.  * In particular, we work with a bare nonblock-mode socket, rather than
  13.  * a stdio stream, so that we can avoid unwanted blocking of the application.
  14.  *
  15.  * XXX: MOVE DEBUG PRINTOUT TO HIGHER LEVEL.  As is, block and restart
  16.  * will cause repeat printouts.
  17.  *
  18.  * We must speak the same transmitted data representations as the backend
  19.  * routines.  Note that this module supports *only* network byte order
  20.  * for transmitted ints, whereas the backend modules (as of this writing)
  21.  * still handle either network or little-endian byte order.
  22.  *
  23.  * Copyright (c) 1994, Regents of the University of California
  24.  *
  25.  *
  26.  * IDENTIFICATION
  27.  *   $Header: /usr/local/cvsroot/pgsql/src/interfaces/libpq/fe-misc.c,v 1.25 1999/05/28 01:54:53 tgl Exp $
  28.  *
  29.  *-------------------------------------------------------------------------
  30.  */
  31. #include "libpq-fe.h"
  32. #include "libpq-int.h"
  33. #include "postgres.h"
  34. #include "pqsignal.h"
  35. #include <stdlib.h>
  36. #include <string.h>
  37. #include <errno.h>
  38. #include <signal.h>
  39. #include <time.h>
  40. #ifdef WIN32
  41. #include "win32.h"
  42. #else
  43. #include <sys/time.h>
  44. #if !defined(NO_UNISTD_H)
  45. #include <unistd.h>
  46. #endif
  47. #endif  /* WIN32 */
  48. #ifdef HAVE_SYS_SELECT_H
  49. #include <sys/select.h>
  50. #endif
  51. #define DONOTICE(conn,message) 
  52. ((*(conn)->noticeHook) ((conn)->noticeArg, (message)))
  53. /* --------------------------------------------------------------------- */
  54. /* pqGetc:
  55.    get a character from the connection
  56.    All these routines return 0 on success, EOF on error.
  57.    Note that for the Get routines, EOF only means there is not enough
  58.    data in the buffer, not that there is necessarily a hard error.
  59. */
  60. int
  61. pqGetc(char *result, PGconn *conn)
  62. {
  63. if (conn->inCursor >= conn->inEnd)
  64. return EOF;
  65. *result = conn->inBuffer[conn->inCursor++];
  66. if (conn->Pfdebug)
  67. fprintf(conn->Pfdebug, "From backend> %cn", *result);
  68. return 0;
  69. }
  70. /* --------------------------------------------------------------------- */
  71. /* pqPutBytes: local routine to write N bytes to the connection,
  72.    with buffering
  73.  */
  74. static int
  75. pqPutBytes(const char *s, int nbytes, PGconn *conn)
  76. {
  77. int avail = conn->outBufSize - conn->outCount;
  78. while (nbytes > avail)
  79. {
  80. memcpy(conn->outBuffer + conn->outCount, s, avail);
  81. conn->outCount += avail;
  82. s += avail;
  83. nbytes -= avail;
  84. if (pqFlush(conn))
  85. return EOF;
  86. avail = conn->outBufSize;
  87. }
  88. memcpy(conn->outBuffer + conn->outCount, s, nbytes);
  89. conn->outCount += nbytes;
  90. return 0;
  91. }
  92. /* --------------------------------------------------------------------- */
  93. /* pqGets:
  94.    get a null-terminated string from the connection,
  95.    and store it in a buffer of size maxlen bytes.
  96.    If the incoming string is >= maxlen bytes, all of it is read,
  97.    but the excess characters are silently discarded.
  98. */
  99. int
  100. pqGets(char *s, int maxlen, PGconn *conn)
  101. {
  102. /* Copy conn data to locals for faster search loop */
  103. char    *inBuffer = conn->inBuffer;
  104. int inCursor = conn->inCursor;
  105. int inEnd = conn->inEnd;
  106. int slen;
  107. while (inCursor < inEnd && inBuffer[inCursor])
  108. inCursor++;
  109. if (inCursor >= inEnd)
  110. return EOF;
  111. slen = inCursor - conn->inCursor;
  112. if (slen < maxlen)
  113. strcpy(s, inBuffer + conn->inCursor);
  114. else
  115. {
  116. strncpy(s, inBuffer + conn->inCursor, maxlen - 1);
  117. s[maxlen - 1] = '';
  118. }
  119. conn->inCursor = ++inCursor;
  120. if (conn->Pfdebug)
  121. fprintf(conn->Pfdebug, "From backend> "%s"n", s);
  122. return 0;
  123. }
  124. /* --------------------------------------------------------------------- */
  125. int
  126. pqPuts(const char *s, PGconn *conn)
  127. {
  128. if (pqPutBytes(s, strlen(s) + 1, conn))
  129. return EOF;
  130. if (conn->Pfdebug)
  131. fprintf(conn->Pfdebug, "To backend> %sn", s);
  132. return 0;
  133. }
  134. /* --------------------------------------------------------------------- */
  135. /* pqGetnchar:
  136.    get a string of exactly len bytes in buffer s, no null termination
  137. */
  138. int
  139. pqGetnchar(char *s, int len, PGconn *conn)
  140. {
  141. if (len < 0 || len > conn->inEnd - conn->inCursor)
  142. return EOF;
  143. memcpy(s, conn->inBuffer + conn->inCursor, len);
  144. /* no terminating null */
  145. conn->inCursor += len;
  146. if (conn->Pfdebug)
  147. fprintf(conn->Pfdebug, "From backend (%d)> %.*sn", len, len, s);
  148. return 0;
  149. }
  150. /* --------------------------------------------------------------------- */
  151. /* pqPutnchar:
  152.    send a string of exactly len bytes, no null termination needed
  153. */
  154. int
  155. pqPutnchar(const char *s, int len, PGconn *conn)
  156. {
  157. if (pqPutBytes(s, len, conn))
  158. return EOF;
  159. if (conn->Pfdebug)
  160. fprintf(conn->Pfdebug, "To backend> %.*sn", len, s);
  161. return 0;
  162. }
  163. /* --------------------------------------------------------------------- */
  164. /* pgGetInt
  165.    read a 2 or 4 byte integer and convert from network byte order
  166.    to local byte order
  167. */
  168. int
  169. pqGetInt(int *result, int bytes, PGconn *conn)
  170. {
  171. uint16 tmp2;
  172. uint32 tmp4;
  173. switch (bytes)
  174. {
  175. case 2:
  176. if (conn->inCursor + 2 > conn->inEnd)
  177. return EOF;
  178. memcpy(&tmp2, conn->inBuffer + conn->inCursor, 2);
  179. conn->inCursor += 2;
  180. *result = (int) ntohs(tmp2);
  181. break;
  182. case 4:
  183. if (conn->inCursor + 4 > conn->inEnd)
  184. return EOF;
  185. memcpy(&tmp4, conn->inBuffer + conn->inCursor, 4);
  186. conn->inCursor += 4;
  187. *result = (int) ntohl(tmp4);
  188. break;
  189. default:
  190. sprintf(conn->errorMessage,
  191. "pqGetInt: int size %d not supportedn", bytes);
  192. DONOTICE(conn, conn->errorMessage);
  193. return EOF;
  194. }
  195. if (conn->Pfdebug)
  196. fprintf(conn->Pfdebug, "From backend (#%d)> %dn", bytes, *result);
  197. return 0;
  198. }
  199. /* --------------------------------------------------------------------- */
  200. /* pgPutInt
  201.    send an integer of 2 or 4 bytes, converting from host byte order
  202.    to network byte order.
  203. */
  204. int
  205. pqPutInt(int value, int bytes, PGconn *conn)
  206. {
  207. uint16 tmp2;
  208. uint32 tmp4;
  209. switch (bytes)
  210. {
  211. case 2:
  212. tmp2 = htons((uint16) value);
  213. if (pqPutBytes((const char *) &tmp2, 2, conn))
  214. return EOF;
  215. break;
  216. case 4:
  217. tmp4 = htonl((uint32) value);
  218. if (pqPutBytes((const char *) &tmp4, 4, conn))
  219. return EOF;
  220. break;
  221. default:
  222. sprintf(conn->errorMessage,
  223. "pqPutInt: int size %d not supportedn", bytes);
  224. DONOTICE(conn, conn->errorMessage);
  225. return EOF;
  226. }
  227. if (conn->Pfdebug)
  228. fprintf(conn->Pfdebug, "To backend (%d#)> %dn", bytes, value);
  229. return 0;
  230. }
  231. /* --------------------------------------------------------------------- */
  232. /* pqReadReady: is select() saying the file is ready to read?
  233.  */
  234. static int
  235. pqReadReady(PGconn *conn)
  236. {
  237. fd_set input_mask;
  238. struct timeval timeout;
  239. if (conn->sock < 0)
  240. return 0;
  241. FD_ZERO(&input_mask);
  242. FD_SET(conn->sock, &input_mask);
  243. timeout.tv_sec = 0;
  244. timeout.tv_usec = 0;
  245. if (select(conn->sock + 1, &input_mask, (fd_set *) NULL, (fd_set *) NULL,
  246.    &timeout) < 0)
  247. {
  248. sprintf(conn->errorMessage,
  249. "pqReadReady() -- select() failed: errno=%dn%sn",
  250. errno, strerror(errno));
  251. return 0;
  252. }
  253. return FD_ISSET(conn->sock, &input_mask);
  254. }
  255. /* --------------------------------------------------------------------- */
  256. /* pqReadData: read more data, if any is available
  257.  * Possible return values:
  258.  *  1: successfully loaded at least one more byte
  259.  *  0: no data is presently available, but no error detected
  260.  * -1: error detected (including EOF = connection closure);
  261.  * conn->errorMessage set
  262.  * NOTE: callers must not assume that pointers or indexes into conn->inBuffer
  263.  * remain valid across this call!
  264.  */
  265. int
  266. pqReadData(PGconn *conn)
  267. {
  268. int nread;
  269. if (conn->sock < 0)
  270. {
  271. strcpy(conn->errorMessage, "pqReadData() -- connection not openn");
  272. return -1;
  273. }
  274. /* Left-justify any data in the buffer to make room */
  275. if (conn->inStart < conn->inEnd)
  276. {
  277. memmove(conn->inBuffer, conn->inBuffer + conn->inStart,
  278. conn->inEnd - conn->inStart);
  279. conn->inEnd -= conn->inStart;
  280. conn->inCursor -= conn->inStart;
  281. conn->inStart = 0;
  282. }
  283. else
  284. conn->inStart = conn->inCursor = conn->inEnd = 0;
  285. /*
  286.  * If the buffer is fairly full, enlarge it. We need to be able to
  287.  * enlarge the buffer in case a single message exceeds the initial
  288.  * buffer size.  We enlarge before filling the buffer entirely so as
  289.  * to avoid asking the kernel for a partial packet. The magic constant
  290.  * here should be at least one TCP packet.
  291.  */
  292. if (conn->inBufSize - conn->inEnd < 2000)
  293. {
  294. int newSize = conn->inBufSize * 2;
  295. char    *newBuf = (char *) realloc(conn->inBuffer, newSize);
  296. if (newBuf)
  297. {
  298. conn->inBuffer = newBuf;
  299. conn->inBufSize = newSize;
  300. }
  301. }
  302. /* OK, try to read some data */
  303. tryAgain:
  304. nread = recv(conn->sock, conn->inBuffer + conn->inEnd,
  305.  conn->inBufSize - conn->inEnd, 0);
  306. if (nread < 0)
  307. {
  308. if (errno == EINTR)
  309. goto tryAgain;
  310. /* Some systems return EAGAIN/EWOULDBLOCK for no data */
  311. #ifdef EAGAIN
  312. if (errno == EAGAIN)
  313. return 0;
  314. #endif
  315. #if defined(EWOULDBLOCK) && (!defined(EAGAIN) || (EWOULDBLOCK != EAGAIN))
  316. if (errno == EWOULDBLOCK)
  317. return 0;
  318. #endif
  319. /* We might get ECONNRESET here if using TCP and backend died */
  320. #ifdef ECONNRESET
  321. if (errno == ECONNRESET)
  322. goto definitelyFailed;
  323. #endif
  324. sprintf(conn->errorMessage,
  325. "pqReadData() --  read() failed: errno=%dn%sn",
  326. errno, strerror(errno));
  327. return -1;
  328. }
  329. if (nread > 0)
  330. {
  331. conn->inEnd += nread;
  332. return 1;
  333. }
  334. /*
  335.  * A return value of 0 could mean just that no data is now available,
  336.  * or it could mean EOF --- that is, the server has closed the
  337.  * connection. Since we have the socket in nonblock mode, the only way
  338.  * to tell the difference is to see if select() is saying that the
  339.  * file is ready. Grumble. Fortunately, we don't expect this path to
  340.  * be taken much, since in normal practice we should not be trying to
  341.  * read data unless the file selected for reading already.
  342.  */
  343. if (!pqReadReady(conn))
  344. return 0; /* definitely no data available */
  345. /*
  346.  * Still not sure that it's EOF, because some data could have just
  347.  * arrived.
  348.  */
  349. tryAgain2:
  350. nread = recv(conn->sock, conn->inBuffer + conn->inEnd,
  351.  conn->inBufSize - conn->inEnd, 0);
  352. if (nread < 0)
  353. {
  354. if (errno == EINTR)
  355. goto tryAgain2;
  356. /* Some systems return EAGAIN/EWOULDBLOCK for no data */
  357. #ifdef EAGAIN
  358. if (errno == EAGAIN)
  359. return 0;
  360. #endif
  361. #if defined(EWOULDBLOCK) && (!defined(EAGAIN) || (EWOULDBLOCK != EAGAIN))
  362. if (errno == EWOULDBLOCK)
  363. return 0;
  364. #endif
  365. /* We might get ECONNRESET here if using TCP and backend died */
  366. #ifdef ECONNRESET
  367. if (errno == ECONNRESET)
  368. goto definitelyFailed;
  369. #endif
  370. sprintf(conn->errorMessage,
  371. "pqReadData() --  read() failed: errno=%dn%sn",
  372. errno, strerror(errno));
  373. return -1;
  374. }
  375. if (nread > 0)
  376. {
  377. conn->inEnd += nread;
  378. return 1;
  379. }
  380. /*
  381.  * OK, we are getting a zero read even though select() says ready.
  382.  * This means the connection has been closed.  Cope.
  383.  */
  384. definitelyFailed:
  385. sprintf(conn->errorMessage,
  386. "pqReadData() -- backend closed the channel unexpectedly.n"
  387. "tThis probably means the backend terminated abnormallyn"
  388. "tbefore or while processing the request.n");
  389. conn->status = CONNECTION_BAD; /* No more connection to backend */
  390. #ifdef WIN32
  391. closesocket(conn->sock);
  392. #else
  393. close(conn->sock);
  394. #endif
  395. conn->sock = -1;
  396. return -1;
  397. }
  398. /* --------------------------------------------------------------------- */
  399. /* pqFlush: send any data waiting in the output buffer
  400.  */
  401. int
  402. pqFlush(PGconn *conn)
  403. {
  404. char    *ptr = conn->outBuffer;
  405. int len = conn->outCount;
  406. if (conn->sock < 0)
  407. {
  408. strcpy(conn->errorMessage, "pqFlush() -- connection not openn");
  409. return EOF;
  410. }
  411. while (len > 0)
  412. {
  413. /* Prevent being SIGPIPEd if backend has closed the connection. */
  414. #ifndef WIN32
  415. pqsigfunc oldsighandler = pqsignal(SIGPIPE, SIG_IGN);
  416. #endif
  417. int sent = send(conn->sock, ptr, len, 0);
  418. #ifndef WIN32
  419. pqsignal(SIGPIPE, oldsighandler);
  420. #endif
  421. if (sent < 0)
  422. {
  423. /*
  424.  * Anything except EAGAIN or EWOULDBLOCK is trouble. If it's
  425.  * EPIPE or ECONNRESET, assume we've lost the backend
  426.  * connection permanently.
  427.  */
  428. switch (errno)
  429. {
  430. #ifdef EAGAIN
  431. case EAGAIN:
  432. break;
  433. #endif
  434. #if defined(EWOULDBLOCK) && (!defined(EAGAIN) || (EWOULDBLOCK != EAGAIN))
  435. case EWOULDBLOCK:
  436. break;
  437. #endif
  438. case EPIPE:
  439. #ifdef ECONNRESET
  440. case ECONNRESET:
  441. #endif
  442. sprintf(conn->errorMessage,
  443. "pqFlush() -- backend closed the channel unexpectedly.n"
  444. "tThis probably means the backend terminated abnormally"
  445. " before or while processing the request.n");
  446. /*
  447.  * We used to close the socket here, but that's a bad
  448.  * idea since there might be unread data waiting
  449.  * (typically, a NOTICE message from the backend telling
  450.  * us it's committing hara-kiri...).  Leave the socket
  451.  * open until pqReadData finds no more data can be read.
  452.  */
  453. return EOF;
  454. default:
  455. sprintf(conn->errorMessage,
  456.   "pqFlush() --  couldn't send data: errno=%dn%sn",
  457. errno, strerror(errno));
  458. /* We don't assume it's a fatal error... */
  459. return EOF;
  460. }
  461. }
  462. else
  463. {
  464. ptr += sent;
  465. len -= sent;
  466. }
  467. if (len > 0)
  468. {
  469. /* We didn't send it all, wait till we can send more */
  470. if (pqWait(FALSE, TRUE, conn))
  471. return EOF;
  472. }
  473. }
  474. conn->outCount = 0;
  475. if (conn->Pfdebug)
  476. fflush(conn->Pfdebug);
  477. return 0;
  478. }
  479. /* --------------------------------------------------------------------- */
  480. /* pqWait: wait until we can read or write the connection socket
  481.  */
  482. int
  483. pqWait(int forRead, int forWrite, PGconn *conn)
  484. {
  485. fd_set input_mask;
  486. fd_set output_mask;
  487. if (conn->sock < 0)
  488. {
  489. strcpy(conn->errorMessage, "pqWait() -- connection not openn");
  490. return EOF;
  491. }
  492. /* loop in case select returns EINTR */
  493. for (;;)
  494. {
  495. FD_ZERO(&input_mask);
  496. FD_ZERO(&output_mask);
  497. if (forRead)
  498. FD_SET(conn->sock, &input_mask);
  499. if (forWrite)
  500. FD_SET(conn->sock, &output_mask);
  501. if (select(conn->sock + 1, &input_mask, &output_mask, (fd_set *) NULL,
  502.    (struct timeval *) NULL) < 0)
  503. {
  504. if (errno == EINTR)
  505. continue;
  506. sprintf(conn->errorMessage,
  507. "pqWait() -- select() failed: errno=%dn%sn",
  508. errno, strerror(errno));
  509. return EOF;
  510. }
  511. /* On nonerror return, assume we're done */
  512. break;
  513. }
  514. return 0;
  515. }