structs from libpq-fe.h, as we previously discussed.
There turned out to be sloppy coding practices in more places than
I had realized :-(, but all in all I think it was a well-worth-while
exercise.
I ended up adding several routines to libpq's API in order to respond
to application requirements that were exposed by this work. I owe the
docs crew updates for libpq.sgml to describe these changes. I'm way too
tired to work on the docs tonight, however.
This is the last major change I intend to submit for 6.4. I do want
to see if I can make libpgtcl work with Tcl 8.0 before we go final,
but hopefully that will be a minor bug fix.
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_dump.c,v 1.83 1998/09/01 04:33:45 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_dump.c,v 1.84 1998/09/03 02:10:36 momjian Exp $
*
*
copydone = false;
while (!copydone)
{
- ret = PQgetline(res->conn, copybuf, COPYBUFSIZ);
+ ret = PQgetline(g_conn, copybuf, COPYBUFSIZ);
if (copybuf[0] == '\\' &&
copybuf[1] == '.' &&
}
fprintf(fout, "\\.\n");
}
- ret = PQendcopy(res->conn);
+ ret = PQendcopy(g_conn);
if (ret != 0)
{
fprintf(stderr, "SQL query to dump the contents of Table '%s' "
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/bin/psql/Attic/psql.c,v 1.158 1998/09/01 04:33:51 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/bin/psql/Attic/psql.c,v 1.159 1998/09/03 02:10:38 momjian Exp $
*
*-------------------------------------------------------------------------
*/
/* declarations for functions in this file */
static void usage(char *progname);
static void slashUsage();
-static bool handleCopyOut(PGresult *res, FILE *copystream);
+static bool handleCopyOut(PGconn *conn, FILE *copystream);
static bool handleCopyIn(PGresult *res, const bool mustprompt,
FILE *copystream);
static int tableList(PsqlSettings *pset, bool deep_tablelist,
break;
case PGRES_COPY_OUT:
if (copy_out)
- *success_p = handleCopyOut(results, copystream);
+ *success_p = handleCopyOut(pset->db, copystream);
else
{
if (!pset->quiet)
printf("Copy command returns...\n");
- *success_p = handleCopyOut(results, stdout);
+ *success_p = handleCopyOut(pset->db, stdout);
}
break;
case PGRES_COPY_IN:
if (copy_in)
- *success_p = handleCopyIn(results, false, copystream);
+ *success_p = handleCopyIn(pset->db, false, copystream);
else
- *success_p = handleCopyIn(results,
+ *success_p = handleCopyIn(pset->db,
!pset->quiet && !pset->notty,
stdin);
break;
else
userparam = PQuser(olddb);
- /*
- * libpq doesn't provide an accessor function for the password, so
- * we cheat here.
- */
- pwparam = olddb->pgpass;
+ /* FIXME: if changing user, ought to prompt for a new password? */
+ pwparam = PQpass(olddb);
pset->db = PQsetdbLogin(PQhost(olddb), PQport(olddb),
NULL, NULL, dbparam, userparam, pwparam);
#define COPYBUFSIZ 8192
static bool
-handleCopyOut(PGresult *res, FILE *copystream)
+handleCopyOut(PGconn *conn, FILE *copystream)
{
bool copydone;
char copybuf[COPYBUFSIZ];
while (!copydone)
{
- ret = PQgetline(res->conn, copybuf, COPYBUFSIZ);
+ ret = PQgetline(conn, copybuf, COPYBUFSIZ);
if (copybuf[0] == '\\' &&
copybuf[1] == '.' &&
}
}
fflush(copystream);
- return !PQendcopy(res->conn);
+ return ! PQendcopy(conn);
}
static bool
-handleCopyIn(PGresult *res, const bool mustprompt, FILE *copystream)
+handleCopyIn(PGconn *conn, const bool mustprompt, FILE *copystream)
{
bool copydone = false;
bool firstload;
*s++ = c;
if (c == EOF)
{
- PQputline(res->conn, "\\.");
+ PQputline(conn, "\\.");
copydone = true;
break;
}
*s = '\0';
- PQputline(res->conn, copybuf);
+ PQputline(conn, copybuf);
if (firstload)
{
if (!strcmp(copybuf, "\\."))
firstload = false;
}
}
- PQputline(res->conn, "\n");
+ PQputline(conn, "\n");
}
- return !PQendcopy(res->conn);
+ return ! PQendcopy(conn);
}
break;
case PGRES_COPY_OUT:
ECPGlog("ECPGexecute line %d: Got PGRES_COPY_OUT ... tossing.\n", stmt->lineno);
- PQendcopy(results->conn);
+ PQendcopy(actual_connection->connection);
break;
case PGRES_COPY_IN:
ECPGlog("ECPGexecute line %d: Got PGRES_COPY_IN ... tossing.\n", stmt->lineno);
- PQendcopy(results->conn);
+ PQendcopy(actual_connection->connection);
break;
default:
ECPGlog("ECPGexecute line %d: Got something else, postgres error.\n",
if (!f)
return;
- sprintf(f, "[%d]: %s", getpid(), format);
+ sprintf(f, "[%d]: %s", (int) getpid(), format);
va_start(ap, format);
vfprintf(debugstream, f, ap);
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/interfaces/libpgtcl/Attic/pgtclCmds.c,v 1.31 1998/09/01 04:39:56 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/interfaces/libpgtcl/Attic/pgtclCmds.c,v 1.32 1998/09/03 02:10:42 momjian Exp $
*
*-------------------------------------------------------------------------
*/
conn = PQsetdb(pghost, pgport, pgoptions, pgtty, dbName);
}
- if (conn->status == CONNECTION_OK)
+ if (PQstatus(conn) == CONNECTION_OK) {
{
PgSetConnectionId(interp, conn);
return TCL_OK;
}
else
{
- Tcl_AppendResult(interp, "Connection to database failed\n", 0);
- Tcl_AppendResult(interp, conn->errorMessage, 0);
+ Tcl_AppendResult(interp, "Connection to database failed\n",
+ PQerrorMessage(conn), 0);
PQfinish(conn);
return TCL_ERROR;
}
Pg_ConnectionId *connid;
PGconn *conn;
PGresult *result;
- int connStatus;
if (argc != 3)
{
return TCL_ERROR;
}
- connStatus = conn->status;
result = PQexec(conn, argv[2]);
/* Transfer any notify events from libpq to Tcl event queue. */
{
int rId = PgSetResultId(interp, argv[1], result);
- if (result->resultStatus == PGRES_COPY_IN ||
- result->resultStatus == PGRES_COPY_OUT)
+ ExecStatusType rStat = PQresultStatus(result);
+ if (rStat == PGRES_COPY_IN || rStat == PGRES_COPY_OUT)
{
connid->res_copyStatus = RES_COPY_INPROGRESS;
connid->res_copy = rId;
else
{
/* error occurred during the query */
- Tcl_SetResult(interp, conn->errorMessage, TCL_VOLATILE);
+ Tcl_SetResult(interp, PQerrorMessage(conn), TCL_VOLATILE);
return TCL_ERROR;
}
}
-conn
the connection that produced the result
-assign arrayName
- assign the results to an array
- -assignbyidx arrayName
- assign the results to an array using the first field as a key
+ assign the results to an array, using subscripts of the form
+ (tupno,attributeName)
+ -assignbyidx arrayName ?appendstr?
+ assign the results to an array using the first field's value as a key.
+ All but the first field of each tuple are stored, using subscripts of the form
+ (field0value,attributeNameappendstr)
-numTuples
the number of tuples in the query
-attributes
int tupno;
char *arrVar;
char nameBuffer[256];
+ const char *appendstr;
if (argc < 3 || argc > 5)
{
/*
* this assignment assigns the table of result tuples into a giant
- * array with the name given in the argument, the indices of the
- * array or (tupno,attrName). Note we expect field names not to
+ * array with the name given in the argument.
+ * The indices of the array are of the form (tupno,attrName).
+ * Note we expect field names not to
* exceed a few dozen characters, so truncating to prevent buffer
* overflow shouldn't be a problem.
*/
}
else if (strcmp(opt, "-assignbyidx") == 0)
{
- if (argc != 4)
+ if (argc != 4 && argc != 5)
{
- Tcl_AppendResult(interp, "-assignbyidx option must be followed by a variable name", 0);
+ Tcl_AppendResult(interp, "-assignbyidx option requires an array name and optionally an append string",0);
return TCL_ERROR;
}
arrVar = argv[3];
+ appendstr = (argc == 5) ? (const char *) argv[4] : "";
/*
* this assignment assigns the table of result tuples into a giant
- * array with the name given in the argument, the indices of the
- * array or (tupno,attrName). Here, we still assume PQfname won't
- * exceed 200 characters, but we dare not make the same assumption
- * about the data in field 0.
+ * array with the name given in the argument. The indices of the array
+ * are of the form (field0Value,attrNameappendstr).
+ * Here, we still assume PQfname won't exceed 200 characters,
+ * but we dare not make the same assumption about the data in field 0
+ * nor the append string.
*/
for (tupno = 0; tupno < PQntuples(result); tupno++)
{
const char *field0 = PQgetvalue(result, tupno, 0);
- char *workspace = malloc(strlen(field0) + 210);
+ char * workspace = malloc(strlen(field0) + strlen(appendstr) + 210);
for (i = 1; i < PQnfields(result); i++)
{
- sprintf(workspace, "%s,%.200s", field0, PQfname(result, i));
+ sprintf(workspace, "%s,%.200s%s", field0, PQfname(result,i),
+ appendstr);
+ sprintf(workspace, "%s,%.200s", field0, PQfname(result,i));
if (Tcl_SetVar2(interp, arrVar, workspace,
PQgetvalue(result, tupno, i),
TCL_LEAVE_ERR_MSG) == NULL)
"\t-status\n",
"\t-conn\n",
"\t-assign arrayVarName\n",
- "\t-assignbyidx arrayVarName\n",
+ "\t-assignbyidx arrayVarName ?appendstr?\n",
"\t-numTuples\n",
"\t-numAttrs\n"
"\t-attributes\n"
if ((result = PQexec(conn, argv[2])) == 0)
{
/* error occurred during the query */
- Tcl_SetResult(interp, conn->errorMessage, TCL_STATIC);
+ Tcl_SetResult(interp, PQerrorMessage(conn), TCL_STATIC);
return TCL_ERROR;
}
ckfree(cmd);
/* Transfer any notify events from libpq to Tcl event queue. */
PgNotifyTransferEvents(connid);
- if (!result || (result->resultStatus != PGRES_COMMAND_OK))
+ if (PQresultStatus(result) != PGRES_COMMAND_OK) {
{
/* Error occurred during the execution of command */
- if (result)
- PQclear(result);
+ PQclear(result);
ckfree(callback);
ckfree(caserelname);
Tcl_DeleteHashEntry(entry);
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/interfaces/libpgtcl/Attic/pgtclId.c,v 1.14 1998/09/01 04:39:58 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/interfaces/libpgtcl/Attic/pgtclId.c,v 1.15 1998/09/03 02:10:44 momjian Exp $
*
*-------------------------------------------------------------------------
*/
connid->res_copyStatus = RES_COPY_NONE;
if (PQendcopy(connid->conn))
{
- connid->results[connid->res_copy]->resultStatus = PGRES_BAD_RESPONSE;
+ PQclear(connid->results[connid->res_copy]);
+ connid->results[connid->res_copy] =
+ PQmakeEmptyPGresult(connid->conn, PGRES_BAD_RESPONSE);
connid->res_copy = -1;
*errorCodePtr = EIO;
return -1;
}
else
{
- connid->results[connid->res_copy]->resultStatus = PGRES_COMMAND_OK;
+ PQclear(connid->results[connid->res_copy]);
+ connid->results[connid->res_copy] =
+ PQmakeEmptyPGresult(connid->conn, PGRES_COMMAND_OK);
connid->res_copy = -1;
return 0;
}
}
/*
- * Called when reading data (via gets) for a copy to stdout.
- *
- * NOTE: this routine knows way more than it ought to about libpq's
- * internal buffering mechanisms.
+ * Called when reading data (via gets) for a copy to stdout.
*/
-int
-PgInputProc(DRIVER_INPUT_PROTO)
+int PgInputProc(DRIVER_INPUT_PROTO)
{
- Pg_ConnectionId *connid;
- PGconn *conn;
- char c;
- int avail;
+ Pg_ConnectionId *connid;
+ PGconn *conn;
+ int avail;
- connid = (Pg_ConnectionId *) cData;
- conn = connid->conn;
+ connid = (Pg_ConnectionId *)cData;
+ conn = connid->conn;
- if (connid->res_copy < 0 ||
- connid->results[connid->res_copy]->resultStatus != PGRES_COPY_OUT)
+ if (connid->res_copy < 0 ||
+ PQresultStatus(connid->results[connid->res_copy]) != PGRES_COPY_OUT)
{
*errorCodePtr = EBUSY;
return -1;
- }
+ }
- /* Try to load any newly arrived data */
- conn->errorMessage[0] = '\0';
- PQconsumeInput(conn);
- if (conn->errorMessage[0])
+ /* Read any newly arrived data into libpq's buffer,
+ * thereby clearing the socket's read-ready condition.
+ */
+ if (! PQconsumeInput(conn))
{
*errorCodePtr = EIO;
return -1;
- }
+ }
- /*
- * Move data from libpq's buffer to Tcl's. We want to accept data only
- * in units of whole lines, not partial lines. This ensures that we
- * can recognize the terminator line "\\.\n". (Otherwise, if it
- * happened to cross a packet/buffer boundary, we might hand the first
- * one or two characters off to Tcl, which we shouldn't.)
- */
+ /* Move data from libpq's buffer to Tcl's. */
- conn->inCursor = conn->inStart;
+ avail = PQgetlineAsync(conn, buf, bufSize);
- avail = bufSize;
- while (avail > 0 && conn->inCursor < conn->inEnd)
+ if (avail < 0)
{
- c = conn->inBuffer[conn->inCursor++];
- *buf++ = c;
- --avail;
- if (c == '\n')
- {
- /* Got a complete line; mark the data removed from libpq */
- conn->inStart = conn->inCursor;
- /* Is it the endmarker line? */
- if (bufSize - avail == 3 && buf[-3] == '\\' && buf[-2] == '.')
- {
- /* Yes, change state and return 0 */
- return PgEndCopy(connid, errorCodePtr);
- }
- /* No, return the data to Tcl */
- /* fprintf(stderr, "returning %d chars\n", bufSize - avail); */
- return bufSize - avail;
- }
- }
+ /* Endmarker detected, change state and return 0 */
+ return PgEndCopy(connid, errorCodePtr);
+ }
- /*
- * We don't have a complete line. We'd prefer to leave it in libpq's
- * buffer until the rest arrives, but there is a special case: what if
- * the line is longer than the buffer Tcl is offering us? In that
- * case we'd better hand over a partial line, else we'd get into an
- * infinite loop. Do this in a way that ensures we can't misrecognize
- * a terminator line later: leave last 3 characters in libpq buffer.
- */
- if (avail == 0 && bufSize > 3)
- {
- conn->inStart = conn->inCursor - 3;
- return bufSize - 3;
- }
- return 0;
+ return avail;
}
/*
conn = connid->conn;
if (connid->res_copy < 0 ||
- connid->results[connid->res_copy]->resultStatus != PGRES_COPY_IN)
+ PQresultStatus(connid->results[connid->res_copy]) != PGRES_COPY_IN)
{
*errorCodePtr = EBUSY;
return -1;
}
- conn->errorMessage[0] = '\0';
-
- PQputnbytes(conn, buf, bufSize);
-
- if (conn->errorMessage[0])
+ if (PQputnbytes(conn, buf, bufSize))
{
*errorCodePtr = EIO;
return -1;
connid = (Pg_ConnectionId *) Tcl_GetChannelInstanceData(conn_chan);
- if (resid < 0 || resid > connid->res_max || connid->results[resid] == NULL)
+ if (resid < 0 || resid >= connid->res_max || connid->results[resid] == NULL)
{
Tcl_SetResult(interp, "Invalid result handle", TCL_STATIC);
return -1;
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-connect.c,v 1.80 1998/09/01 04:40:04 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-connect.c,v 1.81 1998/09/03 02:10:46 momjian Exp $
*
*-------------------------------------------------------------------------
*/
return conn->pguser;
}
+char *
+PQpass(PGconn *conn)
+{
+ if (!conn)
+ return (char *) NULL;
+ return conn->pgpass;
+}
+
char *
PQhost(PGconn *conn)
{
}
char *
-PQoptions(PGconn *conn)
+PQport(PGconn *conn)
{
if (!conn)
return (char *) NULL;
- return conn->pgoptions;
+ return conn->pgport;
}
char *
}
char *
-PQport(PGconn *conn)
+PQoptions(PGconn *conn)
{
if (!conn)
return (char *) NULL;
- return conn->pgport;
+ return conn->pgoptions;
}
ConnStatusType
return conn->sock;
}
+int
+PQbackendPID(PGconn *conn)
+{
+ if (!conn || conn->status != CONNECTION_OK)
+ return 0;
+ return conn->be_pid;
+}
+
void
PQtrace(PGconn *conn, FILE *debug_port)
{
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-exec.c,v 1.65 1998/09/01 04:40:05 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-exec.c,v 1.66 1998/09/03 02:10:47 momjian Exp $
*
*-------------------------------------------------------------------------
*/
((*(conn)->noticeHook) ((conn)->noticeArg, (message)))
-static PGresult *makeEmptyPGresult(PGconn *conn, ExecStatusType status);
static void freeTuple(PGresAttValue *tuple, int numAttributes);
static void addTuple(PGresult *res, PGresAttValue *tup);
static void parseInput(PGconn *conn);
/*
- * PGresult -
- * returns a newly allocated, initialized PGresult
+ * PQmakeEmptyPGresult
+ * returns a newly allocated, initialized PGresult with given status
*
+ * Note this is exported --- you wouldn't think an application would need
+ * to build its own PGresults, but this has proven useful in both libpgtcl
+ * and the Perl5 interface, so maybe it's not so unreasonable.
*/
-static PGresult *
-makeEmptyPGresult(PGconn *conn, ExecStatusType status)
+PGresult *
+PQmakeEmptyPGresult(PGconn *conn, ExecStatusType status)
{
PGresult *result;
/*
* Consume any available input from the backend
+ * 0 return: some kind of trouble
+ * 1 return: no problem
*/
-void
+int
PQconsumeInput(PGconn *conn)
{
if (!conn)
- return;
+ return 0;
/*
* Load more data, if available. We do this no matter what state we
* application wants to get rid of a read-select condition. Note that
* we will NOT block waiting for more input.
*/
- if (pqReadData(conn) < 0)
+ if (pqReadData(conn) < 0) {
strcpy(conn->asyncErrorMessage, conn->errorMessage);
+ return 0;
+ }
/* Parsing of the data waits till later. */
+ return 1;
}
{
case 'C': /* command complete */
if (conn->result == NULL)
- conn->result = makeEmptyPGresult(conn,
- PGRES_COMMAND_OK);
+ conn->result = PQmakeEmptyPGresult(conn,
+ PGRES_COMMAND_OK);
if (pqGets(conn->result->cmdStatus, CMDSTATUS_LEN, conn))
return;
conn->asyncStatus = PGASYNC_READY;
DONOTICE(conn, conn->errorMessage);
}
if (conn->result == NULL)
- conn->result = makeEmptyPGresult(conn,
- PGRES_EMPTY_QUERY);
+ conn->result = PQmakeEmptyPGresult(conn,
+ PGRES_EMPTY_QUERY);
conn->asyncStatus = PGASYNC_READY;
break;
case 'K': /* secret key data from the backend */
int nfields;
int i;
- result = makeEmptyPGresult(conn, PGRES_TUPLES_OK);
+ result = PQmakeEmptyPGresult(conn, PGRES_TUPLES_OK);
/* parseInput already read the 'T' label. */
/* the next two bytes are the number of fields */
}
result->attDescs[i].name = strdup(typName);
result->attDescs[i].typid = typid;
- result->attDescs[i].typlen = (short) typlen;
+ result->attDescs[i].typlen = typlen;
result->attDescs[i].atttypmod = atttypmod;
}
pqClearAsyncResult(conn);
conn->asyncStatus = PGASYNC_IDLE;
/* conn->errorMessage has been set by pqWait or pqReadData. */
- return makeEmptyPGresult(conn, PGRES_FATAL_ERROR);
+ return PQmakeEmptyPGresult(conn, PGRES_FATAL_ERROR);
}
/* Parse it. */
parseInput(conn);
conn->result = NULL;/* handing over ownership to caller */
conn->curTuple = NULL; /* just in case */
if (!res)
- res = makeEmptyPGresult(conn, PGRES_FATAL_ERROR);
+ res = PQmakeEmptyPGresult(conn, PGRES_FATAL_ERROR);
strcpy(conn->errorMessage, conn->asyncErrorMessage);
/* Set the state back to BUSY, allowing parsing to proceed. */
conn->asyncStatus = PGASYNC_BUSY;
break;
case PGASYNC_COPY_IN:
- res = makeEmptyPGresult(conn, PGRES_COPY_IN);
+ res = PQmakeEmptyPGresult(conn, PGRES_COPY_IN);
break;
case PGASYNC_COPY_OUT:
- res = makeEmptyPGresult(conn, PGRES_COPY_OUT);
+ res = PQmakeEmptyPGresult(conn, PGRES_COPY_OUT);
break;
default:
sprintf(conn->errorMessage,
"PQgetResult: Unexpected asyncStatus %d\n",
(int) conn->asyncStatus);
- res = makeEmptyPGresult(conn, PGRES_FATAL_ERROR);
+ res = PQmakeEmptyPGresult(conn, PGRES_FATAL_ERROR);
break;
}
* PQgetline reads up to maxlen-1 characters (like fgets(3)) but strips
* the terminating \n (like gets(3)).
*
+ * CAUTION: the caller is responsible for detecting the end-of-copy signal
+ * (a line containing just "\.") when using this routine.
+ *
* RETURNS:
* EOF if it is detected or invalid arguments are given
* 0 if EOL is reached (i.e., \n has been read)
return result;
}
+/*
+ * PQgetlineAsync - gets a newline-terminated string without blocking.
+ *
+ * This routine is for applications that want to do "COPY to stdout"
+ * asynchronously, that is without blocking. Having issued the COPY command
+ * and gotten a PGRES_COPY_OUT response, the app should call PQconsumeInput
+ * and this routine until the end-of-data signal is detected. Unlike
+ * PQgetline, this routine takes responsibility for detecting end-of-data.
+ *
+ * On each call, PQgetlineAsync will return data if a complete newline-
+ * terminated data line is available in libpq's input buffer, or if the
+ * incoming data line is too long to fit in the buffer offered by the caller.
+ * Otherwise, no data is returned until the rest of the line arrives.
+ *
+ * If -1 is returned, the end-of-data signal has been recognized (and removed
+ * from libpq's input buffer). The caller *must* next call PQendcopy and
+ * then return to normal processing.
+ *
+ * RETURNS:
+ * -1 if the end-of-copy-data marker has been recognized
+ * 0 if no data is available
+ * >0 the number of bytes returned.
+ * The data returned will not extend beyond a newline character. If possible
+ * a whole line will be returned at one time. But if the buffer offered by
+ * the caller is too small to hold a line sent by the backend, then a partial
+ * data line will be returned. This can be detected by testing whether the
+ * last returned byte is '\n' or not.
+ * The returned string is *not* null-terminated.
+ */
+
+int
+PQgetlineAsync(PGconn *conn, char *buffer, int bufsize)
+{
+ int avail;
+
+ if (!conn || conn->asyncStatus != PGASYNC_COPY_OUT)
+ return -1; /* we are not doing a copy... */
+
+ /*
+ * Move data from libpq's buffer to the caller's.
+ * We want to accept data only in units of whole lines,
+ * not partial lines. This ensures that we can recognize
+ * the terminator line "\\.\n". (Otherwise, if it happened
+ * to cross a packet/buffer boundary, we might hand the first
+ * one or two characters off to the caller, which we shouldn't.)
+ */
+
+ conn->inCursor = conn->inStart;
+
+ avail = bufsize;
+ while (avail > 0 && conn->inCursor < conn->inEnd)
+ {
+ char c = conn->inBuffer[conn->inCursor++];
+ *buffer++ = c;
+ --avail;
+ if (c == '\n')
+ {
+ /* Got a complete line; mark the data removed from libpq */
+ conn->inStart = conn->inCursor;
+ /* Is it the endmarker line? */
+ if (bufsize-avail == 3 && buffer[-3] == '\\' && buffer[-2] == '.')
+ return -1;
+ /* No, return the data line to the caller */
+ return bufsize - avail;
+ }
+ }
+
+ /*
+ * We don't have a complete line.
+ * We'd prefer to leave it in libpq's buffer until the rest arrives,
+ * but there is a special case: what if the line is longer than the
+ * buffer the caller is offering us? In that case we'd better hand over
+ * a partial line, else we'd get into an infinite loop.
+ * Do this in a way that ensures we can't misrecognize a terminator
+ * line later: leave last 3 characters in libpq buffer.
+ */
+ if (avail == 0 && bufsize > 3)
+ {
+ conn->inStart = conn->inCursor - 3;
+ return bufsize - 3;
+ }
+ return 0;
+}
+
/*
* PQputline -- sends a string to the backend.
+ * Returns 0 if OK, EOF if not.
*
* Chiefly here so that applications can use "COPY from stdin".
*/
-void
+int
PQputline(PGconn *conn, const char *s)
{
- if (conn && conn->sock >= 0)
- (void) pqPutnchar(s, strlen(s), conn);
+ if (!conn || conn->sock < 0)
+ return EOF;
+ return pqPutnchar(s, strlen(s), conn);
}
/*
* PQputnbytes -- like PQputline, but buffer need not be null-terminated.
+ * Returns 0 if OK, EOF if not.
*/
-void
+int
PQputnbytes(PGconn *conn, const char *buffer, int nbytes)
{
- if (conn && conn->sock >= 0)
- (void) pqPutnchar(buffer, nbytes, conn);
+ if (!conn || conn->sock < 0)
+ return EOF;
+ return pqPutnchar(buffer, nbytes, conn);
}
/*
sprintf(conn->errorMessage,
"FATAL: PQfn: protocol error: id=%x\n", id);
conn->inStart = conn->inCursor;
- return makeEmptyPGresult(conn, PGRES_FATAL_ERROR);
+ return PQmakeEmptyPGresult(conn, PGRES_FATAL_ERROR);
}
break;
case 'E': /* error return */
case 'Z': /* backend is ready for new query */
/* consume the message and exit */
conn->inStart = conn->inCursor;
- return makeEmptyPGresult(conn, status);
+ return PQmakeEmptyPGresult(conn, status);
default:
/* The backend violates the protocol. */
sprintf(conn->errorMessage,
"FATAL: PQfn: protocol error: id=%x\n", id);
conn->inStart = conn->inCursor;
- return makeEmptyPGresult(conn, PGRES_FATAL_ERROR);
+ return PQmakeEmptyPGresult(conn, PGRES_FATAL_ERROR);
}
/* Completed this message, keep going */
conn->inStart = conn->inCursor;
}
/* we fall out of the loop only upon failing to read data */
- return makeEmptyPGresult(conn, PGRES_FATAL_ERROR);
+ return PQmakeEmptyPGresult(conn, PGRES_FATAL_ERROR);
}
return res->numAttributes;
}
+int
+PQbinaryTuples(PGresult *res)
+{
+ if (!res)
+ return 0;
+ return res->binary;
+}
+
/*
* Helper routines to range-check field numbers and tuple numbers.
* Return TRUE if OK, FALSE if not
return InvalidOid;
}
-short
+int
PQfsize(PGresult *res, int field_num)
{
if (!check_field_number("PQfsize", res, field_num))
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-misc.c,v 1.20 1998/09/01 04:40:08 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-misc.c,v 1.21 1998/09/03 02:10:50 momjian Exp $
*
*-------------------------------------------------------------------------
*/
conn->inCursor += len;
if (conn->Pfdebug)
- fprintf(conn->Pfdebug, "From backend (%d)> %s\n", len, s);
+ fprintf(conn->Pfdebug, "From backend (%d)> %.*s\n", len, len, s);
return 0;
}
/* --------------------------------------------------------------------- */
/* pqPutnchar:
- send a string of exactly len bytes
- The buffer should have a terminating null, but it's not sent.
+ send a string of exactly len bytes, no null termination needed
*/
int
pqPutnchar(const char *s, int len, PGconn *conn)
return EOF;
if (conn->Pfdebug)
- fprintf(conn->Pfdebug, "To backend> %s\n", s);
+ fprintf(conn->Pfdebug, "To backend> %.*s\n", len, s);
return 0;
}
*
* Copyright (c) 1994, Regents of the University of California
*
- * $Id: libpq-fe.h,v 1.40 1998/09/01 04:40:10 momjian Exp $
+ * $Id: libpq-fe.h,v 1.41 1998/09/03 02:10:51 momjian Exp $
*
*-------------------------------------------------------------------------
*/
#endif
#include
-/* these wouldn't need to be included if PGSockAddr weren't exported: */
-#ifdef WIN32
-#include
-#else
-#include
-#include
-#include
-#endif
-/* ----------------
- * include stuff common to fe and be
- * ----------------
+/* postgres_ext.h defines the backend's externally visible types,
+ * such as Oid.
*/
#include "postgres_ext.h"
-#include "lib/dllist.h"
/* Application-visible enum types */
typedef enum
{
PGRES_EMPTY_QUERY = 0,
- PGRES_COMMAND_OK, /* a query command that doesn't return */
- /* anything was executed properly by the backend */
- PGRES_TUPLES_OK, /* a query command that returns tuples */
- /* was executed properly by the backend, PGresult */
- /* contains the result tuples */
+ PGRES_COMMAND_OK, /* a query command that doesn't return anything
+ * was executed properly by the backend */
+ PGRES_TUPLES_OK, /* a query command that returns tuples
+ * was executed properly by the backend,
+ * PGresult contains the result tuples */
PGRES_COPY_OUT, /* Copy Out data transfer in progress */
PGRES_COPY_IN, /* Copy In data transfer in progress */
PGRES_BAD_RESPONSE, /* an unexpected response was recv'd from
PGRES_FATAL_ERROR
} ExecStatusType;
-/* string descriptions of the ExecStatusTypes */
- extern const char *const pgresStatus[];
+/* String descriptions of the ExecStatusTypes */
+ extern const char * const pgresStatus[];
-/*
- * POSTGRES backend dependent Constants.
+/* PGconn encapsulates a connection to the backend.
+ * The contents of this struct are not supposed to be known to applications.
*/
+ typedef struct pg_conn PGconn;
-/* ERROR_MSG_LENGTH should really be the same as ELOG_MAXLEN in utils/elog.h*/
-#define ERROR_MSG_LENGTH 4096
-#define CMDSTATUS_LEN 40
-
-/* PGresult and the subsidiary types PGresAttDesc, PGresAttValue
- * represent the result of a query (or more precisely, of a single SQL
- * command --- a query string given to PQexec can contain multiple commands).
- * Note we assume that a single command can return at most one tuple group,
- * hence there is no need for multiple descriptor sets.
+/* PGresult encapsulates the result of a query (or more precisely, of a single
+ * SQL command --- a query string given to PQsendQuery can contain multiple
+ * commands and thus return multiple PGresult objects).
+ * The contents of this struct are not supposed to be known to applications.
*/
+ typedef struct pg_result PGresult;
- typedef struct pgresAttDesc
- {
- char *name; /* type name */
- Oid typid; /* type id */
- short typlen; /* type size */
- int atttypmod; /* type-specific modifier info */
- } PGresAttDesc;
-
-/* use char* for Attribute values,
- ASCII tuples are guaranteed to be null-terminated
- For binary tuples, the first four bytes of the value is the size,
- and the bytes afterwards are the value. The binary value is
- not guaranteed to be null-terminated. In fact, it can have embedded nulls
+/* PGnotify represents the occurrence of a NOTIFY message.
+ * Ideally this would be an opaque typedef, but it's so simple that it's
+ * unlikely to change.
*/
-
-#define NULL_LEN (-1) /* pg_result len for NULL value */
-
- typedef struct pgresAttValue
- {
- int len; /* length in bytes of the value */
- char *value; /* actual value */
- } PGresAttValue;
-
- struct pg_conn; /* forward reference */
-
- typedef struct pg_result
- {
- int ntups;
- int numAttributes;
- PGresAttDesc *attDescs;
- PGresAttValue **tuples; /* each PGresTuple is an array of
- * PGresAttValue's */
- int tupArrSize; /* size of tuples array allocated */
- ExecStatusType resultStatus;
- char cmdStatus[CMDSTATUS_LEN]; /* cmd status from the
- * last insert query */
- int binary; /* binary tuple values if binary == 1,
- * otherwise ASCII */
- struct pg_conn *conn; /* connection we did the query on */
- } PGresult;
-
-/* PGnotify represents the occurrence of a NOTIFY message */
typedef struct pgNotify
{
char relname[NAMEDATALEN]; /* name of relation
* containing data */
- int be_pid; /* process id of backend */
+ int be_pid; /* process id of backend */
} PGnotify;
-/* PQnoticeProcessor is a typedef for a callback function type */
- typedef void (*PQnoticeProcessor) (void *arg, const char *message);
-
-/* PGAsyncStatusType is private to libpq, really shouldn't be seen by users */
- typedef enum
- {
- PGASYNC_IDLE, /* nothing's happening, dude */
- PGASYNC_BUSY, /* query in progress */
- PGASYNC_READY, /* result ready for PQgetResult */
- PGASYNC_COPY_IN, /* Copy In data transfer in progress */
- PGASYNC_COPY_OUT /* Copy Out data transfer in progress */
- } PGAsyncStatusType;
-
-/* generic socket address type for PGconn connection information.
- * Really shouldn't be visible to users */
- typedef union PGSockAddr
- {
- struct sockaddr sa;
- struct sockaddr_in in;
-#ifndef WIN32
- struct sockaddr_un un;
-#endif
- } PGSockAddr;
-
-/* large-object-access data ... allocated only if large-object code is used.
- * Really shouldn't be visible to users */
- typedef struct pgLobjfuncs
- {
- Oid fn_lo_open; /* OID of backend function lo_open */
- Oid fn_lo_close;/* OID of backend function lo_close */
- Oid fn_lo_creat;/* OID of backend function lo_creat */
- Oid fn_lo_unlink; /* OID of backend function
- * lo_unlink */
- Oid fn_lo_lseek;/* OID of backend function lo_lseek */
- Oid fn_lo_tell; /* OID of backend function lo_tell */
- Oid fn_lo_read; /* OID of backend function LOread */
- Oid fn_lo_write;/* OID of backend function LOwrite */
- } PGlobjfuncs;
-
-/* PGconn encapsulates a connection to the backend.
- * XXX contents of this struct really shouldn't be visible to applications,
- * but we might break some existing applications if we tried to make it
- * completely opaque.
+/* PQnoticeProcessor is the function type for the notice-message callback.
*/
- typedef struct pg_conn
- {
- /* Saved values of connection options */
- char *pghost; /* the machine on which the server is
- * running */
- char *pgport; /* the server's communication port */
- char *pgtty; /* tty on which the backend messages is
- * displayed (NOT ACTUALLY USED???) */
- char *pgoptions; /* options to start the backend with */
- char *dbName; /* database name */
- char *pguser; /* Postgres username and password, if any */
- char *pgpass;
-
- /* Optional file to write trace info to */
- FILE *Pfdebug;
-
- /* Callback procedure for notice/error message processing */
- PQnoticeProcessor noticeHook;
- void *noticeArg;
-
- /* Status indicators */
- ConnStatusType status;
- PGAsyncStatusType asyncStatus;
- Dllist *notifyList; /* Notify msgs not yet handed to
- * application */
-
- /* Connection data */
- int sock; /* Unix FD for socket, -1 if not connected */
- PGSockAddr laddr; /* Local address */
- PGSockAddr raddr; /* Remote address */
- int raddr_len; /* Length of remote address */
-
- /* Miscellaneous stuff */
- int be_pid; /* PID of backend --- needed for cancels */
- int be_key; /* key of backend --- needed for cancels */
- char salt[2]; /* password salt received from backend */
- PGlobjfuncs *lobjfuncs; /* private state for large-object access
- * fns */
-
- /* Buffer for data received from backend and not yet processed */
- char *inBuffer; /* currently allocated buffer */
- int inBufSize; /* allocated size of buffer */
- int inStart; /* offset to first unconsumed data in
- * buffer */
- int inCursor; /* next byte to tentatively consume */
- int inEnd; /* offset to first position after avail
- * data */
-
- /* Buffer for data not yet sent to backend */
- char *outBuffer; /* currently allocated buffer */
- int outBufSize; /* allocated size of buffer */
- int outCount; /* number of chars waiting in buffer */
-
- /* Status for asynchronous result construction */
- PGresult *result; /* result being constructed */
- PGresAttValue *curTuple;/* tuple currently being read */
-
- /*
- * Message space. Placed last for code-size reasons. errorMessage
- * is the message last returned to the application. When
- * asyncStatus=READY, asyncErrorMessage is the pending message
- * that will be put in errorMessage by PQgetResult.
- */
- char errorMessage[ERROR_MSG_LENGTH];
- char asyncErrorMessage[ERROR_MSG_LENGTH];
- } PGconn;
- /*
- * We can't use the conventional "bool", because we are designed to be
- * included in a user's program, and user may already have that type
- * defined. Pqbool, on the other hand, is unlikely to be used.
- */
-
- typedef char pqbool;
+typedef void (*PQnoticeProcessor) (void * arg, const char * message);
/* Print options for PQprint() */
+
+ /*
+ * We can't use the conventional "bool", because we are designed to be
+ * included in a user's program, and user may already have that type
+ * defined. Pqbool, on the other hand, is unlikely to be used.
+ */
+ typedef char pqbool;
typedef struct _PQprintOpt
{
* field names */
} PQprintOpt;
-/* ----------------
- * PQArgBlock -- structure for PQfn() arguments
- * ----------------
- */
- typedef struct
- {
- int len;
- int isint;
- union
- {
- int *ptr; /* can't use void (dec compiler barfs) */
- int integer;
- } u;
- } PQArgBlock;
-
/* ----------------
* Structure for the conninfo parameter definitions returned by PQconndefaults
* ----------------
char *val; /* Options value */
char *label; /* Label for field in connect dialog */
char *dispchar; /* Character to display for this field */
- /* in a connect dialog. Values are: */
- /* "" Display entered value as is */
- /* "*" Password field - hide value */
- /* "D" Debug options - don't */
- /* create a field by default */
+ /* in a connect dialog. Values are: */
+ /* "" Display entered value as is */
+ /* "*" Password field - hide value */
+ /* "D" Debug options - don't */
+ /* create a field by default */
int dispsize; /* Field size in characters for dialog */
} PQconninfoOption;
+/* ----------------
+ * PQArgBlock -- structure for PQfn() arguments
+ * ----------------
+ */
+ typedef struct
+ {
+ int len;
+ int isint;
+ union
+ {
+ int *ptr; /* can't use void (dec compiler barfs) */
+ int integer;
+ } u;
+ } PQArgBlock;
+
/* ----------------
* Exported functions of libpq
* ----------------
/* Accessor functions for PGconn objects */
extern char *PQdb(PGconn *conn);
extern char *PQuser(PGconn *conn);
+ extern char *PQpass(PGconn *conn);
extern char *PQhost(PGconn *conn);
- extern char *PQoptions(PGconn *conn);
extern char *PQport(PGconn *conn);
extern char *PQtty(PGconn *conn);
+ extern char *PQoptions(PGconn *conn);
extern ConnStatusType PQstatus(PGconn *conn);
extern char *PQerrorMessage(PGconn *conn);
extern int PQsocket(PGconn *conn);
+ extern int PQsocket(PGconn *conn);
+ extern int PQbackendPID(PGconn *conn);
/* Enable/disable tracing */
extern void PQtrace(PGconn *conn, FILE *debug_port);
/* Routines for managing an asychronous query */
extern int PQisBusy(PGconn *conn);
- extern void PQconsumeInput(PGconn *conn);
+ extern int PQconsumeInput(PGconn *conn);
/* Routines for copy in/out */
extern int PQgetline(PGconn *conn, char *string, int length);
- extern void PQputline(PGconn *conn, const char *string);
- extern void PQputnbytes(PGconn *conn, const char *buffer, int nbytes);
+ extern int PQputline(PGconn *conn, const char *string);
+ extern int PQgetlineAsync(PGconn *conn, char *buffer, int bufsize);
+ extern int PQputnbytes(PGconn *conn, const char *buffer, int nbytes);
extern int PQendcopy(PGconn *conn);
/*
extern ExecStatusType PQresultStatus(PGresult *res);
extern int PQntuples(PGresult *res);
extern int PQnfields(PGresult *res);
+ extern int PQbinaryTuples(PGresult *res);
extern char *PQfname(PGresult *res, int field_num);
extern int PQfnumber(PGresult *res, const char *field_name);
extern Oid PQftype(PGresult *res, int field_num);
- extern short PQfsize(PGresult *res, int field_num);
+ extern int PQfsize(PGresult *res, int field_num);
extern int PQfmod(PGresult *res, int field_num);
extern char *PQcmdStatus(PGresult *res);
extern const char *PQoidStatus(PGresult *res);
/* Delete a PGresult */
extern void PQclear(PGresult *res);
+ /* Make an empty PGresult with given status (some apps find this useful) */
+ extern PGresult * PQmakeEmptyPGresult(PGconn *conn, ExecStatusType status);
+
/* === in fe-print.c === */
extern void PQprint(FILE *fout, /* output stream */
* This file contains internal definitions meant to be used only by
* the frontend libpq library, not by applications that call it.
*
+ * An application can include this file if it wants to bypass the
+ * official API defined by libpq-fe.h, but code that does so is much
+ * more likely to break across PostgreSQL releases than code that uses
+ * only the official API.
+ *
* Copyright (c) 1994, Regents of the University of California
*
- * $Id: libpq-int.h,v 1.2 1998/09/01 04:40:12 momjian Exp $
+ * $Id: libpq-int.h,v 1.3 1998/09/03 02:10:53 momjian Exp $
*
*-------------------------------------------------------------------------
*/
* ----------------
*/
#include "libpq/pqcomm.h"
+#include "lib/dllist.h"
/* libpq supports this version of the frontend/backend protocol.
*
#define PG_PROTOCOL_LIBPQ PG_PROTOCOL(2,0)
+/*
+ * 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
+
+/* PGresult and the subsidiary types PGresAttDesc, PGresAttValue
+ * represent the result of a query (or more precisely, of a single SQL
+ * command --- a query string given to PQexec can contain multiple commands).
+ * Note we assume that a single command can return at most one tuple group,
+ * hence there is no need for multiple descriptor sets.
+ */
+ typedef struct pgresAttDesc
+ {
+ char *name; /* type name */
+ Oid typid; /* type id */
+ int typlen; /* type size */
+ int atttypmod; /* type-specific modifier info */
+ } PGresAttDesc;
+
+/* use char* for Attribute values,
+ ASCII tuples are guaranteed to be null-terminated
+ For binary tuples, the first four bytes of the value is the size,
+ and the bytes afterwards are the value. The binary value is
+ not guaranteed to be null-terminated. In fact, it can have embedded nulls
+ */
+
+#define NULL_LEN (-1) /* pg_result len for NULL value */
+
+ typedef struct pgresAttValue
+ {
+ int len; /* length in bytes of the value */
+ char *value; /* actual value */
+ } PGresAttValue;
+
+ struct pg_result
+ {
+ int ntups;
+ int numAttributes;
+ PGresAttDesc *attDescs;
+ PGresAttValue **tuples; /* each PGresTuple is an array of
+ * PGresAttValue's */
+ int tupArrSize; /* size of tuples array allocated */
+ ExecStatusType resultStatus;
+ char cmdStatus[CMDSTATUS_LEN]; /* cmd status from the
+ * last insert query */
+ int binary; /* binary tuple values if binary == 1,
+ * otherwise ASCII */
+ PGconn *conn; /* connection we did the query on */
+ };
+
+/* PGAsyncStatusType defines the state of the query-execution state machine */
+ typedef enum
+ {
+ PGASYNC_IDLE, /* nothing's happening, dude */
+ PGASYNC_BUSY, /* query in progress */
+ PGASYNC_READY, /* result ready for PQgetResult */
+ PGASYNC_COPY_IN, /* Copy In data transfer in progress */
+ PGASYNC_COPY_OUT /* Copy Out data transfer in progress */
+ } PGAsyncStatusType;
+
+/* large-object-access data ... allocated only if large-object code is used. */
+ typedef struct pgLobjfuncs
+ {
+ Oid fn_lo_open; /* OID of backend function lo_open */
+ Oid fn_lo_close;/* OID of backend function lo_close */
+ Oid fn_lo_creat;/* OID of backend function lo_creat */
+ Oid fn_lo_unlink; /* OID of backend function
+ * lo_unlink */
+ Oid fn_lo_lseek;/* OID of backend function lo_lseek */
+ Oid fn_lo_tell; /* OID of backend function lo_tell */
+ Oid fn_lo_read; /* OID of backend function LOread */
+ Oid fn_lo_write;/* OID of backend function LOwrite */
+ } PGlobjfuncs;
+
+/* PGconn stores all the state data associated with a single connection
+ * to a backend.
+ */
+ struct pg_conn
+ {
+ /* Saved values of connection options */
+ char *pghost; /* the machine on which the server is
+ * running */
+ char *pgport; /* the server's communication port */
+ char *pgtty; /* tty on which the backend messages is
+ * displayed (NOT ACTUALLY USED???) */
+ char *pgoptions; /* options to start the backend with */
+ char *dbName; /* database name */
+ char *pguser; /* Postgres username and password, if any */
+ char *pgpass;
+
+ /* Optional file to write trace info to */
+ FILE *Pfdebug;
+
+ /* Callback procedure for notice/error message processing */
+ PQnoticeProcessor noticeHook;
+ void *noticeArg;
+
+ /* Status indicators */
+ ConnStatusType status;
+ PGAsyncStatusType asyncStatus;
+ Dllist *notifyList; /* Notify msgs not yet handed to application */
+
+ /* Connection data */
+ int sock; /* Unix FD for socket, -1 if not connected */
+ SockAddr laddr; /* Local address */
+ SockAddr raddr; /* Remote address */
+ int raddr_len; /* Length of remote address */
+
+ /* Miscellaneous stuff */
+ int be_pid; /* PID of backend --- needed for cancels */
+ int be_key; /* key of backend --- needed for cancels */
+ char salt[2]; /* password salt received from backend */
+ PGlobjfuncs *lobjfuncs; /* private state for large-object access fns */
+
+ /* Buffer for data received from backend and not yet processed */
+ char *inBuffer; /* currently allocated buffer */
+ int inBufSize; /* allocated size of buffer */
+ int inStart; /* offset to first unconsumed data in buffer */
+ int inCursor; /* next byte to tentatively consume */
+ int inEnd; /* offset to first position after avail data */
+
+ /* Buffer for data not yet sent to backend */
+ char *outBuffer; /* currently allocated buffer */
+ int outBufSize; /* allocated size of buffer */
+ int outCount; /* number of chars waiting in buffer */
+
+ /* Status for asynchronous result construction */
+ PGresult *result; /* result being constructed */
+ PGresAttValue *curTuple; /* tuple currently being read */
+
+ /* Message space. Placed last for code-size reasons.
+ * errorMessage is the message last returned to the application.
+ * When asyncStatus=READY, asyncErrorMessage is the pending message
+ * that will be put in errorMessage by PQgetResult. */
+ char errorMessage[ERROR_MSG_LENGTH];
+ char asyncErrorMessage[ERROR_MSG_LENGTH];
+ };
+
/* ----------------
* Internal functions of libpq
* Functions declared here need to be visible across files of libpq,
PQrequestCancel @ 6
PQdb @ 7
PQuser @ 8
- PQhost @ 9
- PQoptions @ 10
+ PQpass @ 9
+ PQhost @ 10
PQport @ 11
PQtty @ 12
- PQstatus @ 13
- PQerrorMessage @ 14
- PQsocket @ 15
- PQtrace @ 16
- PQuntrace @ 17
- PQsetNoticeProcessor @ 18
- PQexec @ 19
- PQnotifies @ 20
- PQsendQuery @ 21
- PQgetResult @ 22
- PQisBusy @ 23
- PQconsumeInput @ 24
- PQgetline @ 25
- PQputline @ 26
- PQputnbytes @ 27
- PQendcopy @ 28
- PQfn @ 29
- PQresultStatus @ 30
- PQntuples @ 31
- PQnfields @ 32
- PQfname @ 33
- PQfnumber @ 34
- PQftype @ 35
- PQfsize @ 36
- PQfmod @ 37
- PQcmdStatus @ 38
- PQoidStatus @ 39
- PQcmdTuples @ 40
- PQgetvalue @ 41
- PQgetlength @ 42
- PQgetisnull @ 43
- PQclear @ 44
- PQprint @ 45
- PQdisplayTuples @ 46
- PQprintTuples @ 47
- lo_open @ 48
- lo_close @ 49
- lo_read @ 50
- lo_write @ 51
- lo_lseek @ 52
- lo_creat @ 53
- lo_tell @ 54
- lo_unlink @ 55
- lo_import @ 56
- lo_export @ 57
+ PQoptions @ 13
+ PQstatus @ 14
+ PQerrorMessage @ 15
+ PQsocket @ 16
+ PQbackendPID @ 17
+ PQtrace @ 18
+ PQuntrace @ 19
+ PQsetNoticeProcessor @ 20
+ PQexec @ 21
+ PQnotifies @ 22
+ PQsendQuery @ 23
+ PQgetResult @ 24
+ PQisBusy @ 25
+ PQconsumeInput @ 26
+ PQgetline @ 27
+ PQputline @ 28
+ PQgetlineAsync @ 29
+ PQputnbytes @ 30
+ PQendcopy @ 31
+ PQfn @ 32
+ PQresultStatus @ 33
+ PQntuples @ 34
+ PQnfields @ 35
+ PQbinaryTuples @ 36
+ PQfname @ 37
+ PQfnumber @ 38
+ PQftype @ 39
+ PQfsize @ 40
+ PQfmod @ 41
+ PQcmdStatus @ 42
+ PQoidStatus @ 43
+ PQcmdTuples @ 44
+ PQgetvalue @ 45
+ PQgetlength @ 46
+ PQgetisnull @ 47
+ PQclear @ 48
+ PQmakeEmptyPGresult @ 49
+ PQprint @ 50
+ PQdisplayTuples @ 51
+ PQprintTuples @ 52
+ lo_open @ 53
+ lo_close @ 54
+ lo_read @ 55
+ lo_write @ 56
+ lo_lseek @ 57
+ lo_creat @ 58
+ lo_tell @ 59
+ lo_unlink @ 60
+ lo_import @ 61
+ lo_export @ 62
/*-------------------------------------------------------
*
- * $Id: Pg.xs,v 1.7 1998/06/01 16:41:19 mergl Exp $
+ * $Id: Pg.xs,v 1.8 1998/09/03 02:10:56 momjian Exp $
*
* Copyright (c) 1997, 1998 Edmund Mergl
*
char * query
CODE:
RETVAL = PQexec(conn, query);
- if (! RETVAL) { RETVAL = (PGresult *)calloc(1, sizeof(PGresult)); }
+ if (! RETVAL) { RETVAL = PQmakeEmptyPGresult(conn, PGRES_FATAL_ERROR); }
OUTPUT:
RETVAL
if (RETVAL) {
RETVAL->result = PQexec((PGconn *)conn, query);
if (!RETVAL->result) {
- RETVAL->result = (PG_result)calloc(1, sizeof(PGresult));
+ RETVAL->result = PQmakeEmptyPGresult(conn, PGRES_FATAL_ERROR);
}
}
OUTPUT: