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