From: Randy Kunkee <kunkee@pluto.ops.NeoSoft.com>
authorMarc G. Fournier <scrappy@hub.org>
Sun, 15 Mar 1998 08:03:00 +0000 (08:03 +0000)
committerMarc G. Fournier <scrappy@hub.org>
Sun, 15 Mar 1998 08:03:00 +0000 (08:03 +0000)
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.

src/interfaces/libpgtcl/Makefile.in
src/interfaces/libpgtcl/README
src/interfaces/libpgtcl/pgtcl.c
src/interfaces/libpgtcl/pgtclCmds.c
src/interfaces/libpgtcl/pgtclCmds.h
src/interfaces/libpgtcl/pgtclId.c
src/interfaces/libpgtcl/pgtclId.h

index 0905a8a7227b8c5027a4fc5dcb32ac48aad93632..92852a597042d70931983fbe6f1660cf01842607 100644 (file)
@@ -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
 
index b17416bf90f9fe9f66d92b05cfd7116f3599a7c6..c672405955de19005a3b868307a4aef4236d70ed 100644 (file)
@@ -1,6 +1,38 @@
-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.
index e8502da5c24e1a5edd541db8917f7ac2eaf4d022..a90c0c7c4908e759aa360f8b057849df94779014 100644 (file)
@@ -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 $
  *
  *-------------------------------------------------------------------------
  */
 #include "pgtclId.h"
 
 /*
- * Pgtcl_Init
- *   initialization package for the PGLITE Tcl package
+ * Pgtcl_Init 
+ *    initialization package for the PGLITE Tcl package
  *
  */
 
-/*
- * 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);
-
-   /* register all pgtcl commands */
-   Tcl_CreateCommand(interp,
-                     "pg_conndefaults",
-                     Pg_conndefaults,
-                     (ClientData) cd, (Tcl_CmdDeleteProc *) NULL);
-
-   Tcl_CreateCommand(interp,
-                     "pg_connect",
-                     Pg_connect,
-                     (ClientData) cd, (Tcl_CmdDeleteProc *) NULL);
-
-   Tcl_CreateCommand(interp,
-                     "pg_disconnect",
-                     Pg_disconnect,
-                     (ClientData) cd, (Tcl_CmdDeleteProc *) NULL);
-
-   Tcl_CreateCommand(interp,
-                     "pg_exec",
-                     Pg_exec,
-                     (ClientData) cd, (Tcl_CmdDeleteProc *) NULL);
-
-   Tcl_CreateCommand(interp,
-                     "pg_select",
-                     Pg_select,
-                     (ClientData) cd, (Tcl_CmdDeleteProc *) NULL);
-
-   Tcl_CreateCommand(interp,
-                     "pg_result",
-                     Pg_result,
-                     (ClientData) cd, (Tcl_CmdDeleteProc *) NULL);
-
-   Tcl_CreateCommand(interp,
-                     "pg_lo_open",
-                     Pg_lo_open,
-                     (ClientData) cd, (Tcl_CmdDeleteProc *) NULL);
-
-   Tcl_CreateCommand(interp,
-                     "pg_lo_close",
-                     Pg_lo_close,
-                     (ClientData) cd, (Tcl_CmdDeleteProc *) NULL);
-
-   Tcl_CreateCommand(interp,
-                     "pg_lo_read",
-                     Pg_lo_read,
-                     (ClientData) cd, (Tcl_CmdDeleteProc *) NULL);
-
-   Tcl_CreateCommand(interp,
-                     "pg_lo_write",
-                     Pg_lo_write,
-                     (ClientData) cd, (Tcl_CmdDeleteProc *) NULL);
-
-   Tcl_CreateCommand(interp,
-                     "pg_lo_lseek",
-                     Pg_lo_lseek,
-                     (ClientData) cd, (Tcl_CmdDeleteProc *) NULL);
-
-   Tcl_CreateCommand(interp,
-                     "pg_lo_creat",
-                     Pg_lo_creat,
-                     (ClientData) cd, (Tcl_CmdDeleteProc *) NULL);
-
-   Tcl_CreateCommand(interp,
-                     "pg_lo_tell",
-                     Pg_lo_tell,
-                     (ClientData) cd, (Tcl_CmdDeleteProc *) NULL);
-
-   Tcl_CreateCommand(interp,
-                     "pg_lo_unlink",
-                     Pg_lo_unlink,
-                     (ClientData) cd, (Tcl_CmdDeleteProc *) NULL);
-
-   Tcl_CreateCommand(interp,
-                     "pg_lo_import",
-                     Pg_lo_import,
-                     (ClientData) cd, (Tcl_CmdDeleteProc *) NULL);
-
-   Tcl_CreateCommand(interp,
-                     "pg_lo_export",
-                     Pg_lo_export,
-                     (ClientData) cd, (Tcl_CmdDeleteProc *) NULL);
-
-   Tcl_CreateCommand(interp,
-                     "pg_listen",
-                     Pg_listen,
-                     (ClientData) cd, (Tcl_CmdDeleteProc *) NULL);
-
-   Tcl_CreateCommand(interp,
-                     "pg_notifies",
-                     Pg_notifies,
-                     (ClientData) cd, (Tcl_CmdDeleteProc *) NULL);
-
-   Tcl_PkgProvide(interp, "Pgtcl", "1.0");
-
-   return TCL_OK;
+
+  /* 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)NULL, (Tcl_CmdDeleteProc*)NULL);
+
+  Tcl_CreateCommand(interp,
+           "pg_connect",
+           Pg_connect,
+           (ClientData)NULL, (Tcl_CmdDeleteProc*)NULL);
+
+  Tcl_CreateCommand(interp,
+           "pg_disconnect",
+           Pg_disconnect,
+           (ClientData)NULL, (Tcl_CmdDeleteProc*)NULL);
+  
+  Tcl_CreateCommand(interp,
+           "pg_exec",
+           Pg_exec,
+           (ClientData)NULL, (Tcl_CmdDeleteProc*)NULL);
+  
+  Tcl_CreateCommand(interp,
+           "pg_select",
+           Pg_select,
+           (ClientData)NULL, (Tcl_CmdDeleteProc*)NULL);
+  
+  Tcl_CreateCommand(interp,
+           "pg_result",
+           Pg_result,
+           (ClientData)NULL, (Tcl_CmdDeleteProc*)NULL);
+  
+  Tcl_CreateCommand(interp,
+           "pg_lo_open",
+           Pg_lo_open,
+           (ClientData)NULL, (Tcl_CmdDeleteProc*)NULL);
+  
+  Tcl_CreateCommand(interp,
+           "pg_lo_close",
+           Pg_lo_close,
+           (ClientData)NULL, (Tcl_CmdDeleteProc*)NULL);
+
+  Tcl_CreateCommand(interp,
+           "pg_lo_read",
+           Pg_lo_read,
+           (ClientData)NULL, (Tcl_CmdDeleteProc*)NULL);
+
+  Tcl_CreateCommand(interp,
+           "pg_lo_write",
+           Pg_lo_write,
+           (ClientData)NULL, (Tcl_CmdDeleteProc*)NULL);
+
+  Tcl_CreateCommand(interp,
+           "pg_lo_lseek",
+           Pg_lo_lseek,
+           (ClientData)NULL, (Tcl_CmdDeleteProc*)NULL);
+
+  Tcl_CreateCommand(interp,
+           "pg_lo_creat",
+           Pg_lo_creat,
+           (ClientData)NULL, (Tcl_CmdDeleteProc*)NULL);
+
+  Tcl_CreateCommand(interp,
+           "pg_lo_tell",
+           Pg_lo_tell,
+           (ClientData)NULL, (Tcl_CmdDeleteProc*)NULL);
+
+  Tcl_CreateCommand(interp,
+           "pg_lo_unlink",
+           Pg_lo_unlink,
+           (ClientData)NULL, (Tcl_CmdDeleteProc*)NULL);
+
+  Tcl_CreateCommand(interp,
+           "pg_lo_import",
+           Pg_lo_import,
+           (ClientData)NULL, (Tcl_CmdDeleteProc*)NULL);
+  
+  Tcl_CreateCommand(interp,
+           "pg_lo_export",
+           Pg_lo_export,
+           (ClientData)NULL, (Tcl_CmdDeleteProc*)NULL);
+  
+  Tcl_CreateCommand(interp,
+           "pg_listen",
+           Pg_listen,
+           (ClientData)NULL, (Tcl_CmdDeleteProc*)NULL);
+
+  Tcl_CreateCommand(interp,
+           "pg_notifies",
+           Pg_notifies,
+           (ClientData)NULL, (Tcl_CmdDeleteProc*)NULL);
+
+  Tcl_PkgProvide(interp, "Pgtcl", "1.1");
+
+  return TCL_OK;
 }
 
 
 int
-Pgtcl_SafeInit(Tcl_Interp * interp)
+Pgtcl_SafeInit (Tcl_Interp *interp)
 {
-   return Pgtcl_Init(interp);
+    return Pgtcl_Init(interp);
 }
index 7f30db081833e7fc281af941e0507a4b0222e288..c68c842fedc84a15c1f5e9888fd31d0c3353eac9 100644 (file)
@@ -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 $
  *
  *-------------------------------------------------------------------------
  */
