aboutsummaryrefslogtreecommitdiff
path: root/src/backend/lib
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>1999-04-25 03:19:27 +0000
committerTom Lane <tgl@sss.pgh.pa.us>1999-04-25 03:19:27 +0000
commit95cc41b81dd3917a1b9bb0b7c9cbe231d2557760 (patch)
tree528782b9d55a9ceb7acbe4cc55c0699514ab284d /src/backend/lib
parentfc08814e00c04cddad512494bb52d9266928619e (diff)
downloadpostgresql-95cc41b81dd3917a1b9bb0b7c9cbe231d2557760.tar.gz
postgresql-95cc41b81dd3917a1b9bb0b7c9cbe231d2557760.zip
Revise backend libpq interfaces so that messages to the frontend
can be generated in a buffer and then sent to the frontend in a single libpq call. This solves problems with NOTICE and ERROR messages generated in the middle of a data message or COPY OUT operation.
Diffstat (limited to 'src/backend/lib')
-rw-r--r--src/backend/lib/stringinfo.c216
1 files changed, 131 insertions, 85 deletions
diff --git a/src/backend/lib/stringinfo.c b/src/backend/lib/stringinfo.c
index 2d129d12b2e..3ded7799749 100644
--- a/src/backend/lib/stringinfo.c
+++ b/src/backend/lib/stringinfo.c
@@ -1,125 +1,171 @@
-/*
+/*-------------------------------------------------------------------------
+ *
* stringinfo.c
- * These are routines that can be used to write informations to a string,
- * without having to worry about string lengths, space allocation etc.
- * Ideally the interface should look like the file i/o interface,
+ *
+ * StringInfo provides an indefinitely-extensible string data type.
+ * It can be used to buffer either ordinary C strings (null-terminated text)
+ * or arbitrary binary data. All storage is allocated with palloc().
*
* Copyright (c) 1994, Regents of the University of California
*
- * $Id: stringinfo.c,v 1.14 1999/02/13 23:15:36 momjian Exp $
+ * $Id: stringinfo.c,v 1.15 1999/04/25 03:19:25 tgl Exp $
+ *
+ *-------------------------------------------------------------------------
*/
#include <stdio.h>
#include <string.h>
-#include <stdarg.h>
-
-#include <postgres.h>
-
-#include <nodes/pg_list.h>
-#include <lib/stringinfo.h>
+#include "postgres.h"
+#include "lib/stringinfo.h"
/*
* makeStringInfo
*
- * Create a StringInfoData & return a pointer to it.
- *
+ * Create an empty 'StringInfoData' & return a pointer to it.
*/
StringInfo
-makeStringInfo()
+makeStringInfo(void)
{
StringInfo res;
- int size;
res = (StringInfo) palloc(sizeof(StringInfoData));
if (res == NULL)
- elog(ERROR, "makeStringInfo: Out of memory!");
+ elog(ERROR, "makeStringInfo: Out of memory");
- size = 256; /* initial default size */
- res->data = palloc(size);
- if (res->data == NULL)
- {
- elog(ERROR,
- "makeStringInfo: Out of memory! (%d bytes requested)", size);
- }
- res->maxlen = size;
- res->len = 0;
- /* Make sure the string is empty initially. */
- res->data[0] = '\0';
+ initStringInfo(res);
return res;
}
/*
- * appendStringInfo
+ * initStringInfo
*
- * append to the current 'StringInfo' a new string.
- * If there is not enough space in the current 'data', then reallocate
- * some more...
+ * Initialize a StringInfoData struct (with previously undefined contents)
+ * to describe an empty string.
+ */
+void
+initStringInfo(StringInfo str)
+{
+ int size = 256; /* initial default buffer size */
+
+ str->data = palloc(size);
+ if (str->data == NULL)
+ elog(ERROR,
+ "initStringInfo: Out of memory (%d bytes requested)", size);
+ str->maxlen = size;
+ str->len = 0;
+ str->data[0] = '\0';
+}
+
+/*
+ * enlargeStringInfo
*
- * NOTE: if we reallocate space, we pfree the old one!
+ * Internal routine: make sure there is enough space for 'needed' more bytes
+ * ('needed' does not include the terminating null).
+ */
+static void
+enlargeStringInfo(StringInfo str, int needed)
+{
+ int newlen;
+ char *newdata;
+
+ needed += str->len + 1; /* total space required now */
+ if (needed <= str->maxlen)
+ return; /* got enough space already */
+
+ /*
+ * We don't want to allocate just a little more space with each append;
+ * for efficiency, double the buffer size each time it overflows.
+ * Actually, we might need to more than double it if 'needed' is big...
+ */
+ newlen = 2 * str->maxlen;
+ while (needed > newlen)
+ newlen = 2 * newlen;
+
+ newdata = palloc(newlen);
+ if (newdata == NULL)
+ elog(ERROR,
+ "enlargeStringInfo: Out of memory (%d bytes requested)", newlen);
+
+ /* OK, transfer data into new buffer, and release old buffer */
+ memcpy(newdata, str->data, str->len + 1);
+ pfree(str->data);
+ str->data = newdata;
+ str->maxlen = newlen;
+}
+
+/*
+ * appendStringInfo
+ *
+ * Format text data under the control of fmt (an sprintf-like format string)
+ * and append it to whatever is already in str. More space is allocated
+ * to str if necessary. This is sort of like a combination of sprintf and
+ * strcat.
*
+ * CAUTION: the current implementation has a 1K limit on the amount of text
+ * generated in a single call (not on the total string length).
*/
void
-appendStringInfo(StringInfo str, const char *fmt,...)
+appendStringInfo(StringInfo str, const char *fmt, ...)
{
- int buflen,
- newlen,
- needed;
- char *s,
- buffer[512];
+ va_list args;
+ char buffer[1024];
+ int buflen;
+
+ Assert(str != NULL);
- va_list args;
va_start(args, fmt);
- buflen = vsnprintf(buffer, 512, fmt, args);
- va_end(args);
+ buflen = vsnprintf(buffer, sizeof(buffer), fmt, args);
+ va_end(args);
+
+ /* Make more room if needed */
+ enlargeStringInfo(str, buflen);
+
+ /* OK, append the data, including the trailing null */
+ memcpy(str->data + str->len, buffer, buflen + 1);
+ str->len += buflen;
+}
+/*------------------------
+ * appendStringInfoChar
+ * Append a single byte to str.
+ * Like appendStringInfo(str, "%c", ch) but much faster.
+ */
+void
+appendStringInfoChar(StringInfo str, char ch)
+{
Assert(str != NULL);
- if (buflen == 0)
- strcpy(buffer, "<>");
- /*
- * do we have enough space to append the new string? (don't forget to
- * count the null string terminating char!) If no, then reallocate
- * some more.
- */
- needed = str->len + buflen + 1;
- if (needed > str->maxlen)
- {
-
- /*
- * how much more space to allocate ? Let's say double the current
- * space... However we must check if this is enough!
- */
- newlen = 2 * str->maxlen;
- while (needed > newlen)
- newlen = 2 * newlen;
-
- /*
- * allocate enough space.
- */
- s = palloc(newlen);
- if (s == NULL)
- {
- elog(ERROR,
- "appendStringInfo: Out of memory (%d bytes requested)", newlen);
- }
- /*
- * transfer the data. strcpy() would work, but is probably a tad
- * slower than memcpy(), and since we know the string length...
- */
- memcpy(s, str->data, str->len + 1);
- pfree(str->data);
- str->maxlen = newlen;
- str->data = s;
- }
+ /* Make more room if needed */
+ enlargeStringInfo(str, 1);
- /*
- * OK, we have enough space now, append 'buffer' at the end of the
- * string & update the string length. NOTE: strcat() would work,
- * but is certainly slower than just memcpy'ing the data to the right
- * place.
+ /* OK, append the character */
+ str->data[str->len] = ch;
+ str->len++;
+ str->data[str->len] = '\0';
+}
+
+/*
+ * appendBinaryStringInfo
+ *
+ * Append arbitrary binary data to a StringInfo, allocating more space
+ * if necessary.
+ */
+void
+appendBinaryStringInfo(StringInfo str, const char *data, int datalen)
+{
+ Assert(str != NULL);
+
+ /* Make more room if needed */
+ enlargeStringInfo(str, datalen);
+
+ /* OK, append the data */
+ memcpy(str->data + str->len, data, datalen);
+ str->len += datalen;
+
+ /* Keep a trailing null in place, even though it's probably useless
+ * for binary data...
*/
- memcpy(str->data + str->len, buffer, buflen + 1);
- str->len += buflen;
+ str->data[str->len] = '\0';
}