diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 1999-04-25 03:19:27 +0000 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 1999-04-25 03:19:27 +0000 |
commit | 95cc41b81dd3917a1b9bb0b7c9cbe231d2557760 (patch) | |
tree | 528782b9d55a9ceb7acbe4cc55c0699514ab284d /src/backend/lib | |
parent | fc08814e00c04cddad512494bb52d9266928619e (diff) | |
download | postgresql-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.c | 216 |
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'; } |