diff --git a/doc/src/sgml/libpq.sgml b/doc/src/sgml/libpq.sgml index be92de3e70..fe15c2b1bb 100644 --- a/doc/src/sgml/libpq.sgml +++ b/doc/src/sgml/libpq.sgml @@ -1,5 +1,5 @@ @@ -581,14 +581,15 @@ typedef struct - Returns a connection options array. This may - be used to determine all possible PQconnectdb options and their + Returns a connection options array. This may be used to determine + all possible PQconnectdb options and their current default values. The return value points to an array of - PQconninfoOption structures, which ends with an entry having a null - keyword pointer. Note that the current default values - (val fields) - will depend on environment variables and other context. - Callers must treat the connection options data as read-only. + PQconninfoOption structures, which ends + with an entry having a null keyword pointer. The + null pointer is returned if memory could not be allocated. Note that + the current default values (val fields) + will depend on environment variables and other context. Callers + must treat the connection options data as read-only. @@ -1651,18 +1652,22 @@ void PQclear(PGresult *res); Constructs an empty PGresult object with the given status. -PGresult* PQmakeEmptyPGresult(PGconn *conn, ExecStatusType status); +PGresult *PQmakeEmptyPGresult(PGconn *conn, ExecStatusType status); -This is libpq's internal function to allocate and initialize an empty -PGresult object. It is exported because some applications find it -useful to generate result objects (particularly objects with error -status) themselves. If conn is not null and status indicates an error, -the current error message of the specified connection is copied into the PGresult. -Note that PQclear should eventually be called on the object, just -as with a PGresult returned by libpq itself. +This is libpq's internal function to allocate and +initialize an empty PGresult object. This +function returns NULL if memory could not be allocated. It is exported +because some applications find it useful to generate result objects +(particularly objects with error status) themselves. If +conn is not null and status +indicates an error, the current error message of the specified +connection is copied into the PGresult. Note +that PQclear should eventually be called on the +object, just as with a PGresult returned by +libpq itself. @@ -2266,15 +2271,15 @@ unsigned char *PQescapeBytea(const unsigned char *from, PQescapeBytea returns an escaped version of the from parameter binary string in memory - allocated with malloc(). This memory must be freed - using PQfreemem when the result is no longer needed. - The return string has all special characters replaced so that they - can be properly processed by the - PostgreSQL string literal parser, and - the bytea input function. A terminating zero byte is - also added. The single quotes that must surround - PostgreSQL string literals are not part - of the result string. + allocated with malloc() (a null pointer is returned if + memory could not be allocated). This memory must be freed using + PQfreemem when the result is no longer needed. The + return string has all special characters replaced so that they can + be properly processed by the PostgreSQL + string literal parser, and the bytea input function. A + terminating zero byte is also added. The single quotes that must + surround PostgreSQL string literals are + not part of the result string. diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c index 979f5cd073..13958b9ad3 100644 --- a/src/interfaces/libpq/fe-connect.c +++ b/src/interfaces/libpq/fe-connect.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/interfaces/libpq/fe-connect.c,v 1.309 2005/06/10 04:01:36 momjian Exp $ + * $PostgreSQL: pgsql/src/interfaces/libpq/fe-connect.c,v 1.310 2005/06/12 00:00:21 neilc Exp $ * *------------------------------------------------------------------------- */ @@ -368,6 +368,8 @@ connectOptions1(PGconn *conn, const char *conninfo) * * Don't put anything cute here --- intelligence should be in * connectOptions2 ... + * + * XXX: probably worth checking strdup() return value here... */ tmp = conninfo_getval(connOptions, "hostaddr"); conn->pghostaddr = tmp ? strdup(tmp) : NULL; @@ -459,7 +461,6 @@ connectOptions2(PGconn *conn) } #ifdef NOT_USED - /* * parse dbName to get all additional info in it, if any */ @@ -2167,11 +2168,9 @@ closePGconn(PGconn *conn) } /* - PQfinish: - properly close a connection to the backend - also frees the PGconn data structure so it shouldn't be re-used - after this -*/ + * PQfinish: properly close a connection to the backend. Also frees + * the PGconn data structure so it shouldn't be re-used after this. + */ void PQfinish(PGconn *conn) { @@ -2182,10 +2181,10 @@ PQfinish(PGconn *conn) } } -/* PQreset : - resets the connection to the backend - closes the existing connection and makes a new one -*/ +/* + * PQreset: resets the connection to the backend by closing the + * existing connection and creating a new one. + */ void PQreset(PGconn *conn) { @@ -2199,11 +2198,12 @@ PQreset(PGconn *conn) } -/* PQresetStart : - resets the connection to the backend - closes the existing connection and makes a new one - Returns 1 on success, 0 on failure. -*/ +/* + * PQresetStart: + * resets the connection to the backend + * closes the existing connection and makes a new one + * Returns 1 on success, 0 on failure. + */ int PQresetStart(PGconn *conn) { @@ -2218,11 +2218,11 @@ PQresetStart(PGconn *conn) } -/* PQresetPoll : - resets the connection to the backend - closes the existing connection and makes a new one -*/ - +/* + * PQresetPoll: + * resets the connection to the backend + * closes the existing connection and makes a new one + */ PostgresPollingStatusType PQresetPoll(PGconn *conn) { @@ -2514,7 +2514,7 @@ parseServiceInfo(PQconninfoOption *options, PQExpBuffer errorMessage) * location to find our config files. */ snprintf(serviceFile, MAXPGPATH, "%s/pg_service.conf", - getenv("PGSYSCONFDIR") ? getenv("PGSYSCONFDIR") : SYSCONFDIR); + getenv("PGSYSCONFDIR") ? getenv("PGSYSCONFDIR") : SYSCONFDIR); if (service != NULL) { @@ -2802,7 +2802,14 @@ conninfo_parse(const char *conninfo, PQExpBuffer errorMessage) if (option->val) free(option->val); option->val = strdup(pval); - + if (!option->val) + { + printfPQExpBuffer(errorMessage, + libpq_gettext("out of memory\n")); + PQconninfoFree(options); + free(buf); + return NULL; + } } /* Done with the modifiable input string */ @@ -2835,6 +2842,13 @@ conninfo_parse(const char *conninfo, PQExpBuffer errorMessage) if ((tmp = getenv(option->envvar)) != NULL) { option->val = strdup(tmp); + if (!option->val) + { + printfPQExpBuffer(errorMessage, + libpq_gettext("out of memory\n")); + PQconninfoFree(options); + return NULL; + } continue; } } @@ -2846,6 +2860,13 @@ conninfo_parse(const char *conninfo, PQExpBuffer errorMessage) if (option->compiled != NULL) { option->val = strdup(option->compiled); + if (!option->val) + { + printfPQExpBuffer(errorMessage, + libpq_gettext("out of memory\n")); + PQconninfoFree(options); + return NULL; + } continue; } diff --git a/src/interfaces/libpq/fe-exec.c b/src/interfaces/libpq/fe-exec.c index 1a01a4c627..64ef9cd428 100644 --- a/src/interfaces/libpq/fe-exec.c +++ b/src/interfaces/libpq/fe-exec.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/interfaces/libpq/fe-exec.c,v 1.168 2005/06/09 20:01:16 tgl Exp $ + * $PostgreSQL: pgsql/src/interfaces/libpq/fe-exec.c,v 1.169 2005/06/12 00:00:21 neilc Exp $ * *------------------------------------------------------------------------- */ @@ -134,6 +134,8 @@ PQmakeEmptyPGresult(PGconn *conn, ExecStatusType status) PGresult *result; result = (PGresult *) malloc(sizeof(PGresult)); + if (!result) + return NULL; result->ntups = 0; result->numAttributes = 0; @@ -453,7 +455,7 @@ pqPrepareAsyncResult(PGconn *conn) * a trailing newline, and should not be more than one line). */ void -pqInternalNotice(const PGNoticeHooks *hooks, const char *fmt,...) +pqInternalNotice(const PGNoticeHooks *hooks, const char *fmt, ...) { char msgBuf[1024]; va_list args; @@ -470,6 +472,8 @@ pqInternalNotice(const PGNoticeHooks *hooks, const char *fmt,...) /* Make a PGresult to pass to the notice receiver */ res = PQmakeEmptyPGresult(NULL, PGRES_NONFATAL_ERROR); + if (!res) + return; res->noticeHooks = *hooks; /* @@ -480,15 +484,19 @@ pqInternalNotice(const PGNoticeHooks *hooks, const char *fmt,...) /* XXX should provide a SQLSTATE too? */ /* - * Result text is always just the primary message + newline. + * Result text is always just the primary message + newline. If we + * can't allocate it, don't bother invoking the receiver. */ res->errMsg = (char *) pqResultAlloc(res, strlen(msgBuf) + 2, FALSE); - sprintf(res->errMsg, "%s\n", msgBuf); + if (res->errMsg) + { + sprintf(res->errMsg, "%s\n", msgBuf); - /* - * Pass to receiver, then free it. - */ - (*res->noticeHooks.noticeRec) (res->noticeHooks.noticeRecArg, res); + /* + * Pass to receiver, then free it. + */ + (*res->noticeHooks.noticeRec) (res->noticeHooks.noticeRecArg, res); + } PQclear(res); } @@ -1127,8 +1135,9 @@ PQisBusy(PGconn *conn) /* * PQgetResult - * Get the next PGresult produced by a query. - * Returns NULL if and only if no query work remains. + * Get the next PGresult produced by a query. Returns NULL if no + * query work remains or an error has occurred (e.g. out of + * memory). */ PGresult * diff --git a/src/interfaces/libpq/fe-misc.c b/src/interfaces/libpq/fe-misc.c index f3ed41423e..66ad325c52 100644 --- a/src/interfaces/libpq/fe-misc.c +++ b/src/interfaces/libpq/fe-misc.c @@ -23,7 +23,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $PostgreSQL: pgsql/src/interfaces/libpq/fe-misc.c,v 1.113 2005/02/22 04:42:20 momjian Exp $ + * $PostgreSQL: pgsql/src/interfaces/libpq/fe-misc.c,v 1.114 2005/06/12 00:00:21 neilc Exp $ * *------------------------------------------------------------------------- */ @@ -175,7 +175,8 @@ pqGetnchar(char *s, size_t len, PGconn *conn) conn->inCursor += len; if (conn->Pfdebug) - fprintf(conn->Pfdebug, libpq_gettext("From backend (%lu)> %.*s\n"), (unsigned long) len, (int) len, s); + fprintf(conn->Pfdebug, libpq_gettext("From backend (%lu)> %.*s\n"), + (unsigned long) len, (int) len, s); return 0; } diff --git a/src/interfaces/libpq/fe-print.c b/src/interfaces/libpq/fe-print.c index e6740a3d18..762383feba 100644 --- a/src/interfaces/libpq/fe-print.c +++ b/src/interfaces/libpq/fe-print.c @@ -10,7 +10,7 @@ * didn't really belong there. * * IDENTIFICATION - * $PostgreSQL: pgsql/src/interfaces/libpq/fe-print.c,v 1.59 2005/02/22 04:42:20 momjian Exp $ + * $PostgreSQL: pgsql/src/interfaces/libpq/fe-print.c,v 1.60 2005/06/12 00:00:21 neilc Exp $ * *------------------------------------------------------------------------- */ @@ -62,14 +62,11 @@ static void fill(int length, int max, char filler, FILE *fp); * details * * This function should probably be removed sometime since psql - * doesn't use it anymore. It is unclear to what extend this is used + * doesn't use it anymore. It is unclear to what extent this is used * by external clients, however. */ - void -PQprint(FILE *fout, - const PGresult *res, - const PQprintOpt *po) +PQprint(FILE *fout, const PGresult *res, const PQprintOpt *po) { int nFields; @@ -611,6 +608,12 @@ PQdisplayTuples(const PGresult *res, if (fillAlign) { fLength = (int *) malloc(nFields * sizeof(int)); + if (!fLength) + { + fprintf(stderr, libpq_gettext("out of memory\n")); + exit(1); + } + for (j = 0; j < nFields; j++) { fLength[j] = strlen(PQfname(res, j)); @@ -705,6 +708,11 @@ PQprintTuples(const PGresult *res, width = nFields * 14; tborder = malloc(width + 1); + if (!tborder) + { + fprintf(stderr, libpq_gettext("out of memory\n")); + exit(1); + } for (i = 0; i <= width; i++) tborder[i] = '-'; tborder[i] = '\0'; diff --git a/src/interfaces/libpq/fe-protocol2.c b/src/interfaces/libpq/fe-protocol2.c index 2501ef4a60..b5753dba44 100644 --- a/src/interfaces/libpq/fe-protocol2.c +++ b/src/interfaces/libpq/fe-protocol2.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/interfaces/libpq/fe-protocol2.c,v 1.17 2005/05/11 01:26:02 neilc Exp $ + * $PostgreSQL: pgsql/src/interfaces/libpq/fe-protocol2.c,v 1.18 2005/06/12 00:00:21 neilc Exp $ * *------------------------------------------------------------------------- */ @@ -438,8 +438,12 @@ pqParseInput2(PGconn *conn) if (pqGets(&conn->workBuffer, conn)) return; if (conn->result == NULL) + { conn->result = PQmakeEmptyPGresult(conn, PGRES_COMMAND_OK); + if (!conn->result) + return; + } strncpy(conn->result->cmdStatus, conn->workBuffer.data, CMDSTATUS_LEN); checkXactStatus(conn, conn->workBuffer.data); @@ -572,19 +576,18 @@ pqParseInput2(PGconn *conn) static int getRowDescriptions(PGconn *conn) { - PGresult *result; + PGresult *result = NULL; int nfields; int i; result = PQmakeEmptyPGresult(conn, PGRES_TUPLES_OK); + if (!result) + goto failure; /* parseInput already read the 'T' label. */ /* the next two bytes are the number of fields */ if (pqGetInt(&(result->numAttributes), 2, conn)) - { - PQclear(result); - return EOF; - } + goto failure; nfields = result->numAttributes; /* allocate space for the attribute descriptors */ @@ -592,6 +595,8 @@ getRowDescriptions(PGconn *conn) { result->attDescs = (PGresAttDesc *) pqResultAlloc(result, nfields * sizeof(PGresAttDesc), TRUE); + if (!result->attDescs) + goto failure; MemSet(result->attDescs, 0, nfields * sizeof(PGresAttDesc)); } @@ -606,10 +611,7 @@ getRowDescriptions(PGconn *conn) pqGetInt(&typid, 4, conn) || pqGetInt(&typlen, 2, conn) || pqGetInt(&atttypmod, 4, conn)) - { - PQclear(result); - return EOF; - } + goto failure; /* * Since pqGetInt treats 2-byte integers as unsigned, we need to @@ -619,6 +621,8 @@ getRowDescriptions(PGconn *conn) result->attDescs[i].name = pqResultStrdup(result, conn->workBuffer.data); + if (!result->attDescs[i].name) + goto failure; result->attDescs[i].tableid = 0; result->attDescs[i].columnid = 0; result->attDescs[i].format = 0; @@ -630,6 +634,11 @@ getRowDescriptions(PGconn *conn) /* Success! */ conn->result = result; return 0; + +failure: + if (result) + PQclear(result); + return EOF; } /* @@ -685,7 +694,11 @@ getAnotherTuple(PGconn *conn, bool binary) nbytes = (nfields + BITS_PER_BYTE - 1) / BITS_PER_BYTE; /* malloc() only for unusually large field counts... */ if (nbytes > sizeof(std_bitmap)) + { bitmap = (char *) malloc(nbytes); + if (!bitmap) + goto outOfMemory; + } if (pqGetnchar(bitmap, nbytes, conn)) goto EOFexit; @@ -758,13 +771,18 @@ outOfMemory: pqClearAsyncResult(conn); printfPQExpBuffer(&conn->errorMessage, libpq_gettext("out of memory for query result\n")); + + /* + * XXX: if PQmakeEmptyPGresult() fails, there's probably not much + * we can do to recover... + */ conn->result = PQmakeEmptyPGresult(conn, PGRES_FATAL_ERROR); conn->asyncStatus = PGASYNC_READY; /* Discard the failed message --- good idea? */ conn->inStart = conn->inEnd; EOFexit: - if (bitmap != std_bitmap) + if (bitmap != NULL && bitmap != std_bitmap) free(bitmap); return EOF; } @@ -780,7 +798,7 @@ EOFexit: static int pqGetErrorNotice2(PGconn *conn, bool isError) { - PGresult *res; + PGresult *res = NULL; PQExpBufferData workBuf; char *startp; char *splitp; @@ -792,10 +810,7 @@ pqGetErrorNotice2(PGconn *conn, bool isError) */ initPQExpBuffer(&workBuf); if (pqGets(&workBuf, conn)) - { - termPQExpBuffer(&workBuf); - return EOF; - } + goto failure; /* * Make a PGresult to hold the message. We temporarily lie about the @@ -803,8 +818,12 @@ pqGetErrorNotice2(PGconn *conn, bool isError) * conn->errorMessage. */ res = PQmakeEmptyPGresult(conn, PGRES_EMPTY_QUERY); + if (!res) + goto failure; res->resultStatus = isError ? PGRES_FATAL_ERROR : PGRES_NONFATAL_ERROR; res->errMsg = pqResultStrdup(res, workBuf.data); + if (!res->errMsg) + goto failure; /* * Break the message into fields. We can't do very much here, but we @@ -869,6 +888,12 @@ pqGetErrorNotice2(PGconn *conn, bool isError) termPQExpBuffer(&workBuf); return 0; + +failure: + if (res) + PQclear(res); + termPQExpBuffer(&workBuf); + return EOF; } /* diff --git a/src/interfaces/libpq/fe-protocol3.c b/src/interfaces/libpq/fe-protocol3.c index ae8435bf1a..273159f430 100644 --- a/src/interfaces/libpq/fe-protocol3.c +++ b/src/interfaces/libpq/fe-protocol3.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/interfaces/libpq/fe-protocol3.c,v 1.20 2004/12/31 22:03:50 pgsql Exp $ + * $PostgreSQL: pgsql/src/interfaces/libpq/fe-protocol3.c,v 1.21 2005/06/12 00:00:21 neilc Exp $ * *------------------------------------------------------------------------- */ @@ -51,7 +51,7 @@ static int getParameterStatus(PGconn *conn); static int getNotify(PGconn *conn); static int getCopyStart(PGconn *conn, ExecStatusType copytype); static int getReadyForQuery(PGconn *conn); -static int build_startup_packet(const PGconn *conn, char *packet, +static int build_startup_packet(const PGconn *conn, char *packet, const PQEnvironmentOption *options); @@ -197,8 +197,12 @@ pqParseInput3(PGconn *conn) if (pqGets(&conn->workBuffer, conn)) return; if (conn->result == NULL) + { conn->result = PQmakeEmptyPGresult(conn, PGRES_COMMAND_OK); + if (!conn->result) + return; + } strncpy(conn->result->cmdStatus, conn->workBuffer.data, CMDSTATUS_LEN); conn->asyncStatus = PGASYNC_READY; @@ -215,8 +219,12 @@ pqParseInput3(PGconn *conn) break; case 'I': /* empty query */ if (conn->result == NULL) + { conn->result = PQmakeEmptyPGresult(conn, PGRES_EMPTY_QUERY); + if (!conn->result) + return; + } conn->asyncStatus = PGASYNC_READY; break; case '1': /* Parse Complete */ @@ -224,8 +232,12 @@ pqParseInput3(PGconn *conn) if (conn->queryclass == PGQUERY_PREPARE) { if (conn->result == NULL) + { conn->result = PQmakeEmptyPGresult(conn, PGRES_COMMAND_OK); + if (!conn->result) + return; + } conn->asyncStatus = PGASYNC_READY; } break; @@ -412,14 +424,13 @@ getRowDescriptions(PGconn *conn) int i; result = PQmakeEmptyPGresult(conn, PGRES_TUPLES_OK); + if (!result) + goto failure; /* parseInput already read the 'T' label and message length. */ /* the next two bytes are the number of fields */ if (pqGetInt(&(result->numAttributes), 2, conn)) - { - PQclear(result); - return EOF; - } + goto failure; nfields = result->numAttributes; /* allocate space for the attribute descriptors */ @@ -427,7 +438,9 @@ getRowDescriptions(PGconn *conn) { result->attDescs = (PGresAttDesc *) pqResultAlloc(result, nfields * sizeof(PGresAttDesc), TRUE); - MemSet((char *) result->attDescs, 0, nfields * sizeof(PGresAttDesc)); + if (!result->attDescs) + goto failure; + MemSet(result->attDescs, 0, nfields * sizeof(PGresAttDesc)); } /* result->binary is true only if ALL columns are binary */ @@ -451,8 +464,7 @@ getRowDescriptions(PGconn *conn) pqGetInt(&atttypmod, 4, conn) || pqGetInt(&format, 2, conn)) { - PQclear(result); - return EOF; + goto failure; } /* @@ -465,6 +477,8 @@ getRowDescriptions(PGconn *conn) result->attDescs[i].name = pqResultStrdup(result, conn->workBuffer.data); + if (!result->attDescs[i].name) + goto failure; result->attDescs[i].tableid = tableid; result->attDescs[i].columnid = columnid; result->attDescs[i].format = format; @@ -479,6 +493,10 @@ getRowDescriptions(PGconn *conn) /* Success! */ conn->result = result; return 0; + +failure: + PQclear(result); + return EOF; } /* @@ -507,7 +525,7 @@ getAnotherTuple(PGconn *conn, int msgLength) pqResultAlloc(result, nfields * sizeof(PGresAttValue), TRUE); if (conn->curTuple == NULL) goto outOfMemory; - MemSet((char *) conn->curTuple, 0, nfields * sizeof(PGresAttValue)); + MemSet(conn->curTuple, 0, nfields * sizeof(PGresAttValue)); } tup = conn->curTuple; @@ -593,19 +611,11 @@ outOfMemory: int pqGetErrorNotice3(PGconn *conn, bool isError) { - PGresult *res; + PGresult *res = NULL; PQExpBufferData workBuf; char id; const char *val; - /* - * Make a PGresult to hold the accumulated fields. We temporarily lie - * about the result status, so that PQmakeEmptyPGresult doesn't - * uselessly copy conn->errorMessage. - */ - res = PQmakeEmptyPGresult(conn, PGRES_EMPTY_QUERY); - res->resultStatus = isError ? PGRES_FATAL_ERROR : PGRES_NONFATAL_ERROR; - /* * Since the fields might be pretty long, we create a temporary * PQExpBuffer rather than using conn->workBuffer. workBuffer is @@ -614,6 +624,16 @@ pqGetErrorNotice3(PGconn *conn, bool isError) */ initPQExpBuffer(&workBuf); + /* + * Make a PGresult to hold the accumulated fields. We temporarily lie + * about the result status, so that PQmakeEmptyPGresult doesn't + * uselessly copy conn->errorMessage. + */ + res = PQmakeEmptyPGresult(conn, PGRES_EMPTY_QUERY); + if (!res) + goto fail; + res->resultStatus = isError ? PGRES_FATAL_ERROR : PGRES_NONFATAL_ERROR; + /* * Read the fields and save into res. */ @@ -702,6 +722,8 @@ pqGetErrorNotice3(PGconn *conn, bool isError) if (isError) { res->errMsg = pqResultStrdup(res, workBuf.data); + if (!res->errMsg) + goto fail; pqClearAsyncResult(conn); conn->result = res; resetPQExpBuffer(&conn->errorMessage); @@ -825,19 +847,15 @@ getCopyStart(PGconn *conn, ExecStatusType copytype) int i; result = PQmakeEmptyPGresult(conn, copytype); + if (!result) + goto failure; if (pqGetc(&conn->copy_is_binary, conn)) - { - PQclear(result); - return EOF; - } + goto failure; result->binary = conn->copy_is_binary; /* the next two bytes are the number of fields */ if (pqGetInt(&(result->numAttributes), 2, conn)) - { - PQclear(result); - return EOF; - } + goto failure; nfields = result->numAttributes; /* allocate space for the attribute descriptors */ @@ -845,7 +863,9 @@ getCopyStart(PGconn *conn, ExecStatusType copytype) { result->attDescs = (PGresAttDesc *) pqResultAlloc(result, nfields * sizeof(PGresAttDesc), TRUE); - MemSet((char *) result->attDescs, 0, nfields * sizeof(PGresAttDesc)); + if (!result->attDescs) + goto failure; + MemSet(result->attDescs, 0, nfields * sizeof(PGresAttDesc)); } for (i = 0; i < nfields; i++) @@ -853,23 +873,23 @@ getCopyStart(PGconn *conn, ExecStatusType copytype) int format; if (pqGetInt(&format, 2, conn)) - { - PQclear(result); - return EOF; - } + goto failure; /* * Since pqGetInt treats 2-byte integers as unsigned, we need to * coerce these results to signed form. */ format = (int) ((int16) format); - result->attDescs[i].format = format; } /* Success! */ conn->result = result; return 0; + +failure: + PQclear(result); + return EOF; } /* diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h index e4692d5d5f..6e14fa8df2 100644 --- a/src/interfaces/libpq/libpq-int.h +++ b/src/interfaces/libpq/libpq-int.h @@ -12,7 +12,7 @@ * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/interfaces/libpq/libpq-int.h,v 1.101 2005/06/04 20:42:43 momjian Exp $ + * $PostgreSQL: pgsql/src/interfaces/libpq/libpq-int.h,v 1.102 2005/06/12 00:00:21 neilc Exp $ * *------------------------------------------------------------------------- */ @@ -403,7 +403,7 @@ extern void pqClearAsyncResult(PGconn *conn); extern void pqSaveErrorResult(PGconn *conn); extern PGresult *pqPrepareAsyncResult(PGconn *conn); extern void -pqInternalNotice(const PGNoticeHooks *hooks, const char *fmt,...) +pqInternalNotice(const PGNoticeHooks *hooks, const char *fmt, ...) /* This lets gcc check the format string for consistency. */ __attribute__((format(printf, 2, 3))); extern int pqAddTuple(PGresult *res, PGresAttValue *tup);