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-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
7663 tgl@sss.pgh.pa.us 88 :CBC 575132 : pq_beginmessage(StringInfo buf, char msgtype)
89 : : {
90 : 575132 : 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 : 575132 : buf->cursor = msgtype;
98 : 575132 : }
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
2377 andres@anarazel.de 109 : 3344844 : pq_beginmessage_reuse(StringInfo buf, char msgtype)
110 : : {
111 : 3344844 : 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 : 3344844 : buf->cursor = msgtype;
9121 tgl@sss.pgh.pa.us 119 : 3344844 : }
120 : :
121 : : /* --------------------------------
122 : : * pq_sendbytes - append raw data to a StringInfo buffer
123 : : * --------------------------------
124 : : */
125 : : void
425 peter@eisentraut.org 126 : 124130 : pq_sendbytes(StringInfo buf, const void *data, int datalen)
127 : : {
128 : : /* use variant that maintains a trailing null-byte, out of caution */
9121 tgl@sss.pgh.pa.us 129 : 124130 : appendBinaryStringInfo(buf, data, datalen);
130 : 124130 : }
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
41 heikki.linnakangas@i 142 :GNC 13818121 : pq_sendcountedtext(StringInfo buf, const char *str, int slen)
143 : : {
144 : : char *p;
145 : :
6777 tgl@sss.pgh.pa.us 146 :CBC 13818121 : p = pg_server_to_client(str, slen);
9121 147 [ + + ]: 13818121 : if (p != str) /* actual conversion has been done? */
148 : : {
8982 149 : 25 : slen = strlen(p);
41 heikki.linnakangas@i 150 :GNC 25 : pq_sendint32(buf, slen);
2377 andres@anarazel.de 151 :CBC 25 : appendBinaryStringInfoNT(buf, p, slen);
8982 tgl@sss.pgh.pa.us 152 : 25 : pfree(p);
153 : : }
154 : : else
155 : : {
41 heikki.linnakangas@i 156 :GNC 13818096 : pq_sendint32(buf, slen);
2377 andres@anarazel.de 157 :CBC 13818096 : appendBinaryStringInfoNT(buf, str, slen);
158 : : }
9121 tgl@sss.pgh.pa.us 159 : 13818121 : }
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
7646 172 : 2456 : pq_sendtext(StringInfo buf, const char *str, int slen)
173 : : {
174 : : char *p;
175 : :
6777 176 : 2456 : p = pg_server_to_client(str, slen);
7646 177 [ - + ]: 2456 : if (p != str) /* actual conversion has been done? */
178 : : {
7646 tgl@sss.pgh.pa.us 179 :UBC 0 : slen = strlen(p);
180 : 0 : appendBinaryStringInfo(buf, p, slen);
181 : 0 : pfree(p);
182 : : }
183 : : else
7646 tgl@sss.pgh.pa.us 184 :CBC 2456 : appendBinaryStringInfo(buf, str, slen);
185 : 2456 : }
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
9121 195 : 1100603 : pq_sendstring(StringInfo buf, const char *str)
196 : : {
9091 bruce@momjian.us 197 : 1100603 : int slen = strlen(str);
198 : : char *p;
199 : :
6777 tgl@sss.pgh.pa.us 200 : 1100603 : p = pg_server_to_client(str, slen);
9121 201 [ + + ]: 1100603 : if (p != str) /* actual conversion has been done? */
202 : : {
8982 203 : 102 : slen = strlen(p);
2377 andres@anarazel.de 204 : 102 : appendBinaryStringInfoNT(buf, p, slen + 1);
8982 tgl@sss.pgh.pa.us 205 : 102 : pfree(p);
206 : : }
207 : : else
2377 andres@anarazel.de 208 : 1100501 : appendBinaryStringInfoNT(buf, str, slen + 1);
9121 tgl@sss.pgh.pa.us 209 : 1100603 : }
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
5522 tgl@sss.pgh.pa.us 227 :UBC 0 : pq_send_ascii_string(StringInfo buf, const char *str)
228 : : {
229 [ # # ]: 0 : while (*str)
230 : : {
5421 bruce@momjian.us 231 : 0 : char ch = *str++;
232 : :
5522 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
7646 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;
2377 andres@anarazel.de 261 : 3246 : pq_sendint32(buf, swap.i);
7646 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
9121 296 : 575124 : pq_endmessage(StringInfo buf)
297 : : {
298 : : /* msgtype was saved in cursor field */
7663 299 : 575124 : (void) pq_putmessage(buf->cursor, buf->data, buf->len);
300 : : /* no need to complain about any failure, since pqcomm.c already did */
9121 301 : 575124 : pfree(buf->data);
302 : 575124 : buf->data = NULL;
303 : 575124 : }
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
2377 andres@anarazel.de 314 : 3344792 : pq_endmessage_reuse(StringInfo buf)
315 : : {
316 : : /* msgtype was saved in cursor field */
317 : 3344792 : (void) pq_putmessage(buf->cursor, buf->data, buf->len);
318 : 3344792 : }
319 : :
320 : :
321 : : /* --------------------------------
322 : : * pq_begintypsend - initialize for constructing a bytea result
323 : : * --------------------------------
324 : : */
325 : : void
7646 tgl@sss.pgh.pa.us 326 : 95210 : pq_begintypsend(StringInfo buf)
327 : : {
328 : 95210 : initStringInfo(buf);
329 : : /* Reserve four bytes for the bytea length word */
330 [ - + ]: 95210 : appendStringInfoCharMacro(buf, '\0');
331 [ - + ]: 95210 : appendStringInfoCharMacro(buf, '\0');
332 [ - + ]: 95210 : appendStringInfoCharMacro(buf, '\0');
333 [ - + ]: 95210 : appendStringInfoCharMacro(buf, '\0');
334 : 95210 : }
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 : 95210 : pq_endtypsend(StringInfo buf)
347 : : {
348 : 95210 : bytea *result = (bytea *) buf->data;
349 : :
350 : : /* Insert correct length into bytea length word */
351 [ - + ]: 95210 : Assert(buf->len >= VARHDRSZ);
6256 352 : 95210 : SET_VARSIZE(result, buf->len);
353 : :
7646 354 : 95210 : 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
9121 367 : 441 : pq_puttextmessage(char msgtype, const char *str)
368 : : {
9091 bruce@momjian.us 369 : 441 : int slen = strlen(str);
370 : : char *p;
371 : :
6777 tgl@sss.pgh.pa.us 372 : 441 : p = pg_server_to_client(str, slen);
9121 373 [ - + ]: 441 : if (p != str) /* actual conversion has been done? */
374 : : {
7663 tgl@sss.pgh.pa.us 375 :UBC 0 : (void) pq_putmessage(msgtype, p, strlen(p) + 1);
8982 376 : 0 : pfree(p);
7663 377 : 0 : return;
378 : : }
7663 tgl@sss.pgh.pa.us 379 :CBC 441 : (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 : 21634 : pq_putemptymessage(char msgtype)
389 : : {
390 : 21634 : (void) pq_putmessage(msgtype, NULL, 0);
9121 391 : 21634 : }
392 : :
393 : :
394 : : /* --------------------------------
395 : : * pq_getmsgbyte - get a raw byte from a message buffer
396 : : * --------------------------------
397 : : */
398 : : int
7666 399 : 1271753 : pq_getmsgbyte(StringInfo msg)
400 : : {
401 [ - + ]: 1271753 : if (msg->cursor >= msg->len)
7572 tgl@sss.pgh.pa.us 402 [ # # ]:UBC 0 : ereport(ERROR,
403 : : (errcode(ERRCODE_PROTOCOL_VIOLATION),
404 : : errmsg("no data left in message")));
7666 tgl@sss.pgh.pa.us 405 :CBC 1271753 : 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 : 1298785 : pq_getmsgint(StringInfo msg, int b)
416 : : {
417 : : unsigned int result;
418 : : unsigned char n8;
419 : : uint16 n16;
420 : : uint32 n32;
421 : :
9121 422 [ + + + - ]: 1298785 : switch (b)
423 : : {
424 : 19 : case 1:
7666 425 : 19 : pq_copymsgbytes(msg, (char *) &n8, 1);
426 : 19 : result = n8;
9121 427 : 19 : break;
428 : 516595 : case 2:
7666 429 : 516595 : pq_copymsgbytes(msg, (char *) &n16, 2);
2387 andres@anarazel.de 430 : 516595 : result = pg_ntoh16(n16);
9121 tgl@sss.pgh.pa.us 431 : 516595 : break;
432 : 782171 : case 4:
7666 433 : 782171 : pq_copymsgbytes(msg, (char *) &n32, 4);
2387 andres@anarazel.de 434 : 782171 : result = pg_ntoh32(n32);
9121 tgl@sss.pgh.pa.us 435 : 782171 : break;
9121 tgl@sss.pgh.pa.us 436 :UBC 0 : default:
7572 437 [ # # ]: 0 : elog(ERROR, "unsupported integer size %d", b);
438 : : result = 0; /* keep compiler quiet */
439 : : break;
440 : : }
7666 tgl@sss.pgh.pa.us 441 :CBC 1298785 : 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
7646 453 : 1054003 : pq_getmsgint64(StringInfo msg)
454 : : {
455 : : uint64 n64;
456 : :
2387 andres@anarazel.de 457 : 1054003 : pq_copymsgbytes(msg, (char *) &n64, sizeof(n64));
458 : :
459 : 1054003 : 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
7646 tgl@sss.pgh.pa.us 469 :UBC 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
7646 tgl@sss.pgh.pa.us 488 :CBC 31 : pq_getmsgfloat8(StringInfo msg)
489 : : {
490 : : union
491 : : {
492 : : float8 f;
493 : : int64 i;
494 : : } swap;
495 : :
496 : 31 : swap.i = pq_getmsgint64(msg);
497 : 31 : 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 *
7666 508 : 14263 : pq_getmsgbytes(StringInfo msg, int datalen)
509 : : {
510 : : const char *result;
511 : :
7647 512 [ + - - + ]: 14263 : if (datalen < 0 || datalen > (msg->len - msg->cursor))
7572 tgl@sss.pgh.pa.us 513 [ # # ]:UBC 0 : ereport(ERROR,
514 : : (errcode(ERRCODE_PROTOCOL_VIOLATION),
515 : : errmsg("insufficient data left in message")));
7666 tgl@sss.pgh.pa.us 516 :CBC 14263 : result = &msg->data[msg->cursor];
517 : 14263 : msg->cursor += datalen;
518 : 14263 : 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 : 2862605 : pq_copymsgbytes(StringInfo msg, char *buf, int datalen)
529 : : {
7647 530 [ + - - + ]: 2862605 : if (datalen < 0 || datalen > (msg->len - msg->cursor))
7572 tgl@sss.pgh.pa.us 531 [ # # ]:UBC 0 : ereport(ERROR,
532 : : (errcode(ERRCODE_PROTOCOL_VIOLATION),
533 : : errmsg("insufficient data left in message")));
7666 tgl@sss.pgh.pa.us 534 :CBC 2862605 : memcpy(buf, &msg->data[msg->cursor], datalen);
535 : 2862605 : msg->cursor += datalen;
536 : 2862605 : }
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 *
7646 546 : 28 : pq_getmsgtext(StringInfo msg, int rawbytes, int *nbytes)
547 : : {
548 : : char *str;
549 : : char *p;
550 : :
551 [ + - - + ]: 28 : if (rawbytes < 0 || rawbytes > (msg->len - msg->cursor))
7572 tgl@sss.pgh.pa.us 552 [ # # ]:UBC 0 : ereport(ERROR,
553 : : (errcode(ERRCODE_PROTOCOL_VIOLATION),
554 : : errmsg("insufficient data left in message")));
7646 tgl@sss.pgh.pa.us 555 :CBC 28 : str = &msg->data[msg->cursor];
556 : 28 : msg->cursor += rawbytes;
557 : :
6777 558 : 28 : p = pg_client_to_server(str, rawbytes);
7646 559 [ - + ]: 28 : if (p != str) /* actual conversion has been done? */
7646 tgl@sss.pgh.pa.us 560 :UBC 0 : *nbytes = strlen(p);
561 : : else
562 : : {
7646 tgl@sss.pgh.pa.us 563 :CBC 28 : p = (char *) palloc(rawbytes + 1);
564 : 28 : memcpy(p, str, rawbytes);
565 : 28 : p[rawbytes] = '\0';
566 : 28 : *nbytes = rawbytes;
567 : : }
568 : 28 : 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 *
7666 579 : 335864 : pq_getmsgstring(StringInfo msg)
580 : : {
581 : : char *str;
582 : : int slen;
583 : :
584 : 335864 : 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 : 335864 : slen = strlen(str);
592 [ - + ]: 335864 : if (msg->cursor + slen >= msg->len)
7572 tgl@sss.pgh.pa.us 593 [ # # ]:UBC 0 : ereport(ERROR,
594 : : (errcode(ERRCODE_PROTOCOL_VIOLATION),
595 : : errmsg("invalid string in message")));
7666 tgl@sss.pgh.pa.us 596 :CBC 335864 : msg->cursor += slen + 1;
597 : :
6777 598 : 335864 : 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 *
2845 rhaas@postgresql.org 608 : 81 : pq_getmsgrawstring(StringInfo msg)
609 : : {
610 : : char *str;
611 : : int slen;
612 : :
613 : 81 : 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 : 81 : slen = strlen(str);
621 [ - + ]: 81 : if (msg->cursor + slen >= msg->len)
2845 rhaas@postgresql.org 622 [ # # ]:UBC 0 : ereport(ERROR,
623 : : (errcode(ERRCODE_PROTOCOL_VIOLATION),
624 : : errmsg("invalid string in message")));
2845 rhaas@postgresql.org 625 :CBC 81 : msg->cursor += slen + 1;
626 : :
627 : 81 : return str;
628 : : }
629 : :
630 : : /* --------------------------------
631 : : * pq_getmsgend - verify message fully consumed
632 : : * --------------------------------
633 : : */
634 : : void
7666 tgl@sss.pgh.pa.us 635 : 331722 : pq_getmsgend(StringInfo msg)
636 : : {
637 [ - + ]: 331722 : if (msg->cursor != msg->len)
7572 tgl@sss.pgh.pa.us 638 [ # # ]:UBC 0 : ereport(ERROR,
639 : : (errcode(ERRCODE_PROTOCOL_VIOLATION),
640 : : errmsg("invalid message format")));
9121 tgl@sss.pgh.pa.us 641 :CBC 331722 : }
|