1
0
mirror of https://github.com/postgres/postgres.git synced 2025-10-29 22:49:41 +03:00

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.
This commit is contained in:
Bruce Momjian
1998-09-03 02:10:56 +00:00
parent bcc15f15e1
commit f71d0cf64e
12 changed files with 516 additions and 430 deletions

View File

@@ -7,7 +7,7 @@
*
*
* 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[])
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;
}
@@ -423,7 +423,6 @@ Pg_exec(ClientData cData, Tcl_Interp * interp, int argc, char *argv[])
Pg_ConnectionId *connid;
PGconn *conn;
PGresult *result;
int connStatus;
if (argc != 3)
{
@@ -442,7 +441,6 @@ Pg_exec(ClientData cData, Tcl_Interp * interp, int argc, char *argv[])
return TCL_ERROR;
}
connStatus = conn->status;
result = PQexec(conn, argv[2]);
/* 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[])
{
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;
@@ -463,7 +461,7 @@ Pg_exec(ClientData cData, Tcl_Interp * interp, int argc, char *argv[])
else
{
/* error occurred during the query */
Tcl_SetResult(interp, conn->errorMessage, TCL_VOLATILE);
Tcl_SetResult(interp, PQerrorMessage(conn), TCL_VOLATILE);
return TCL_ERROR;
}
}
@@ -481,9 +479,12 @@ Pg_exec(ClientData cData, Tcl_Interp * interp, int argc, char *argv[])
-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
@@ -509,6 +510,7 @@ Pg_result(ClientData cData, Tcl_Interp * interp, int argc, char *argv[])
int tupno;
char *arrVar;
char nameBuffer[256];
const char *appendstr;
if (argc < 3 || argc > 5)
{
@@ -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
* 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.
*/
@@ -589,28 +592,32 @@ Pg_result(ClientData cData, Tcl_Interp * interp, int argc, char *argv[])
}
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)
@@ -701,7 +708,7 @@ Pg_result_errReturn:
"\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"
@@ -1238,7 +1245,7 @@ Pg_select(ClientData cData, Tcl_Interp * interp, int argc, char **argv)
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;
}
@@ -1406,11 +1413,10 @@ Pg_listen(ClientData cData, Tcl_Interp * interp, int argc, char *argv[])
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);

View File

@@ -12,7 +12,7 @@
*
*
* 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)
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 <rel> 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 <rel> 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;
}
/*
@@ -140,17 +104,13 @@ PgOutputProc(DRIVER_OUTPUT_PROTO)
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;
@@ -398,7 +358,7 @@ getresid(Tcl_Interp * interp, char *id, Pg_ConnectionId ** connid_p)
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;