|
7 | 7 | *
|
8 | 8 | *
|
9 | 9 | * IDENTIFICATION
|
10 |
| - * $Header: /cvsroot/pgsql/src/interfaces/libpgtcl/Attic/pgtclCmds.c,v 1.7 1996/11/11 12:14:42 scrappy Exp $ |
| 10 | + * $Header: /cvsroot/pgsql/src/interfaces/libpgtcl/Attic/pgtclCmds.c,v 1.8 1996/12/19 05:02:49 scrappy Exp $ |
11 | 11 | *
|
12 | 12 | *-------------------------------------------------------------------------
|
13 | 13 | */
|
|
24 | 24 | #include"pgtclCmds.h"
|
25 | 25 | #include"pgtclId.h"
|
26 | 26 |
|
| 27 | +staticTcl_HashTablenotifyTable= {NULL }; |
| 28 | + |
27 | 29 | #ifdefTCL_ARRAYS
|
28 | 30 | #defineISOCTAL(c)(((c) >= '0') && ((c) <= '7'))
|
29 | 31 | #defineDIGIT(c)((c) - '0')
|
@@ -1210,3 +1212,155 @@ Pg_select(ClientData cData, Tcl_Interp *interp, int argc, char **argv)
|
1210 | 1212 | returnTCL_OK;
|
1211 | 1213 | }
|
1212 | 1214 |
|
| 1215 | +int |
| 1216 | +Pg_listen(ClientDatacData,Tcl_Interp*interp,intargc,char*argv[]) |
| 1217 | +{ |
| 1218 | +intnew; |
| 1219 | +char*relname; |
| 1220 | +char*callback=NULL; |
| 1221 | +Tcl_HashEntry*entry; |
| 1222 | +PGconn*conn; |
| 1223 | +PGresult*result; |
| 1224 | + |
| 1225 | +if ((argc<3)|| (argc>4)) { |
| 1226 | +Tcl_AppendResult(interp,"wrong # args, should be \"", |
| 1227 | +argv[0]," connection relname ?callback?\"",0); |
| 1228 | +returnTCL_ERROR; |
| 1229 | + } |
| 1230 | + |
| 1231 | +/* |
| 1232 | + * Initialize the notify hash table if not already done. |
| 1233 | + */ |
| 1234 | +if (notifyTable.buckets==NULL) { |
| 1235 | +Tcl_InitHashTable(¬ifyTable,TCL_STRING_KEYS); |
| 1236 | + } |
| 1237 | + |
| 1238 | +/* |
| 1239 | + * Get the command arguments. Note that relname will copied by |
| 1240 | + * Tcl_CreateHashEntry while callback must be allocated. |
| 1241 | + */ |
| 1242 | +if (!PgValidId(argv[1])) { |
| 1243 | +Tcl_AppendResult(interp,"not a valid connection\n",0); |
| 1244 | +returnTCL_ERROR; |
| 1245 | + } |
| 1246 | +conn= (PGconn*)PgGetId(argv[1]); |
| 1247 | +relname=argv[2]; |
| 1248 | +if ((argc>3)&&*argv[3]) { |
| 1249 | +callback= (char*)ckalloc((unsigned) (strlen(argv[3])+1)); |
| 1250 | +strcpy(callback,argv[3]); |
| 1251 | + } |
| 1252 | + |
| 1253 | +/* |
| 1254 | + * Set or update a callback for a relation; |
| 1255 | + */ |
| 1256 | +if (callback) { |
| 1257 | +entry=Tcl_CreateHashEntry(¬ifyTable,relname,&new); |
| 1258 | +if (new) { |
| 1259 | +/* New callback, execute a listen command on the relation */ |
| 1260 | +char*cmd= (char*)ckalloc((unsigned) (strlen(argv[2])+8)); |
| 1261 | +sprintf(cmd,"LISTEN %s",relname); |
| 1262 | +result=PQexec(conn,cmd); |
| 1263 | +ckfree(cmd); |
| 1264 | +if (!result|| (result->resultStatus!=PGRES_COMMAND_OK)) { |
| 1265 | +/* Error occurred during the execution of command */ |
| 1266 | +if (result)PQclear(result); |
| 1267 | +ckfree(callback); |
| 1268 | +Tcl_DeleteHashEntry(entry); |
| 1269 | +Tcl_SetResult(interp,conn->errorMessage,TCL_STATIC); |
| 1270 | +returnTCL_ERROR; |
| 1271 | + } |
| 1272 | +PQclear(result); |
| 1273 | +}else { |
| 1274 | +/* Free the old callback string */ |
| 1275 | +ckfree((char*)Tcl_GetHashValue(entry)); |
| 1276 | +} |
| 1277 | +/* Store the new callback command */ |
| 1278 | +Tcl_SetHashValue(entry,callback); |
| 1279 | + } |
| 1280 | + |
| 1281 | +/* |
| 1282 | + * Remove a callback for a relation. There is no way to |
| 1283 | + * un-listen a relation, simply remove the callback from |
| 1284 | + * the notify hash table. |
| 1285 | + */ |
| 1286 | +if (callback==NULL) { |
| 1287 | +entry=Tcl_FindHashEntry(¬ifyTable,relname); |
| 1288 | +if (entry==NULL) { |
| 1289 | +Tcl_AppendResult(interp,"not listening on ",relname,0); |
| 1290 | +returnTCL_ERROR; |
| 1291 | +} |
| 1292 | +ckfree((char*)Tcl_GetHashValue(entry)); |
| 1293 | +Tcl_DeleteHashEntry(entry); |
| 1294 | + } |
| 1295 | + |
| 1296 | +returnTCL_OK; |
| 1297 | +} |
| 1298 | + |
| 1299 | +Pg_notifies(ClientDatacData,Tcl_Interp*interp,intargc,char*argv[]) |
| 1300 | +{ |
| 1301 | +intcount; |
| 1302 | +charbuff[12]; |
| 1303 | +char*relname; |
| 1304 | +char*callback; |
| 1305 | +Tcl_HashEntry*entry; |
| 1306 | +PGconn*conn; |
| 1307 | +PGresult*result; |
| 1308 | +PGnotify*notify; |
| 1309 | + |
| 1310 | +if (argc!=2) { |
| 1311 | +Tcl_AppendResult(interp,"wrong # args, should be \"", |
| 1312 | +argv[0]," connection\"",0); |
| 1313 | +returnTCL_ERROR; |
| 1314 | + } |
| 1315 | + |
| 1316 | +/* |
| 1317 | + * Initialize the notify hash table if not already done. |
| 1318 | + */ |
| 1319 | +if (notifyTable.buckets==NULL) { |
| 1320 | +Tcl_InitHashTable(¬ifyTable,TCL_STRING_KEYS); |
| 1321 | + } |
| 1322 | + |
| 1323 | +/* |
| 1324 | + * Get the connection argument. |
| 1325 | + */ |
| 1326 | +if (!PgValidId(argv[1])) { |
| 1327 | +Tcl_AppendResult(interp,"not a valid connection\n",0); |
| 1328 | +returnTCL_ERROR; |
| 1329 | + } |
| 1330 | +conn= (PGconn*)PgGetId(argv[1]); |
| 1331 | + |
| 1332 | +/* Execute an empty command to retrieve asynchronous notifications */ |
| 1333 | +result=PQexec(conn," "); |
| 1334 | +if (result==NULL) { |
| 1335 | +/* Error occurred during the execution of command */ |
| 1336 | +Tcl_SetResult(interp,conn->errorMessage,TCL_STATIC); |
| 1337 | +returnTCL_ERROR; |
| 1338 | + } |
| 1339 | +PQclear(result); |
| 1340 | + |
| 1341 | +/* |
| 1342 | + * Loop while there are pending notifies. |
| 1343 | + */ |
| 1344 | +for (count=0;count<999;count++) { |
| 1345 | +/* See if there is a pending notification */ |
| 1346 | +notify=PQnotifies(conn); |
| 1347 | +if (notify==NULL) { |
| 1348 | +break; |
| 1349 | +} |
| 1350 | +entry=Tcl_FindHashEntry(¬ifyTable,notify->relname); |
| 1351 | +if (entry!=NULL) { |
| 1352 | +callback=Tcl_GetHashValue(entry); |
| 1353 | +if (callback) { |
| 1354 | +Tcl_Eval(interp,callback); |
| 1355 | + } |
| 1356 | +} |
| 1357 | +free(notify); |
| 1358 | + } |
| 1359 | + |
| 1360 | +/* |
| 1361 | + * Return the number of notifications processed. |
| 1362 | + */ |
| 1363 | +sprintf(buff,"%d",count); |
| 1364 | +Tcl_SetResult(interp,buff,TCL_VOLATILE); |
| 1365 | +returnTCL_OK; |
| 1366 | +} |