@@ -240,258 +240,255 @@ tcl_value(char *value)
 
 /**********************************
  * pg_conndefaults
-
  syntax:
  pg_conndefaults
-
  the return result is a list describing the possible options and their
  current default values for a call to pg_connect with the new -conninfo
  syntax. Each entry in the list is a sublist of the format:
 
-    {optname label dispchar dispsize value}
-
+     {optname label dispchar dispsize 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)
-       {
-           option->val = "";
-       }
-       sprintf(buf, "{%s} {%s} {%s} %d {%s}",
-               option->keyword,
-               option->label,
-               option->dispchar,
-               option->dispsize,
-               option->val);
-       Tcl_AppendElement(interp, buf);
-   }
-
-   return TCL_OK;
+    PQconninfoOption *option;
+    char   buf[8192];
+
+    Tcl_ResetResult(interp);
+    for(option = PQconndefaults(); option->keyword != NULL; option++) {
+        if(option->val == NULL) {
+       option->val = "";
+   }
+   sprintf(buf, "{%s} {%s} {%s} %d {%s}",
+       option->keyword,
+       option->label,
+       option->dispchar,
+       option->dispsize,
+       option->val);
+        Tcl_AppendElement(interp, buf);
+    }
+
+    return TCL_OK;
 }
 
 
 /**********************************
  * pg_connect
- make a connection to a backend.
-
+ make a connection to a backend.  
  syntax:
  pg_connect dbName [-host hostName] [-port portNumber] [-tty pqtty]]
-
  the return result is either an error message or a handle for a database
  connection.  Handles start with the prefix "pgp"
-
  **********************************/
 
 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;
-   char       *pgoptions = NULL;
-   char       *dbName;
-   int         i;
-   PGconn     *conn;
-
-   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);
-       return TCL_ERROR;
+    char *pghost = NULL;
+    char *pgtty = NULL;
+    char *pgport = NULL;
+    char *pgoptions = NULL;
+    char *dbName; 
+    int i;
+    PGconn *conn;
+  
+    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);
+   return TCL_ERROR;
+    
+    }
 
