LCOV - differential code coverage report
Current view: top level - src/common - stringinfo.c (source / functions) Coverage Total Hit UBC CBC
Current: c70b6db34ffeab48beef1fb4ce61bcad3772b8dd vs 06473f5a344df8c9594ead90a609b86f6724cff8 Lines: 89.4 % 104 93 11 93
Current Date: 2025-09-06 07:49:51 +0900 Functions: 93.8 % 16 15 1 15
Baseline: lcov-20250906-005545-baseline Branches: 65.0 % 40 26 14 26
Baseline Date: 2025-09-05 08:21:35 +0100 Line coverage date bins:
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
(30,360] days: 88.2 % 17 15 2 15
(360..) days: 89.7 % 87 78 9 78
Function coverage date bins:
(30,360] days: 75.0 % 4 3 1 3
(360..) days: 100.0 % 12 12 12
Branch coverage date bins:
(30,360] days: 75.0 % 4 3 1 3
(360..) days: 63.9 % 36 23 13 23

 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-2025, 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
  238 ishii@postgresql.org       41                 :CBC     4345285 : initStringInfoInternal(StringInfo str, int initsize)
                                 42                 :                : {
                                 43   [ +  -  +  + ]:        4345285 :     Assert(initsize >= 1 && initsize <= MaxAllocSize);
                                 44                 :                : 
                                 45                 :        4345285 :     str->data = (char *) palloc(initsize);
                                 46                 :        4345285 :     str->maxlen = initsize;
                                 47                 :        4345285 :     resetStringInfo(str);
                                 48                 :        4345285 : }
                                 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                 :          53898 : makeStringInfoInternal(int initsize)
                                 59                 :                : {
                                 60                 :          53898 :     StringInfo  res = (StringInfo) palloc(sizeof(StringInfoData));
                                 61                 :                : 
                                 62                 :          53898 :     initStringInfoInternal(res, initsize);
                                 63                 :          53898 :     return res;
                                 64                 :                : }
                                 65                 :                : 
                                 66                 :                : /*
                                 67                 :                :  * makeStringInfo
                                 68                 :                :  *
                                 69                 :                :  * Create an empty 'StringInfoData' & return a pointer to it.
                                 70                 :                :  */
                                 71                 :                : StringInfo
 9631 tgl@sss.pgh.pa.us          72                 :          53846 : makeStringInfo(void)
                                 73                 :                : {
  238 ishii@postgresql.org       74                 :          53846 :     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
 9631 tgl@sss.pgh.pa.us          97                 :        4291387 : initStringInfo(StringInfo str)
                                 98                 :                : {
  238 ishii@postgresql.org       99                 :        4291387 :     initStringInfoInternal(str, STRINGINFO_DEFAULT_SIZE);
                                100                 :        4291387 : }
                                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
  238 ishii@postgresql.org      111                 :UBC           0 : initStringInfoExt(StringInfo str, int initsize)
                                112                 :                : {
                                113                 :              0 :     initStringInfoInternal(str, initsize);
 6762 neilc@samurai.com         114                 :              0 : }
                                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
 6762 neilc@samurai.com         126                 :CBC    17941070 : resetStringInfo(StringInfo str)
                                127                 :                : {
                                128                 :                :     /* don't allow resets of read-only StringInfos */
  681 drowley@postgresql.o      129         [ -  + ]:       17941070 :     Assert(str->maxlen != 0);
                                130                 :                : 
 9631 tgl@sss.pgh.pa.us         131                 :       17941070 :     str->data[0] = '\0';
 6762 neilc@samurai.com         132                 :       17941070 :     str->len = 0;
 8176 tgl@sss.pgh.pa.us         133                 :       17941070 :     str->cursor = 0;
 9631                           134                 :       17941070 : }
                                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
 8069 bruce@momjian.us          145                 :       13932815 : appendStringInfo(StringInfo str, const char *fmt,...)
                                146                 :                : {
 2537 tgl@sss.pgh.pa.us         147                 :       13932815 :     int         save_errno = errno;
                                148                 :                : 
                                149                 :                :     for (;;)
 8171                           150                 :          23773 :     {
                                151                 :                :         va_list     args;
                                152                 :                :         int         needed;
                                153                 :                : 
                                154                 :                :         /* Try to format the data. */
 2537                           155                 :       13956588 :         errno = save_errno;
 8171                           156                 :       13956588 :         va_start(args, fmt);
 4335                           157                 :       13956588 :         needed = appendStringInfoVA(str, fmt, args);
 8171                           158                 :       13956588 :         va_end(args);
                                159                 :                : 
 4335                           160         [ +  + ]:       13956588 :         if (needed == 0)
                                161                 :       13932815 :             break;              /* success */
                                162                 :                : 
                                163                 :                :         /* Increase the buffer size and try again. */
                                164                 :          23773 :         enlargeStringInfo(str, needed);
                                165                 :                :     }
 8171                           166                 :       13932815 : }
                                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                 :       14216967 : appendStringInfoVA(StringInfo str, const char *fmt, va_list args)
                                188                 :                : {
                                189                 :                :     int         avail;
                                190                 :                :     size_t      nprinted;
                                191                 :                : 
 9631                           192         [ -  + ]:       14216967 :     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                 :                :      */
 4335                           199                 :       14216967 :     avail = str->maxlen - str->len;
 8171                           200         [ +  + ]:       14216967 :     if (avail < 16)
 4335                           201                 :          22322 :         return 32;
                                202                 :                : 
                                203                 :       14194645 :     nprinted = pvsnprintf(str->data + str->len, (size_t) avail, fmt, args);
                                204                 :                : 
                                205         [ +  + ]:       14194645 :     if (nprinted < (size_t) avail)
                                206                 :                :     {
                                207                 :                :         /* Success.  Note nprinted does not include trailing null. */
                                208                 :       14192134 :         str->len += (int) nprinted;
                                209                 :       14192134 :         return 0;
                                210                 :                :     }
                                211                 :                : 
                                212                 :                :     /* Restore the trailing null so that str is unmodified. */
 8171                           213                 :           2511 :     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                 :                :      */
 4335                           220                 :           2511 :     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
 8171                           230                 :        8855220 : appendStringInfoString(StringInfo str, const char *s)
                                231                 :                : {
                                232                 :        8855220 :     appendBinaryStringInfo(str, s, strlen(s));
 9631                           233                 :        8855220 : }
                                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                 :       45251551 : appendStringInfoChar(StringInfo str, char ch)
                                243                 :                : {
                                244                 :                :     /* Make more room if needed */
 9441                           245         [ +  + ]:       45251551 :     if (str->len + 1 >= str->maxlen)
                                246                 :          13036 :         enlargeStringInfo(str, 1);
                                247                 :                : 
                                248                 :                :     /* OK, append the character */
 9631                           249                 :       45251551 :     str->data[str->len] = ch;
                                250                 :       45251551 :     str->len++;
                                251                 :       45251551 :     str->data[str->len] = '\0';
                                252                 :       45251551 : }
                                253                 :                : 
                                254                 :                : /*
                                255                 :                :  * appendStringInfoSpaces
                                256                 :                :  *
                                257                 :                :  * Append the specified number of spaces to a buffer.
                                258                 :                :  */
                                259                 :                : void
 5888                           260                 :         105490 : appendStringInfoSpaces(StringInfo str, int count)
                                261                 :                : {
                                262         [ +  + ]:         105490 :     if (count > 0)
                                263                 :                :     {
                                264                 :                :         /* Make more room if needed */
                                265                 :         102430 :         enlargeStringInfo(str, count);
                                266                 :                : 
                                267                 :                :         /* OK, append the spaces */
  960 drowley@postgresql.o      268                 :         102430 :         memset(&str->data[str->len], ' ', count);
                                269                 :         102430 :         str->len += count;
 5888 tgl@sss.pgh.pa.us         270                 :         102430 :         str->data[str->len] = '\0';
                                271                 :                :     }
                                272                 :         105490 : }
                                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
  981 peter@eisentraut.org      281                 :       20204358 : appendBinaryStringInfo(StringInfo str, const void *data, int datalen)
                                282                 :                : {
 9631 tgl@sss.pgh.pa.us         283         [ -  + ]:       20204358 :     Assert(str != NULL);
                                284                 :                : 
                                285                 :                :     /* Make more room if needed */
                                286                 :       20204358 :     enlargeStringInfo(str, datalen);
                                287                 :                : 
                                288                 :                :     /* OK, append the data */
                                289                 :       20204358 :     memcpy(str->data + str->len, data, datalen);
                                290                 :       20204358 :     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                 :       20204358 :     str->data[str->len] = '\0';
10651 scrappy@hub.org           298                 :       20204358 : }
                                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
  981 peter@eisentraut.org      307                 :       18090301 : appendBinaryStringInfoNT(StringInfo str, const void *data, int datalen)
                                308                 :                : {
 2887 andres@anarazel.de        309         [ -  + ]:       18090301 :     Assert(str != NULL);
                                310                 :                : 
                                311                 :                :     /* Make more room if needed */
                                312                 :       18090301 :     enlargeStringInfo(str, datalen);
                                313                 :                : 
                                314                 :                :     /* OK, append the data */
                                315                 :       18090301 :     memcpy(str->data + str->len, data, datalen);
                                316                 :       18090301 :     str->len += datalen;
                                317                 :       18090301 : }
                                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
 8176 tgl@sss.pgh.pa.us         337                 :       67453290 : enlargeStringInfo(StringInfo str, int needed)
                                338                 :                : {
                                339                 :                :     int         newlen;
                                340                 :                : 
                                341                 :                :     /* validate this is not a read-only StringInfo */
  681 drowley@postgresql.o      342         [ -  + ]:       67453290 :     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                 :                :      */
 6676 tgl@sss.pgh.pa.us         348         [ -  + ]:       67453290 :     if (needed < 0)              /* should not happen */
                                349                 :                :     {
                                350                 :                : #ifndef FRONTEND
 6676 tgl@sss.pgh.pa.us         351         [ #  # ]:UBC           0 :         elog(ERROR, "invalid string enlargement request size: %d", needed);
                                352                 :                : #else
 2132 andres@anarazel.de        353                 :              0 :         fprintf(stderr, "invalid string enlargement request size: %d\n", needed);
                                354                 :              0 :         exit(EXIT_FAILURE);
                                355                 :                : #endif
                                356                 :                :     }
 3041 alvherre@alvh.no-ip.      357         [ -  + ]:CBC    67453290 :     if (((Size) needed) >= (MaxAllocSize - (Size) str->len))
                                358                 :                :     {
                                359                 :                : #ifndef FRONTEND
 6676 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
 2132 andres@anarazel.de        366                 :              0 :         fprintf(stderr,
  432 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);
 2132 andres@anarazel.de        369                 :              0 :         exit(EXIT_FAILURE);
                                370                 :                : #endif
                                371                 :                :     }
                                372                 :                : 
 8176 tgl@sss.pgh.pa.us         373                 :CBC    67453290 :     needed += str->len + 1;      /* total space required now */
                                374                 :                : 
                                375                 :                :     /* Because of the above test, we now have needed <= MaxAllocSize */
                                376                 :                : 
                                377         [ +  + ]:       67453290 :     if (needed <= str->maxlen)
                                378                 :       67339822 :         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                 :                :      */
 3041 alvherre@alvh.no-ip.      385                 :         113468 :     newlen = 2 * str->maxlen;
                                386         [ +  + ]:         235874 :     while (needed > newlen)
 8176 tgl@sss.pgh.pa.us         387                 :         122406 :         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                 :                :      */
 3041 alvherre@alvh.no-ip.      394         [ -  + ]:         113468 :     if (newlen > (int) MaxAllocSize)
 3041 alvherre@alvh.no-ip.      395                 :UBC           0 :         newlen = (int) MaxAllocSize;
                                396                 :                : 
 3041 alvherre@alvh.no-ip.      397                 :CBC      113468 :     str->data = (char *) repalloc(str->data, newlen);
                                398                 :                : 
 8176 tgl@sss.pgh.pa.us         399                 :         113468 :     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
  539 dgustafsson@postgres      409                 :           4496 : destroyStringInfo(StringInfo str)
                                410                 :                : {
                                411                 :                :     /* don't allow destroys of read-only StringInfos */
                                412         [ -  + ]:           4496 :     Assert(str->maxlen != 0);
                                413                 :                : 
                                414                 :           4496 :     pfree(str->data);
                                415                 :           4496 :     pfree(str);
                                416                 :           4496 : }
        

Generated by: LCOV version 2.4-beta