LCOV - code coverage report
Current view: top level - src/backend/libpq - pqformat.c (source / functions) Coverage Total Hit
Test: PostgreSQL 19devel Lines: 82.8 % 157 130
Test Date: 2026-03-13 06:15:19 Functions: 92.3 % 26 24
Legend: Lines:     hit not hit

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

Generated by: LCOV version 2.0-1