mirror of
https://github.com/postgres/postgres.git
synced 2025-04-25 21:42:33 +03:00
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...
This commit is contained in:
parent
130e372b5d
commit
ab5cafa5d3
@ -6,7 +6,7 @@
|
|||||||
# Copyright (c) 1994, Regents of the University of California
|
# Copyright (c) 1994, Regents of the University of California
|
||||||
#
|
#
|
||||||
# IDENTIFICATION
|
# 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
|
endif
|
||||||
|
|
||||||
OBJS= fe-auth.o fe-connect.o fe-exec.o fe-misc.o fe-print.o fe-lobj.o \
|
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
|
ifdef MULTIBYTE
|
||||||
OBJS+= common.o wchar.o conv.o big5.o
|
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
|
@if [ ! -d $(HEADERDIR) ]; then mkdir $(HEADERDIR); fi
|
||||||
$(INSTALL) $(INSTLOPTS) libpq-fe.h $(HEADERDIR)/libpq-fe.h
|
$(INSTALL) $(INSTLOPTS) libpq-fe.h $(HEADERDIR)/libpq-fe.h
|
||||||
$(INSTALL) $(INSTLOPTS) libpq-int.h $(HEADERDIR)/libpq-int.h
|
$(INSTALL) $(INSTLOPTS) libpq-int.h $(HEADERDIR)/libpq-int.h
|
||||||
|
$(INSTALL) $(INSTLOPTS) pqexpbuffer.h $(HEADERDIR)/pqexpbuffer.h
|
||||||
|
|
||||||
|
|
||||||
.PHONY: clean
|
.PHONY: clean
|
||||||
|
@ -5,9 +5,11 @@
|
|||||||
*
|
*
|
||||||
* Copyright (c) 1994, Regents of the University of California
|
* 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
|
* 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 $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-connect.c,v 1.101 1999/07/19 06:25:38 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-connect.c,v 1.102 1999/08/31 01:37:36 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -44,7 +44,7 @@ static ConnStatusType connectDB(PGconn *conn);
|
|||||||
static PGconn *makeEmptyPGconn(void);
|
static PGconn *makeEmptyPGconn(void);
|
||||||
static void freePGconn(PGconn *conn);
|
static void freePGconn(PGconn *conn);
|
||||||
static void closePGconn(PGconn *conn);
|
static void closePGconn(PGconn *conn);
|
||||||
static int conninfo_parse(const char *conninfo, char *errorMessage);
|
static int conninfo_parse(const char *conninfo, PQExpBuffer errorMessage);
|
||||||
static char *conninfo_getval(char *keyword);
|
static char *conninfo_getval(char *keyword);
|
||||||
static void conninfo_free(void);
|
static void conninfo_free(void);
|
||||||
static void defaultNoticeProcessor(void *arg, const char *message);
|
static void defaultNoticeProcessor(void *arg, const char *message);
|
||||||
@ -178,7 +178,7 @@ PQconnectdb(const char *conninfo)
|
|||||||
* Parse the conninfo string and save settings in conn structure
|
* Parse the conninfo string and save settings in conn structure
|
||||||
* ----------
|
* ----------
|
||||||
*/
|
*/
|
||||||
if (conninfo_parse(conninfo, conn->errorMessage) < 0)
|
if (conninfo_parse(conninfo, &conn->errorMessage) < 0)
|
||||||
{
|
{
|
||||||
conn->status = CONNECTION_BAD;
|
conn->status = CONNECTION_BAD;
|
||||||
conninfo_free();
|
conninfo_free();
|
||||||
@ -226,9 +226,11 @@ PQconnectdb(const char *conninfo)
|
|||||||
PQconninfoOption *
|
PQconninfoOption *
|
||||||
PQconndefaults(void)
|
PQconndefaults(void)
|
||||||
{
|
{
|
||||||
char errorMessage[ERROR_MSG_LENGTH];
|
PQExpBufferData errorBuf;
|
||||||
|
|
||||||
conninfo_parse("", errorMessage);
|
initPQExpBuffer(&errorBuf);
|
||||||
|
conninfo_parse("", &errorBuf);
|
||||||
|
termPQExpBuffer(&errorBuf);
|
||||||
return PQconninfoOptions;
|
return PQconninfoOptions;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -328,13 +330,17 @@ PQsetdbLogin(const char *pghost, const char *pgport, const char *pgoptions, cons
|
|||||||
else if ((tmp = getenv("PGUSER")) != NULL)
|
else if ((tmp = getenv("PGUSER")) != NULL)
|
||||||
conn->pguser = strdup(tmp);
|
conn->pguser = strdup(tmp);
|
||||||
else
|
else
|
||||||
conn->pguser = fe_getauthname(conn->errorMessage);
|
{
|
||||||
|
/* fe-auth.c has not been fixed to support PQExpBuffers, so: */
|
||||||
|
conn->pguser = fe_getauthname(conn->errorMessage.data);
|
||||||
|
conn->errorMessage.len = strlen(conn->errorMessage.data);
|
||||||
|
}
|
||||||
|
|
||||||
if (conn->pguser == NULL)
|
if (conn->pguser == NULL)
|
||||||
{
|
{
|
||||||
error = TRUE;
|
error = TRUE;
|
||||||
sprintf(conn->errorMessage,
|
printfPQExpBuffer(&conn->errorMessage,
|
||||||
"FATAL: PQsetdbLogin(): Unable to determine a Postgres username!\n");
|
"FATAL: PQsetdbLogin(): Unable to determine a Postgres username!\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pwd)
|
if (pwd)
|
||||||
@ -469,8 +475,8 @@ update_db_info(PGconn *conn)
|
|||||||
conn->pghost = NULL;
|
conn->pghost = NULL;
|
||||||
if (strcmp(old + offset, "localhost") != 0)
|
if (strcmp(old + offset, "localhost") != 0)
|
||||||
{
|
{
|
||||||
(void) sprintf(conn->errorMessage,
|
printfPQExpBuffer(&conn->errorMessage,
|
||||||
"connectDB() -- non-tcp access only possible on localhost\n");
|
"connectDB() -- non-tcp access only possible on localhost\n");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -533,9 +539,9 @@ connectDB(PGconn *conn)
|
|||||||
hp = gethostbyname(conn->pghost);
|
hp = gethostbyname(conn->pghost);
|
||||||
if ((hp == NULL) || (hp->h_addrtype != AF_INET))
|
if ((hp == NULL) || (hp->h_addrtype != AF_INET))
|
||||||
{
|
{
|
||||||
(void) sprintf(conn->errorMessage,
|
printfPQExpBuffer(&conn->errorMessage,
|
||||||
"connectDB() -- unknown hostname: %s\n",
|
"connectDB() -- unknown hostname: %s\n",
|
||||||
conn->pghost);
|
conn->pghost);
|
||||||
goto connect_errReturn;
|
goto connect_errReturn;
|
||||||
}
|
}
|
||||||
family = AF_INET;
|
family = AF_INET;
|
||||||
@ -567,21 +573,21 @@ connectDB(PGconn *conn)
|
|||||||
/* Connect to the server */
|
/* Connect to the server */
|
||||||
if ((conn->sock = socket(family, SOCK_STREAM, 0)) < 0)
|
if ((conn->sock = socket(family, SOCK_STREAM, 0)) < 0)
|
||||||
{
|
{
|
||||||
(void) sprintf(conn->errorMessage,
|
printfPQExpBuffer(&conn->errorMessage,
|
||||||
"connectDB() -- socket() failed: errno=%d\n%s\n",
|
"connectDB() -- socket() failed: errno=%d\n%s\n",
|
||||||
errno, strerror(errno));
|
errno, strerror(errno));
|
||||||
goto connect_errReturn;
|
goto connect_errReturn;
|
||||||
}
|
}
|
||||||
if (connect(conn->sock, &conn->raddr.sa, conn->raddr_len) < 0)
|
if (connect(conn->sock, &conn->raddr.sa, conn->raddr_len) < 0)
|
||||||
{
|
{
|
||||||
(void) sprintf(conn->errorMessage,
|
printfPQExpBuffer(&conn->errorMessage,
|
||||||
"connectDB() -- connect() failed: %s\n"
|
"connectDB() -- connect() failed: %s\n"
|
||||||
"Is the postmaster running%s at '%s' and accepting connections on %s '%s'?\n",
|
"Is the postmaster running%s at '%s' and accepting connections on %s '%s'?\n",
|
||||||
strerror(errno),
|
strerror(errno),
|
||||||
(family == AF_INET) ? " (with -i)" : "",
|
(family == AF_INET) ? " (with -i)" : "",
|
||||||
conn->pghost ? conn->pghost : "localhost",
|
conn->pghost ? conn->pghost : "localhost",
|
||||||
(family == AF_INET) ? "TCP/IP port" : "Unix socket",
|
(family == AF_INET) ? "TCP/IP port" : "Unix socket",
|
||||||
conn->pgport);
|
conn->pgport);
|
||||||
goto connect_errReturn;
|
goto connect_errReturn;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -596,9 +602,9 @@ connectDB(PGconn *conn)
|
|||||||
if (ioctlsocket(conn->sock, FIONBIO, &on) != 0)
|
if (ioctlsocket(conn->sock, FIONBIO, &on) != 0)
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
(void) sprintf(conn->errorMessage,
|
printfPQExpBuffer(&conn->errorMessage,
|
||||||
"connectDB() -- fcntl() failed: errno=%d\n%s\n",
|
"connectDB() -- fcntl() failed: errno=%d\n%s\n",
|
||||||
errno, strerror(errno));
|
errno, strerror(errno));
|
||||||
goto connect_errReturn;
|
goto connect_errReturn;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -609,8 +615,8 @@ connectDB(PGconn *conn)
|
|||||||
pe = getprotobyname("TCP");
|
pe = getprotobyname("TCP");
|
||||||
if (pe == NULL)
|
if (pe == NULL)
|
||||||
{
|
{
|
||||||
(void) sprintf(conn->errorMessage,
|
printfPQExpBuffer(&conn->errorMessage,
|
||||||
"connectDB(): getprotobyname failed\n");
|
"connectDB(): getprotobyname failed\n");
|
||||||
goto connect_errReturn;
|
goto connect_errReturn;
|
||||||
}
|
}
|
||||||
if (setsockopt(conn->sock, pe->p_proto, TCP_NODELAY,
|
if (setsockopt(conn->sock, pe->p_proto, TCP_NODELAY,
|
||||||
@ -620,9 +626,9 @@ connectDB(PGconn *conn)
|
|||||||
&on,
|
&on,
|
||||||
sizeof(on)) < 0)
|
sizeof(on)) < 0)
|
||||||
{
|
{
|
||||||
(void) sprintf(conn->errorMessage,
|
printfPQExpBuffer(&conn->errorMessage,
|
||||||
"connectDB() -- setsockopt failed: errno=%d\n%s\n",
|
"connectDB() -- setsockopt failed: errno=%d\n%s\n",
|
||||||
errno, strerror(errno));
|
errno, strerror(errno));
|
||||||
#ifdef WIN32
|
#ifdef WIN32
|
||||||
printf("Winsock error: %i\n", WSAGetLastError());
|
printf("Winsock error: %i\n", WSAGetLastError());
|
||||||
#endif
|
#endif
|
||||||
@ -634,9 +640,9 @@ connectDB(PGconn *conn)
|
|||||||
laddrlen = sizeof(conn->laddr);
|
laddrlen = sizeof(conn->laddr);
|
||||||
if (getsockname(conn->sock, &conn->laddr.sa, &laddrlen) < 0)
|
if (getsockname(conn->sock, &conn->laddr.sa, &laddrlen) < 0)
|
||||||
{
|
{
|
||||||
(void) sprintf(conn->errorMessage,
|
printfPQExpBuffer(&conn->errorMessage,
|
||||||
"connectDB() -- getsockname() failed: errno=%d\n%s\n",
|
"connectDB() -- getsockname() failed: errno=%d\n%s\n",
|
||||||
errno, strerror(errno));
|
errno, strerror(errno));
|
||||||
goto connect_errReturn;
|
goto connect_errReturn;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -648,9 +654,9 @@ connectDB(PGconn *conn)
|
|||||||
|
|
||||||
if (pqPacketSend(conn, (char *) &sp, sizeof(StartupPacket)) != STATUS_OK)
|
if (pqPacketSend(conn, (char *) &sp, sizeof(StartupPacket)) != STATUS_OK)
|
||||||
{
|
{
|
||||||
sprintf(conn->errorMessage,
|
printfPQExpBuffer(&conn->errorMessage,
|
||||||
"connectDB() -- couldn't send startup packet: errno=%d\n%s\n",
|
"connectDB() -- couldn't send startup packet: errno=%d\n%s\n",
|
||||||
errno, strerror(errno));
|
errno, strerror(errno));
|
||||||
goto connect_errReturn;
|
goto connect_errReturn;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -681,7 +687,7 @@ connectDB(PGconn *conn)
|
|||||||
/* Handle errors. */
|
/* Handle errors. */
|
||||||
if (beresp == 'E')
|
if (beresp == 'E')
|
||||||
{
|
{
|
||||||
if (pqGets(conn->errorMessage, sizeof(conn->errorMessage), conn))
|
if (pqGets(&conn->errorMessage, conn))
|
||||||
continue;
|
continue;
|
||||||
goto connect_errReturn;
|
goto connect_errReturn;
|
||||||
}
|
}
|
||||||
@ -689,8 +695,8 @@ connectDB(PGconn *conn)
|
|||||||
/* Otherwise it should be an authentication request. */
|
/* Otherwise it should be an authentication request. */
|
||||||
if (beresp != 'R')
|
if (beresp != 'R')
|
||||||
{
|
{
|
||||||
(void) sprintf(conn->errorMessage,
|
printfPQExpBuffer(&conn->errorMessage,
|
||||||
"connectDB() -- expected authentication request\n");
|
"connectDB() -- expected authentication request\n");
|
||||||
goto connect_errReturn;
|
goto connect_errReturn;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -709,9 +715,14 @@ connectDB(PGconn *conn)
|
|||||||
conn->inStart = conn->inCursor;
|
conn->inStart = conn->inCursor;
|
||||||
|
|
||||||
/* Respond to the request if necessary. */
|
/* Respond to the request if necessary. */
|
||||||
|
/* fe-auth.c has not been fixed to support PQExpBuffers, so: */
|
||||||
if (fe_sendauth(areq, conn, conn->pghost, conn->pgpass,
|
if (fe_sendauth(areq, conn, conn->pghost, conn->pgpass,
|
||||||
conn->errorMessage) != STATUS_OK)
|
conn->errorMessage.data) != STATUS_OK)
|
||||||
|
{
|
||||||
|
conn->errorMessage.len = strlen(conn->errorMessage.data);
|
||||||
goto connect_errReturn;
|
goto connect_errReturn;
|
||||||
|
}
|
||||||
|
|
||||||
if (pqFlush(conn))
|
if (pqFlush(conn))
|
||||||
goto connect_errReturn;
|
goto connect_errReturn;
|
||||||
|
|
||||||
@ -737,36 +748,12 @@ connectDB(PGconn *conn)
|
|||||||
if (res)
|
if (res)
|
||||||
{
|
{
|
||||||
if (res->resultStatus != PGRES_FATAL_ERROR)
|
if (res->resultStatus != PGRES_FATAL_ERROR)
|
||||||
sprintf(conn->errorMessage,
|
printfPQExpBuffer(&conn->errorMessage,
|
||||||
"connectDB() -- unexpected message during startup\n");
|
"connectDB() -- unexpected message during startup\n");
|
||||||
PQclear(res);
|
PQclear(res);
|
||||||
goto connect_errReturn;
|
goto connect_errReturn;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Given the new protocol that sends a ReadyForQuery message after
|
|
||||||
* successful backend startup, it should no longer be necessary to
|
|
||||||
* send an empty query to test for startup.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifdef NOT_USED
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Send a blank query to make sure everything works; in particular,
|
|
||||||
* that the database exists.
|
|
||||||
*/
|
|
||||||
res = PQexec(conn, " ");
|
|
||||||
if (res == NULL || res->resultStatus != PGRES_EMPTY_QUERY)
|
|
||||||
{
|
|
||||||
/* PQexec has put error message in conn->errorMessage */
|
|
||||||
closePGconn(conn);
|
|
||||||
PQclear(res);
|
|
||||||
goto connect_errReturn;
|
|
||||||
}
|
|
||||||
PQclear(res);
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Post-connection housekeeping. Send environment variables to server
|
* Post-connection housekeeping. Send environment variables to server
|
||||||
*/
|
*/
|
||||||
@ -870,11 +857,27 @@ makeEmptyPGconn(void)
|
|||||||
conn->asyncStatus = PGASYNC_IDLE;
|
conn->asyncStatus = PGASYNC_IDLE;
|
||||||
conn->notifyList = DLNewList();
|
conn->notifyList = DLNewList();
|
||||||
conn->sock = -1;
|
conn->sock = -1;
|
||||||
conn->inBufSize = PQ_BUFFER_SIZE;
|
/*
|
||||||
|
* The output buffer size is set to 8K, which is the usual size of pipe
|
||||||
|
* buffers on Unix systems. That way, when we are sending a large
|
||||||
|
* amount of data, we avoid incurring extra kernel context swaps for
|
||||||
|
* partial bufferloads. Note that we currently don't ever enlarge
|
||||||
|
* the output buffer.
|
||||||
|
*
|
||||||
|
* With the same goal of minimizing context swaps, the input buffer will
|
||||||
|
* be enlarged anytime it has less than 8K free, so we initially allocate
|
||||||
|
* twice that.
|
||||||
|
*/
|
||||||
|
conn->inBufSize = 16 * 1024;
|
||||||
conn->inBuffer = (char *) malloc(conn->inBufSize);
|
conn->inBuffer = (char *) malloc(conn->inBufSize);
|
||||||
conn->outBufSize = PQ_BUFFER_SIZE;
|
conn->outBufSize = 8 * 1024;
|
||||||
conn->outBuffer = (char *) malloc(conn->outBufSize);
|
conn->outBuffer = (char *) malloc(conn->outBufSize);
|
||||||
if (conn->inBuffer == NULL || conn->outBuffer == NULL)
|
initPQExpBuffer(&conn->errorMessage);
|
||||||
|
initPQExpBuffer(&conn->workBuffer);
|
||||||
|
if (conn->inBuffer == NULL ||
|
||||||
|
conn->outBuffer == NULL ||
|
||||||
|
conn->errorMessage.data == NULL ||
|
||||||
|
conn->workBuffer.data == NULL)
|
||||||
{
|
{
|
||||||
freePGconn(conn);
|
freePGconn(conn);
|
||||||
conn = NULL;
|
conn = NULL;
|
||||||
@ -922,6 +925,8 @@ freePGconn(PGconn *conn)
|
|||||||
free(conn->inBuffer);
|
free(conn->inBuffer);
|
||||||
if (conn->outBuffer)
|
if (conn->outBuffer)
|
||||||
free(conn->outBuffer);
|
free(conn->outBuffer);
|
||||||
|
termPQExpBuffer(&conn->errorMessage);
|
||||||
|
termPQExpBuffer(&conn->workBuffer);
|
||||||
free(conn);
|
free(conn);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1002,16 +1007,24 @@ PQreset(PGconn *conn)
|
|||||||
* PQrequestCancel: attempt to request cancellation of the current operation.
|
* PQrequestCancel: attempt to request cancellation of the current operation.
|
||||||
*
|
*
|
||||||
* The return value is TRUE if the cancel request was successfully
|
* The return value is TRUE if the cancel request was successfully
|
||||||
* dispatched, FALSE if not (in which case errorMessage is set).
|
* dispatched, FALSE if not (in which case conn->errorMessage is set).
|
||||||
* Note: successful dispatch is no guarantee that there will be any effect at
|
* Note: successful dispatch is no guarantee that there will be any effect at
|
||||||
* the backend. The application must read the operation result as usual.
|
* the backend. The application must read the operation result as usual.
|
||||||
*
|
*
|
||||||
|
* XXX it was a bad idea to have the error message returned in
|
||||||
|
* conn->errorMessage, since it could overwrite a message already there.
|
||||||
|
* Would be better to return it in a char array passed by the caller.
|
||||||
|
*
|
||||||
* CAUTION: we want this routine to be safely callable from a signal handler
|
* CAUTION: we want this routine to be safely callable from a signal handler
|
||||||
* (for example, an application might want to call it in a SIGINT handler).
|
* (for example, an application might want to call it in a SIGINT handler).
|
||||||
* This means we cannot use any C library routine that might be non-reentrant.
|
* This means we cannot use any C library routine that might be non-reentrant.
|
||||||
* malloc/free are often non-reentrant, and anything that might call them is
|
* malloc/free are often non-reentrant, and anything that might call them is
|
||||||
* just as dangerous. We avoid sprintf here for that reason. Building up
|
* just as dangerous. We avoid sprintf here for that reason. Building up
|
||||||
* error messages with strcpy/strcat is tedious but should be quite safe.
|
* error messages with strcpy/strcat is tedious but should be quite safe.
|
||||||
|
*
|
||||||
|
* NOTE: this routine must not generate any error message longer than
|
||||||
|
* INITIAL_EXPBUFFER_SIZE (currently 256), since we dare not try to
|
||||||
|
* expand conn->errorMessage!
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int
|
int
|
||||||
@ -1030,8 +1043,9 @@ PQrequestCancel(PGconn *conn)
|
|||||||
|
|
||||||
if (conn->sock < 0)
|
if (conn->sock < 0)
|
||||||
{
|
{
|
||||||
strcpy(conn->errorMessage,
|
strcpy(conn->errorMessage.data,
|
||||||
"PQrequestCancel() -- connection is not open\n");
|
"PQrequestCancel() -- connection is not open\n");
|
||||||
|
conn->errorMessage.len = strlen(conn->errorMessage.data);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1041,12 +1055,14 @@ PQrequestCancel(PGconn *conn)
|
|||||||
*/
|
*/
|
||||||
if ((tmpsock = socket(conn->raddr.sa.sa_family, SOCK_STREAM, 0)) < 0)
|
if ((tmpsock = socket(conn->raddr.sa.sa_family, SOCK_STREAM, 0)) < 0)
|
||||||
{
|
{
|
||||||
strcpy(conn->errorMessage, "PQrequestCancel() -- socket() failed: ");
|
strcpy(conn->errorMessage.data,
|
||||||
|
"PQrequestCancel() -- socket() failed: ");
|
||||||
goto cancel_errReturn;
|
goto cancel_errReturn;
|
||||||
}
|
}
|
||||||
if (connect(tmpsock, &conn->raddr.sa, conn->raddr_len) < 0)
|
if (connect(tmpsock, &conn->raddr.sa, conn->raddr_len) < 0)
|
||||||
{
|
{
|
||||||
strcpy(conn->errorMessage, "PQrequestCancel() -- connect() failed: ");
|
strcpy(conn->errorMessage.data,
|
||||||
|
"PQrequestCancel() -- connect() failed: ");
|
||||||
goto cancel_errReturn;
|
goto cancel_errReturn;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1063,7 +1079,8 @@ PQrequestCancel(PGconn *conn)
|
|||||||
|
|
||||||
if (send(tmpsock, (char *) &crp, sizeof(crp), 0) != (int) sizeof(crp))
|
if (send(tmpsock, (char *) &crp, sizeof(crp), 0) != (int) sizeof(crp))
|
||||||
{
|
{
|
||||||
strcpy(conn->errorMessage, "PQrequestCancel() -- send() failed: ");
|
strcpy(conn->errorMessage.data,
|
||||||
|
"PQrequestCancel() -- send() failed: ");
|
||||||
goto cancel_errReturn;
|
goto cancel_errReturn;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1077,8 +1094,9 @@ PQrequestCancel(PGconn *conn)
|
|||||||
return TRUE;
|
return TRUE;
|
||||||
|
|
||||||
cancel_errReturn:
|
cancel_errReturn:
|
||||||
strcat(conn->errorMessage, strerror(errno));
|
strcat(conn->errorMessage.data, strerror(errno));
|
||||||
strcat(conn->errorMessage, "\n");
|
strcat(conn->errorMessage.data, "\n");
|
||||||
|
conn->errorMessage.len = strlen(conn->errorMessage.data);
|
||||||
if (tmpsock >= 0)
|
if (tmpsock >= 0)
|
||||||
{
|
{
|
||||||
#ifdef WIN32
|
#ifdef WIN32
|
||||||
@ -1123,7 +1141,7 @@ pqPacketSend(PGconn *conn, const char *buf, size_t len)
|
|||||||
* ----------------
|
* ----------------
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
conninfo_parse(const char *conninfo, char *errorMessage)
|
conninfo_parse(const char *conninfo, PQExpBuffer errorMessage)
|
||||||
{
|
{
|
||||||
char *pname;
|
char *pname;
|
||||||
char *pval;
|
char *pval;
|
||||||
@ -1132,13 +1150,13 @@ conninfo_parse(const char *conninfo, char *errorMessage)
|
|||||||
char *cp;
|
char *cp;
|
||||||
char *cp2;
|
char *cp2;
|
||||||
PQconninfoOption *option;
|
PQconninfoOption *option;
|
||||||
char errortmp[ERROR_MSG_LENGTH];
|
char errortmp[INITIAL_EXPBUFFER_SIZE];
|
||||||
|
|
||||||
conninfo_free();
|
conninfo_free();
|
||||||
|
|
||||||
if ((buf = strdup(conninfo)) == NULL)
|
if ((buf = strdup(conninfo)) == NULL)
|
||||||
{
|
{
|
||||||
strcpy(errorMessage,
|
printfPQExpBuffer(errorMessage,
|
||||||
"FATAL: cannot allocate memory for copy of conninfo string\n");
|
"FATAL: cannot allocate memory for copy of conninfo string\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -1176,9 +1194,9 @@ conninfo_parse(const char *conninfo, char *errorMessage)
|
|||||||
/* Check that there is a following '=' */
|
/* Check that there is a following '=' */
|
||||||
if (*cp != '=')
|
if (*cp != '=')
|
||||||
{
|
{
|
||||||
sprintf(errorMessage,
|
printfPQExpBuffer(errorMessage,
|
||||||
"ERROR: PQconnectdb() - Missing '=' after '%s' in conninfo\n",
|
"ERROR: PQconnectdb() - Missing '=' after '%s' in conninfo\n",
|
||||||
pname);
|
pname);
|
||||||
free(buf);
|
free(buf);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -1223,7 +1241,7 @@ conninfo_parse(const char *conninfo, char *errorMessage)
|
|||||||
{
|
{
|
||||||
if (*cp == '\0')
|
if (*cp == '\0')
|
||||||
{
|
{
|
||||||
sprintf(errorMessage,
|
printfPQExpBuffer(errorMessage,
|
||||||
"ERROR: PQconnectdb() - unterminated quoted string in conninfo\n");
|
"ERROR: PQconnectdb() - unterminated quoted string in conninfo\n");
|
||||||
free(buf);
|
free(buf);
|
||||||
return -1;
|
return -1;
|
||||||
@ -1257,9 +1275,9 @@ conninfo_parse(const char *conninfo, char *errorMessage)
|
|||||||
}
|
}
|
||||||
if (option->keyword == NULL)
|
if (option->keyword == NULL)
|
||||||
{
|
{
|
||||||
sprintf(errorMessage,
|
printfPQExpBuffer(errorMessage,
|
||||||
"ERROR: PQconnectdb() - unknown option '%s'\n",
|
"ERROR: PQconnectdb() - unknown option '%s'\n",
|
||||||
pname);
|
pname);
|
||||||
free(buf);
|
free(buf);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -1314,6 +1332,7 @@ conninfo_parse(const char *conninfo, char *errorMessage)
|
|||||||
if (!strcmp(option->keyword, "user"))
|
if (!strcmp(option->keyword, "user"))
|
||||||
{
|
{
|
||||||
option->val = fe_getauthname(errortmp);
|
option->val = fe_getauthname(errortmp);
|
||||||
|
/* note any error message is thrown away */
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1436,7 +1455,7 @@ PQerrorMessage(PGconn *conn)
|
|||||||
|
|
||||||
if (!conn)
|
if (!conn)
|
||||||
return noConn;
|
return noConn;
|
||||||
return conn->errorMessage;
|
return conn->errorMessage.data;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-exec.c,v 1.84 1999/07/19 06:25:39 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-exec.c,v 1.85 1999/08/31 01:37:36 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -42,6 +42,9 @@ const char *const pgresStatus[] = {
|
|||||||
((*(conn)->noticeHook) ((conn)->noticeArg, (message)))
|
((*(conn)->noticeHook) ((conn)->noticeArg, (message)))
|
||||||
|
|
||||||
|
|
||||||
|
static void pqCatenateResultError(PGresult *res, const char *msg);
|
||||||
|
static void saveErrorResult(PGconn *conn);
|
||||||
|
static PGresult *prepareAsyncResult(PGconn *conn);
|
||||||
static int addTuple(PGresult *res, PGresAttValue *tup);
|
static int addTuple(PGresult *res, PGresAttValue *tup);
|
||||||
static void parseInput(PGconn *conn);
|
static void parseInput(PGconn *conn);
|
||||||
static void handleSendFailure(PGconn *conn);
|
static void handleSendFailure(PGconn *conn);
|
||||||
@ -158,7 +161,7 @@ PQmakeEmptyPGresult(PGconn *conn, ExecStatusType status)
|
|||||||
/* non-error cases */
|
/* non-error cases */
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
pqSetResultError(result, conn->errorMessage);
|
pqSetResultError(result, conn->errorMessage.data);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -298,6 +301,25 @@ pqSetResultError(PGresult *res, const char *msg)
|
|||||||
res->errMsg = NULL;
|
res->errMsg = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* pqCatenateResultError -
|
||||||
|
* concatenate a new error message to the one already in a PGresult
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
pqCatenateResultError(PGresult *res, const char *msg)
|
||||||
|
{
|
||||||
|
PQExpBufferData errorBuf;
|
||||||
|
|
||||||
|
if (!res || !msg)
|
||||||
|
return;
|
||||||
|
initPQExpBuffer(&errorBuf);
|
||||||
|
if (res->errMsg)
|
||||||
|
appendPQExpBufferStr(&errorBuf, res->errMsg);
|
||||||
|
appendPQExpBufferStr(&errorBuf, msg);
|
||||||
|
pqSetResultError(res, errorBuf.data);
|
||||||
|
termPQExpBuffer(&errorBuf);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* PQclear -
|
* PQclear -
|
||||||
* free's the memory associated with a PGresult
|
* free's the memory associated with a PGresult
|
||||||
@ -338,6 +360,72 @@ pqClearAsyncResult(PGconn *conn)
|
|||||||
conn->curTuple = NULL;
|
conn->curTuple = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This subroutine deletes any existing async result, sets conn->result
|
||||||
|
* to a PGresult with status PGRES_FATAL_ERROR, and stores the current
|
||||||
|
* contents of conn->errorMessage into that result. It differs from a
|
||||||
|
* plain call on PQmakeEmptyPGresult() in that if there is already an
|
||||||
|
* async result with status PGRES_FATAL_ERROR, the current error message
|
||||||
|
* is APPENDED to the old error message instead of replacing it. This
|
||||||
|
* behavior lets us report multiple error conditions properly, if necessary.
|
||||||
|
* (An example where this is needed is when the backend sends an 'E' message
|
||||||
|
* and immediately closes the connection --- we want to report both the
|
||||||
|
* backend error and the connection closure error.)
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
saveErrorResult(PGconn *conn)
|
||||||
|
{
|
||||||
|
/* If no old async result, just let PQmakeEmptyPGresult make one.
|
||||||
|
* Likewise if old result is not an error message.
|
||||||
|
*/
|
||||||
|
if (conn->result == NULL ||
|
||||||
|
conn->result->resultStatus != PGRES_FATAL_ERROR ||
|
||||||
|
conn->result->errMsg == NULL)
|
||||||
|
{
|
||||||
|
pqClearAsyncResult(conn);
|
||||||
|
conn->result = PQmakeEmptyPGresult(conn, PGRES_FATAL_ERROR);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Else, concatenate error message to existing async result. */
|
||||||
|
pqCatenateResultError(conn->result, conn->errorMessage.data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This subroutine prepares an async result object for return to the caller.
|
||||||
|
* If there is not already an async result object, build an error object
|
||||||
|
* using whatever is in conn->errorMessage. In any case, clear the async
|
||||||
|
* result storage and make sure PQerrorMessage will agree with the result's
|
||||||
|
* error string.
|
||||||
|
*/
|
||||||
|
static PGresult *
|
||||||
|
prepareAsyncResult(PGconn *conn)
|
||||||
|
{
|
||||||
|
PGresult *res;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* conn->result is the PGresult to return. If it is NULL
|
||||||
|
* (which probably shouldn't happen) we assume there is an
|
||||||
|
* appropriate error message in conn->errorMessage.
|
||||||
|
*/
|
||||||
|
res = conn->result;
|
||||||
|
conn->result = NULL; /* handing over ownership to caller */
|
||||||
|
conn->curTuple = NULL; /* just in case */
|
||||||
|
if (!res)
|
||||||
|
res = PQmakeEmptyPGresult(conn, PGRES_FATAL_ERROR);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Make sure PQerrorMessage agrees with result; it could
|
||||||
|
* be different if we have concatenated messages.
|
||||||
|
*/
|
||||||
|
resetPQExpBuffer(&conn->errorMessage);
|
||||||
|
appendPQExpBufferStr(&conn->errorMessage,
|
||||||
|
PQresultErrorMessage(res));
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* addTuple
|
* addTuple
|
||||||
@ -394,37 +482,33 @@ PQsendQuery(PGconn *conn, const char *query)
|
|||||||
{
|
{
|
||||||
if (!conn)
|
if (!conn)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
/* clear the error string */
|
||||||
|
resetPQExpBuffer(&conn->errorMessage);
|
||||||
|
|
||||||
if (!query)
|
if (!query)
|
||||||
{
|
{
|
||||||
sprintf(conn->errorMessage, "PQsendQuery() -- query pointer is null.");
|
printfPQExpBuffer(&conn->errorMessage,
|
||||||
return 0;
|
"PQsendQuery() -- query pointer is null.\n");
|
||||||
}
|
|
||||||
/* check to see if the query string is too long */
|
|
||||||
if (strlen(query) > MAX_MESSAGE_LEN - 2)
|
|
||||||
{
|
|
||||||
sprintf(conn->errorMessage, "PQsendQuery() -- query is too long. "
|
|
||||||
"Maximum length is %d\n", MAX_MESSAGE_LEN - 2);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Don't try to send if we know there's no live connection. */
|
/* Don't try to send if we know there's no live connection. */
|
||||||
if (conn->status != CONNECTION_OK)
|
if (conn->status != CONNECTION_OK)
|
||||||
{
|
{
|
||||||
sprintf(conn->errorMessage, "PQsendQuery() -- There is no connection "
|
printfPQExpBuffer(&conn->errorMessage,
|
||||||
"to the backend.\n");
|
"PQsendQuery() -- There is no connection "
|
||||||
|
"to the backend.\n");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
/* Can't send while already busy, either. */
|
/* Can't send while already busy, either. */
|
||||||
if (conn->asyncStatus != PGASYNC_IDLE)
|
if (conn->asyncStatus != PGASYNC_IDLE)
|
||||||
{
|
{
|
||||||
sprintf(conn->errorMessage,
|
printfPQExpBuffer(&conn->errorMessage,
|
||||||
"PQsendQuery() -- another query already in progress.");
|
"PQsendQuery() -- another query already in progress.\n");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* clear the error string */
|
|
||||||
conn->errorMessage[0] = '\0';
|
|
||||||
|
|
||||||
/* initialize async result-accumulation state */
|
/* initialize async result-accumulation state */
|
||||||
conn->result = NULL;
|
conn->result = NULL;
|
||||||
conn->curTuple = NULL;
|
conn->curTuple = NULL;
|
||||||
@ -456,9 +540,6 @@ PQsendQuery(PGconn *conn, const char *query)
|
|||||||
static void
|
static void
|
||||||
handleSendFailure(PGconn *conn)
|
handleSendFailure(PGconn *conn)
|
||||||
{
|
{
|
||||||
/* Preserve the error message emitted by the failing output routine */
|
|
||||||
char * svErrMsg = strdup(conn->errorMessage);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Accept any available input data, ignoring errors. Note that if
|
* Accept any available input data, ignoring errors. Note that if
|
||||||
* pqReadData decides the backend has closed the channel, it will
|
* pqReadData decides the backend has closed the channel, it will
|
||||||
@ -472,11 +553,6 @@ handleSendFailure(PGconn *conn)
|
|||||||
* state, only NOTICE and NOTIFY messages will be eaten.
|
* state, only NOTICE and NOTIFY messages will be eaten.
|
||||||
*/
|
*/
|
||||||
parseInput(conn);
|
parseInput(conn);
|
||||||
|
|
||||||
/* Restore error message generated by output routine, if any. */
|
|
||||||
if (*svErrMsg != '\0')
|
|
||||||
strcpy(conn->errorMessage, svErrMsg);
|
|
||||||
free(svErrMsg);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -514,6 +590,7 @@ static void
|
|||||||
parseInput(PGconn *conn)
|
parseInput(PGconn *conn)
|
||||||
{
|
{
|
||||||
char id;
|
char id;
|
||||||
|
char noticeWorkspace[128];
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Loop to parse successive complete messages available in the buffer.
|
* Loop to parse successive complete messages available in the buffer.
|
||||||
@ -565,10 +642,10 @@ parseInput(PGconn *conn)
|
|||||||
{
|
{
|
||||||
if (conn->asyncStatus == PGASYNC_IDLE)
|
if (conn->asyncStatus == PGASYNC_IDLE)
|
||||||
{
|
{
|
||||||
sprintf(conn->errorMessage,
|
sprintf(noticeWorkspace,
|
||||||
"Backend message type 0x%02x arrived while idle\n",
|
"Backend message type 0x%02x arrived while idle\n",
|
||||||
id);
|
id);
|
||||||
DONOTICE(conn, conn->errorMessage);
|
DONOTICE(conn, noticeWorkspace);
|
||||||
/* Discard the unexpected message; good idea?? */
|
/* Discard the unexpected message; good idea?? */
|
||||||
conn->inStart = conn->inEnd;
|
conn->inStart = conn->inEnd;
|
||||||
}
|
}
|
||||||
@ -577,21 +654,20 @@ parseInput(PGconn *conn)
|
|||||||
switch (id)
|
switch (id)
|
||||||
{
|
{
|
||||||
case 'C': /* command complete */
|
case 'C': /* command complete */
|
||||||
|
if (pqGets(&conn->workBuffer, conn))
|
||||||
|
return;
|
||||||
if (conn->result == NULL)
|
if (conn->result == NULL)
|
||||||
conn->result = PQmakeEmptyPGresult(conn,
|
conn->result = PQmakeEmptyPGresult(conn,
|
||||||
PGRES_COMMAND_OK);
|
PGRES_COMMAND_OK);
|
||||||
if (pqGets(conn->result->cmdStatus, CMDSTATUS_LEN, conn))
|
strncpy(conn->result->cmdStatus, conn->workBuffer.data,
|
||||||
return;
|
CMDSTATUS_LEN);
|
||||||
conn->asyncStatus = PGASYNC_READY;
|
conn->asyncStatus = PGASYNC_READY;
|
||||||
break;
|
break;
|
||||||
case 'E': /* error return */
|
case 'E': /* error return */
|
||||||
if (pqGets(conn->errorMessage, ERROR_MSG_LENGTH, conn))
|
if (pqGets(& conn->errorMessage, conn))
|
||||||
return;
|
return;
|
||||||
/* delete any partially constructed result */
|
/* build an error result holding the error message */
|
||||||
pqClearAsyncResult(conn);
|
saveErrorResult(conn);
|
||||||
/* and build an error result holding the error message */
|
|
||||||
conn->result = PQmakeEmptyPGresult(conn,
|
|
||||||
PGRES_FATAL_ERROR);
|
|
||||||
conn->asyncStatus = PGASYNC_READY;
|
conn->asyncStatus = PGASYNC_READY;
|
||||||
break;
|
break;
|
||||||
case 'Z': /* backend is ready for new query */
|
case 'Z': /* backend is ready for new query */
|
||||||
@ -603,9 +679,10 @@ parseInput(PGconn *conn)
|
|||||||
return;
|
return;
|
||||||
if (id != '\0')
|
if (id != '\0')
|
||||||
{
|
{
|
||||||
sprintf(conn->errorMessage,
|
sprintf(noticeWorkspace,
|
||||||
"unexpected character %c following 'I'\n", id);
|
"unexpected character %c following 'I'\n",
|
||||||
DONOTICE(conn, conn->errorMessage);
|
id);
|
||||||
|
DONOTICE(conn, noticeWorkspace);
|
||||||
}
|
}
|
||||||
if (conn->result == NULL)
|
if (conn->result == NULL)
|
||||||
conn->result = PQmakeEmptyPGresult(conn,
|
conn->result = PQmakeEmptyPGresult(conn,
|
||||||
@ -625,7 +702,7 @@ parseInput(PGconn *conn)
|
|||||||
return;
|
return;
|
||||||
break;
|
break;
|
||||||
case 'P': /* synchronous (normal) portal */
|
case 'P': /* synchronous (normal) portal */
|
||||||
if (pqGets(conn->errorMessage, ERROR_MSG_LENGTH, conn))
|
if (pqGets(&conn->workBuffer, conn))
|
||||||
return;
|
return;
|
||||||
/* We pretty much ignore this message type... */
|
/* We pretty much ignore this message type... */
|
||||||
break;
|
break;
|
||||||
@ -660,9 +737,9 @@ parseInput(PGconn *conn)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
sprintf(conn->errorMessage,
|
sprintf(noticeWorkspace,
|
||||||
"Backend sent D message without prior T\n");
|
"Backend sent D message without prior T\n");
|
||||||
DONOTICE(conn, conn->errorMessage);
|
DONOTICE(conn, noticeWorkspace);
|
||||||
/* Discard the unexpected message; good idea?? */
|
/* Discard the unexpected message; good idea?? */
|
||||||
conn->inStart = conn->inEnd;
|
conn->inStart = conn->inEnd;
|
||||||
return;
|
return;
|
||||||
@ -677,9 +754,9 @@ parseInput(PGconn *conn)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
sprintf(conn->errorMessage,
|
sprintf(noticeWorkspace,
|
||||||
"Backend sent B message without prior T\n");
|
"Backend sent B message without prior T\n");
|
||||||
DONOTICE(conn, conn->errorMessage);
|
DONOTICE(conn, noticeWorkspace);
|
||||||
/* Discard the unexpected message; good idea?? */
|
/* Discard the unexpected message; good idea?? */
|
||||||
conn->inStart = conn->inEnd;
|
conn->inStart = conn->inEnd;
|
||||||
return;
|
return;
|
||||||
@ -692,18 +769,15 @@ parseInput(PGconn *conn)
|
|||||||
conn->asyncStatus = PGASYNC_COPY_OUT;
|
conn->asyncStatus = PGASYNC_COPY_OUT;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
sprintf(conn->errorMessage,
|
printfPQExpBuffer(&conn->errorMessage,
|
||||||
"unknown protocol character '%c' read from backend. "
|
"Unknown protocol character '%c' read from backend. "
|
||||||
"(The protocol character is the first character the "
|
"(The protocol character is the first character the "
|
||||||
"backend sends in response to a query it receives).\n",
|
"backend sends in response to a query it receives).\n",
|
||||||
id);
|
id);
|
||||||
|
/* build an error result holding the error message */
|
||||||
|
saveErrorResult(conn);
|
||||||
/* Discard the unexpected message; good idea?? */
|
/* Discard the unexpected message; good idea?? */
|
||||||
conn->inStart = conn->inEnd;
|
conn->inStart = conn->inEnd;
|
||||||
/* delete any partially constructed result */
|
|
||||||
pqClearAsyncResult(conn);
|
|
||||||
/* and build an error result holding the error message */
|
|
||||||
conn->result = PQmakeEmptyPGresult(conn,
|
|
||||||
PGRES_FATAL_ERROR);
|
|
||||||
conn->asyncStatus = PGASYNC_READY;
|
conn->asyncStatus = PGASYNC_READY;
|
||||||
return;
|
return;
|
||||||
} /* switch on protocol character */
|
} /* switch on protocol character */
|
||||||
@ -753,12 +827,11 @@ getRowDescriptions(PGconn *conn)
|
|||||||
/* get type info */
|
/* get type info */
|
||||||
for (i = 0; i < nfields; i++)
|
for (i = 0; i < nfields; i++)
|
||||||
{
|
{
|
||||||
char typName[MAX_MESSAGE_LEN];
|
|
||||||
int typid;
|
int typid;
|
||||||
int typlen;
|
int typlen;
|
||||||
int atttypmod;
|
int atttypmod;
|
||||||
|
|
||||||
if (pqGets(typName, MAX_MESSAGE_LEN, conn) ||
|
if (pqGets(&conn->workBuffer, conn) ||
|
||||||
pqGetInt(&typid, 4, conn) ||
|
pqGetInt(&typid, 4, conn) ||
|
||||||
pqGetInt(&typlen, 2, conn) ||
|
pqGetInt(&typlen, 2, conn) ||
|
||||||
pqGetInt(&atttypmod, 4, conn))
|
pqGetInt(&atttypmod, 4, conn))
|
||||||
@ -777,7 +850,8 @@ getRowDescriptions(PGconn *conn)
|
|||||||
*/
|
*/
|
||||||
if (typlen == 0xFFFF)
|
if (typlen == 0xFFFF)
|
||||||
typlen = -1;
|
typlen = -1;
|
||||||
result->attDescs[i].name = pqResultStrdup(result, typName);
|
result->attDescs[i].name = pqResultStrdup(result,
|
||||||
|
conn->workBuffer.data);
|
||||||
result->attDescs[i].typid = typid;
|
result->attDescs[i].typid = typid;
|
||||||
result->attDescs[i].typlen = typlen;
|
result->attDescs[i].typlen = typlen;
|
||||||
result->attDescs[i].atttypmod = atttypmod;
|
result->attDescs[i].atttypmod = atttypmod;
|
||||||
@ -804,8 +878,9 @@ getAnotherTuple(PGconn *conn, int binary)
|
|||||||
PGresult *result = conn->result;
|
PGresult *result = conn->result;
|
||||||
int nfields = result->numAttributes;
|
int nfields = result->numAttributes;
|
||||||
PGresAttValue *tup;
|
PGresAttValue *tup;
|
||||||
char bitmap[MAX_FIELDS]; /* the backend sends us a bitmap
|
/* the backend sends us a bitmap of which attributes are null */
|
||||||
* of which attributes are null */
|
char std_bitmap[64]; /* used unless it doesn't fit */
|
||||||
|
char *bitmap = std_bitmap;
|
||||||
int i;
|
int i;
|
||||||
int nbytes; /* the number of bytes in bitmap */
|
int nbytes; /* the number of bytes in bitmap */
|
||||||
char bmap; /* One byte of the bitmap */
|
char bmap; /* One byte of the bitmap */
|
||||||
@ -828,21 +903,12 @@ getAnotherTuple(PGconn *conn, int binary)
|
|||||||
|
|
||||||
/* Get the null-value bitmap */
|
/* Get the null-value bitmap */
|
||||||
nbytes = (nfields + BYTELEN - 1) / BYTELEN;
|
nbytes = (nfields + BYTELEN - 1) / BYTELEN;
|
||||||
if (nbytes >= MAX_FIELDS)
|
/* malloc() only for unusually large field counts... */
|
||||||
{
|
if (nbytes > sizeof(std_bitmap))
|
||||||
/* Replace partially constructed result with an error result */
|
bitmap = (char *) malloc(nbytes);
|
||||||
pqClearAsyncResult(conn);
|
|
||||||
sprintf(conn->errorMessage,
|
|
||||||
"getAnotherTuple() -- null-values bitmap is too large\n");
|
|
||||||
conn->result = PQmakeEmptyPGresult(conn, PGRES_FATAL_ERROR);
|
|
||||||
conn->asyncStatus = PGASYNC_READY;
|
|
||||||
/* Discard the broken message */
|
|
||||||
conn->inStart = conn->inEnd;
|
|
||||||
return EOF;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pqGetnchar(bitmap, nbytes, conn))
|
if (pqGetnchar(bitmap, nbytes, conn))
|
||||||
return EOF;
|
goto EOFexit;
|
||||||
|
|
||||||
/* Scan the fields */
|
/* Scan the fields */
|
||||||
bitmap_index = 0;
|
bitmap_index = 0;
|
||||||
@ -861,7 +927,7 @@ getAnotherTuple(PGconn *conn, int binary)
|
|||||||
{
|
{
|
||||||
/* get the value length (the first four bytes are for length) */
|
/* get the value length (the first four bytes are for length) */
|
||||||
if (pqGetInt(&vlen, 4, conn))
|
if (pqGetInt(&vlen, 4, conn))
|
||||||
return EOF;
|
goto EOFexit;
|
||||||
if (binary == 0)
|
if (binary == 0)
|
||||||
vlen = vlen - 4;
|
vlen = vlen - 4;
|
||||||
if (vlen < 0)
|
if (vlen < 0)
|
||||||
@ -876,7 +942,7 @@ getAnotherTuple(PGconn *conn, int binary)
|
|||||||
/* read in the value */
|
/* read in the value */
|
||||||
if (vlen > 0)
|
if (vlen > 0)
|
||||||
if (pqGetnchar((char *) (tup[i].value), vlen, conn))
|
if (pqGetnchar((char *) (tup[i].value), vlen, conn))
|
||||||
return EOF;
|
goto EOFexit;
|
||||||
/* we have to terminate this ourselves */
|
/* we have to terminate this ourselves */
|
||||||
tup[i].value[vlen] = '\0';
|
tup[i].value[vlen] = '\0';
|
||||||
}
|
}
|
||||||
@ -897,17 +963,27 @@ getAnotherTuple(PGconn *conn, int binary)
|
|||||||
goto outOfMemory;
|
goto outOfMemory;
|
||||||
/* and reset for a new message */
|
/* and reset for a new message */
|
||||||
conn->curTuple = NULL;
|
conn->curTuple = NULL;
|
||||||
|
|
||||||
|
if (bitmap != std_bitmap)
|
||||||
|
free(bitmap);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
outOfMemory:
|
outOfMemory:
|
||||||
/* Replace partially constructed result with an error result */
|
/* Replace partially constructed result with an error result */
|
||||||
|
/* we do NOT use saveErrorResult() here, because of the likelihood
|
||||||
|
* that there's not enough memory to concatenate messages...
|
||||||
|
*/
|
||||||
pqClearAsyncResult(conn);
|
pqClearAsyncResult(conn);
|
||||||
sprintf(conn->errorMessage,
|
printfPQExpBuffer(&conn->errorMessage,
|
||||||
"getAnotherTuple() -- out of memory for result\n");
|
"getAnotherTuple() -- out of memory for result\n");
|
||||||
conn->result = PQmakeEmptyPGresult(conn, PGRES_FATAL_ERROR);
|
conn->result = PQmakeEmptyPGresult(conn, PGRES_FATAL_ERROR);
|
||||||
conn->asyncStatus = PGASYNC_READY;
|
conn->asyncStatus = PGASYNC_READY;
|
||||||
/* Discard the failed message --- good idea? */
|
/* Discard the failed message --- good idea? */
|
||||||
conn->inStart = conn->inEnd;
|
conn->inStart = conn->inEnd;
|
||||||
|
|
||||||
|
EOFexit:
|
||||||
|
if (bitmap != std_bitmap)
|
||||||
|
free(bitmap);
|
||||||
return EOF;
|
return EOF;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -955,10 +1031,12 @@ PQgetResult(PGconn *conn)
|
|||||||
if (pqWait(TRUE, FALSE, conn) ||
|
if (pqWait(TRUE, FALSE, conn) ||
|
||||||
pqReadData(conn) < 0)
|
pqReadData(conn) < 0)
|
||||||
{
|
{
|
||||||
pqClearAsyncResult(conn);
|
/* conn->errorMessage has been set by pqWait or pqReadData.
|
||||||
|
* We want to append it to any already-received error message.
|
||||||
|
*/
|
||||||
|
saveErrorResult(conn);
|
||||||
conn->asyncStatus = PGASYNC_IDLE;
|
conn->asyncStatus = PGASYNC_IDLE;
|
||||||
/* conn->errorMessage has been set by pqWait or pqReadData. */
|
return prepareAsyncResult(conn);
|
||||||
return PQmakeEmptyPGresult(conn, PGRES_FATAL_ERROR);
|
|
||||||
}
|
}
|
||||||
/* Parse it. */
|
/* Parse it. */
|
||||||
parseInput(conn);
|
parseInput(conn);
|
||||||
@ -971,28 +1049,7 @@ PQgetResult(PGconn *conn)
|
|||||||
res = NULL; /* query is complete */
|
res = NULL; /* query is complete */
|
||||||
break;
|
break;
|
||||||
case PGASYNC_READY:
|
case PGASYNC_READY:
|
||||||
|
res = prepareAsyncResult(conn);
|
||||||
/*
|
|
||||||
* conn->result is the PGresult to return. If it is NULL
|
|
||||||
* (which probably shouldn't happen) we assume there is an
|
|
||||||
* appropriate error message in conn->errorMessage.
|
|
||||||
*/
|
|
||||||
res = conn->result;
|
|
||||||
conn->result = NULL;/* handing over ownership to caller */
|
|
||||||
conn->curTuple = NULL; /* just in case */
|
|
||||||
if (!res)
|
|
||||||
res = PQmakeEmptyPGresult(conn, PGRES_FATAL_ERROR);
|
|
||||||
else
|
|
||||||
{
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Make sure PQerrorMessage agrees with result; it could
|
|
||||||
* be that we have done other operations that changed
|
|
||||||
* errorMessage since the result's error message was
|
|
||||||
* saved.
|
|
||||||
*/
|
|
||||||
strcpy(conn->errorMessage, PQresultErrorMessage(res));
|
|
||||||
}
|
|
||||||
/* Set the state back to BUSY, allowing parsing to proceed. */
|
/* Set the state back to BUSY, allowing parsing to proceed. */
|
||||||
conn->asyncStatus = PGASYNC_BUSY;
|
conn->asyncStatus = PGASYNC_BUSY;
|
||||||
break;
|
break;
|
||||||
@ -1003,9 +1060,9 @@ PQgetResult(PGconn *conn)
|
|||||||
res = PQmakeEmptyPGresult(conn, PGRES_COPY_OUT);
|
res = PQmakeEmptyPGresult(conn, PGRES_COPY_OUT);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
sprintf(conn->errorMessage,
|
printfPQExpBuffer(&conn->errorMessage,
|
||||||
"PQgetResult: Unexpected asyncStatus %d\n",
|
"PQgetResult: Unexpected asyncStatus %d\n",
|
||||||
(int) conn->asyncStatus);
|
(int) conn->asyncStatus);
|
||||||
res = PQmakeEmptyPGresult(conn, PGRES_FATAL_ERROR);
|
res = PQmakeEmptyPGresult(conn, PGRES_FATAL_ERROR);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -1043,7 +1100,7 @@ PQexec(PGconn *conn, const char *query)
|
|||||||
result->resultStatus == PGRES_COPY_OUT)
|
result->resultStatus == PGRES_COPY_OUT)
|
||||||
{
|
{
|
||||||
PQclear(result);
|
PQclear(result);
|
||||||
sprintf(conn->errorMessage,
|
printfPQExpBuffer(&conn->errorMessage,
|
||||||
"PQexec: you gotta get out of a COPY state yourself.\n");
|
"PQexec: you gotta get out of a COPY state yourself.\n");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@ -1056,14 +1113,30 @@ PQexec(PGconn *conn, const char *query)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* For backwards compatibility, return the last result if there are
|
* For backwards compatibility, return the last result if there are
|
||||||
* more than one. We have to stop if we see copy in/out, however. We
|
* more than one --- but merge error messages if we get more than one
|
||||||
* will resume parsing when application calls PQendcopy.
|
* error result.
|
||||||
|
*
|
||||||
|
* We have to stop if we see copy in/out, however.
|
||||||
|
* We will resume parsing when application calls PQendcopy.
|
||||||
*/
|
*/
|
||||||
lastResult = NULL;
|
lastResult = NULL;
|
||||||
while ((result = PQgetResult(conn)) != NULL)
|
while ((result = PQgetResult(conn)) != NULL)
|
||||||
{
|
{
|
||||||
if (lastResult)
|
if (lastResult)
|
||||||
PQclear(lastResult);
|
{
|
||||||
|
if (lastResult->resultStatus == PGRES_FATAL_ERROR &&
|
||||||
|
result->resultStatus == PGRES_FATAL_ERROR)
|
||||||
|
{
|
||||||
|
pqCatenateResultError(lastResult, result->errMsg);
|
||||||
|
PQclear(result);
|
||||||
|
result = lastResult;
|
||||||
|
/* Make sure PQerrorMessage agrees with catenated result */
|
||||||
|
resetPQExpBuffer(&conn->errorMessage);
|
||||||
|
appendPQExpBufferStr(&conn->errorMessage, result->errMsg);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
PQclear(lastResult);
|
||||||
|
}
|
||||||
lastResult = result;
|
lastResult = result;
|
||||||
if (result->resultStatus == PGRES_COPY_IN ||
|
if (result->resultStatus == PGRES_COPY_IN ||
|
||||||
result->resultStatus == PGRES_COPY_OUT)
|
result->resultStatus == PGRES_COPY_OUT)
|
||||||
@ -1083,9 +1156,20 @@ PQexec(PGconn *conn, const char *query)
|
|||||||
static int
|
static int
|
||||||
getNotice(PGconn *conn)
|
getNotice(PGconn *conn)
|
||||||
{
|
{
|
||||||
if (pqGets(conn->errorMessage, ERROR_MSG_LENGTH, conn))
|
/* Since the Notice might be pretty long, we create a temporary
|
||||||
|
* PQExpBuffer rather than using conn->workBuffer. workBuffer is
|
||||||
|
* intended for stuff that is expected to be short.
|
||||||
|
*/
|
||||||
|
PQExpBufferData noticeBuf;
|
||||||
|
|
||||||
|
initPQExpBuffer(¬iceBuf);
|
||||||
|
if (pqGets(¬iceBuf, conn))
|
||||||
|
{
|
||||||
|
termPQExpBuffer(¬iceBuf);
|
||||||
return EOF;
|
return EOF;
|
||||||
DONOTICE(conn, conn->errorMessage);
|
}
|
||||||
|
DONOTICE(conn, noticeBuf.data);
|
||||||
|
termPQExpBuffer(¬iceBuf);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1099,15 +1183,16 @@ getNotice(PGconn *conn)
|
|||||||
static int
|
static int
|
||||||
getNotify(PGconn *conn)
|
getNotify(PGconn *conn)
|
||||||
{
|
{
|
||||||
PGnotify tempNotify;
|
int be_pid;
|
||||||
PGnotify *newNotify;
|
PGnotify *newNotify;
|
||||||
|
|
||||||
if (pqGetInt(&(tempNotify.be_pid), 4, conn))
|
if (pqGetInt(&be_pid, 4, conn))
|
||||||
return EOF;
|
return EOF;
|
||||||
if (pqGets(tempNotify.relname, NAMEDATALEN, conn))
|
if (pqGets(&conn->workBuffer, conn))
|
||||||
return EOF;
|
return EOF;
|
||||||
newNotify = (PGnotify *) malloc(sizeof(PGnotify));
|
newNotify = (PGnotify *) malloc(sizeof(PGnotify));
|
||||||
memcpy(newNotify, &tempNotify, sizeof(PGnotify));
|
strncpy(newNotify->relname, conn->workBuffer.data, NAMEDATALEN);
|
||||||
|
newNotify->be_pid = be_pid;
|
||||||
DLAddTail(conn->notifyList, DLNewElem(newNotify));
|
DLAddTail(conn->notifyList, DLNewElem(newNotify));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -1342,8 +1427,8 @@ PQendcopy(PGconn *conn)
|
|||||||
if (conn->asyncStatus != PGASYNC_COPY_IN &&
|
if (conn->asyncStatus != PGASYNC_COPY_IN &&
|
||||||
conn->asyncStatus != PGASYNC_COPY_OUT)
|
conn->asyncStatus != PGASYNC_COPY_OUT)
|
||||||
{
|
{
|
||||||
sprintf(conn->errorMessage,
|
printfPQExpBuffer(&conn->errorMessage,
|
||||||
"PQendcopy() -- I don't think there's a copy in progress.");
|
"PQendcopy() -- I don't think there's a copy in progress.\n");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1351,7 +1436,7 @@ PQendcopy(PGconn *conn)
|
|||||||
|
|
||||||
/* Return to active duty */
|
/* Return to active duty */
|
||||||
conn->asyncStatus = PGASYNC_BUSY;
|
conn->asyncStatus = PGASYNC_BUSY;
|
||||||
conn->errorMessage[0] = '\0';
|
resetPQExpBuffer(&conn->errorMessage);
|
||||||
|
|
||||||
/* Wait for the completion response */
|
/* Wait for the completion response */
|
||||||
result = PQgetResult(conn);
|
result = PQgetResult(conn);
|
||||||
@ -1370,8 +1455,8 @@ PQendcopy(PGconn *conn)
|
|||||||
*/
|
*/
|
||||||
PQclear(result);
|
PQclear(result);
|
||||||
|
|
||||||
if (conn->errorMessage[0])
|
if (conn->errorMessage.len > 0)
|
||||||
DONOTICE(conn, conn->errorMessage);
|
DONOTICE(conn, conn->errorMessage.data);
|
||||||
|
|
||||||
DONOTICE(conn, "PQendcopy: resetting connection\n");
|
DONOTICE(conn, "PQendcopy: resetting connection\n");
|
||||||
|
|
||||||
@ -1423,15 +1508,17 @@ PQfn(PGconn *conn,
|
|||||||
if (!conn)
|
if (!conn)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
if (conn->sock < 0 || conn->asyncStatus != PGASYNC_IDLE)
|
/* clear the error string */
|
||||||
|
resetPQExpBuffer(&conn->errorMessage);
|
||||||
|
|
||||||
|
if (conn->sock < 0 || conn->asyncStatus != PGASYNC_IDLE ||
|
||||||
|
conn->result != NULL)
|
||||||
{
|
{
|
||||||
sprintf(conn->errorMessage, "PQfn() -- connection in wrong state\n");
|
printfPQExpBuffer(&conn->errorMessage,
|
||||||
|
"PQfn() -- connection in wrong state\n");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* clear the error string */
|
|
||||||
conn->errorMessage[0] = '\0';
|
|
||||||
|
|
||||||
if (pqPuts("F ", conn) || /* function */
|
if (pqPuts("F ", conn) || /* function */
|
||||||
pqPutInt(fnid, 4, conn) || /* function id */
|
pqPutInt(fnid, 4, conn) || /* function id */
|
||||||
pqPutInt(nargs, 4, conn)) /* # of args */
|
pqPutInt(nargs, 4, conn)) /* # of args */
|
||||||
@ -1529,15 +1616,19 @@ PQfn(PGconn *conn,
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* The backend violates the protocol. */
|
/* The backend violates the protocol. */
|
||||||
sprintf(conn->errorMessage,
|
printfPQExpBuffer(&conn->errorMessage,
|
||||||
"FATAL: PQfn: protocol error: id=%x\n", id);
|
"FATAL: PQfn: protocol error: id=0x%x\n",
|
||||||
|
id);
|
||||||
|
saveErrorResult(conn);
|
||||||
conn->inStart = conn->inCursor;
|
conn->inStart = conn->inCursor;
|
||||||
return PQmakeEmptyPGresult(conn, PGRES_FATAL_ERROR);
|
return prepareAsyncResult(conn);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'E': /* error return */
|
case 'E': /* error return */
|
||||||
if (pqGets(conn->errorMessage, ERROR_MSG_LENGTH, conn))
|
if (pqGets(&conn->errorMessage, conn))
|
||||||
continue;
|
continue;
|
||||||
|
/* build an error result holding the error message */
|
||||||
|
saveErrorResult(conn);
|
||||||
status = PGRES_FATAL_ERROR;
|
status = PGRES_FATAL_ERROR;
|
||||||
break;
|
break;
|
||||||
case 'A': /* notify message */
|
case 'A': /* notify message */
|
||||||
@ -1553,21 +1644,30 @@ PQfn(PGconn *conn,
|
|||||||
case 'Z': /* backend is ready for new query */
|
case 'Z': /* backend is ready for new query */
|
||||||
/* consume the message and exit */
|
/* consume the message and exit */
|
||||||
conn->inStart = conn->inCursor;
|
conn->inStart = conn->inCursor;
|
||||||
|
/* if we saved a result object (probably an error), use it */
|
||||||
|
if (conn->result)
|
||||||
|
return prepareAsyncResult(conn);
|
||||||
return PQmakeEmptyPGresult(conn, status);
|
return PQmakeEmptyPGresult(conn, status);
|
||||||
default:
|
default:
|
||||||
/* The backend violates the protocol. */
|
/* The backend violates the protocol. */
|
||||||
sprintf(conn->errorMessage,
|
printfPQExpBuffer(&conn->errorMessage,
|
||||||
"FATAL: PQfn: protocol error: id=%x\n", id);
|
"FATAL: PQfn: protocol error: id=0x%x\n",
|
||||||
|
id);
|
||||||
|
saveErrorResult(conn);
|
||||||
conn->inStart = conn->inCursor;
|
conn->inStart = conn->inCursor;
|
||||||
return PQmakeEmptyPGresult(conn, PGRES_FATAL_ERROR);
|
return prepareAsyncResult(conn);
|
||||||
}
|
}
|
||||||
/* Completed this message, keep going */
|
/* Completed this message, keep going */
|
||||||
conn->inStart = conn->inCursor;
|
conn->inStart = conn->inCursor;
|
||||||
needInput = false;
|
needInput = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* we fall out of the loop only upon failing to read data */
|
/* We fall out of the loop only upon failing to read data.
|
||||||
return PQmakeEmptyPGresult(conn, PGRES_FATAL_ERROR);
|
* conn->errorMessage has been set by pqWait or pqReadData.
|
||||||
|
* We want to append it to any already-received error message.
|
||||||
|
*/
|
||||||
|
saveErrorResult(conn);
|
||||||
|
return prepareAsyncResult(conn);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1630,16 +1730,18 @@ PQbinaryTuples(PGresult *res)
|
|||||||
static int
|
static int
|
||||||
check_field_number(const char *routineName, PGresult *res, int field_num)
|
check_field_number(const char *routineName, PGresult *res, int field_num)
|
||||||
{
|
{
|
||||||
|
char noticeBuf[128];
|
||||||
|
|
||||||
if (!res)
|
if (!res)
|
||||||
return FALSE; /* no way to display error message... */
|
return FALSE; /* no way to display error message... */
|
||||||
if (field_num < 0 || field_num >= res->numAttributes)
|
if (field_num < 0 || field_num >= res->numAttributes)
|
||||||
{
|
{
|
||||||
if (res->conn)
|
if (res->conn)
|
||||||
{
|
{
|
||||||
sprintf(res->conn->errorMessage,
|
sprintf(noticeBuf,
|
||||||
"%s: ERROR! field number %d is out of range 0..%d\n",
|
"%s: ERROR! field number %d is out of range 0..%d\n",
|
||||||
routineName, field_num, res->numAttributes - 1);
|
routineName, field_num, res->numAttributes - 1);
|
||||||
DONOTICE(res->conn, res->conn->errorMessage);
|
DONOTICE(res->conn, noticeBuf);
|
||||||
}
|
}
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
@ -1650,16 +1752,18 @@ static int
|
|||||||
check_tuple_field_number(const char *routineName, PGresult *res,
|
check_tuple_field_number(const char *routineName, PGresult *res,
|
||||||
int tup_num, int field_num)
|
int tup_num, int field_num)
|
||||||
{
|
{
|
||||||
|
char noticeBuf[128];
|
||||||
|
|
||||||
if (!res)
|
if (!res)
|
||||||
return FALSE; /* no way to display error message... */
|
return FALSE; /* no way to display error message... */
|
||||||
if (tup_num < 0 || tup_num >= res->ntups)
|
if (tup_num < 0 || tup_num >= res->ntups)
|
||||||
{
|
{
|
||||||
if (res->conn)
|
if (res->conn)
|
||||||
{
|
{
|
||||||
sprintf(res->conn->errorMessage,
|
sprintf(noticeBuf,
|
||||||
"%s: ERROR! tuple number %d is out of range 0..%d\n",
|
"%s: ERROR! tuple number %d is out of range 0..%d\n",
|
||||||
routineName, tup_num, res->ntups - 1);
|
routineName, tup_num, res->ntups - 1);
|
||||||
DONOTICE(res->conn, res->conn->errorMessage);
|
DONOTICE(res->conn, noticeBuf);
|
||||||
}
|
}
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
@ -1667,10 +1771,10 @@ check_tuple_field_number(const char *routineName, PGresult *res,
|
|||||||
{
|
{
|
||||||
if (res->conn)
|
if (res->conn)
|
||||||
{
|
{
|
||||||
sprintf(res->conn->errorMessage,
|
sprintf(noticeBuf,
|
||||||
"%s: ERROR! field number %d is out of range 0..%d\n",
|
"%s: ERROR! field number %d is out of range 0..%d\n",
|
||||||
routineName, field_num, res->numAttributes - 1);
|
routineName, field_num, res->numAttributes - 1);
|
||||||
DONOTICE(res->conn, res->conn->errorMessage);
|
DONOTICE(res->conn, noticeBuf);
|
||||||
}
|
}
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
@ -1830,6 +1934,8 @@ PQoidStatus(PGresult *res)
|
|||||||
const char *
|
const char *
|
||||||
PQcmdTuples(PGresult *res)
|
PQcmdTuples(PGresult *res)
|
||||||
{
|
{
|
||||||
|
char noticeBuf[128];
|
||||||
|
|
||||||
if (!res)
|
if (!res)
|
||||||
return "";
|
return "";
|
||||||
|
|
||||||
@ -1843,10 +1949,10 @@ PQcmdTuples(PGresult *res)
|
|||||||
{
|
{
|
||||||
if (res->conn)
|
if (res->conn)
|
||||||
{
|
{
|
||||||
sprintf(res->conn->errorMessage,
|
sprintf(noticeBuf,
|
||||||
"PQcmdTuples (%s) -- bad input from server\n",
|
"PQcmdTuples (%s) -- bad input from server\n",
|
||||||
res->cmdStatus);
|
res->cmdStatus);
|
||||||
DONOTICE(res->conn, res->conn->errorMessage);
|
DONOTICE(res->conn, noticeBuf);
|
||||||
}
|
}
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
@ -1859,9 +1965,9 @@ PQcmdTuples(PGresult *res)
|
|||||||
{
|
{
|
||||||
if (res->conn)
|
if (res->conn)
|
||||||
{
|
{
|
||||||
sprintf(res->conn->errorMessage,
|
sprintf(noticeBuf,
|
||||||
"PQcmdTuples (INSERT) -- there's no # of tuples\n");
|
"PQcmdTuples (INSERT) -- there's no # of tuples\n");
|
||||||
DONOTICE(res->conn, res->conn->errorMessage);
|
DONOTICE(res->conn, noticeBuf);
|
||||||
}
|
}
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* 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
|
#endif
|
||||||
if (fd < 0)
|
if (fd < 0)
|
||||||
{ /* error */
|
{ /* error */
|
||||||
sprintf(conn->errorMessage,
|
printfPQExpBuffer(&conn->errorMessage,
|
||||||
"lo_import: can't open unix file\"%s\"\n", filename);
|
"lo_import: can't open unix file\"%s\"\n",
|
||||||
|
filename);
|
||||||
return InvalidOid;
|
return InvalidOid;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -408,16 +409,18 @@ lo_import(PGconn *conn, char *filename)
|
|||||||
lobjOid = lo_creat(conn, INV_READ | INV_WRITE);
|
lobjOid = lo_creat(conn, INV_READ | INV_WRITE);
|
||||||
if (lobjOid == InvalidOid)
|
if (lobjOid == InvalidOid)
|
||||||
{
|
{
|
||||||
sprintf(conn->errorMessage,
|
printfPQExpBuffer(&conn->errorMessage,
|
||||||
"lo_import: can't create inv object for \"%s\"", filename);
|
"lo_import: can't create inv object for \"%s\"",
|
||||||
|
filename);
|
||||||
return InvalidOid;
|
return InvalidOid;
|
||||||
}
|
}
|
||||||
|
|
||||||
lobj = lo_open(conn, lobjOid, INV_WRITE);
|
lobj = lo_open(conn, lobjOid, INV_WRITE);
|
||||||
if (lobj == -1)
|
if (lobj == -1)
|
||||||
{
|
{
|
||||||
sprintf(conn->errorMessage,
|
printfPQExpBuffer(&conn->errorMessage,
|
||||||
"lo_import: could not open inv object oid %u", lobjOid);
|
"lo_import: could not open inv object oid %u",
|
||||||
|
lobjOid);
|
||||||
return InvalidOid;
|
return InvalidOid;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -429,8 +432,9 @@ lo_import(PGconn *conn, char *filename)
|
|||||||
tmp = lo_write(conn, lobj, buf, nbytes);
|
tmp = lo_write(conn, lobj, buf, nbytes);
|
||||||
if (tmp < nbytes)
|
if (tmp < nbytes)
|
||||||
{
|
{
|
||||||
sprintf(conn->errorMessage,
|
printfPQExpBuffer(&conn->errorMessage,
|
||||||
"lo_import: error while reading \"%s\"", filename);
|
"lo_import: error while reading \"%s\"",
|
||||||
|
filename);
|
||||||
return InvalidOid;
|
return InvalidOid;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -461,8 +465,8 @@ lo_export(PGconn *conn, Oid lobjId, char *filename)
|
|||||||
lobj = lo_open(conn, lobjId, INV_READ);
|
lobj = lo_open(conn, lobjId, INV_READ);
|
||||||
if (lobj == -1)
|
if (lobj == -1)
|
||||||
{
|
{
|
||||||
sprintf(conn->errorMessage,
|
printfPQExpBuffer(&conn->errorMessage,
|
||||||
"lo_export: can't open inv object %u", lobjId);
|
"lo_export: can't open inv object %u", lobjId);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -476,8 +480,9 @@ lo_export(PGconn *conn, Oid lobjId, char *filename)
|
|||||||
#endif
|
#endif
|
||||||
if (fd < 0)
|
if (fd < 0)
|
||||||
{ /* error */
|
{ /* error */
|
||||||
sprintf(conn->errorMessage,
|
printfPQExpBuffer(&conn->errorMessage,
|
||||||
"lo_export: can't open unix file\"%s\"", filename);
|
"lo_export: can't open unix file\"%s\"",
|
||||||
|
filename);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -489,9 +494,9 @@ lo_export(PGconn *conn, Oid lobjId, char *filename)
|
|||||||
tmp = write(fd, buf, nbytes);
|
tmp = write(fd, buf, nbytes);
|
||||||
if (tmp < nbytes)
|
if (tmp < nbytes)
|
||||||
{
|
{
|
||||||
sprintf(conn->errorMessage,
|
printfPQExpBuffer(&conn->errorMessage,
|
||||||
"lo_export: error while writing \"%s\"",
|
"lo_export: error while writing \"%s\"",
|
||||||
filename);
|
filename);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -527,8 +532,8 @@ lo_initialize(PGconn *conn)
|
|||||||
lobjfuncs = (PGlobjfuncs *) malloc(sizeof(PGlobjfuncs));
|
lobjfuncs = (PGlobjfuncs *) malloc(sizeof(PGlobjfuncs));
|
||||||
if (lobjfuncs == (PGlobjfuncs *) NULL)
|
if (lobjfuncs == (PGlobjfuncs *) NULL)
|
||||||
{
|
{
|
||||||
strcpy(conn->errorMessage,
|
printfPQExpBuffer(&conn->errorMessage,
|
||||||
"FATAL: malloc() failed in lo_initialize()\n");
|
"FATAL: malloc() failed in lo_initialize()\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
MemSet((char *) lobjfuncs, 0, sizeof(PGlobjfuncs));
|
MemSet((char *) lobjfuncs, 0, sizeof(PGlobjfuncs));
|
||||||
@ -556,8 +561,8 @@ lo_initialize(PGconn *conn)
|
|||||||
{
|
{
|
||||||
free(lobjfuncs);
|
free(lobjfuncs);
|
||||||
PQclear(res);
|
PQclear(res);
|
||||||
strcpy(conn->errorMessage,
|
printfPQExpBuffer(&conn->errorMessage,
|
||||||
"ERROR: SELECT didn't return data in lo_initialize()\n");
|
"ERROR: SELECT didn't return data in lo_initialize()\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -596,57 +601,57 @@ lo_initialize(PGconn *conn)
|
|||||||
*/
|
*/
|
||||||
if (lobjfuncs->fn_lo_open == 0)
|
if (lobjfuncs->fn_lo_open == 0)
|
||||||
{
|
{
|
||||||
strcpy(conn->errorMessage,
|
printfPQExpBuffer(&conn->errorMessage,
|
||||||
"ERROR: Cannot determine OID for function lo_open\n");
|
"ERROR: Cannot determine OID for function lo_open\n");
|
||||||
free(lobjfuncs);
|
free(lobjfuncs);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (lobjfuncs->fn_lo_close == 0)
|
if (lobjfuncs->fn_lo_close == 0)
|
||||||
{
|
{
|
||||||
strcpy(conn->errorMessage,
|
printfPQExpBuffer(&conn->errorMessage,
|
||||||
"ERROR: Cannot determine OID for function lo_close\n");
|
"ERROR: Cannot determine OID for function lo_close\n");
|
||||||
free(lobjfuncs);
|
free(lobjfuncs);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (lobjfuncs->fn_lo_creat == 0)
|
if (lobjfuncs->fn_lo_creat == 0)
|
||||||
{
|
{
|
||||||
strcpy(conn->errorMessage,
|
printfPQExpBuffer(&conn->errorMessage,
|
||||||
"ERROR: Cannot determine OID for function lo_creat\n");
|
"ERROR: Cannot determine OID for function lo_creat\n");
|
||||||
free(lobjfuncs);
|
free(lobjfuncs);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (lobjfuncs->fn_lo_unlink == 0)
|
if (lobjfuncs->fn_lo_unlink == 0)
|
||||||
{
|
{
|
||||||
strcpy(conn->errorMessage,
|
printfPQExpBuffer(&conn->errorMessage,
|
||||||
"ERROR: Cannot determine OID for function lo_unlink\n");
|
"ERROR: Cannot determine OID for function lo_unlink\n");
|
||||||
free(lobjfuncs);
|
free(lobjfuncs);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (lobjfuncs->fn_lo_lseek == 0)
|
if (lobjfuncs->fn_lo_lseek == 0)
|
||||||
{
|
{
|
||||||
strcpy(conn->errorMessage,
|
printfPQExpBuffer(&conn->errorMessage,
|
||||||
"ERROR: Cannot determine OID for function lo_lseek\n");
|
"ERROR: Cannot determine OID for function lo_lseek\n");
|
||||||
free(lobjfuncs);
|
free(lobjfuncs);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (lobjfuncs->fn_lo_tell == 0)
|
if (lobjfuncs->fn_lo_tell == 0)
|
||||||
{
|
{
|
||||||
strcpy(conn->errorMessage,
|
printfPQExpBuffer(&conn->errorMessage,
|
||||||
"ERROR: Cannot determine OID for function lo_tell\n");
|
"ERROR: Cannot determine OID for function lo_tell\n");
|
||||||
free(lobjfuncs);
|
free(lobjfuncs);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (lobjfuncs->fn_lo_read == 0)
|
if (lobjfuncs->fn_lo_read == 0)
|
||||||
{
|
{
|
||||||
strcpy(conn->errorMessage,
|
printfPQExpBuffer(&conn->errorMessage,
|
||||||
"ERROR: Cannot determine OID for function loread\n");
|
"ERROR: Cannot determine OID for function loread\n");
|
||||||
free(lobjfuncs);
|
free(lobjfuncs);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (lobjfuncs->fn_lo_write == 0)
|
if (lobjfuncs->fn_lo_write == 0)
|
||||||
{
|
{
|
||||||
strcpy(conn->errorMessage,
|
printfPQExpBuffer(&conn->errorMessage,
|
||||||
"ERROR: Cannot determine OID for function lowrite\n");
|
"ERROR: Cannot determine OID for function lowrite\n");
|
||||||
free(lobjfuncs);
|
free(lobjfuncs);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -24,7 +24,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* 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:
|
/* pqGets:
|
||||||
get a null-terminated string from the connection,
|
get a null-terminated string from the connection,
|
||||||
and store it in a buffer of size maxlen bytes.
|
and store it in an expansible PQExpBuffer.
|
||||||
If the incoming string is >= maxlen bytes, all of it is read,
|
If we run out of memory, all of the string is still read,
|
||||||
but the excess characters are silently discarded.
|
but the excess characters are silently discarded.
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
pqGets(char *s, int maxlen, PGconn *conn)
|
pqGets(PQExpBuffer buf, PGconn *conn)
|
||||||
{
|
{
|
||||||
/* Copy conn data to locals for faster search loop */
|
/* Copy conn data to locals for faster search loop */
|
||||||
char *inBuffer = conn->inBuffer;
|
char *inBuffer = conn->inBuffer;
|
||||||
@ -126,18 +126,15 @@ pqGets(char *s, int maxlen, PGconn *conn)
|
|||||||
return EOF;
|
return EOF;
|
||||||
|
|
||||||
slen = inCursor - conn->inCursor;
|
slen = inCursor - conn->inCursor;
|
||||||
if (slen < maxlen)
|
|
||||||
strcpy(s, inBuffer + conn->inCursor);
|
resetPQExpBuffer(buf);
|
||||||
else
|
appendBinaryPQExpBuffer(buf, inBuffer + conn->inCursor, slen);
|
||||||
{
|
|
||||||
strncpy(s, inBuffer + conn->inCursor, maxlen - 1);
|
|
||||||
s[maxlen - 1] = '\0';
|
|
||||||
}
|
|
||||||
|
|
||||||
conn->inCursor = ++inCursor;
|
conn->inCursor = ++inCursor;
|
||||||
|
|
||||||
if (conn->Pfdebug)
|
if (conn->Pfdebug)
|
||||||
fprintf(conn->Pfdebug, "From backend> \"%s\"\n", s);
|
fprintf(conn->Pfdebug, "From backend> \"%s\"\n",
|
||||||
|
buf->data);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -202,6 +199,7 @@ pqGetInt(int *result, int bytes, PGconn *conn)
|
|||||||
{
|
{
|
||||||
uint16 tmp2;
|
uint16 tmp2;
|
||||||
uint32 tmp4;
|
uint32 tmp4;
|
||||||
|
char noticeBuf[64];
|
||||||
|
|
||||||
switch (bytes)
|
switch (bytes)
|
||||||
{
|
{
|
||||||
@ -220,9 +218,9 @@ pqGetInt(int *result, int bytes, PGconn *conn)
|
|||||||
*result = (int) ntohl(tmp4);
|
*result = (int) ntohl(tmp4);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
sprintf(conn->errorMessage,
|
sprintf(noticeBuf,
|
||||||
"pqGetInt: int size %d not supported\n", bytes);
|
"pqGetInt: int size %d not supported\n", bytes);
|
||||||
DONOTICE(conn, conn->errorMessage);
|
DONOTICE(conn, noticeBuf);
|
||||||
return EOF;
|
return EOF;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -242,6 +240,7 @@ pqPutInt(int value, int bytes, PGconn *conn)
|
|||||||
{
|
{
|
||||||
uint16 tmp2;
|
uint16 tmp2;
|
||||||
uint32 tmp4;
|
uint32 tmp4;
|
||||||
|
char noticeBuf[64];
|
||||||
|
|
||||||
switch (bytes)
|
switch (bytes)
|
||||||
{
|
{
|
||||||
@ -256,9 +255,9 @@ pqPutInt(int value, int bytes, PGconn *conn)
|
|||||||
return EOF;
|
return EOF;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
sprintf(conn->errorMessage,
|
sprintf(noticeBuf,
|
||||||
"pqPutInt: int size %d not supported\n", bytes);
|
"pqPutInt: int size %d not supported\n", bytes);
|
||||||
DONOTICE(conn, conn->errorMessage);
|
DONOTICE(conn, noticeBuf);
|
||||||
return EOF;
|
return EOF;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -287,9 +286,9 @@ pqReadReady(PGconn *conn)
|
|||||||
if (select(conn->sock + 1, &input_mask, (fd_set *) NULL, (fd_set *) NULL,
|
if (select(conn->sock + 1, &input_mask, (fd_set *) NULL, (fd_set *) NULL,
|
||||||
&timeout) < 0)
|
&timeout) < 0)
|
||||||
{
|
{
|
||||||
sprintf(conn->errorMessage,
|
printfPQExpBuffer(&conn->errorMessage,
|
||||||
"pqReadReady() -- select() failed: errno=%d\n%s\n",
|
"pqReadReady() -- select() failed: errno=%d\n%s\n",
|
||||||
errno, strerror(errno));
|
errno, strerror(errno));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return FD_ISSET(conn->sock, &input_mask);
|
return FD_ISSET(conn->sock, &input_mask);
|
||||||
@ -312,7 +311,8 @@ pqReadData(PGconn *conn)
|
|||||||
|
|
||||||
if (conn->sock < 0)
|
if (conn->sock < 0)
|
||||||
{
|
{
|
||||||
strcpy(conn->errorMessage, "pqReadData() -- connection not open\n");
|
printfPQExpBuffer(&conn->errorMessage,
|
||||||
|
"pqReadData() -- connection not open\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -333,9 +333,10 @@ pqReadData(PGconn *conn)
|
|||||||
* enlarge the buffer in case a single message exceeds the initial
|
* enlarge the buffer in case a single message exceeds the initial
|
||||||
* buffer size. We enlarge before filling the buffer entirely so as
|
* buffer size. We enlarge before filling the buffer entirely so as
|
||||||
* to avoid asking the kernel for a partial packet. The magic constant
|
* 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;
|
int newSize = conn->inBufSize * 2;
|
||||||
char *newBuf = (char *) realloc(conn->inBuffer, newSize);
|
char *newBuf = (char *) realloc(conn->inBuffer, newSize);
|
||||||
@ -369,9 +370,9 @@ tryAgain:
|
|||||||
if (errno == ECONNRESET)
|
if (errno == ECONNRESET)
|
||||||
goto definitelyFailed;
|
goto definitelyFailed;
|
||||||
#endif
|
#endif
|
||||||
sprintf(conn->errorMessage,
|
printfPQExpBuffer(&conn->errorMessage,
|
||||||
"pqReadData() -- read() failed: errno=%d\n%s\n",
|
"pqReadData() -- read() failed: errno=%d\n%s\n",
|
||||||
errno, strerror(errno));
|
errno, strerror(errno));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (nread > 0)
|
if (nread > 0)
|
||||||
@ -417,9 +418,9 @@ tryAgain2:
|
|||||||
if (errno == ECONNRESET)
|
if (errno == ECONNRESET)
|
||||||
goto definitelyFailed;
|
goto definitelyFailed;
|
||||||
#endif
|
#endif
|
||||||
sprintf(conn->errorMessage,
|
printfPQExpBuffer(&conn->errorMessage,
|
||||||
"pqReadData() -- read() failed: errno=%d\n%s\n",
|
"pqReadData() -- read() failed: errno=%d\n%s\n",
|
||||||
errno, strerror(errno));
|
errno, strerror(errno));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (nread > 0)
|
if (nread > 0)
|
||||||
@ -433,7 +434,7 @@ tryAgain2:
|
|||||||
* This means the connection has been closed. Cope.
|
* This means the connection has been closed. Cope.
|
||||||
*/
|
*/
|
||||||
definitelyFailed:
|
definitelyFailed:
|
||||||
sprintf(conn->errorMessage,
|
printfPQExpBuffer(&conn->errorMessage,
|
||||||
"pqReadData() -- backend closed the channel unexpectedly.\n"
|
"pqReadData() -- backend closed the channel unexpectedly.\n"
|
||||||
"\tThis probably means the backend terminated abnormally\n"
|
"\tThis probably means the backend terminated abnormally\n"
|
||||||
"\tbefore or while processing the request.\n");
|
"\tbefore or while processing the request.\n");
|
||||||
@ -459,7 +460,8 @@ pqFlush(PGconn *conn)
|
|||||||
|
|
||||||
if (conn->sock < 0)
|
if (conn->sock < 0)
|
||||||
{
|
{
|
||||||
strcpy(conn->errorMessage, "pqFlush() -- connection not open\n");
|
printfPQExpBuffer(&conn->errorMessage,
|
||||||
|
"pqFlush() -- connection not open\n");
|
||||||
return EOF;
|
return EOF;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -499,7 +501,7 @@ pqFlush(PGconn *conn)
|
|||||||
#ifdef ECONNRESET
|
#ifdef ECONNRESET
|
||||||
case ECONNRESET:
|
case ECONNRESET:
|
||||||
#endif
|
#endif
|
||||||
sprintf(conn->errorMessage,
|
printfPQExpBuffer(&conn->errorMessage,
|
||||||
"pqFlush() -- backend closed the channel unexpectedly.\n"
|
"pqFlush() -- backend closed the channel unexpectedly.\n"
|
||||||
"\tThis probably means the backend terminated abnormally"
|
"\tThis probably means the backend terminated abnormally"
|
||||||
" before or while processing the request.\n");
|
" before or while processing the request.\n");
|
||||||
@ -513,8 +515,8 @@ pqFlush(PGconn *conn)
|
|||||||
return EOF;
|
return EOF;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
sprintf(conn->errorMessage,
|
printfPQExpBuffer(&conn->errorMessage,
|
||||||
"pqFlush() -- couldn't send data: errno=%d\n%s\n",
|
"pqFlush() -- couldn't send data: errno=%d\n%s\n",
|
||||||
errno, strerror(errno));
|
errno, strerror(errno));
|
||||||
/* We don't assume it's a fatal error... */
|
/* We don't assume it's a fatal error... */
|
||||||
return EOF;
|
return EOF;
|
||||||
@ -552,7 +554,8 @@ pqWait(int forRead, int forWrite, PGconn *conn)
|
|||||||
|
|
||||||
if (conn->sock < 0)
|
if (conn->sock < 0)
|
||||||
{
|
{
|
||||||
strcpy(conn->errorMessage, "pqWait() -- connection not open\n");
|
printfPQExpBuffer(&conn->errorMessage,
|
||||||
|
"pqWait() -- connection not open\n");
|
||||||
return EOF;
|
return EOF;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -570,9 +573,9 @@ pqWait(int forRead, int forWrite, PGconn *conn)
|
|||||||
{
|
{
|
||||||
if (errno == EINTR)
|
if (errno == EINTR)
|
||||||
continue;
|
continue;
|
||||||
sprintf(conn->errorMessage,
|
printfPQExpBuffer(&conn->errorMessage,
|
||||||
"pqWait() -- select() failed: errno=%d\n%s\n",
|
"pqWait() -- select() failed: errno=%d\n%s\n",
|
||||||
errno, strerror(errno));
|
errno, strerror(errno));
|
||||||
return EOF;
|
return EOF;
|
||||||
}
|
}
|
||||||
/* On nonerror return, assume we're done */
|
/* On nonerror return, assume we're done */
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
* didn't really belong there.
|
* didn't really belong there.
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* 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,
|
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,
|
char **fields,
|
||||||
const int nFields, char **fieldNames,
|
const int nFields, char **fieldNames,
|
||||||
unsigned char *fieldNotNum, int *fieldMax,
|
unsigned char *fieldNotNum, int *fieldMax,
|
||||||
@ -103,7 +103,6 @@ PQprint(FILE *fout,
|
|||||||
int usePipe = 0;
|
int usePipe = 0;
|
||||||
pqsigfunc oldsigpipehandler = NULL;
|
pqsigfunc oldsigpipehandler = NULL;
|
||||||
char *pagerenv;
|
char *pagerenv;
|
||||||
char buf[MAX_QUERY_SIZE + 1];
|
|
||||||
|
|
||||||
nTups = PQntuples(res);
|
nTups = PQntuples(res);
|
||||||
if (!(fieldNames = (char **) calloc(nFields, sizeof(char *))))
|
if (!(fieldNames = (char **) calloc(nFields, sizeof(char *))))
|
||||||
@ -254,7 +253,7 @@ PQprint(FILE *fout,
|
|||||||
fprintf(fout, "-- RECORD %d --\n", i);
|
fprintf(fout, "-- RECORD %d --\n", i);
|
||||||
}
|
}
|
||||||
for (j = 0; j < nFields; j++)
|
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,
|
fieldNames, fieldNotNum,
|
||||||
fieldMax, fieldMaxLen, fout);
|
fieldMax, fieldMaxLen, fout);
|
||||||
if (po->html3 && po->expanded)
|
if (po->html3 && po->expanded)
|
||||||
@ -332,7 +331,7 @@ PQdisplayTuples(PGresult *res,
|
|||||||
j;
|
j;
|
||||||
int nFields;
|
int nFields;
|
||||||
int nTuples;
|
int nTuples;
|
||||||
int fLength[MAX_FIELDS];
|
int *fLength = NULL;
|
||||||
|
|
||||||
if (fieldSep == NULL)
|
if (fieldSep == NULL)
|
||||||
fieldSep = DEFAULT_FIELD_SEP;
|
fieldSep = DEFAULT_FIELD_SEP;
|
||||||
@ -344,19 +343,19 @@ PQdisplayTuples(PGresult *res,
|
|||||||
if (fp == NULL)
|
if (fp == NULL)
|
||||||
fp = stdout;
|
fp = stdout;
|
||||||
|
|
||||||
/* Zero the initial field lengths */
|
/* Figure the field lengths to align to */
|
||||||
for (j = 0; j < nFields; j++)
|
|
||||||
fLength[j] = strlen(PQfname(res, j));
|
|
||||||
/* Find the max length of each field in the result */
|
|
||||||
/* will be somewhat time consuming for very large results */
|
/* will be somewhat time consuming for very large results */
|
||||||
if (fillAlign)
|
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])
|
int flen = PQgetlength(res, i, j);
|
||||||
fLength[j] = PQgetlength(res, i, j);
|
if (flen > fLength[j])
|
||||||
|
fLength[j] = flen;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -401,6 +400,9 @@ PQdisplayTuples(PGresult *res,
|
|||||||
(PQntuples(res) == 1) ? "" : "s");
|
(PQntuples(res) == 1) ? "" : "s");
|
||||||
|
|
||||||
fflush(fp);
|
fflush(fp);
|
||||||
|
|
||||||
|
if (fLength)
|
||||||
|
free(fLength);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -522,7 +524,7 @@ PQmblen(unsigned char *s)
|
|||||||
|
|
||||||
static void
|
static void
|
||||||
do_field(PQprintOpt *po, PGresult *res,
|
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,
|
char **fields,
|
||||||
const int nFields, char **fieldNames,
|
const int nFields, char **fieldNames,
|
||||||
unsigned char *fieldNotNum, int *fieldMax,
|
unsigned char *fieldNotNum, int *fieldMax,
|
||||||
@ -530,8 +532,7 @@ do_field(PQprintOpt *po, PGresult *res,
|
|||||||
{
|
{
|
||||||
|
|
||||||
char *pval,
|
char *pval,
|
||||||
*p,
|
*p;
|
||||||
*o;
|
|
||||||
int plen;
|
int plen;
|
||||||
bool skipit;
|
bool skipit;
|
||||||
|
|
||||||
@ -553,62 +554,49 @@ do_field(PQprintOpt *po, PGresult *res,
|
|||||||
|
|
||||||
if (!skipit)
|
if (!skipit)
|
||||||
{
|
{
|
||||||
char ch = 0;
|
if (po->align && ! fieldNotNum[j])
|
||||||
|
{
|
||||||
|
/* Detect whether field contains non-numeric data */
|
||||||
|
char ch = '0';
|
||||||
|
|
||||||
#ifdef MULTIBYTE
|
#ifdef MULTIBYTE
|
||||||
int len;
|
for (p = pval; *p; p += PQmblen(p))
|
||||||
|
|
||||||
for (p = pval, o = buf; *p;
|
|
||||||
len = PQmblen(p), memcpy(o, p, len),
|
|
||||||
o += len, p += len)
|
|
||||||
#else
|
#else
|
||||||
for (p = pval, o = buf; *p; *(o++) = *(p++))
|
for (p = pval; *p; p++)
|
||||||
#endif
|
#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
|
* Above loop will believe E in first column is numeric; also, we
|
||||||
* that the print functions ought not insert backslashes. If
|
* insist on a digit in the last column for a numeric. This test
|
||||||
* you like them, you can re-enable this next bit.
|
* is still not bulletproof but it handles most cases.
|
||||||
*/
|
*/
|
||||||
#ifdef GRATUITOUS_BACKSLASHES
|
if (*pval == 'E' || *pval == 'e' ||
|
||||||
if ((fs_len == 1 && (ch == *(po->fieldSep))) ||
|
!(ch >= '0' && ch <= '9'))
|
||||||
ch == '\\' || ch == '\n')
|
|
||||||
*(o++) = '\\';
|
|
||||||
#endif
|
|
||||||
if (po->align &&
|
|
||||||
!((ch >= '0' && ch <= '9') ||
|
|
||||||
ch == '.' ||
|
|
||||||
ch == 'E' ||
|
|
||||||
ch == 'e' ||
|
|
||||||
ch == ' ' ||
|
|
||||||
ch == '-'))
|
|
||||||
fieldNotNum[j] = 1;
|
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))
|
if (!po->expanded && (po->align || po->html3))
|
||||||
{
|
{
|
||||||
int n = strlen(buf);
|
if (plen > fieldMax[j])
|
||||||
|
fieldMax[j] = plen;
|
||||||
if (n > fieldMax[j])
|
if (!(fields[i * nFields + j] = (char *) malloc(plen + 1)))
|
||||||
fieldMax[j] = n;
|
|
||||||
if (!(fields[i * nFields + j] = (char *) malloc(n + 1)))
|
|
||||||
{
|
{
|
||||||
perror("malloc");
|
perror("malloc");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
strcpy(fields[i * nFields + j], buf);
|
strcpy(fields[i * nFields + j], pval);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -620,23 +608,26 @@ do_field(PQprintOpt *po, PGresult *res,
|
|||||||
"<td align=%s>%s</td></tr>\n",
|
"<td align=%s>%s</td></tr>\n",
|
||||||
fieldNames[j],
|
fieldNames[j],
|
||||||
fieldNotNum[j] ? "left" : "right",
|
fieldNotNum[j] ? "left" : "right",
|
||||||
buf);
|
pval);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (po->align)
|
if (po->align)
|
||||||
fprintf(fout,
|
fprintf(fout,
|
||||||
"%-*s%s %s\n",
|
"%-*s%s %s\n",
|
||||||
fieldMaxLen - fs_len, fieldNames[j], po->fieldSep,
|
fieldMaxLen - fs_len, fieldNames[j],
|
||||||
buf);
|
po->fieldSep,
|
||||||
|
pval);
|
||||||
else
|
else
|
||||||
fprintf(fout, "%s%s%s\n", fieldNames[j], po->fieldSep, buf);
|
fprintf(fout,
|
||||||
|
"%s%s%s\n",
|
||||||
|
fieldNames[j], po->fieldSep, pval);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (!po->html3)
|
if (!po->html3)
|
||||||
{
|
{
|
||||||
fputs(buf, fout);
|
fputs(pval, fout);
|
||||||
efield:
|
efield:
|
||||||
if ((j + 1) < nFields)
|
if ((j + 1) < nFields)
|
||||||
fputs(po->fieldSep, fout);
|
fputs(po->fieldSep, fout);
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
*
|
*
|
||||||
* Copyright (c) 1994, Regents of the University of California
|
* 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. */
|
/* 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 "libpq/pqcomm.h"
|
||||||
#include "lib/dllist.h"
|
#include "lib/dllist.h"
|
||||||
|
/* include stuff found in fe only */
|
||||||
|
#include "pqexpbuffer.h"
|
||||||
|
|
||||||
|
|
||||||
/* libpq supports this version of the frontend/backend protocol.
|
/* libpq supports this version of the frontend/backend protocol.
|
||||||
*
|
*
|
||||||
@ -45,8 +45,6 @@
|
|||||||
* POSTGRES backend dependent Constants.
|
* 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
|
#define CMDSTATUS_LEN 40
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -115,7 +113,7 @@ struct pg_result
|
|||||||
int tupArrSize; /* size of tuples array allocated */
|
int tupArrSize; /* size of tuples array allocated */
|
||||||
ExecStatusType resultStatus;
|
ExecStatusType resultStatus;
|
||||||
char cmdStatus[CMDSTATUS_LEN]; /* cmd status from the
|
char cmdStatus[CMDSTATUS_LEN]; /* cmd status from the
|
||||||
* last insert query */
|
* last query */
|
||||||
int binary; /* binary tuple values if binary == 1,
|
int binary; /* binary tuple values if binary == 1,
|
||||||
* otherwise ASCII */
|
* otherwise ASCII */
|
||||||
PGconn *conn; /* connection we did the query on, if any */
|
PGconn *conn; /* connection we did the query on, if any */
|
||||||
@ -217,8 +215,11 @@ struct pg_conn
|
|||||||
PGresult *result; /* result being constructed */
|
PGresult *result; /* result being constructed */
|
||||||
PGresAttValue *curTuple; /* tuple currently being read */
|
PGresAttValue *curTuple; /* tuple currently being read */
|
||||||
|
|
||||||
/* Message space. Placed last for code-size reasons. */
|
/* Buffer for current error message */
|
||||||
char errorMessage[ERROR_MSG_LENGTH];
|
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.
|
* necessarily any error.
|
||||||
*/
|
*/
|
||||||
extern int pqGetc(char *result, PGconn *conn);
|
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 pqPuts(const char *s, PGconn *conn);
|
||||||
extern int pqGetnchar(char *s, int len, PGconn *conn);
|
extern int pqGetnchar(char *s, int len, PGconn *conn);
|
||||||
extern int pqPutnchar(const 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 pqFlush(PGconn *conn);
|
||||||
extern int pqWait(int forRead, int forWrite, 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 */
|
/* bits in a byte */
|
||||||
#define BYTELEN 8
|
#define BYTELEN 8
|
||||||
|
|
||||||
|
254
src/interfaces/libpq/pqexpbuffer.c
Normal file
254
src/interfaces/libpq/pqexpbuffer.c
Normal file
@ -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';
|
||||||
|
}
|
169
src/interfaces/libpq/pqexpbuffer.h
Normal file
169
src/interfaces/libpq/pqexpbuffer.h
Normal file
@ -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 */
|
@ -29,6 +29,7 @@ CLEAN :
|
|||||||
-@erase "$(INTDIR)\fe-lobj.obj"
|
-@erase "$(INTDIR)\fe-lobj.obj"
|
||||||
-@erase "$(INTDIR)\fe-misc.obj"
|
-@erase "$(INTDIR)\fe-misc.obj"
|
||||||
-@erase "$(INTDIR)\fe-print.obj"
|
-@erase "$(INTDIR)\fe-print.obj"
|
||||||
|
-@erase "$(INTDIR)\pqexpbuffer.obj"
|
||||||
-@erase "$(OUTDIR)\libpqdll.obj"
|
-@erase "$(OUTDIR)\libpqdll.obj"
|
||||||
-@erase "$(OUTDIR)\libpq.lib"
|
-@erase "$(OUTDIR)\libpq.lib"
|
||||||
-@erase "$(OUTDIR)\libpq.dll"
|
-@erase "$(OUTDIR)\libpq.dll"
|
||||||
@ -70,7 +71,8 @@ LIB32_OBJS= \
|
|||||||
"$(INTDIR)\fe-exec.obj" \
|
"$(INTDIR)\fe-exec.obj" \
|
||||||
"$(INTDIR)\fe-lobj.obj" \
|
"$(INTDIR)\fe-lobj.obj" \
|
||||||
"$(INTDIR)\fe-misc.obj" \
|
"$(INTDIR)\fe-misc.obj" \
|
||||||
"$(INTDIR)\fe-print.obj"
|
"$(INTDIR)\fe-print.obj" \
|
||||||
|
"$(INTDIR)\pqexpbuffer.obj"
|
||||||
|
|
||||||
!IFDEF MULTIBYTE
|
!IFDEF MULTIBYTE
|
||||||
LIB32_OBJS = $(LIB32_OBJS) "$(INTDIR)\common.obj" "$(INTDIR)\wchar.obj" "$(INTDIR)\conv.obj" "$(INTDIR)\big5.obj"
|
LIB32_OBJS = $(LIB32_OBJS) "$(INTDIR)\common.obj" "$(INTDIR)\wchar.obj" "$(INTDIR)\conv.obj" "$(INTDIR)\big5.obj"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user