LCOV - differential code coverage report
Current view: top level - src/common - stringinfo.c (source / functions) Coverage Total Hit UBC GBC GNC CBC DCB
Current: 0e5ff9b9b45a657aea12440478dc002e9b01f138 vs 0123ce131fca454009439dfa3b2266d1d40737d7 Lines: 92.3 % 104 96 8 3 1 92 1
Current Date: 2026-03-14 14:10:32 -0400 Functions: 100.0 % 16 16 1 1 14
Baseline: lcov-20260315-024220-baseline Branches: 65.0 % 40 26 14 26
Baseline Date: 2026-03-14 15:27:56 +0100 Line coverage date bins:
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
(30,360] days: 100.0 % 1 1 1
(360..) days: 92.2 % 103 95 8 3 92
Function coverage date bins:
(360..) days: 100.0 % 16 16 1 1 14
Branch coverage date bins:
(360..) days: 65.0 % 40 26 14 26

 Age         Owner                    Branch data    TLA  Line data    Source code
                                  1                 :                : /*-------------------------------------------------------------------------
                                  2                 :                :  *
                                  3                 :                :  * stringinfo.c
                                  4                 :                :  *
                                  5                 :                :  * StringInfo provides an extensible string data type (currently limited to a
                                  6                 :                :  * length of 1GB).  It can be used to buffer either ordinary C strings
                                  7                 :                :  * (null-terminated text) or arbitrary binary data.  All storage is allocated
                                  8                 :                :  * with palloc() (falling back to malloc in frontend code).
                                  9                 :                :  *
                                 10                 :                :  * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
                                 11                 :                :  * Portions Copyright (c) 1994, Regents of the University of California
                                 12                 :                :  *
                                 13                 :                :  *    src/common/stringinfo.c
                                 14                 :                :  *
                                 15                 :                :  *-------------------------------------------------------------------------
                                 16                 :                :  */
                                 17                 :                : 
                                 18                 :                : #ifndef FRONTEND
                                 19                 :                : 
                                 20                 :                : #include "postgres.h"
                                 21                 :                : #include "utils/memutils.h"
                                 22                 :                : 
                                 23                 :                : #else
                                 24                 :                : 
                                 25                 :                : #include "postgres_fe.h"
                                 26                 :                : 
                                 27                 :                : #endif
                                 28                 :                : 
                                 29                 :                : #include "lib/stringinfo.h"
                                 30                 :                : 
                                 31                 :                : 
                                 32                 :                : /*
                                 33                 :                :  * initStringInfoInternal
                                 34                 :                :  *
                                 35                 :                :  * Initialize a StringInfoData struct (with previously undefined contents)
                                 36                 :                :  * to describe an empty string.
                                 37                 :                :  * The initial memory allocation size is specified by 'initsize'.
                                 38                 :                :  * The valid range for 'initsize' is 1 to MaxAllocSize.
                                 39                 :                :  */
                                 40                 :                : static inline void
  428 ishii@postgresql.org       41                 :CBC     4664059 : initStringInfoInternal(StringInfo str, int initsize)
                                 42                 :                : {
                                 43   [ +  -  +  + ]:        4664059 :     Assert(initsize >= 1 && initsize <= MaxAllocSize);
                                 44                 :                : 
                                 45                 :        4664059 :     str->data = (char *) palloc(initsize);
                                 46                 :        4664059 :     str->maxlen = initsize;
                                 47                 :        4664059 :     resetStringInfo(str);
                                 48                 :        4664059 : }
                                 49                 :                : 
                                 50                 :                : /*
                                 51                 :                :  * makeStringInfoInternal(int initsize)
                                 52                 :                :  *
                                 53                 :                :  * Create an empty 'StringInfoData' & return a pointer to it.
                                 54                 :                :  * The initial memory allocation size is specified by 'initsize'.
                                 55                 :                :  * The valid range for 'initsize' is 1 to MaxAllocSize.
                                 56                 :                :  */
                                 57                 :                : static inline StringInfo
                                 58                 :          51299 : makeStringInfoInternal(int initsize)
                                 59                 :                : {
   96 michael@paquier.xyz        60                 :GNC       51299 :     StringInfo  res = palloc_object(StringInfoData);
                                 61                 :                : 
  428 ishii@postgresql.org       62                 :CBC       51299 :     initStringInfoInternal(res, initsize);
                                 63                 :          51299 :     return res;
                                 64                 :                : }
                                 65                 :                : 
                                 66                 :                : /*
                                 67                 :                :  * makeStringInfo
                                 68                 :                :  *
                                 69                 :                :  * Create an empty 'StringInfoData' & return a pointer to it.
                                 70                 :                :  */
                                 71                 :                : StringInfo
 9821 tgl@sss.pgh.pa.us          72                 :          51247 : makeStringInfo(void)
                                 73                 :                : {
  428 ishii@postgresql.org       74                 :          51247 :     return makeStringInfoInternal(STRINGINFO_DEFAULT_SIZE);
                                 75                 :                : }
                                 76                 :                : 
                                 77                 :                : /*
                                 78                 :                :  * makeStringInfoExt(int initsize)
                                 79                 :                :  *
                                 80                 :                :  * Create an empty 'StringInfoData' & return a pointer to it.
                                 81                 :                :  * The initial memory allocation size is specified by 'initsize'.
                                 82                 :                :  * The valid range for 'initsize' is 1 to MaxAllocSize.
                                 83                 :                :  */
                                 84                 :                : StringInfo
                                 85                 :             52 : makeStringInfoExt(int initsize)
                                 86                 :                : {
                                 87                 :             52 :     return makeStringInfoInternal(initsize);
                                 88                 :                : }
                                 89                 :                : 
                                 90                 :                : /*
                                 91                 :                :  * initStringInfo
                                 92                 :                :  *
                                 93                 :                :  * Initialize a StringInfoData struct (with previously undefined contents)
                                 94                 :                :  * to describe an empty string.
                                 95                 :                :  */
                                 96                 :                : void
 9821 tgl@sss.pgh.pa.us          97                 :        4611093 : initStringInfo(StringInfo str)
                                 98                 :                : {
  428 ishii@postgresql.org       99                 :        4611093 :     initStringInfoInternal(str, STRINGINFO_DEFAULT_SIZE);
                                100                 :        4611093 : }
                                101                 :                : 
                                102                 :                : /*
                                103                 :                :  * initStringInfoExt
                                104                 :                :  *
                                105                 :                :  * Initialize a StringInfoData struct (with previously undefined contents)
                                106                 :                :  * to describe an empty string.
                                107                 :                :  * The initial memory allocation size is specified by 'initsize'.
                                108                 :                :  * The valid range for 'initsize' is 1 to MaxAllocSize.
                                109                 :                :  */
                                110                 :                : void
  428 ishii@postgresql.org      111                 :GBC        1667 : initStringInfoExt(StringInfo str, int initsize)
                                112                 :                : {
                                113                 :           1667 :     initStringInfoInternal(str, initsize);
 6952 neilc@samurai.com         114                 :           1667 : }
                                115                 :                : 
                                116                 :                : /*
                                117                 :                :  * resetStringInfo
                                118                 :                :  *
                                119                 :                :  * Reset the StringInfo: the data buffer remains valid, but its
                                120                 :                :  * previous content, if any, is cleared.
                                121                 :                :  *
                                122                 :                :  * Read-only StringInfos as initialized by initReadOnlyStringInfo cannot be
                                123                 :                :  * reset.
                                124                 :                :  */
                                125                 :                : void
 6952 neilc@samurai.com         126                 :CBC    19270497 : resetStringInfo(StringInfo str)
                                127                 :                : {
                                128                 :                :     /* don't allow resets of read-only StringInfos */
  871 drowley@postgresql.o      129         [ -  + ]:       19270497 :     Assert(str->maxlen != 0);
                                130                 :                : 
 9821 tgl@sss.pgh.pa.us         131                 :       19270497 :     str->data[0] = '\0';
 6952 neilc@samurai.com         132                 :       19270497 :     str->len = 0;
 8366 tgl@sss.pgh.pa.us         133                 :       19270497 :     str->cursor = 0;
 9821                           134                 :       19270497 : }
                                135                 :                : 
                                136                 :                : /*
                                137                 :                :  * appendStringInfo
                                138                 :                :  *
                                139                 :                :  * Format text data under the control of fmt (an sprintf-style format string)
                                140                 :                :  * and append it to whatever is already in str.  More space is allocated
                                141                 :                :  * to str if necessary.  This is sort of like a combination of sprintf and
                                142                 :                :  * strcat.
                                143                 :                :  */
                                144                 :                : void
 8259 bruce@momjian.us          145                 :       14552685 : appendStringInfo(StringInfo str, const char *fmt,...)
                                146                 :                : {
 2727 tgl@sss.pgh.pa.us         147                 :       14552685 :     int         save_errno = errno;
                                148                 :                : 
                                149                 :                :     for (;;)
 8361                           150                 :          24788 :     {
                                151                 :                :         va_list     args;
                                152                 :                :         int         needed;
                                153                 :                : 
                                154                 :                :         /* Try to format the data. */
 2727                           155                 :       14577473 :         errno = save_errno;
 8361                           156                 :       14577473 :         va_start(args, fmt);
 4525                           157                 :       14577473 :         needed = appendStringInfoVA(str, fmt, args);
 8361                           158                 :       14577473 :         va_end(args);
                                159                 :                : 
 4525                           160         [ +  + ]:       14577473 :         if (needed == 0)
                                161                 :       14552685 :             break;              /* success */
                                162                 :                : 
                                163                 :                :         /* Increase the buffer size and try again. */
                                164                 :          24788 :         enlargeStringInfo(str, needed);
                                165                 :                :     }
 8361                           166                 :       14552685 : }
                                167                 :                : 
                                168                 :                : /*
                                169                 :                :  * appendStringInfoVA
                                170                 :                :  *
                                171                 :                :  * Attempt to format text data under the control of fmt (an sprintf-style
                                172                 :                :  * format string) and append it to whatever is already in str.  If successful
                                173                 :                :  * return zero; if not (because there's not enough space), return an estimate
                                174                 :                :  * of the space needed, without modifying str.  Typically the caller should
                                175                 :                :  * pass the return value to enlargeStringInfo() before trying again; see
                                176                 :                :  * appendStringInfo for standard usage pattern.
                                177                 :                :  *
                                178                 :                :  * Caution: callers must be sure to preserve their entry-time errno
                                179                 :                :  * when looping, in case the fmt contains "%m".
                                180                 :                :  *
                                181                 :                :  * XXX This API is ugly, but there seems no alternative given the C spec's
                                182                 :                :  * restrictions on what can portably be done with va_list arguments: you have
                                183                 :                :  * to redo va_start before you can rescan the argument list, and we can't do
                                184                 :                :  * that from here.
                                185                 :                :  */
                                186                 :                : int
                                187                 :       14869366 : appendStringInfoVA(StringInfo str, const char *fmt, va_list args)
                                188                 :                : {
                                189                 :                :     int         avail;
                                190                 :                :     size_t      nprinted;
                                191                 :                : 
 9821                           192         [ -  + ]:       14869366 :     Assert(str != NULL);
                                193                 :                : 
                                194                 :                :     /*
                                195                 :                :      * If there's hardly any space, don't bother trying, just fail to make the
                                196                 :                :      * caller enlarge the buffer first.  We have to guess at how much to
                                197                 :                :      * enlarge, since we're skipping the formatting work.
                                198                 :                :      */
 4525                           199                 :       14869366 :     avail = str->maxlen - str->len;
 8361                           200         [ +  + ]:       14869366 :     if (avail < 16)
 4525                           201                 :          23314 :         return 32;
                                202                 :                : 
                                203                 :       14846052 :     nprinted = pvsnprintf(str->data + str->len, (size_t) avail, fmt, args);
                                204                 :                : 
                                205         [ +  + ]:       14846052 :     if (nprinted < (size_t) avail)
                                206                 :                :     {
                                207                 :                :         /* Success.  Note nprinted does not include trailing null. */
                                208                 :       14842537 :         str->len += (int) nprinted;
                                209                 :       14842537 :         return 0;
                                210                 :                :     }
                                211                 :                : 
                                212                 :                :     /* Restore the trailing null so that str is unmodified. */
 8361                           213                 :           3515 :     str->data[str->len] = '\0';
                                214                 :                : 
                                215                 :                :     /*
                                216                 :                :      * Return pvsnprintf's estimate of the space needed.  (Although this is
                                217                 :                :      * given as a size_t, we know it will fit in int because it's not more
                                218                 :                :      * than MaxAllocSize.)
                                219                 :                :      */
 4525                           220                 :           3515 :     return (int) nprinted;
                                221                 :                : }
                                222                 :                : 
                                223                 :                : /*
                                224                 :                :  * appendStringInfoString
                                225                 :                :  *
                                226                 :                :  * Append a null-terminated string to str.
                                227                 :                :  * Like appendStringInfo(str, "%s", s) but faster.
                                228                 :                :  */
                                229                 :                : void
 8361                           230                 :        9249348 : appendStringInfoString(StringInfo str, const char *s)
                                231                 :                : {
                                232                 :        9249348 :     appendBinaryStringInfo(str, s, strlen(s));
 9821                           233                 :        9249348 : }
                                234                 :                : 
                                235                 :                : /*
                                236                 :                :  * appendStringInfoChar
                                237                 :                :  *
                                238                 :                :  * Append a single byte to str.
                                239                 :                :  * Like appendStringInfo(str, "%c", ch) but much faster.
                                240                 :                :  */
                                241                 :                : void
                                242                 :       46250165 : appendStringInfoChar(StringInfo str, char ch)
                                243                 :                : {
                                244                 :                :     /* Make more room if needed */
 9631                           245         [ +  + ]:       46250165 :     if (str->len + 1 >= str->maxlen)
                                246                 :          13943 :         enlargeStringInfo(str, 1);
                                247                 :                : 
                                248                 :                :     /* OK, append the character */
 9821                           249                 :       46250165 :     str->data[str->len] = ch;
                                250                 :       46250165 :     str->len++;
                                251                 :       46250165 :     str->data[str->len] = '\0';
                                252                 :       46250165 : }
                                253                 :                : 
                                254                 :                : /*
                                255                 :                :  * appendStringInfoSpaces
                                256                 :                :  *
                                257                 :                :  * Append the specified number of spaces to a buffer.
                                258                 :                :  */
                                259                 :                : void
 6078                           260                 :         113246 : appendStringInfoSpaces(StringInfo str, int count)
                                261                 :                : {
                                262         [ +  + ]:         113246 :     if (count > 0)
                                263                 :                :     {
                                264                 :                :         /* Make more room if needed */
                                265                 :         109892 :         enlargeStringInfo(str, count);
                                266                 :                : 
                                267                 :                :         /* OK, append the spaces */
 1150 drowley@postgresql.o      268                 :         109892 :         memset(&str->data[str->len], ' ', count);
                                269                 :         109892 :         str->len += count;
 6078 tgl@sss.pgh.pa.us         270                 :         109892 :         str->data[str->len] = '\0';
                                271                 :                :     }
                                272                 :         113246 : }
                                273                 :                : 
                                274                 :                : /*
                                275                 :                :  * appendBinaryStringInfo
                                276                 :                :  *
                                277                 :                :  * Append arbitrary binary data to a StringInfo, allocating more space
                                278                 :                :  * if necessary. Ensures that a trailing null byte is present.
                                279                 :                :  */
                                280                 :                : void
 1171 peter@eisentraut.org      281                 :       20794689 : appendBinaryStringInfo(StringInfo str, const void *data, int datalen)
                                282                 :                : {
 9821 tgl@sss.pgh.pa.us         283         [ -  + ]:       20794689 :     Assert(str != NULL);
                                284                 :                : 
                                285                 :                :     /* Make more room if needed */
                                286                 :       20794689 :     enlargeStringInfo(str, datalen);
                                287                 :                : 
                                288                 :                :     /* OK, append the data */
                                289                 :       20794689 :     memcpy(str->data + str->len, data, datalen);
                                290                 :       20794689 :     str->len += datalen;
                                291                 :                : 
                                292                 :                :     /*
                                293                 :                :      * Keep a trailing null in place, even though it's probably useless for
                                294                 :                :      * binary data.  (Some callers are dealing with text but call this because
                                295                 :                :      * their input isn't null-terminated.)
                                296                 :                :      */
                                297                 :       20794689 :     str->data[str->len] = '\0';
10841 scrappy@hub.org           298                 :       20794689 : }
                                299                 :                : 
                                300                 :                : /*
                                301                 :                :  * appendBinaryStringInfoNT
                                302                 :                :  *
                                303                 :                :  * Append arbitrary binary data to a StringInfo, allocating more space
                                304                 :                :  * if necessary. Does not ensure a trailing null-byte exists.
                                305                 :                :  */
                                306                 :                : void
 1171 peter@eisentraut.org      307                 :       23509519 : appendBinaryStringInfoNT(StringInfo str, const void *data, int datalen)
                                308                 :                : {
 3077 andres@anarazel.de        309         [ -  + ]:       23509519 :     Assert(str != NULL);
                                310                 :                : 
                                311                 :                :     /* Make more room if needed */
                                312                 :       23509519 :     enlargeStringInfo(str, datalen);
                                313                 :                : 
                                314                 :                :     /* OK, append the data */
                                315                 :       23509519 :     memcpy(str->data + str->len, data, datalen);
                                316                 :       23509519 :     str->len += datalen;
                                317                 :       23509519 : }
                                318                 :                : 
                                319                 :                : /*
                                320                 :                :  * enlargeStringInfo
                                321                 :                :  *
                                322                 :                :  * Make sure there is enough space for 'needed' more bytes
                                323                 :                :  * ('needed' does not include the terminating null).
                                324                 :                :  *
                                325                 :                :  * External callers usually need not concern themselves with this, since
                                326                 :                :  * all stringinfo.c routines do it automatically.  However, if a caller
                                327                 :                :  * knows that a StringInfo will eventually become X bytes large, it
                                328                 :                :  * can save some palloc overhead by enlarging the buffer before starting
                                329                 :                :  * to store data in it.
                                330                 :                :  *
                                331                 :                :  * NB: In the backend, because we use repalloc() to enlarge the buffer, the
                                332                 :                :  * string buffer will remain allocated in the same memory context that was
                                333                 :                :  * current when initStringInfo was called, even if another context is now
                                334                 :                :  * current.  This is the desired and indeed critical behavior!
                                335                 :                :  */
                                336                 :                : void
 8366 tgl@sss.pgh.pa.us         337                 :       79864559 : enlargeStringInfo(StringInfo str, int needed)
                                338                 :                : {
                                339                 :                :     int         newlen;
                                340                 :                : 
                                341                 :                :     /* validate this is not a read-only StringInfo */
  871 drowley@postgresql.o      342         [ -  + ]:       79864559 :     Assert(str->maxlen != 0);
                                343                 :                : 
                                344                 :                :     /*
                                345                 :                :      * Guard against out-of-range "needed" values.  Without this, we can get
                                346                 :                :      * an overflow or infinite loop in the following.
                                347                 :                :      */
 6866 tgl@sss.pgh.pa.us         348         [ -  + ]:       79864559 :     if (needed < 0)              /* should not happen */
                                349                 :                :     {
                                350                 :                : #ifndef FRONTEND
 6866 tgl@sss.pgh.pa.us         351         [ #  # ]:UBC           0 :         elog(ERROR, "invalid string enlargement request size: %d", needed);
                                352                 :                : #else
 2322 andres@anarazel.de        353                 :              0 :         fprintf(stderr, "invalid string enlargement request size: %d\n", needed);
                                354                 :              0 :         exit(EXIT_FAILURE);
                                355                 :                : #endif
                                356                 :                :     }
 3231 alvherre@alvh.no-ip.      357         [ -  + ]:CBC    79864559 :     if (((Size) needed) >= (MaxAllocSize - (Size) str->len))
                                358                 :                :     {
                                359                 :                : #ifndef FRONTEND
 6866 tgl@sss.pgh.pa.us         360         [ #  # ]:UBC           0 :         ereport(ERROR,
                                361                 :                :                 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
                                362                 :                :                  errmsg("string buffer exceeds maximum allowed length (%zu bytes)", MaxAllocSize),
                                363                 :                :                  errdetail("Cannot enlarge string buffer containing %d bytes by %d more bytes.",
                                364                 :                :                            str->len, needed)));
                                365                 :                : #else
 2322 andres@anarazel.de        366                 :              0 :         fprintf(stderr,
  622 drowley@postgresql.o      367                 :              0 :                 _("string buffer exceeds maximum allowed length (%zu bytes)\n\nCannot enlarge string buffer containing %d bytes by %d more bytes.\n"),
                                368                 :                :                 MaxAllocSize, str->len, needed);
 2322 andres@anarazel.de        369                 :              0 :         exit(EXIT_FAILURE);
                                370                 :                : #endif
                                371                 :                :     }
                                372                 :                : 
 8366 tgl@sss.pgh.pa.us         373                 :CBC    79864559 :     needed += str->len + 1;      /* total space required now */
                                374                 :                : 
                                375                 :                :     /* Because of the above test, we now have needed <= MaxAllocSize */
                                376                 :                : 
                                377         [ +  + ]:       79864559 :     if (needed <= str->maxlen)
                                378                 :       79741102 :         return;                 /* got enough space already */
                                379                 :                : 
                                380                 :                :     /*
                                381                 :                :      * We don't want to allocate just a little more space with each append;
                                382                 :                :      * for efficiency, double the buffer size each time it overflows.
                                383                 :                :      * Actually, we might need to more than double it if 'needed' is big...
                                384                 :                :      */
 3231 alvherre@alvh.no-ip.      385                 :         123457 :     newlen = 2 * str->maxlen;
                                386         [ +  + ]:         249296 :     while (needed > newlen)
 8366 tgl@sss.pgh.pa.us         387                 :         125839 :         newlen = 2 * newlen;
                                388                 :                : 
                                389                 :                :     /*
                                390                 :                :      * Clamp to MaxAllocSize in case we went past it.  Note we are assuming
                                391                 :                :      * here that MaxAllocSize <= INT_MAX/2, else the above loop could
                                392                 :                :      * overflow.  We will still have newlen >= needed.
                                393                 :                :      */
 3231 alvherre@alvh.no-ip.      394         [ -  + ]:         123457 :     if (newlen > (int) MaxAllocSize)
 3231 alvherre@alvh.no-ip.      395                 :UBC           0 :         newlen = (int) MaxAllocSize;
                                396                 :                : 
 3231 alvherre@alvh.no-ip.      397                 :CBC      123457 :     str->data = (char *) repalloc(str->data, newlen);
                                398                 :                : 
 8366 tgl@sss.pgh.pa.us         399                 :         123457 :     str->maxlen = newlen;
                                400                 :                : }
                                401                 :                : 
                                402                 :                : /*
                                403                 :                :  * destroyStringInfo
                                404                 :                :  *
                                405                 :                :  * Frees a StringInfo and its buffer (opposite of makeStringInfo()).
                                406                 :                :  * This must only be called on palloc'd StringInfos.
                                407                 :                :  */
                                408                 :                : void
  729 dgustafsson@postgres      409                 :           4286 : destroyStringInfo(StringInfo str)
                                410                 :                : {
                                411                 :                :     /* don't allow destroys of read-only StringInfos */
                                412         [ -  + ]:           4286 :     Assert(str->maxlen != 0);
                                413                 :                : 
                                414                 :           4286 :     pfree(str->data);
                                415                 :           4286 :     pfree(str);
                                416                 :           4286 : }
        

Generated by: LCOV version 2.4-beta