Commit 6ac25286 authored by Marc G. Fournier's avatar Marc G. Fournier

From: Randy Kunkee <kunkee@pluto.ops.NeoSoft.com>

It is my hope that the following "patches" to libpgtcl get included
in the next release.

See the update to the README file to get a full description of the changes.
This version of libpgtcl is completely interpreter-safe, implements the
database connection handle as a channel (no events yet, but will make it
a lot easier to do fileevents on it in the future), and supports the SQL
"copy table to stdout" and "copy table from stdin" commands, with the
I/O being from and to the connection handle.  The connection and result
handles are formatted in a way to make access to the tables more efficient.
parent 609026bb
......@@ -7,7 +7,7 @@
#
#
# IDENTIFICATION
# $Header: /cvsroot/pgsql/src/interfaces/libpgtcl/Attic/Makefile.in,v 1.3 1998/02/13 05:09:57 scrappy Exp $
# $Header: /cvsroot/pgsql/src/interfaces/libpgtcl/Attic/Makefile.in,v 1.4 1998/03/15 08:02:55 scrappy Exp $
#
#-------------------------------------------------------------------------
......@@ -37,7 +37,7 @@ ifeq ($(PORTNAME), linux)
install-shlib-dep := install-shlib
shlib := libpgtcl.so.1
CFLAGS += $(CFLAGS_SL)
LDFLAGS_SL = -shared -L $(SRCDIR)/interfaces/libpq -lpq
LDFLAGS_SL = -shared -L$(SRCDIR)/interfaces/libpq -lpq
endif
endif
......@@ -53,14 +53,14 @@ endif
ifeq ($(PORTNAME), i386_solaris)
install-shlib-dep := install-shlib
shlib := libpgtcl.so.1
LDFLAGS_SL = -G -z text -L $(SRCDIR)/interfaces/libpq -lpq
LDFLAGS_SL = -G -z text -L$(SRCDIR)/interfaces/libpq -lpq
CFLAGS += $(CFLAGS_SL)
endif
ifeq ($(PORTNAME), univel)
install-shlib-dep := install-shlib
shlib := libpgtcl.so.1
LDFLAGS_SL = -G -z text -L $(SRCDIR)/interfaces/libpq -lpq
LDFLAGS_SL = -G -z text -L$(SRCDIR)/interfaces/libpq -lpq
CFLAGS += $(CFLAGS_SL)
endif
......
libpgtcl is a library that implements Tcl commands for front-end clients
to interact with the PostgreSQL backend. See libpgtcl.doc for details.
libpgtcl is a library that implements Tcl commands for front-end
clients to interact with the Postgresql 6.3 (and perhaps later)
backends. See libpgtcl.doc for details.
For an example of how to build a new tclsh to use libpgtcl, see the
directory ../bin/pgtclsh
Note this version is modified by NeoSoft to have the following additional
features:
1. Postgres connections are a valid Tcl channel, and can therefore
be manipulated by the interp command (ie. shared or transfered).
A connection handle's results are transfered/shared with it.
(Result handles are NOT channels, though it was tempting). Note
that a "close $connection" is now functionally identical to a
"pg_disconnect $connection", although pg_connect must be used
to create a connection.
2. Result handles are changed in format: ${connection}.<result#>.
This just means for a connection 'pgtcl0', they look like pgtcl0.0,
pgtcl0.1, etc. Enforcing this syntax makes it easy to look up
the real pointer by indexing into an array associated with the
connection.
3. I/O routines are now defined for the connection handle. I/O to/from
the connection is only valid under certain circumstances: following
the execution of the queries "copy <table> from stdin" or
"copy <table> to stdout". In these cases, the result handle obtains
an intermediate status of "PGRES_COPY_IN" or "PGRES_COPY_OUT". The
programmer is then expected to use Tcl gets or read commands on the
database connection (not the result handle) to extract the copy data.
For copy outs, read until the standard EOF indication is encountered.
For copy ins, puts a single terminator (\.). The statement for this
would be
puts $conn "\\." or puts $conn {\.}
In either case (upon detecting the EOF or putting the `\.', the status
of the result handle will change to "PGRES_COMMAND_OK", and any further
I/O attempts will cause a Tcl error.
......@@ -9,7 +9,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/interfaces/libpgtcl/Attic/pgtcl.c,v 1.9 1997/09/08 02:40:08 momjian Exp $
* $Header: /cvsroot/pgsql/src/interfaces/libpgtcl/Attic/pgtcl.c,v 1.10 1998/03/15 08:02:57 scrappy Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -28,158 +28,117 @@
*
*/
/*
* Tidy up forgotten postgres connection at Tcl_Exit
*/
static void
Pgtcl_AtExit(ClientData cData)
{
Pg_clientData *cd = (Pg_clientData *) cData;
Tcl_HashEntry *hent;
Tcl_HashSearch hsearch;
Pg_ConnectionId *connid;
PGconn *conn;
while ((hent = Tcl_FirstHashEntry(&(cd->dbh_hash), &hsearch)) != NULL)
{
connid = (Pg_ConnectionId *) Tcl_GetHashValue(hent);
conn = connid->conn;
PgDelConnectionId(cd, connid->id);
PQfinish(conn);
}
Tcl_DeleteHashTable(&(cd->dbh_hash));
Tcl_DeleteHashTable(&(cd->res_hash));
Tcl_DeleteHashTable(&(cd->notify_hash));
Tcl_DeleteExitHandler(Pgtcl_AtExit, cData);
}
/*
* Tidy up forgotten postgres connections on Interpreter deletion
*/
static void
Pgtcl_Shutdown(ClientData cData, Tcl_Interp * interp)
{
Pgtcl_AtExit(cData);
}
int
Pgtcl_Init(Tcl_Interp * interp)
Pgtcl_Init (Tcl_Interp *interp)
{
Pg_clientData *cd;
/* Create and initialize the client data area */
cd = (Pg_clientData *) ckalloc(sizeof(Pg_clientData));
Tcl_InitHashTable(&(cd->dbh_hash), TCL_STRING_KEYS);
Tcl_InitHashTable(&(cd->res_hash), TCL_STRING_KEYS);
Tcl_InitHashTable(&(cd->notify_hash), TCL_STRING_KEYS);
cd->dbh_count = 0L;
cd->res_count = 0L;
/* Arrange for tidy up when interpreter is deleted or Tcl exits */
Tcl_CallWhenDeleted(interp, Pgtcl_Shutdown, (ClientData) cd);
Tcl_CreateExitHandler(Pgtcl_AtExit, (ClientData) cd);
/* finish off the ChannelType struct. Much easier to do it here then
* to guess where it might be by position in the struct. This is needed
* for Tcl7.6 and beyond, which have the getfileproc.
*/
#if (TCL_MAJOR_VERSION == 7 && TCL_MINOR_VERSION == 6)
Pg_ConnType.getFileProc = PgGetFileProc;
#endif
/* register all pgtcl commands */
Tcl_CreateCommand(interp,
"pg_conndefaults",
Pg_conndefaults,
(ClientData) cd, (Tcl_CmdDeleteProc *) NULL);
(ClientData)NULL, (Tcl_CmdDeleteProc*)NULL);
Tcl_CreateCommand(interp,
"pg_connect",
Pg_connect,
(ClientData) cd, (Tcl_CmdDeleteProc *) NULL);
(ClientData)NULL, (Tcl_CmdDeleteProc*)NULL);
Tcl_CreateCommand(interp,
"pg_disconnect",
Pg_disconnect,
(ClientData) cd, (Tcl_CmdDeleteProc *) NULL);
(ClientData)NULL, (Tcl_CmdDeleteProc*)NULL);
Tcl_CreateCommand(interp,
"pg_exec",
Pg_exec,
(ClientData) cd, (Tcl_CmdDeleteProc *) NULL);
(ClientData)NULL, (Tcl_CmdDeleteProc*)NULL);
Tcl_CreateCommand(interp,
"pg_select",
Pg_select,
(ClientData) cd, (Tcl_CmdDeleteProc *) NULL);
(ClientData)NULL, (Tcl_CmdDeleteProc*)NULL);
Tcl_CreateCommand(interp,
"pg_result",
Pg_result,
(ClientData) cd, (Tcl_CmdDeleteProc *) NULL);
(ClientData)NULL, (Tcl_CmdDeleteProc*)NULL);
Tcl_CreateCommand(interp,
"pg_lo_open",
Pg_lo_open,
(ClientData) cd, (Tcl_CmdDeleteProc *) NULL);
(ClientData)NULL, (Tcl_CmdDeleteProc*)NULL);
Tcl_CreateCommand(interp,
"pg_lo_close",
Pg_lo_close,
(ClientData) cd, (Tcl_CmdDeleteProc *) NULL);
(ClientData)NULL, (Tcl_CmdDeleteProc*)NULL);
Tcl_CreateCommand(interp,
"pg_lo_read",
Pg_lo_read,
(ClientData) cd, (Tcl_CmdDeleteProc *) NULL);
(ClientData)NULL, (Tcl_CmdDeleteProc*)NULL);
Tcl_CreateCommand(interp,
"pg_lo_write",
Pg_lo_write,
(ClientData) cd, (Tcl_CmdDeleteProc *) NULL);
(ClientData)NULL, (Tcl_CmdDeleteProc*)NULL);
Tcl_CreateCommand(interp,
"pg_lo_lseek",
Pg_lo_lseek,
(ClientData) cd, (Tcl_CmdDeleteProc *) NULL);
(ClientData)NULL, (Tcl_CmdDeleteProc*)NULL);
Tcl_CreateCommand(interp,
"pg_lo_creat",
Pg_lo_creat,
(ClientData) cd, (Tcl_CmdDeleteProc *) NULL);
(ClientData)NULL, (Tcl_CmdDeleteProc*)NULL);
Tcl_CreateCommand(interp,
"pg_lo_tell",
Pg_lo_tell,
(ClientData) cd, (Tcl_CmdDeleteProc *) NULL);
(ClientData)NULL, (Tcl_CmdDeleteProc*)NULL);
Tcl_CreateCommand(interp,
"pg_lo_unlink",
Pg_lo_unlink,
(ClientData) cd, (Tcl_CmdDeleteProc *) NULL);
(ClientData)NULL, (Tcl_CmdDeleteProc*)NULL);
Tcl_CreateCommand(interp,
"pg_lo_import",
Pg_lo_import,
(ClientData) cd, (Tcl_CmdDeleteProc *) NULL);
(ClientData)NULL, (Tcl_CmdDeleteProc*)NULL);
Tcl_CreateCommand(interp,
"pg_lo_export",
Pg_lo_export,
(ClientData) cd, (Tcl_CmdDeleteProc *) NULL);
(ClientData)NULL, (Tcl_CmdDeleteProc*)NULL);
Tcl_CreateCommand(interp,
"pg_listen",
Pg_listen,
(ClientData) cd, (Tcl_CmdDeleteProc *) NULL);
(ClientData)NULL, (Tcl_CmdDeleteProc*)NULL);
Tcl_CreateCommand(interp,
"pg_notifies",
Pg_notifies,
(ClientData) cd, (Tcl_CmdDeleteProc *) NULL);
(ClientData)NULL, (Tcl_CmdDeleteProc*)NULL);
Tcl_PkgProvide(interp, "Pgtcl", "1.0");
Tcl_PkgProvide(interp, "Pgtcl", "1.1");
return TCL_OK;
}
int
Pgtcl_SafeInit(Tcl_Interp * interp)
Pgtcl_SafeInit (Tcl_Interp *interp)
{
return Pgtcl_Init(interp);
}
......@@ -7,7 +7,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/interfaces/libpgtcl/Attic/pgtclCmds.c,v 1.21 1998/02/26 04:44:48 momjian Exp $
* $Header: /cvsroot/pgsql/src/interfaces/libpgtcl/Attic/pgtclCmds.c,v 1.22 1998/03/15 08:02:58 scrappy Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -253,16 +253,14 @@ tcl_value(char *value)
**********************************/
int
Pg_conndefaults(ClientData cData, Tcl_Interp * interp, int argc, char **argv)
Pg_conndefaults(ClientData cData, Tcl_Interp *interp, int argc, char **argv)
{
PQconninfoOption *option;
char buf[8192];
Tcl_ResetResult(interp);
for (option = PQconndefaults(); option->keyword != NULL; option++)
{
if (option->val == NULL)
{
for(option = PQconndefaults(); option->keyword != NULL; option++) {
if(option->val == NULL) {
option->val = "";
}
sprintf(buf, "{%s} {%s} {%s} %d {%s}",
......@@ -291,9 +289,8 @@ Pg_conndefaults(ClientData cData, Tcl_Interp * interp, int argc, char **argv)
**********************************/
int
Pg_connect(ClientData cData, Tcl_Interp * interp, int argc, char *argv[])
Pg_connect(ClientData cData, Tcl_Interp *interp, int argc, char* argv[])
{
Pg_clientData *cd = (Pg_clientData *) cData;
char *pghost = NULL;
char *pgtty = NULL;
char *pgport = NULL;
......@@ -302,8 +299,7 @@ Pg_connect(ClientData cData, Tcl_Interp * interp, int argc, char *argv[])
int i;
PGconn *conn;
if (argc == 1)
{
if (argc == 1) {
Tcl_AppendResult(interp, "pg_connect: database name missing\n", 0);
Tcl_AppendResult(interp, "pg_connect databaseName [-host hostName] [-port portNumber] [-tty pgtty]]\n", 0);
Tcl_AppendResult(interp, "pg_connect -conninfo <conninfo-string>", 0);
......@@ -311,64 +307,52 @@ Pg_connect(ClientData cData, Tcl_Interp * interp, int argc, char *argv[])
}
if (!strcmp("-conninfo", argv[1]))
{
if (!strcmp("-conninfo", argv[1])) {
/*
* Establish a connection using the new PQconnectdb() interface
*/
if (argc != 3)
{
if (argc != 3) {
Tcl_AppendResult(interp, "pg_connect: syntax error\n", 0);
Tcl_AppendResult(interp, "pg_connect -conninfo <conninfo-string>", 0);
return TCL_ERROR;
}
conn = PQconnectdb(argv[2]);
}
else
{
} else {
/*
* Establish a connection using the old PQsetdb() interface
*/
if (argc > 2)
{
if (argc > 2) {
/* parse for pg environment settings */
i = 2;
while (i + 1 < argc)
{
if (strcmp(argv[i], "-host") == 0)
{
pghost = argv[i + 1];
while (i+1 < argc) {
if (strcmp(argv[i], "-host") == 0) {
pghost = argv[i+1];
i += 2;
}
else if (strcmp(argv[i], "-port") == 0)
{
pgport = argv[i + 1];
else
if (strcmp(argv[i], "-port") == 0) {
pgport = argv[i+1];
i += 2;
}
else if (strcmp(argv[i], "-tty") == 0)
{
pgtty = argv[i + 1];
else
if (strcmp(argv[i], "-tty") == 0) {
pgtty = argv[i+1];
i += 2;
}
else if (strcmp(argv[i], "-options") == 0)
{
pgoptions = argv[i + 1];
else if (strcmp(argv[i], "-options") == 0) {
pgoptions = argv[i+1];
i += 2;
}
else
{
else {
Tcl_AppendResult(interp, "Bad option to pg_connect : \n",
argv[i], 0);
Tcl_AppendResult(interp, "pg_connect databaseName [-host hostName] [-port portNumber] [-tty pgtty]]", 0);
Tcl_AppendResult(interp, "pg_connect databaseName [-host hostName] [-port portNumber] [-tty pgtty]]",0);
return TCL_ERROR;
}
} /* while */
if ((i % 2 != 0) || i != argc)
{
Tcl_AppendResult(interp, "wrong # of arguments to pg_connect\n", argv[i], 0);
Tcl_AppendResult(interp, "pg_connect databaseName [-host hostName] [-port portNumber] [-tty pgtty]]", 0);
if ((i % 2 != 0) || i != argc) {
Tcl_AppendResult(interp, "wrong # of arguments to pg_connect\n", argv[i],0);
Tcl_AppendResult(interp, "pg_connect databaseName [-host hostName] [-port portNumber] [-tty pgtty]]",0);
return TCL_ERROR;
}
}
......@@ -376,13 +360,11 @@ Pg_connect(ClientData cData, Tcl_Interp * interp, int argc, char *argv[])
conn = PQsetdb(pghost, pgport, pgoptions, pgtty, dbName);
}
if (conn->status == CONNECTION_OK)
{
PgSetConnectionId(cd, interp->result, conn);
if (conn->status == CONNECTION_OK) {
PgSetConnectionId(interp, conn);
return TCL_OK;
}
else
{
else {
Tcl_AppendResult(interp, "Connection to database failed\n", 0);
Tcl_AppendResult(interp, conn->errorMessage, 0);
PQfinish(conn);
......@@ -403,27 +385,23 @@ Pg_connect(ClientData cData, Tcl_Interp * interp, int argc, char *argv[])
**********************************/
int
Pg_disconnect(ClientData cData, Tcl_Interp * interp, int argc, char *argv[])
Pg_disconnect(ClientData cData, Tcl_Interp *interp, int argc, char* argv[])
{
Pg_clientData *cd = (Pg_clientData *) cData;
PGconn *conn;
Tcl_Channel conn_chan;
if (argc != 2)
{
if (argc != 2) {
Tcl_AppendResult(interp, "Wrong # of arguments\n", "pg_disconnect connection", 0);
return TCL_ERROR;
}
conn = PgGetConnectionId(cd, argv[1]);
if (conn == (PGconn *) NULL)
{
Tcl_AppendResult(interp, "First argument is not a valid connection\n", 0);
conn_chan = Tcl_GetChannel(interp, argv[1], 0);
if (conn_chan == NULL) {
Tcl_ResetResult(interp);
Tcl_AppendResult(interp, argv[1], " is not a valid connection\n", 0);
return TCL_ERROR;
}
PgDelConnectionId(cd, argv[1]);
PQfinish(conn);
return TCL_OK;
return Tcl_UnregisterChannel(interp, conn_chan);
}
/**********************************
......@@ -438,40 +416,61 @@ Pg_disconnect(ClientData cData, Tcl_Interp * interp, int argc, char *argv[])
**********************************/
int
Pg_exec(ClientData cData, Tcl_Interp * interp, int argc, char *argv[])
Pg_exec(ClientData cData, Tcl_Interp *interp, int argc, char* argv[])
{
Pg_clientData *cd = (Pg_clientData *) cData;
Pg_ConnectionId *connid;
PGconn *conn;
PGresult *result;
int connStatus;
if (argc != 3)
{
if (argc != 3) {
Tcl_AppendResult(interp, "Wrong # of arguments\n",
"pg_exec connection queryString", 0);
return TCL_ERROR;
}
conn = PgGetConnectionId(cd, argv[1]);
if (conn == (PGconn *) NULL)
{
conn = PgGetConnectionId(interp, argv[1], &connid);
if (conn == (PGconn *)NULL) {
Tcl_AppendResult(interp, "First argument is not a valid connection\n", 0);
return TCL_ERROR;
}
if (connid->res_copyStatus != RES_COPY_NONE) {
Tcl_SetResult(interp, "Attempt to query while COPY in progress", TCL_STATIC);
return TCL_ERROR;
}
connStatus = conn->status;
result = PQexec(conn, argv[2]);
if (result)
{
PgSetResultId(cd, interp->result, argv[1], result);
if (result) {
int rId = PgSetResultId(interp, argv[1], result);
if (result->resultStatus == PGRES_COPY_IN ||
result->resultStatus == PGRES_COPY_OUT) {
connid->res_copyStatus = RES_COPY_INPROGRESS;
connid->res_copy = rId;
}
return TCL_OK;
}
else
{
else {
/* error occurred during the query */
Tcl_SetResult(interp, conn->errorMessage, TCL_STATIC);
return TCL_ERROR;
if (connStatus == CONNECTION_OK) {
PQreset(conn);
if (conn->status == CONNECTION_OK) {
result = PQexec(conn, argv[2]);
if (result) {
int rId = PgSetResultId(interp, argv[1], result);
if (result->resultStatus == PGRES_COPY_IN ||
result->resultStatus == PGRES_COPY_OUT) {
connid->res_copyStatus = RES_COPY_INPROGRESS;
connid->res_copy = rId;
}
/* check return status of result */
return TCL_OK;
}
}
}
return TCL_ERROR;
}
}
/**********************************
......@@ -488,10 +487,8 @@ Pg_exec(ClientData cData, Tcl_Interp * interp, int argc, char *argv[])
the connection that produced the result
-assign arrayName
assign the results to an array
-assignbyidx arrayName ?appendstr?
-assignbyidx arrayName
assign the results to an array using the first field as a key
optional appendstr append that string to the key name. Usefull for
creating pseudo-multi dimentional arrays in tcl.
-numTuples
the number of tuples in the query
-attributes
......@@ -502,87 +499,73 @@ Pg_exec(ClientData cData, Tcl_Interp * interp, int argc, char *argv[])
returns the number of attributes returned by the query
-getTuple tupleNumber
returns the values of the tuple in a list
-tupleArray tupleNumber arrayName
stores the values of the tuple in array arrayName, indexed
by the attributes returned
-clear
clear the result buffer. Do not reuse after this
**********************************/
int
Pg_result(ClientData cData, Tcl_Interp * interp, int argc, char *argv[])
Pg_result(ClientData cData, Tcl_Interp *interp, int argc, char* argv[])
{
Pg_clientData *cd = (Pg_clientData *) cData;
PGresult *result;
char *opt;
int i;
int tupno;
char prearrayInd[MAX_MESSAGE_LEN];
char arrayInd[MAX_MESSAGE_LEN];
char *appendstr;
char *arrVar;
if (argc != 3 && argc != 4 && argc != 5)
{
Tcl_AppendResult(interp, "Wrong # of arguments\n", 0);
if (argc < 3 || argc > 5) {
Tcl_AppendResult(interp, "Wrong # of arguments\n",0);
goto Pg_result_errReturn;
}
result = PgGetResultId(cd, argv[1]);
if (result == (PGresult *) NULL)
{
Tcl_AppendResult(interp, "First argument is not a valid query result\n", 0);
result = PgGetResultId(interp, argv[1]);
if (result == (PGresult *)NULL) {
Tcl_AppendResult(interp, "First argument is not a valid query result", 0);
return TCL_ERROR;
}
opt = argv[2];
if (strcmp(opt, "-status") == 0)
{
if (strcmp(opt, "-status") == 0) {
Tcl_AppendResult(interp, pgresStatus[PQresultStatus(result)], 0);
return TCL_OK;
}
else if (strcmp(opt, "-oid") == 0)
{
else if (strcmp(opt, "-oid") == 0) {
Tcl_AppendResult(interp, PQoidStatus(result), 0);
return TCL_OK;
}
else if (strcmp(opt, "-conn") == 0)
{
PgGetConnByResultId(cd, interp->result, argv[1]);
return TCL_OK;
else if (strcmp(opt, "-conn") == 0) {
return PgGetConnByResultId(interp, argv[1]);
}
else if (strcmp(opt, "-clear") == 0)
{
PgDelResultId(cd, argv[1]);
else if (strcmp(opt, "-clear") == 0) {
PgDelResultId(interp, argv[1]);
PQclear(result);
return TCL_OK;
}
else if (strcmp(opt, "-numTuples") == 0)
{
else if (strcmp(opt, "-numTuples") == 0) {
sprintf(interp->result, "%d", PQntuples(result));
return TCL_OK;
}
else if (strcmp(opt, "-assign") == 0)
{
if (argc != 4)
{
Tcl_AppendResult(interp, "-assign option must be followed by a variable name", 0);
else if (strcmp(opt, "-assign") == 0) {
if (argc != 4) {
Tcl_AppendResult(interp, "-assign option must be followed by a variable name",0);
return TCL_ERROR;
}
arrVar = argv[3];
/*
* 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)
*/
for (tupno = 0; tupno < PQntuples(result); tupno++)
{
for (i = 0; i < PQnfields(result); i++)
{
sprintf(arrayInd, "%d,%s", tupno, PQfname(result, i));
/* 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)*/
for (tupno = 0; tupno<PQntuples(result); tupno++) {
for (i=0;i<PQnfields(result);i++) {
sprintf(arrayInd, "%d,%s", tupno, PQfname(result,i));
Tcl_SetVar2(interp, arrVar, arrayInd,
#ifdef TCL_ARRAYS
tcl_value(PQgetvalue(result, tupno, i)),
tcl_value(PQgetvalue(result,tupno,i)),
#else
PQgetvalue(result, tupno, i),
PQgetvalue(result,tupno,i),
#endif
TCL_LEAVE_ERR_MSG);
}
......@@ -590,91 +573,84 @@ Pg_result(ClientData cData, Tcl_Interp * interp, int argc, char *argv[])
Tcl_AppendResult(interp, arrVar, 0);
return TCL_OK;
}
else if (strcmp(opt, "-assignbyidx") == 0)
{
if (argc != 4 && argc != 5)
{
Tcl_AppendResult(interp, "-assignbyidx requires the array name and takes one optional argument as an append string", 0);
else if (strcmp(opt, "-assignbyidx") == 0) {
if (argc != 4) {
Tcl_AppendResult(interp, "-assignbyidx option must be followed by a variable name",0);
return TCL_ERROR;
}
arrVar = argv[3];
/*
* 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)
*/
if (argc == 5)
{
appendstr = argv[4];
}
else
{
appendstr = "";
}
for (tupno = 0; tupno < PQntuples(result); tupno++)
{
sprintf(prearrayInd, "%s", PQgetvalue(result, tupno, 0));
for (i = 1; i < PQnfields(result); i++)
{
sprintf(arrayInd, "%s,%s%s", prearrayInd, PQfname(result, i),
appendstr);
/* 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)*/
for (tupno = 0; tupno<PQntuples(result); tupno++) {
sprintf(prearrayInd,"%s",PQgetvalue(result,tupno,0));
for (i=1;i<PQnfields(result);i++) {
sprintf(arrayInd, "%s,%s", prearrayInd, PQfname(result,i));
Tcl_SetVar2(interp, arrVar, arrayInd,
PQgetvalue(result, tupno, i),
PQgetvalue(result,tupno,i),
TCL_LEAVE_ERR_MSG);
}
}
Tcl_AppendResult(interp, arrVar, 0);
return TCL_OK;
}
else if (strcmp(opt, "-getTuple") == 0)
{
if (argc != 4)
{
Tcl_AppendResult(interp, "-getTuple option must be followed by a tuple number", 0);
else if (strcmp(opt, "-getTuple") == 0) {
if (argc != 4) {
Tcl_AppendResult(interp, "-getTuple option must be followed by a tuple number",0);
return TCL_ERROR;
}
tupno = atoi(argv[3]);
if (tupno >= PQntuples(result))
{
Tcl_AppendResult(interp, "argument to getTuple cannot exceed number of tuples - 1", 0);
if (tupno >= PQntuples(result)) {
Tcl_AppendResult(interp, "argument to getTuple cannot exceed number of tuples - 1",0);
return TCL_ERROR;
}
#ifdef TCL_ARRAYS
for (i = 0; i < PQnfields(result); i++)
{
Tcl_AppendElement(interp, PQgetvalue(result, tupno, i));
for (i=0; i<PQnfields(result); i++) {
Tcl_AppendElement(interp, tcl_value(PQgetvalue(result,tupno,i)));
}
#else
/* Tcl_AppendResult(interp, PQgetvalue(result,tupno,0),NULL); */
Tcl_AppendElement(interp, PQgetvalue(result, tupno, 0));
for (i = 1; i < PQnfields(result); i++)
{
Tcl_AppendElement(interp, PQgetvalue(result,tupno,0));
for (i=1;i<PQnfields(result);i++) {
/* Tcl_AppendResult(interp, " ", PQgetvalue(result,tupno,i),NULL);*/
Tcl_AppendElement(interp, PQgetvalue(result, tupno, i));
Tcl_AppendElement(interp, PQgetvalue(result,tupno,i));
}
#endif
return TCL_OK;
}
else if (strcmp(opt, "-attributes") == 0)
{
Tcl_AppendResult(interp, PQfname(result, 0), NULL);
for (i = 1; i < PQnfields(result); i++)
{
Tcl_AppendResult(interp, " ", PQfname(result, i), NULL);
else if (strcmp(opt, "-tupleArray") == 0) {
if (argc != 5) {
Tcl_AppendResult(interp, "-tupleArray option must be followed by a tuple number and array name",0);
return TCL_ERROR;
}
tupno = atoi(argv[3]);
if (tupno >= PQntuples(result)) {
Tcl_AppendResult(interp, "argument to tupleArray cannot exceed number of tuples - 1",0);
return TCL_ERROR;
}
for ( i = 0; i < PQnfields(result); i++) {
if (Tcl_SetVar2(interp, argv[4], PQfname(result, i), PQgetvalue(result, tupno, i), TCL_LEAVE_ERR_MSG) == NULL) {
return TCL_ERROR;
}
}
return TCL_OK;
}
else if (strcmp(opt, "-lAttributes") == 0)
{
else if (strcmp(opt, "-attributes") == 0) {
Tcl_AppendResult(interp, PQfname(result,0),NULL);
for (i=1;i<PQnfields(result);i++) {
Tcl_AppendResult(interp, " ", PQfname(result,i), NULL);
}
return TCL_OK;
}
else if (strcmp(opt, "-lAttributes") == 0) {
char buf[512];
Tcl_ResetResult(interp);
for (i = 0; i < PQnfields(result); i++)
{
for (i = 0; i < PQnfields(result); i++) {
sprintf(buf, "{%s} %ld %d", PQfname(result, i),
(long) PQftype(result, i),
PQfsize(result, i));
......@@ -682,33 +658,32 @@ Pg_result(ClientData cData, Tcl_Interp * interp, int argc, char *argv[])
}
return TCL_OK;
}
else if (strcmp(opt, "-numAttrs") == 0)
{
else if (strcmp(opt, "-numAttrs") == 0) {
sprintf(interp->result, "%d", PQnfields(result));
return TCL_OK;
}
else
{
Tcl_AppendResult(interp, "Invalid option", 0);
else {
Tcl_AppendResult(interp, "Invalid option",0);
goto Pg_result_errReturn;
}
Pg_result_errReturn:
Pg_result_errReturn:
Tcl_AppendResult(interp,
"pg_result result ?option? where ?option is\n",
"\t-status\n",
"\t-conn\n",
"\t-assign arrayVarName\n",
"\t-assignbyidx arrayVarName ?appendstr?\n",
"\t-assignbyidx arrayVarName\n",
"\t-numTuples\n",
"\t-attributes\n"
"\t-lAttributes\n"
"\t-numAttrs\n"
"\t-getTuple tupleNumber\n",
"\t-tupleArray tupleNumber arrayVarName\n",
"\t-clear\n",
"\t-oid\n",
0);
(char*)0);
return TCL_ERROR;
......@@ -725,24 +700,21 @@ Pg_result_errReturn:
**********************/
int
Pg_lo_open(ClientData cData, Tcl_Interp * interp, int argc, char *argv[])
Pg_lo_open(ClientData cData, Tcl_Interp *interp, int argc, char* argv[])
{
Pg_clientData *cd = (Pg_clientData *) cData;
PGconn *conn;
int lobjId;
int mode;
int fd;
if (argc != 4)
{
if (argc != 4) {
Tcl_AppendResult(interp, "Wrong # of arguments\n",
"pg_lo_open connection lobjOid mode", 0);
return TCL_ERROR;
}
conn = PgGetConnectionId(cd, argv[1]);
if (conn == (PGconn *) NULL)
{
conn = PgGetConnectionId(interp, argv[1], (Pg_ConnectionId**)NULL);
if (conn == (PGconn *)NULL) {
Tcl_AppendResult(interp, "First argument is not a valid connection\n", 0);
return TCL_ERROR;
}
......@@ -751,11 +723,10 @@ Pg_lo_open(ClientData cData, Tcl_Interp * interp, int argc, char *argv[])
if (strlen(argv[3]) < 1 ||
strlen(argv[3]) > 2)
{
Tcl_AppendResult(interp, "mode argument must be 'r', 'w', or 'rw'", 0);
Tcl_AppendResult(interp,"mode argument must be 'r', 'w', or 'rw'",0);
return TCL_ERROR;
}
switch (argv[3][0])
{
switch (argv[3][0]) {
case 'r':
case 'R':
mode = INV_READ;
......@@ -765,11 +736,10 @@ Pg_lo_open(ClientData cData, Tcl_Interp * interp, int argc, char *argv[])
mode = INV_WRITE;
break;
default:
Tcl_AppendResult(interp, "mode argument must be 'r', 'w', or 'rw'", 0);
Tcl_AppendResult(interp,"mode argument must be 'r', 'w', or 'rw'",0);
return TCL_ERROR;
}
switch (argv[3][1])
{
switch (argv[3][1]) {
case '\0':
break;
case 'r':
......@@ -781,12 +751,12 @@ Pg_lo_open(ClientData cData, Tcl_Interp * interp, int argc, char *argv[])
mode = mode & INV_WRITE;
break;
default:
Tcl_AppendResult(interp, "mode argument must be 'r', 'w', or 'rw'", 0);
Tcl_AppendResult(interp,"mode argument must be 'r', 'w', or 'rw'",0);
return TCL_ERROR;
}
fd = lo_open(conn, lobjId, mode);
sprintf(interp->result, "%d", fd);
fd = lo_open(conn,lobjId,mode);
sprintf(interp->result,"%d",fd);
return TCL_OK;
}
......@@ -799,28 +769,25 @@ Pg_lo_open(ClientData cData, Tcl_Interp * interp, int argc, char *argv[])
**********************/
int
Pg_lo_close(ClientData cData, Tcl_Interp * interp, int argc, char *argv[])
Pg_lo_close(ClientData cData, Tcl_Interp *interp, int argc, char* argv[])
{
Pg_clientData *cd = (Pg_clientData *) cData;
PGconn *conn;
int fd;
if (argc != 3)
{
if (argc != 3) {
Tcl_AppendResult(interp, "Wrong # of arguments\n",
"pg_lo_close connection fd", 0);
return TCL_ERROR;
}
conn = PgGetConnectionId(cd, argv[1]);
if (conn == (PGconn *) NULL)
{
conn = PgGetConnectionId(interp, argv[1], (Pg_ConnectionId**)NULL);
if (conn == (PGconn *)NULL) {
Tcl_AppendResult(interp, "First argument is not a valid connection\n", 0);
return TCL_ERROR;
}
fd = atoi(argv[2]);
sprintf(interp->result, "%d", lo_close(conn, fd));
sprintf(interp->result,"%d",lo_close(conn,fd));
return TCL_OK;
}
......@@ -836,9 +803,8 @@ Pg_lo_close(ClientData cData, Tcl_Interp * interp, int argc, char *argv[])
**********************/
int
Pg_lo_read(ClientData cData, Tcl_Interp * interp, int argc, char *argv[])
Pg_lo_read(ClientData cData, Tcl_Interp *interp, int argc, char* argv[])
{
Pg_clientData *cd = (Pg_clientData *) cData;
PGconn *conn;
int fd;
int nbytes = 0;
......@@ -846,16 +812,14 @@ Pg_lo_read(ClientData cData, Tcl_Interp * interp, int argc, char *argv[])
char *bufVar;
int len;
if (argc != 5)
{
if (argc != 5) {
Tcl_AppendResult(interp, "Wrong # of arguments\n",
" pg_lo_read conn fd bufVar len", 0);
return TCL_ERROR;
}
conn = PgGetConnectionId(cd, argv[1]);
if (conn == (PGconn *) NULL)
{
conn = PgGetConnectionId(interp, argv[1], (Pg_ConnectionId**)NULL);
if (conn == (PGconn *)NULL) {
Tcl_AppendResult(interp, "First argument is not a valid connection\n", 0);
return TCL_ERROR;
}
......@@ -866,18 +830,17 @@ Pg_lo_read(ClientData cData, Tcl_Interp * interp, int argc, char *argv[])
len = atoi(argv[4]);
if (len <= 0)
{
sprintf(interp->result, "%d", nbytes);
if (len <= 0) {
sprintf(interp->result,"%d",nbytes);
return TCL_OK;
}
buf = malloc(sizeof(len + 1));
buf = ckalloc(sizeof(len+1));
nbytes = lo_read(conn, fd, buf, len);
nbytes = lo_read(conn,fd,buf,len);
Tcl_SetVar(interp, bufVar, buf, TCL_LEAVE_ERR_MSG);
sprintf(interp->result, "%d", nbytes);
free(buf);
Tcl_SetVar(interp,bufVar,buf,TCL_LEAVE_ERR_MSG);
sprintf(interp->result,"%d",nbytes);
ckfree(buf);
return TCL_OK;
}
......@@ -891,25 +854,22 @@ Pg_lo_write
***********************************/
int
Pg_lo_write(ClientData cData, Tcl_Interp * interp, int argc, char *argv[])
Pg_lo_write(ClientData cData, Tcl_Interp *interp, int argc, char* argv[])
{
Pg_clientData *cd = (Pg_clientData *) cData;
PGconn *conn;
char *buf;
int fd;
int nbytes = 0;
int len;
if (argc != 5)
{
if (argc != 5) {
Tcl_AppendResult(interp, "Wrong # of arguments\n",
"pg_lo_write conn fd buf len", 0);
return TCL_ERROR;
}
conn = PgGetConnectionId(cd, argv[1]);
if (conn == (PGconn *) NULL)
{
conn = PgGetConnectionId(interp, argv[1], (Pg_ConnectionId**)NULL);
if (conn == (PGconn *)NULL) {
Tcl_AppendResult(interp, "First argument is not a valid connection\n", 0);
return TCL_ERROR;
}
......@@ -920,14 +880,13 @@ Pg_lo_write(ClientData cData, Tcl_Interp * interp, int argc, char *argv[])
len = atoi(argv[4]);
if (len <= 0)
{
sprintf(interp->result, "%d", nbytes);
if (len <= 0) {
sprintf(interp->result,"%d",nbytes);
return TCL_OK;
}
nbytes = lo_write(conn, fd, buf, len);
sprintf(interp->result, "%d", nbytes);
nbytes = lo_write(conn,fd,buf,len);
sprintf(interp->result,"%d",nbytes);
return TCL_OK;
}
......@@ -942,25 +901,21 @@ whence can be either
"SEEK_CUR", "SEEK_END", or "SEEK_SET"
***********************************/
int
Pg_lo_lseek(ClientData cData, Tcl_Interp * interp, int argc, char *argv[])
Pg_lo_lseek(ClientData cData, Tcl_Interp *interp, int argc, char* argv[])
{
Pg_clientData *cd = (Pg_clientData *) cData;
PGconn *conn;
int fd;
char *whenceStr;
int offset,
whence;
int offset, whence;
if (argc != 5)
{
if (argc != 5) {
Tcl_AppendResult(interp, "Wrong # of arguments\n",
"pg_lo_lseek conn fd offset whence", 0);
return TCL_ERROR;
}
conn = PgGetConnectionId(cd, argv[1]);
if (conn == (PGconn *) NULL)
{
conn = PgGetConnectionId(interp, argv[1], (Pg_ConnectionId**)NULL);
if (conn == (PGconn *)NULL) {
Tcl_AppendResult(interp, "First argument is not a valid connection\n", 0);
return TCL_ERROR;
}
......@@ -970,25 +925,18 @@ Pg_lo_lseek(ClientData cData, Tcl_Interp * interp, int argc, char *argv[])
offset = atoi(argv[3]);
whenceStr = argv[4];
if (strcmp(whenceStr, "SEEK_SET") == 0)
{
if (strcmp(whenceStr,"SEEK_SET") == 0) {
whence = SEEK_SET;
}
else if (strcmp(whenceStr, "SEEK_CUR") == 0)
{
} else if (strcmp(whenceStr,"SEEK_CUR") == 0) {
whence = SEEK_CUR;
}
else if (strcmp(whenceStr, "SEEK_END") == 0)
{
} else if (strcmp(whenceStr,"SEEK_END") == 0) {
whence = SEEK_END;
}
else
{
Tcl_AppendResult(interp, "the whence argument to Pg_lo_lseek must be SEEK_SET, SEEK_CUR or SEEK_END", 0);
} else {
Tcl_AppendResult(interp, "the whence argument to Pg_lo_lseek must be SEEK_SET, SEEK_CUR or SEEK_END",0);
return TCL_ERROR;
}
sprintf(interp->result, "%d", lo_lseek(conn, fd, offset, whence));
sprintf(interp->result,"%d",lo_lseek(conn,fd,offset,whence));
return TCL_OK;
}
......@@ -1000,71 +948,57 @@ Pg_lo_creat
syntax:
pg_lo_creat conn mode
mode can be any OR'ing together of INV_READ, INV_WRITE
mode can be any OR'ing together of INV_READ, INV_WRITE,
for now, we don't support any additional storage managers.
***********************************/
int
Pg_lo_creat(ClientData cData, Tcl_Interp * interp, int argc, char *argv[])
Pg_lo_creat(ClientData cData, Tcl_Interp *interp, int argc, char* argv[])
{
Pg_clientData *cd = (Pg_clientData *) cData;
PGconn *conn;
char *modeStr;
char *modeWord;
int mode;
if (argc != 3)
{
if (argc != 3) {
Tcl_AppendResult(interp, "Wrong # of arguments\n",
"pg_lo_creat conn mode", 0);
return TCL_ERROR;
}
conn = PgGetConnectionId(cd, argv[1]);
if (conn == (PGconn *) NULL)
{
conn = PgGetConnectionId(interp, argv[1], (Pg_ConnectionId**)NULL);
if (conn == (PGconn *)NULL) {
Tcl_AppendResult(interp, "First argument is not a valid connection\n", 0);
return TCL_ERROR;
}
modeStr = argv[2];
modeWord = strtok(modeStr, "|");
if (strcmp(modeWord, "INV_READ") == 0)
{
modeWord = strtok(modeStr,"|");
if (strcmp(modeWord,"INV_READ") == 0) {
mode = INV_READ;
}
else if (strcmp(modeWord, "INV_WRITE") == 0)
{
} else if (strcmp(modeWord,"INV_WRITE") == 0) {
mode = INV_WRITE;
}
else
{
} else {
Tcl_AppendResult(interp,
"invalid mode argument to Pg_lo_creat\nmode argument must be some OR'd combination of INV_READ, and INV_WRITE",
0);
return TCL_ERROR;
}
while ((modeWord = strtok((char *) NULL, "|")) != NULL)
{
if (strcmp(modeWord, "INV_READ") == 0)
{
while ( (modeWord = strtok((char*)NULL, "|")) != NULL) {
if (strcmp(modeWord,"INV_READ") == 0) {
mode |= INV_READ;
}
else if (strcmp(modeWord, "INV_WRITE") == 0)
{
} else if (strcmp(modeWord,"INV_WRITE") == 0) {
mode |= INV_WRITE;
}
else
{
} else {
Tcl_AppendResult(interp,
"invalid mode argument to Pg_lo_creat\nmode argument must be some OR'd combination of INV_READ, and INV_WRITE",
"invalid mode argument to Pg_lo_creat\nmode argument must be some OR'd combination of INV_READ, INV_WRITE",
0);
return TCL_ERROR;
}
}
sprintf(interp->result, "%d", lo_creat(conn, mode));
sprintf(interp->result,"%d",lo_creat(conn,mode));
return TCL_OK;
}
......@@ -1077,29 +1011,26 @@ Pg_lo_tell
***********************************/
int
Pg_lo_tell(ClientData cData, Tcl_Interp * interp, int argc, char *argv[])
Pg_lo_tell(ClientData cData, Tcl_Interp *interp, int argc, char* argv[])
{
Pg_clientData *cd = (Pg_clientData *) cData;
PGconn *conn;
int fd;
if (argc != 3)
{
if (argc != 3) {
Tcl_AppendResult(interp, "Wrong # of arguments\n",
"pg_lo_tell conn fd", 0);
return TCL_ERROR;
}
conn = PgGetConnectionId(cd, argv[1]);
if (conn == (PGconn *) NULL)
{
conn = PgGetConnectionId(interp, argv[1], (Pg_ConnectionId**)NULL);
if (conn == (PGconn *)NULL) {
Tcl_AppendResult(interp, "First argument is not a valid connection\n", 0);
return TCL_ERROR;
}
fd = atoi(argv[2]);
sprintf(interp->result, "%d", lo_tell(conn, fd));
sprintf(interp->result,"%d",lo_tell(conn,fd));
return TCL_OK;
}
......@@ -1114,37 +1045,33 @@ Pg_lo_unlink
***********************************/
int
Pg_lo_unlink(ClientData cData, Tcl_Interp * interp, int argc, char *argv[])
Pg_lo_unlink(ClientData cData, Tcl_Interp *interp, int argc, char* argv[])
{
Pg_clientData *cd = (Pg_clientData *) cData;
PGconn *conn;
int lobjId;
int retval;
if (argc != 3)
{
if (argc != 3) {
Tcl_AppendResult(interp, "Wrong # of arguments\n",
"pg_lo_tell conn fd", 0);
return TCL_ERROR;
}
conn = PgGetConnectionId(cd, argv[1]);
if (conn == (PGconn *) NULL)
{
conn = PgGetConnectionId(interp, argv[1], (Pg_ConnectionId**)NULL);
if (conn == (PGconn *)NULL) {
Tcl_AppendResult(interp, "First argument is not a valid connection\n", 0);
return TCL_ERROR;
}
lobjId = atoi(argv[2]);
retval = lo_unlink(conn, lobjId);
if (retval == -1)
{
sprintf(interp->result, "Pg_lo_unlink of '%d' failed", lobjId);
retval = lo_unlink(conn,lobjId);
if (retval == -1) {
sprintf(interp->result,"Pg_lo_unlink of '%d' failed",lobjId);
return TCL_ERROR;
}
sprintf(interp->result, "%d", retval);
sprintf(interp->result,"%d",retval);
return TCL_OK;
}
......@@ -1160,36 +1087,32 @@ Pg_lo_import
***********************************/
int
Pg_lo_import(ClientData cData, Tcl_Interp * interp, int argc, char *argv[])
Pg_lo_import(ClientData cData, Tcl_Interp *interp, int argc, char* argv[])
{
Pg_clientData *cd = (Pg_clientData *) cData;
PGconn *conn;
char *filename;
char* filename;
Oid lobjId;
if (argc != 3)
{
if (argc != 3) {
Tcl_AppendResult(interp, "Wrong # of arguments\n",
"pg_lo_import conn filename", 0);
return TCL_ERROR;
}
conn = PgGetConnectionId(cd, argv[1]);
if (conn == (PGconn *) NULL)
{
conn = PgGetConnectionId(interp, argv[1], (Pg_ConnectionId**)NULL);
if (conn == (PGconn *)NULL) {
Tcl_AppendResult(interp, "First argument is not a valid connection\n", 0);
return TCL_ERROR;
}
filename = argv[2];
lobjId = lo_import(conn, filename);
if (lobjId == InvalidOid)
{
sprintf(interp->result, "Pg_lo_import of '%s' failed", filename);
lobjId = lo_import(conn,filename);
if (lobjId == InvalidOid) {
sprintf(interp->result, "Pg_lo_import of '%s' failed",filename);
return TCL_ERROR;
}
sprintf(interp->result, "%d", lobjId);
sprintf(interp->result,"%d",lobjId);
return TCL_OK;
}
......@@ -1203,24 +1126,21 @@ Pg_lo_export
***********************************/
int
Pg_lo_export(ClientData cData, Tcl_Interp * interp, int argc, char *argv[])
Pg_lo_export(ClientData cData, Tcl_Interp *interp, int argc, char* argv[])
{
Pg_clientData *cd = (Pg_clientData *) cData;
PGconn *conn;
char *filename;
char* filename;
Oid lobjId;
int retval;
if (argc != 4)
{
if (argc != 4) {
Tcl_AppendResult(interp, "Wrong # of arguments\n",
"pg_lo_export conn lobjId filename", 0);
return TCL_ERROR;
}
conn = PgGetConnectionId(cd, argv[1]);
if (conn == (PGconn *) NULL)
{
conn = PgGetConnectionId(interp, argv[1], (Pg_ConnectionId**)NULL);
if (conn == (PGconn *)NULL) {
Tcl_AppendResult(interp, "First argument is not a valid connection\n", 0);
return TCL_ERROR;
}
......@@ -1228,10 +1148,9 @@ Pg_lo_export(ClientData cData, Tcl_Interp * interp, int argc, char *argv[])
lobjId = atoi(argv[2]);
filename = argv[3];
retval = lo_export(conn, lobjId, filename);
if (retval == -1)
{
sprintf(interp->result, "Pg_lo_export %d %s failed", lobjId, filename);
retval = lo_export(conn,lobjId,filename);
if (retval == -1) {
sprintf(interp->result, "Pg_lo_export %d %s failed",lobjId, filename);
return TCL_ERROR;
}
return TCL_OK;
......@@ -1259,19 +1178,15 @@ Pg_lo_export(ClientData cData, Tcl_Interp * interp, int argc, char *argv[])
**********************************/
int
Pg_select(ClientData cData, Tcl_Interp * interp, int argc, char **argv)
Pg_select(ClientData cData, Tcl_Interp *interp, int argc, char **argv)
{
Pg_clientData *cd = (Pg_clientData *) cData;
PGconn *conn;
PGresult *result;
int r;
size_t tupno,
column,
ncols;
size_t tupno, column, ncols;
Tcl_DString headers;
char buffer[2048];
struct
{
struct info_s {
char *cname;
int change;
} *info;
......@@ -1283,10 +1198,8 @@ Pg_select(ClientData cData, Tcl_Interp * interp, int argc, char **argv)
return TCL_ERROR;
}
conn = PgGetConnectionId(cd, argv[1]);
if (conn == (PGconn *) NULL)
{
Tcl_AppendResult(interp, "First argument is not a valid connection\n", 0);
conn = PgGetConnectionId(interp, argv[1], (Pg_ConnectionId**)NULL);
if (conn == (PGconn *)NULL) {
return TCL_ERROR;
}
......@@ -1297,7 +1210,7 @@ Pg_select(ClientData cData, Tcl_Interp * interp, int argc, char **argv)
return TCL_ERROR;
}
if ((info = malloc(sizeof(*info) * (ncols = PQnfields(result)))) == NULL)
if ((info = (struct info_s *)ckalloc(sizeof(*info) * (ncols = PQnfields(result)))) == NULL)
{
Tcl_AppendResult(interp, "Not enough memory", 0);
return TCL_ERROR;
......@@ -1323,8 +1236,8 @@ Pg_select(ClientData cData, Tcl_Interp * interp, int argc, char **argv)
for (column = 0; column < ncols; column++)
{
Tcl_SetVar2(interp, argv[3], info[column].cname,
PQgetvalue(result, tupno, column), 0);
strcpy(buffer, PQgetvalue(result, tupno, column));
Tcl_SetVar2(interp, argv[3], info[column].cname, buffer, 0);
}
Tcl_SetVar2(interp, argv[3], ".command", "update", 0);
......@@ -1332,17 +1245,8 @@ Pg_select(ClientData cData, Tcl_Interp * interp, int argc, char **argv)
if ((r = Tcl_Eval(interp, argv[4])) != TCL_OK && r != TCL_CONTINUE)
{
if (r == TCL_BREAK)
{
/*
* I suppose that memory used by info and result must be
* released
*/
free(info);
PQclear(result);
Tcl_UnsetVar(interp, argv[3], 0);
return TCL_OK;
}
if (r == TCL_ERROR)
{
char msg[60];
......@@ -1351,35 +1255,29 @@ Pg_select(ClientData cData, Tcl_Interp * interp, int argc, char **argv)
interp->errorLine);
Tcl_AddErrorInfo(interp, msg);
}
/* also, releasing memory used by info and result */
free(info);
PQclear(result);
Tcl_UnsetVar(interp, argv[3], 0);
return r;
}
}
free(info);
/* Release memory used by result */
PQclear(result);
ckfree((void*)info);
Tcl_UnsetVar(interp, argv[3], 0);
Tcl_AppendResult(interp, "", 0);
return TCL_OK;
}
int
Pg_listen(ClientData cData, Tcl_Interp * interp, int argc, char *argv[])
Pg_listen(ClientData cData, Tcl_Interp *interp, int argc, char* argv[])
{
Pg_clientData *cd = (Pg_clientData *) cData;
int new;
char *relname;
char *callback = NULL;
Tcl_HashEntry *entry;
Pg_ConnectionId *connid;
PGconn *conn;
PGresult *result;
if ((argc < 3) || (argc > 4))
{
if ((argc < 3) || (argc > 4)) {
Tcl_AppendResult(interp, "wrong # args, should be \"",
argv[0], " connection relname ?callback?\"", 0);
return TCL_ERROR;
......@@ -1389,47 +1287,38 @@ Pg_listen(ClientData cData, Tcl_Interp * interp, int argc, char *argv[])
* Get the command arguments. Note that relname will copied by
* Tcl_CreateHashEntry while callback must be allocated.
*/
conn = (PGconn *) PgGetConnectionId(cd, argv[1]);
if (conn == (PGconn *) NULL)
{
conn = PgGetConnectionId(interp, argv[1], &connid);
if (conn == (PGconn *)NULL) {
Tcl_AppendResult(interp, "First argument is not a valid connection\n", 0);
return TCL_ERROR;
}
relname = argv[2];
if ((argc > 3) && *argv[3])
{
callback = (char *) ckalloc((unsigned) (strlen(argv[3]) + 1));
if ((argc > 3) && *argv[3]) {
callback = (char *) ckalloc((unsigned) (strlen(argv[3])+1));
strcpy(callback, argv[3]);
}
/*
* Set or update a callback for a relation;
*/
if (callback)
{
entry = Tcl_CreateHashEntry(&(cd->notify_hash), relname, &new);
if (new)
{
if (callback) {
entry = Tcl_CreateHashEntry(&(connid->notify_hash), relname, &new);
if (new) {
/* New callback, execute a listen command on the relation */
char *cmd = (char *) ckalloc((unsigned) (strlen(argv[2]) + 8));
char *cmd = (char *) ckalloc((unsigned) (strlen(argv[2])+8));
sprintf(cmd, "LISTEN %s", relname);
result = PQexec(conn, cmd);
ckfree(cmd);
if (!result || (result->resultStatus != PGRES_COMMAND_OK))
{
if (!result || (result->resultStatus != PGRES_COMMAND_OK)) {
/* Error occurred during the execution of command */
if (result)
PQclear(result);
if (result) PQclear(result);
ckfree(callback);
Tcl_DeleteHashEntry(entry);
Tcl_SetResult(interp, conn->errorMessage, TCL_STATIC);
return TCL_ERROR;
}
PQclear(result);
}
else
{
} else {
/* Free the old callback string */
ckfree((char *) Tcl_GetHashValue(entry));
}
......@@ -1438,14 +1327,13 @@ Pg_listen(ClientData cData, Tcl_Interp * interp, int argc, char *argv[])
}
/*
* Remove a callback for a relation. There is no way to un-listen a
* relation, simply remove the callback from the notify hash table.
* Remove a callback for a relation. There is no way to
* un-listen a relation, simply remove the callback from
* the notify hash table.
*/
if (callback == NULL)
{
entry = Tcl_FindHashEntry(&(cd->notify_hash), relname);
if (entry == NULL)
{
if (callback == NULL) {
entry = Tcl_FindHashEntry(&(connid->notify_hash), relname);
if (entry == NULL) {
Tcl_AppendResult(interp, "not listening on ", relname, 0);
return TCL_ERROR;
}
......@@ -1457,19 +1345,18 @@ Pg_listen(ClientData cData, Tcl_Interp * interp, int argc, char *argv[])
}
int
Pg_notifies(ClientData cData, Tcl_Interp * interp, int argc, char *argv[])
Pg_notifies(ClientData cData, Tcl_Interp *interp, int argc, char* argv[])
{
Pg_clientData *cd = (Pg_clientData *) cData;
int count;
char buff[12];
char *callback;
Tcl_HashEntry *entry;
Pg_ConnectionId *connid;
PGconn *conn;
PGresult *result;
PGnotify *notify;
if (argc != 2)
{
if (argc != 2) {
Tcl_AppendResult(interp, "wrong # args, should be \"",
argv[0], " connection\"", 0);
return TCL_ERROR;
......@@ -1478,17 +1365,15 @@ Pg_notifies(ClientData cData, Tcl_Interp * interp, int argc, char *argv[])
/*
* Get the connection argument.
*/
conn = (PGconn *) PgGetConnectionId(cd, argv[1]);
if (conn == (PGconn *) NULL)
{
conn = (PGconn*)PgGetConnectionId(interp, argv[1], &connid);
if (conn == (PGconn *)NULL) {
Tcl_AppendResult(interp, "First argument is not a valid connection\n", 0);
return TCL_ERROR;
}
/* Execute an empty command to retrieve asynchronous notifications */
result = PQexec(conn, " ");
if (result == NULL)
{
if (result == NULL) {
/* Error occurred during the execution of command */
Tcl_SetResult(interp, conn->errorMessage, TCL_STATIC);
return TCL_ERROR;
......@@ -1498,21 +1383,19 @@ Pg_notifies(ClientData cData, Tcl_Interp * interp, int argc, char *argv[])
/*
* Loop while there are pending notifies.
*/
for (count = 0; count < 999; count++)
{
for (count=0; count < 999; count++) {
/* See if there is a pending notification */
notify = PQnotifies(conn);
if (notify == NULL)
{
if (notify == NULL) {
break;
}
entry = Tcl_FindHashEntry(&(cd->notify_hash), notify->relname);
if (entry != NULL)
{
callback = Tcl_GetHashValue(entry);
if (callback)
{
entry = Tcl_FindHashEntry(&(connid->notify_hash), notify->relname);
if (entry != NULL) {
callback = (char*)Tcl_GetHashValue(entry);
if (callback) {
/* This should be a global eval, shouldn't it? */
Tcl_Eval(interp, callback);
/* And what if there's an error. Bgerror should be called? */
}
}
free(notify);
......
......@@ -5,7 +5,7 @@
*
* Copyright (c) 1994, Regents of the University of California
*
* $Id: pgtclCmds.h,v 1.8 1997/09/08 02:40:16 momjian Exp $
* $Id: pgtclCmds.h,v 1.9 1998/03/15 08:02:59 scrappy Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -18,89 +18,69 @@
#include "libpq-fe.h"
#include "libpq/libpq-fs.h"
typedef struct Pg_clientData_s
{
Tcl_HashTable dbh_hash;
Tcl_HashTable res_hash;
Tcl_HashTable notify_hash;
long dbh_count;
long res_count;
} Pg_clientData;
#define RES_HARD_MAX 128
#define RES_START 16
typedef struct Pg_ConnectionId_s
{
typedef struct Pg_ConnectionId_s {
char id[32];
PGconn *conn;
Tcl_HashTable res_hash;
int res_max; /* Max number of results allocated */
int res_hardmax; /* Absolute max to allow */
int res_count; /* Current count of active results */
int res_last; /* Optimize where to start looking */
int res_copy; /* Query result with active copy */
int res_copyStatus; /* Copying status */
PGresult **results; /* The results */
Tcl_HashTable notify_hash;
} Pg_ConnectionId;
typedef struct Pg_ResultId_s
{
char id[32];
PGresult *result;
Pg_ConnectionId *connection;
} Pg_ResultId;
#define RES_COPY_NONE 0
#define RES_COPY_INPROGRESS 1
#define RES_COPY_FIN 2
/* **************************/
/* registered Tcl functions */
/* **************************/
extern int
Pg_conndefaults(
ClientData cData, Tcl_Interp * interp, int argc, char *argv[]);
extern int
Pg_connect(
ClientData cData, Tcl_Interp * interp, int argc, char *argv[]);
extern int
Pg_disconnect(
ClientData cData, Tcl_Interp * interp, int argc, char *argv[]);
extern int
Pg_exec(
ClientData cData, Tcl_Interp * interp, int argc, char *argv[]);
extern int
Pg_select(
ClientData cData, Tcl_Interp * interp, int argc, char *argv[]);
extern int
Pg_result(
ClientData cData, Tcl_Interp * interp, int argc, char *argv[]);
extern int
Pg_lo_open(
ClientData cData, Tcl_Interp * interp, int argc, char *argv[]);
extern int
Pg_lo_close(
ClientData cData, Tcl_Interp * interp, int argc, char *argv[]);
extern int
Pg_lo_read(
ClientData cData, Tcl_Interp * interp, int argc, char *argv[]);
extern int
Pg_lo_write(
ClientData cData, Tcl_Interp * interp, int argc, char *argv[]);
extern int
Pg_lo_lseek(
ClientData cData, Tcl_Interp * interp, int argc, char *argv[]);
extern int
Pg_lo_creat(
ClientData cData, Tcl_Interp * interp, int argc, char *argv[]);
extern int
Pg_lo_tell(
ClientData cData, Tcl_Interp * interp, int argc, char *argv[]);
extern int
Pg_lo_unlink(
ClientData cData, Tcl_Interp * interp, int argc, char *argv[]);
extern int
Pg_lo_import(
ClientData cData, Tcl_Interp * interp, int argc, char *argv[]);
extern int
Pg_lo_export(
ClientData cData, Tcl_Interp * interp, int argc, char *argv[]);
extern int
Pg_listen(
ClientData cData, Tcl_Interp * interp, int argc, char *argv[]);
extern int
Pg_notifies(
ClientData cData, Tcl_Interp * interp, int argc, char *argv[]);
extern int Pg_conndefaults(
ClientData cData, Tcl_Interp *interp, int argc, char* argv[]);
extern int Pg_connect(
ClientData cData, Tcl_Interp *interp, int argc, char* argv[]);
extern int Pg_disconnect(
ClientData cData, Tcl_Interp *interp, int argc, char* argv[]);
extern int Pg_exec(
ClientData cData, Tcl_Interp *interp, int argc, char* argv[]);
extern int Pg_select(
ClientData cData, Tcl_Interp *interp, int argc, char* argv[]);
extern int Pg_result(
ClientData cData, Tcl_Interp *interp, int argc, char* argv[]);
extern int Pg_lo_open(
ClientData cData, Tcl_Interp *interp, int argc, char* argv[]);
extern int Pg_lo_close(
ClientData cData, Tcl_Interp *interp, int argc, char* argv[]);
extern int Pg_lo_read(
ClientData cData, Tcl_Interp *interp, int argc, char* argv[]);
extern int Pg_lo_write(
ClientData cData, Tcl_Interp *interp, int argc, char* argv[]);
extern int Pg_lo_lseek(
ClientData cData, Tcl_Interp *interp, int argc, char* argv[]);
extern int Pg_lo_creat(
ClientData cData, Tcl_Interp *interp, int argc, char* argv[]);
extern int Pg_lo_tell(
ClientData cData, Tcl_Interp *interp, int argc, char* argv[]);
extern int Pg_lo_unlink(
ClientData cData, Tcl_Interp *interp, int argc, char* argv[]);
extern int Pg_lo_import(
ClientData cData, Tcl_Interp *interp, int argc, char* argv[]);
extern int Pg_lo_export(
ClientData cData, Tcl_Interp *interp, int argc, char* argv[]);
extern int Pg_listen(
ClientData cData, Tcl_Interp *interp, int argc, char* argv[]);
extern int Pg_notifies(
ClientData cData, Tcl_Interp *interp, int argc, char* argv[]);
#endif /*PGTCLCMDS_H*/
#endif /* PGTCLCMDS_H */
......@@ -12,37 +12,162 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/interfaces/libpgtcl/Attic/pgtclId.c,v 1.7 1998/02/26 04:44:53 momjian Exp $
* $Header: /cvsroot/pgsql/src/interfaces/libpgtcl/Attic/pgtclId.c,v 1.8 1998/03/15 08:03:00 scrappy Exp $
*
*-------------------------------------------------------------------------
*/
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <tcl.h>
#include "postgres.h"
#include "pgtclCmds.h"
#include "pgtclId.h"
int 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;
connid->res_copy = -1;
*errorCodePtr = EIO;
return -1;
} else {
connid->results[connid->res_copy]->resultStatus = PGRES_COMMAND_OK;
connid->res_copy = -1;
return 0;
}
}
/*
* Called when reading data (via gets) for a copy <rel> to stdout
*/
int PgInputProc(DRIVER_INPUT_PROTO)
{
Pg_ConnectionId *connid;
PGconn *conn;
int c;
int avail;
connid = (Pg_ConnectionId *)cData;
conn = connid->conn;
if (connid->res_copy < 0 ||
connid->results[connid->res_copy]->resultStatus != PGRES_COPY_OUT) {
*errorCodePtr = EBUSY;
return -1;
}
if (connid->res_copyStatus == RES_COPY_FIN) {
return PgEndCopy(connid, errorCodePtr);
}
avail = bufSize;
while (avail > 0 &&
(c = pqGetc(conn->Pfin, conn->Pfdebug)) != EOF) {
/* fprintf(stderr, "%d: got char %c\n", bufSize-avail, c); */
*buf++ = c;
--avail;
if (c == '\n' && bufSize-avail > 3) {
if ((bufSize-avail == 3 || buf[-4] == '\n') &&
buf[-3] == '\\' && buf[-2] == '.') {
avail += 3;
connid->res_copyStatus = RES_COPY_FIN;
break;
}
}
}
/* fprintf(stderr, "returning %d chars\n", bufSize - avail); */
return bufSize - avail;
}
/*
* Called when writing data (via puts) for a copy <rel> from stdin
*/
int PgOutputProc(DRIVER_OUTPUT_PROTO)
{
Pg_ConnectionId *connid;
PGconn *conn;
connid = (Pg_ConnectionId *)cData;
conn = connid->conn;
if (connid->res_copy < 0 ||
connid->results[connid->res_copy]->resultStatus != PGRES_COPY_IN) {
*errorCodePtr = EBUSY;
return -1;
}
/*
fprintf(stderr, "PgOutputProc called: bufSize=%d: atend:%d <", bufSize,
strncmp(buf, "\\.\n", 3));
fwrite(buf, 1, bufSize, stderr);
fputs(">\n", stderr);
*/
fwrite(buf, 1, bufSize, conn->Pfout);
if (bufSize > 2 && strncmp(&buf[bufSize-3], "\\.\n", 3) == 0) {
/* fprintf(stderr,"checking closure\n"); */
fflush(conn->Pfout);
if (PgEndCopy(connid, errorCodePtr) == -1)
return -1;
}
return bufSize;
}
#if (TCL_MAJOR_VERSION == 7 && TCL_MINOR_VERSION == 6)
Tcl_File
PgGetFileProc(ClientData cData, int direction)
{
return (Tcl_File)NULL;
}
#endif
Tcl_ChannelType Pg_ConnType = {
"pgsql", /* channel type */
NULL, /* blockmodeproc */
PgDelConnectionId, /* closeproc */
PgInputProc, /* inputproc */
PgOutputProc, /* outputproc */
/* Note the additional stuff can be left NULL,
or is initialized during a PgSetConnectionId */
};
/*
* Create the Id for a new connection and hash it
* Create and register a new channel for the connection
*/
void
PgSetConnectionId(Pg_clientData * cd, char *id, PGconn *conn)
PgSetConnectionId(Tcl_Interp *interp, PGconn *conn)
{
Tcl_HashEntry *hent;
Tcl_Channel conn_chan;
Pg_ConnectionId *connid;
int hnew;
int i;
connid = (Pg_ConnectionId *) ckalloc(sizeof(Pg_ConnectionId));
connid = (Pg_ConnectionId *)ckalloc(sizeof(Pg_ConnectionId));
connid->conn = conn;
Tcl_InitHashTable(&(connid->res_hash), TCL_STRING_KEYS);
sprintf(connid->id, "pgc%ld", cd->dbh_count++);
strcpy(id, connid->id);
hent = Tcl_CreateHashEntry(&(cd->dbh_hash), connid->id, &hnew);
Tcl_SetHashValue(hent, (ClientData) connid);
connid->res_count = 0;
connid->res_last = -1;
connid->res_max = RES_START;
connid->res_hardmax = RES_HARD_MAX;
connid->res_copy = -1;
connid->res_copyStatus = RES_COPY_NONE;
connid->results = (PGresult**)ckalloc(sizeof(PGresult*) * RES_START);
for (i = 0; i < RES_START; i++) connid->results[i] = NULL;
Tcl_InitHashTable(&connid->notify_hash, TCL_STRING_KEYS);
sprintf(connid->id, "pgsql%d", fileno(conn->Pfout));
#if TCL_MAJOR_VERSION == 7 && TCL_MINOR_VERSION == 5
conn_chan = Tcl_CreateChannel(&Pg_ConnType, connid->id, conn->Pfin, conn->Pfout, (ClientData)connid);
#else
conn_chan = Tcl_CreateChannel(&Pg_ConnType, connid->id, (ClientData)connid,
TCL_READABLE | TCL_WRITABLE);
#endif
Tcl_SetChannelOption(interp, conn_chan, "-buffering", "line");
Tcl_SetResult(interp, connid->id, TCL_VOLATILE);
Tcl_RegisterChannel(interp, conn_chan);
}
......@@ -50,18 +175,21 @@ PgSetConnectionId(Pg_clientData * cd, char *id, PGconn *conn)
* Get back the connection from the Id
*/
PGconn *
PgGetConnectionId(Pg_clientData * cd, char *id)
PgGetConnectionId(Tcl_Interp *interp, char *id, Pg_ConnectionId **connid_p)
{
Tcl_HashEntry *hent;
Tcl_Channel conn_chan;
Pg_ConnectionId *connid;
hent = Tcl_FindHashEntry(&(cd->dbh_hash), id);
if (hent == NULL)
{
return (PGconn *) NULL;
conn_chan = Tcl_GetChannel(interp, id, 0);
if(conn_chan == NULL || Tcl_GetChannelType(conn_chan) != &Pg_ConnType) {
Tcl_ResetResult(interp);
Tcl_AppendResult(interp, id, " is not a valid postgresql connection\n", 0);
return (PGconn *)NULL;
}
connid = (Pg_ConnectionId *) Tcl_GetHashValue(hent);
connid = (Pg_ConnectionId *)Tcl_GetChannelInstanceData(conn_chan);
if (connid_p)
*connid_p = connid;
return connid->conn;
}
......@@ -70,78 +198,121 @@ PgGetConnectionId(Pg_clientData * cd, char *id)
* Remove a connection Id from the hash table and
* close all portals the user forgot.
*/
void
PgDelConnectionId(Pg_clientData * cd, char *id)
int PgDelConnectionId(DRIVER_DEL_PROTO)
{
Tcl_HashEntry *hent;
Tcl_HashEntry *hent2;
Tcl_HashEntry *hent3;
Tcl_HashEntry *entry;
char *hval;
Tcl_HashSearch hsearch;
Pg_ConnectionId *connid;
Pg_ResultId *resid;
int i;
hent = Tcl_FindHashEntry(&(cd->dbh_hash), id);
if (hent == NULL)
{
return;
}
connid = (Pg_ConnectionId *)cData;
connid = (Pg_ConnectionId *) Tcl_GetHashValue(hent);
for (i = 0; i < connid->res_max; i++) {
if (connid->results[i])
PQclear(connid->results[i]);
}
ckfree((void*)connid->results);
hent2 = Tcl_FirstHashEntry(&(connid->res_hash), &hsearch);
while (hent2 != NULL)
{
resid = (Pg_ResultId *) Tcl_GetHashValue(hent2);
PQclear(resid->result);
hent3 = Tcl_FindHashEntry(&(cd->res_hash), resid->id);
if (hent3 != NULL)
for (entry = Tcl_FirstHashEntry(&(connid->notify_hash), &hsearch);
entry != NULL;
entry = Tcl_NextHashEntry(&hsearch))
{
Tcl_DeleteHashEntry(hent3);
hval = (char*)Tcl_GetHashValue(entry);
ckfree(hval);
}
ckfree(resid);
hent2 = Tcl_NextHashEntry(&hsearch);
}
Tcl_DeleteHashTable(&(connid->res_hash));
Tcl_DeleteHashEntry(hent);
ckfree(connid);
Tcl_DeleteHashTable(&connid->notify_hash);
PQfinish(connid->conn);
ckfree((void*)connid);
return 0;
}
/*
* Create a new result Id and hash it
* Find a slot for a new result id. If the table is full, expand it by
* a factor of 2. However, do not expand past the hard max, as the client
* is probably just not clearing result handles like they should.
*/
void
PgSetResultId(Pg_clientData * cd, char *id, char *connid_c, PGresult *res)
int
PgSetResultId(Tcl_Interp *interp, char *connid_c, PGresult *res)
{
Tcl_HashEntry *hent;
Tcl_Channel conn_chan;
Pg_ConnectionId *connid;
Pg_ResultId *resid;
int hnew;
int resid, i;
char buf[32];
hent = Tcl_FindHashEntry(&(cd->dbh_hash), connid_c);
if (hent == NULL)
conn_chan = Tcl_GetChannel(interp, connid_c, 0);
if(conn_chan == NULL)
return TCL_ERROR;
connid = (Pg_ConnectionId *)Tcl_GetChannelInstanceData(conn_chan);
for (resid = connid->res_last+1; resid != connid->res_last; resid++) {
if (resid == connid->res_max)
resid = 0;
if (!connid->results[resid])
{
connid = NULL;
connid->res_last = resid;
break;
}
else
{
connid = (Pg_ConnectionId *) Tcl_GetHashValue(hent);
}
resid = (Pg_ResultId *) ckalloc(sizeof(Pg_ResultId));
resid->result = res;
resid->connection = connid;
sprintf(resid->id, "pgr%ld", cd->res_count++);
strcpy(id, resid->id);
if (connid->results[resid]) {
if (connid->res_max == connid->res_hardmax) {
Tcl_SetResult(interp, "hard limit on result handles reached",
TCL_STATIC);
return TCL_ERROR;
}
connid->res_last = connid->res_max;
resid = connid->res_max;
connid->res_max *= 2;
if (connid->res_max > connid->res_hardmax)
connid->res_max = connid->res_hardmax;
connid->results = (PGresult**)ckrealloc((void*)connid->results,
sizeof(PGresult*) * connid->res_max);
for (i = connid->res_last; i < connid->res_max; i++)
connid->results[i] = NULL;
}
hent = Tcl_CreateHashEntry(&(cd->res_hash), resid->id, &hnew);
Tcl_SetHashValue(hent, (ClientData) resid);
connid->results[resid] = res;
sprintf(buf, "%s.%d", connid_c, resid);
Tcl_SetResult(interp, buf, TCL_VOLATILE);
return resid;
}
if (connid != NULL)
{
hent = Tcl_CreateHashEntry(&(connid->res_hash), resid->id, &hnew);
Tcl_SetHashValue(hent, (ClientData) resid);
static int getresid(Tcl_Interp *interp, char *id, Pg_ConnectionId **connid_p)
{
Tcl_Channel conn_chan;
char *mark;
int resid;
Pg_ConnectionId *connid;
if (!(mark = strchr(id, '.')))
return -1;
*mark = '\0';
conn_chan = Tcl_GetChannel(interp, id, 0);
*mark = '.';
if(conn_chan == NULL || Tcl_GetChannelType(conn_chan) != &Pg_ConnType) {
Tcl_SetResult(interp, "Invalid connection handle", TCL_STATIC);
return -1;
}
if (Tcl_GetInt(interp, mark + 1, &resid) == TCL_ERROR) {
Tcl_SetResult(interp, "Poorly formated result handle", TCL_STATIC);
return -1;
}
connid = (Pg_ConnectionId *)Tcl_GetChannelInstanceData(conn_chan);
if (resid < 0 || resid > connid->res_max || connid->results[resid] == NULL) {
Tcl_SetResult(interp, "Invalid result handle", TCL_STATIC);
return -1;
}
*connid_p = connid;
return resid;
}
......@@ -149,19 +320,17 @@ PgSetResultId(Pg_clientData * cd, char *id, char *connid_c, PGresult *res)
* Get back the result pointer from the Id
*/
PGresult *
PgGetResultId(Pg_clientData * cd, char *id)
PgGetResultId(Tcl_Interp *interp, char *id)
{
Tcl_HashEntry *hent;
Pg_ResultId *resid;
hent = Tcl_FindHashEntry(&(cd->res_hash), id);
if (hent == NULL)
{
return (PGresult *) NULL;
}
resid = (Pg_ResultId *) Tcl_GetHashValue(hent);
return resid->result;
Pg_ConnectionId *connid;
int resid;
if (!id)
return NULL;
resid = getresid(interp, id, &connid);
if (resid == -1)
return NULL;
return connid->results[resid];
}
......@@ -169,51 +338,41 @@ PgGetResultId(Pg_clientData * cd, char *id)
* Remove a result Id from the hash tables
*/
void
PgDelResultId(Pg_clientData * cd, char *id)
PgDelResultId(Tcl_Interp *interp, char *id)
{
Tcl_HashEntry *hent;
Tcl_HashEntry *hent2;
Pg_ResultId *resid;
Pg_ConnectionId *connid;
int resid;
hent = Tcl_FindHashEntry(&(cd->res_hash), id);
if (hent == NULL)
{
resid = getresid(interp, id, &connid);
if (resid == -1)
return;
}
resid = (Pg_ResultId *) Tcl_GetHashValue(hent);
if (resid->connection != NULL)
{
hent2 = Tcl_FindHashEntry(&(resid->connection->res_hash), id);
if (hent2 != NULL)
{
Tcl_DeleteHashEntry(hent2);
}
}
Tcl_DeleteHashEntry(hent);
ckfree(resid);
connid->results[resid] = 0;
}
/*
* Get the connection Id from the result Id
*/
void
PgGetConnByResultId(Pg_clientData * cd, char *id, char *resid_c)
int
PgGetConnByResultId(Tcl_Interp *interp, char *resid_c)
{
Tcl_HashEntry *hent;
Pg_ResultId *resid;
hent = Tcl_FindHashEntry(&(cd->res_hash), id);
if (hent == NULL)
{
return;
char *mark;
Tcl_Channel conn_chan;
if (!(mark = strchr(resid_c, '.')))
goto error_out;
*mark = '\0';
conn_chan = Tcl_GetChannel(interp, resid_c, 0);
*mark = '.';
if(conn_chan && Tcl_GetChannelType(conn_chan) != &Pg_ConnType) {
Tcl_SetResult(interp, Tcl_GetChannelName(conn_chan), TCL_VOLATILE);
return TCL_OK;
}
resid = (Pg_ResultId *) Tcl_GetHashValue(hent);
if (resid->connection != NULL)
{
strcpy(id, resid->connection->id);
}
error_out:
Tcl_ResetResult(interp);
Tcl_AppendResult(interp, resid_c, " is not a valid connection\n", 0);
return TCL_ERROR;
}
/*-------------------------------------------------------------------------
*
* pgtclId.h--
* useful routines to convert between strings and pointers
* Needed because everything in tcl is a string, but often, pointers
* to data structures are needed.
*
*
* Copyright (c) 1994, Regents of the University of California
*
* $Id: pgtclId.h,v 1.5 1997/09/08 21:55:26 momjian Exp $
*
*-------------------------------------------------------------------------
*/
*
* pgtclId.h--
* useful routines to convert between strings and pointers
* Needed because everything in tcl is a string, but often, pointers
* to data structures are needed.
*
*
* Copyright (c) 1994, Regents of the University of California
*
* $Id: pgtclId.h,v 1.6 1998/03/15 08:03:00 scrappy Exp $
*
*-------------------------------------------------------------------------
*/
extern void PgSetConnectionId(Pg_clientData * cd, char *id, PGconn *conn);
extern PGconn *PgGetConnectionId(Pg_clientData * cd, char *id);
extern void PgDelConnectionId(Pg_clientData * cd, char *id);
extern void PgSetResultId(Pg_clientData * cd, char *id, char *connid, PGresult *res);
extern PGresult *PgGetResultId(Pg_clientData * cd, char *id);
extern void PgDelResultId(Pg_clientData * cd, char *id);
extern void PgGetConnByResultId(Pg_clientData * cd, char *id, char *resid);
extern void PgSetConnectionId(Tcl_Interp *interp, PGconn *conn);
#if (TCL_MAJOR_VERSION == 7 && TCL_MINOR_VERSION == 5)
# define DRIVER_DEL_PROTO ClientData cData, Tcl_Interp *interp, \
Tcl_File inFile, Tcl_File outFile
# define DRIVER_OUTPUT_PROTO ClientData cData, Tcl_File outFile, char *buf, \
int bufSize, int *errorCodePtr
# define DRIVER_INPUT_PROTO ClientData cData, Tcl_File inFile, char *buf, \
int bufSize, int *errorCodePtr
#else
# define DRIVER_OUTPUT_PROTO ClientData cData, char *buf, int bufSize, \
int *errorCodePtr
# define DRIVER_INPUT_PROTO ClientData cData, char *buf, int bufSize, \
int *errorCodePtr
# define DRIVER_DEL_PROTO ClientData cData, Tcl_Interp *interp
#endif
extern PGconn *PgGetConnectionId(Tcl_Interp *interp, char *id, \
Pg_ConnectionId **);
extern PgDelConnectionId(DRIVER_DEL_PROTO);
extern int PgOutputProc(DRIVER_OUTPUT_PROTO);
extern PgInputProc(DRIVER_INPUT_PROTO);
extern int PgSetResultId(Tcl_Interp *interp, char *connid, PGresult *res);
extern PGresult *PgGetResultId(Tcl_Interp *interp, char *id);
extern void PgDelResultId(Tcl_Interp *interp, char *id);
extern int PgGetConnByResultId(Tcl_Interp *interp, char *resid);
#if (TCL_MAJOR_VERSION < 8)
extern Tcl_File PgGetFileProc(ClientData cData, int direction);
#endif
extern Tcl_ChannelType Pg_ConnType;
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