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 : }
|