LCOV - code coverage report
Current view: top level - src/backend/libpq - pqformat.c (source / functions) Hit Total Coverage
Test: PostgreSQL 19devel Lines: 130 157 82.8 %
Date: 2025-12-13 10:19:04 Functions: 24 26 92.3 %
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-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     1357972 : pq_beginmessage(StringInfo buf, char msgtype)
      89             : {
      90     1357972 :     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     1357972 :     buf->cursor = msgtype;
      98     1357972 : }
      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     7294508 : pq_beginmessage_reuse(StringInfo buf, char msgtype)
     110             : {
     111     7294508 :     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     7294508 :     buf->cursor = msgtype;
     119     7294508 : }
     120             : 
     121             : /* --------------------------------
     122             :  *      pq_sendbytes    - append raw data to a StringInfo buffer
     123             :  * --------------------------------
     124             :  */
     125             : void
     126      274222 : pq_sendbytes(StringInfo buf, const void *data, int datalen)
     127             : {
     128             :     /* use variant that maintains a trailing null-byte, out of caution */
     129      274222 :     appendBinaryStringInfo(buf, data, datalen);
     130      274222 : }
     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    33162768 : pq_sendcountedtext(StringInfo buf, const char *str, int slen)
     143             : {
     144             :     char       *p;
     145             : 
     146    33162768 :     p = pg_server_to_client(str, slen);
     147    33162768 :     if (p != str)               /* actual conversion has been done? */
     148             :     {
     149          56 :         slen = strlen(p);
     150          56 :         pq_sendint32(buf, slen);
     151          56 :         appendBinaryStringInfoNT(buf, p, slen);
     152          56 :         pfree(p);
     153             :     }
     154             :     else
     155             :     {
     156    33162712 :         pq_sendint32(buf, slen);
     157    33162712 :         appendBinaryStringInfoNT(buf, str, slen);
     158             :     }
     159    33162768 : }
     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        4760 : pq_sendtext(StringInfo buf, const char *str, int slen)
     173             : {
     174             :     char       *p;
     175             : 
     176        4760 :     p = pg_server_to_client(str, slen);
     177        4760 :     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        4760 :         appendBinaryStringInfo(buf, str, slen);
     185        4760 : }
     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     2445822 : pq_sendstring(StringInfo buf, const char *str)
     196             : {
     197     2445822 :     int         slen = strlen(str);
     198             :     char       *p;
     199             : 
     200     2445822 :     p = pg_server_to_client(str, slen);
     201     2445822 :     if (p != str)               /* actual conversion has been done? */
     202             :     {
     203         294 :         slen = strlen(p);
     204         294 :         appendBinaryStringInfoNT(buf, p, slen + 1);
     205         294 :         pfree(p);
     206             :     }
     207             :     else
     208     2445528 :         appendBinaryStringInfoNT(buf, str, slen + 1);
     209     2445822 : }
     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        6492 : pq_sendfloat4(StringInfo buf, float4 f)
     253             : {
     254             :     union
     255             :     {
     256             :         float4      f;
     257             :         uint32      i;
     258             :     }           swap;
     259             : 
     260        6492 :     swap.f = f;
     261        6492 :     pq_sendint32(buf, swap.i);
     262        6492 : }
     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        5192 : pq_sendfloat8(StringInfo buf, float8 f)
     277             : {
     278             :     union
     279             :     {
     280             :         float8      f;
     281             :         int64       i;
     282             :     }           swap;
     283             : 
     284        5192 :     swap.f = f;
     285        5192 :     pq_sendint64(buf, swap.i);
     286        5192 : }
     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     1357950 : pq_endmessage(StringInfo buf)
     297             : {
     298             :     /* msgtype was saved in cursor field */
     299     1357950 :     (void) pq_putmessage(buf->cursor, buf->data, buf->len);
     300             :     /* no need to complain about any failure, since pqcomm.c already did */
     301     1357950 :     pfree(buf->data);
     302     1357950 :     buf->data = NULL;
     303     1357950 : }
     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     7294410 : pq_endmessage_reuse(StringInfo buf)
     314             : {
     315             :     /* msgtype was saved in cursor field */
     316     7294410 :     (void) pq_putmessage(buf->cursor, buf->data, buf->len);
     317     7294410 : }
     318             : 
     319             : 
     320             : /* --------------------------------
     321             :  *      pq_begintypsend     - initialize for constructing a bytea result
     322             :  * --------------------------------
     323             :  */
     324             : void
     325      231080 : pq_begintypsend(StringInfo buf)
     326             : {
     327      231080 :     initStringInfo(buf);
     328             :     /* Reserve four bytes for the bytea length word */
     329      231080 :     appendStringInfoCharMacro(buf, '\0');
     330      231080 :     appendStringInfoCharMacro(buf, '\0');
     331      231080 :     appendStringInfoCharMacro(buf, '\0');
     332      231080 :     appendStringInfoCharMacro(buf, '\0');
     333      231080 : }
     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      231080 : pq_endtypsend(StringInfo buf)
     346             : {
     347      231080 :     bytea      *result = (bytea *) buf->data;
     348             : 
     349             :     /* Insert correct length into bytea length word */
     350             :     Assert(buf->len >= VARHDRSZ);
     351      231080 :     SET_VARSIZE(result, buf->len);
     352             : 
     353      231080 :     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         968 : pq_puttextmessage(char msgtype, const char *str)
     367             : {
     368         968 :     int         slen = strlen(str);
     369             :     char       *p;
     370             : 
     371         968 :     p = pg_server_to_client(str, slen);
     372         968 :     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         968 :     (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       57146 : pq_putemptymessage(char msgtype)
     388             : {
     389       57146 :     (void) pq_putmessage(msgtype, NULL, 0);
     390       57146 : }
     391             : 
     392             : 
     393             : /* --------------------------------
     394             :  *      pq_getmsgbyte   - get a raw byte from a message buffer
     395             :  * --------------------------------
     396             :  */
     397             : int
     398     2630048 : pq_getmsgbyte(StringInfo msg)
     399             : {
     400     2630048 :     if (msg->cursor >= msg->len)
     401           0 :         ereport(ERROR,
     402             :                 (errcode(ERRCODE_PROTOCOL_VIOLATION),
     403             :                  errmsg("no data left in message")));
     404     2630048 :     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     2615896 : pq_getmsgint(StringInfo msg, int b)
     415             : {
     416             :     unsigned int result;
     417             :     unsigned char n8;
     418             :     uint16      n16;
     419             :     uint32      n32;
     420             : 
     421     2615896 :     switch (b)
     422             :     {
     423          40 :         case 1:
     424          40 :             pq_copymsgbytes(msg, &n8, 1);
     425          40 :             result = n8;
     426          40 :             break;
     427     1052048 :         case 2:
     428     1052048 :             pq_copymsgbytes(msg, &n16, 2);
     429     1052048 :             result = pg_ntoh16(n16);
     430     1052048 :             break;
     431     1563808 :         case 4:
     432     1563808 :             pq_copymsgbytes(msg, &n32, 4);
     433     1563808 :             result = pg_ntoh32(n32);
     434     1563808 :             break;
     435           0 :         default:
     436           0 :             elog(ERROR, "unsupported integer size %d", b);
     437             :             result = 0;         /* keep compiler quiet */
     438             :             break;
     439             :     }
     440     2615896 :     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     2734680 : pq_getmsgint64(StringInfo msg)
     453             : {
     454             :     uint64      n64;
     455             : 
     456     2734680 :     pq_copymsgbytes(msg, &n64, sizeof(n64));
     457             : 
     458     2734680 :     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          62 : pq_getmsgfloat8(StringInfo msg)
     488             : {
     489             :     union
     490             :     {
     491             :         float8      f;
     492             :         int64       i;
     493             :     }           swap;
     494             : 
     495          62 :     swap.i = pq_getmsgint64(msg);
     496          62 :     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       33132 : pq_getmsgbytes(StringInfo msg, int datalen)
     508             : {
     509             :     const char *result;
     510             : 
     511       33132 :     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       33132 :     result = &msg->data[msg->cursor];
     516       33132 :     msg->cursor += datalen;
     517       33132 :     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     6365244 : pq_copymsgbytes(StringInfo msg, void *buf, int datalen)
     528             : {
     529     6365244 :     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     6365244 :     memcpy(buf, &msg->data[msg->cursor], datalen);
     534     6365244 :     msg->cursor += datalen;
     535     6365244 : }
     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          56 : pq_getmsgtext(StringInfo msg, int rawbytes, int *nbytes)
     546             : {
     547             :     char       *str;
     548             :     char       *p;
     549             : 
     550          56 :     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          56 :     str = &msg->data[msg->cursor];
     555          56 :     msg->cursor += rawbytes;
     556             : 
     557          56 :     p = pg_client_to_server(str, rawbytes);
     558          56 :     if (p != str)               /* actual conversion has been done? */
     559           0 :         *nbytes = strlen(p);
     560             :     else
     561             :     {
     562          56 :         p = (char *) palloc(rawbytes + 1);
     563          56 :         memcpy(p, str, rawbytes);
     564          56 :         p[rawbytes] = '\0';
     565          56 :         *nbytes = rawbytes;
     566             :     }
     567          56 :     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      800942 : pq_getmsgstring(StringInfo msg)
     579             : {
     580             :     char       *str;
     581             :     int         slen;
     582             : 
     583      800942 :     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      800942 :     slen = strlen(str);
     591      800942 :     if (msg->cursor + slen >= msg->len)
     592           0 :         ereport(ERROR,
     593             :                 (errcode(ERRCODE_PROTOCOL_VIOLATION),
     594             :                  errmsg("invalid string in message")));
     595      800942 :     msg->cursor += slen + 1;
     596             : 
     597      800942 :     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         242 : pq_getmsgrawstring(StringInfo msg)
     608             : {
     609             :     char       *str;
     610             :     int         slen;
     611             : 
     612         242 :     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         242 :     slen = strlen(str);
     620         242 :     if (msg->cursor + slen >= msg->len)
     621           0 :         ereport(ERROR,
     622             :                 (errcode(ERRCODE_PROTOCOL_VIOLATION),
     623             :                  errmsg("invalid string in message")));
     624         242 :     msg->cursor += slen + 1;
     625             : 
     626         242 :     return str;
     627             : }
     628             : 
     629             : /* --------------------------------
     630             :  *      pq_getmsgend    - verify message fully consumed
     631             :  * --------------------------------
     632             :  */
     633             : void
     634      790370 : pq_getmsgend(StringInfo msg)
     635             : {
     636      790370 :     if (msg->cursor != msg->len)
     637           0 :         ereport(ERROR,
     638             :                 (errcode(ERRCODE_PROTOCOL_VIOLATION),
     639             :                  errmsg("invalid message format")));
     640      790370 : }

Generated by: LCOV version 1.16