+    if (!strcmp("-conninfo", argv[1])) {
+   /*
+    * Establish a connection using the new PQconnectdb() interface
+    */
+        if (argc != 3) {
+       Tcl_AppendResult(interp, "pg_connect: syntax error\n", 0);
+       Tcl_AppendResult(interp, "pg_connect -conninfo <conninfo-string>", 0);
+       return TCL_ERROR;
    }
-
-   if (!strcmp("-conninfo", argv[1]))
-   {
-
-       /*
-        * Establish a connection using the new PQconnectdb() interface
-        */
-       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 {
+   /*
+    * Establish a connection using the old PQsetdb() interface
+    */
+   if (argc > 2) { 
+       /* parse for pg environment settings */
+       i = 2;
+       while (i+1 < argc) {
+       if (strcmp(argv[i], "-host") == 0) {
+           pghost = argv[i+1];
+           i += 2;
        }
-       conn = PQconnectdb(argv[2]);
-   }
-   else
-   {
-
-       /*
-        * Establish a connection using the old PQsetdb() interface
-        */
-       if (argc > 2)
-       {
-           /* parse for pg environment settings */
-           i = 2;
-           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];
-                   i += 2;
-               }
-               else if (strcmp(argv[i], "-tty") == 0)
-               {
-                   pgtty = argv[i + 1];
-                   i += 2;
-               }
-               else if (strcmp(argv[i], "-options") == 0)
-               {
-                   pgoptions = argv[i + 1];
-                   i += 2;
-               }
-               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);
-                   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);
-               return TCL_ERROR;
+       else
+           if (strcmp(argv[i], "-port") == 0) {
+           pgport = argv[i+1];
+           i += 2;
+           }
+           else
+           if (strcmp(argv[i], "-tty") == 0) {
+               pgtty = argv[i+1];
+               i += 2;
            }
-       }
-       dbName = argv[1];
-       conn = PQsetdb(pghost, pgport, pgoptions, pgtty, dbName);
-   }
-
-   if (conn->status == CONNECTION_OK)
-   {
-       PgSetConnectionId(cd, interp->result, conn);
-       return TCL_OK;
-   }
-   else
-   {
-       Tcl_AppendResult(interp, "Connection to database failed\n", 0);
-       Tcl_AppendResult(interp, conn->errorMessage, 0);
-       PQfinish(conn);
+           else if (strcmp(argv[i], "-options") == 0) {
+               pgoptions = argv[i+1];
+               i += 2;
+           }
+           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);
+               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);
        return TCL_ERROR;
+       }
    }
+   dbName = argv[1];
+        conn = PQsetdb(pghost, pgport, pgoptions, pgtty, dbName);
+    }
+
+    if (conn->status == CONNECTION_OK) {
+   PgSetConnectionId(interp, conn);
+   return TCL_OK;
+    }
+    else {
+   Tcl_AppendResult(interp, "Connection to database failed\n", 0);
+   Tcl_AppendResult(interp, conn->errorMessage, 0);
+   PQfinish(conn);
+   return TCL_ERROR;
+    }
 }
 
 
 /**********************************
  * pg_disconnect
  close a backend connection
-
  syntax:
  pg_disconnect connection
-
  The argument passed in must be a connection pointer.
-
  **********************************/
 
 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)
-   {
-       Tcl_AppendResult(interp, "Wrong # of arguments\n", "pg_disconnect connection", 0);
-       return TCL_ERROR;
-   }
+    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);
-       return TCL_ERROR;
-   }
+    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);
 }
 
 /**********************************
  * pg_exec
  send a query string to the backend connection
-
  syntax:
  pg_exec connection query
-
  the return result is either an error message or a handle for a query
  result.  Handles start with the prefix "pgp"
  **********************************/
 
 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;
-   PGconn     *conn;
-   PGresult   *result;
+    Pg_ConnectionId *connid;
+    PGconn *conn;
+    PGresult *result;
+    int connStatus;
+
+    if (argc != 3) {
+   Tcl_AppendResult(interp, "Wrong # of arguments\n",
+            "pg_exec connection queryString", 0);
+   return TCL_ERROR;
+    }
 
-   if (argc != 3)
-   {
-       Tcl_AppendResult(interp, "Wrong # of arguments\n",
-                        "pg_exec connection queryString", 0);
-       return TCL_ERROR;
-   }
+    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;
+    }
 
-   conn = PgGetConnectionId(cd, argv[1]);
-   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;
+    }
 
-   result = PQexec(conn, argv[2]);
-   if (result)
-   {
-       PgSetResultId(cd, interp->result, argv[1], result);
-       return TCL_OK;
+    connStatus = conn->status;
+    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;
    }
-   else
-   {
-       /* error occurred during the query */
-       Tcl_SetResult(interp, conn->errorMessage, TCL_STATIC);
-       return TCL_ERROR;
-   }
-   /* check return status of result */
    return TCL_OK;
+    }
+    else {
+   /* error occurred during the query */
+   Tcl_SetResult(interp, conn->errorMessage, TCL_STATIC);
+   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;
+           }
+           return TCL_OK;
+       }
+       }
+   }
+   return TCL_ERROR;
+    }
 }
 
 /**********************************
  * pg_result
  get information about the results of a query
-
  syntax:
- pg_result result ?option?
-
+ pg_result result ?option? 
  the options are:
- -status
+ -status  
  the status of the result
  -conn
  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,333 +499,303 @@ 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
- -clear
+ -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);
-       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);
-       return TCL_ERROR;
-   }
+    PGresult *result;
+    char *opt;
+    int i;
+    int tupno;
+    char prearrayInd[MAX_MESSAGE_LEN];
+    char arrayInd[MAX_MESSAGE_LEN];
+    char *arrVar;
+
+    if (argc < 3 || argc > 5) {
+   Tcl_AppendResult(interp, "Wrong # of arguments\n",0);
+   goto Pg_result_errReturn;
+    }
+
+    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];
+    opt = argv[2];
 
-   if (strcmp(opt, "-status") == 0)
-   {
-       Tcl_AppendResult(interp, pgresStatus[PQresultStatus(result)], 0);
-       return TCL_OK;
-   }
-   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, "-clear") == 0)
-   {
-       PgDelResultId(cd, argv[1]);
-       PQclear(result);
-       return TCL_OK;
-   }
-   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);
-           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));
-               Tcl_SetVar2(interp, arrVar, arrayInd,
+    if (strcmp(opt, "-status") == 0) {
+   Tcl_AppendResult(interp, pgresStatus[PQresultStatus(result)], 0);
+   return TCL_OK;
+    }
+    else if (strcmp(opt, "-oid") == 0) {
+   Tcl_AppendResult(interp, PQoidStatus(result), 0);
+   return TCL_OK;
+    }
+    else if (strcmp(opt, "-conn") == 0) {
+   return PgGetConnByResultId(interp, argv[1]);
+    }
+    else if (strcmp(opt, "-clear") == 0) {
+   PgDelResultId(interp, argv[1]);
+   PQclear(result);
+   return TCL_OK;
+    }
+    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);
+       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));
+       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);
-           }
-       }
-       Tcl_AppendResult(interp, arrVar, 0);
-       return TCL_OK;
+               TCL_LEAVE_ERR_MSG);
+       }
    }
-   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);
-           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);
-               Tcl_SetVar2(interp, arrVar, arrayInd,
-                           PQgetvalue(result, tupno, i),
-                           TCL_LEAVE_ERR_MSG);
-           }
-       }
-       Tcl_AppendResult(interp, arrVar, 0);
-       return TCL_OK;
+   Tcl_AppendResult(interp, arrVar, 0);
+   return TCL_OK;
+    }
+    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)*/
+      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),
+                          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);
+       return TCL_ERROR;
+   }
+   tupno = atoi(argv[3]);
+   
+   if (tupno >= PQntuples(result)) {
+       Tcl_AppendResult(interp, "argument to getTuple cannot exceed number of tuples - 1",0);
+       return TCL_ERROR;
    }
