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