PostgreSQL Source Code git master
stringinfo.c
Go to the documentation of this file.
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 */
40static inline void
42{
43 Assert(initsize >= 1 && initsize <= MaxAllocSize);
44
45 str->data = (char *) palloc(initsize);
46 str->maxlen = initsize;
48}
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 */
57static inline StringInfo
59{
61
62 initStringInfoInternal(res, initsize);
63 return res;
64}
65
66/*
67 * makeStringInfo
68 *
69 * Create an empty 'StringInfoData' & return a pointer to it.
70 */
73{
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 */
85makeStringInfoExt(int initsize)
86{
87 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 */
96void
98{
100}
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 */
110void
112{
113 initStringInfoInternal(str, initsize);
114}
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 */
125void
127{
128 /* don't allow resets of read-only StringInfos */
129 Assert(str->maxlen != 0);
130
131 str->data[0] = '\0';
132 str->len = 0;
133 str->cursor = 0;
134}
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 */
144void
146{
147 int save_errno = errno;
148
149 for (;;)
150 {
151 va_list args;
152 int needed;
153
154 /* Try to format the data. */
155 errno = save_errno;
156 va_start(args, fmt);
157 needed = appendStringInfoVA(str, fmt, args);
158 va_end(args);
159
160 if (needed == 0)
161 break; /* success */
162
163 /* Increase the buffer size and try again. */
164 enlargeStringInfo(str, needed);
165 }
166}
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 */
186int
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 avail = str->maxlen - str->len;
200 if (avail < 16)
201 return 32;
202
203 nprinted = pvsnprintf(str->data + str->len, (size_t) avail, fmt, args);
204
205 if (nprinted < (size_t) avail)
206 {
207 /* Success. Note nprinted does not include trailing null. */
208 str->len += (int) nprinted;
209 return 0;
210 }
211
212 /* Restore the trailing null so that str is unmodified. */
213 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 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 */
229void
231{
232 appendBinaryStringInfo(str, s, strlen(s));
233}
234
235/*
236 * appendStringInfoChar
237 *
238 * Append a single byte to str.
239 * Like appendStringInfo(str, "%c", ch) but much faster.
240 */
241void
243{
244 /* Make more room if needed */
245 if (str->len + 1 >= str->maxlen)
247
248 /* OK, append the character */
249 str->data[str->len] = ch;
250 str->len++;
251 str->data[str->len] = '\0';
252}
253
254/*
255 * appendStringInfoSpaces
256 *
257 * Append the specified number of spaces to a buffer.
258 */
259void
261{
262 if (count > 0)
263 {
264 /* Make more room if needed */
265 enlargeStringInfo(str, count);
266
267 /* OK, append the spaces */
268 memset(&str->data[str->len], ' ', count);
269 str->len += count;
270 str->data[str->len] = '\0';
271 }
272}
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 */
280void
281appendBinaryStringInfo(StringInfo str, const void *data, int datalen)
282{
283 Assert(str != NULL);
284
285 /* Make more room if needed */
286 enlargeStringInfo(str, datalen);
287
288 /* OK, append the data */
289 memcpy(str->data + str->len, data, datalen);
290 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 str->data[str->len] = '\0';
298}
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 */
306void
307appendBinaryStringInfoNT(StringInfo str, const void *data, int datalen)
308{
309 Assert(str != NULL);
310
311 /* Make more room if needed */
312 enlargeStringInfo(str, datalen);
313
314 /* OK, append the data */
315 memcpy(str->data + str->len, data, datalen);
316 str->len += datalen;
317}
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 */
336void
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 if (needed < 0) /* should not happen */
349 {
350#ifndef FRONTEND
351 elog(ERROR, "invalid string enlargement request size: %d", needed);
352#else
353 fprintf(stderr, "invalid string enlargement request size: %d\n", needed);
355#endif
356 }
357 if (((Size) needed) >= (MaxAllocSize - (Size) str->len))
358 {
359#ifndef FRONTEND
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 fprintf(stderr,
367 _("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);
370#endif
371 }
372
373 needed += str->len + 1; /* total space required now */
374
375 /* Because of the above test, we now have needed <= MaxAllocSize */
376
377 if (needed <= str->maxlen)
378 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 newlen = 2 * str->maxlen;
386 while (needed > newlen)
387 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 if (newlen > (int) MaxAllocSize)
395 newlen = (int) MaxAllocSize;
396
397 str->data = (char *) repalloc(str->data, newlen);
398
399 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 */
408void
410{
411 /* don't allow destroys of read-only StringInfos */
412 Assert(str->maxlen != 0);
413
414 pfree(str->data);
415 pfree(str);
416}
#define Assert(condition)
Definition: c.h:815
size_t Size
Definition: c.h:562
#define fprintf(file, fmt, msg)
Definition: cubescan.l:21
int errdetail(const char *fmt,...)
Definition: elog.c:1203
int errcode(int sqlerrcode)
Definition: elog.c:853
int errmsg(const char *fmt,...)
Definition: elog.c:1070
#define _(x)
Definition: elog.c:90
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:225
#define ereport(elevel,...)
Definition: elog.h:149
#define MaxAllocSize
Definition: fe_memutils.h:22
const char * str
static void const char * fmt
va_end(args)
exit(1)
va_start(args, fmt)
void * repalloc(void *pointer, Size size)
Definition: mcxt.c:1541
void pfree(void *pointer)
Definition: mcxt.c:1521
void * palloc(Size size)
Definition: mcxt.c:1317
const void * data
size_t pvsnprintf(char *buf, size_t len, const char *fmt, va_list args)
Definition: psprintf.c:103
#define EXIT_FAILURE
Definition: settings.h:178
int appendStringInfoVA(StringInfo str, const char *fmt, va_list args)
Definition: stringinfo.c:187
void destroyStringInfo(StringInfo str)
Definition: stringinfo.c:409
StringInfo makeStringInfo(void)
Definition: stringinfo.c:72
static void initStringInfoInternal(StringInfo str, int initsize)
Definition: stringinfo.c:41
void resetStringInfo(StringInfo str)
Definition: stringinfo.c:126
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition: stringinfo.c:145
void enlargeStringInfo(StringInfo str, int needed)
Definition: stringinfo.c:337
StringInfo makeStringInfoExt(int initsize)
Definition: stringinfo.c:85
void appendBinaryStringInfoNT(StringInfo str, const void *data, int datalen)
Definition: stringinfo.c:307
void appendBinaryStringInfo(StringInfo str, const void *data, int datalen)
Definition: stringinfo.c:281
static StringInfo makeStringInfoInternal(int initsize)
Definition: stringinfo.c:58
void appendStringInfoSpaces(StringInfo str, int count)
Definition: stringinfo.c:260
void initStringInfoExt(StringInfo str, int initsize)
Definition: stringinfo.c:111
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:230
void appendStringInfoChar(StringInfo str, char ch)
Definition: stringinfo.c:242
void initStringInfo(StringInfo str)
Definition: stringinfo.c:97
#define STRINGINFO_DEFAULT_SIZE
Definition: stringinfo.h:112
StringInfoData * StringInfo
Definition: stringinfo.h:54