-   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);
-           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_AppendResult(interp, " ", PQgetvalue(result,tupno,i),NULL);*/
-           Tcl_AppendElement(interp, PQgetvalue(result, tupno, i));
-       }
+/* Tcl_AppendResult(interp, PQgetvalue(result,tupno,0),NULL); */
+        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));
+   }
 #endif
 
-       return TCL_OK;
+   return TCL_OK;
+    }
+    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;
    }
-   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;
+   tupno = atoi(argv[3]);
+   
+   if (tupno >= PQntuples(result)) {
+       Tcl_AppendResult(interp, "argument to tupleArray cannot exceed number of tuples - 1",0);
+       return TCL_ERROR;
    }
-   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),
-                   (long) 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;
+   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;
+      }
    }
-   else
-   {
-       Tcl_AppendResult(interp, "Invalid option", 0);
-       goto 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-numTuples\n",
-                    "\t-attributes\n"
-                    "\t-lAttributes\n"
-                    "\t-numAttrs\n"
-                    "\t-getTuple tupleNumber\n",
-                    "\t-clear\n",
-                    "\t-oid\n",
-                    0);
-   return TCL_ERROR;
-
+   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);
+      }
+      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),
+                     (long) 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;
+    }
+  
+
+ 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\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",
+            (char*)0);
+    return TCL_ERROR;
+  
 
 }
 
 /**********************************
  * pg_lo_open
-    open a large object
-
+     open a large object
  syntax:
- pg_lo_open conn objOid mode
+ pg_lo_open conn objOid mode 
 
  where mode can be either 'r', 'w', or 'rw'
 **********************/
 
 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)
-   {
-       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)
-   {
-       Tcl_AppendResult(interp, "First argument is not a valid connection\n", 0);
-       return TCL_ERROR;
-   }
-
-   lobjId = atoi(argv[2]);
-   if (strlen(argv[3]) < 1 ||
-       strlen(argv[3]) > 2)
-   {
-       Tcl_AppendResult(interp, "mode argument must be 'r', 'w', or 'rw'", 0);
-       return TCL_ERROR;
-   }
-   switch (argv[3][0])
-   {
-       case 'r':
-       case 'R':
-           mode = INV_READ;
-           break;
-       case 'w':
-       case 'W':
-           mode = INV_WRITE;
-           break;
-       default:
-           Tcl_AppendResult(interp, "mode argument must be 'r', 'w', or 'rw'", 0);
-           return TCL_ERROR;
-   }
-   switch (argv[3][1])
-   {
-       case '\0':
-           break;
-       case 'r':
-       case 'R':
-           mode = mode & INV_READ;
-           break;
-       case 'w':
-       case 'W':
-           mode = mode & INV_WRITE;
-           break;
-       default:
-           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);
-   return TCL_OK;
+    PGconn *conn;
+    int lobjId;
+    int mode;
+    int fd;
+
+    if (argc != 4) {
+   Tcl_AppendResult(interp, "Wrong # of arguments\n",
+            "pg_lo_open connection lobjOid mode", 0);
+   return TCL_ERROR;
+    }
+  
+    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]);
+    if (strlen(argv[3]) < 1 ||
+   strlen(argv[3]) > 2)
+   {
+   Tcl_AppendResult(interp,"mode argument must be 'r', 'w', or 'rw'",0);
+        return TCL_ERROR;
+    }
+    switch (argv[3][0]) {
+    case 'r':
+    case 'R':
+   mode = INV_READ;
+   break;
+    case 'w':
+    case 'W':
+   mode = INV_WRITE;
+   break;
+    default:
+   Tcl_AppendResult(interp,"mode argument must be 'r', 'w', or 'rw'",0);
+        return TCL_ERROR;
+   }
+    switch (argv[3][1]) {
+    case '\0':
+   break;
+    case 'r':
+    case 'R':
+   mode = mode & INV_READ;
+   break;
+    case 'w':
+    case 'W':
+   mode = mode & INV_WRITE;
+   break;
+    default:
+   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);
+    return TCL_OK;
 }
 
 /**********************************
  * pg_lo_close
-    close a large object
-
+     close a large object
  syntax:
- pg_lo_close conn fd
+ pg_lo_close conn fd 
 
 **********************/
 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;
+    PGconn *conn;
+    int fd;
 
-   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)
-   {
-       Tcl_AppendResult(interp, "First argument is not a valid connection\n", 0);
-       return TCL_ERROR;
-   }
+    if (argc != 3) {
+   Tcl_AppendResult(interp, "Wrong # of arguments\n",
+            "pg_lo_close connection fd", 0);
+   return TCL_ERROR;
+    }
 
