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

Generated by: LCOV version 1.13