LCOV - code coverage report
Current view: top level - src/backend/libpq - pqformat.c (source / functions) Coverage Total Hit
Test: PostgreSQL 20devel Lines: 82.8 % 157 130
Test Date: 2026-07-03 19:57:34 Functions: 92.3 % 26 24
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
Branches: 37.5 % 64 24

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

Generated by: LCOV version 2.0-1