mirror of https://github.com/postgres/postgres
error/notice message lengths, and number of fields per tuple. Add pqexpbuffer.c/.h, a frontend version of backend's stringinfo module. This is first step in applying Mike Ansley's long-query patches, even though he didn't do any of these particular changes...REL7_0_PATCHES
parent
130e372b5d
commit
ab5cafa5d3
@ -0,0 +1,254 @@ |
||||
/*-------------------------------------------------------------------------
|
||||
* |
||||
* pqexpbuffer.c |
||||
* |
||||
* PQExpBuffer 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 malloc(). |
||||
* |
||||
* This module is essentially the same as the backend's StringInfo data type, |
||||
* but it is intended for use in frontend libpq and client applications. |
||||
* Thus, it does not rely on palloc(), elog(), nor vsnprintf(). |
||||
* |
||||
* Copyright (c) 1994, Regents of the University of California |
||||
* |
||||
* $Header: /cvsroot/pgsql/src/interfaces/libpq/pqexpbuffer.c,v 1.1 1999/08/31 01:37:37 tgl Exp $ |
||||
* |
||||
*------------------------------------------------------------------------- |
||||
*/ |
||||
|
||||
#include "postgres.h" |
||||
#include "pqexpbuffer.h" |
||||
|
||||
/*
|
||||
* createPQExpBuffer |
||||
* |
||||
* Create an empty 'PQExpBufferData' & return a pointer to it. |
||||
*/ |
||||
PQExpBuffer |
||||
createPQExpBuffer(void) |
||||
{ |
||||
PQExpBuffer res; |
||||
|
||||
res = (PQExpBuffer) malloc(sizeof(PQExpBufferData)); |
||||
if (res != NULL) |
||||
initPQExpBuffer(res); |
||||
|
||||
return res; |
||||
} |
||||
|
||||
/*
|
||||
* initPQExpBuffer |
||||
* |
||||
* Initialize a PQExpBufferData struct (with previously undefined contents) |
||||
* to describe an empty string. |
||||
*/ |
||||
void |
||||
initPQExpBuffer(PQExpBuffer str) |
||||
{ |
||||
str->data = (char *) malloc(INITIAL_EXPBUFFER_SIZE); |
||||
if (str->data == NULL) |
||||
{ |
||||
str->maxlen = 0; |
||||
str->len = 0; |
||||
} |
||||
else |
||||
{ |
||||
str->maxlen = INITIAL_EXPBUFFER_SIZE; |
||||
str->len = 0; |
||||
str->data[0] = '\0'; |
||||
} |
||||
} |
||||
|
||||
/*------------------------
|
||||
* destroyPQExpBuffer(str); |
||||
* free()s both the data buffer and the PQExpBufferData. |
||||
* This is the inverse of createPQExpBuffer(). |
||||
*/ |
||||
void |
||||
destroyPQExpBuffer(PQExpBuffer str) |
||||
{ |
||||
if (str) |
||||
{ |
||||
termPQExpBuffer(str); |
||||
free(str); |
||||
} |
||||
} |
||||
|
||||
/*------------------------
|
||||
* termPQExpBuffer(str) |
||||
* free()s the data buffer but not the PQExpBufferData itself. |
||||
* This is the inverse of initPQExpBuffer(). |
||||
*/ |
||||
void |
||||
termPQExpBuffer(PQExpBuffer str) |
||||
{ |
||||
if (str->data) |
||||
{ |
||||
free(str->data); |
||||
str->data = NULL; |
||||
} |
||||
} |
||||
|
||||
/*------------------------
|
||||
* resetPQExpBuffer |
||||
* Reset a PQExpBuffer to empty |
||||
*/ |
||||
void |
||||
resetPQExpBuffer(PQExpBuffer str) |
||||
{ |
||||
if (str) |
||||
{ |
||||
str->len = 0; |
||||
if (str->data) |
||||
str->data[0] = '\0'; |
||||
} |
||||
} |
||||
|
||||
/*------------------------
|
||||
* enlargePQExpBuffer |
||||
* Make sure there is enough space for 'needed' more bytes in the buffer |
||||
* ('needed' does not include the terminating null). |
||||
* |
||||
* Returns 1 if OK, 0 if failed to enlarge buffer. |
||||
*/ |
||||
int |
||||
enlargePQExpBuffer(PQExpBuffer str, int needed) |
||||
{ |
||||
int newlen; |
||||
char *newdata; |
||||
|
||||
needed += str->len + 1; /* total space required now */ |
||||
if (needed <= str->maxlen) |
||||
return 1; /* 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 = str->maxlen ? (2 * str->maxlen) : 64; |
||||
while (needed > newlen) |
||||
newlen = 2 * newlen; |
||||
|
||||
newdata = (char *) realloc(str->data, newlen); |
||||
if (newdata != NULL) |
||||
{ |
||||
str->data = newdata; |
||||
str->maxlen = newlen; |
||||
return 1; |
||||
} |
||||
return 0; |
||||
} |
||||
|
||||
/*------------------------
|
||||
* printfPQExpBuffer |
||||
* Format text data under the control of fmt (an sprintf-like format string) |
||||
* and insert it into str. More space is allocated to str if necessary. |
||||
* This is a convenience routine that does the same thing as |
||||
* resetPQExpBuffer() followed by appendPQExpBuffer(). |
||||
* |
||||
* CAUTION: the frontend version of this routine WILL FAIL if the result of |
||||
* the sprintf formatting operation exceeds 1KB of data (but the size of the |
||||
* pre-existing string in the buffer doesn't matter). We could make it |
||||
* support larger strings, but that requires vsnprintf() which is not |
||||
* universally available. Currently there is no need for long strings to be |
||||
* formatted in the frontend. We could support it, if necessary, by |
||||
* conditionally including a vsnprintf emulation. |
||||
*/ |
||||
void |
||||
printfPQExpBuffer(PQExpBuffer str, const char *fmt,...) |
||||
{ |
||||
va_list args; |
||||
char buffer[1024]; |
||||
|
||||
va_start(args, fmt); |
||||
vsprintf(buffer, fmt, args); |
||||
va_end(args); |
||||
|
||||
resetPQExpBuffer(str); |
||||
appendPQExpBufferStr(str, buffer); |
||||
} |
||||
|
||||
/*------------------------
|
||||
* appendPQExpBuffer |
||||
* |
||||
* 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 frontend version of this routine WILL FAIL if the result of |
||||
* the sprintf formatting operation exceeds 1KB of data (but the size of the |
||||
* pre-existing string in the buffer doesn't matter). We could make it |
||||
* support larger strings, but that requires vsnprintf() which is not |
||||
* universally available. Currently there is no need for long strings to be |
||||
* formatted in the frontend. We could support it, if necessary, by |
||||
* conditionally including a vsnprintf emulation. |
||||
*/ |
||||
void |
||||
appendPQExpBuffer(PQExpBuffer str, const char *fmt,...) |
||||
{ |
||||
va_list args; |
||||
char buffer[1024]; |
||||
|
||||
va_start(args, fmt); |
||||
vsprintf(buffer, fmt, args); |
||||
va_end(args); |
||||
|
||||
appendPQExpBufferStr(str, buffer); |
||||
} |
||||
|
||||
/*------------------------
|
||||
* appendPQExpBufferStr |
||||
* Append the given string to a PQExpBuffer, allocating more space |
||||
* if necessary. |
||||
*/ |
||||
void |
||||
appendPQExpBufferStr(PQExpBuffer str, const char *data) |
||||
{ |
||||
appendBinaryPQExpBuffer(str, data, strlen(data)); |
||||
} |
||||
|
||||
/*------------------------
|
||||
* appendPQExpBufferChar |
||||
* Append a single byte to str. |
||||
* Like appendPQExpBuffer(str, "%c", ch) but much faster. |
||||
*/ |
||||
void |
||||
appendPQExpBufferChar(PQExpBuffer str, char ch) |
||||
{ |
||||
/* Make more room if needed */ |
||||
if (! enlargePQExpBuffer(str, 1)) |
||||
return; |
||||
|
||||
/* OK, append the character */ |
||||
str->data[str->len] = ch; |
||||
str->len++; |
||||
str->data[str->len] = '\0'; |
||||
} |
||||
|
||||
/*
|
||||
* appendBinaryPQExpBuffer |
||||
* |
||||
* Append arbitrary binary data to a PQExpBuffer, allocating more space |
||||
* if necessary. |
||||
*/ |
||||
void |
||||
appendBinaryPQExpBuffer(PQExpBuffer str, const char *data, int datalen) |
||||
{ |
||||
/* Make more room if needed */ |
||||
if (! enlargePQExpBuffer(str, datalen)) |
||||
return; |
||||
|
||||
/* 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'; |
||||
} |
||||
@ -0,0 +1,169 @@ |
||||
/*-------------------------------------------------------------------------
|
||||
* |
||||
* pqexpbuffer.h |
||||
* Declarations/definitions for "PQExpBuffer" functions. |
||||
* |
||||
* PQExpBuffer 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 malloc(). |
||||
* |
||||
* This module is essentially the same as the backend's StringInfo data type, |
||||
* but it is intended for use in frontend libpq and client applications. |
||||
* Thus, it does not rely on palloc(), elog(), nor vsnprintf(). |
||||
* |
||||
* Copyright (c) 1994, Regents of the University of California |
||||
* |
||||
* $Id: pqexpbuffer.h,v 1.1 1999/08/31 01:37:37 tgl Exp $ |
||||
* |
||||
*------------------------------------------------------------------------- |
||||
*/ |
||||
#ifndef PQEXPBUFFER_H |
||||
#define PQEXPBUFFER_H |
||||
|
||||
/*-------------------------
|
||||
* PQExpBufferData holds information about an extensible string. |
||||
* data is the current buffer for the string (allocated with malloc). |
||||
* len is the current string length. There is guaranteed to be |
||||
* a terminating '\0' at data[len], although this is not very |
||||
* useful when the string holds binary data rather than text. |
||||
* maxlen is the allocated size in bytes of 'data', i.e. the maximum |
||||
* string size (including the terminating '\0' char) that we can |
||||
* currently store in 'data' without having to reallocate |
||||
* more space. We must always have maxlen > len. |
||||
*------------------------- |
||||
*/ |
||||
typedef struct PQExpBufferData |
||||
{ |
||||
char *data; |
||||
int len; |
||||
int maxlen; |
||||
} PQExpBufferData; |
||||
|
||||
typedef PQExpBufferData *PQExpBuffer; |
||||
|
||||
/*------------------------
|
||||
* Initial size of the data buffer in a PQExpBuffer. |
||||
* NB: this must be large enough to hold error messages that might |
||||
* be returned by PQrequestCancel() or any routine in fe-auth.c. |
||||
*------------------------ |
||||
*/ |
||||
#define INITIAL_EXPBUFFER_SIZE 256 |
||||
|
||||
/*------------------------
|
||||
* There are two ways to create a PQExpBuffer object initially: |
||||
* |
||||
* PQExpBuffer stringptr = createPQExpBuffer(); |
||||
* Both the PQExpBufferData and the data buffer are malloc'd. |
||||
* |
||||
* PQExpBufferData string; |
||||
* initPQExpBuffer(&string); |
||||
* The data buffer is malloc'd but the PQExpBufferData is presupplied. |
||||
* This is appropriate if the PQExpBufferData is a field of another |
||||
* struct. |
||||
*------------------------- |
||||
*/ |
||||
|
||||
/*------------------------
|
||||
* createPQExpBuffer |
||||
* Create an empty 'PQExpBufferData' & return a pointer to it. |
||||
*/ |
||||
extern PQExpBuffer createPQExpBuffer(void); |
||||
|
||||
/*------------------------
|
||||
* initPQExpBuffer |
||||
* Initialize a PQExpBufferData struct (with previously undefined contents) |
||||
* to describe an empty string. |
||||
*/ |
||||
extern void initPQExpBuffer(PQExpBuffer str); |
||||
|
||||
/*------------------------
|
||||
* To destroy a PQExpBuffer, use either: |
||||
* |
||||
* destroyPQExpBuffer(str); |
||||
* free()s both the data buffer and the PQExpBufferData. |
||||
* This is the inverse of createPQExpBuffer(). |
||||
* |
||||
* termPQExpBuffer(str) |
||||
* free()s the data buffer but not the PQExpBufferData itself. |
||||
* This is the inverse of initPQExpBuffer(). |
||||
* |
||||
* NOTE: some routines build up a string using PQExpBuffer, and then |
||||
* release the PQExpBufferData but return the data string itself to their |
||||
* caller. At that point the data string looks like a plain malloc'd |
||||
* string. |
||||
*/ |
||||
extern void destroyPQExpBuffer(PQExpBuffer str); |
||||
extern void termPQExpBuffer(PQExpBuffer str); |
||||
|
||||
/*------------------------
|
||||
* resetPQExpBuffer |
||||
* Reset a PQExpBuffer to empty |
||||
*/ |
||||
extern void resetPQExpBuffer(PQExpBuffer str); |
||||
|
||||
/*------------------------
|
||||
* enlargePQExpBuffer |
||||
* Make sure there is enough space for 'needed' more bytes in the buffer |
||||
* ('needed' does not include the terminating null). |
||||
* |
||||
* Returns 1 if OK, 0 if failed to enlarge buffer. |
||||
*/ |
||||
extern int enlargePQExpBuffer(PQExpBuffer str, int needed); |
||||
|
||||
/*------------------------
|
||||
* printfPQExpBuffer |
||||
* Format text data under the control of fmt (an sprintf-like format string) |
||||
* and insert it into str. More space is allocated to str if necessary. |
||||
* This is a convenience routine that does the same thing as |
||||
* resetPQExpBuffer() followed by appendPQExpBuffer(). |
||||
* |
||||
* CAUTION: the frontend version of this routine WILL FAIL if the result of |
||||
* the sprintf formatting operation exceeds 1KB of data (but the size of the |
||||
* pre-existing string in the buffer doesn't matter). We could make it |
||||
* support larger strings, but that requires vsnprintf() which is not |
||||
* universally available. Currently there is no need for long strings to be |
||||
* formatted in the frontend. We could support it, if necessary, by |
||||
* conditionally including a vsnprintf emulation. |
||||
*/ |
||||
extern void printfPQExpBuffer(PQExpBuffer str, const char *fmt,...); |
||||
|
||||
/*------------------------
|
||||
* appendPQExpBuffer |
||||
* 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 frontend version of this routine WILL FAIL if the result of |
||||
* the sprintf formatting operation exceeds 1KB of data (but the size of the |
||||
* pre-existing string in the buffer doesn't matter). We could make it |
||||
* support larger strings, but that requires vsnprintf() which is not |
||||
* universally available. Currently there is no need for long strings to be |
||||
* formatted in the frontend. We could support it, if necessary, by |
||||
* conditionally including a vsnprintf emulation. |
||||
*/ |
||||
extern void appendPQExpBuffer(PQExpBuffer str, const char *fmt,...); |
||||
|
||||
/*------------------------
|
||||
* appendPQExpBufferStr |
||||
* Append the given string to a PQExpBuffer, allocating more space |
||||
* if necessary. |
||||
*/ |
||||
extern void appendPQExpBufferStr(PQExpBuffer str, const char *data); |
||||
|
||||
/*------------------------
|
||||
* appendPQExpBufferChar |
||||
* Append a single byte to str. |
||||
* Like appendPQExpBuffer(str, "%c", ch) but much faster. |
||||
*/ |
||||
extern void appendPQExpBufferChar(PQExpBuffer str, char ch); |
||||
|
||||
/*------------------------
|
||||
* appendBinaryPQExpBuffer |
||||
* Append arbitrary binary data to a PQExpBuffer, allocating more space |
||||
* if necessary. |
||||
*/ |
||||
extern void appendBinaryPQExpBuffer(PQExpBuffer str, |
||||
const char *data, int datalen); |
||||
|
||||
#endif /* PQEXPBUFFER_H */ |
||||
Loading…
Reference in new issue