diff --git a/src/backend/lib/stringinfo.c b/src/backend/lib/stringinfo.c index a5b9f2e..2de6bbf 100644 --- a/src/backend/lib/stringinfo.c +++ b/src/backend/lib/stringinfo.c @@ -80,18 +80,28 @@ appendStringInfo(StringInfo str, const char *fmt,...) for (;;) { va_list args; - bool success; + int needed; /* Try to format the data. */ va_start(args, fmt); - success = appendStringInfoVA(str, fmt, args); + needed = appendStringInfoVA(str, fmt, args); va_end(args); - if (success) + if (!needed) break; - /* Double the buffer size and try again. */ - enlargeStringInfo(str, str->maxlen); + /* maintain growth in multiples of 2 */ + if (needed > str->maxlen) + { + int newsize = str->maxlen; + while (newsize < needed) + newsize *= 2; + needed = newsize; + } + else + needed = str->maxlen; + + enlargeStringInfo(str, needed); } } @@ -100,16 +110,20 @@ appendStringInfo(StringInfo str, const char *fmt,...) * * Attempt to format text data under the control of fmt (an sprintf-style * format string) and append it to whatever is already in str. If successful - * return true; if not (because there's not enough space), return false - * without modifying str. Typically the caller would enlarge str and retry - * on false return --- see appendStringInfo for standard usage pattern. - * + * return 0; if not (because there's not enough space), return a positive + * number. This number is the return value of the call to vsnprintf. + * Implementations of vsnprintf vary and this value may NOT be the length + * required for the whole string, so callers should take this value with a + * pinch of salt and treat the value returned as a hint that the space + * required might be bigger than they would think. + * --- see appendStringInfo for standard usage pattern. + * * XXX This API is ugly, but there seems no alternative given the C spec's * restrictions on what can portably be done with va_list arguments: you have * to redo va_start before you can rescan the argument list, and we can't do * that from here. */ -bool +int appendStringInfoVA(StringInfo str, const char *fmt, va_list args) { int avail, @@ -123,7 +137,7 @@ appendStringInfoVA(StringInfo str, const char *fmt, va_list args) */ avail = str->maxlen - str->len - 1; if (avail < 16) - return false; + return 1; /* 1 will do as we don't know how much space is needed */ /* * Assert check here is to catch buggy vsnprintf that overruns the @@ -147,12 +161,12 @@ appendStringInfoVA(StringInfo str, const char *fmt, va_list args) { /* Success. Note nprinted does not include trailing null. */ str->len += nprinted; - return true; + return 0; } /* Restore the trailing null so that str is unmodified. */ str->data[str->len] = '\0'; - return false; + return nprinted < 0 ? 1 : nprinted + 1; } /* diff --git a/src/backend/utils/error/elog.c b/src/backend/utils/error/elog.c index 9c7489a..319af01 100644 --- a/src/backend/utils/error/elog.c +++ b/src/backend/utils/error/elog.c @@ -714,12 +714,12 @@ errcode_for_socket_access(void) /* Generate actual output --- have to use appendStringInfoVA */ \ for (;;) \ { \ - va_list args; \ - bool success; \ + va_list args; \ + int needed; \ va_start(args, fmt); \ - success = appendStringInfoVA(&buf, fmtbuf, args); \ + needed = appendStringInfoVA(&buf, fmtbuf, args); \ va_end(args); \ - if (success) \ + if (!needed) \ break; \ enlargeStringInfo(&buf, buf.maxlen); \ } \ @@ -757,12 +757,12 @@ errcode_for_socket_access(void) /* Generate actual output --- have to use appendStringInfoVA */ \ for (;;) \ { \ - va_list args; \ - bool success; \ + va_list args; \ + int needed; \ va_start(args, n); \ - success = appendStringInfoVA(&buf, fmtbuf, args); \ + needed = appendStringInfoVA(&buf, fmtbuf, args); \ va_end(args); \ - if (success) \ + if (!needed) \ break; \ enlargeStringInfo(&buf, buf.maxlen); \ } \ diff --git a/src/include/lib/stringinfo.h b/src/include/lib/stringinfo.h index ecb693f..f6b14ac 100644 --- a/src/include/lib/stringinfo.h +++ b/src/include/lib/stringinfo.h @@ -97,15 +97,20 @@ appendStringInfo(StringInfo str, const char *fmt,...) /* This extension allows gcc to check the format string */ __attribute__((format(PG_PRINTF_ATTRIBUTE, 2, 3))); -/*------------------------ + /*------------------------ * appendStringInfoVA + * * Attempt to format text data under the control of fmt (an sprintf-style * format string) and append it to whatever is already in str. If successful - * return true; if not (because there's not enough space), return false - * without modifying str. Typically the caller would enlarge str and retry - * on false return --- see appendStringInfo for standard usage pattern. + * return 0; if not (because there's not enough space), return a positive + * number. This number is the return value of the call to vsnprintf. + * Implementations of vsnprintf vary and this value may NOT be the length + * required for the whole string, so callers should take this value with a + * pinch of salt and treat the value returned as a hint that the space + * required might be bigger than they would think. + * --- see appendStringInfo for standard usage pattern. */ -extern bool +extern int appendStringInfoVA(StringInfo str, const char *fmt, va_list args) __attribute__((format(PG_PRINTF_ATTRIBUTE, 2, 0)));