LCOV - code coverage report
Current view: top level - src/backend/libpq - pqformat.c (source / functions) Hit Total Coverage
Test: PostgreSQL 18devel Lines: 130 157 82.8 %
Date: 2024-12-12 17:14:55 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-2024, PostgreSQL Global Development Group
      25             :  * Portions Copyright (c) 1994, Regents of the University of California
      26             :  *
      27             :  *  src/backend/libpq/pqformat.c
      28             :  *
      29             :  *-------------------------------------------------------------------------
      30             :  */
      31             : /*
      32             :  * INTERFACE ROUTINES
      33             :  * Message assembly and output:
      34             :  *      pq_beginmessage - initialize StringInfo buffer
      35             :  *      pq_sendbyte     - append a raw byte to a StringInfo buffer
      36             :  *      pq_sendint      - append a binary integer to a StringInfo buffer
      37             :  *      pq_sendint64    - append a binary 8-byte int to a StringInfo buffer
      38             :  *      pq_sendfloat4   - append a float4 to a StringInfo buffer
      39             :  *      pq_sendfloat8   - append a float8 to a StringInfo buffer
      40             :  *      pq_sendbytes    - append raw data to a StringInfo buffer
      41             :  *      pq_sendcountedtext - append a counted text string (with character set conversion)
      42             :  *      pq_sendtext     - append a text string (with conversion)
      43             :  *      pq_sendstring   - append a null-terminated text string (with conversion)
      44             :  *      pq_send_ascii_string - append a null-terminated text string (without conversion)
      45             :  *      pq_endmessage   - send the completed message to the frontend
      46             :  * Note: it is also possible to append data to the StringInfo buffer using
      47             :  * the regular StringInfo routines, but this is discouraged since required
      48             :  * character set conversion may not occur.
      49             :  *
      50             :  * typsend support (construct a bytea value containing external binary data):
      51             :  *      pq_begintypsend - initialize StringInfo buffer
      52             :  *      pq_endtypsend   - return the completed string as a "bytea*"
      53             :  *
      54             :  * Special-case message output:
      55             :  *      pq_puttextmessage - generate a character set-converted message in one step
      56             :  *      pq_putemptymessage - convenience routine for message with empty body
      57             :  *
      58             :  * Message parsing after input:
      59             :  *      pq_getmsgbyte   - get a raw byte from a message buffer
      60             :  *      pq_getmsgint    - get a binary integer from a message buffer
      61             :  *      pq_getmsgint64  - get a binary 8-byte int from a message buffer
      62             :  *      pq_getmsgfloat4 - get a float4 from a message buffer
      63             :  *      pq_getmsgfloat8 - get a float8 from a message buffer
      64             :  *      pq_getmsgbytes  - get raw data from a message buffer
      65             :  *      pq_copymsgbytes - copy raw data from a message buffer
      66             :  *      pq_getmsgtext   - get a counted text string (with conversion)
      67             :  *      pq_getmsgstring - get a null-terminated text string (with conversion)
      68             :  *      pq_getmsgrawstring - get a null-terminated text string - NO conversion
      69             :  *      pq_getmsgend    - verify message fully consumed
      70             :  */
      71             : 
      72             : #include "postgres.h"
      73             : 
      74             : #include <sys/param.h>
      75             : 
      76             : #include "libpq/libpq.h"
      77             : #include "libpq/pqformat.h"
      78             : #include "mb/pg_wchar.h"
      79             : #include "port/pg_bswap.h"
      80             : #include "varatt.h"
      81             : 
      82             : 
      83             : /* --------------------------------
      84             :  *      pq_beginmessage     - initialize for sending a message
      85             :  * --------------------------------
      86             :  */
      87             : void
      88     1261194 : pq_beginmessage(StringInfo buf, char msgtype)
      89             : {
      90     1261194 :     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     1261194 :     buf->cursor = msgtype;
      98     1261194 : }
      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     6368698 : pq_beginmessage_reuse(StringInfo buf, char msgtype)
     110             : {
     111     6368698 :     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     6368698 :     buf->cursor = msgtype;
     119     6368698 : }
     120             : 
     121             : /* --------------------------------
     122             :  *      pq_sendbytes    - append raw data to a StringInfo buffer
     123             :  * --------------------------------
     124             :  */
     125             : void
     126      247896 : pq_sendbytes(StringInfo buf, const void *data, int datalen)
     127             : {
     128             :     /* use variant that maintains a trailing null-byte, out of caution */
     129      247896 :     appendBinaryStringInfo(buf, data, datalen);
     130      247896 : }
     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    26983316 : pq_sendcountedtext(StringInfo buf, const char *str, int slen)
     143             : {
     144             :     char       *p;
     145             : 
     146    26983316 :     p = pg_server_to_client(str, slen);
     147    26983316 :     if (p != str)               /* actual conversion has been done? */
     148             :     {
     149          54 :         slen = strlen(p);
     150          54 :         pq_sendint32(buf, slen);
     151          54 :         appendBinaryStringInfoNT(buf, p, slen);
     152          54 :         pfree(p);
     153             :     }
     154             :     else
     155             :     {
     156    26983262 :         pq_sendint32(buf, slen);
     157    26983262 :         appendBinaryStringInfoNT(buf, str, slen);
     158             :     }
     159    26983316 : }
     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        4914 : pq_sendtext(StringInfo buf, const char *str, int slen)
     173             : {
     174             :     char       *p;
     175             : 
     176        4914 :     p = pg_server_to_client(str, slen);
     177        4914 :     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        4914 :         appendBinaryStringInfo(buf, str, slen);
     185        4914 : }
     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     2360010 : pq_sendstring(StringInfo buf, const char *str)
     196             : {
     197     2360010 :     int         slen = strlen(str);
     198             :     char       *p;
     199             : 
     200     2360010 :     p = pg_server_to_client(str, slen);
     201     2360010 :     if (p != str)               /* actual conversion has been done? */
     202             :     {
     203         222 :         slen = strlen(p);
     204         222 :         appendBinaryStringInfoNT(buf, p, slen + 1);
     205         222 :         pfree(p);
     206             :     }
     207             :     else
     208     2359788 :         appendBinaryStringInfoNT(buf, str, slen + 1);
     209     2360010 : }
     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     1261174 : pq_endmessage(StringInfo buf)
     297             : {
     298             :     /* msgtype was saved in cursor field */
     299     1261174 :     (void) pq_putmessage(buf->cursor, buf->data, buf->len);
     300             :     /* no need to complain about any failure, since pqcomm.c already did */
     301     1261174 :     pfree(buf->data);
     302     1261174 :     buf->data = NULL;
     303     1261174 : }
     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     6368598 : pq_endmessage_reuse(StringInfo buf)
     315             : {
     316             :     /* msgtype was saved in cursor field */
     317     6368598 :     (void) pq_putmessage(buf->cursor, buf->data, buf->len);
     318     6368598 : }
     319             : 
     320             : 
     321             : /* --------------------------------
     322             :  *      pq_begintypsend     - initialize for constructing a bytea result
     323             :  * --------------------------------
     324             :  */
     325             : void
     326      190164 : pq_begintypsend(StringInfo buf)
     327             : {
     328      190164 :     initStringInfo(buf);
     329             :     /* Reserve four bytes for the bytea length word */
     330      190164 :     appendStringInfoCharMacro(buf, '\0');
     331      190164 :     appendStringInfoCharMacro(buf, '\0');
     332      190164 :     appendStringInfoCharMacro(buf, '\0');
     333      190164 :     appendStringInfoCharMacro(buf, '\0');
     334      190164 : }
     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      190164 : pq_endtypsend(StringInfo buf)
     347             : {
     348      190164 :     bytea      *result = (bytea *) buf->data;
     349             : 
     350             :     /* Insert correct length into bytea length word */
     351             :     Assert(buf->len >= VARHDRSZ);
     352      190164 :     SET_VARSIZE(result, buf->len);
     353             : 
     354      190164 :     return result;
     355             : }
     356             : 
     357             : 
     358             : /* --------------------------------
     359             :  *      pq_puttextmessage - generate a character set-converted message in one step
     360             :  *
     361             :  *      This is the same as the pqcomm.c routine pq_putmessage, except that
     362             :  *      the message body is a null-terminated string to which encoding
     363             :  *      conversion applies.
     364             :  * --------------------------------
     365             :  */
     366             : void
     367         922 : pq_puttextmessage(char msgtype, const char *str)
     368             : {
     369         922 :     int         slen = strlen(str);
     370             :     char       *p;
     371             : 
     372         922 :     p = pg_server_to_client(str, slen);
     373         922 :     if (p != str)               /* actual conversion has been done? */
     374             :     {
     375           0 :         (void) pq_putmessage(msgtype, p, strlen(p) + 1);
     376           0 :         pfree(p);
     377           0 :         return;
     378             :     }
     379         922 :     (void) pq_putmessage(msgtype, str, slen + 1);
     380             : }
     381             : 
     382             : 
     383             : /* --------------------------------
     384             :  *      pq_putemptymessage - convenience routine for message with empty body
     385             :  * --------------------------------
     386             :  */
     387             : void
     388       51840 : pq_putemptymessage(char msgtype)
     389             : {
     390       51840 :     (void) pq_putmessage(msgtype, NULL, 0);
     391       51840 : }
     392             : 
     393             : 
     394             : /* --------------------------------
     395             :  *      pq_getmsgbyte   - get a raw byte from a message buffer
     396             :  * --------------------------------
     397             :  */
     398             : int
     399     2327390 : pq_getmsgbyte(StringInfo msg)
     400             : {
     401     2327390 :     if (msg->cursor >= msg->len)
     402           0 :         ereport(ERROR,
     403             :                 (errcode(ERRCODE_PROTOCOL_VIOLATION),
     404             :                  errmsg("no data left in message")));
     405     2327390 :     return (unsigned char) msg->data[msg->cursor++];
     406             : }
     407             : 
     408             : /* --------------------------------
     409             :  *      pq_getmsgint    - get a binary integer from a message buffer
     410             :  *
     411             :  *      Values are treated as unsigned.
     412             :  * --------------------------------
     413             :  */
     414             : unsigned int
     415     2605106 : pq_getmsgint(StringInfo msg, int b)
     416             : {
     417             :     unsigned int result;
     418             :     unsigned char n8;
     419             :     uint16      n16;
     420             :     uint32      n32;
     421             : 
     422     2605106 :     switch (b)
     423             :     {
     424          38 :         case 1:
     425          38 :             pq_copymsgbytes(msg, (char *) &n8, 1);
     426          38 :             result = n8;
     427          38 :             break;
     428     1044428 :         case 2:
     429     1044428 :             pq_copymsgbytes(msg, (char *) &n16, 2);
     430     1044428 :             result = pg_ntoh16(n16);
     431     1044428 :             break;
     432     1560640 :         case 4:
     433     1560640 :             pq_copymsgbytes(msg, (char *) &n32, 4);
     434     1560640 :             result = pg_ntoh32(n32);
     435     1560640 :             break;
     436           0 :         default:
     437           0 :             elog(ERROR, "unsupported integer size %d", b);
     438             :             result = 0;         /* keep compiler quiet */
     439             :             break;
     440             :     }
     441     2605106 :     return result;
     442             : }
     443             : 
     444             : /* --------------------------------
     445             :  *      pq_getmsgint64  - get a binary 8-byte int from a message buffer
     446             :  *
     447             :  * It is tempting to merge this with pq_getmsgint, but we'd have to make the
     448             :  * result int64 for all data widths --- that could be a big performance
     449             :  * hit on machines where int64 isn't efficient.
     450             :  * --------------------------------
     451             :  */
     452             : int64
     453     2053178 : pq_getmsgint64(StringInfo msg)
     454             : {
     455             :     uint64      n64;
     456             : 
     457     2053178 :     pq_copymsgbytes(msg, (char *) &n64, sizeof(n64));
     458             : 
     459     2053178 :     return pg_ntoh64(n64);
     460             : }
     461             : 
     462             : /* --------------------------------
     463             :  *      pq_getmsgfloat4 - get a float4 from a message buffer
     464             :  *
     465             :  * See notes for pq_sendfloat4.
     466             :  * --------------------------------
     467             :  */
     468             : float4
     469           0 : pq_getmsgfloat4(StringInfo msg)
     470             : {
     471             :     union
     472             :     {
     473             :         float4      f;
     474             :         uint32      i;
     475             :     }           swap;
     476             : 
     477           0 :     swap.i = pq_getmsgint(msg, 4);
     478           0 :     return swap.f;
     479             : }
     480             : 
     481             : /* --------------------------------
     482             :  *      pq_getmsgfloat8 - get a float8 from a message buffer
     483             :  *
     484             :  * See notes for pq_sendfloat8.
     485             :  * --------------------------------
     486             :  */
     487             : float8
     488          62 : pq_getmsgfloat8(StringInfo msg)
     489             : {
     490             :     union
     491             :     {
     492             :         float8      f;
     493             :         int64       i;
     494             :     }           swap;
     495             : 
     496          62 :     swap.i = pq_getmsgint64(msg);
     497          62 :     return swap.f;
     498             : }
     499             : 
     500             : /* --------------------------------
     501             :  *      pq_getmsgbytes  - get raw data from a message buffer
     502             :  *
     503             :  *      Returns a pointer directly into the message buffer; note this
     504             :  *      may not have any particular alignment.
     505             :  * --------------------------------
     506             :  */
     507             : const char *
     508       31086 : pq_getmsgbytes(StringInfo msg, int datalen)
     509             : {
     510             :     const char *result;
     511             : 
     512       31086 :     if (datalen < 0 || datalen > (msg->len - msg->cursor))
     513           0 :         ereport(ERROR,
     514             :                 (errcode(ERRCODE_PROTOCOL_VIOLATION),
     515             :                  errmsg("insufficient data left in message")));
     516       31086 :     result = &msg->data[msg->cursor];
     517       31086 :     msg->cursor += datalen;
     518       31086 :     return result;
     519             : }
     520             : 
     521             : /* --------------------------------
     522             :  *      pq_copymsgbytes - copy raw data from a message buffer
     523             :  *
     524             :  *      Same as above, except data is copied to caller's buffer.
     525             :  * --------------------------------
     526             :  */
     527             : void
     528     5672996 : pq_copymsgbytes(StringInfo msg, char *buf, int datalen)
     529             : {
     530     5672996 :     if (datalen < 0 || datalen > (msg->len - msg->cursor))
     531           0 :         ereport(ERROR,
     532             :                 (errcode(ERRCODE_PROTOCOL_VIOLATION),
     533             :                  errmsg("insufficient data left in message")));
     534     5672996 :     memcpy(buf, &msg->data[msg->cursor], datalen);
     535     5672996 :     msg->cursor += datalen;
     536     5672996 : }
     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          56 : pq_getmsgtext(StringInfo msg, int rawbytes, int *nbytes)
     547             : {
     548             :     char       *str;
     549             :     char       *p;
     550             : 
     551          56 :     if (rawbytes < 0 || rawbytes > (msg->len - msg->cursor))
     552           0 :         ereport(ERROR,
     553             :                 (errcode(ERRCODE_PROTOCOL_VIOLATION),
     554             :                  errmsg("insufficient data left in message")));
     555          56 :     str = &msg->data[msg->cursor];
     556          56 :     msg->cursor += rawbytes;
     557             : 
     558          56 :     p = pg_client_to_server(str, rawbytes);
     559          56 :     if (p != str)               /* actual conversion has been done? */
     560           0 :         *nbytes = strlen(p);
     561             :     else
     562             :     {
     563          56 :         p = (char *) palloc(rawbytes + 1);
     564          56 :         memcpy(p, str, rawbytes);
     565          56 :         p[rawbytes] = '\0';
     566          56 :         *nbytes = rawbytes;
     567             :     }
     568          56 :     return p;
     569             : }
     570             : 
     571             : /* --------------------------------
     572             :  *      pq_getmsgstring - get a null-terminated text string (with conversion)
     573             :  *
     574             :  *      May return a pointer directly into the message buffer, or a pointer
     575             :  *      to a palloc'd conversion result.
     576             :  * --------------------------------
     577             :  */
     578             : const char *
     579      718782 : pq_getmsgstring(StringInfo msg)
     580             : {
     581             :     char       *str;
     582             :     int         slen;
     583             : 
     584      718782 :     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      718782 :     slen = strlen(str);
     592      718782 :     if (msg->cursor + slen >= msg->len)
     593           0 :         ereport(ERROR,
     594             :                 (errcode(ERRCODE_PROTOCOL_VIOLATION),
     595             :                  errmsg("invalid string in message")));
     596      718782 :     msg->cursor += slen + 1;
     597             : 
     598      718782 :     return pg_client_to_server(str, slen);
     599             : }
     600             : 
     601             : /* --------------------------------
     602             :  *      pq_getmsgrawstring - get a null-terminated text string - NO conversion
     603             :  *
     604             :  *      Returns a pointer directly into the message buffer.
     605             :  * --------------------------------
     606             :  */
     607             : const char *
     608         188 : pq_getmsgrawstring(StringInfo msg)
     609             : {
     610             :     char       *str;
     611             :     int         slen;
     612             : 
     613         188 :     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         188 :     slen = strlen(str);
     621         188 :     if (msg->cursor + slen >= msg->len)
     622           0 :         ereport(ERROR,
     623             :                 (errcode(ERRCODE_PROTOCOL_VIOLATION),
     624             :                  errmsg("invalid string in message")));
     625         188 :     msg->cursor += slen + 1;
     626             : 
     627         188 :     return str;
     628             : }
     629             : 
     630             : /* --------------------------------
     631             :  *      pq_getmsgend    - verify message fully consumed
     632             :  * --------------------------------
     633             :  */
     634             : void
     635      709272 : pq_getmsgend(StringInfo msg)
     636             : {
     637      709272 :     if (msg->cursor != msg->len)
     638           0 :         ereport(ERROR,
     639             :                 (errcode(ERRCODE_PROTOCOL_VIOLATION),
     640             :                  errmsg("invalid message format")));
     641      709272 : }

Generated by: LCOV version 1.14