LCOV - differential code coverage report
Current view: top level - src/common - stringinfo.c (source / functions) Coverage Total Hit UBC GNC CBC DCB
Current: Differential Code Coverage HEAD vs 15 Lines: 90.8 % 87 79 8 4 75 4
Current Date: 2023-04-08 17:13:01 Functions: 100.0 % 11 11 3 8 2
Baseline: 15 Line coverage date bins:
Baseline Date: 2023-04-08 15:09:40 (60,120] days: 100.0 % 4 4 4
Legend: Lines: hit not hit (240..) days: 90.4 % 83 75 8 75
Function coverage date bins:
(60,120] days: 100.0 % 2 2 2
(240..) days: 100.0 % 9 9 1 8

 Age         Owner                  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-2023, 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                 : /* It's possible we could use a different value for this in frontend code */
                                 28                 : #define MaxAllocSize    ((Size) 0x3fffffff) /* 1 gigabyte - 1 */
                                 29                 : 
                                 30                 : #endif
                                 31                 : 
                                 32                 : #include "lib/stringinfo.h"
                                 33                 : 
                                 34                 : 
                                 35                 : /*
                                 36                 :  * makeStringInfo
                                 37                 :  *
                                 38                 :  * Create an empty 'StringInfoData' & return a pointer to it.
                                 39                 :  */
                                 40                 : StringInfo
 8750 tgl                        41 CBC       43774 : makeStringInfo(void)
                                 42                 : {
                                 43                 :     StringInfo  res;
                                 44                 : 
 9345 bruce                      45           43774 :     res = (StringInfo) palloc(sizeof(StringInfoData));
                                 46                 : 
 8750 tgl                        47           43774 :     initStringInfo(res);
                                 48                 : 
 8986 bruce                      49           43774 :     return res;
                                 50                 : }
                                 51                 : 
                                 52                 : /*
                                 53                 :  * initStringInfo
                                 54                 :  *
                                 55                 :  * Initialize a StringInfoData struct (with previously undefined contents)
                                 56                 :  * to describe an empty string.
                                 57                 :  */
                                 58                 : void
 8750 tgl                        59         3461519 : initStringInfo(StringInfo str)
                                 60                 : {
 5624 bruce                      61         3461519 :     int         size = 1024;    /* initial default buffer size */
                                 62                 : 
 8622 tgl                        63         3461519 :     str->data = (char *) palloc(size);
 8750                            64         3461519 :     str->maxlen = size;
 5881 neilc                      65         3461519 :     resetStringInfo(str);
                                 66         3461519 : }
                                 67                 : 
                                 68                 : /*
                                 69                 :  * resetStringInfo
                                 70                 :  *
                                 71                 :  * Reset the StringInfo: the data buffer remains valid, but its
                                 72                 :  * previous content, if any, is cleared.
                                 73                 :  */
                                 74                 : void
                                 75        19262388 : resetStringInfo(StringInfo str)
                                 76                 : {
 8750 tgl                        77        19262388 :     str->data[0] = '\0';
 5881 neilc                      78        19262388 :     str->len = 0;
 7295 tgl                        79        19262388 :     str->cursor = 0;
 8750                            80        19262388 : }
                                 81                 : 
                                 82                 : /*
                                 83                 :  * appendStringInfo
                                 84                 :  *
                                 85                 :  * Format text data under the control of fmt (an sprintf-style format string)
                                 86                 :  * and append it to whatever is already in str.  More space is allocated
                                 87                 :  * to str if necessary.  This is sort of like a combination of sprintf and
                                 88                 :  * strcat.
                                 89                 :  */
                                 90                 : void
 7188 bruce                      91        56644065 : appendStringInfo(StringInfo str, const char *fmt,...)
                                 92                 : {
 1656 tgl                        93        56644065 :     int         save_errno = errno;
                                 94                 : 
                                 95                 :     for (;;)
 7290                            96          119076 :     {
                                 97                 :         va_list     args;
                                 98                 :         int         needed;
                                 99                 : 
                                100                 :         /* Try to format the data. */
 1656                           101        56763141 :         errno = save_errno;
 7290                           102        56763141 :         va_start(args, fmt);
 3454                           103        56763141 :         needed = appendStringInfoVA(str, fmt, args);
 7290                           104        56763141 :         va_end(args);
                                105                 : 
 3454                           106        56763141 :         if (needed == 0)
                                107        56644065 :             break;              /* success */
                                108                 : 
                                109                 :         /* Increase the buffer size and try again. */
                                110          119076 :         enlargeStringInfo(str, needed);
                                111                 :     }
 7290                           112        56644065 : }
                                113                 : 
                                114                 : /*
                                115                 :  * appendStringInfoVA
                                116                 :  *
                                117                 :  * Attempt to format text data under the control of fmt (an sprintf-style
                                118                 :  * format string) and append it to whatever is already in str.  If successful
                                119                 :  * return zero; if not (because there's not enough space), return an estimate
                                120                 :  * of the space needed, without modifying str.  Typically the caller should
                                121                 :  * pass the return value to enlargeStringInfo() before trying again; see
                                122                 :  * appendStringInfo for standard usage pattern.
                                123                 :  *
                                124                 :  * Caution: callers must be sure to preserve their entry-time errno
                                125                 :  * when looping, in case the fmt contains "%m".
                                126                 :  *
                                127                 :  * XXX This API is ugly, but there seems no alternative given the C spec's
                                128                 :  * restrictions on what can portably be done with va_list arguments: you have
                                129                 :  * to redo va_start before you can rescan the argument list, and we can't do
                                130                 :  * that from here.
                                131                 :  */
                                132                 : int
                                133        57000105 : appendStringInfoVA(StringInfo str, const char *fmt, va_list args)
                                134                 : {
                                135                 :     int         avail;
                                136                 :     size_t      nprinted;
                                137                 : 
 8750                           138        57000105 :     Assert(str != NULL);
                                139                 : 
                                140                 :     /*
                                141                 :      * If there's hardly any space, don't bother trying, just fail to make the
                                142                 :      * caller enlarge the buffer first.  We have to guess at how much to
                                143                 :      * enlarge, since we're skipping the formatting work.
                                144                 :      */
 3454                           145        57000105 :     avail = str->maxlen - str->len;
 7290                           146        57000105 :     if (avail < 16)
 3454                           147          115916 :         return 32;
                                148                 : 
                                149        56884189 :     nprinted = pvsnprintf(str->data + str->len, (size_t) avail, fmt, args);
                                150                 : 
                                151        56884189 :     if (nprinted < (size_t) avail)
                                152                 :     {
                                153                 :         /* Success.  Note nprinted does not include trailing null. */
                                154        56879901 :         str->len += (int) nprinted;
                                155        56879901 :         return 0;
                                156                 :     }
                                157                 : 
                                158                 :     /* Restore the trailing null so that str is unmodified. */
 7290                           159            4288 :     str->data[str->len] = '\0';
                                160                 : 
                                161                 :     /*
                                162                 :      * Return pvsnprintf's estimate of the space needed.  (Although this is
                                163                 :      * given as a size_t, we know it will fit in int because it's not more
                                164                 :      * than MaxAllocSize.)
                                165                 :      */
 3454                           166            4288 :     return (int) nprinted;
                                167                 : }
                                168                 : 
                                169                 : /*
                                170                 :  * appendStringInfoString
                                171                 :  *
                                172                 :  * Append a null-terminated string to str.
                                173                 :  * Like appendStringInfo(str, "%s", s) but faster.
                                174                 :  */
                                175                 : void
 7290                           176        24299141 : appendStringInfoString(StringInfo str, const char *s)
                                177                 : {
                                178        24299141 :     appendBinaryStringInfo(str, s, strlen(s));
 8750                           179        24299141 : }
                                180                 : 
                                181                 : /*
                                182                 :  * appendStringInfoChar
                                183                 :  *
                                184                 :  * Append a single byte to str.
                                185                 :  * Like appendStringInfo(str, "%c", ch) but much faster.
                                186                 :  */
                                187                 : void
                                188       185273738 : appendStringInfoChar(StringInfo str, char ch)
                                189                 : {
                                190                 :     /* Make more room if needed */
 8560                           191       185273738 :     if (str->len + 1 >= str->maxlen)
                                192           62511 :         enlargeStringInfo(str, 1);
                                193                 : 
                                194                 :     /* OK, append the character */
 8750                           195       185273738 :     str->data[str->len] = ch;
                                196       185273738 :     str->len++;
                                197       185273738 :     str->data[str->len] = '\0';
                                198       185273738 : }
                                199                 : 
                                200                 : /*
                                201                 :  * appendStringInfoSpaces
                                202                 :  *
                                203                 :  * Append the specified number of spaces to a buffer.
                                204                 :  */
                                205                 : void
 5007                           206           75400 : appendStringInfoSpaces(StringInfo str, int count)
                                207                 : {
                                208           75400 :     if (count > 0)
                                209                 :     {
                                210                 :         /* Make more room if needed */
                                211           72814 :         enlargeStringInfo(str, count);
                                212                 : 
                                213                 :         /* OK, append the spaces */
   79 drowley                   214 GNC       72814 :         memset(&str->data[str->len], ' ', count);
                                215           72814 :         str->len += count;
 5007 tgl                       216 CBC       72814 :         str->data[str->len] = '\0';
                                217                 :     }
                                218           75400 : }
                                219                 : 
                                220                 : /*
                                221                 :  * appendBinaryStringInfo
                                222                 :  *
                                223                 :  * Append arbitrary binary data to a StringInfo, allocating more space
                                224                 :  * if necessary. Ensures that a trailing null byte is present.
                                225                 :  */
                                226                 : void
  100 peter                     227 GNC    32449729 : appendBinaryStringInfo(StringInfo str, const void *data, int datalen)
                                228                 : {
 8750 tgl                       229 CBC    32449729 :     Assert(str != NULL);
                                230                 : 
                                231                 :     /* Make more room if needed */
                                232        32449729 :     enlargeStringInfo(str, datalen);
                                233                 : 
                                234                 :     /* OK, append the data */
                                235        32449729 :     memcpy(str->data + str->len, data, datalen);
                                236        32449729 :     str->len += datalen;
                                237                 : 
                                238                 :     /*
                                239                 :      * Keep a trailing null in place, even though it's probably useless for
                                240                 :      * binary data.  (Some callers are dealing with text but call this because
                                241                 :      * their input isn't null-terminated.)
                                242                 :      */
                                243        32449729 :     str->data[str->len] = '\0';
 9770 scrappy                   244        32449729 : }
                                245                 : 
                                246                 : /*
                                247                 :  * appendBinaryStringInfoNT
                                248                 :  *
                                249                 :  * Append arbitrary binary data to a StringInfo, allocating more space
                                250                 :  * if necessary. Does not ensure a trailing null-byte exists.
                                251                 :  */
                                252                 : void
  100 peter                     253 GNC    13934242 : appendBinaryStringInfoNT(StringInfo str, const void *data, int datalen)
                                254                 : {
 2006 andres                    255 CBC    13934242 :     Assert(str != NULL);
                                256                 : 
                                257                 :     /* Make more room if needed */
                                258        13934242 :     enlargeStringInfo(str, datalen);
                                259                 : 
                                260                 :     /* OK, append the data */
                                261        13934242 :     memcpy(str->data + str->len, data, datalen);
                                262        13934242 :     str->len += datalen;
                                263        13934242 : }
                                264                 : 
                                265                 : /*
                                266                 :  * enlargeStringInfo
                                267                 :  *
                                268                 :  * Make sure there is enough space for 'needed' more bytes
                                269                 :  * ('needed' does not include the terminating null).
                                270                 :  *
                                271                 :  * External callers usually need not concern themselves with this, since
                                272                 :  * all stringinfo.c routines do it automatically.  However, if a caller
                                273                 :  * knows that a StringInfo will eventually become X bytes large, it
                                274                 :  * can save some palloc overhead by enlarging the buffer before starting
                                275                 :  * to store data in it.
                                276                 :  *
                                277                 :  * NB: In the backend, because we use repalloc() to enlarge the buffer, the
                                278                 :  * string buffer will remain allocated in the same memory context that was
                                279                 :  * current when initStringInfo was called, even if another context is now
                                280                 :  * current.  This is the desired and indeed critical behavior!
                                281                 :  */
                                282                 : void
 7295 tgl                       283        69832025 : enlargeStringInfo(StringInfo str, int needed)
                                284                 : {
                                285                 :     int         newlen;
                                286                 : 
                                287                 :     /*
                                288                 :      * Guard against out-of-range "needed" values.  Without this, we can get
                                289                 :      * an overflow or infinite loop in the following.
                                290                 :      */
 5795                           291        69832025 :     if (needed < 0)              /* should not happen */
                                292                 :     {
                                293                 : #ifndef FRONTEND
 5795 tgl                       294 UBC           0 :         elog(ERROR, "invalid string enlargement request size: %d", needed);
                                295                 : #else
 1251 andres                    296               0 :         fprintf(stderr, "invalid string enlargement request size: %d\n", needed);
                                297               0 :         exit(EXIT_FAILURE);
                                298                 : #endif
                                299                 :     }
 2160 alvherre                  300 CBC    69832025 :     if (((Size) needed) >= (MaxAllocSize - (Size) str->len))
                                301                 :     {
                                302                 : #ifndef FRONTEND
 5795 tgl                       303 UBC           0 :         ereport(ERROR,
                                304                 :                 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
                                305                 :                  errmsg("out of memory"),
                                306                 :                  errdetail("Cannot enlarge string buffer containing %d bytes by %d more bytes.",
                                307                 :                            str->len, needed)));
                                308                 : #else
 1251 andres                    309               0 :         fprintf(stderr,
                                310               0 :                 _("out of memory\n\nCannot enlarge string buffer containing %d bytes by %d more bytes.\n"),
                                311                 :                 str->len, needed);
                                312               0 :         exit(EXIT_FAILURE);
                                313                 : #endif
                                314                 :     }
                                315                 : 
 7295 tgl                       316 CBC    69832025 :     needed += str->len + 1;      /* total space required now */
                                317                 : 
                                318                 :     /* Because of the above test, we now have needed <= MaxAllocSize */
                                319                 : 
                                320        69832025 :     if (needed <= str->maxlen)
                                321        69562121 :         return;                 /* got enough space already */
                                322                 : 
                                323                 :     /*
                                324                 :      * We don't want to allocate just a little more space with each append;
                                325                 :      * for efficiency, double the buffer size each time it overflows.
                                326                 :      * Actually, we might need to more than double it if 'needed' is big...
                                327                 :      */
 2160 alvherre                  328          269904 :     newlen = 2 * str->maxlen;
                                329          382143 :     while (needed > newlen)
 7295 tgl                       330          112239 :         newlen = 2 * newlen;
                                331                 : 
                                332                 :     /*
                                333                 :      * Clamp to MaxAllocSize in case we went past it.  Note we are assuming
                                334                 :      * here that MaxAllocSize <= INT_MAX/2, else the above loop could
                                335                 :      * overflow.  We will still have newlen >= needed.
                                336                 :      */
 2160 alvherre                  337          269904 :     if (newlen > (int) MaxAllocSize)
 2160 alvherre                  338 UBC           0 :         newlen = (int) MaxAllocSize;
                                339                 : 
 2160 alvherre                  340 CBC      269904 :     str->data = (char *) repalloc(str->data, newlen);
                                341                 : 
 7295 tgl                       342          269904 :     str->maxlen = newlen;
                                343                 : }
        

Generated by: LCOV version v1.16-55-g56c0a2a