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

数据库系统

开发平台:

Unix_Linux

  1. /*-------------------------------------------------------------------------
  2.  *
  3.  * pqformat.c
  4.  * Routines for formatting and parsing frontend/backend messages
  5.  *
  6.  * Outgoing messages are built up in a StringInfo buffer (which is expansible)
  7.  * and then sent in a single call to pq_putmessage.  This module provides data
  8.  * formatting/conversion routines that are needed to produce valid messages.
  9.  * Note in particular the distinction between "raw data" and "text"; raw data
  10.  * is message protocol characters and binary values that are not subject to
  11.  * MULTIBYTE conversion, while text is converted by MULTIBYTE rules.
  12.  *
  13.  * Incoming messages are read directly off the wire, as it were, but there
  14.  * are still data-conversion tasks to be performed.
  15.  *
  16.  * Copyright (c) 1994, Regents of the University of California
  17.  *
  18.  * $Id: pqformat.c,v 1.4.2.1 1999/09/12 22:25:32 scrappy Exp $
  19.  *
  20.  *-------------------------------------------------------------------------
  21.  */
  22. /*
  23.  * INTERFACE ROUTINES
  24.  * Message assembly and output:
  25.  * pq_beginmessage - initialize StringInfo buffer
  26.  * pq_sendbyte - append a raw byte to a StringInfo buffer
  27.  * pq_sendint - append a binary integer to a StringInfo buffer
  28.  * pq_sendbytes - append raw data to a StringInfo buffer
  29.  * pq_sendcountedtext - append a text string (with MULTIBYTE conversion)
  30.  * pq_sendstring - append a null-terminated text string (with MULTIBYTE)
  31.  * pq_endmessage - send the completed message to the frontend
  32.  * Note: it is also possible to append data to the StringInfo buffer using
  33.  * the regular StringInfo routines, but this is discouraged since required
  34.  * MULTIBYTE conversion may not occur.
  35.  *
  36.  * Special-case message output:
  37.  * pq_puttextmessage - generate a MULTIBYTE-converted message in one step
  38.  *
  39.  * Message input:
  40.  * pq_getint - get an integer from connection
  41.  * pq_getstr - get a null terminated string from connection
  42.  * pq_getstr performs MULTIBYTE conversion on the collected string.
  43.  * Use the raw pqcomm.c routines pq_getstring or pq_getbytes
  44.  * to fetch data without conversion.
  45.  */
  46. #include "postgres.h"
  47. #include "libpq/pqformat.h"
  48. #include "libpq/libpq.h"
  49. #ifdef MULTIBYTE
  50. #include "mb/pg_wchar.h"
  51. #endif
  52. #include <string.h>
  53. #ifdef HAVE_ENDIAN_H
  54. #include <endian.h>
  55. #endif
  56. #ifdef HAVE_SYS_PARAM_H
  57. #include <sys/param.h>
  58. #endif
  59. #ifndef BYTE_ORDER
  60. #error BYTE_ORDER must be defined as LITTLE_ENDIAN, BIG_ENDIAN or PDP_ENDIAN
  61. #endif
  62. #if BYTE_ORDER == LITTLE_ENDIAN
  63. #define ntoh_s(n) n
  64. #define ntoh_l(n) n
  65. #define hton_s(n) n
  66. #define hton_l(n) n
  67. #else
  68. #if BYTE_ORDER == BIG_ENDIAN
  69. #define ntoh_s(n) (uint16)((((uint16)n & 0x00ff) <<  8) | 
  70.  (((uint16)n & 0xff00) >>  8))
  71. #define ntoh_l(n) (uint32)((((uint32)n & 0x000000ff) << 24) | 
  72.  (((uint32)n & 0x0000ff00) <<  8) | 
  73.  (((uint32)n & 0x00ff0000) >>  8) | 
  74.  (((uint32)n & 0xff000000) >> 24))
  75. #define hton_s(n) (ntoh_s(n))
  76. #define hton_l(n) (ntoh_l(n))
  77. #else
  78. #if BYTE_ORDER == PDP_ENDIAN
  79. #error PDP_ENDIAN macros not written yet
  80. #else
  81. #error BYTE_ORDER not defined as anything understood
  82. #endif
  83. #endif
  84. #endif
  85. /* --------------------------------
  86.  * pq_sendbyte - append a raw byte to a StringInfo buffer
  87.  * --------------------------------
  88.  */
  89. void
  90. pq_sendbyte(StringInfo buf, int byt)
  91. {
  92. appendStringInfoChar(buf, byt);
  93. }
  94. /* --------------------------------
  95.  * pq_sendbytes - append raw data to a StringInfo buffer
  96.  * --------------------------------
  97.  */
  98. void
  99. pq_sendbytes(StringInfo buf, const char *data, int datalen)
  100. {
  101. appendBinaryStringInfo(buf, data, datalen);
  102. }
  103. /* --------------------------------
  104.  * pq_sendcountedtext - append a text string (with MULTIBYTE conversion)
  105.  *
  106.  * The data sent to the frontend by this routine is a 4-byte count field
  107.  * (the count includes itself, by convention) followed by the string.
  108.  * The passed text string need not be null-terminated, and the data sent
  109.  * to the frontend isn't either.
  110.  * --------------------------------
  111.  */
  112. void
  113. pq_sendcountedtext(StringInfo buf, const char *str, int slen)
  114. {
  115. #ifdef MULTIBYTE
  116. const char *p;
  117. p = (const char *) pg_server_to_client((unsigned char *) str, slen);
  118. if (p != str) /* actual conversion has been done? */
  119. {
  120. str = p;
  121. slen = strlen(str);
  122. }
  123. #endif
  124. pq_sendint(buf, slen + 4, 4);
  125. appendBinaryStringInfo(buf, str, slen);
  126. }
  127. /* --------------------------------
  128.  * pq_sendstring - append a null-terminated text string (with MULTIBYTE)
  129.  *
  130.  * NB: passed text string must be null-terminated, and so is the data
  131.  * sent to the frontend.
  132.  * --------------------------------
  133.  */
  134. void
  135. pq_sendstring(StringInfo buf, const char *str)
  136. {
  137. int slen = strlen(str);
  138. #ifdef MULTIBYTE
  139. const char *p;
  140. p = (const char *) pg_server_to_client((unsigned char *) str, slen);
  141. if (p != str) /* actual conversion has been done? */
  142. {
  143. str = p;
  144. slen = strlen(str);
  145. }
  146. #endif
  147. appendBinaryStringInfo(buf, str, slen + 1);
  148. }
  149. /* --------------------------------
  150.  * pq_sendint - append a binary integer to a StringInfo buffer
  151.  * --------------------------------
  152.  */
  153. void
  154. pq_sendint(StringInfo buf, int i, int b)
  155. {
  156. unsigned char n8;
  157. uint16 n16;
  158. uint32 n32;
  159. switch (b)
  160. {
  161. case 1:
  162. n8 = (unsigned char) i;
  163. appendBinaryStringInfo(buf, (char *) &n8, 1);
  164. break;
  165. case 2:
  166. n16 = ((PG_PROTOCOL_MAJOR(FrontendProtocol) == 0) ? hton_s(i) : htons((uint16) i));
  167. appendBinaryStringInfo(buf, (char *) &n16, 2);
  168. break;
  169. case 4:
  170. n32 = ((PG_PROTOCOL_MAJOR(FrontendProtocol) == 0) ? hton_l(i) : htonl((uint32) i));
  171. appendBinaryStringInfo(buf, (char *) &n32, 4);
  172. break;
  173. default:
  174. elog(ERROR, "pq_sendint: unsupported size %d", b);
  175. break;
  176. }
  177. }
  178. /* --------------------------------
  179.  * pq_endmessage - send the completed message to the frontend
  180.  *
  181.  * The data buffer is pfree()d, but if the StringInfo was allocated with
  182.  * makeStringInfo then the caller must still pfree it.
  183.  * --------------------------------
  184.  */
  185. void
  186. pq_endmessage(StringInfo buf)
  187. {
  188. if (pq_putmessage('', buf->data, buf->len))
  189. {
  190. snprintf(PQerrormsg, ERROR_MSG_LENGTH,
  191.  "FATAL: pq_endmessage failed: errno=%dn", errno);
  192. fputs(PQerrormsg, stderr);
  193. pqdebug("%s", PQerrormsg);
  194. }
  195. pfree(buf->data);
  196. buf->data = NULL;
  197. }
  198. /* --------------------------------
  199.  * pq_puttextmessage - generate a MULTIBYTE-converted message in one step
  200.  *
  201.  * This is the same as the pqcomm.c routine pq_putmessage, except that
  202.  * the message body is a null-terminated string to which MULTIBYTE
  203.  * conversion applies.
  204.  *
  205.  * returns 0 if OK, EOF if trouble
  206.  * --------------------------------
  207.  */
  208. int
  209. pq_puttextmessage(char msgtype, const char *str)
  210. {
  211. int slen = strlen(str);
  212. #ifdef MULTIBYTE
  213. const char *p;
  214. p = (const char *) pg_server_to_client((unsigned char *) str, slen);
  215. if (p != str) /* actual conversion has been done? */
  216. {
  217. str = p;
  218. slen = strlen(str);
  219. }
  220. #endif
  221. return pq_putmessage(msgtype, str, slen + 1);
  222. }
  223. /* --------------------------------
  224.  * pq_getint - get an integer from connection
  225.  *
  226.  * returns 0 if OK, EOF if trouble
  227.  * --------------------------------
  228.  */
  229. int
  230. pq_getint(int *result, int b)
  231. {
  232. int status;
  233. unsigned char n8;
  234. uint16 n16;
  235. uint32 n32;
  236. switch (b)
  237. {
  238. case 1:
  239. status = pq_getbytes((char *) &n8, 1);
  240. *result = (int) n8;
  241. break;
  242. case 2:
  243. status = pq_getbytes((char *) &n16, 2);
  244. *result = (int) ((PG_PROTOCOL_MAJOR(FrontendProtocol) == 0) ?
  245.  ntoh_s(n16) : ntohs(n16));
  246. break;
  247. case 4:
  248. status = pq_getbytes((char *) &n32, 4);
  249. *result = (int) ((PG_PROTOCOL_MAJOR(FrontendProtocol) == 0) ?
  250.  ntoh_l(n32) : ntohl(n32));
  251. break;
  252. default:
  253. /*
  254.  * if we elog(ERROR) here, we will lose sync with the
  255.  * frontend, so just complain to postmaster log instead...
  256.  */
  257. fprintf(stderr, "pq_getint: unsupported size %dn", b);
  258. status = EOF;
  259. *result = 0;
  260. break;
  261. }
  262. return status;
  263. }
  264. /* --------------------------------
  265.  * pq_getstr - get a null terminated string from connection
  266.  *
  267.  * FIXME: we ought to use an expansible StringInfo buffer,
  268.  * rather than dropping data if the message is too long.
  269.  *
  270.  * returns 0 if OK, EOF if trouble
  271.  * --------------------------------
  272.  */
  273. int
  274. pq_getstr(char *s, int maxlen)
  275. {
  276. int c;
  277. #ifdef MULTIBYTE
  278. char    *p;
  279. #endif
  280. c = pq_getstring(s, maxlen);
  281. #ifdef MULTIBYTE
  282. p = (char *) pg_client_to_server((unsigned char *) s, strlen(s));
  283. if (p != s) /* actual conversion has been done? */
  284. {
  285. int newlen = strlen(p);
  286. if (newlen < maxlen)
  287. strcpy(s, p);
  288. else
  289. {
  290. strncpy(s, p, maxlen);
  291. s[maxlen - 1] = '';
  292. }
  293. }
  294. #endif
  295. return c;
  296. }