LCOV - code coverage report
Current view: top level - src/common - stringinfo.c (source / functions) Hit Total Coverage
Test: PostgreSQL 18devel Lines: 84 97 86.6 %
Date: 2025-01-18 04:15:08 Functions: 14 16 87.5 %
Legend: Lines: hit not hit

          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
      41    11361404 : initStringInfoInternal(StringInfo str, int initsize)
      42             : {
      43             :     Assert(initsize >= 1 && initsize <= MaxAllocSize);
      44             : 
      45    11361404 :     str->data = (char *) palloc(initsize);
      46    11361404 :     str->maxlen = initsize;
      47    11361404 :     resetStringInfo(str);
      48    11361404 : }
      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      101700 : makeStringInfoInternal(int initsize)
      59             : {
      60      101700 :     StringInfo  res = (StringInfo) palloc(sizeof(StringInfoData));
      61             : 
      62      101700 :     initStringInfoInternal(res, initsize);
      63      101700 :     return res;
      64             : }
      65             : 
      66             : /*
      67             :  * makeStringInfo
      68             :  *
      69             :  * Create an empty 'StringInfoData' & return a pointer to it.
      70             :  */
      71             : StringInfo
      72      101700 : makeStringInfo(void)
      73             : {
      74      101700 :     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           0 : makeStringInfoExt(int initsize)
      86             : {
      87           0 :     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
      97    11259704 : initStringInfo(StringInfo str)
      98             : {
      99    11259704 :     initStringInfoInternal(str, STRINGINFO_DEFAULT_SIZE);
     100    11259704 : }
     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
     111           0 : initStringInfoExt(StringInfo str, int initsize)
     112             : {
     113           0 :     initStringInfoInternal(str, initsize);
     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
     126    35237604 : resetStringInfo(StringInfo str)
     127             : {
     128             :     /* don't allow resets of read-only StringInfos */
     129             :     Assert(str->maxlen != 0);
     130             : 
     131    35237604 :     str->data[0] = '\0';
     132    35237604 :     str->len = 0;
     133    35237604 :     str->cursor = 0;
     134    35237604 : }
     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
     145   408422150 : appendStringInfo(StringInfo str, const char *fmt,...)
     146             : {
     147   408422150 :     int         save_errno = errno;
     148             : 
     149             :     for (;;)
     150     1463372 :     {
     151             :         va_list     args;
     152             :         int         needed;
     153             : 
     154             :         /* Try to format the data. */
     155   409885522 :         errno = save_errno;
     156   409885522 :         va_start(args, fmt);
     157   409885522 :         needed = appendStringInfoVA(str, fmt, args);
     158   409885522 :         va_end(args);
     159             : 
     160   409885522 :         if (needed == 0)
     161   408422150 :             break;              /* success */
     162             : 
     163             :         /* Increase the buffer size and try again. */
     164     1463372 :         enlargeStringInfo(str, needed);
     165             :     }
     166   408422150 : }
     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   410979058 : appendStringInfoVA(StringInfo str, const char *fmt, va_list args)
     188             : {
     189             :     int         avail;
     190             :     size_t      nprinted;
     191             : 
     192             :     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             :      */
     199   410979058 :     avail = str->maxlen - str->len;
     200   410979058 :     if (avail < 16)
     201     1360090 :         return 32;
     202             : 
     203   409618968 :     nprinted = pvsnprintf(str->data + str->len, (size_t) avail, fmt, args);
     204             : 
     205   409618968 :     if (nprinted < (size_t) avail)
     206             :     {
     207             :         /* Success.  Note nprinted does not include trailing null. */
     208   409512910 :         str->len += (int) nprinted;
     209   409512910 :         return 0;
     210             :     }
     211             : 
     212             :     /* Restore the trailing null so that str is unmodified. */
     213      106058 :     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             :      */
     220      106058 :     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
     230   240624654 : appendStringInfoString(StringInfo str, const char *s)
     231             : {
     232   240624654 :     appendBinaryStringInfo(str, s, strlen(s));
     233   240624654 : }
     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   584936170 : appendStringInfoChar(StringInfo str, char ch)
     243             : {
     244             :     /* Make more room if needed */
     245   584936170 :     if (str->len + 1 >= str->maxlen)
     246      170458 :         enlargeStringInfo(str, 1);
     247             : 
     248             :     /* OK, append the character */
     249   584936170 :     str->data[str->len] = ch;
     250   584936170 :     str->len++;
     251   584936170 :     str->data[str->len] = '\0';
     252   584936170 : }
     253             : 
     254             : /*
     255             :  * appendStringInfoSpaces
     256             :  *
     257             :  * Append the specified number of spaces to a buffer.
     258             :  */
     259             : void
     260      200940 : appendStringInfoSpaces(StringInfo str, int count)
     261             : {
     262      200940 :     if (count > 0)
     263             :     {
     264             :         /* Make more room if needed */
     265      194934 :         enlargeStringInfo(str, count);
     266             : 
     267             :         /* OK, append the spaces */
     268      194934 :         memset(&str->data[str->len], ' ', count);
     269      194934 :         str->len += count;
     270      194934 :         str->data[str->len] = '\0';
     271             :     }
     272      200940 : }
     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
     281   262335628 : appendBinaryStringInfo(StringInfo str, const void *data, int datalen)
     282             : {
     283             :     Assert(str != NULL);
     284             : 
     285             :     /* Make more room if needed */
     286   262335628 :     enlargeStringInfo(str, datalen);
     287             : 
     288             :     /* OK, append the data */
     289   262335628 :     memcpy(str->data + str->len, data, datalen);
     290   262335628 :     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   262335628 :     str->data[str->len] = '\0';
     298   262335628 : }
     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
     307    29420480 : appendBinaryStringInfoNT(StringInfo str, const void *data, int datalen)
     308             : {
     309             :     Assert(str != NULL);
     310             : 
     311             :     /* Make more room if needed */
     312    29420480 :     enlargeStringInfo(str, datalen);
     313             : 
     314             :     /* OK, append the data */
     315    29420480 :     memcpy(str->data + str->len, data, datalen);
     316    29420480 :     str->len += datalen;
     317    29420480 : }
     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
     337   341347162 : enlargeStringInfo(StringInfo str, int needed)
     338             : {
     339             :     int         newlen;
     340             : 
     341             :     /* validate this is not a read-only StringInfo */
     342             :     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             :      */
     348   341347162 :     if (needed < 0)              /* should not happen */
     349             :     {
     350             : #ifndef FRONTEND
     351           0 :         elog(ERROR, "invalid string enlargement request size: %d", needed);
     352             : #else
     353           0 :         fprintf(stderr, "invalid string enlargement request size: %d\n", needed);
     354           0 :         exit(EXIT_FAILURE);
     355             : #endif
     356             :     }
     357   341347162 :     if (((Size) needed) >= (MaxAllocSize - (Size) str->len))
     358             :     {
     359             : #ifndef FRONTEND
     360           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
     366           0 :         fprintf(stderr,
     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);
     369           0 :         exit(EXIT_FAILURE);
     370             : #endif
     371             :     }
     372             : 
     373   341347162 :     needed += str->len + 1;      /* total space required now */
     374             : 
     375             :     /* Because of the above test, we now have needed <= MaxAllocSize */
     376             : 
     377   341347162 :     if (needed <= str->maxlen)
     378   338660386 :         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             :      */
     385     2686776 :     newlen = 2 * str->maxlen;
     386     2924960 :     while (needed > newlen)
     387      238184 :         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             :      */
     394     2686776 :     if (newlen > (int) MaxAllocSize)
     395           0 :         newlen = (int) MaxAllocSize;
     396             : 
     397     2686776 :     str->data = (char *) repalloc(str->data, newlen);
     398             : 
     399     2686776 :     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
     409        8778 : destroyStringInfo(StringInfo str)
     410             : {
     411             :     /* don't allow destroys of read-only StringInfos */
     412             :     Assert(str->maxlen != 0);
     413             : 
     414        8778 :     pfree(str->data);
     415        8778 :     pfree(str);
     416        8778 : }

Generated by: LCOV version 1.14