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