From: Marc G. Fournier Date: Wed, 30 Oct 1996 06:18:42 +0000 (+0000) Subject: Changes to libpgtcl submitted by: wieck@sapserv.debis.de (Jan Wieck) X-Git-Tag: REL2_0~352 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=552620c8b24a53c13da540fc0d5f316597e9d2e8;p=postgresql Changes to libpgtcl submitted by: wieck@sapserv.debis.de (Jan Wieck) Adds: -lAttributes Returns another format of the results attribute list. Per attribute a sublist of {{attname} atttype attlen} is returned and an empty string if no attributes where received. -numAttrs Returns the number of attributes in the result. --- diff --git a/src/interfaces/libpgtcl/Makefile b/src/interfaces/libpgtcl/Makefile index 25a2a0ac6e..ff0e99e0f9 100644 --- a/src/interfaces/libpgtcl/Makefile +++ b/src/interfaces/libpgtcl/Makefile @@ -7,7 +7,7 @@ # # # IDENTIFICATION -# $Header: /cvsroot/pgsql/src/interfaces/libpgtcl/Attic/Makefile,v 1.2 1996/07/23 03:38:42 scrappy Exp $ +# $Header: /cvsroot/pgsql/src/interfaces/libpgtcl/Attic/Makefile,v 1.3 1996/10/30 06:18:36 scrappy Exp $ # #------------------------------------------------------------------------- @@ -23,6 +23,8 @@ CFLAGS+= -I$(HEADERDIR) \ -I$(TCL_INCDIR) \ -I$(srcdir)/libpq +LIBLDLIBS+= -L$(LIBDIR) -lpq + ifdef KRBVERS CFLAGS+= $(KRBFLAGS) endif diff --git a/src/interfaces/libpgtcl/libpgtcl.h b/src/interfaces/libpgtcl/libpgtcl.h index 923bf594d7..7a5fa0364c 100644 --- a/src/interfaces/libpgtcl/libpgtcl.h +++ b/src/interfaces/libpgtcl/libpgtcl.h @@ -6,7 +6,7 @@ * * Copyright (c) 1994, Regents of the University of California * - * $Id: libpgtcl.h,v 1.1.1.1 1996/07/09 06:22:16 scrappy Exp $ + * $Id: libpgtcl.h,v 1.2 1996/10/30 06:18:37 scrappy Exp $ * *------------------------------------------------------------------------- */ @@ -16,6 +16,7 @@ #include "tcl.h" -extern int Pg_Init (Tcl_Interp *interp); +extern int Pgtcl_Init (Tcl_Interp *interp); +extern int Pgtcl_SafeInit (Tcl_Interp *interp); #endif /* LIBPGTCL_H */ diff --git a/src/interfaces/libpgtcl/pgtcl.c b/src/interfaces/libpgtcl/pgtcl.c index f3758cd8fb..d4021894e4 100644 --- a/src/interfaces/libpgtcl/pgtcl.c +++ b/src/interfaces/libpgtcl/pgtcl.c @@ -9,7 +9,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/interfaces/libpgtcl/Attic/pgtcl.c,v 1.2 1996/10/07 21:19:06 scrappy Exp $ + * $Header: /cvsroot/pgsql/src/interfaces/libpgtcl/Attic/pgtcl.c,v 1.3 1996/10/30 06:18:38 scrappy Exp $ * *------------------------------------------------------------------------- */ @@ -19,92 +19,145 @@ #include "pgtclCmds.h" /* - * PG_Init + * Pgtcl_Init * initialization package for the PGLITE Tcl package * */ +/* + * Tidy up forgotten postgres connection at Tcl_Exit + */ +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_DeleteExitHandler(Pgtcl_AtExit, cData); +} + +/* + * Tidy up forgotten postgres connections on Interpreter deletion + */ +void +Pgtcl_Shutdown (ClientData cData, Tcl_Interp *interp) +{ + Pgtcl_AtExit(cData); +} + int -Pg_Init (Tcl_Interp *interp) +Pgtcl_Init (Tcl_Interp *interp) { - /* register all pgtcl commands */ + 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); + 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); + /* register all pgtcl commands */ Tcl_CreateCommand(interp, "pg_connect", Pg_connect, - (ClientData)NULL, (Tcl_CmdDeleteProc*)NULL); + (ClientData)cd, (Tcl_CmdDeleteProc*)NULL); Tcl_CreateCommand(interp, "pg_disconnect", Pg_disconnect, - (ClientData)NULL, (Tcl_CmdDeleteProc*)NULL); + (ClientData)cd, (Tcl_CmdDeleteProc*)NULL); Tcl_CreateCommand(interp, "pg_exec", Pg_exec, - (ClientData)NULL, (Tcl_CmdDeleteProc*)NULL); + (ClientData)cd, (Tcl_CmdDeleteProc*)NULL); Tcl_CreateCommand(interp, "pg_select", Pg_select, - (ClientData)NULL, (Tcl_CmdDeleteProc*)NULL); + (ClientData)cd, (Tcl_CmdDeleteProc*)NULL); Tcl_CreateCommand(interp, "pg_result", Pg_result, - (ClientData)NULL, (Tcl_CmdDeleteProc*)NULL); + (ClientData)cd, (Tcl_CmdDeleteProc*)NULL); Tcl_CreateCommand(interp, "pg_lo_open", Pg_lo_open, - (ClientData)NULL, (Tcl_CmdDeleteProc*)NULL); + (ClientData)cd, (Tcl_CmdDeleteProc*)NULL); Tcl_CreateCommand(interp, "pg_lo_close", Pg_lo_close, - (ClientData)NULL, (Tcl_CmdDeleteProc*)NULL); + (ClientData)cd, (Tcl_CmdDeleteProc*)NULL); Tcl_CreateCommand(interp, "pg_lo_read", Pg_lo_read, - (ClientData)NULL, (Tcl_CmdDeleteProc*)NULL); + (ClientData)cd, (Tcl_CmdDeleteProc*)NULL); Tcl_CreateCommand(interp, "pg_lo_write", Pg_lo_write, - (ClientData)NULL, (Tcl_CmdDeleteProc*)NULL); + (ClientData)cd, (Tcl_CmdDeleteProc*)NULL); Tcl_CreateCommand(interp, "pg_lo_lseek", Pg_lo_lseek, - (ClientData)NULL, (Tcl_CmdDeleteProc*)NULL); + (ClientData)cd, (Tcl_CmdDeleteProc*)NULL); Tcl_CreateCommand(interp, "pg_lo_creat", Pg_lo_creat, - (ClientData)NULL, (Tcl_CmdDeleteProc*)NULL); + (ClientData)cd, (Tcl_CmdDeleteProc*)NULL); Tcl_CreateCommand(interp, "pg_lo_tell", Pg_lo_tell, - (ClientData)NULL, (Tcl_CmdDeleteProc*)NULL); + (ClientData)cd, (Tcl_CmdDeleteProc*)NULL); Tcl_CreateCommand(interp, "pg_lo_unlink", Pg_lo_unlink, - (ClientData)NULL, (Tcl_CmdDeleteProc*)NULL); + (ClientData)cd, (Tcl_CmdDeleteProc*)NULL); Tcl_CreateCommand(interp, "pg_lo_import", Pg_lo_import, - (ClientData)NULL, (Tcl_CmdDeleteProc*)NULL); + (ClientData)cd, (Tcl_CmdDeleteProc*)NULL); Tcl_CreateCommand(interp, "pg_lo_export", Pg_lo_export, - (ClientData)NULL, (Tcl_CmdDeleteProc*)NULL); + (ClientData)cd, (Tcl_CmdDeleteProc*)NULL); + Tcl_PkgProvide(interp, "Pgtcl", "1.0"); + return TCL_OK; } +int +Pgtcl_SafeInit (Tcl_Interp *interp) +{ + return Pgtcl_Init(interp); +} diff --git a/src/interfaces/libpgtcl/pgtclCmds.c b/src/interfaces/libpgtcl/pgtclCmds.c index 029a4329f9..91be2bd37f 100644 --- a/src/interfaces/libpgtcl/pgtclCmds.c +++ b/src/interfaces/libpgtcl/pgtclCmds.c @@ -7,7 +7,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/interfaces/libpgtcl/Attic/pgtclCmds.c,v 1.4 1996/10/07 21:19:07 scrappy Exp $ + * $Header: /cvsroot/pgsql/src/interfaces/libpgtcl/Attic/pgtclCmds.c,v 1.5 1996/10/30 06:18:39 scrappy Exp $ * *------------------------------------------------------------------------- */ @@ -224,6 +224,7 @@ tcl_value (char *value) int 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; @@ -277,7 +278,7 @@ Pg_connect(ClientData cData, Tcl_Interp *interp, int argc, char* argv[]) conn = PQsetdb(pghost, pgport, pgoptions, pgtty, dbName); if (conn->status == CONNECTION_OK) { - PgSetId(interp->result, (void*)conn); + PgSetConnectionId(cd, interp->result, conn); return TCL_OK; } else { @@ -302,21 +303,21 @@ Pg_connect(ClientData cData, Tcl_Interp *interp, int argc, char* argv[]) int Pg_disconnect(ClientData cData, Tcl_Interp *interp, int argc, char* argv[]) { + Pg_clientData *cd = (Pg_clientData *)cData; PGconn *conn; - char* connPtrName; if (argc != 2) { Tcl_AppendResult(interp, "Wrong # of arguments\n", "pg_disconnect connection", 0); return TCL_ERROR; } - connPtrName = argv[1]; - if (! PgValidId(connPtrName)) { + conn = PgGetConnectionId(cd, argv[1]); + if (conn == (PGconn *)NULL) { Tcl_AppendResult(interp, "First argument is not a valid connection\n", 0); return TCL_ERROR; } - conn = (PGconn*)PgGetId(connPtrName); + PgDelConnectionId(cd, argv[1]); PQfinish(conn); return TCL_OK; } @@ -335,26 +336,25 @@ Pg_disconnect(ClientData cData, Tcl_Interp *interp, int argc, char* argv[]) int Pg_exec(AlientData cData, Tcl_Interp *interp, int argc, char* argv[]) { + Pg_clientData *cd = (Pg_clientData *)cData; PGconn *conn; PGresult *result; - char* connPtrName; if (argc != 3) { Tcl_AppendResult(interp, "Wrong # of arguments\n", "pg_exec connection queryString", 0); return TCL_ERROR; } - connPtrName = argv[1]; - if (! PgValidId(connPtrName)) { - Tcl_AppendResult(interp, "Argument passed in is not a valid connection\n", 0); + conn = PgGetConnectionId(cd, argv[1]); + if (conn == (PGconn *)NULL) { + Tcl_AppendResult(interp, "First argument is not a valid connection\n", 0); return TCL_ERROR; } - conn = (PGconn*)PgGetId(connPtrName); result = PQexec(conn, argv[2]); if (result) { - PgSetId(interp->result, (void*)result); + PgSetResultId(cd, interp->result, argv[1], result); return TCL_OK; } else { @@ -386,6 +386,10 @@ Pg_exec(AlientData cData, Tcl_Interp *interp, int argc, char* argv[]) the number of tuples in the query -attributes returns a list of the name/type pairs of the tuple attributes + -lAttributes + returns a list of the {name type len} entries of the tuple attributes + -numAttrs + returns the number of attributes returned by the query -getTuple tupleNumber returns the values of the tuple in a list -clear @@ -394,7 +398,7 @@ Pg_exec(AlientData cData, Tcl_Interp *interp, int argc, char* argv[]) int Pg_result(ClientData cData, Tcl_Interp *interp, int argc, char* argv[]) { - char* resultPtrName; + Pg_clientData *cd = (Pg_clientData *)cData; PGresult *result; char *opt; int i; @@ -408,13 +412,12 @@ Pg_result(ClientData cData, Tcl_Interp *interp, int argc, char* argv[]) goto Pg_result_errReturn; } - resultPtrName = argv[1]; - if (! PgValidId(resultPtrName)) { + result = PgGetResultId(cd, argv[1]); + if (result == (PGresult *)NULL) { Tcl_AppendResult(interp, "First argument is not a valid query result\n", 0); return TCL_ERROR; } - result = (PGresult*)PgGetId(resultPtrName); opt = argv[2]; if (strcmp(opt, "-status") == 0) { @@ -426,10 +429,11 @@ Pg_result(ClientData cData, Tcl_Interp *interp, int argc, char* argv[]) return TCL_OK; } else if (strcmp(opt, "-conn") == 0) { - PgSetId(interp->result, (void*)result->conn); + PgGetConnByResultId(cd, interp->result, argv[1]); return TCL_OK; } else if (strcmp(opt, "-clear") == 0) { + PgDelResultId(cd, argv[1]); PQclear(result); return TCL_OK; } @@ -516,6 +520,21 @@ Pg_result(ClientData cData, Tcl_Interp *interp, int argc, char* argv[]) } return TCL_OK; } + else if (strcmp(opt, "-lAttributes") == 0) { + char buf[512]; + Tcl_ResetResult(interp); + for (i = 0; i < PQnfields(result); i++) { + sprintf(buf, "{%s} %ld %d", PQfname(result, i), + PQftype(result, i), + PQfsize(result, i)); + Tcl_AppendElement(interp, buf); + } + return TCL_OK; + } + else if (strcmp(opt, "-numAttrs") == 0) { + sprintf(interp->result, "%d", PQnfields(result)); + return TCL_OK; + } else { Tcl_AppendResult(interp, "Invalid option",0); goto Pg_result_errReturn; @@ -531,6 +550,8 @@ Pg_result(ClientData cData, Tcl_Interp *interp, int argc, char* argv[]) "\t-assignbyidx arrayVarName\n", "\t-numTuples\n", "\t-attributes\n" + "\t-lAttributes\n" + "\t-numAttrs\n" "\t-getTuple tupleNumber\n", "\t-clear\n", "\t-oid\n", @@ -553,8 +574,8 @@ Pg_result(ClientData cData, Tcl_Interp *interp, int argc, char* argv[]) int Pg_lo_open(ClientData cData, Tcl_Interp *interp, int argc, char* argv[]) { + Pg_clientData *cd = (Pg_clientData *)cData; PGconn *conn; - char* connPtrName; int lobjId; int mode; int fd; @@ -564,13 +585,13 @@ Pg_lo_open(ClientData cData, Tcl_Interp *interp, int argc, char* argv[]) "pg_lo_open connection lobjOid mode", 0); return TCL_ERROR; } - connPtrName = argv[1]; - if (! PgValidId(connPtrName)) { - Tcl_AppendResult(interp, "Argument passed in is not a valid connection\n", 0); + + conn = PgGetConnectionId(cd, argv[1]); + if (conn == (PGconn *)NULL) { + Tcl_AppendResult(interp, "First argument is not a valid connection\n", 0); return TCL_ERROR; } - conn = (PGconn*)PgGetId(connPtrName); lobjId = atoi(argv[2]); if (strlen(argv[3]) < 1 || strlen(argv[3]) > 2) @@ -623,8 +644,8 @@ 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_clientData *cd = (Pg_clientData *)cData; PGconn *conn; - char* connPtrName; int fd; if (argc != 3) { @@ -633,13 +654,12 @@ Pg_lo_close(ClientData cData, Tcl_Interp *interp, int argc, char* argv[]) return TCL_ERROR; } - connPtrName = argv[1]; - if (! PgValidId(connPtrName)) { - Tcl_AppendResult(interp, "Argument passed in is not a valid connection\n", 0); + conn = PgGetConnectionId(cd, argv[1]); + if (conn == (PGconn *)NULL) { + Tcl_AppendResult(interp, "First argument is not a valid connection\n", 0); return TCL_ERROR; } - conn = (PGconn*)PgGetId(connPtrName); fd = atoi(argv[2]); sprintf(interp->result,"%d",lo_close(conn,fd)); return TCL_OK; @@ -659,8 +679,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_clientData *cd = (Pg_clientData *)cData; PGconn *conn; - char* connPtrName; int fd; int nbytes = 0; char *buf; @@ -673,13 +693,12 @@ Pg_lo_read(ClientData cData, Tcl_Interp *interp, int argc, char* argv[]) return TCL_ERROR; } - connPtrName = argv[1]; - if (! PgValidId(connPtrName)) { - Tcl_AppendResult(interp, "Argument passed in is not a valid connection\n", 0); + conn = PgGetConnectionId(cd, argv[1]); + if (conn == (PGconn *)NULL) { + Tcl_AppendResult(interp, "First argument is not a valid connection\n", 0); return TCL_ERROR; } - conn = (PGconn*)PgGetId(connPtrName); fd = atoi(argv[2]); bufVar = argv[3]; @@ -712,8 +731,8 @@ Pg_lo_write int Pg_lo_write(ClientData cData, Tcl_Interp *interp, int argc, char* argv[]) { + Pg_clientData *cd = (Pg_clientData *)cData; PGconn *conn; - char *connPtrName; char *buf; int fd; int nbytes = 0; @@ -725,13 +744,12 @@ Pg_lo_write(ClientData cData, Tcl_Interp *interp, int argc, char* argv[]) return TCL_ERROR; } - connPtrName = argv[1]; - if (! PgValidId(connPtrName)) { - Tcl_AppendResult(interp, "Argument passed in is not a valid connection\n", 0); + conn = PgGetConnectionId(cd, argv[1]); + if (conn == (PGconn *)NULL) { + Tcl_AppendResult(interp, "First argument is not a valid connection\n", 0); return TCL_ERROR; } - conn = (PGconn*)PgGetId(connPtrName); fd = atoi(argv[2]); buf = argv[3]; @@ -761,8 +779,8 @@ whence can be either int Pg_lo_lseek(ClientData cData, Tcl_Interp *interp, int argc, char* argv[]) { + Pg_clientData *cd = (Pg_clientData *)cData; PGconn *conn; - char* connPtrName; int fd; char *whenceStr; int offset, whence; @@ -773,13 +791,12 @@ Pg_lo_lseek(ClientData cData, Tcl_Interp *interp, int argc, char* argv[]) return TCL_ERROR; } - connPtrName = argv[1]; - if (! PgValidId(connPtrName)) { - Tcl_AppendResult(interp, "Argument passed in is not a valid connection\n", 0); + conn = PgGetConnectionId(cd, argv[1]); + if (conn == (PGconn *)NULL) { + Tcl_AppendResult(interp, "First argument is not a valid connection\n", 0); return TCL_ERROR; } - conn = (PGconn*)PgGetId(connPtrName); fd = atoi(argv[2]); offset = atoi(argv[3]); @@ -815,8 +832,8 @@ for now, we don't support any additional storage managers. int Pg_lo_creat(ClientData cData, Tcl_Interp *interp, int argc, char* argv[]) { + Pg_clientData *cd = (Pg_clientData *)cData; PGconn *conn; - char* connPtrName; char *modeStr; char *modeWord; int mode; @@ -827,14 +844,12 @@ Pg_lo_creat(ClientData cData, Tcl_Interp *interp, int argc, char* argv[]) return TCL_ERROR; } - connPtrName = argv[1]; - if (! PgValidId(connPtrName)) { - Tcl_AppendResult(interp, "Argument passed in is not a valid connection\n", 0); + conn = PgGetConnectionId(cd, argv[1]); + if (conn == (PGconn *)NULL) { + Tcl_AppendResult(interp, "First argument is not a valid connection\n", 0); return TCL_ERROR; } - conn = (PGconn*)PgGetId(connPtrName); - modeStr = argv[2]; modeWord = strtok(modeStr,"|"); @@ -880,8 +895,8 @@ Pg_lo_tell int Pg_lo_tell(ClientData cData, Tcl_Interp *interp, int argc, char* argv[]) { + Pg_clientData *cd = (Pg_clientData *)cData; PGconn *conn; - char* connPtrName; int fd; if (argc != 3) { @@ -890,13 +905,12 @@ Pg_lo_tell(ClientData cData, Tcl_Interp *interp, int argc, char* argv[]) return TCL_ERROR; } - connPtrName = argv[1]; - if (! PgValidId(connPtrName)) { - Tcl_AppendResult(interp, "Argument passed in is not a valid connection\n", 0); + conn = PgGetConnectionId(cd, argv[1]); + if (conn == (PGconn *)NULL) { + Tcl_AppendResult(interp, "First argument is not a valid connection\n", 0); return TCL_ERROR; } - conn = (PGconn*)PgGetId(connPtrName); fd = atoi(argv[2]); sprintf(interp->result,"%d",lo_tell(conn,fd)); @@ -916,8 +930,8 @@ Pg_lo_unlink int Pg_lo_unlink(ClientData cData, Tcl_Interp *interp, int argc, char* argv[]) { + Pg_clientData *cd = (Pg_clientData *)cData; PGconn *conn; - char* connPtrName; int lobjId; int retval; @@ -927,13 +941,12 @@ Pg_lo_unlink(ClientData cData, Tcl_Interp *interp, int argc, char* argv[]) return TCL_ERROR; } - connPtrName = argv[1]; - if (! PgValidId(connPtrName)) { - Tcl_AppendResult(interp, "Argument passed in is not a valid connection\n", 0); + conn = PgGetConnectionId(cd, argv[1]); + if (conn == (PGconn *)NULL) { + Tcl_AppendResult(interp, "First argument is not a valid connection\n", 0); return TCL_ERROR; } - conn = (PGconn*)PgGetId(connPtrName); lobjId = atoi(argv[2]); retval = lo_unlink(conn,lobjId); @@ -960,8 +973,8 @@ Pg_lo_import int Pg_lo_import(ClientData cData, Tcl_Interp *interp, int argc, char* argv[]) { + Pg_clientData *cd = (Pg_clientData *)cData; PGconn *conn; - char* connPtrName; char* filename; Oid lobjId; @@ -971,13 +984,12 @@ Pg_lo_import(ClientData cData, Tcl_Interp *interp, int argc, char* argv[]) return TCL_ERROR; } - connPtrName = argv[1]; - if (! PgValidId(connPtrName)) { - Tcl_AppendResult(interp, "Argument passed in is not a valid connection\n", 0); + conn = PgGetConnectionId(cd, argv[1]); + if (conn == (PGconn *)NULL) { + Tcl_AppendResult(interp, "First argument is not a valid connection\n", 0); return TCL_ERROR; } - conn = (PGconn*)PgGetId(connPtrName); filename = argv[2]; lobjId = lo_import(conn,filename); @@ -1001,8 +1013,8 @@ Pg_lo_export int Pg_lo_export(ClientData cData, Tcl_Interp *interp, int argc, char* argv[]) { + Pg_clientData *cd = (Pg_clientData *)cData; PGconn *conn; - char* connPtrName; char* filename; Oid lobjId; int retval; @@ -1013,13 +1025,12 @@ Pg_lo_export(ClientData cData, Tcl_Interp *interp, int argc, char* argv[]) return TCL_ERROR; } - connPtrName = argv[1]; - if (! PgValidId(connPtrName)) { - Tcl_AppendResult(interp, "Argument passed in is not a valid connection\n", 0); + conn = PgGetConnectionId(cd, argv[1]); + if (conn == (PGconn *)NULL) { + Tcl_AppendResult(interp, "First argument is not a valid connection\n", 0); return TCL_ERROR; } - conn = (PGconn*)PgGetId(connPtrName); lobjId = atoi(argv[2]); filename = argv[3]; @@ -1055,6 +1066,7 @@ 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_clientData *cd = (Pg_clientData *)cData; PGconn *conn; PGresult *result; int ch_flag, r; @@ -1073,15 +1085,12 @@ Pg_select(ClientData cData, Tcl_Interp *interp, int argc, char **argv) return TCL_ERROR; } - if (! PgValidId(argv[1])) - { - Tcl_AppendResult(interp, - "Argument passed in is not a valid connection\n", 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); + return TCL_ERROR; } - conn = (PGconn*)PgGetId(argv[1]); - if ((result = PQexec(conn, argv[2])) == 0) { /* error occurred during the query */ diff --git a/src/interfaces/libpgtcl/pgtclCmds.h b/src/interfaces/libpgtcl/pgtclCmds.h index 23664de18f..ea3ea84225 100644 --- a/src/interfaces/libpgtcl/pgtclCmds.h +++ b/src/interfaces/libpgtcl/pgtclCmds.h @@ -5,7 +5,7 @@ * * Copyright (c) 1994, Regents of the University of California * - * $Id: pgtclCmds.h,v 1.2 1996/10/07 21:19:09 scrappy Exp $ + * $Id: pgtclCmds.h,v 1.3 1996/10/30 06:18:40 scrappy Exp $ * *------------------------------------------------------------------------- */ @@ -14,6 +14,31 @@ #define PGTCLCMDS_H #include "tcl.h" +#include "libpq/pqcomm.h" +#include "libpq-fe.h" +#include "libpq/libpq-fs.h" + +typedef struct Pg_clientData_s { + Tcl_HashTable dbh_hash; + Tcl_HashTable res_hash; + long dbh_count; + long res_count; +} Pg_clientData; + + +typedef struct Pg_ConnectionId_s { + char id[32]; + PGconn *conn; + Tcl_HashTable res_hash; +} Pg_ConnectionId; + + +typedef struct Pg_ResultId_s { + char id[32]; + PGresult *result; + Pg_ConnectionId *connection; +} Pg_ResultId; + /* **************************/ /* registered Tcl functions */ diff --git a/src/interfaces/libpgtcl/pgtclId.c b/src/interfaces/libpgtcl/pgtclId.c index 00dffe7a88..53654b6da7 100644 --- a/src/interfaces/libpgtcl/pgtclId.c +++ b/src/interfaces/libpgtcl/pgtclId.c @@ -12,7 +12,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/interfaces/libpgtcl/Attic/pgtclId.c,v 1.1.1.1 1996/07/09 06:22:16 scrappy Exp $ + * $Header: /cvsroot/pgsql/src/interfaces/libpgtcl/Attic/pgtclId.c,v 1.2 1996/10/30 06:18:41 scrappy Exp $ * *------------------------------------------------------------------------- */ @@ -21,31 +21,186 @@ #include #include "tcl.h" +#include "pgtclCmds.h" #include "pgtclId.h" -/* convert a pointer into a string */ +/* + * Create the Id for a new connection and hash it + */ +void +PgSetConnectionId(Pg_clientData *cd, char *id, PGconn *conn) +{ + Tcl_HashEntry *hent; + Pg_ConnectionId *connid; + int hnew; + + 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); +} + + +/* + * Get back the connection from the Id + */ +PGconn * +PgGetConnectionId(Pg_clientData *cd, char *id) +{ + Tcl_HashEntry *hent; + Pg_ConnectionId *connid; + + hent = Tcl_FindHashEntry(&(cd->dbh_hash), id); + if(hent == NULL) { + return (PGconn *)NULL; + } + + connid = (Pg_ConnectionId *)Tcl_GetHashValue(hent); + return connid->conn; +} + + +/* + * Remove a connection Id from the hash table and + * close all portals the user forgot. + */ +void +PgDelConnectionId(Pg_clientData *cd, char *id) +{ + Tcl_HashEntry *hent; + Tcl_HashEntry *hent2; + Tcl_HashEntry *hent3; + Tcl_HashSearch hsearch; + Pg_ConnectionId *connid; + Pg_ResultId *resid; + + hent = Tcl_FindHashEntry(&(cd->dbh_hash), id); + if(hent == NULL) { + return; + } + + connid = (Pg_ConnectionId *)Tcl_GetHashValue(hent); + + 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) { + Tcl_DeleteHashEntry(hent3); + } + ckfree(resid); + hent2 = Tcl_NextHashEntry(&hsearch); + } + Tcl_DeleteHashTable(&(connid->res_hash)); + Tcl_DeleteHashEntry(hent); + ckfree(connid); +} + + +/* + * Create a new result Id and hash it + */ void -PgSetId(char *id, void *ptr) +PgSetResultId(Pg_clientData *cd, char *id, char *connid_c, PGresult *res) +{ + Tcl_HashEntry *hent; + Pg_ConnectionId *connid; + Pg_ResultId *resid; + int hnew; + + hent = Tcl_FindHashEntry(&(cd->dbh_hash), connid_c); + if(hent == NULL) { + connid = NULL; + } 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); + + hent = Tcl_CreateHashEntry(&(cd->res_hash), resid->id, &hnew); + Tcl_SetHashValue(hent, (ClientData)resid); + + if(connid != NULL) { + hent = Tcl_CreateHashEntry(&(connid->res_hash), resid->id, &hnew); + Tcl_SetHashValue(hent, (ClientData)resid); + } +} + + +/* + * Get back the result pointer from the Id + */ +PGresult * +PgGetResultId(Pg_clientData *cd, char *id) { - (void) sprintf(id, "pgp%lx", (long) ptr); + 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; } -/* get back a pointer from a string */ -void * -PgGetId(char *id) +/* + * Remove a result Id from the hash tables + */ +void +PgDelResultId(Pg_clientData *cd, char *id) { - long ptr; - ptr = strtol(id+3, NULL, 16); - return (void *) ptr; + Tcl_HashEntry *hent; + Tcl_HashEntry *hent2; + Pg_ResultId *resid; + + hent = Tcl_FindHashEntry(&(cd->res_hash), id); + if(hent == NULL) { + 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); } -/* check to see if the string is a valid pgtcl pointer */ -int -PgValidId(char* id) + +/* + * Get the connection Id from the result Id + */ +void +PgGetConnByResultId(Pg_clientData *cd, char *id, char *resid_c) { - if ( (strlen(id) > 3) && id[0]=='p' && id[1] == 'g' && id[2] == 'p') - return 1; - else - return 0; + Tcl_HashEntry *hent; + Pg_ResultId *resid; + + hent = Tcl_FindHashEntry(&(cd->res_hash), id); + if(hent == NULL) { + return; + } + + resid = (Pg_ResultId *)Tcl_GetHashValue(hent); + if (resid->connection != NULL) { + strcpy(id, resid->connection->id); + } } + + diff --git a/src/interfaces/libpgtcl/pgtclId.h b/src/interfaces/libpgtcl/pgtclId.h index af9839ceb1..9cb431918a 100644 --- a/src/interfaces/libpgtcl/pgtclId.h +++ b/src/interfaces/libpgtcl/pgtclId.h @@ -8,11 +8,15 @@ * * Copyright (c) 1994, Regents of the University of California * - * $Id: pgtclId.h,v 1.1.1.1 1996/07/09 06:22:16 scrappy Exp $ + * $Id: pgtclId.h,v 1.2 1996/10/30 06:18:42 scrappy Exp $ * *------------------------------------------------------------------------- */ -extern void PgSetId(char *id, void *ptr); -extern void* PgGetId(char *id); -extern int PgValidId(char* id); +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);