LCOV - code coverage report
Current view: top level - src/backend/libpq - pqformat.c (source / functions) Coverage Total Hit
Test: Code coverage Lines: 75.3 % 190 143
Test Date: 2026-01-26 10:56:24 Functions: 88.5 % 26 23
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
Branches: 24.4 % 78 19

             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                 :       75368 : pq_beginmessage(StringInfo buf, char msgtype)
      89                 :             : {
      90                 :       75368 :         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                 :       75368 :         buf->cursor = msgtype;
      98                 :       75368 : }
      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                 :      106674 : pq_beginmessage_reuse(StringInfo buf, char msgtype)
     110                 :             : {
     111                 :      106674 :         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                 :      106674 :         buf->cursor = msgtype;
     119                 :      106674 : }
     120                 :             : 
     121                 :             : /* --------------------------------
     122                 :             :  *              pq_sendbytes    - append raw data to a StringInfo buffer
     123                 :             :  * --------------------------------
     124                 :             :  */
     125                 :             : void
     126                 :         735 : pq_sendbytes(StringInfo buf, const void *data, int datalen)
     127                 :             : {
     128                 :             :         /* use variant that maintains a trailing null-byte, out of caution */
     129                 :         735 :         appendBinaryStringInfo(buf, data, datalen);
     130                 :         735 : }
     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                 :      191313 : pq_sendcountedtext(StringInfo buf, const char *str, int slen)
     143                 :             : {
     144                 :      191313 :         char       *p;
     145                 :             : 
     146                 :      191313 :         p = pg_server_to_client(str, slen);
     147         [ -  + ]:      191313 :         if (p != str)                           /* actual conversion has been done? */
     148                 :             :         {
     149                 :           0 :                 slen = strlen(p);
     150                 :           0 :                 pq_sendint32(buf, slen);
     151                 :           0 :                 appendBinaryStringInfoNT(buf, p, slen);
     152                 :           0 :                 pfree(p);
     153                 :           0 :         }
     154                 :             :         else
     155                 :             :         {
     156                 :      191313 :                 pq_sendint32(buf, slen);
     157                 :      191313 :                 appendBinaryStringInfoNT(buf, str, slen);
     158                 :             :         }
     159                 :      191313 : }
     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                 :           4 : pq_sendtext(StringInfo buf, const char *str, int slen)
     173                 :             : {
     174                 :           4 :         char       *p;
     175                 :             : 
     176                 :           4 :         p = pg_server_to_client(str, slen);
     177         [ -  + ]:           4 :         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                 :           0 :         }
     183                 :             :         else
     184                 :           4 :                 appendBinaryStringInfo(buf, str, slen);
     185                 :           4 : }
     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                 :       87778 : pq_sendstring(StringInfo buf, const char *str)
     196                 :             : {
     197                 :       87778 :         int                     slen = strlen(str);
     198                 :       87778 :         char       *p;
     199                 :             : 
     200                 :       87778 :         p = pg_server_to_client(str, slen);
     201         [ +  + ]:       87778 :         if (p != str)                           /* actual conversion has been done? */
     202                 :             :         {
     203                 :          12 :                 slen = strlen(p);
     204                 :          12 :                 appendBinaryStringInfoNT(buf, p, slen + 1);
     205                 :          12 :                 pfree(p);
     206                 :          12 :         }
     207                 :             :         else
     208                 :       87766 :                 appendBinaryStringInfoNT(buf, str, slen + 1);
     209                 :       87778 : }
     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                 :           0 :         }
     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                 :        1082 : pq_sendfloat4(StringInfo buf, float4 f)
     253                 :             : {
     254                 :        1082 :         union
     255                 :             :         {
     256                 :             :                 float4          f;
     257                 :             :                 uint32          i;
     258                 :             :         }                       swap;
     259                 :             : 
     260                 :        1082 :         swap.f = f;
     261                 :        1082 :         pq_sendint32(buf, swap.i);
     262                 :        1082 : }
     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                 :         864 : pq_sendfloat8(StringInfo buf, float8 f)
     277                 :             : {
     278                 :         864 :         union
     279                 :             :         {
     280                 :             :                 float8          f;
     281                 :             :                 int64           i;
     282                 :             :         }                       swap;
     283                 :             : 
     284                 :         864 :         swap.f = f;
     285                 :         864 :         pq_sendint64(buf, swap.i);
     286                 :         864 : }
     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                 :       75368 : pq_endmessage(StringInfo buf)
     297                 :             : {
     298                 :             :         /* msgtype was saved in cursor field */
     299                 :       75368 :         (void) pq_putmessage(buf->cursor, buf->data, buf->len);
     300                 :             :         /* no need to complain about any failure, since pqcomm.c already did */
     301                 :       75368 :         pfree(buf->data);
     302                 :       75368 :         buf->data = NULL;
     303                 :       75368 : }
     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                 :      106654 : pq_endmessage_reuse(StringInfo buf)
     314                 :             : {
     315                 :             :         /* msgtype was saved in cursor field */
     316                 :      106654 :         (void) pq_putmessage(buf->cursor, buf->data, buf->len);
     317                 :      106654 : }
     318                 :             : 
     319                 :             : 
     320                 :             : /* --------------------------------
     321                 :             :  *              pq_begintypsend         - initialize for constructing a bytea result
     322                 :             :  * --------------------------------
     323                 :             :  */
     324                 :             : void
     325                 :        2244 : pq_begintypsend(StringInfo buf)
     326                 :             : {
     327                 :        2244 :         initStringInfo(buf);
     328                 :             :         /* Reserve four bytes for the bytea length word */
     329         [ -  + ]:        2244 :         appendStringInfoCharMacro(buf, '\0');
     330         [ -  + ]:        2244 :         appendStringInfoCharMacro(buf, '\0');
     331         [ -  + ]:        2244 :         appendStringInfoCharMacro(buf, '\0');
     332         [ -  + ]:        2244 :         appendStringInfoCharMacro(buf, '\0');
     333                 :        2244 : }
     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                 :        2244 : pq_endtypsend(StringInfo buf)
     346                 :             : {
     347                 :        2244 :         bytea      *result = (bytea *) buf->data;
     348                 :             : 
     349                 :             :         /* Insert correct length into bytea length word */
     350         [ +  - ]:        2244 :         Assert(buf->len >= VARHDRSZ);
     351                 :        2244 :         SET_VARSIZE(result, buf->len);
     352                 :             : 
     353                 :        4488 :         return result;
     354                 :        2244 : }
     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                 :           0 : pq_puttextmessage(char msgtype, const char *str)
     367                 :             : {
     368                 :           0 :         int                     slen = strlen(str);
     369                 :           0 :         char       *p;
     370                 :             : 
     371                 :           0 :         p = pg_server_to_client(str, slen);
     372         [ #  # ]:           0 :         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                 :           0 :         (void) pq_putmessage(msgtype, str, slen + 1);
     379         [ #  # ]:           0 : }
     380                 :             : 
     381                 :             : 
     382                 :             : /* --------------------------------
     383                 :             :  *              pq_putemptymessage - convenience routine for message with empty body
     384                 :             :  * --------------------------------
     385                 :             :  */
     386                 :             : void
     387                 :         338 : pq_putemptymessage(char msgtype)
     388                 :             : {
     389                 :         338 :         (void) pq_putmessage(msgtype, NULL, 0);
     390                 :         338 : }
     391                 :             : 
     392                 :             : 
     393                 :             : /* --------------------------------
     394                 :             :  *              pq_getmsgbyte   - get a raw byte from a message buffer
     395                 :             :  * --------------------------------
     396                 :             :  */
     397                 :             : int
     398                 :         645 : pq_getmsgbyte(StringInfo msg)
     399                 :             : {
     400         [ +  - ]:         645 :         if (msg->cursor >= msg->len)
     401   [ #  #  #  # ]:           0 :                 ereport(ERROR,
     402                 :             :                                 (errcode(ERRCODE_PROTOCOL_VIOLATION),
     403                 :             :                                  errmsg("no data left in message")));
     404                 :         645 :         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                 :      109422 : pq_getmsgint(StringInfo msg, int b)
     415                 :             : {
     416                 :      109422 :         unsigned int result;
     417                 :      109422 :         unsigned char n8;
     418                 :      109422 :         uint16          n16;
     419                 :      109422 :         uint32          n32;
     420                 :             : 
     421   [ +  -  +  - ]:      109422 :         switch (b)
     422                 :             :         {
     423                 :             :                 case 1:
     424                 :           0 :                         pq_copymsgbytes(msg, &n8, 1);
     425                 :           0 :                         result = n8;
     426                 :           0 :                         break;
     427                 :             :                 case 2:
     428                 :      107864 :                         pq_copymsgbytes(msg, &n16, 2);
     429                 :      107864 :                         result = pg_ntoh16(n16);
     430                 :      107864 :                         break;
     431                 :             :                 case 4:
     432                 :        1558 :                         pq_copymsgbytes(msg, &n32, 4);
     433                 :        1558 :                         result = pg_ntoh32(n32);
     434                 :        1558 :                         break;
     435                 :             :                 default:
     436   [ #  #  #  # ]:           0 :                         elog(ERROR, "unsupported integer size %d", b);
     437                 :           0 :                         result = 0;                     /* keep compiler quiet */
     438                 :           0 :                         break;
     439                 :             :         }
     440                 :      218844 :         return result;
     441                 :      109422 : }
     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                 :         114 : pq_getmsgint64(StringInfo msg)
     453                 :             : {
     454                 :         114 :         uint64          n64;
     455                 :             : 
     456                 :         114 :         pq_copymsgbytes(msg, &n64, sizeof(n64));
     457                 :             : 
     458                 :         228 :         return pg_ntoh64(n64);
     459                 :         114 : }
     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                 :           0 :         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                 :           0 : }
     479                 :             : 
     480                 :             : /* --------------------------------
     481                 :             :  *              pq_getmsgfloat8 - get a float8 from a message buffer
     482                 :             :  *
     483                 :             :  * See notes for pq_sendfloat8.
     484                 :             :  * --------------------------------
     485                 :             :  */
     486                 :             : float8
     487                 :           9 : pq_getmsgfloat8(StringInfo msg)
     488                 :             : {
     489                 :           9 :         union
     490                 :             :         {
     491                 :             :                 float8          f;
     492                 :             :                 int64           i;
     493                 :             :         }                       swap;
     494                 :             : 
     495                 :           9 :         swap.i = pq_getmsgint64(msg);
     496                 :          18 :         return swap.f;
     497                 :           9 : }
     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                 :         726 : pq_getmsgbytes(StringInfo msg, int datalen)
     508                 :             : {
     509                 :         726 :         const char *result;
     510                 :             : 
     511         [ +  - ]:         726 :         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                 :         726 :         result = &msg->data[msg->cursor];
     516                 :         726 :         msg->cursor += datalen;
     517                 :        1452 :         return result;
     518                 :         726 : }
     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                 :      109826 : pq_copymsgbytes(StringInfo msg, void *buf, int datalen)
     528                 :             : {
     529         [ +  - ]:      109826 :         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                 :      109826 :         memcpy(buf, &msg->data[msg->cursor], datalen);
     534                 :      109826 :         msg->cursor += datalen;
     535                 :      109826 : }
     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                 :           4 : pq_getmsgtext(StringInfo msg, int rawbytes, int *nbytes)
     546                 :             : {
     547                 :           4 :         char       *str;
     548                 :           4 :         char       *p;
     549                 :             : 
     550         [ +  - ]:           4 :         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                 :           4 :         str = &msg->data[msg->cursor];
     555                 :           4 :         msg->cursor += rawbytes;
     556                 :             : 
     557                 :           4 :         p = pg_client_to_server(str, rawbytes);
     558         [ -  + ]:           4 :         if (p != str)                           /* actual conversion has been done? */
     559                 :           0 :                 *nbytes = strlen(p);
     560                 :             :         else
     561                 :             :         {
     562                 :           4 :                 p = (char *) palloc(rawbytes + 1);
     563                 :           4 :                 memcpy(p, str, rawbytes);
     564                 :           4 :                 p[rawbytes] = '\0';
     565                 :           4 :                 *nbytes = rawbytes;
     566                 :             :         }
     567                 :           8 :         return p;
     568                 :           4 : }
     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                 :       59312 : pq_getmsgstring(StringInfo msg)
     579                 :             : {
     580                 :       59312 :         char       *str;
     581                 :       59312 :         int                     slen;
     582                 :             : 
     583                 :       59312 :         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                 :       59312 :         slen = strlen(str);
     591         [ +  - ]:       59312 :         if (msg->cursor + slen >= msg->len)
     592   [ #  #  #  # ]:           0 :                 ereport(ERROR,
     593                 :             :                                 (errcode(ERRCODE_PROTOCOL_VIOLATION),
     594                 :             :                                  errmsg("invalid string in message")));
     595                 :       59312 :         msg->cursor += slen + 1;
     596                 :             : 
     597                 :      118624 :         return pg_client_to_server(str, slen);
     598                 :       59312 : }
     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                 :          15 : pq_getmsgrawstring(StringInfo msg)
     608                 :             : {
     609                 :          15 :         char       *str;
     610                 :          15 :         int                     slen;
     611                 :             : 
     612                 :          15 :         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                 :          15 :         slen = strlen(str);
     620         [ +  - ]:          15 :         if (msg->cursor + slen >= msg->len)
     621   [ #  #  #  # ]:           0 :                 ereport(ERROR,
     622                 :             :                                 (errcode(ERRCODE_PROTOCOL_VIOLATION),
     623                 :             :                                  errmsg("invalid string in message")));
     624                 :          15 :         msg->cursor += slen + 1;
     625                 :             : 
     626                 :          30 :         return str;
     627                 :          15 : }
     628                 :             : 
     629                 :             : /* --------------------------------
     630                 :             :  *              pq_getmsgend    - verify message fully consumed
     631                 :             :  * --------------------------------
     632                 :             :  */
     633                 :             : void
     634                 :       59547 : pq_getmsgend(StringInfo msg)
     635                 :             : {
     636         [ +  - ]:       59547 :         if (msg->cursor != msg->len)
     637   [ #  #  #  # ]:           0 :                 ereport(ERROR,
     638                 :             :                                 (errcode(ERRCODE_PROTOCOL_VIOLATION),
     639                 :             :                                  errmsg("invalid message format")));
     640                 :       59547 : }
        

Generated by: LCOV version 2.3.2-1