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