]> granicus.if.org Git - postgresql/commitdiff
Add two new comments to pglibtcl...
authorMarc G. Fournier <scrappy@hub.org>
Thu, 19 Dec 1996 05:02:51 +0000 (05:02 +0000)
committerMarc G. Fournier <scrappy@hub.org>
Thu, 19 Dec 1996 05:02:51 +0000 (05:02 +0000)
From: Massimo Dal Zotto <dz@cs.unitn.it>

src/interfaces/libpgtcl/pgtcl.c
src/interfaces/libpgtcl/pgtclCmds.c
src/interfaces/libpgtcl/pgtclCmds.h

index 2cbec47395d40b6ee78b134b947e891b65e37615..cc77d7e6857ce230c5c50a5cc6086f1af8383d9f 100644 (file)
@@ -9,7 +9,7 @@
  *
  *
  * IDENTIFICATION
- *    $Header: /cvsroot/pgsql/src/interfaces/libpgtcl/Attic/pgtcl.c,v 1.5 1996/11/11 12:14:38 scrappy Exp $
+ *    $Header: /cvsroot/pgsql/src/interfaces/libpgtcl/Attic/pgtcl.c,v 1.6 1996/12/19 05:02:47 scrappy Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -159,6 +159,16 @@ Pgtcl_Init (Tcl_Interp *interp)
                    Pg_lo_export,
                    (ClientData)cd, (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.0");
 
   return TCL_OK;
index 980055e378dd85c76ddc2e3127770308aab3125a..65839b18b2cab1953aee41168b9d0a1a0c243ec6 100644 (file)
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *    $Header: /cvsroot/pgsql/src/interfaces/libpgtcl/Attic/pgtclCmds.c,v 1.7 1996/11/11 12:14:42 scrappy Exp $
+ *    $Header: /cvsroot/pgsql/src/interfaces/libpgtcl/Attic/pgtclCmds.c,v 1.8 1996/12/19 05:02:49 scrappy Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -24,6 +24,8 @@
 #include "pgtclCmds.h"
 #include "pgtclId.h"
 
+static Tcl_HashTable notifyTable = { NULL };
+
 #ifdef TCL_ARRAYS
 #define ISOCTAL(c)     (((c) >= '0') && ((c) <= '7'))
 #define DIGIT(c)       ((c) - '0')
@@ -1210,3 +1212,155 @@ Pg_select(ClientData cData, Tcl_Interp *interp, int argc, char **argv)
        return TCL_OK;
 }
 
+int
+Pg_listen(ClientData cData, Tcl_Interp *interp, int argc, char* argv[])
+{
+    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;
+    }
+
+    /*
+     * Initialize the notify hash table if not already done.
+     */
+    if (notifyTable.buckets == NULL) {
+       Tcl_InitHashTable(&notifyTable, TCL_STRING_KEYS);
+    }
+
+    /*
+     * Get the command arguments. Note that relname will copied by
+     * Tcl_CreateHashEntry while callback must be allocated.
+     */
+    if (!PgValidId(argv[1])) {
+       Tcl_AppendResult(interp, "not a valid connection\n", 0);
+       return TCL_ERROR;
+    }
+    conn = (PGconn*)PgGetId(argv[1]);
+    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(&notifyTable, 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(&notifyTable, 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;
+}
+
+Pg_notifies(ClientData cData, Tcl_Interp *interp, int argc, char* argv[])
+{
+    int count;
+    char buff[12];
+    char *relname;
+    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;
+    }
+
+    /*
+     * Initialize the notify hash table if not already done.
+     */
+    if (notifyTable.buckets == NULL) {
+       Tcl_InitHashTable(&notifyTable, TCL_STRING_KEYS);
+    }
+
+    /*
+     * Get the connection argument.
+     */
+    if (!PgValidId(argv[1])) {
+       Tcl_AppendResult(interp, "not a valid connection\n", 0);
+       return TCL_ERROR;
+    }
+    conn = (PGconn*)PgGetId(argv[1]);
+
+    /* 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(&notifyTable, 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;
+}
index 4883b926eaaf448cf70318df4b8434bebd515108..78c4e1d770f1f5824dbc1529413e06ecdce66ff7 100644 (file)
@@ -5,7 +5,7 @@
  *
  * Copyright (c) 1994, Regents of the University of California
  *
- * $Id: pgtclCmds.h,v 1.4 1996/11/09 10:39:42 scrappy Exp $
+ * $Id: pgtclCmds.h,v 1.5 1996/12/19 05:02:51 scrappy Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -75,6 +75,10 @@ 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*/