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-2026, 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
8363 tgl@sss.pgh.pa.us 88 :CBC 650051 : pq_beginmessage(StringInfo buf, char msgtype)
89 : : {
90 : 650051 : 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 : 650051 : buf->cursor = msgtype;
98 : 650051 : }
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
3077 andres@anarazel.de 109 : 4772635 : pq_beginmessage_reuse(StringInfo buf, char msgtype)
110 : : {
111 : 4772635 : 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 : 4772635 : buf->cursor = msgtype;
9821 tgl@sss.pgh.pa.us 119 : 4772635 : }
120 : :
121 : : /* --------------------------------
122 : : * pq_sendbytes - append raw data to a StringInfo buffer
123 : : * --------------------------------
124 : : */
125 : : void
1125 peter@eisentraut.org 126 : 137672 : pq_sendbytes(StringInfo buf, const void *data, int datalen)
127 : : {
128 : : /* use variant that maintains a trailing null-byte, out of caution */
9821 tgl@sss.pgh.pa.us 129 : 137672 : appendBinaryStringInfo(buf, data, datalen);
130 : 137672 : }
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
741 heikki.linnakangas@i 142 : 22698513 : pq_sendcountedtext(StringInfo buf, const char *str, int slen)
143 : : {
144 : : char *p;
145 : :
7477 tgl@sss.pgh.pa.us 146 : 22698513 : p = pg_server_to_client(str, slen);
9821 147 [ + + ]: 22698513 : if (p != str) /* actual conversion has been done? */
148 : : {
9682 149 : 28 : slen = strlen(p);
741 heikki.linnakangas@i 150 : 28 : pq_sendint32(buf, slen);
3077 andres@anarazel.de 151 : 28 : appendBinaryStringInfoNT(buf, p, slen);
9682 tgl@sss.pgh.pa.us 152 : 28 : pfree(p);
153 : : }
154 : : else
155 : : {
741 heikki.linnakangas@i 156 : 22698485 : pq_sendint32(buf, slen);
3077 andres@anarazel.de 157 : 22698485 : appendBinaryStringInfoNT(buf, str, slen);
158 : : }
9821 tgl@sss.pgh.pa.us 159 : 22698513 : }
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
8346 172 : 2356 : pq_sendtext(StringInfo buf, const char *str, int slen)
173 : : {
174 : : char *p;
175 : :
7477 176 : 2356 : p = pg_server_to_client(str, slen);
8346 177 [ - + ]: 2356 : if (p != str) /* actual conversion has been done? */
178 : : {
8346 tgl@sss.pgh.pa.us 179 :UBC 0 : slen = strlen(p);
180 : 0 : appendBinaryStringInfo(buf, p, slen);
181 : 0 : pfree(p);
182 : : }
183 : : else
8346 tgl@sss.pgh.pa.us 184 :CBC 2356 : appendBinaryStringInfo(buf, str, slen);
185 : 2356 : }
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
9821 195 : 730362 : pq_sendstring(StringInfo buf, const char *str)
196 : : {
9791 bruce@momjian.us 197 : 730362 : int slen = strlen(str);
198 : : char *p;
199 : :
7477 tgl@sss.pgh.pa.us 200 : 730362 : p = pg_server_to_client(str, slen);
9821 201 [ + + ]: 730362 : if (p != str) /* actual conversion has been done? */
202 : : {
9682 203 : 147 : slen = strlen(p);
3077 andres@anarazel.de 204 : 147 : appendBinaryStringInfoNT(buf, p, slen + 1);
9682 tgl@sss.pgh.pa.us 205 : 147 : pfree(p);
206 : : }
207 : : else
3077 andres@anarazel.de 208 : 730215 : appendBinaryStringInfoNT(buf, str, slen + 1);
9821 tgl@sss.pgh.pa.us 209 : 730362 : }
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
6222 tgl@sss.pgh.pa.us 227 :UBC 0 : pq_send_ascii_string(StringInfo buf, const char *str)
228 : : {
229 [ # # ]: 0 : while (*str)
230 : : {
6121 bruce@momjian.us 231 : 0 : char ch = *str++;
232 : :
6222 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
8346 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;
3077 andres@anarazel.de 261 : 3246 : pq_sendint32(buf, swap.i);
8346 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
9821 296 : 650039 : pq_endmessage(StringInfo buf)
297 : : {
298 : : /* msgtype was saved in cursor field */
8363 299 : 650039 : (void) pq_putmessage(buf->cursor, buf->data, buf->len);
300 : : /* no need to complain about any failure, since pqcomm.c already did */
9821 301 : 650039 : pfree(buf->data);
302 : 650039 : buf->data = NULL;
303 : 650039 : }
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
3077 andres@anarazel.de 313 : 4772581 : pq_endmessage_reuse(StringInfo buf)
314 : : {
315 : : /* msgtype was saved in cursor field */
316 : 4772581 : (void) pq_putmessage(buf->cursor, buf->data, buf->len);
317 : 4772581 : }
318 : :
319 : :
320 : : /* --------------------------------
321 : : * pq_begintypsend - initialize for constructing a bytea result
322 : : * --------------------------------
323 : : */
324 : : void
8346 tgl@sss.pgh.pa.us 325 : 115502 : pq_begintypsend(StringInfo buf)
326 : : {
327 : 115502 : initStringInfo(buf);
328 : : /* Reserve four bytes for the bytea length word */
329 [ - + ]: 115502 : appendStringInfoCharMacro(buf, '\0');
330 [ - + ]: 115502 : appendStringInfoCharMacro(buf, '\0');
331 [ - + ]: 115502 : appendStringInfoCharMacro(buf, '\0');
332 [ - + ]: 115502 : appendStringInfoCharMacro(buf, '\0');
333 : 115502 : }
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 : 115502 : pq_endtypsend(StringInfo buf)
346 : : {
347 : 115502 : bytea *result = (bytea *) buf->data;
348 : :
349 : : /* Insert correct length into bytea length word */
350 [ - + ]: 115502 : Assert(buf->len >= VARHDRSZ);
6956 351 : 115502 : SET_VARSIZE(result, buf->len);
352 : :
8346 353 : 115502 : 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
9821 366 : 523 : pq_puttextmessage(char msgtype, const char *str)
367 : : {
9791 bruce@momjian.us 368 : 523 : int slen = strlen(str);
369 : : char *p;
370 : :
7477 tgl@sss.pgh.pa.us 371 : 523 : p = pg_server_to_client(str, slen);
9821 372 [ - + ]: 523 : if (p != str) /* actual conversion has been done? */
373 : : {
8363 tgl@sss.pgh.pa.us 374 :UBC 0 : (void) pq_putmessage(msgtype, p, strlen(p) + 1);
9682 375 : 0 : pfree(p);
8363 376 : 0 : return;
377 : : }
8363 tgl@sss.pgh.pa.us 378 :CBC 523 : (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 : 25229 : pq_putemptymessage(char msgtype)
388 : : {
389 : 25229 : (void) pq_putmessage(msgtype, NULL, 0);
9821 390 : 25229 : }
391 : :
392 : :
393 : : /* --------------------------------
394 : : * pq_getmsgbyte - get a raw byte from a message buffer
395 : : * --------------------------------
396 : : */
397 : : int
8366 398 : 1264972 : pq_getmsgbyte(StringInfo msg)
399 : : {
400 [ - + ]: 1264972 : if (msg->cursor >= msg->len)
8272 tgl@sss.pgh.pa.us 401 [ # # ]:UBC 0 : ereport(ERROR,
402 : : (errcode(ERRCODE_PROTOCOL_VIOLATION),
403 : : errmsg("no data left in message")));
8366 tgl@sss.pgh.pa.us 404 :CBC 1264972 : 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 : 1297262 : pq_getmsgint(StringInfo msg, int b)
415 : : {
416 : : unsigned int result;
417 : : unsigned char n8;
418 : : uint16 n16;
419 : : uint32 n32;
420 : :
9821 421 [ + + + - ]: 1297262 : switch (b)
422 : : {
423 : 20 : case 1:
385 peter@eisentraut.org 424 : 20 : pq_copymsgbytes(msg, &n8, 1);
8366 tgl@sss.pgh.pa.us 425 : 20 : result = n8;
9821 426 : 20 : break;
427 : 518225 : case 2:
385 peter@eisentraut.org 428 : 518225 : pq_copymsgbytes(msg, &n16, 2);
3087 andres@anarazel.de 429 : 518225 : result = pg_ntoh16(n16);
9821 tgl@sss.pgh.pa.us 430 : 518225 : break;
431 : 779017 : case 4:
385 peter@eisentraut.org 432 : 779017 : pq_copymsgbytes(msg, &n32, 4);
3087 andres@anarazel.de 433 : 779017 : result = pg_ntoh32(n32);
9821 tgl@sss.pgh.pa.us 434 : 779017 : break;
9821 tgl@sss.pgh.pa.us 435 :UBC 0 : default:
8272 436 [ # # ]: 0 : elog(ERROR, "unsupported integer size %d", b);
437 : : result = 0; /* keep compiler quiet */
438 : : break;
439 : : }
8366 tgl@sss.pgh.pa.us 440 :CBC 1297262 : 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
8346 452 : 1290082 : pq_getmsgint64(StringInfo msg)
453 : : {
454 : : uint64 n64;
455 : :
385 peter@eisentraut.org 456 : 1290082 : pq_copymsgbytes(msg, &n64, sizeof(n64));
457 : :
3087 andres@anarazel.de 458 : 1290082 : 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
8346 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
8346 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 *
8366 507 : 15118 : pq_getmsgbytes(StringInfo msg, int datalen)
508 : : {
509 : : const char *result;
510 : :
8347 511 [ + - - + ]: 15118 : if (datalen < 0 || datalen > (msg->len - msg->cursor))
8272 tgl@sss.pgh.pa.us 512 [ # # ]:UBC 0 : ereport(ERROR,
513 : : (errcode(ERRCODE_PROTOCOL_VIOLATION),
514 : : errmsg("insufficient data left in message")));
8366 tgl@sss.pgh.pa.us 515 :CBC 15118 : result = &msg->data[msg->cursor];
516 : 15118 : msg->cursor += datalen;
517 : 15118 : 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
385 peter@eisentraut.org 527 : 3094738 : pq_copymsgbytes(StringInfo msg, void *buf, int datalen)
528 : : {
8347 tgl@sss.pgh.pa.us 529 [ + - - + ]: 3094738 : if (datalen < 0 || datalen > (msg->len - msg->cursor))
8272 tgl@sss.pgh.pa.us 530 [ # # ]:UBC 0 : ereport(ERROR,
531 : : (errcode(ERRCODE_PROTOCOL_VIOLATION),
532 : : errmsg("insufficient data left in message")));
8366 tgl@sss.pgh.pa.us 533 :CBC 3094738 : memcpy(buf, &msg->data[msg->cursor], datalen);
534 : 3094738 : msg->cursor += datalen;
535 : 3094738 : }
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 *
8346 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))
8272 tgl@sss.pgh.pa.us 551 [ # # ]:UBC 0 : ereport(ERROR,
552 : : (errcode(ERRCODE_PROTOCOL_VIOLATION),
553 : : errmsg("insufficient data left in message")));
8346 tgl@sss.pgh.pa.us 554 :CBC 28 : str = &msg->data[msg->cursor];
555 : 28 : msg->cursor += rawbytes;
556 : :
7477 557 : 28 : p = pg_client_to_server(str, rawbytes);
8346 558 [ - + ]: 28 : if (p != str) /* actual conversion has been done? */
8346 tgl@sss.pgh.pa.us 559 :UBC 0 : *nbytes = strlen(p);
560 : : else
561 : : {
8346 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 *
8366 578 : 404035 : pq_getmsgstring(StringInfo msg)
579 : : {
580 : : char *str;
581 : : int slen;
582 : :
583 : 404035 : 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 : 404035 : slen = strlen(str);
591 [ - + ]: 404035 : if (msg->cursor + slen >= msg->len)
8272 tgl@sss.pgh.pa.us 592 [ # # ]:UBC 0 : ereport(ERROR,
593 : : (errcode(ERRCODE_PROTOCOL_VIOLATION),
594 : : errmsg("invalid string in message")));
8366 tgl@sss.pgh.pa.us 595 :CBC 404035 : msg->cursor += slen + 1;
596 : :
7477 597 : 404035 : 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 *
3545 rhaas@postgresql.org 607 : 234 : pq_getmsgrawstring(StringInfo msg)
608 : : {
609 : : char *str;
610 : : int slen;
611 : :
612 : 234 : 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 : 234 : slen = strlen(str);
620 [ - + ]: 234 : if (msg->cursor + slen >= msg->len)
3545 rhaas@postgresql.org 621 [ # # ]:UBC 0 : ereport(ERROR,
622 : : (errcode(ERRCODE_PROTOCOL_VIOLATION),
623 : : errmsg("invalid string in message")));
3545 rhaas@postgresql.org 624 :CBC 234 : msg->cursor += slen + 1;
625 : :
626 : 234 : return str;
627 : : }
628 : :
629 : : /* --------------------------------
630 : : * pq_getmsgend - verify message fully consumed
631 : : * --------------------------------
632 : : */
633 : : void
8366 tgl@sss.pgh.pa.us 634 : 399315 : pq_getmsgend(StringInfo msg)
635 : : {
636 [ - + ]: 399315 : if (msg->cursor != msg->len)
8272 tgl@sss.pgh.pa.us 637 [ # # ]:UBC 0 : ereport(ERROR,
638 : : (errcode(ERRCODE_PROTOCOL_VIOLATION),
639 : : errmsg("invalid message format")));
9821 tgl@sss.pgh.pa.us 640 :CBC 399315 : }
|