1
0
mirror of https://github.com/postgres/postgres.git synced 2025-06-13 07:41:39 +03:00

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.
This commit is contained in:
Tom Lane
1999-04-25 03:19:27 +00:00
parent fc08814e00
commit 95cc41b81d
18 changed files with 1071 additions and 1028 deletions

View File

@ -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
*
* append to the current 'StringInfo' a new string.
* If there is not enough space in the current 'data', then reallocate
* some more...
*
* NOTE: if we reallocate space, we pfree the old one!
* initStringInfo
*
* Initialize a StringInfoData struct (with previously undefined contents)
* to describe an empty string.
*/
void
appendStringInfo(StringInfo str, const char *fmt,...)
initStringInfo(StringInfo str)
{
int buflen,
newlen,
needed;
char *s,
buffer[512];
int size = 256; /* initial default buffer size */
va_list args;
va_start(args, fmt);
buflen = vsnprintf(buffer, 512, fmt, args);
va_end(args);
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
*
* 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, ...)
{
va_list args;
char buffer[1024];
int buflen;
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)
{
va_start(args, fmt);
buflen = vsnprintf(buffer, sizeof(buffer), fmt, args);
va_end(args);
/*
* 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;
/* Make more room if needed */
enlargeStringInfo(str, buflen);
/*
* 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;
}
/*
* 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 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);
/* Make more room if needed */
enlargeStringInfo(str, 1);
/* 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...
*/
str->data[str->len] = '\0';
}