-   fd = atoi(argv[2]);
-   sprintf(interp->result, "%d", lo_close(conn, fd));
-   return TCL_OK;
+    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));
+    return TCL_OK;
 }
 
 /**********************************
  * pg_lo_read
-    reads at most len bytes from a large object into a variable named
+     reads at most len bytes from a large object into a variable named
  bufVar
-
  syntax:
  pg_lo_read conn fd bufVar len
 
@@ -836,104 +803,96 @@ 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;
-   char       *buf;
-   char       *bufVar;
-   int         len;
-
-   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)
-   {
-       Tcl_AppendResult(interp, "First argument is not a valid connection\n", 0);
-       return TCL_ERROR;
-   }
-
-   fd = atoi(argv[2]);
-
-   bufVar = argv[3];
+    PGconn *conn;
+    int fd;
+    int nbytes = 0;
+    char *buf;
+    char *bufVar;
+    int len;
+
+    if (argc != 5) {
+   Tcl_AppendResult(interp, "Wrong # of arguments\n",
+            " pg_lo_read conn fd bufVar len", 0);
+   return TCL_ERROR;
+    }
 
-   len = atoi(argv[4]);
+    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]);
 
-   if (len <= 0)
-   {
-       sprintf(interp->result, "%d", nbytes);
-       return TCL_OK;
-   }
-   buf = malloc(sizeof(len + 1));
+    bufVar = argv[3];
 
-   nbytes = lo_read(conn, fd, buf, len);
+    len = atoi(argv[4]);
 
-   Tcl_SetVar(interp, bufVar, buf, TCL_LEAVE_ERR_MSG);
-   sprintf(interp->result, "%d", nbytes);
-   free(buf);
+    if (len <= 0) {
+   sprintf(interp->result,"%d",nbytes);
    return TCL_OK;
+    }
+    buf = ckalloc(sizeof(len+1));
 
+    nbytes = lo_read(conn,fd,buf,len);
+
+    Tcl_SetVar(interp,bufVar,buf,TCL_LEAVE_ERR_MSG);
+    sprintf(interp->result,"%d",nbytes);
+    ckfree(buf);
+    return TCL_OK;
+    
 }
 
 /***********************************
 Pg_lo_write
-   write at most len bytes to a large object
+   write at most len bytes to a large object 
 
  syntax:
  pg_lo_write conn fd buf len
 
 ***********************************/
 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)
-   {
-       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)
-   {
-       Tcl_AppendResult(interp, "First argument is not a valid connection\n", 0);
-       return TCL_ERROR;
-   }
+    PGconn *conn;
+    char *buf;
+    int fd;
+    int nbytes = 0;
+    int len;
+
+    if (argc != 5) {
+   Tcl_AppendResult(interp, "Wrong # of arguments\n",
+            "pg_lo_write conn fd buf len", 0);
+   return TCL_ERROR;
+    }
 
-   fd = atoi(argv[2]);
+    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]);
 
-   buf = argv[3];
+    buf = argv[3];
 
-   len = atoi(argv[4]);
+    len = atoi(argv[4]);
 
-   if (len <= 0)
-   {
-       sprintf(interp->result, "%d", nbytes);
-       return TCL_OK;
-   }
-
-   nbytes = lo_write(conn, fd, buf, len);
-   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);
+    return TCL_OK;
 }
 
 /***********************************
 Pg_lo_lseek
-   seek to a certain position in a large object
+    seek to a certain position in a large object
 
 syntax
   pg_lo_lseek conn fd offset whence
@@ -942,54 +901,43 @@ 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;
-
-   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)
-   {
-       Tcl_AppendResult(interp, "First argument is not a valid connection\n", 0);
-       return TCL_ERROR;
-   }
-
-   fd = atoi(argv[2]);
-
-   offset = atoi(argv[3]);
-
-   whenceStr = argv[4];
-   if (strcmp(whenceStr, "SEEK_SET") == 0)
-   {
-       whence = SEEK_SET;
-   }
-   else if (strcmp(whenceStr, "SEEK_CUR") == 0)
-   {
-       whence = SEEK_CUR;
-   }
-   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);
-       return TCL_ERROR;
-   }
+    PGconn *conn;
+    int fd;
+    char *whenceStr;
+    int offset, whence;
+
+    if (argc != 5) {
+   Tcl_AppendResult(interp, "Wrong # of arguments\n",
+            "pg_lo_lseek conn fd offset whence", 0);
+   return TCL_ERROR;
+    }
 
-   sprintf(interp->result, "%d", lo_lseek(conn, fd, offset, whence));
-   return TCL_OK;
+    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]);
+
+    offset = atoi(argv[3]);
+
+    whenceStr = argv[4];
+    if (strcmp(whenceStr,"SEEK_SET") == 0) {
+   whence = SEEK_SET;
+    } else if (strcmp(whenceStr,"SEEK_CUR") == 0) {
+   whence = SEEK_CUR;
+    } 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);
+   return TCL_ERROR;
+    }
+   
+    sprintf(interp->result,"%d",lo_lseek(conn,fd,offset,whence));
+    return TCL_OK;
 }
 
 
@@ -1000,113 +948,96 @@ 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)
-   {
-       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)
-   {
-       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)
-   {
-       mode = INV_READ;
-   }
-   else if (strcmp(modeWord, "INV_WRITE") == 0)
-   {
-       mode = INV_WRITE;
-   }
-   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;
-   }
+    PGconn *conn;
+    char *modeStr;
+    char *modeWord;
+    int mode;
+
+    if (argc != 3) {
+   Tcl_AppendResult(interp, "Wrong # of arguments\n",
+            "pg_lo_creat conn mode", 0);
+   return TCL_ERROR;
+    }
 
-   while ((modeWord = strtok((char *) NULL, "|")) != NULL)
-   {
-       if (strcmp(modeWord, "INV_READ") == 0)
-       {
-           mode |= INV_READ;
-       }
-       else if (strcmp(modeWord, "INV_WRITE") == 0)
-       {
-           mode |= INV_WRITE;
-       }
-       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;
-       }
-   }
-   sprintf(interp->result, "%d", lo_creat(conn, mode));
-   return TCL_OK;
+    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) {
+   mode = INV_READ;
+    } else if (strcmp(modeWord,"INV_WRITE") == 0) {
+   mode = INV_WRITE;
+    } 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) {
+       mode |= INV_READ;
+   } else if (strcmp(modeWord,"INV_WRITE") == 0) {
+       mode |= INV_WRITE;
+   } else {
+       Tcl_AppendResult(interp,
+                "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));
+    return TCL_OK;
 }
 
 /***********************************
 Pg_lo_tell
-   returns the current seek location of the large object
+    returns the current seek location of the large object
 
  syntax:
    pg_lo_tell conn fd
 
 ***********************************/
 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)
