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