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