-   {
-       Tcl_AppendResult(interp, "Wrong # of arguments\n",
-                        "pg_lo_tell conn fd", 0);
-       return TCL_ERROR;
-   }
+    PGconn *conn;
+    int fd;
 
-   conn = PgGetConnectionId(cd, argv[1]);
-   if (conn == (PGconn *) NULL)
-   {
-       Tcl_AppendResult(interp, "First argument is not a valid connection\n", 0);
-       return TCL_ERROR;
-   }
+    if (argc != 3) {
+   Tcl_AppendResult(interp, "Wrong # of arguments\n",
+            "pg_lo_tell conn fd", 0);
+   return TCL_ERROR;
+    }
 
-   fd = atoi(argv[2]);
+    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));
-   return TCL_OK;
+    sprintf(interp->result,"%d",lo_tell(conn,fd));
+    return TCL_OK;
 
 }
 
 /***********************************
 Pg_lo_unlink
-   unlink a file based on lobject id
+    unlink a file based on lobject id 
 
  syntax:
    pg_lo_unlink conn lobjId
@@ -1114,43 +1045,39 @@ 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)
-   {
-       Tcl_AppendResult(interp, "Wrong # of arguments\n",
-                        "pg_lo_tell conn fd", 0);
-       return TCL_ERROR;
-   }
+    PGconn *conn;
+    int lobjId;
+    int retval;
 
-   conn = PgGetConnectionId(cd, argv[1]);
-   if (conn == (PGconn *) NULL)
-   {
-       Tcl_AppendResult(interp, "First argument is not a valid connection\n", 0);
-       return TCL_ERROR;
-   }
-
-   lobjId = atoi(argv[2]);
+    if (argc != 3) {
+   Tcl_AppendResult(interp, "Wrong # of arguments\n",
+            "pg_lo_tell conn fd", 0);
+   return TCL_ERROR;
+    }
 
-   retval = lo_unlink(conn, lobjId);
-   if (retval == -1)
-   {
-       sprintf(interp->result, "Pg_lo_unlink of '%d' failed", lobjId);
-       return TCL_ERROR;
-   }
+    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]);
 
-   sprintf(interp->result, "%d", retval);
-   return TCL_OK;
+    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);
+    return TCL_OK;
 }
 
 /***********************************
 Pg_lo_import
-   import a Unix file into an (inversion) large objct
+    import a Unix file into an (inversion) large objct
  returns the oid of that object upon success
  returns InvalidOid upon failure
 
@@ -1160,87 +1087,79 @@ 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;
-   Oid         lobjId;
-
-   if (argc != 3)
-   {
-       Tcl_AppendResult(interp, "Wrong # of arguments\n",
-                        "pg_lo_import conn filename", 0);
-       return TCL_ERROR;
-   }
+    PGconn *conn;
+    char* filename;
+    Oid lobjId;
 
-   conn = PgGetConnectionId(cd, argv[1]);
-   if (conn == (PGconn *) NULL)
-   {
-       Tcl_AppendResult(interp, "First argument is not a valid connection\n", 0);
-       return TCL_ERROR;
-   }
+    if (argc != 3) {
+   Tcl_AppendResult(interp, "Wrong # of arguments\n",
+            "pg_lo_import conn filename", 0);
+   return TCL_ERROR;
+    }
 
-   filename = argv[2];
+    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);
-       return TCL_ERROR;
-   }
-   sprintf(interp->result, "%d", lobjId);
-   return TCL_OK;
+    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);
+    return TCL_OK;
 }
 
 /***********************************
 Pg_lo_export
-   export an Inversion large object to a Unix file
-
+    export an Inversion large object to a Unix file
+    
  syntax:
    pg_lo_export conn lobjId filename
 
 ***********************************/
 
 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;
-   Oid         lobjId;
-   int         retval;
-
-   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)
-   {
-       Tcl_AppendResult(interp, "First argument is not a valid connection\n", 0);
-       return TCL_ERROR;
-   }
-
-   lobjId = atoi(argv[2]);
-   filename = argv[3];
+    PGconn *conn;
+    char* filename;
+    Oid lobjId;
+    int retval;
+
+    if (argc != 4) {
+   Tcl_AppendResult(interp, "Wrong # of arguments\n",
+            "pg_lo_export conn lobjId filename", 0);
+   return TCL_ERROR;
+    }
 
-   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;
+    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]);
+    filename = argv[3];
+
+    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;
 }
 
 /**********************************
  * pg_select
  send a select query string to the backend connection
-
  syntax:
  pg_select connection query var proc
 
@@ -1250,7 +1169,7 @@ Pg_lo_export(ClientData cData, Tcl_Interp * interp, int argc, char *argv[])
 
  Originally I was also going to update changes but that has turned out
  to be not so simple.  Instead, the caller should get the OID of any
- table they want to update and update it themself in the loop. I may
+ table they want to update and update it themself in the loop.  I may
  try to write a simplified table lookup and update function to make
  that task a little easier.
 
@@ -1259,45 +1178,39 @@ 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;
+   PGconn *conn;
+       PGresult *result;
+    int r;
+    size_t tupno, column, ncols;
    Tcl_DString headers;
-   char        buffer[2048];
-   struct
-   {
-       char       *cname;
-       int         change;
-   }          *info;
+   char    buffer[2048];
+   struct info_s {
+       char    *cname;
+       int     change;
+   } *info;
 
    if (argc != 5)
    {
        Tcl_AppendResult(interp, "Wrong # of arguments\n",
-                        "pg_select connection queryString var proc", 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);
+            "pg_select connection queryString var proc", 0);
        return TCL_ERROR;
    }
 
+    conn = PgGetConnectionId(interp, argv[1], (Pg_ConnectionId**)NULL);
+    if (conn == (PGconn *)NULL) {
+   return TCL_ERROR;
+    }
+  
    if ((result = PQexec(conn, argv[2])) == 0)
-   {
+    {
        /* error occurred during the query */
        Tcl_SetResult(interp, conn->errorMessage, TCL_STATIC);
        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,196 +1245,166 @@ 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];
+               char    msg[60];
 
                sprintf(msg, "\n    (\"pg_select\" body line %d)",
-                       interp->errorLine);
+                               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;
-   PGconn     *conn;
-   PGresult   *result;
-
-   if ((argc < 3) || (argc > 4))
-   {
-       Tcl_AppendResult(interp, "wrong # args, should be \"",
-                        argv[0], " connection relname ?callback?\"", 0);
-       return TCL_ERROR;
-   }
-
-   /*
-    * 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)
-   {
-       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));
-       strcpy(callback, argv[3]);
-   }
-
-   /*
-    * Set or update a callback for a relation;
-    */
-   if (callback)
-   {
-       entry = Tcl_CreateHashEntry(&(cd->notify_hash), relname, &new);
-       if (new)
-       {
-           /* New callback, execute a listen command on the relation */
-           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))
-           {
-               /* Error occurred during the execution of command */
-               if (result)
-                   PQclear(result);
-               ckfree(callback);
-               Tcl_DeleteHashEntry(entry);
-               Tcl_SetResult(interp, conn->errorMessage, TCL_STATIC);
-               return TCL_ERROR;
-           }
-           PQclear(result);
-       }
-       else
-       {
-           /* Free the old callback string */
-           ckfree((char *) Tcl_GetHashValue(entry));
-       }
-       /* Store the new callback command */
-       Tcl_SetHashValue(entry, callback);
-   }
-
-   /*
-    * 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)
-       {
-           Tcl_AppendResult(interp, "not listening on ", relname, 0);
-           return TCL_ERROR;
-       }
-       ckfree((char *) Tcl_GetHashValue(entry));
+    int new;
+    char *relname;
+    char *callback = NULL;
+    Tcl_HashEntry *entry;
+    Pg_ConnectionId *connid;
+    PGconn *conn;
+    PGresult *result;
+
+    if ((argc < 3) || (argc > 4)) {
+   Tcl_AppendResult(interp, "wrong # args, should be \"",
+            argv[0], " connection relname ?callback?\"", 0);
+   return TCL_ERROR;
+    }
+
+    /*
+     * Get the command arguments. Note that relname will copied by
+     * Tcl_CreateHashEntry while callback must be allocated.
+     */
+    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));
+   strcpy(callback, argv[3]);
+    }
+
+    /*
+     * Set or update a callback for a relation;
+     */
+    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));
+       sprintf(cmd, "LISTEN %s", relname);
+       result = PQexec(conn, cmd);
+       ckfree(cmd);
+       if (!result || (result->resultStatus != PGRES_COMMAND_OK)) {
+       /* Error occurred during the execution of command */
+       if (result) PQclear(result);
+       ckfree(callback);
        Tcl_DeleteHashEntry(entry);
-   }
-
-   return TCL_OK;
+       Tcl_SetResult(interp, conn->errorMessage, TCL_STATIC);
+       return TCL_ERROR;
+       }
+       PQclear(result);
+   } else {
+       /* Free the old callback string */
+       ckfree((char *) Tcl_GetHashValue(entry));
+   }
+   /* Store the new callback command */
+   Tcl_SetHashValue(entry, callback);
+    }
+
+    /*
+     * 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(&(connid->notify_hash), relname);
+   if (entry == NULL) {
+       Tcl_AppendResult(interp, "not listening on ", relname, 0);
+       return TCL_ERROR;
+   }
+   ckfree((char *) Tcl_GetHashValue(entry));
+   Tcl_DeleteHashEntry(entry);
+    }
+
+    return TCL_OK;
 }
 
 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;
-   PGconn     *conn;
-   PGresult   *result;
-   PGnotify   *notify;
-
-   if (argc != 2)
-   {
-       Tcl_AppendResult(interp, "wrong # args, should be \"",
-                        argv[0], " connection\"", 0);
-       return TCL_ERROR;
-   }
-
-   /*
-    * Get the connection argument.
-    */
-   conn = (PGconn *) PgGetConnectionId(cd, argv[1]);
-   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)
-   {
-       /* Error occurred during the execution of command */
-       Tcl_SetResult(interp, conn->errorMessage, TCL_STATIC);
-       return TCL_ERROR;
-   }
-   PQclear(result);
-
-   /*
-    * Loop while there are pending notifies.
-    */
-   for (count = 0; count < 999; count++)
-   {
-       /* See if there is a pending notification */
-       notify = PQnotifies(conn);
-       if (notify == NULL)
-       {
-           break;
-       }
-       entry = Tcl_FindHashEntry(&(cd->notify_hash), notify->relname);
-       if (entry != NULL)
-       {
-           callback = Tcl_GetHashValue(entry);
-           if (callback)
-           {
-               Tcl_Eval(interp, callback);
-           }
-       }
-       free(notify);
-   }
-
-   /*
-    * Return the number of notifications processed.
-    */
-   sprintf(buff, "%d", count);
-   Tcl_SetResult(interp, buff, TCL_VOLATILE);
-   return TCL_OK;
+    int count;
+    char buff[12];
+    char *callback;
+    Tcl_HashEntry *entry;
+    Pg_ConnectionId *connid;
+    PGconn *conn;
+    PGresult *result;
+    PGnotify *notify;
+
+    if (argc != 2) {
+   Tcl_AppendResult(interp, "wrong # args, should be \"",
+            argv[0], " connection\"", 0);
+   return TCL_ERROR;
+    }
+
+    /*
+     * Get the connection argument.
+     */
+    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) {
+      /* Error occurred during the execution of command */
+      Tcl_SetResult(interp, conn->errorMessage, TCL_STATIC);
+      return TCL_ERROR;
+    }
+    PQclear(result);
+
+    /*
+     * Loop while there are pending notifies.
+     */
+    for (count=0; count < 999; count++) {
+   /* See if there is a pending notification */
+   notify = PQnotifies(conn);
+   if (notify == NULL) {
+       break;
+   }
+   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);
+    }
+
+    /*
+     * Return the number of notifications processed.
+     */
+    sprintf(buff, "%d", count);
+    Tcl_SetResult(interp, buff, TCL_VOLATILE);
+    return TCL_OK;
 }
index 6def84d97ffc0dde6cf61fa59292feca1b972844..f0f8513da449bdbdb77dc63f9223794ba3e5e4c8 100644 (file)
@@ -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 $
  *
  *-------------------------------------------------------------------------
  */
 #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 {
+    char       id[32];
+    PGconn     *conn;
+    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_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;
+#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 */
index 2473b6c3181013ff3a08a001912843b571c7bbdd..971b04039b45c330c772ead51ffa7353f6cd3afd 100644 (file)
 /*-------------------------------------------------------------------------
  *
  * pgtclId.c--
- *   useful routines to convert between strings and pointers
- * Needed because everything in tcl is a string, but we want pointers
- * to data structures
+ *    useful routines to convert between strings and pointers
+ *  Needed because everything in tcl is a string, but we want pointers
+ *  to data structures
  *
- * ASSUMPTION:  sizeof(long) >= sizeof(void*)
+ *  ASSUMPTION:  sizeof(long) >= sizeof(void*)
  *
  *
  * Copyright (c) 1994, Regents of the University of California
  *
  *
  * 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;
-   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);
+    Tcl_Channel        conn_chan;
+    Pg_ConnectionId    *connid;
+    int            i;
+
+    connid = (Pg_ConnectionId *)ckalloc(sizeof(Pg_ConnectionId));
+    connid->conn = conn;
+    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,19 +175,22 @@ 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;
-   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;
+    Tcl_Channel conn_chan;
+    Pg_ConnectionId    *connid;
+
+    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_GetChannelInstanceData(conn_chan);
+    if (connid_p)
+   *connid_p = connid;
+    return connid->conn;
 }
 
 
@@ -70,98 +198,139 @@ 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_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);
+    Tcl_HashEntry  *entry;
+    char       *hval;
+    Tcl_HashSearch hsearch;
+    Pg_ConnectionId    *connid;
+    int            i;
+
+    connid = (Pg_ConnectionId *)cData;
+
+    for (i = 0; i < connid->res_max; i++) {
+   if (connid->results[i])
+       PQclear(connid->results[i]);
+    }
+    ckfree((void*)connid->results);
+
+    for (entry = Tcl_FirstHashEntry(&(connid->notify_hash), &hsearch);
+   entry != NULL;
+   entry = Tcl_NextHashEntry(&hsearch))
+    {
+   hval = (char*)Tcl_GetHashValue(entry);
+   ckfree(hval);
+    }
+    
+    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;
-   Pg_ConnectionId *connid;
-   Pg_ResultId *resid;
-   int         hnew;
+    Tcl_Channel        conn_chan;
+    Pg_ConnectionId    *connid;
+    int            resid, i;
+    char       buf[32];
 
-   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);
+    conn_chan = Tcl_GetChannel(interp, connid_c, 0);
+    if(conn_chan == NULL)
+        return TCL_ERROR;
+    connid = (Pg_ConnectionId *)Tcl_GetChannelInstanceData(conn_chan);
 
-   if (connid != NULL)
+    for (resid = connid->res_last+1; resid != connid->res_last; resid++) {
+   if (resid == connid->res_max)
+       resid = 0;
+   if (!connid->results[resid])
    {
-       hent = Tcl_CreateHashEntry(&(connid->res_hash), resid->id, &hnew);
-       Tcl_SetHashValue(hent, (ClientData) resid);
+       connid->res_last = resid;
+       break;
+   }
+    }
+
+    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;
+    }
+
+    connid->results[resid] = res;
+    sprintf(buf, "%s.%d", connid_c, resid);
+    Tcl_SetResult(interp, buf, TCL_VOLATILE);
+    return 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;
 }
 
 
 /*
  * Get back the result pointer from the Id
  */
-PGresult   *
-PgGetResultId(Pg_clientData * cd, char *id)
+PGresult *
+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;
-
-   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);
-       }
-   }
+    Pg_ConnectionId    *connid;
+    int            resid;
 
-   Tcl_DeleteHashEntry(hent);
-   ckfree(resid);
+    resid = getresid(interp, id, &connid);
+    if (resid == -1)
+   return;
+    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;
+    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;
+    }
+
+  error_out:
+    Tcl_ResetResult(interp);
+    Tcl_AppendResult(interp, resid_c, " is not a valid connection\n", 0);
+    return TCL_ERROR;
+}
 
-   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);
-   }
-}
index 130f017ec6ec39a740c67af283d6f458de6fa3c7..648531fdc7fe9dd8fba4248d3056635f04dd89f7 100644 (file)
@@ -1,22 +1,47 @@
 /*-------------------------------------------------------------------------
- *
- * 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(Tcl_Interp *interp, PGconn *conn);
 
-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);
+#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;