Coverage Report

Created: 2025-09-27 06:52

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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
}