<!--
-$PostgreSQL: pgsql/doc/src/sgml/libpq.sgml,v 1.184 2005/06/10 03:02:01 momjian Exp $
+$PostgreSQL: pgsql/doc/src/sgml/libpq.sgml,v 1.185 2005/06/12 00:00:20 neilc Exp $
-->
<chapter id="libpq">
</para>
<para>
- Returns a connection options array. This may
- be used to determine all possible <function>PQconnectdb</function> options and their
+ Returns a connection options array. This may be used to determine
+ all possible <function>PQconnectdb</function> options and their
current default values. The return value points to an array of
- <structname>PQconninfoOption</structname> structures, which ends with an entry having a null
- <structfield>keyword</> pointer. Note that the current default values
- (<structfield>val</structfield> fields)
- will depend on environment variables and other context.
- Callers must treat the connection options data as read-only.
+ <structname>PQconninfoOption</structname> structures, which ends
+ with an entry having a null <structfield>keyword</> pointer. The
+ null pointer is returned if memory could not be allocated. Note that
+ the current default values (<structfield>val</structfield> fields)
+ will depend on environment variables and other context. Callers
+ must treat the connection options data as read-only.
</para>
<para>
<para>
Constructs an empty <structname>PGresult</structname> object with the given status.
<synopsis>
-PGresult* PQmakeEmptyPGresult(PGconn *conn, ExecStatusType status);
+PGresult *PQmakeEmptyPGresult(PGconn *conn, ExecStatusType status);
</synopsis>
</para>
<para>
-This is <application>libpq</>'s internal function to allocate and initialize an empty
-<structname>PGresult</structname> object. It is exported because some applications find it
-useful to generate result objects (particularly objects with error
-status) themselves. If <parameter>conn</parameter> is not null and <parameter>status</> indicates an error,
-the current error message of the specified connection is copied into the <structname>PGresult</structname>.
-Note that <function>PQclear</function> should eventually be called on the object, just
-as with a <structname>PGresult</structname> returned by <application>libpq</application> itself.
+This is <application>libpq</>'s internal function to allocate and
+initialize an empty <structname>PGresult</structname> 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
+<parameter>conn</parameter> is not null and <parameter>status</>
+indicates an error, the current error message of the specified
+connection is copied into the <structname>PGresult</structname>. Note
+that <function>PQclear</function> should eventually be called on the
+object, just as with a <structname>PGresult</structname> returned by
+<application>libpq</application> itself.
</para>
</listitem>
</varlistentry>
<para>
<function>PQescapeBytea</> returns an escaped version of the
<parameter>from</parameter> parameter binary string in memory
- allocated with <function>malloc()</>. This memory must be freed
- using <function>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
- <productname>PostgreSQL</productname> string literal parser, and
- the <type>bytea</type> input function. A terminating zero byte is
- also added. The single quotes that must surround
- <productname>PostgreSQL</productname> string literals are not part
- of the result string.
+ allocated with <function>malloc()</> (a null pointer is returned if
+ memory could not be allocated). This memory must be freed using
+ <function>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 <productname>PostgreSQL</productname>
+ string literal parser, and the <type>bytea</type> input function. A
+ terminating zero byte is also added. The single quotes that must
+ surround <productname>PostgreSQL</productname> string literals are
+ not part of the result string.
</para>
</listitem>
</varlistentry>
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
*
* 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;
}
#ifdef NOT_USED
-
/*
* parse dbName to get all additional info in it, if any
*/
}
/*
- 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)
{
}
}
-/* 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)
{
}
-/* 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)
{
}
-/* 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)
{
* 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)
{
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 */
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;
}
}
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;
}
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
PGresult *result;
result = (PGresult *) malloc(sizeof(PGresult));
+ if (!result)
+ return NULL;
result->ntups = 0;
result->numAttributes = 0;
* 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;
/* Make a PGresult to pass to the notice receiver */
res = PQmakeEmptyPGresult(NULL, PGRES_NONFATAL_ERROR);
+ if (!res)
+ return;
res->noticeHooks = *hooks;
/*
/* 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);
}
/*
* 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 *
* 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 $
*
*-------------------------------------------------------------------------
*/
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;
}
* 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 $
*
*-------------------------------------------------------------------------
*/
* 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;
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));
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';
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
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);
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 */
{
result->attDescs = (PGresAttDesc *)
pqResultAlloc(result, nfields * sizeof(PGresAttDesc), TRUE);
+ if (!result->attDescs)
+ goto failure;
MemSet(result->attDescs, 0, nfields * sizeof(PGresAttDesc));
}
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
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;
/* Success! */
conn->result = result;
return 0;
+
+failure:
+ if (result)
+ PQclear(result);
+ return EOF;
}
/*
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;
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;
}
static int
pqGetErrorNotice2(PGconn *conn, bool isError)
{
- PGresult *res;
+ PGresult *res = NULL;
PQExpBufferData workBuf;
char *startp;
char *splitp;
*/
initPQExpBuffer(&workBuf);
if (pqGets(&workBuf, conn))
- {
- termPQExpBuffer(&workBuf);
- return EOF;
- }
+ goto failure;
/*
* Make a PGresult to hold the message. We temporarily lie about the
* 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
termPQExpBuffer(&workBuf);
return 0;
+
+failure:
+ if (res)
+ PQclear(res);
+ termPQExpBuffer(&workBuf);
+ return EOF;
}
/*
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
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);
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;
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 */
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;
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 */
{
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 */
pqGetInt(&atttypmod, 4, conn) ||
pqGetInt(&format, 2, conn))
{
- PQclear(result);
- return EOF;
+ goto failure;
}
/*
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;
/* Success! */
conn->result = result;
return 0;
+
+failure:
+ PQclear(result);
+ return EOF;
}
/*
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;
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
*/
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.
*/
if (isError)
{
res->errMsg = pqResultStrdup(res, workBuf.data);
+ if (!res->errMsg)
+ goto fail;
pqClearAsyncResult(conn);
conn->result = res;
resetPQExpBuffer(&conn->errorMessage);
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 */
{
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++)
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;
}
/*
* 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 $
*
*-------------------------------------------------------------------------
*/
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);