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

Generated by: LCOV version 1.11