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

Generated by: LCOV version 1.14