]> granicus.if.org Git - postgresql/blob - src/backend/libpq/pqformat.c
15cb4b4df2a386453394329000d6df222c994745
[postgresql] / src / backend / libpq / pqformat.c
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  * character set conversion, while text is converted by character encoding
12  * rules.
13  *
14  * Incoming messages are similarly read into a StringInfo buffer, via
15  * pq_getmessage, and then parsed and converted from that using the routines
16  * in this module.
17  *
18  * These same routines support reading and writing of external binary formats
19  * (typsend/typreceive routines).  The conversion routines for individual
20  * data types are exactly the same, only initialization and completion
21  * are different.
22  *
23  *
24  * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
25  * Portions Copyright (c) 1994, Regents of the University of California
26  *
27  *      $PostgreSQL: pgsql/src/backend/libpq/pqformat.c,v 1.47 2008/01/01 19:45:49 momjian Exp $
28  *
29  *-------------------------------------------------------------------------
30  */
31 /*
32  * INTERFACE ROUTINES
33  * Message assembly and output:
34  *              pq_beginmessage - initialize StringInfo buffer
35  *              pq_sendbyte             - append a raw byte to a StringInfo buffer
36  *              pq_sendint              - append a binary integer to a StringInfo buffer
37  *              pq_sendint64    - append a binary 8-byte int to a StringInfo buffer
38  *              pq_sendfloat4   - append a float4 to a StringInfo buffer
39  *              pq_sendfloat8   - append a float8 to a StringInfo buffer
40  *              pq_sendbytes    - append raw data to a StringInfo buffer
41  *              pq_sendcountedtext - append a counted text string (with character set conversion)
42  *              pq_sendtext             - append a text string (with conversion)
43  *              pq_sendstring   - append a null-terminated text string (with conversion)
44  *              pq_endmessage   - send the completed message to the frontend
45  * Note: it is also possible to append data to the StringInfo buffer using
46  * the regular StringInfo routines, but this is discouraged since required
47  * character set conversion may not occur.
48  *
49  * typsend support (construct a bytea value containing external binary data):
50  *              pq_begintypsend - initialize StringInfo buffer
51  *              pq_endtypsend   - return the completed string as a "bytea*"
52  *
53  * Special-case message output:
54  *              pq_puttextmessage - generate a character set-converted message in one step
55  *              pq_putemptymessage - convenience routine for message with empty body
56  *
57  * Message parsing after input:
58  *              pq_getmsgbyte   - get a raw byte from a message buffer
59  *              pq_getmsgint    - get a binary integer from a message buffer
60  *              pq_getmsgint64  - get a binary 8-byte int from a message buffer
61  *              pq_getmsgfloat4 - get a float4 from a message buffer
62  *              pq_getmsgfloat8 - get a float8 from a message buffer
63  *              pq_getmsgbytes  - get raw data from a message buffer
64  *              pq_copymsgbytes - copy raw data from a message buffer
65  *              pq_getmsgtext   - get a counted text string (with conversion)
66  *              pq_getmsgstring - get a null-terminated text string (with conversion)
67  *              pq_getmsgend    - verify message fully consumed
68  */
69
70 #include "postgres.h"
71
72 #include <sys/param.h>
73 #include <netinet/in.h>
74 #include <arpa/inet.h>
75
76 #include "libpq/libpq.h"
77 #include "libpq/pqformat.h"
78 #include "mb/pg_wchar.h"
79
80
81 /* --------------------------------
82  *              pq_beginmessage         - initialize for sending a message
83  * --------------------------------
84  */
85 void
86 pq_beginmessage(StringInfo buf, char msgtype)
87 {
88         initStringInfo(buf);
89
90         /*
91          * We stash the message type into the buffer's cursor field, expecting
92          * that the pq_sendXXX routines won't touch it.  We could alternatively
93          * make it the first byte of the buffer contents, but this seems easier.
94          */
95         buf->cursor = msgtype;
96 }
97
98 /* --------------------------------
99  *              pq_sendbyte             - append a raw byte to a StringInfo buffer
100  * --------------------------------
101  */
102 void
103 pq_sendbyte(StringInfo buf, int byt)
104 {
105         appendStringInfoCharMacro(buf, byt);
106 }
107
108 /* --------------------------------
109  *              pq_sendbytes    - append raw data to a StringInfo buffer
110  * --------------------------------
111  */
112 void
113 pq_sendbytes(StringInfo buf, const char *data, int datalen)
114 {
115         appendBinaryStringInfo(buf, data, datalen);
116 }
117
118 /* --------------------------------
119  *              pq_sendcountedtext - append a counted text string (with character set conversion)
120  *
121  * The data sent to the frontend by this routine is a 4-byte count field
122  * followed by the string.      The count includes itself or not, as per the
123  * countincludesself flag (pre-3.0 protocol requires it to include itself).
124  * The passed text string need not be null-terminated, and the data sent
125  * to the frontend isn't either.
126  * --------------------------------
127  */
128 void
129 pq_sendcountedtext(StringInfo buf, const char *str, int slen,
130                                    bool countincludesself)
131 {
132         int                     extra = countincludesself ? 4 : 0;
133         char       *p;
134
135         p = pg_server_to_client(str, slen);
136         if (p != str)                           /* actual conversion has been done? */
137         {
138                 slen = strlen(p);
139                 pq_sendint(buf, slen + extra, 4);
140                 appendBinaryStringInfo(buf, p, slen);
141                 pfree(p);
142         }
143         else
144         {
145                 pq_sendint(buf, slen + extra, 4);
146                 appendBinaryStringInfo(buf, str, slen);
147         }
148 }
149
150 /* --------------------------------
151  *              pq_sendtext             - append a text string (with conversion)
152  *
153  * The passed text string need not be null-terminated, and the data sent
154  * to the frontend isn't either.  Note that this is not actually useful
155  * for direct frontend transmissions, since there'd be no way for the
156  * frontend to determine the string length.  But it is useful for binary
157  * format conversions.
158  * --------------------------------
159  */
160 void
161 pq_sendtext(StringInfo buf, const char *str, int slen)
162 {
163         char       *p;
164
165         p = pg_server_to_client(str, slen);
166         if (p != str)                           /* actual conversion has been done? */
167         {
168                 slen = strlen(p);
169                 appendBinaryStringInfo(buf, p, slen);
170                 pfree(p);
171         }
172         else
173                 appendBinaryStringInfo(buf, str, slen);
174 }
175
176 /* --------------------------------
177  *              pq_sendstring   - append a null-terminated text string (with conversion)
178  *
179  * NB: passed text string must be null-terminated, and so is the data
180  * sent to the frontend.
181  * --------------------------------
182  */
183 void
184 pq_sendstring(StringInfo buf, const char *str)
185 {
186         int                     slen = strlen(str);
187
188         char       *p;
189
190         p = pg_server_to_client(str, slen);
191         if (p != str)                           /* actual conversion has been done? */
192         {
193                 slen = strlen(p);
194                 appendBinaryStringInfo(buf, p, slen + 1);
195                 pfree(p);
196         }
197         else
198                 appendBinaryStringInfo(buf, str, slen + 1);
199 }
200
201 /* --------------------------------
202  *              pq_sendint              - append a binary integer to a StringInfo buffer
203  * --------------------------------
204  */
205 void
206 pq_sendint(StringInfo buf, int i, int b)
207 {
208         unsigned char n8;
209         uint16          n16;
210         uint32          n32;
211
212         switch (b)
213         {
214                 case 1:
215                         n8 = (unsigned char) i;
216                         appendBinaryStringInfo(buf, (char *) &n8, 1);
217                         break;
218                 case 2:
219                         n16 = htons((uint16) i);
220                         appendBinaryStringInfo(buf, (char *) &n16, 2);
221                         break;
222                 case 4:
223                         n32 = htonl((uint32) i);
224                         appendBinaryStringInfo(buf, (char *) &n32, 4);
225                         break;
226                 default:
227                         elog(ERROR, "unsupported integer size %d", b);
228                         break;
229         }
230 }
231
232 /* --------------------------------
233  *              pq_sendint64    - append a binary 8-byte int to a StringInfo buffer
234  *
235  * It is tempting to merge this with pq_sendint, but we'd have to make the
236  * argument int64 for all data widths --- that could be a big performance
237  * hit on machines where int64 isn't efficient.
238  * --------------------------------
239  */
240 void
241 pq_sendint64(StringInfo buf, int64 i)
242 {
243         uint32          n32;
244
245         /* High order half first, since we're doing MSB-first */
246 #ifdef INT64_IS_BUSTED
247         /* don't try a right shift of 32 on a 32-bit word */
248         n32 = (i < 0) ? -1 : 0;
249 #else
250         n32 = (uint32) (i >> 32);
251 #endif
252         n32 = htonl(n32);
253         appendBinaryStringInfo(buf, (char *) &n32, 4);
254
255         /* Now the low order half */
256         n32 = (uint32) i;
257         n32 = htonl(n32);
258         appendBinaryStringInfo(buf, (char *) &n32, 4);
259 }
260
261 /* --------------------------------
262  *              pq_sendfloat4   - append a float4 to a StringInfo buffer
263  *
264  * The point of this routine is to localize knowledge of the external binary
265  * representation of float4, which is a component of several datatypes.
266  *
267  * We currently assume that float4 should be byte-swapped in the same way
268  * as int4.  This rule is not perfect but it gives us portability across
269  * most IEEE-float-using architectures.
270  * --------------------------------
271  */
272 void
273 pq_sendfloat4(StringInfo buf, float4 f)
274 {
275         union
276         {
277                 float4          f;
278                 uint32          i;
279         }                       swap;
280
281         swap.f = f;
282         swap.i = htonl(swap.i);
283
284         appendBinaryStringInfo(buf, (char *) &swap.i, 4);
285 }
286
287 /* --------------------------------
288  *              pq_sendfloat8   - append a float8 to a StringInfo buffer
289  *
290  * The point of this routine is to localize knowledge of the external binary
291  * representation of float8, which is a component of several datatypes.
292  *
293  * We currently assume that float8 should be byte-swapped in the same way
294  * as int8.  This rule is not perfect but it gives us portability across
295  * most IEEE-float-using architectures.
296  * --------------------------------
297  */
298 void
299 pq_sendfloat8(StringInfo buf, float8 f)
300 {
301 #ifdef INT64_IS_BUSTED
302         union
303         {
304                 float8          f;
305                 uint32          h[2];
306         }                       swap;
307
308         swap.f = f;
309         swap.h[0] = htonl(swap.h[0]);
310         swap.h[1] = htonl(swap.h[1]);
311
312 #ifdef WORDS_BIGENDIAN
313         /* machine seems to be big-endian, send h[0] first */
314         appendBinaryStringInfo(buf, (char *) &swap.h[0], 4);
315         appendBinaryStringInfo(buf, (char *) &swap.h[1], 4);
316 #else
317         /* machine seems to be little-endian, send h[1] first */
318         appendBinaryStringInfo(buf, (char *) &swap.h[1], 4);
319         appendBinaryStringInfo(buf, (char *) &swap.h[0], 4);
320 #endif
321 #else                                                   /* INT64 works */
322         union
323         {
324                 float8          f;
325                 int64           i;
326         }                       swap;
327
328         swap.f = f;
329         pq_sendint64(buf, swap.i);
330 #endif
331 }
332
333 /* --------------------------------
334  *              pq_endmessage   - send the completed message to the frontend
335  *
336  * The data buffer is pfree()d, but if the StringInfo was allocated with
337  * makeStringInfo then the caller must still pfree it.
338  * --------------------------------
339  */
340 void
341 pq_endmessage(StringInfo buf)
342 {
343         /* msgtype was saved in cursor field */
344         (void) pq_putmessage(buf->cursor, buf->data, buf->len);
345         /* no need to complain about any failure, since pqcomm.c already did */
346         pfree(buf->data);
347         buf->data = NULL;
348 }
349
350
351 /* --------------------------------
352  *              pq_begintypsend         - initialize for constructing a bytea result
353  * --------------------------------
354  */
355 void
356 pq_begintypsend(StringInfo buf)
357 {
358         initStringInfo(buf);
359         /* Reserve four bytes for the bytea length word */
360         appendStringInfoCharMacro(buf, '\0');
361         appendStringInfoCharMacro(buf, '\0');
362         appendStringInfoCharMacro(buf, '\0');
363         appendStringInfoCharMacro(buf, '\0');
364 }
365
366 /* --------------------------------
367  *              pq_endtypsend   - finish constructing a bytea result
368  *
369  * The data buffer is returned as the palloc'd bytea value.  (We expect
370  * that it will be suitably aligned for this because it has been palloc'd.)
371  * We assume the StringInfoData is just a local variable in the caller and
372  * need not be pfree'd.
373  * --------------------------------
374  */
375 bytea *
376 pq_endtypsend(StringInfo buf)
377 {
378         bytea      *result = (bytea *) buf->data;
379
380         /* Insert correct length into bytea length word */
381         Assert(buf->len >= VARHDRSZ);
382         SET_VARSIZE(result, buf->len);
383
384         return result;
385 }
386
387
388 /* --------------------------------
389  *              pq_puttextmessage - generate a character set-converted message in one step
390  *
391  *              This is the same as the pqcomm.c routine pq_putmessage, except that
392  *              the message body is a null-terminated string to which encoding
393  *              conversion applies.
394  * --------------------------------
395  */
396 void
397 pq_puttextmessage(char msgtype, const char *str)
398 {
399         int                     slen = strlen(str);
400         char       *p;
401
402         p = pg_server_to_client(str, slen);
403         if (p != str)                           /* actual conversion has been done? */
404         {
405                 (void) pq_putmessage(msgtype, p, strlen(p) + 1);
406                 pfree(p);
407                 return;
408         }
409         (void) pq_putmessage(msgtype, str, slen + 1);
410 }
411
412
413 /* --------------------------------
414  *              pq_putemptymessage - convenience routine for message with empty body
415  * --------------------------------
416  */
417 void
418 pq_putemptymessage(char msgtype)
419 {
420         (void) pq_putmessage(msgtype, NULL, 0);
421 }
422
423
424 /* --------------------------------
425  *              pq_getmsgbyte   - get a raw byte from a message buffer
426  * --------------------------------
427  */
428 int
429 pq_getmsgbyte(StringInfo msg)
430 {
431         if (msg->cursor >= msg->len)
432                 ereport(ERROR,
433                                 (errcode(ERRCODE_PROTOCOL_VIOLATION),
434                                  errmsg("no data left in message")));
435         return (unsigned char) msg->data[msg->cursor++];
436 }
437
438 /* --------------------------------
439  *              pq_getmsgint    - get a binary integer from a message buffer
440  *
441  *              Values are treated as unsigned.
442  * --------------------------------
443  */
444 unsigned int
445 pq_getmsgint(StringInfo msg, int b)
446 {
447         unsigned int result;
448         unsigned char n8;
449         uint16          n16;
450         uint32          n32;
451
452         switch (b)
453         {
454                 case 1:
455                         pq_copymsgbytes(msg, (char *) &n8, 1);
456                         result = n8;
457                         break;
458                 case 2:
459                         pq_copymsgbytes(msg, (char *) &n16, 2);
460                         result = ntohs(n16);
461                         break;
462                 case 4:
463                         pq_copymsgbytes(msg, (char *) &n32, 4);
464                         result = ntohl(n32);
465                         break;
466                 default:
467                         elog(ERROR, "unsupported integer size %d", b);
468                         result = 0;                     /* keep compiler quiet */
469                         break;
470         }
471         return result;
472 }
473
474 /* --------------------------------
475  *              pq_getmsgint64  - get a binary 8-byte int from a message buffer
476  *
477  * It is tempting to merge this with pq_getmsgint, but we'd have to make the
478  * result int64 for all data widths --- that could be a big performance
479  * hit on machines where int64 isn't efficient.
480  * --------------------------------
481  */
482 int64
483 pq_getmsgint64(StringInfo msg)
484 {
485         int64           result;
486         uint32          h32;
487         uint32          l32;
488
489         pq_copymsgbytes(msg, (char *) &h32, 4);
490         pq_copymsgbytes(msg, (char *) &l32, 4);
491         h32 = ntohl(h32);
492         l32 = ntohl(l32);
493
494 #ifdef INT64_IS_BUSTED
495         /* error out if incoming value is wider than 32 bits */
496         result = l32;
497         if ((result < 0) ? (h32 != -1) : (h32 != 0))
498                 ereport(ERROR,
499                                 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
500                                  errmsg("binary value is out of range for type bigint")));
501 #else
502         result = h32;
503         result <<= 32;
504         result |= l32;
505 #endif
506
507         return result;
508 }
509
510 /* --------------------------------
511  *              pq_getmsgfloat4 - get a float4 from a message buffer
512  *
513  * See notes for pq_sendfloat4.
514  * --------------------------------
515  */
516 float4
517 pq_getmsgfloat4(StringInfo msg)
518 {
519         union
520         {
521                 float4          f;
522                 uint32          i;
523         }                       swap;
524
525         swap.i = pq_getmsgint(msg, 4);
526         return swap.f;
527 }
528
529 /* --------------------------------
530  *              pq_getmsgfloat8 - get a float8 from a message buffer
531  *
532  * See notes for pq_sendfloat8.
533  * --------------------------------
534  */
535 float8
536 pq_getmsgfloat8(StringInfo msg)
537 {
538 #ifdef INT64_IS_BUSTED
539         union
540         {
541                 float8          f;
542                 uint32          h[2];
543         }                       swap;
544
545 #ifdef WORDS_BIGENDIAN
546         /* machine seems to be big-endian, receive h[0] first */
547         swap.h[0] = pq_getmsgint(msg, 4);
548         swap.h[1] = pq_getmsgint(msg, 4);
549 #else
550         /* machine seems to be little-endian, receive h[1] first */
551         swap.h[1] = pq_getmsgint(msg, 4);
552         swap.h[0] = pq_getmsgint(msg, 4);
553 #endif
554         return swap.f;
555 #else                                                   /* INT64 works */
556         union
557         {
558                 float8          f;
559                 int64           i;
560         }                       swap;
561
562         swap.i = pq_getmsgint64(msg);
563         return swap.f;
564 #endif
565 }
566
567 /* --------------------------------
568  *              pq_getmsgbytes  - get raw data from a message buffer
569  *
570  *              Returns a pointer directly into the message buffer; note this
571  *              may not have any particular alignment.
572  * --------------------------------
573  */
574 const char *
575 pq_getmsgbytes(StringInfo msg, int datalen)
576 {
577         const char *result;
578
579         if (datalen < 0 || datalen > (msg->len - msg->cursor))
580                 ereport(ERROR,
581                                 (errcode(ERRCODE_PROTOCOL_VIOLATION),
582                                  errmsg("insufficient data left in message")));
583         result = &msg->data[msg->cursor];
584         msg->cursor += datalen;
585         return result;
586 }
587
588 /* --------------------------------
589  *              pq_copymsgbytes - copy raw data from a message buffer
590  *
591  *              Same as above, except data is copied to caller's buffer.
592  * --------------------------------
593  */
594 void
595 pq_copymsgbytes(StringInfo msg, char *buf, int datalen)
596 {
597         if (datalen < 0 || datalen > (msg->len - msg->cursor))
598                 ereport(ERROR,
599                                 (errcode(ERRCODE_PROTOCOL_VIOLATION),
600                                  errmsg("insufficient data left in message")));
601         memcpy(buf, &msg->data[msg->cursor], datalen);
602         msg->cursor += datalen;
603 }
604
605 /* --------------------------------
606  *              pq_getmsgtext   - get a counted text string (with conversion)
607  *
608  *              Always returns a pointer to a freshly palloc'd result.
609  *              The result has a trailing null, *and* we return its strlen in *nbytes.
610  * --------------------------------
611  */
612 char *
613 pq_getmsgtext(StringInfo msg, int rawbytes, int *nbytes)
614 {
615         char       *str;
616         char       *p;
617
618         if (rawbytes < 0 || rawbytes > (msg->len - msg->cursor))
619                 ereport(ERROR,
620                                 (errcode(ERRCODE_PROTOCOL_VIOLATION),
621                                  errmsg("insufficient data left in message")));
622         str = &msg->data[msg->cursor];
623         msg->cursor += rawbytes;
624
625         p = pg_client_to_server(str, rawbytes);
626         if (p != str)                           /* actual conversion has been done? */
627                 *nbytes = strlen(p);
628         else
629         {
630                 p = (char *) palloc(rawbytes + 1);
631                 memcpy(p, str, rawbytes);
632                 p[rawbytes] = '\0';
633                 *nbytes = rawbytes;
634         }
635         return p;
636 }
637
638 /* --------------------------------
639  *              pq_getmsgstring - get a null-terminated text string (with conversion)
640  *
641  *              May return a pointer directly into the message buffer, or a pointer
642  *              to a palloc'd conversion result.
643  * --------------------------------
644  */
645 const char *
646 pq_getmsgstring(StringInfo msg)
647 {
648         char       *str;
649         int                     slen;
650
651         str = &msg->data[msg->cursor];
652
653         /*
654          * It's safe to use strlen() here because a StringInfo is guaranteed to
655          * have a trailing null byte.  But check we found a null inside the
656          * message.
657          */
658         slen = strlen(str);
659         if (msg->cursor + slen >= msg->len)
660                 ereport(ERROR,
661                                 (errcode(ERRCODE_PROTOCOL_VIOLATION),
662                                  errmsg("invalid string in message")));
663         msg->cursor += slen + 1;
664
665         return pg_client_to_server(str, slen);
666 }
667
668 /* --------------------------------
669  *              pq_getmsgend    - verify message fully consumed
670  * --------------------------------
671  */
672 void
673 pq_getmsgend(StringInfo msg)
674 {
675         if (msg->cursor != msg->len)
676                 ereport(ERROR,
677                                 (errcode(ERRCODE_PROTOCOL_VIOLATION),
678                                  errmsg("invalid message format")));
679 }