Commit ab5cafa5 authored by Tom Lane's avatar Tom Lane

Update frontend libpq to remove limits on query lengths,

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...
parent 130e372b
......@@ -6,7 +6,7 @@
# Copyright (c) 1994, Regents of the University of California
#
# IDENTIFICATION
# $Header: /cvsroot/pgsql/src/interfaces/libpq/Attic/Makefile.in,v 1.46 1999/06/30 23:57:25 tgl Exp $
# $Header: /cvsroot/pgsql/src/interfaces/libpq/Attic/Makefile.in,v 1.47 1999/08/31 01:37:36 tgl Exp $
#
#-------------------------------------------------------------------------
......@@ -28,7 +28,7 @@ CFLAGS+= $(MBFLAGS)
endif
OBJS= fe-auth.o fe-connect.o fe-exec.o fe-misc.o fe-print.o fe-lobj.o \
dllist.o pqsignal.o
pqexpbuffer.o dllist.o pqsignal.o
ifdef MULTIBYTE
OBJS+= common.o wchar.o conv.o big5.o
......@@ -80,6 +80,7 @@ install-headers: libpq-fe.h libpq-int.h
@if [ ! -d $(HEADERDIR) ]; then mkdir $(HEADERDIR); fi
$(INSTALL) $(INSTLOPTS) libpq-fe.h $(HEADERDIR)/libpq-fe.h
$(INSTALL) $(INSTLOPTS) libpq-int.h $(HEADERDIR)/libpq-int.h
$(INSTALL) $(INSTLOPTS) pqexpbuffer.h $(HEADERDIR)/pqexpbuffer.h
.PHONY: clean
......
......@@ -5,9 +5,11 @@
*
* Copyright (c) 1994, Regents of the University of California
*
* NOTE: the error message strings returned by this module must not
* exceed INITIAL_EXPBUFFER_SIZE (currently 256 bytes).
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-auth.c,v 1.32 1999/07/19 06:25:38 momjian Exp $
* $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-auth.c,v 1.33 1999/08/31 01:37:36 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......
This diff is collapsed.
This diff is collapsed.
......@@ -7,7 +7,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-lobj.c,v 1.24 1999/07/19 06:25:39 momjian Exp $
* $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-lobj.c,v 1.25 1999/08/31 01:37:36 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -397,8 +397,9 @@ lo_import(PGconn *conn, char *filename)
#endif
if (fd < 0)
{ /* error */
sprintf(conn->errorMessage,
"lo_import: can't open unix file\"%s\"\n", filename);
printfPQExpBuffer(&conn->errorMessage,
"lo_import: can't open unix file\"%s\"\n",
filename);
return InvalidOid;
}
......@@ -408,16 +409,18 @@ lo_import(PGconn *conn, char *filename)
lobjOid = lo_creat(conn, INV_READ | INV_WRITE);
if (lobjOid == InvalidOid)
{
sprintf(conn->errorMessage,
"lo_import: can't create inv object for \"%s\"", filename);
printfPQExpBuffer(&conn->errorMessage,
"lo_import: can't create inv object for \"%s\"",
filename);
return InvalidOid;
}
lobj = lo_open(conn, lobjOid, INV_WRITE);
if (lobj == -1)
{
sprintf(conn->errorMessage,
"lo_import: could not open inv object oid %u", lobjOid);
printfPQExpBuffer(&conn->errorMessage,
"lo_import: could not open inv object oid %u",
lobjOid);
return InvalidOid;
}
......@@ -429,8 +432,9 @@ lo_import(PGconn *conn, char *filename)
tmp = lo_write(conn, lobj, buf, nbytes);
if (tmp < nbytes)
{
sprintf(conn->errorMessage,
"lo_import: error while reading \"%s\"", filename);
printfPQExpBuffer(&conn->errorMessage,
"lo_import: error while reading \"%s\"",
filename);
return InvalidOid;
}
}
......@@ -461,8 +465,8 @@ lo_export(PGconn *conn, Oid lobjId, char *filename)
lobj = lo_open(conn, lobjId, INV_READ);
if (lobj == -1)
{
sprintf(conn->errorMessage,
"lo_export: can't open inv object %u", lobjId);
printfPQExpBuffer(&conn->errorMessage,
"lo_export: can't open inv object %u", lobjId);
return -1;
}
......@@ -476,8 +480,9 @@ lo_export(PGconn *conn, Oid lobjId, char *filename)
#endif
if (fd < 0)
{ /* error */
sprintf(conn->errorMessage,
"lo_export: can't open unix file\"%s\"", filename);
printfPQExpBuffer(&conn->errorMessage,
"lo_export: can't open unix file\"%s\"",
filename);
return 0;
}
......@@ -489,9 +494,9 @@ lo_export(PGconn *conn, Oid lobjId, char *filename)
tmp = write(fd, buf, nbytes);
if (tmp < nbytes)
{
sprintf(conn->errorMessage,
"lo_export: error while writing \"%s\"",
filename);
printfPQExpBuffer(&conn->errorMessage,
"lo_export: error while writing \"%s\"",
filename);
return -1;
}
}
......@@ -527,8 +532,8 @@ lo_initialize(PGconn *conn)
lobjfuncs = (PGlobjfuncs *) malloc(sizeof(PGlobjfuncs));
if (lobjfuncs == (PGlobjfuncs *) NULL)
{
strcpy(conn->errorMessage,
"FATAL: malloc() failed in lo_initialize()\n");
printfPQExpBuffer(&conn->errorMessage,
"FATAL: malloc() failed in lo_initialize()\n");
return -1;
}
MemSet((char *) lobjfuncs, 0, sizeof(PGlobjfuncs));
......@@ -556,8 +561,8 @@ lo_initialize(PGconn *conn)
{
free(lobjfuncs);
PQclear(res);
strcpy(conn->errorMessage,
"ERROR: SELECT didn't return data in lo_initialize()\n");
printfPQExpBuffer(&conn->errorMessage,
"ERROR: SELECT didn't return data in lo_initialize()\n");
return -1;
}
......@@ -596,57 +601,57 @@ lo_initialize(PGconn *conn)
*/
if (lobjfuncs->fn_lo_open == 0)
{
strcpy(conn->errorMessage,
"ERROR: Cannot determine OID for function lo_open\n");
printfPQExpBuffer(&conn->errorMessage,
"ERROR: Cannot determine OID for function lo_open\n");
free(lobjfuncs);
return -1;
}
if (lobjfuncs->fn_lo_close == 0)
{
strcpy(conn->errorMessage,
"ERROR: Cannot determine OID for function lo_close\n");
printfPQExpBuffer(&conn->errorMessage,
"ERROR: Cannot determine OID for function lo_close\n");
free(lobjfuncs);
return -1;
}
if (lobjfuncs->fn_lo_creat == 0)
{
strcpy(conn->errorMessage,
"ERROR: Cannot determine OID for function lo_creat\n");
printfPQExpBuffer(&conn->errorMessage,
"ERROR: Cannot determine OID for function lo_creat\n");
free(lobjfuncs);
return -1;
}
if (lobjfuncs->fn_lo_unlink == 0)
{
strcpy(conn->errorMessage,
"ERROR: Cannot determine OID for function lo_unlink\n");
printfPQExpBuffer(&conn->errorMessage,
"ERROR: Cannot determine OID for function lo_unlink\n");
free(lobjfuncs);
return -1;
}
if (lobjfuncs->fn_lo_lseek == 0)
{
strcpy(conn->errorMessage,
"ERROR: Cannot determine OID for function lo_lseek\n");
printfPQExpBuffer(&conn->errorMessage,
"ERROR: Cannot determine OID for function lo_lseek\n");
free(lobjfuncs);
return -1;
}
if (lobjfuncs->fn_lo_tell == 0)
{
strcpy(conn->errorMessage,
"ERROR: Cannot determine OID for function lo_tell\n");
printfPQExpBuffer(&conn->errorMessage,
"ERROR: Cannot determine OID for function lo_tell\n");
free(lobjfuncs);
return -1;
}
if (lobjfuncs->fn_lo_read == 0)
{
strcpy(conn->errorMessage,
"ERROR: Cannot determine OID for function loread\n");
printfPQExpBuffer(&conn->errorMessage,
"ERROR: Cannot determine OID for function loread\n");
free(lobjfuncs);
return -1;
}
if (lobjfuncs->fn_lo_write == 0)
{
strcpy(conn->errorMessage,
"ERROR: Cannot determine OID for function lowrite\n");
printfPQExpBuffer(&conn->errorMessage,
"ERROR: Cannot determine OID for function lowrite\n");
free(lobjfuncs);
return -1;
}
......
......@@ -24,7 +24,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-misc.c,v 1.28 1999/07/19 06:25:40 momjian Exp $
* $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-misc.c,v 1.29 1999/08/31 01:37:36 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -106,12 +106,12 @@ pqPutBytes(const char *s, int nbytes, PGconn *conn)
/* --------------------------------------------------------------------- */
/* pqGets:
get a null-terminated string from the connection,
and store it in a buffer of size maxlen bytes.
If the incoming string is >= maxlen bytes, all of it is read,
and store it in an expansible PQExpBuffer.
If we run out of memory, all of the string is still read,
but the excess characters are silently discarded.
*/
int
pqGets(char *s, int maxlen, PGconn *conn)
pqGets(PQExpBuffer buf, PGconn *conn)
{
/* Copy conn data to locals for faster search loop */
char *inBuffer = conn->inBuffer;
......@@ -126,18 +126,15 @@ pqGets(char *s, int maxlen, PGconn *conn)
return EOF;
slen = inCursor - conn->inCursor;
if (slen < maxlen)
strcpy(s, inBuffer + conn->inCursor);
else
{
strncpy(s, inBuffer + conn->inCursor, maxlen - 1);
s[maxlen - 1] = '\0';
}
resetPQExpBuffer(buf);
appendBinaryPQExpBuffer(buf, inBuffer + conn->inCursor, slen);
conn->inCursor = ++inCursor;
if (conn->Pfdebug)
fprintf(conn->Pfdebug, "From backend> \"%s\"\n", s);
fprintf(conn->Pfdebug, "From backend> \"%s\"\n",
buf->data);
return 0;
}
......@@ -202,6 +199,7 @@ pqGetInt(int *result, int bytes, PGconn *conn)
{
uint16 tmp2;
uint32 tmp4;
char noticeBuf[64];
switch (bytes)
{
......@@ -220,9 +218,9 @@ pqGetInt(int *result, int bytes, PGconn *conn)
*result = (int) ntohl(tmp4);
break;
default:
sprintf(conn->errorMessage,
sprintf(noticeBuf,
"pqGetInt: int size %d not supported\n", bytes);
DONOTICE(conn, conn->errorMessage);
DONOTICE(conn, noticeBuf);
return EOF;
}
......@@ -242,6 +240,7 @@ pqPutInt(int value, int bytes, PGconn *conn)
{
uint16 tmp2;
uint32 tmp4;
char noticeBuf[64];
switch (bytes)
{
......@@ -256,9 +255,9 @@ pqPutInt(int value, int bytes, PGconn *conn)
return EOF;
break;
default:
sprintf(conn->errorMessage,
sprintf(noticeBuf,
"pqPutInt: int size %d not supported\n", bytes);
DONOTICE(conn, conn->errorMessage);
DONOTICE(conn, noticeBuf);
return EOF;
}
......@@ -287,9 +286,9 @@ pqReadReady(PGconn *conn)
if (select(conn->sock + 1, &input_mask, (fd_set *) NULL, (fd_set *) NULL,
&timeout) < 0)
{
sprintf(conn->errorMessage,
"pqReadReady() -- select() failed: errno=%d\n%s\n",
errno, strerror(errno));
printfPQExpBuffer(&conn->errorMessage,
"pqReadReady() -- select() failed: errno=%d\n%s\n",
errno, strerror(errno));
return 0;
}
return FD_ISSET(conn->sock, &input_mask);
......@@ -312,7 +311,8 @@ pqReadData(PGconn *conn)
if (conn->sock < 0)
{
strcpy(conn->errorMessage, "pqReadData() -- connection not open\n");
printfPQExpBuffer(&conn->errorMessage,
"pqReadData() -- connection not open\n");
return -1;
}
......@@ -333,9 +333,10 @@ pqReadData(PGconn *conn)
* enlarge the buffer in case a single message exceeds the initial
* buffer size. We enlarge before filling the buffer entirely so as
* to avoid asking the kernel for a partial packet. The magic constant
* here should be at least one TCP packet.
* here should be large enough for a TCP packet or Unix pipe
* bufferload. 8K is the usual pipe buffer size, so...
*/
if (conn->inBufSize - conn->inEnd < 2000)
if (conn->inBufSize - conn->inEnd < 8192)
{
int newSize = conn->inBufSize * 2;
char *newBuf = (char *) realloc(conn->inBuffer, newSize);
......@@ -369,9 +370,9 @@ tryAgain:
if (errno == ECONNRESET)
goto definitelyFailed;
#endif
sprintf(conn->errorMessage,
"pqReadData() -- read() failed: errno=%d\n%s\n",
errno, strerror(errno));
printfPQExpBuffer(&conn->errorMessage,
"pqReadData() -- read() failed: errno=%d\n%s\n",
errno, strerror(errno));
return -1;
}
if (nread > 0)
......@@ -417,9 +418,9 @@ tryAgain2:
if (errno == ECONNRESET)
goto definitelyFailed;
#endif
sprintf(conn->errorMessage,
"pqReadData() -- read() failed: errno=%d\n%s\n",
errno, strerror(errno));
printfPQExpBuffer(&conn->errorMessage,
"pqReadData() -- read() failed: errno=%d\n%s\n",
errno, strerror(errno));
return -1;
}
if (nread > 0)
......@@ -433,7 +434,7 @@ tryAgain2:
* This means the connection has been closed. Cope.
*/
definitelyFailed:
sprintf(conn->errorMessage,
printfPQExpBuffer(&conn->errorMessage,
"pqReadData() -- backend closed the channel unexpectedly.\n"
"\tThis probably means the backend terminated abnormally\n"
"\tbefore or while processing the request.\n");
......@@ -459,7 +460,8 @@ pqFlush(PGconn *conn)
if (conn->sock < 0)
{
strcpy(conn->errorMessage, "pqFlush() -- connection not open\n");
printfPQExpBuffer(&conn->errorMessage,
"pqFlush() -- connection not open\n");
return EOF;
}
......@@ -499,7 +501,7 @@ pqFlush(PGconn *conn)
#ifdef ECONNRESET
case ECONNRESET:
#endif
sprintf(conn->errorMessage,
printfPQExpBuffer(&conn->errorMessage,
"pqFlush() -- backend closed the channel unexpectedly.\n"
"\tThis probably means the backend terminated abnormally"
" before or while processing the request.\n");
......@@ -513,8 +515,8 @@ pqFlush(PGconn *conn)
return EOF;
default:
sprintf(conn->errorMessage,
"pqFlush() -- couldn't send data: errno=%d\n%s\n",
printfPQExpBuffer(&conn->errorMessage,
"pqFlush() -- couldn't send data: errno=%d\n%s\n",
errno, strerror(errno));
/* We don't assume it's a fatal error... */
return EOF;
......@@ -552,7 +554,8 @@ pqWait(int forRead, int forWrite, PGconn *conn)
if (conn->sock < 0)
{
strcpy(conn->errorMessage, "pqWait() -- connection not open\n");
printfPQExpBuffer(&conn->errorMessage,
"pqWait() -- connection not open\n");
return EOF;
}
......@@ -570,9 +573,9 @@ pqWait(int forRead, int forWrite, PGconn *conn)
{
if (errno == EINTR)
continue;
sprintf(conn->errorMessage,
"pqWait() -- select() failed: errno=%d\n%s\n",
errno, strerror(errno));
printfPQExpBuffer(&conn->errorMessage,
"pqWait() -- select() failed: errno=%d\n%s\n",
errno, strerror(errno));
return EOF;
}
/* On nonerror return, assume we're done */
......
......@@ -9,7 +9,7 @@
* didn't really belong there.
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-print.c,v 1.26 1999/07/19 06:25:40 momjian Exp $
* $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-print.c,v 1.27 1999/08/31 01:37:37 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -51,7 +51,7 @@ static struct winsize
static void do_field(PQprintOpt *po, PGresult *res,
const int i, const int j, char *buf, const int fs_len,
const int i, const int j, const int fs_len,
char **fields,
const int nFields, char **fieldNames,
unsigned char *fieldNotNum, int *fieldMax,
......@@ -103,7 +103,6 @@ PQprint(FILE *fout,
int usePipe = 0;
pqsigfunc oldsigpipehandler = NULL;
char *pagerenv;
char buf[MAX_QUERY_SIZE + 1];
nTups = PQntuples(res);
if (!(fieldNames = (char **) calloc(nFields, sizeof(char *))))
......@@ -254,7 +253,7 @@ PQprint(FILE *fout,
fprintf(fout, "-- RECORD %d --\n", i);
}
for (j = 0; j < nFields; j++)
do_field(po, res, i, j, buf, fs_len, fields, nFields,
do_field(po, res, i, j, fs_len, fields, nFields,
fieldNames, fieldNotNum,
fieldMax, fieldMaxLen, fout);
if (po->html3 && po->expanded)
......@@ -332,7 +331,7 @@ PQdisplayTuples(PGresult *res,
j;
int nFields;
int nTuples;
int fLength[MAX_FIELDS];
int *fLength = NULL;
if (fieldSep == NULL)
fieldSep = DEFAULT_FIELD_SEP;
......@@ -344,19 +343,19 @@ PQdisplayTuples(PGresult *res,
if (fp == NULL)
fp = stdout;
/* Zero the initial field lengths */
for (j = 0; j < nFields; j++)
fLength[j] = strlen(PQfname(res, j));
/* Find the max length of each field in the result */
/* Figure the field lengths to align to */
/* will be somewhat time consuming for very large results */
if (fillAlign)
{
for (i = 0; i < nTuples; i++)
fLength = (int *) malloc(nFields * sizeof(int));
for (j = 0; j < nFields; j++)
{
for (j = 0; j < nFields; j++)
fLength[j] = strlen(PQfname(res, j));
for (i = 0; i < nTuples; i++)
{
if (PQgetlength(res, i, j) > fLength[j])
fLength[j] = PQgetlength(res, i, j);
int flen = PQgetlength(res, i, j);
if (flen > fLength[j])
fLength[j] = flen;
}
}
}
......@@ -401,6 +400,9 @@ PQdisplayTuples(PGresult *res,
(PQntuples(res) == 1) ? "" : "s");
fflush(fp);
if (fLength)
free(fLength);
}
......@@ -522,7 +524,7 @@ PQmblen(unsigned char *s)
static void
do_field(PQprintOpt *po, PGresult *res,
const int i, const int j, char *buf, const int fs_len,
const int i, const int j, const int fs_len,
char **fields,
const int nFields, char **fieldNames,
unsigned char *fieldNotNum, int *fieldMax,
......@@ -530,8 +532,7 @@ do_field(PQprintOpt *po, PGresult *res,
{
char *pval,
*p,
*o;
*p;
int plen;
bool skipit;
......@@ -553,62 +554,49 @@ do_field(PQprintOpt *po, PGresult *res,
if (!skipit)
{
char ch = 0;
if (po->align && ! fieldNotNum[j])
{
/* Detect whether field contains non-numeric data */
char ch = '0';
#ifdef MULTIBYTE
int len;
for (p = pval, o = buf; *p;
len = PQmblen(p), memcpy(o, p, len),
o += len, p += len)
for (p = pval; *p; p += PQmblen(p))
#else
for (p = pval, o = buf; *p; *(o++) = *(p++))
for (p = pval; *p; p++)
#endif
{
ch = *p;
{
ch = *p;
if (! ((ch >= '0' && ch <= '9') ||
ch == '.' ||
ch == 'E' ||
ch == 'e' ||
ch == ' ' ||
ch == '-'))
{
fieldNotNum[j] = 1;
break;
}
}
/*
* Consensus on pgsql-interfaces (as of Aug 1998) seems to be
* that the print functions ought not insert backslashes. If
* you like them, you can re-enable this next bit.
* Above loop will believe E in first column is numeric; also, we
* insist on a digit in the last column for a numeric. This test
* is still not bulletproof but it handles most cases.
*/
#ifdef GRATUITOUS_BACKSLASHES
if ((fs_len == 1 && (ch == *(po->fieldSep))) ||
ch == '\\' || ch == '\n')
*(o++) = '\\';
#endif
if (po->align &&
!((ch >= '0' && ch <= '9') ||
ch == '.' ||
ch == 'E' ||
ch == 'e' ||
ch == ' ' ||
ch == '-'))
if (*pval == 'E' || *pval == 'e' ||
!(ch >= '0' && ch <= '9'))
fieldNotNum[j] = 1;
}
*o = '\0';
/*
* Above loop will believe E in first column is numeric; also, we
* insist on a digit in the last column for a numeric. This test
* is still not bulletproof but it handles most cases.
*/
if (po->align &&
(*pval == 'E' || *pval == 'e' ||
!(ch >= '0' && ch <= '9')))
fieldNotNum[j] = 1;
if (!po->expanded && (po->align || po->html3))
{
int n = strlen(buf);
if (n > fieldMax[j])
fieldMax[j] = n;
if (!(fields[i * nFields + j] = (char *) malloc(n + 1)))
if (plen > fieldMax[j])
fieldMax[j] = plen;
if (!(fields[i * nFields + j] = (char *) malloc(plen + 1)))
{
perror("malloc");
exit(1);
}
strcpy(fields[i * nFields + j], buf);
strcpy(fields[i * nFields + j], pval);
}
else
{
......@@ -620,23 +608,26 @@ do_field(PQprintOpt *po, PGresult *res,
"<td align=%s>%s</td></tr>\n",
fieldNames[j],
fieldNotNum[j] ? "left" : "right",
buf);
pval);
else
{
if (po->align)
fprintf(fout,
"%-*s%s %s\n",
fieldMaxLen - fs_len, fieldNames[j], po->fieldSep,
buf);
fieldMaxLen - fs_len, fieldNames[j],
po->fieldSep,
pval);
else
fprintf(fout, "%s%s%s\n", fieldNames[j], po->fieldSep, buf);
fprintf(fout,
"%s%s%s\n",
fieldNames[j], po->fieldSep, pval);
}
}
else
{
if (!po->html3)
{
fputs(buf, fout);
fputs(pval, fout);
efield:
if ((j + 1) < nFields)
fputs(po->fieldSep, fout);
......
......@@ -11,7 +11,7 @@
*
* Copyright (c) 1994, Regents of the University of California
*
* $Id: libpq-int.h,v 1.10 1999/07/13 20:00:37 momjian Exp $
* $Id: libpq-int.h,v 1.11 1999/08/31 01:37:37 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -21,12 +21,12 @@
/* We assume libpq-fe.h has already been included. */
/* ----------------
* include stuff common to fe and be
* ----------------
*/
/* include stuff common to fe and be */
#include "libpq/pqcomm.h"
#include "lib/dllist.h"
/* include stuff found in fe only */
#include "pqexpbuffer.h"
/* libpq supports this version of the frontend/backend protocol.
*
......@@ -45,8 +45,6 @@
* POSTGRES backend dependent Constants.
*/
/* ERROR_MSG_LENGTH should really be the same as ELOG_MAXLEN in utils/elog.h*/
#define ERROR_MSG_LENGTH 4096
#define CMDSTATUS_LEN 40
/*
......@@ -115,7 +113,7 @@ struct pg_result
int tupArrSize; /* size of tuples array allocated */
ExecStatusType resultStatus;
char cmdStatus[CMDSTATUS_LEN]; /* cmd status from the
* last insert query */
* last query */
int binary; /* binary tuple values if binary == 1,
* otherwise ASCII */
PGconn *conn; /* connection we did the query on, if any */
......@@ -217,8 +215,11 @@ struct pg_conn
PGresult *result; /* result being constructed */
PGresAttValue *curTuple; /* tuple currently being read */
/* Message space. Placed last for code-size reasons. */
char errorMessage[ERROR_MSG_LENGTH];
/* Buffer for current error message */
PQExpBufferData errorMessage; /* expansible string */
/* Buffer for receiving various parts of messages */
PQExpBufferData workBuffer; /* expansible string */
};
/* ----------------
......@@ -249,7 +250,7 @@ extern void pqClearAsyncResult(PGconn *conn);
* necessarily any error.
*/
extern int pqGetc(char *result, PGconn *conn);
extern int pqGets(char *s, int maxlen, PGconn *conn);
extern int pqGets(PQExpBuffer buf, PGconn *conn);
extern int pqPuts(const char *s, PGconn *conn);
extern int pqGetnchar(char *s, int len, PGconn *conn);
extern int pqPutnchar(const char *s, int len, PGconn *conn);
......@@ -259,12 +260,6 @@ extern int pqReadData(PGconn *conn);
extern int pqFlush(PGconn *conn);
extern int pqWait(int forRead, int forWrite, PGconn *conn);
/* max length of message to send */
#define MAX_MESSAGE_LEN MAX_QUERY_SIZE
/* maximum number of fields in a tuple */
#define MAX_FIELDS 512
/* bits in a byte */
#define BYTELEN 8
......
/*-------------------------------------------------------------------------
*
* 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';
}
/*-------------------------------------------------------------------------
*
* 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 */
......@@ -29,6 +29,7 @@ CLEAN :
-@erase "$(INTDIR)\fe-lobj.obj"
-@erase "$(INTDIR)\fe-misc.obj"
-@erase "$(INTDIR)\fe-print.obj"
-@erase "$(INTDIR)\pqexpbuffer.obj"
-@erase "$(OUTDIR)\libpqdll.obj"
-@erase "$(OUTDIR)\libpq.lib"
-@erase "$(OUTDIR)\libpq.dll"
......@@ -70,7 +71,8 @@ LIB32_OBJS= \
"$(INTDIR)\fe-exec.obj" \
"$(INTDIR)\fe-lobj.obj" \
"$(INTDIR)\fe-misc.obj" \
"$(INTDIR)\fe-print.obj"
"$(INTDIR)\fe-print.obj" \
"$(INTDIR)\pqexpbuffer.obj"
!IFDEF MULTIBYTE
LIB32_OBJS = $(LIB32_OBJS) "$(INTDIR)\common.obj" "$(INTDIR)\wchar.obj" "$(INTDIR)\conv.obj" "$(INTDIR)\big5.obj"
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment