Age Owner Branch data TLA 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-2025, 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
8274 tgl@sss.pgh.pa.us 88 :CBC 595934 : pq_beginmessage(StringInfo buf, char msgtype)
89 : : {
90 : 595934 : 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 : 595934 : buf->cursor = msgtype;
98 : 595934 : }
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
2988 andres@anarazel.de 109 : 3934007 : pq_beginmessage_reuse(StringInfo buf, char msgtype)
110 : : {
111 : 3934007 : 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 : 3934007 : buf->cursor = msgtype;
9732 tgl@sss.pgh.pa.us 119 : 3934007 : }
120 : :
121 : : /* --------------------------------
122 : : * pq_sendbytes - append raw data to a StringInfo buffer
123 : : * --------------------------------
124 : : */
125 : : void
1036 peter@eisentraut.org 126 : 136348 : pq_sendbytes(StringInfo buf, const void *data, int datalen)
127 : : {
128 : : /* use variant that maintains a trailing null-byte, out of caution */
9732 tgl@sss.pgh.pa.us 129 : 136348 : appendBinaryStringInfo(buf, data, datalen);
130 : 136348 : }
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
652 heikki.linnakangas@i 142 : 17785670 : pq_sendcountedtext(StringInfo buf, const char *str, int slen)
143 : : {
144 : : char *p;
145 : :
7388 tgl@sss.pgh.pa.us 146 : 17785670 : p = pg_server_to_client(str, slen);
9732 147 [ + + ]: 17785670 : if (p != str) /* actual conversion has been done? */
148 : : {
9593 149 : 28 : slen = strlen(p);
652 heikki.linnakangas@i 150 : 28 : pq_sendint32(buf, slen);
2988 andres@anarazel.de 151 : 28 : appendBinaryStringInfoNT(buf, p, slen);
9593 tgl@sss.pgh.pa.us 152 : 28 : pfree(p);
153 : : }
154 : : else
155 : : {
652 heikki.linnakangas@i 156 : 17785642 : pq_sendint32(buf, slen);
2988 andres@anarazel.de 157 : 17785642 : appendBinaryStringInfoNT(buf, str, slen);
158 : : }
9732 tgl@sss.pgh.pa.us 159 : 17785670 : }
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
8257 172 : 2361 : pq_sendtext(StringInfo buf, const char *str, int slen)
173 : : {
174 : : char *p;
175 : :
7388 176 : 2361 : p = pg_server_to_client(str, slen);
8257 177 [ - + ]: 2361 : if (p != str) /* actual conversion has been done? */
178 : : {
8257 tgl@sss.pgh.pa.us 179 :UBC 0 : slen = strlen(p);
180 : 0 : appendBinaryStringInfo(buf, p, slen);
181 : 0 : pfree(p);
182 : : }
183 : : else
8257 tgl@sss.pgh.pa.us 184 :CBC 2361 : appendBinaryStringInfo(buf, str, slen);
185 : 2361 : }
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
9732 195 : 667797 : pq_sendstring(StringInfo buf, const char *str)
196 : : {
9702 bruce@momjian.us 197 : 667797 : int slen = strlen(str);
198 : : char *p;
199 : :
7388 tgl@sss.pgh.pa.us 200 : 667797 : p = pg_server_to_client(str, slen);
9732 201 [ + + ]: 667797 : if (p != str) /* actual conversion has been done? */
202 : : {
9593 203 : 147 : slen = strlen(p);
2988 andres@anarazel.de 204 : 147 : appendBinaryStringInfoNT(buf, p, slen + 1);
9593 tgl@sss.pgh.pa.us 205 : 147 : pfree(p);
206 : : }
207 : : else
2988 andres@anarazel.de 208 : 667650 : appendBinaryStringInfoNT(buf, str, slen + 1);
9732 tgl@sss.pgh.pa.us 209 : 667797 : }
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
6133 tgl@sss.pgh.pa.us 227 :UBC 0 : pq_send_ascii_string(StringInfo buf, const char *str)
228 : : {
229 [ # # ]: 0 : while (*str)
230 : : {
6032 bruce@momjian.us 231 : 0 : char ch = *str++;
232 : :
6133 tgl@sss.pgh.pa.us 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
8257 tgl@sss.pgh.pa.us 252 :CBC 3246 : pq_sendfloat4(StringInfo buf, float4 f)
253 : : {
254 : : union
255 : : {
256 : : float4 f;
257 : : uint32 i;
258 : : } swap;
259 : :
260 : 3246 : swap.f = f;
2988 andres@anarazel.de 261 : 3246 : pq_sendint32(buf, swap.i);
8257 tgl@sss.pgh.pa.us 262 : 3246 : }
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 : 2596 : pq_sendfloat8(StringInfo buf, float8 f)
277 : : {
278 : : union
279 : : {
280 : : float8 f;
281 : : int64 i;
282 : : } swap;
283 : :
284 : 2596 : swap.f = f;
285 : 2596 : pq_sendint64(buf, swap.i);
286 : 2596 : }
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
9732 296 : 595923 : pq_endmessage(StringInfo buf)
297 : : {
298 : : /* msgtype was saved in cursor field */
8274 299 : 595923 : (void) pq_putmessage(buf->cursor, buf->data, buf->len);
300 : : /* no need to complain about any failure, since pqcomm.c already did */
9732 301 : 595923 : pfree(buf->data);
302 : 595923 : buf->data = NULL;
303 : 595923 : }
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 : : void
2988 andres@anarazel.de 313 : 3933958 : pq_endmessage_reuse(StringInfo buf)
314 : : {
315 : : /* msgtype was saved in cursor field */
316 : 3933958 : (void) pq_putmessage(buf->cursor, buf->data, buf->len);
317 : 3933958 : }
318 : :
319 : :
320 : : /* --------------------------------
321 : : * pq_begintypsend - initialize for constructing a bytea result
322 : : * --------------------------------
323 : : */
324 : : void
8257 tgl@sss.pgh.pa.us 325 : 115515 : pq_begintypsend(StringInfo buf)
326 : : {
327 : 115515 : initStringInfo(buf);
328 : : /* Reserve four bytes for the bytea length word */
329 [ - + ]: 115515 : appendStringInfoCharMacro(buf, '\0');
330 [ - + ]: 115515 : appendStringInfoCharMacro(buf, '\0');
331 [ - + ]: 115515 : appendStringInfoCharMacro(buf, '\0');
332 [ - + ]: 115515 : appendStringInfoCharMacro(buf, '\0');
333 : 115515 : }
334 : :
335 : : /* --------------------------------
336 : : * pq_endtypsend - finish constructing a bytea result
337 : : *
338 : : * The data buffer is returned as the palloc'd bytea value. (We expect
339 : : * that it will be suitably aligned for this because it has been palloc'd.)
340 : : * We assume the StringInfoData is just a local variable in the caller and
341 : : * need not be pfree'd.
342 : : * --------------------------------
343 : : */
344 : : bytea *
345 : 115515 : pq_endtypsend(StringInfo buf)
346 : : {
347 : 115515 : bytea *result = (bytea *) buf->data;
348 : :
349 : : /* Insert correct length into bytea length word */
350 [ - + ]: 115515 : Assert(buf->len >= VARHDRSZ);
6867 351 : 115515 : SET_VARSIZE(result, buf->len);
352 : :
8257 353 : 115515 : return result;
354 : : }
355 : :
356 : :
357 : : /* --------------------------------
358 : : * pq_puttextmessage - generate a character set-converted message in one step
359 : : *
360 : : * This is the same as the pqcomm.c routine pq_putmessage, except that
361 : : * the message body is a null-terminated string to which encoding
362 : : * conversion applies.
363 : : * --------------------------------
364 : : */
365 : : void
9732 366 : 496 : pq_puttextmessage(char msgtype, const char *str)
367 : : {
9702 bruce@momjian.us 368 : 496 : int slen = strlen(str);
369 : : char *p;
370 : :
7388 tgl@sss.pgh.pa.us 371 : 496 : p = pg_server_to_client(str, slen);
9732 372 [ - + ]: 496 : if (p != str) /* actual conversion has been done? */
373 : : {
8274 tgl@sss.pgh.pa.us 374 :UBC 0 : (void) pq_putmessage(msgtype, p, strlen(p) + 1);
9593 375 : 0 : pfree(p);
8274 376 : 0 : return;
377 : : }
8274 tgl@sss.pgh.pa.us 378 :CBC 496 : (void) pq_putmessage(msgtype, str, slen + 1);
379 : : }
380 : :
381 : :
382 : : /* --------------------------------
383 : : * pq_putemptymessage - convenience routine for message with empty body
384 : : * --------------------------------
385 : : */
386 : : void
387 : 24756 : pq_putemptymessage(char msgtype)
388 : : {
389 : 24756 : (void) pq_putmessage(msgtype, NULL, 0);
9732 390 : 24756 : }
391 : :
392 : :
393 : : /* --------------------------------
394 : : * pq_getmsgbyte - get a raw byte from a message buffer
395 : : * --------------------------------
396 : : */
397 : : int
8277 398 : 1259505 : pq_getmsgbyte(StringInfo msg)
399 : : {
400 [ - + ]: 1259505 : if (msg->cursor >= msg->len)
8183 tgl@sss.pgh.pa.us 401 [ # # ]:UBC 0 : ereport(ERROR,
402 : : (errcode(ERRCODE_PROTOCOL_VIOLATION),
403 : : errmsg("no data left in message")));
8277 tgl@sss.pgh.pa.us 404 :CBC 1259505 : return (unsigned char) msg->data[msg->cursor++];
405 : : }
406 : :
407 : : /* --------------------------------
408 : : * pq_getmsgint - get a binary integer from a message buffer
409 : : *
410 : : * Values are treated as unsigned.
411 : : * --------------------------------
412 : : */
413 : : unsigned int
414 : 1295697 : pq_getmsgint(StringInfo msg, int b)
415 : : {
416 : : unsigned int result;
417 : : unsigned char n8;
418 : : uint16 n16;
419 : : uint32 n32;
420 : :
9732 421 [ + + + - ]: 1295697 : switch (b)
422 : : {
423 : 19 : case 1:
296 peter@eisentraut.org 424 : 19 : pq_copymsgbytes(msg, &n8, 1);
8277 tgl@sss.pgh.pa.us 425 : 19 : result = n8;
9732 426 : 19 : break;
427 : 517495 : case 2:
296 peter@eisentraut.org 428 : 517495 : pq_copymsgbytes(msg, &n16, 2);
2998 andres@anarazel.de 429 : 517495 : result = pg_ntoh16(n16);
9732 tgl@sss.pgh.pa.us 430 : 517495 : break;
431 : 778183 : case 4:
296 peter@eisentraut.org 432 : 778183 : pq_copymsgbytes(msg, &n32, 4);
2998 andres@anarazel.de 433 : 778183 : result = pg_ntoh32(n32);
9732 tgl@sss.pgh.pa.us 434 : 778183 : break;
9732 tgl@sss.pgh.pa.us 435 :UBC 0 : default:
8183 436 [ # # ]: 0 : elog(ERROR, "unsupported integer size %d", b);
437 : : result = 0; /* keep compiler quiet */
438 : : break;
439 : : }
8277 tgl@sss.pgh.pa.us 440 :CBC 1295697 : return result;
441 : : }
442 : :
443 : : /* --------------------------------
444 : : * pq_getmsgint64 - get a binary 8-byte int from a message buffer
445 : : *
446 : : * It is tempting to merge this with pq_getmsgint, but we'd have to make the
447 : : * result int64 for all data widths --- that could be a big performance
448 : : * hit on machines where int64 isn't efficient.
449 : : * --------------------------------
450 : : */
451 : : int64
8257 452 : 1275124 : pq_getmsgint64(StringInfo msg)
453 : : {
454 : : uint64 n64;
455 : :
296 peter@eisentraut.org 456 : 1275124 : pq_copymsgbytes(msg, &n64, sizeof(n64));
457 : :
2998 andres@anarazel.de 458 : 1275124 : return pg_ntoh64(n64);
459 : : }
460 : :
461 : : /* --------------------------------
462 : : * pq_getmsgfloat4 - get a float4 from a message buffer
463 : : *
464 : : * See notes for pq_sendfloat4.
465 : : * --------------------------------
466 : : */
467 : : float4
8257 tgl@sss.pgh.pa.us 468 :UBC 0 : pq_getmsgfloat4(StringInfo msg)
469 : : {
470 : : union
471 : : {
472 : : float4 f;
473 : : uint32 i;
474 : : } swap;
475 : :
476 : 0 : swap.i = pq_getmsgint(msg, 4);
477 : 0 : return swap.f;
478 : : }
479 : :
480 : : /* --------------------------------
481 : : * pq_getmsgfloat8 - get a float8 from a message buffer
482 : : *
483 : : * See notes for pq_sendfloat8.
484 : : * --------------------------------
485 : : */
486 : : float8
8257 tgl@sss.pgh.pa.us 487 :CBC 31 : pq_getmsgfloat8(StringInfo msg)
488 : : {
489 : : union
490 : : {
491 : : float8 f;
492 : : int64 i;
493 : : } swap;
494 : :
495 : 31 : swap.i = pq_getmsgint64(msg);
496 : 31 : return swap.f;
497 : : }
498 : :
499 : : /* --------------------------------
500 : : * pq_getmsgbytes - get raw data from a message buffer
501 : : *
502 : : * Returns a pointer directly into the message buffer; note this
503 : : * may not have any particular alignment.
504 : : * --------------------------------
505 : : */
506 : : const char *
8277 507 : 14950 : pq_getmsgbytes(StringInfo msg, int datalen)
508 : : {
509 : : const char *result;
510 : :
8258 511 [ + - - + ]: 14950 : if (datalen < 0 || datalen > (msg->len - msg->cursor))
8183 tgl@sss.pgh.pa.us 512 [ # # ]:UBC 0 : ereport(ERROR,
513 : : (errcode(ERRCODE_PROTOCOL_VIOLATION),
514 : : errmsg("insufficient data left in message")));
8277 tgl@sss.pgh.pa.us 515 :CBC 14950 : result = &msg->data[msg->cursor];
516 : 14950 : msg->cursor += datalen;
517 : 14950 : return result;
518 : : }
519 : :
520 : : /* --------------------------------
521 : : * pq_copymsgbytes - copy raw data from a message buffer
522 : : *
523 : : * Same as above, except data is copied to caller's buffer.
524 : : * --------------------------------
525 : : */
526 : : void
296 peter@eisentraut.org 527 : 3078051 : pq_copymsgbytes(StringInfo msg, void *buf, int datalen)
528 : : {
8258 tgl@sss.pgh.pa.us 529 [ + - - + ]: 3078051 : if (datalen < 0 || datalen > (msg->len - msg->cursor))
8183 tgl@sss.pgh.pa.us 530 [ # # ]:UBC 0 : ereport(ERROR,
531 : : (errcode(ERRCODE_PROTOCOL_VIOLATION),
532 : : errmsg("insufficient data left in message")));
8277 tgl@sss.pgh.pa.us 533 :CBC 3078051 : memcpy(buf, &msg->data[msg->cursor], datalen);
534 : 3078051 : msg->cursor += datalen;
535 : 3078051 : }
536 : :
537 : : /* --------------------------------
538 : : * pq_getmsgtext - get a counted text string (with conversion)
539 : : *
540 : : * Always returns a pointer to a freshly palloc'd result.
541 : : * The result has a trailing null, *and* we return its strlen in *nbytes.
542 : : * --------------------------------
543 : : */
544 : : char *
8257 545 : 28 : pq_getmsgtext(StringInfo msg, int rawbytes, int *nbytes)
546 : : {
547 : : char *str;
548 : : char *p;
549 : :
550 [ + - - + ]: 28 : if (rawbytes < 0 || rawbytes > (msg->len - msg->cursor))
8183 tgl@sss.pgh.pa.us 551 [ # # ]:UBC 0 : ereport(ERROR,
552 : : (errcode(ERRCODE_PROTOCOL_VIOLATION),
553 : : errmsg("insufficient data left in message")));
8257 tgl@sss.pgh.pa.us 554 :CBC 28 : str = &msg->data[msg->cursor];
555 : 28 : msg->cursor += rawbytes;
556 : :
7388 557 : 28 : p = pg_client_to_server(str, rawbytes);
8257 558 [ - + ]: 28 : if (p != str) /* actual conversion has been done? */
8257 tgl@sss.pgh.pa.us 559 :UBC 0 : *nbytes = strlen(p);
560 : : else
561 : : {
8257 tgl@sss.pgh.pa.us 562 :CBC 28 : p = (char *) palloc(rawbytes + 1);
563 : 28 : memcpy(p, str, rawbytes);
564 : 28 : p[rawbytes] = '\0';
565 : 28 : *nbytes = rawbytes;
566 : : }
567 : 28 : return p;
568 : : }
569 : :
570 : : /* --------------------------------
571 : : * pq_getmsgstring - get a null-terminated text string (with conversion)
572 : : *
573 : : * May return a pointer directly into the message buffer, or a pointer
574 : : * to a palloc'd conversion result.
575 : : * --------------------------------
576 : : */
577 : : const char *
8277 578 : 393742 : pq_getmsgstring(StringInfo msg)
579 : : {
580 : : char *str;
581 : : int slen;
582 : :
583 : 393742 : str = &msg->data[msg->cursor];
584 : :
585 : : /*
586 : : * It's safe to use strlen() here because a StringInfo is guaranteed to
587 : : * have a trailing null byte. But check we found a null inside the
588 : : * message.
589 : : */
590 : 393742 : slen = strlen(str);
591 [ - + ]: 393742 : if (msg->cursor + slen >= msg->len)
8183 tgl@sss.pgh.pa.us 592 [ # # ]:UBC 0 : ereport(ERROR,
593 : : (errcode(ERRCODE_PROTOCOL_VIOLATION),
594 : : errmsg("invalid string in message")));
8277 tgl@sss.pgh.pa.us 595 :CBC 393742 : msg->cursor += slen + 1;
596 : :
7388 597 : 393742 : return pg_client_to_server(str, slen);
598 : : }
599 : :
600 : : /* --------------------------------
601 : : * pq_getmsgrawstring - get a null-terminated text string - NO conversion
602 : : *
603 : : * Returns a pointer directly into the message buffer.
604 : : * --------------------------------
605 : : */
606 : : const char *
3456 rhaas@postgresql.org 607 : 214 : pq_getmsgrawstring(StringInfo msg)
608 : : {
609 : : char *str;
610 : : int slen;
611 : :
612 : 214 : str = &msg->data[msg->cursor];
613 : :
614 : : /*
615 : : * It's safe to use strlen() here because a StringInfo is guaranteed to
616 : : * have a trailing null byte. But check we found a null inside the
617 : : * message.
618 : : */
619 : 214 : slen = strlen(str);
620 [ - + ]: 214 : if (msg->cursor + slen >= msg->len)
3456 rhaas@postgresql.org 621 [ # # ]:UBC 0 : ereport(ERROR,
622 : : (errcode(ERRCODE_PROTOCOL_VIOLATION),
623 : : errmsg("invalid string in message")));
3456 rhaas@postgresql.org 624 :CBC 214 : msg->cursor += slen + 1;
625 : :
626 : 214 : return str;
627 : : }
628 : :
629 : : /* --------------------------------
630 : : * pq_getmsgend - verify message fully consumed
631 : : * --------------------------------
632 : : */
633 : : void
8277 tgl@sss.pgh.pa.us 634 : 389113 : pq_getmsgend(StringInfo msg)
635 : : {
636 [ - + ]: 389113 : if (msg->cursor != msg->len)
8183 tgl@sss.pgh.pa.us 637 [ # # ]:UBC 0 : ereport(ERROR,
638 : : (errcode(ERRCODE_PROTOCOL_VIOLATION),
639 : : errmsg("invalid message format")));
9732 tgl@sss.pgh.pa.us 640 :CBC 389113 : }
|