Commit f71d0cf6 authored by Bruce Momjian's avatar Bruce Momjian

Attached is a patch to remove the definitions of libpq's internal

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.
parent bcc15f15
...@@ -21,7 +21,7 @@ ...@@ -21,7 +21,7 @@
* *
* *
* IDENTIFICATION * 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 $
* *
* Modifications - 6/10/96 - dave@bensoft.com - version 1.13.dhb * Modifications - 6/10/96 - dave@bensoft.com - version 1.13.dhb
* *
...@@ -255,7 +255,7 @@ dumpClasses_nodumpData(FILE *fout, const char *classname, const bool oids) ...@@ -255,7 +255,7 @@ dumpClasses_nodumpData(FILE *fout, const char *classname, const bool oids)
copydone = false; copydone = false;
while (!copydone) while (!copydone)
{ {
ret = PQgetline(res->conn, copybuf, COPYBUFSIZ); ret = PQgetline(g_conn, copybuf, COPYBUFSIZ);
if (copybuf[0] == '\\' && if (copybuf[0] == '\\' &&
copybuf[1] == '.' && copybuf[1] == '.' &&
...@@ -281,7 +281,7 @@ dumpClasses_nodumpData(FILE *fout, const char *classname, const bool oids) ...@@ -281,7 +281,7 @@ dumpClasses_nodumpData(FILE *fout, const char *classname, const bool oids)
} }
fprintf(fout, "\\.\n"); fprintf(fout, "\\.\n");
} }
ret = PQendcopy(res->conn); ret = PQendcopy(g_conn);
if (ret != 0) if (ret != 0)
{ {
fprintf(stderr, "SQL query to dump the contents of Table '%s' " fprintf(stderr, "SQL query to dump the contents of Table '%s' "
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* *
* *
* IDENTIFICATION * 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 $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -148,7 +148,7 @@ struct winsize ...@@ -148,7 +148,7 @@ struct winsize
/* declarations for functions in this file */ /* declarations for functions in this file */
static void usage(char *progname); static void usage(char *progname);
static void slashUsage(); 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, static bool handleCopyIn(PGresult *res, const bool mustprompt,
FILE *copystream); FILE *copystream);
static int tableList(PsqlSettings *pset, bool deep_tablelist, static int tableList(PsqlSettings *pset, bool deep_tablelist,
...@@ -1125,20 +1125,20 @@ SendQuery(bool *success_p, PsqlSettings *pset, const char *query, ...@@ -1125,20 +1125,20 @@ SendQuery(bool *success_p, PsqlSettings *pset, const char *query,
break; break;
case PGRES_COPY_OUT: case PGRES_COPY_OUT:
if (copy_out) if (copy_out)
*success_p = handleCopyOut(results, copystream); *success_p = handleCopyOut(pset->db, copystream);
else else
{ {
if (!pset->quiet) if (!pset->quiet)
printf("Copy command returns...\n"); printf("Copy command returns...\n");
*success_p = handleCopyOut(results, stdout); *success_p = handleCopyOut(pset->db, stdout);
} }
break; break;
case PGRES_COPY_IN: case PGRES_COPY_IN:
if (copy_in) if (copy_in)
*success_p = handleCopyIn(results, false, copystream); *success_p = handleCopyIn(pset->db, false, copystream);
else else
*success_p = handleCopyIn(results, *success_p = handleCopyIn(pset->db,
!pset->quiet && !pset->notty, !pset->quiet && !pset->notty,
stdin); stdin);
break; break;
...@@ -1437,11 +1437,8 @@ do_connect(const char *new_dbname, ...@@ -1437,11 +1437,8 @@ do_connect(const char *new_dbname,
else else
userparam = PQuser(olddb); userparam = PQuser(olddb);
/* /* FIXME: if changing user, ought to prompt for a new password? */
* libpq doesn't provide an accessor function for the password, so pwparam = PQpass(olddb);
* we cheat here.
*/
pwparam = olddb->pgpass;
pset->db = PQsetdbLogin(PQhost(olddb), PQport(olddb), pset->db = PQsetdbLogin(PQhost(olddb), PQport(olddb),
NULL, NULL, dbparam, userparam, pwparam); NULL, NULL, dbparam, userparam, pwparam);
...@@ -2915,7 +2912,7 @@ main(int argc, char **argv) ...@@ -2915,7 +2912,7 @@ main(int argc, char **argv)
#define COPYBUFSIZ 8192 #define COPYBUFSIZ 8192
static bool static bool
handleCopyOut(PGresult *res, FILE *copystream) handleCopyOut(PGconn *conn, FILE *copystream)
{ {
bool copydone; bool copydone;
char copybuf[COPYBUFSIZ]; char copybuf[COPYBUFSIZ];
...@@ -2925,7 +2922,7 @@ handleCopyOut(PGresult *res, FILE *copystream) ...@@ -2925,7 +2922,7 @@ handleCopyOut(PGresult *res, FILE *copystream)
while (!copydone) while (!copydone)
{ {
ret = PQgetline(res->conn, copybuf, COPYBUFSIZ); ret = PQgetline(conn, copybuf, COPYBUFSIZ);
if (copybuf[0] == '\\' && if (copybuf[0] == '\\' &&
copybuf[1] == '.' && copybuf[1] == '.' &&
...@@ -2950,13 +2947,13 @@ handleCopyOut(PGresult *res, FILE *copystream) ...@@ -2950,13 +2947,13 @@ handleCopyOut(PGresult *res, FILE *copystream)
} }
} }
fflush(copystream); fflush(copystream);
return !PQendcopy(res->conn); return ! PQendcopy(conn);
} }
static bool static bool
handleCopyIn(PGresult *res, const bool mustprompt, FILE *copystream) handleCopyIn(PGconn *conn, const bool mustprompt, FILE *copystream)
{ {
bool copydone = false; bool copydone = false;
bool firstload; bool firstload;
...@@ -2991,12 +2988,12 @@ handleCopyIn(PGresult *res, const bool mustprompt, FILE *copystream) ...@@ -2991,12 +2988,12 @@ handleCopyIn(PGresult *res, const bool mustprompt, FILE *copystream)
*s++ = c; *s++ = c;
if (c == EOF) if (c == EOF)
{ {
PQputline(res->conn, "\\."); PQputline(conn, "\\.");
copydone = true; copydone = true;
break; break;
} }
*s = '\0'; *s = '\0';
PQputline(res->conn, copybuf); PQputline(conn, copybuf);
if (firstload) if (firstload)
{ {
if (!strcmp(copybuf, "\\.")) if (!strcmp(copybuf, "\\."))
...@@ -3004,9 +3001,9 @@ handleCopyIn(PGresult *res, const bool mustprompt, FILE *copystream) ...@@ -3004,9 +3001,9 @@ handleCopyIn(PGresult *res, const bool mustprompt, FILE *copystream)
firstload = false; firstload = false;
} }
} }
PQputline(res->conn, "\n"); PQputline(conn, "\n");
} }
return !PQendcopy(res->conn); return ! PQendcopy(conn);
} }
......
...@@ -814,11 +814,11 @@ ECPGexecute(struct statement * stmt) ...@@ -814,11 +814,11 @@ ECPGexecute(struct statement * stmt)
break; break;
case PGRES_COPY_OUT: case PGRES_COPY_OUT:
ECPGlog("ECPGexecute line %d: Got PGRES_COPY_OUT ... tossing.\n", stmt->lineno); ECPGlog("ECPGexecute line %d: Got PGRES_COPY_OUT ... tossing.\n", stmt->lineno);
PQendcopy(results->conn); PQendcopy(actual_connection->connection);
break; break;
case PGRES_COPY_IN: case PGRES_COPY_IN:
ECPGlog("ECPGexecute line %d: Got PGRES_COPY_IN ... tossing.\n", stmt->lineno); ECPGlog("ECPGexecute line %d: Got PGRES_COPY_IN ... tossing.\n", stmt->lineno);
PQendcopy(results->conn); PQendcopy(actual_connection->connection);
break; break;
default: default:
ECPGlog("ECPGexecute line %d: Got something else, postgres error.\n", ECPGlog("ECPGexecute line %d: Got something else, postgres error.\n",
...@@ -995,7 +995,7 @@ ECPGlog(const char *format,...) ...@@ -995,7 +995,7 @@ ECPGlog(const char *format,...)
if (!f) if (!f)
return; return;
sprintf(f, "[%d]: %s", getpid(), format); sprintf(f, "[%d]: %s", (int) getpid(), format);
va_start(ap, format); va_start(ap, format);
vfprintf(debugstream, f, ap); vfprintf(debugstream, f, ap);
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* *
* *
* IDENTIFICATION * 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 $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -358,15 +358,15 @@ Pg_connect(ClientData cData, Tcl_Interp * interp, int argc, char *argv[]) ...@@ -358,15 +358,15 @@ Pg_connect(ClientData cData, Tcl_Interp * interp, int argc, char *argv[])
conn = PQsetdb(pghost, pgport, pgoptions, pgtty, dbName); conn = PQsetdb(pghost, pgport, pgoptions, pgtty, dbName);
} }
if (conn->status == CONNECTION_OK) if (PQstatus(conn) == CONNECTION_OK) {
{ {
PgSetConnectionId(interp, conn); PgSetConnectionId(interp, conn);
return TCL_OK; return TCL_OK;
} }
else else
{ {
Tcl_AppendResult(interp, "Connection to database failed\n", 0); Tcl_AppendResult(interp, "Connection to database failed\n",
Tcl_AppendResult(interp, conn->errorMessage, 0); PQerrorMessage(conn), 0);
PQfinish(conn); PQfinish(conn);
return TCL_ERROR; return TCL_ERROR;
} }
...@@ -423,7 +423,6 @@ Pg_exec(ClientData cData, Tcl_Interp * interp, int argc, char *argv[]) ...@@ -423,7 +423,6 @@ Pg_exec(ClientData cData, Tcl_Interp * interp, int argc, char *argv[])
Pg_ConnectionId *connid; Pg_ConnectionId *connid;
PGconn *conn; PGconn *conn;
PGresult *result; PGresult *result;
int connStatus;
if (argc != 3) if (argc != 3)
{ {
...@@ -442,7 +441,6 @@ Pg_exec(ClientData cData, Tcl_Interp * interp, int argc, char *argv[]) ...@@ -442,7 +441,6 @@ Pg_exec(ClientData cData, Tcl_Interp * interp, int argc, char *argv[])
return TCL_ERROR; return TCL_ERROR;
} }
connStatus = conn->status;
result = PQexec(conn, argv[2]); result = PQexec(conn, argv[2]);
/* Transfer any notify events from libpq to Tcl event queue. */ /* Transfer any notify events from libpq to Tcl event queue. */
...@@ -452,8 +450,8 @@ Pg_exec(ClientData cData, Tcl_Interp * interp, int argc, char *argv[]) ...@@ -452,8 +450,8 @@ Pg_exec(ClientData cData, Tcl_Interp * interp, int argc, char *argv[])
{ {
int rId = PgSetResultId(interp, argv[1], result); int rId = PgSetResultId(interp, argv[1], result);
if (result->resultStatus == PGRES_COPY_IN || ExecStatusType rStat = PQresultStatus(result);
result->resultStatus == PGRES_COPY_OUT) if (rStat == PGRES_COPY_IN || rStat == PGRES_COPY_OUT)
{ {
connid->res_copyStatus = RES_COPY_INPROGRESS; connid->res_copyStatus = RES_COPY_INPROGRESS;
connid->res_copy = rId; connid->res_copy = rId;
...@@ -463,7 +461,7 @@ Pg_exec(ClientData cData, Tcl_Interp * interp, int argc, char *argv[]) ...@@ -463,7 +461,7 @@ Pg_exec(ClientData cData, Tcl_Interp * interp, int argc, char *argv[])
else else
{ {
/* error occurred during the query */ /* error occurred during the query */
Tcl_SetResult(interp, conn->errorMessage, TCL_VOLATILE); Tcl_SetResult(interp, PQerrorMessage(conn), TCL_VOLATILE);
return TCL_ERROR; return TCL_ERROR;
} }
} }
...@@ -481,9 +479,12 @@ Pg_exec(ClientData cData, Tcl_Interp * interp, int argc, char *argv[]) ...@@ -481,9 +479,12 @@ Pg_exec(ClientData cData, Tcl_Interp * interp, int argc, char *argv[])
-conn -conn
the connection that produced the result the connection that produced the result
-assign arrayName -assign arrayName
assign the results to an array assign the results to an array, using subscripts of the form
-assignbyidx arrayName (tupno,attributeName)
assign the results to an array using the first field as a key -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 -numTuples
the number of tuples in the query the number of tuples in the query
-attributes -attributes
...@@ -509,6 +510,7 @@ Pg_result(ClientData cData, Tcl_Interp * interp, int argc, char *argv[]) ...@@ -509,6 +510,7 @@ Pg_result(ClientData cData, Tcl_Interp * interp, int argc, char *argv[])
int tupno; int tupno;
char *arrVar; char *arrVar;
char nameBuffer[256]; char nameBuffer[256];
const char *appendstr;
if (argc < 3 || argc > 5) if (argc < 3 || argc > 5)
{ {
...@@ -564,8 +566,9 @@ Pg_result(ClientData cData, Tcl_Interp * interp, int argc, char *argv[]) ...@@ -564,8 +566,9 @@ Pg_result(ClientData cData, Tcl_Interp * interp, int argc, char *argv[])
/* /*
* this assignment assigns the table of result tuples into a giant * this assignment assigns the table of result tuples into a giant
* array with the name given in the argument, the indices of the * array with the name given in the argument.
* array or (tupno,attrName). Note we expect field names not to * 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 * exceed a few dozen characters, so truncating to prevent buffer
* overflow shouldn't be a problem. * overflow shouldn't be a problem.
*/ */
...@@ -589,28 +592,32 @@ Pg_result(ClientData cData, Tcl_Interp * interp, int argc, char *argv[]) ...@@ -589,28 +592,32 @@ Pg_result(ClientData cData, Tcl_Interp * interp, int argc, char *argv[])
} }
else if (strcmp(opt, "-assignbyidx") == 0) 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; return TCL_ERROR;
} }
arrVar = argv[3]; arrVar = argv[3];
appendstr = (argc == 5) ? (const char *) argv[4] : "";
/* /*
* this assignment assigns the table of result tuples into a giant * this assignment assigns the table of result tuples into a giant
* array with the name given in the argument, the indices of the * array with the name given in the argument. The indices of the array
* array or (tupno,attrName). Here, we still assume PQfname won't * are of the form (field0Value,attrNameappendstr).
* exceed 200 characters, but we dare not make the same assumption * Here, we still assume PQfname won't exceed 200 characters,
* about the data in field 0. * 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++) for (tupno = 0; tupno < PQntuples(result); tupno++)
{ {
const char *field0 = PQgetvalue(result, tupno, 0); 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++) 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, if (Tcl_SetVar2(interp, arrVar, workspace,
PQgetvalue(result, tupno, i), PQgetvalue(result, tupno, i),
TCL_LEAVE_ERR_MSG) == NULL) TCL_LEAVE_ERR_MSG) == NULL)
...@@ -701,7 +708,7 @@ Pg_result_errReturn: ...@@ -701,7 +708,7 @@ Pg_result_errReturn:
"\t-status\n", "\t-status\n",
"\t-conn\n", "\t-conn\n",
"\t-assign arrayVarName\n", "\t-assign arrayVarName\n",
"\t-assignbyidx arrayVarName\n", "\t-assignbyidx arrayVarName ?appendstr?\n",
"\t-numTuples\n", "\t-numTuples\n",
"\t-numAttrs\n" "\t-numAttrs\n"
"\t-attributes\n" "\t-attributes\n"
...@@ -1238,7 +1245,7 @@ Pg_select(ClientData cData, Tcl_Interp * interp, int argc, char **argv) ...@@ -1238,7 +1245,7 @@ Pg_select(ClientData cData, Tcl_Interp * interp, int argc, char **argv)
if ((result = PQexec(conn, argv[2])) == 0) if ((result = PQexec(conn, argv[2])) == 0)
{ {
/* error occurred during the query */ /* error occurred during the query */
Tcl_SetResult(interp, conn->errorMessage, TCL_STATIC); Tcl_SetResult(interp, PQerrorMessage(conn), TCL_STATIC);
return TCL_ERROR; return TCL_ERROR;
} }
...@@ -1406,11 +1413,10 @@ Pg_listen(ClientData cData, Tcl_Interp * interp, int argc, char *argv[]) ...@@ -1406,11 +1413,10 @@ Pg_listen(ClientData cData, Tcl_Interp * interp, int argc, char *argv[])
ckfree(cmd); ckfree(cmd);
/* Transfer any notify events from libpq to Tcl event queue. */ /* Transfer any notify events from libpq to Tcl event queue. */
PgNotifyTransferEvents(connid); PgNotifyTransferEvents(connid);
if (!result || (result->resultStatus != PGRES_COMMAND_OK)) if (PQresultStatus(result) != PGRES_COMMAND_OK) {
{ {
/* Error occurred during the execution of command */ /* Error occurred during the execution of command */
if (result) PQclear(result);
PQclear(result);
ckfree(callback); ckfree(callback);
ckfree(caserelname); ckfree(caserelname);
Tcl_DeleteHashEntry(entry); Tcl_DeleteHashEntry(entry);
......
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
* *
* *
* IDENTIFICATION * 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 $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -33,98 +33,62 @@ PgEndCopy(Pg_ConnectionId * connid, int *errorCodePtr) ...@@ -33,98 +33,62 @@ PgEndCopy(Pg_ConnectionId * connid, int *errorCodePtr)
connid->res_copyStatus = RES_COPY_NONE; connid->res_copyStatus = RES_COPY_NONE;
if (PQendcopy(connid->conn)) 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; connid->res_copy = -1;
*errorCodePtr = EIO; *errorCodePtr = EIO;
return -1; return -1;
} }
else 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; connid->res_copy = -1;
return 0; return 0;
} }
} }
/* /*
* Called when reading data (via gets) for a copy <rel> to stdout. * Called when reading data (via gets) for a copy <rel> to stdout.
*
* NOTE: this routine knows way more than it ought to about libpq's
* internal buffering mechanisms.
*/ */
int int PgInputProc(DRIVER_INPUT_PROTO)
PgInputProc(DRIVER_INPUT_PROTO)
{ {
Pg_ConnectionId *connid; Pg_ConnectionId *connid;
PGconn *conn; PGconn *conn;
char c; int avail;
int avail;
connid = (Pg_ConnectionId *) cData; connid = (Pg_ConnectionId *)cData;
conn = connid->conn; conn = connid->conn;
if (connid->res_copy < 0 || if (connid->res_copy < 0 ||
connid->results[connid->res_copy]->resultStatus != PGRES_COPY_OUT) PQresultStatus(connid->results[connid->res_copy]) != PGRES_COPY_OUT)
{ {
*errorCodePtr = EBUSY; *errorCodePtr = EBUSY;
return -1; return -1;
} }
/* Try to load any newly arrived data */ /* Read any newly arrived data into libpq's buffer,
conn->errorMessage[0] = '\0'; * thereby clearing the socket's read-ready condition.
PQconsumeInput(conn); */
if (conn->errorMessage[0]) if (! PQconsumeInput(conn))
{ {
*errorCodePtr = EIO; *errorCodePtr = EIO;
return -1; return -1;
} }
/* /* Move data from libpq's buffer to Tcl's. */
* 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.)
*/
conn->inCursor = conn->inStart; avail = PQgetlineAsync(conn, buf, bufSize);
avail = bufSize; if (avail < 0)
while (avail > 0 && conn->inCursor < conn->inEnd)
{ {
c = conn->inBuffer[conn->inCursor++]; /* Endmarker detected, change state and return 0 */
*buf++ = c; return PgEndCopy(connid, errorCodePtr);
--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;
}
}
/* return 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 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;
} }
/* /*
...@@ -140,17 +104,13 @@ PgOutputProc(DRIVER_OUTPUT_PROTO) ...@@ -140,17 +104,13 @@ PgOutputProc(DRIVER_OUTPUT_PROTO)
conn = connid->conn; conn = connid->conn;
if (connid->res_copy < 0 || 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; *errorCodePtr = EBUSY;
return -1; return -1;
} }
conn->errorMessage[0] = '\0'; if (PQputnbytes(conn, buf, bufSize))
PQputnbytes(conn, buf, bufSize);
if (conn->errorMessage[0])
{ {
*errorCodePtr = EIO; *errorCodePtr = EIO;
return -1; return -1;
...@@ -398,7 +358,7 @@ getresid(Tcl_Interp * interp, char *id, Pg_ConnectionId ** connid_p) ...@@ -398,7 +358,7 @@ getresid(Tcl_Interp * interp, char *id, Pg_ConnectionId ** connid_p)
connid = (Pg_ConnectionId *) Tcl_GetChannelInstanceData(conn_chan); 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); Tcl_SetResult(interp, "Invalid result handle", TCL_STATIC);
return -1; return -1;
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* *
* *
* IDENTIFICATION * 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 $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -1384,6 +1384,14 @@ PQuser(PGconn *conn) ...@@ -1384,6 +1384,14 @@ PQuser(PGconn *conn)
return conn->pguser; return conn->pguser;
} }
char *
PQpass(PGconn *conn)
{
if (!conn)
return (char *) NULL;
return conn->pgpass;
}
char * char *
PQhost(PGconn *conn) PQhost(PGconn *conn)
{ {
...@@ -1393,11 +1401,11 @@ PQhost(PGconn *conn) ...@@ -1393,11 +1401,11 @@ PQhost(PGconn *conn)
} }
char * char *
PQoptions(PGconn *conn) PQport(PGconn *conn)
{ {
if (!conn) if (!conn)
return (char *) NULL; return (char *) NULL;
return conn->pgoptions; return conn->pgport;
} }
char * char *
...@@ -1409,11 +1417,11 @@ PQtty(PGconn *conn) ...@@ -1409,11 +1417,11 @@ PQtty(PGconn *conn)
} }
char * char *
PQport(PGconn *conn) PQoptions(PGconn *conn)
{ {
if (!conn) if (!conn)
return (char *) NULL; return (char *) NULL;
return conn->pgport; return conn->pgoptions;
} }
ConnStatusType ConnStatusType
...@@ -1442,6 +1450,14 @@ PQsocket(PGconn *conn) ...@@ -1442,6 +1450,14 @@ PQsocket(PGconn *conn)
return conn->sock; return conn->sock;
} }
int
PQbackendPID(PGconn *conn)
{
if (!conn || conn->status != CONNECTION_OK)
return 0;
return conn->be_pid;
}
void void
PQtrace(PGconn *conn, FILE *debug_port) PQtrace(PGconn *conn, FILE *debug_port)
{ {
......
This diff is collapsed.
...@@ -24,7 +24,7 @@ ...@@ -24,7 +24,7 @@
* *
* *
* IDENTIFICATION * 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 $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -174,15 +174,14 @@ pqGetnchar(char *s, int len, PGconn *conn) ...@@ -174,15 +174,14 @@ pqGetnchar(char *s, int len, PGconn *conn)
conn->inCursor += len; conn->inCursor += len;
if (conn->Pfdebug) 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; return 0;
} }
/* --------------------------------------------------------------------- */ /* --------------------------------------------------------------------- */
/* pqPutnchar: /* pqPutnchar:
send a string of exactly len bytes send a string of exactly len bytes, no null termination needed
The buffer should have a terminating null, but it's not sent.
*/ */
int int
pqPutnchar(const char *s, int len, PGconn *conn) pqPutnchar(const char *s, int len, PGconn *conn)
...@@ -191,7 +190,7 @@ pqPutnchar(const char *s, int len, PGconn *conn) ...@@ -191,7 +190,7 @@ pqPutnchar(const char *s, int len, PGconn *conn)
return EOF; return EOF;
if (conn->Pfdebug) if (conn->Pfdebug)
fprintf(conn->Pfdebug, "To backend> %s\n", s); fprintf(conn->Pfdebug, "To backend> %.*s\n", len, s);
return 0; return 0;
} }
......
This diff is collapsed.
...@@ -4,9 +4,14 @@ ...@@ -4,9 +4,14 @@
* This file contains internal definitions meant to be used only by * This file contains internal definitions meant to be used only by
* the frontend libpq library, not by applications that call it. * 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 * 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 $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -21,6 +26,7 @@ ...@@ -21,6 +26,7 @@
* ---------------- * ----------------
*/ */
#include "libpq/pqcomm.h" #include "libpq/pqcomm.h"
#include "lib/dllist.h"
/* libpq supports this version of the frontend/backend protocol. /* libpq supports this version of the frontend/backend protocol.
* *
...@@ -35,6 +41,147 @@ ...@@ -35,6 +41,147 @@
#define PG_PROTOCOL_LIBPQ PG_PROTOCOL(2,0) #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 * Internal functions of libpq
* Functions declared here need to be visible across files of libpq, * Functions declared here need to be visible across files of libpq,
......
...@@ -9,52 +9,57 @@ EXPORTS ...@@ -9,52 +9,57 @@ EXPORTS
PQrequestCancel @ 6 PQrequestCancel @ 6
PQdb @ 7 PQdb @ 7
PQuser @ 8 PQuser @ 8
PQhost @ 9 PQpass @ 9
PQoptions @ 10 PQhost @ 10
PQport @ 11 PQport @ 11
PQtty @ 12 PQtty @ 12
PQstatus @ 13 PQoptions @ 13
PQerrorMessage @ 14 PQstatus @ 14
PQsocket @ 15 PQerrorMessage @ 15
PQtrace @ 16 PQsocket @ 16
PQuntrace @ 17 PQbackendPID @ 17
PQsetNoticeProcessor @ 18 PQtrace @ 18
PQexec @ 19 PQuntrace @ 19
PQnotifies @ 20 PQsetNoticeProcessor @ 20
PQsendQuery @ 21 PQexec @ 21
PQgetResult @ 22 PQnotifies @ 22
PQisBusy @ 23 PQsendQuery @ 23
PQconsumeInput @ 24 PQgetResult @ 24
PQgetline @ 25 PQisBusy @ 25
PQputline @ 26 PQconsumeInput @ 26
PQputnbytes @ 27 PQgetline @ 27
PQendcopy @ 28 PQputline @ 28
PQfn @ 29 PQgetlineAsync @ 29
PQresultStatus @ 30 PQputnbytes @ 30
PQntuples @ 31 PQendcopy @ 31
PQnfields @ 32 PQfn @ 32
PQfname @ 33 PQresultStatus @ 33
PQfnumber @ 34 PQntuples @ 34
PQftype @ 35 PQnfields @ 35
PQfsize @ 36 PQbinaryTuples @ 36
PQfmod @ 37 PQfname @ 37
PQcmdStatus @ 38 PQfnumber @ 38
PQoidStatus @ 39 PQftype @ 39
PQcmdTuples @ 40 PQfsize @ 40
PQgetvalue @ 41 PQfmod @ 41
PQgetlength @ 42 PQcmdStatus @ 42
PQgetisnull @ 43 PQoidStatus @ 43
PQclear @ 44 PQcmdTuples @ 44
PQprint @ 45 PQgetvalue @ 45
PQdisplayTuples @ 46 PQgetlength @ 46
PQprintTuples @ 47 PQgetisnull @ 47
lo_open @ 48 PQclear @ 48
lo_close @ 49 PQmakeEmptyPGresult @ 49
lo_read @ 50 PQprint @ 50
lo_write @ 51 PQdisplayTuples @ 51
lo_lseek @ 52 PQprintTuples @ 52
lo_creat @ 53 lo_open @ 53
lo_tell @ 54 lo_close @ 54
lo_unlink @ 55 lo_read @ 55
lo_import @ 56 lo_write @ 56
lo_export @ 57 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 * Copyright (c) 1997, 1998 Edmund Mergl
* *
...@@ -318,7 +318,7 @@ PQexec(conn, query) ...@@ -318,7 +318,7 @@ PQexec(conn, query)
char * query char * query
CODE: CODE:
RETVAL = PQexec(conn, query); RETVAL = PQexec(conn, query);
if (! RETVAL) { RETVAL = (PGresult *)calloc(1, sizeof(PGresult)); } if (! RETVAL) { RETVAL = PQmakeEmptyPGresult(conn, PGRES_FATAL_ERROR); }
OUTPUT: OUTPUT:
RETVAL RETVAL
...@@ -752,7 +752,7 @@ PQexec(conn, query) ...@@ -752,7 +752,7 @@ PQexec(conn, query)
if (RETVAL) { if (RETVAL) {
RETVAL->result = PQexec((PGconn *)conn, query); RETVAL->result = PQexec((PGconn *)conn, query);
if (!RETVAL->result) { if (!RETVAL->result) {
RETVAL->result = (PG_result)calloc(1, sizeof(PGresult)); RETVAL->result = PQmakeEmptyPGresult(conn, PGRES_FATAL_ERROR);
} }
} }
OUTPUT: OUTPUT:
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment