From 56e8243d223cec721e9a4dd2288f9d9af7cd48c2 Mon Sep 17 00:00:00 2001 From: "Marc G. Fournier" Date: Thu, 19 Dec 1996 05:02:51 +0000 Subject: [PATCH] Add two new comments to pglibtcl... From: Massimo Dal Zotto --- src/interfaces/libpgtcl/pgtcl.c | 12 ++- src/interfaces/libpgtcl/pgtclCmds.c | 156 +++++++++++++++++++++++++++- src/interfaces/libpgtcl/pgtclCmds.h | 6 +- 3 files changed, 171 insertions(+), 3 deletions(-) diff --git a/src/interfaces/libpgtcl/pgtcl.c b/src/interfaces/libpgtcl/pgtcl.c index 2cbec47395..cc77d7e685 100644 --- a/src/interfaces/libpgtcl/pgtcl.c +++ b/src/interfaces/libpgtcl/pgtcl.c @@ -9,7 +9,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/interfaces/libpgtcl/Attic/pgtcl.c,v 1.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; diff --git a/src/interfaces/libpgtcl/pgtclCmds.c b/src/interfaces/libpgtcl/pgtclCmds.c index 980055e378..65839b18b2 100644 --- a/src/interfaces/libpgtcl/pgtclCmds.c +++ b/src/interfaces/libpgtcl/pgtclCmds.c @@ -7,7 +7,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/interfaces/libpgtcl/Attic/pgtclCmds.c,v 1.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(¬ifyTable, 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(¬ifyTable, 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(¬ifyTable, 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(¬ifyTable, 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(¬ifyTable, 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; +} diff --git a/src/interfaces/libpgtcl/pgtclCmds.h b/src/interfaces/libpgtcl/pgtclCmds.h index 4883b926ea..78c4e1d770 100644 --- a/src/interfaces/libpgtcl/pgtclCmds.h +++ b/src/interfaces/libpgtcl/pgtclCmds.h @@ -5,7 +5,7 @@ * * Copyright (c) 1994, Regents of the University of California * - * $Id: pgtclCmds.h,v 1.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*/ -- 2.40.0