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:
parent
bcc15f15e1
commit
f71d0cf64e
@ -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)
|
|||||||
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)
|
|||||||
}
|
}
|
||||||
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 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* 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
|
|||||||
/* 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,
|
|||||||
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,
|
|||||||
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)
|
|||||||
#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)
|
|||||||
|
|
||||||
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)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
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)
|
|||||||
*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)
|
|||||||
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)
|
|||||||
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,...)
|
|||||||
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 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* 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[])
|
|||||||
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[])
|
|||||||
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[])
|
|||||||
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[])
|
|||||||
{
|
{
|
||||||
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[])
|
|||||||
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[])
|
|||||||
-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[])
|
|||||||
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[])
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* 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[])
|
|||||||
}
|
}
|
||||||
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:
|
|||||||
"\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)
|
|||||||
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[])
|
|||||||
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 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* 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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
|
|
||||||
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 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* 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)
|
|||||||
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)
|
|||||||
}
|
}
|
||||||
|
|
||||||
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)
|
|||||||
}
|
}
|
||||||
|
|
||||||
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)
|
|||||||
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)
|
||||||
{
|
{
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* 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 $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -49,7 +49,6 @@ const char *const pgresStatus[] = {
|
|||||||
((*(conn)->noticeHook) ((conn)->noticeArg, (message)))
|
((*(conn)->noticeHook) ((conn)->noticeArg, (message)))
|
||||||
|
|
||||||
|
|
||||||
static PGresult *makeEmptyPGresult(PGconn *conn, ExecStatusType status);
|
|
||||||
static void freeTuple(PGresAttValue *tuple, int numAttributes);
|
static void freeTuple(PGresAttValue *tuple, int numAttributes);
|
||||||
static void addTuple(PGresult *res, PGresAttValue *tup);
|
static void addTuple(PGresult *res, PGresAttValue *tup);
|
||||||
static void parseInput(PGconn *conn);
|
static void parseInput(PGconn *conn);
|
||||||
@ -60,13 +59,16 @@ static int getNotice(PGconn *conn);
|
|||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* PGresult -
|
* PQmakeEmptyPGresult
|
||||||
* returns a newly allocated, initialized PGresult
|
* 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 *
|
PGresult *
|
||||||
makeEmptyPGresult(PGconn *conn, ExecStatusType status)
|
PQmakeEmptyPGresult(PGconn *conn, ExecStatusType status)
|
||||||
{
|
{
|
||||||
PGresult *result;
|
PGresult *result;
|
||||||
|
|
||||||
@ -252,13 +254,15 @@ PQsendQuery(PGconn *conn, const char *query)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Consume any available input from the backend
|
* Consume any available input from the backend
|
||||||
|
* 0 return: some kind of trouble
|
||||||
|
* 1 return: no problem
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void
|
int
|
||||||
PQconsumeInput(PGconn *conn)
|
PQconsumeInput(PGconn *conn)
|
||||||
{
|
{
|
||||||
if (!conn)
|
if (!conn)
|
||||||
return;
|
return 0;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Load more data, if available. We do this no matter what state we
|
* Load more data, if available. We do this no matter what state we
|
||||||
@ -266,9 +270,12 @@ PQconsumeInput(PGconn *conn)
|
|||||||
* application wants to get rid of a read-select condition. Note that
|
* application wants to get rid of a read-select condition. Note that
|
||||||
* we will NOT block waiting for more input.
|
* we will NOT block waiting for more input.
|
||||||
*/
|
*/
|
||||||
if (pqReadData(conn) < 0)
|
if (pqReadData(conn) < 0) {
|
||||||
strcpy(conn->asyncErrorMessage, conn->errorMessage);
|
strcpy(conn->asyncErrorMessage, conn->errorMessage);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
/* Parsing of the data waits till later. */
|
/* Parsing of the data waits till later. */
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -346,8 +353,8 @@ parseInput(PGconn *conn)
|
|||||||
{
|
{
|
||||||
case 'C': /* command complete */
|
case 'C': /* command complete */
|
||||||
if (conn->result == NULL)
|
if (conn->result == NULL)
|
||||||
conn->result = makeEmptyPGresult(conn,
|
conn->result = PQmakeEmptyPGresult(conn,
|
||||||
PGRES_COMMAND_OK);
|
PGRES_COMMAND_OK);
|
||||||
if (pqGets(conn->result->cmdStatus, CMDSTATUS_LEN, conn))
|
if (pqGets(conn->result->cmdStatus, CMDSTATUS_LEN, conn))
|
||||||
return;
|
return;
|
||||||
conn->asyncStatus = PGASYNC_READY;
|
conn->asyncStatus = PGASYNC_READY;
|
||||||
@ -379,8 +386,8 @@ parseInput(PGconn *conn)
|
|||||||
DONOTICE(conn, conn->errorMessage);
|
DONOTICE(conn, conn->errorMessage);
|
||||||
}
|
}
|
||||||
if (conn->result == NULL)
|
if (conn->result == NULL)
|
||||||
conn->result = makeEmptyPGresult(conn,
|
conn->result = PQmakeEmptyPGresult(conn,
|
||||||
PGRES_EMPTY_QUERY);
|
PGRES_EMPTY_QUERY);
|
||||||
conn->asyncStatus = PGASYNC_READY;
|
conn->asyncStatus = PGASYNC_READY;
|
||||||
break;
|
break;
|
||||||
case 'K': /* secret key data from the backend */
|
case 'K': /* secret key data from the backend */
|
||||||
@ -499,7 +506,7 @@ getRowDescriptions(PGconn *conn)
|
|||||||
int nfields;
|
int nfields;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
result = makeEmptyPGresult(conn, PGRES_TUPLES_OK);
|
result = PQmakeEmptyPGresult(conn, PGRES_TUPLES_OK);
|
||||||
|
|
||||||
/* parseInput already read the 'T' label. */
|
/* parseInput already read the 'T' label. */
|
||||||
/* the next two bytes are the number of fields */
|
/* the next two bytes are the number of fields */
|
||||||
@ -536,7 +543,7 @@ getRowDescriptions(PGconn *conn)
|
|||||||
}
|
}
|
||||||
result->attDescs[i].name = strdup(typName);
|
result->attDescs[i].name = strdup(typName);
|
||||||
result->attDescs[i].typid = typid;
|
result->attDescs[i].typid = typid;
|
||||||
result->attDescs[i].typlen = (short) typlen;
|
result->attDescs[i].typlen = typlen;
|
||||||
result->attDescs[i].atttypmod = atttypmod;
|
result->attDescs[i].atttypmod = atttypmod;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -695,7 +702,7 @@ PQgetResult(PGconn *conn)
|
|||||||
pqClearAsyncResult(conn);
|
pqClearAsyncResult(conn);
|
||||||
conn->asyncStatus = PGASYNC_IDLE;
|
conn->asyncStatus = PGASYNC_IDLE;
|
||||||
/* conn->errorMessage has been set by pqWait or pqReadData. */
|
/* conn->errorMessage has been set by pqWait or pqReadData. */
|
||||||
return makeEmptyPGresult(conn, PGRES_FATAL_ERROR);
|
return PQmakeEmptyPGresult(conn, PGRES_FATAL_ERROR);
|
||||||
}
|
}
|
||||||
/* Parse it. */
|
/* Parse it. */
|
||||||
parseInput(conn);
|
parseInput(conn);
|
||||||
@ -719,22 +726,22 @@ PQgetResult(PGconn *conn)
|
|||||||
conn->result = NULL;/* handing over ownership to caller */
|
conn->result = NULL;/* handing over ownership to caller */
|
||||||
conn->curTuple = NULL; /* just in case */
|
conn->curTuple = NULL; /* just in case */
|
||||||
if (!res)
|
if (!res)
|
||||||
res = makeEmptyPGresult(conn, PGRES_FATAL_ERROR);
|
res = PQmakeEmptyPGresult(conn, PGRES_FATAL_ERROR);
|
||||||
strcpy(conn->errorMessage, conn->asyncErrorMessage);
|
strcpy(conn->errorMessage, conn->asyncErrorMessage);
|
||||||
/* Set the state back to BUSY, allowing parsing to proceed. */
|
/* Set the state back to BUSY, allowing parsing to proceed. */
|
||||||
conn->asyncStatus = PGASYNC_BUSY;
|
conn->asyncStatus = PGASYNC_BUSY;
|
||||||
break;
|
break;
|
||||||
case PGASYNC_COPY_IN:
|
case PGASYNC_COPY_IN:
|
||||||
res = makeEmptyPGresult(conn, PGRES_COPY_IN);
|
res = PQmakeEmptyPGresult(conn, PGRES_COPY_IN);
|
||||||
break;
|
break;
|
||||||
case PGASYNC_COPY_OUT:
|
case PGASYNC_COPY_OUT:
|
||||||
res = makeEmptyPGresult(conn, PGRES_COPY_OUT);
|
res = PQmakeEmptyPGresult(conn, PGRES_COPY_OUT);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
sprintf(conn->errorMessage,
|
sprintf(conn->errorMessage,
|
||||||
"PQgetResult: Unexpected asyncStatus %d\n",
|
"PQgetResult: Unexpected asyncStatus %d\n",
|
||||||
(int) conn->asyncStatus);
|
(int) conn->asyncStatus);
|
||||||
res = makeEmptyPGresult(conn, PGRES_FATAL_ERROR);
|
res = PQmakeEmptyPGresult(conn, PGRES_FATAL_ERROR);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -880,6 +887,9 @@ PQnotifies(PGconn *conn)
|
|||||||
* PQgetline reads up to maxlen-1 characters (like fgets(3)) but strips
|
* PQgetline reads up to maxlen-1 characters (like fgets(3)) but strips
|
||||||
* the terminating \n (like gets(3)).
|
* 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:
|
* RETURNS:
|
||||||
* EOF if it is detected or invalid arguments are given
|
* EOF if it is detected or invalid arguments are given
|
||||||
* 0 if EOL is reached (i.e., \n has been read)
|
* 0 if EOL is reached (i.e., \n has been read)
|
||||||
@ -936,26 +946,114 @@ PQgetline(PGconn *conn, char *s, int maxlen)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* PQgetlineAsync - gets a newline-terminated string without blocking.
|
||||||
|
*
|
||||||
|
* This routine is for applications that want to do "COPY <rel> 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.
|
* PQputline -- sends a string to the backend.
|
||||||
|
* Returns 0 if OK, EOF if not.
|
||||||
*
|
*
|
||||||
* Chiefly here so that applications can use "COPY <rel> from stdin".
|
* Chiefly here so that applications can use "COPY <rel> from stdin".
|
||||||
*/
|
*/
|
||||||
void
|
int
|
||||||
PQputline(PGconn *conn, const char *s)
|
PQputline(PGconn *conn, const char *s)
|
||||||
{
|
{
|
||||||
if (conn && conn->sock >= 0)
|
if (!conn || conn->sock < 0)
|
||||||
(void) pqPutnchar(s, strlen(s), conn);
|
return EOF;
|
||||||
|
return pqPutnchar(s, strlen(s), conn);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* PQputnbytes -- like PQputline, but buffer need not be null-terminated.
|
* 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)
|
PQputnbytes(PGconn *conn, const char *buffer, int nbytes)
|
||||||
{
|
{
|
||||||
if (conn && conn->sock >= 0)
|
if (!conn || conn->sock < 0)
|
||||||
(void) pqPutnchar(buffer, nbytes, conn);
|
return EOF;
|
||||||
|
return pqPutnchar(buffer, nbytes, conn);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -1155,7 +1253,7 @@ PQfn(PGconn *conn,
|
|||||||
sprintf(conn->errorMessage,
|
sprintf(conn->errorMessage,
|
||||||
"FATAL: PQfn: protocol error: id=%x\n", id);
|
"FATAL: PQfn: protocol error: id=%x\n", id);
|
||||||
conn->inStart = conn->inCursor;
|
conn->inStart = conn->inCursor;
|
||||||
return makeEmptyPGresult(conn, PGRES_FATAL_ERROR);
|
return PQmakeEmptyPGresult(conn, PGRES_FATAL_ERROR);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'E': /* error return */
|
case 'E': /* error return */
|
||||||
@ -1176,13 +1274,13 @@ PQfn(PGconn *conn,
|
|||||||
case 'Z': /* backend is ready for new query */
|
case 'Z': /* backend is ready for new query */
|
||||||
/* consume the message and exit */
|
/* consume the message and exit */
|
||||||
conn->inStart = conn->inCursor;
|
conn->inStart = conn->inCursor;
|
||||||
return makeEmptyPGresult(conn, status);
|
return PQmakeEmptyPGresult(conn, status);
|
||||||
default:
|
default:
|
||||||
/* The backend violates the protocol. */
|
/* The backend violates the protocol. */
|
||||||
sprintf(conn->errorMessage,
|
sprintf(conn->errorMessage,
|
||||||
"FATAL: PQfn: protocol error: id=%x\n", id);
|
"FATAL: PQfn: protocol error: id=%x\n", id);
|
||||||
conn->inStart = conn->inCursor;
|
conn->inStart = conn->inCursor;
|
||||||
return makeEmptyPGresult(conn, PGRES_FATAL_ERROR);
|
return PQmakeEmptyPGresult(conn, PGRES_FATAL_ERROR);
|
||||||
}
|
}
|
||||||
/* Completed this message, keep going */
|
/* Completed this message, keep going */
|
||||||
conn->inStart = conn->inCursor;
|
conn->inStart = conn->inCursor;
|
||||||
@ -1190,7 +1288,7 @@ PQfn(PGconn *conn,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* we fall out of the loop only upon failing to read data */
|
/* we fall out of the loop only upon failing to read data */
|
||||||
return makeEmptyPGresult(conn, PGRES_FATAL_ERROR);
|
return PQmakeEmptyPGresult(conn, PGRES_FATAL_ERROR);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1220,6 +1318,14 @@ PQnfields(PGresult *res)
|
|||||||
return res->numAttributes;
|
return res->numAttributes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
PQbinaryTuples(PGresult *res)
|
||||||
|
{
|
||||||
|
if (!res)
|
||||||
|
return 0;
|
||||||
|
return res->binary;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Helper routines to range-check field numbers and tuple numbers.
|
* Helper routines to range-check field numbers and tuple numbers.
|
||||||
* Return TRUE if OK, FALSE if not
|
* Return TRUE if OK, FALSE if not
|
||||||
@ -1332,7 +1438,7 @@ PQftype(PGresult *res, int field_num)
|
|||||||
return InvalidOid;
|
return InvalidOid;
|
||||||
}
|
}
|
||||||
|
|
||||||
short
|
int
|
||||||
PQfsize(PGresult *res, int field_num)
|
PQfsize(PGresult *res, int field_num)
|
||||||
{
|
{
|
||||||
if (!check_field_number("PQfsize", res, field_num))
|
if (!check_field_number("PQfsize", res, field_num))
|
||||||
|
@ -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)
|
|||||||
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)
|
|||||||
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;
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
*
|
*
|
||||||
* Copyright (c) 1994, Regents of the University of California
|
* 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 $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -20,20 +20,10 @@ extern "C"
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
/* these wouldn't need to be included if PGSockAddr weren't exported: */
|
/* postgres_ext.h defines the backend's externally visible types,
|
||||||
#ifdef WIN32
|
* such as Oid.
|
||||||
#include <winsock.h>
|
|
||||||
#else
|
|
||||||
#include <sys/socket.h>
|
|
||||||
#include <sys/un.h>
|
|
||||||
#include <netinet/in.h>
|
|
||||||
#endif
|
|
||||||
/* ----------------
|
|
||||||
* include stuff common to fe and be
|
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
#include "postgres_ext.h"
|
#include "postgres_ext.h"
|
||||||
#include "lib/dllist.h"
|
|
||||||
|
|
||||||
/* Application-visible enum types */
|
/* Application-visible enum types */
|
||||||
|
|
||||||
@ -46,11 +36,11 @@ extern "C"
|
|||||||
typedef enum
|
typedef enum
|
||||||
{
|
{
|
||||||
PGRES_EMPTY_QUERY = 0,
|
PGRES_EMPTY_QUERY = 0,
|
||||||
PGRES_COMMAND_OK, /* a query command that doesn't return */
|
PGRES_COMMAND_OK, /* a query command that doesn't return anything
|
||||||
/* anything was executed properly by the backend */
|
* was executed properly by the backend */
|
||||||
PGRES_TUPLES_OK, /* a query command that returns tuples */
|
PGRES_TUPLES_OK, /* a query command that returns tuples
|
||||||
/* was executed properly by the backend, PGresult */
|
* was executed properly by the backend,
|
||||||
/* contains the result tuples */
|
* PGresult contains the result tuples */
|
||||||
PGRES_COPY_OUT, /* Copy Out data transfer in progress */
|
PGRES_COPY_OUT, /* Copy Out data transfer in progress */
|
||||||
PGRES_COPY_IN, /* Copy In data transfer in progress */
|
PGRES_COPY_IN, /* Copy In data transfer in progress */
|
||||||
PGRES_BAD_RESPONSE, /* an unexpected response was recv'd from
|
PGRES_BAD_RESPONSE, /* an unexpected response was recv'd from
|
||||||
@ -59,194 +49,46 @@ extern "C"
|
|||||||
PGRES_FATAL_ERROR
|
PGRES_FATAL_ERROR
|
||||||
} ExecStatusType;
|
} ExecStatusType;
|
||||||
|
|
||||||
/* string descriptions of the ExecStatusTypes */
|
/* String descriptions of the ExecStatusTypes */
|
||||||
extern const char *const pgresStatus[];
|
extern const char * const pgresStatus[];
|
||||||
|
|
||||||
/*
|
/* PGconn encapsulates a connection to the backend.
|
||||||
* POSTGRES backend dependent Constants.
|
* 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*/
|
/* PGresult encapsulates the result of a query (or more precisely, of a single
|
||||||
#define ERROR_MSG_LENGTH 4096
|
* SQL command --- a query string given to PQsendQuery can contain multiple
|
||||||
#define CMDSTATUS_LEN 40
|
* commands and thus return multiple PGresult objects).
|
||||||
|
* The contents of this struct are not supposed to be known to applications.
|
||||||
/* 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 pg_result PGresult;
|
||||||
|
|
||||||
typedef struct pgresAttDesc
|
/* PGnotify represents the occurrence of a NOTIFY message.
|
||||||
{
|
* Ideally this would be an opaque typedef, but it's so simple that it's
|
||||||
char *name; /* type name */
|
* unlikely to change.
|
||||||
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
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#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
|
typedef struct pgNotify
|
||||||
{
|
{
|
||||||
char relname[NAMEDATALEN]; /* name of relation
|
char relname[NAMEDATALEN]; /* name of relation
|
||||||
* containing data */
|
* containing data */
|
||||||
int be_pid; /* process id of backend */
|
int be_pid; /* process id of backend */
|
||||||
} PGnotify;
|
} PGnotify;
|
||||||
|
|
||||||
/* PQnoticeProcessor is a typedef for a callback function type */
|
/* PQnoticeProcessor is the function type for the notice-message callback.
|
||||||
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.
|
|
||||||
*/
|
*/
|
||||||
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 */
|
typedef void (*PQnoticeProcessor) (void * arg, const char * message);
|
||||||
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;
|
|
||||||
|
|
||||||
/* Print options for PQprint() */
|
/* 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
|
typedef struct _PQprintOpt
|
||||||
{
|
{
|
||||||
pqbool header; /* print output field headings and row
|
pqbool header; /* print output field headings and row
|
||||||
@ -263,6 +105,26 @@ extern "C"
|
|||||||
* field names */
|
* field names */
|
||||||
} PQprintOpt;
|
} PQprintOpt;
|
||||||
|
|
||||||
|
/* ----------------
|
||||||
|
* Structure for the conninfo parameter definitions returned by PQconndefaults
|
||||||
|
* ----------------
|
||||||
|
*/
|
||||||
|
typedef struct _PQconninfoOption
|
||||||
|
{
|
||||||
|
char *keyword; /* The keyword of the option */
|
||||||
|
char *environ; /* Fallback environment variable name */
|
||||||
|
char *compiled; /* Fallback compiled in default value */
|
||||||
|
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 */
|
||||||
|
int dispsize; /* Field size in characters for dialog */
|
||||||
|
} PQconninfoOption;
|
||||||
|
|
||||||
/* ----------------
|
/* ----------------
|
||||||
* PQArgBlock -- structure for PQfn() arguments
|
* PQArgBlock -- structure for PQfn() arguments
|
||||||
* ----------------
|
* ----------------
|
||||||
@ -278,26 +140,6 @@ extern "C"
|
|||||||
} u;
|
} u;
|
||||||
} PQArgBlock;
|
} PQArgBlock;
|
||||||
|
|
||||||
/* ----------------
|
|
||||||
* Structure for the conninfo parameter definitions returned by PQconndefaults
|
|
||||||
* ----------------
|
|
||||||
*/
|
|
||||||
typedef struct _PQconninfoOption
|
|
||||||
{
|
|
||||||
char *keyword; /* The keyword of the option */
|
|
||||||
char *environ; /* Fallback environment variable name */
|
|
||||||
char *compiled; /* Fallback compiled in default value */
|
|
||||||
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 */
|
|
||||||
int dispsize; /* Field size in characters for dialog */
|
|
||||||
} PQconninfoOption;
|
|
||||||
|
|
||||||
/* ----------------
|
/* ----------------
|
||||||
* Exported functions of libpq
|
* Exported functions of libpq
|
||||||
* ----------------
|
* ----------------
|
||||||
@ -332,13 +174,16 @@ extern "C"
|
|||||||
/* Accessor functions for PGconn objects */
|
/* Accessor functions for PGconn objects */
|
||||||
extern char *PQdb(PGconn *conn);
|
extern char *PQdb(PGconn *conn);
|
||||||
extern char *PQuser(PGconn *conn);
|
extern char *PQuser(PGconn *conn);
|
||||||
|
extern char *PQpass(PGconn *conn);
|
||||||
extern char *PQhost(PGconn *conn);
|
extern char *PQhost(PGconn *conn);
|
||||||
extern char *PQoptions(PGconn *conn);
|
|
||||||
extern char *PQport(PGconn *conn);
|
extern char *PQport(PGconn *conn);
|
||||||
extern char *PQtty(PGconn *conn);
|
extern char *PQtty(PGconn *conn);
|
||||||
|
extern char *PQoptions(PGconn *conn);
|
||||||
extern ConnStatusType PQstatus(PGconn *conn);
|
extern ConnStatusType PQstatus(PGconn *conn);
|
||||||
extern char *PQerrorMessage(PGconn *conn);
|
extern char *PQerrorMessage(PGconn *conn);
|
||||||
extern int PQsocket(PGconn *conn);
|
extern int PQsocket(PGconn *conn);
|
||||||
|
extern int PQsocket(PGconn *conn);
|
||||||
|
extern int PQbackendPID(PGconn *conn);
|
||||||
|
|
||||||
/* Enable/disable tracing */
|
/* Enable/disable tracing */
|
||||||
extern void PQtrace(PGconn *conn, FILE *debug_port);
|
extern void PQtrace(PGconn *conn, FILE *debug_port);
|
||||||
@ -361,12 +206,13 @@ extern "C"
|
|||||||
|
|
||||||
/* Routines for managing an asychronous query */
|
/* Routines for managing an asychronous query */
|
||||||
extern int PQisBusy(PGconn *conn);
|
extern int PQisBusy(PGconn *conn);
|
||||||
extern void PQconsumeInput(PGconn *conn);
|
extern int PQconsumeInput(PGconn *conn);
|
||||||
|
|
||||||
/* Routines for copy in/out */
|
/* Routines for copy in/out */
|
||||||
extern int PQgetline(PGconn *conn, char *string, int length);
|
extern int PQgetline(PGconn *conn, char *string, int length);
|
||||||
extern void PQputline(PGconn *conn, const char *string);
|
extern int PQputline(PGconn *conn, const char *string);
|
||||||
extern void PQputnbytes(PGconn *conn, const char *buffer, int nbytes);
|
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 int PQendcopy(PGconn *conn);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -385,10 +231,11 @@ extern "C"
|
|||||||
extern ExecStatusType PQresultStatus(PGresult *res);
|
extern ExecStatusType PQresultStatus(PGresult *res);
|
||||||
extern int PQntuples(PGresult *res);
|
extern int PQntuples(PGresult *res);
|
||||||
extern int PQnfields(PGresult *res);
|
extern int PQnfields(PGresult *res);
|
||||||
|
extern int PQbinaryTuples(PGresult *res);
|
||||||
extern char *PQfname(PGresult *res, int field_num);
|
extern char *PQfname(PGresult *res, int field_num);
|
||||||
extern int PQfnumber(PGresult *res, const char *field_name);
|
extern int PQfnumber(PGresult *res, const char *field_name);
|
||||||
extern Oid PQftype(PGresult *res, int field_num);
|
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 int PQfmod(PGresult *res, int field_num);
|
||||||
extern char *PQcmdStatus(PGresult *res);
|
extern char *PQcmdStatus(PGresult *res);
|
||||||
extern const char *PQoidStatus(PGresult *res);
|
extern const char *PQoidStatus(PGresult *res);
|
||||||
@ -400,6 +247,9 @@ extern "C"
|
|||||||
/* Delete a PGresult */
|
/* Delete a PGresult */
|
||||||
extern void PQclear(PGresult *res);
|
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 === */
|
/* === in fe-print.c === */
|
||||||
|
|
||||||
extern void PQprint(FILE *fout, /* output stream */
|
extern void PQprint(FILE *fout, /* output stream */
|
||||||
|
@ -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 @@
|
|||||||
* ----------------
|
* ----------------
|
||||||
*/
|
*/
|
||||||
#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 @@
|
|||||||
|
|
||||||
#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
|
|||||||
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
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/*-------------------------------------------------------
|
/*-------------------------------------------------------
|
||||||
*
|
*
|
||||||
* $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)
|
|||||||
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)
|
|||||||
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:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user