Branch data 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
41 : 9712441 : initStringInfoInternal(StringInfo str, int initsize)
42 : : {
43 : : Assert(initsize >= 1 && initsize <= MaxAllocSize);
44 : :
45 : 9712441 : str->data = (char *) palloc(initsize);
46 : 9712441 : str->maxlen = initsize;
47 : 9712441 : resetStringInfo(str);
48 : 9712441 : }
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 : 66315 : makeStringInfoInternal(int initsize)
59 : : {
60 : 66315 : StringInfo res = palloc_object(StringInfoData);
61 : :
62 : 66315 : initStringInfoInternal(res, initsize);
63 : 66315 : return res;
64 : : }
65 : :
66 : : /*
67 : : * makeStringInfo
68 : : *
69 : : * Create an empty 'StringInfoData' & return a pointer to it.
70 : : */
71 : : StringInfo
72 : 66263 : makeStringInfo(void)
73 : : {
74 : 66263 : 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
97 : 9632643 : initStringInfo(StringInfo str)
98 : : {
99 : 9632643 : initStringInfoInternal(str, STRINGINFO_DEFAULT_SIZE);
100 : 9632643 : }
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 : 13483 : initStringInfoExt(StringInfo str, int initsize)
112 : : {
113 : 13483 : initStringInfoInternal(str, initsize);
114 : 13483 : }
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 : 24624662 : resetStringInfo(StringInfo str)
127 : : {
128 : : /* don't allow resets of read-only StringInfos */
129 : : Assert(str->maxlen != 0);
130 : :
131 : 24624662 : str->data[0] = '\0';
132 : 24624662 : str->len = 0;
133 : 24624662 : str->cursor = 0;
134 : 24624662 : }
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 : 311747054 : appendStringInfo(StringInfo str, const char *fmt, ...)
146 : : {
147 : 311747054 : int save_errno = errno;
148 : :
149 : : for (;;)
150 : 1082915 : {
151 : : va_list args;
152 : : int needed;
153 : :
154 : : /* Try to format the data. */
155 : 312829969 : va_start(args, fmt);
156 : 312829969 : needed = appendStringInfoVA(str, fmt, args);
157 : 312829969 : va_end(args);
158 : :
159 [ + + ]: 312829969 : if (likely(needed == 0))
160 : 311747054 : break; /* success */
161 : :
162 : : /* Increase the buffer size and try again. */
163 : 1082915 : enlargeStringInfo(str, needed);
164 : 1082915 : errno = save_errno;
165 : : }
166 : 311747054 : }
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 : : inline int
187 : 314104331 : appendStringInfoVA(StringInfo str, const char *fmt, va_list args)
188 : : {
189 : : int avail;
190 : : int nprinted;
191 : :
192 : : /*
193 : : * If there's hardly any space, don't bother trying, just fail to make the
194 : : * caller enlarge the buffer first. We have to guess at how much to
195 : : * enlarge, since we're skipping the formatting work.
196 : : */
197 : 314104331 : avail = str->maxlen - str->len;
198 [ + + ]: 314104331 : if (avail < 16)
199 : 995153 : return 32;
200 : :
201 : 313109178 : nprinted = vsnprintf(str->data + str->len, (size_t) avail, fmt, args);
202 : :
203 : : /* We assume failure means the fmt is bogus, hence hard failure is OK */
204 [ - + ]: 313109178 : if (unlikely(nprinted < 0))
205 : : {
206 : : #ifndef FRONTEND
207 [ # # ]: 0 : elog(ERROR, "vsnprintf failed: %m with format string \"%s\"", fmt);
208 : : #else
209 : 0 : fprintf(stderr, "vsnprintf failed: %m with format string \"%s\"\n",
210 : : fmt);
211 : 0 : exit(EXIT_FAILURE);
212 : : #endif
213 : : }
214 : :
215 [ + + ]: 313109178 : if (likely(nprinted < avail))
216 : : {
217 : : /* Success. Note nprinted does not include trailing null. */
218 : 313018843 : str->len += nprinted;
219 : 313018843 : return 0;
220 : : }
221 : :
222 : : /* Restore the trailing null so that str is unmodified. */
223 : 90335 : str->data[str->len] = '\0';
224 : :
225 : : /*
226 : : * We assume a C99-compliant vsnprintf, so believe its estimate of the
227 : : * required space. (If it's wrong, the logic will still work, but we may
228 : : * loop multiple times.)
229 : : *
230 : : * Unlike pvsnprintf(), we don't check for overrunning MaxAllocSize,
231 : : * preferring to leave that to enlargeStringInfo().
232 : : */
233 : 90335 : return nprinted;
234 : : }
235 : :
236 : : /*
237 : : * appendStringInfoString
238 : : *
239 : : * Append a null-terminated string to str.
240 : : * Like appendStringInfo(str, "%s", s) but faster.
241 : : */
242 : : void
243 : 180571752 : appendStringInfoString(StringInfo str, const char *s)
244 : : {
245 : 180571752 : appendBinaryStringInfo(str, s, strlen(s));
246 : 180571752 : }
247 : :
248 : : /*
249 : : * appendStringInfoChar
250 : : *
251 : : * Append a single byte to str.
252 : : * Like appendStringInfo(str, "%c", ch) but much faster.
253 : : */
254 : : void
255 : 451665837 : appendStringInfoChar(StringInfo str, char ch)
256 : : {
257 : : /* Make more room if needed */
258 [ + + ]: 451665837 : if (str->len + 1 >= str->maxlen)
259 : 135807 : enlargeStringInfo(str, 1);
260 : :
261 : : /* OK, append the character */
262 : 451665837 : str->data[str->len] = ch;
263 : 451665837 : str->len++;
264 : 451665837 : str->data[str->len] = '\0';
265 : 451665837 : }
266 : :
267 : : /*
268 : : * appendStringInfoSpaces
269 : : *
270 : : * Append the specified number of spaces to a buffer.
271 : : */
272 : : void
273 : 151839 : appendStringInfoSpaces(StringInfo str, int count)
274 : : {
275 [ + + ]: 151839 : if (count > 0)
276 : : {
277 : : /* Make more room if needed */
278 : 147381 : enlargeStringInfo(str, count);
279 : :
280 : : /* OK, append the spaces */
281 : 147381 : memset(&str->data[str->len], ' ', count);
282 : 147381 : str->len += count;
283 : 147381 : str->data[str->len] = '\0';
284 : : }
285 : 151839 : }
286 : :
287 : : /*
288 : : * appendBinaryStringInfo
289 : : *
290 : : * Append arbitrary binary data to a StringInfo, allocating more space
291 : : * if necessary. Ensures that a trailing null byte is present.
292 : : */
293 : : void
294 : 192713087 : appendBinaryStringInfo(StringInfo str, const void *data, int datalen)
295 : : {
296 : : Assert(str != NULL);
297 : :
298 : : /* Make more room if needed */
299 : 192713087 : enlargeStringInfo(str, datalen);
300 : :
301 : : /* OK, append the data */
302 : 192713087 : memcpy(str->data + str->len, data, datalen);
303 : 192713087 : str->len += datalen;
304 : :
305 : : /*
306 : : * Keep a trailing null in place, even though it's probably useless for
307 : : * binary data. (Some callers are dealing with text but call this because
308 : : * their input isn't null-terminated.)
309 : : */
310 : 192713087 : str->data[str->len] = '\0';
311 : 192713087 : }
312 : :
313 : : /*
314 : : * appendBinaryStringInfoNT
315 : : *
316 : : * Append arbitrary binary data to a StringInfo, allocating more space
317 : : * if necessary. Does not ensure a trailing null-byte exists.
318 : : */
319 : : void
320 : 20519900 : appendBinaryStringInfoNT(StringInfo str, const void *data, int datalen)
321 : : {
322 : : Assert(str != NULL);
323 : :
324 : : /* Make more room if needed */
325 : 20519900 : enlargeStringInfo(str, datalen);
326 : :
327 : : /* OK, append the data */
328 : 20519900 : memcpy(str->data + str->len, data, datalen);
329 : 20519900 : str->len += datalen;
330 : 20519900 : }
331 : :
332 : : /*
333 : : * enlargeStringInfo
334 : : *
335 : : * Make sure there is enough space for 'needed' more bytes
336 : : * ('needed' does not include the terminating null).
337 : : *
338 : : * External callers usually need not concern themselves with this, since
339 : : * all stringinfo.c routines do it automatically. However, if a caller
340 : : * knows that a StringInfo will eventually become X bytes large, it
341 : : * can save some palloc overhead by enlarging the buffer before starting
342 : : * to store data in it.
343 : : *
344 : : * NB: In the backend, because we use repalloc() to enlarge the buffer, the
345 : : * string buffer will remain allocated in the same memory context that was
346 : : * current when initStringInfo was called, even if another context is now
347 : : * current. This is the desired and indeed critical behavior!
348 : : */
349 : : void
350 : 247941970 : enlargeStringInfo(StringInfo str, int needed)
351 : : {
352 : : int newlen;
353 : :
354 : : /* validate this is not a read-only StringInfo */
355 : : Assert(str->maxlen != 0);
356 : :
357 : : /*
358 : : * Guard against out-of-range "needed" values. Without this, we can get
359 : : * an overflow or infinite loop in the following.
360 : : */
361 [ - + ]: 247941970 : if (needed < 0) /* should not happen */
362 : : {
363 : : #ifndef FRONTEND
364 [ # # ]: 0 : elog(ERROR, "invalid string enlargement request size: %d", needed);
365 : : #else
366 : 0 : fprintf(stderr, "invalid string enlargement request size: %d\n", needed);
367 : 0 : exit(EXIT_FAILURE);
368 : : #endif
369 : : }
370 [ - + ]: 247941970 : if (((Size) needed) >= (MaxAllocSize - (Size) str->len))
371 : : {
372 : : #ifndef FRONTEND
373 [ # # ]: 0 : ereport(ERROR,
374 : : (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
375 : : errmsg("string buffer exceeds maximum allowed length (%zu bytes)", MaxAllocSize),
376 : : errdetail("Cannot enlarge string buffer containing %d bytes by %d more bytes.",
377 : : str->len, needed)));
378 : : #else
379 : 0 : fprintf(stderr,
380 : 0 : _("string buffer exceeds maximum allowed length (%zu bytes)\n\nCannot enlarge string buffer containing %d bytes by %d more bytes.\n"),
381 : : MaxAllocSize, str->len, needed);
382 : 0 : exit(EXIT_FAILURE);
383 : : #endif
384 : : }
385 : :
386 : 247941970 : needed += str->len + 1; /* total space required now */
387 : :
388 : : /* Because of the above test, we now have needed <= MaxAllocSize */
389 : :
390 [ + + ]: 247941970 : if (needed <= str->maxlen)
391 : 246033534 : return; /* got enough space already */
392 : :
393 : : /*
394 : : * We don't want to allocate just a little more space with each append;
395 : : * for efficiency, double the buffer size each time it overflows.
396 : : * Actually, we might need to more than double it if 'needed' is big...
397 : : */
398 : 1908436 : newlen = 2 * str->maxlen;
399 [ + + ]: 2070519 : while (needed > newlen)
400 : 162083 : newlen = 2 * newlen;
401 : :
402 : : /*
403 : : * Clamp to MaxAllocSize in case we went past it. Note we are assuming
404 : : * here that MaxAllocSize <= INT_MAX/2, else the above loop could
405 : : * overflow. We will still have newlen >= needed.
406 : : */
407 [ - + ]: 1908436 : if (newlen > (int) MaxAllocSize)
408 : 0 : newlen = (int) MaxAllocSize;
409 : :
410 : 1908436 : str->data = (char *) repalloc(str->data, newlen);
411 : :
412 : 1908436 : str->maxlen = newlen;
413 : : }
414 : :
415 : : /*
416 : : * destroyStringInfo
417 : : *
418 : : * Frees a StringInfo and its buffer (opposite of makeStringInfo()).
419 : : * This must only be called on palloc'd StringInfos.
420 : : */
421 : : void
422 : 5584 : destroyStringInfo(StringInfo str)
423 : : {
424 : : /* don't allow destroys of read-only StringInfos */
425 : : Assert(str->maxlen != 0);
426 : :
427 : 5584 : pfree(str->data);
428 : 5584 : pfree(str);
429 : 5584 : }
|