Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 8c8aa53

Browse files
committed
pg_on_connection_loss command for libpgtcl. Patch from
Gerhard Hintermayer, revised and documented by Tom Lane. This patch also fixes a 'must fix' bug: libpgtcl's LISTEN/NOTIFY support was broken by the recent changes to the PGnotify structure. Guess that change wasn't quite so safe as we thought.
1 parent b356b96 commit 8c8aa53

File tree

6 files changed

+310
-35
lines changed

6 files changed

+310
-35
lines changed

doc/src/sgml/libpgtcl.sgml

Lines changed: 104 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,10 @@
7272
<ENTRY><function>pg_listen</function></ENTRY>
7373
<ENTRY>establish a callback for NOTIFY messages</ENTRY>
7474
</ROW>
75+
<ROW>
76+
<ENTRY><function>pg_on_connection_loss</function></ENTRY>
77+
<ENTRY>establish a callback for unexpected connection loss</ENTRY>
78+
</ROW>
7579

7680
<ROW>
7781
<ENTRY><function>pg_lo_creat</function></ENTRY>
@@ -1245,7 +1249,7 @@ pg_listen <REPLACEABLE CLASS="PARAMETER">dbHandle</REPLACEABLE> <REPLACEABLE CLA
12451249
<REPLACEABLE CLASS="PARAMETER">callbackCommand</REPLACEABLE>
12461250
</TERM>
12471251
<LISTITEM>
1248-
<PARA>If present and not empty, provides the command string to execute
1252+
<PARA>If present, provides the command string to execute
12491253
when a matching notification arrives.
12501254
</PARA>
12511255
</LISTITEM>
@@ -1312,6 +1316,105 @@ invoke the SQL NOTIFY statement using <FUNCTION>pg_exec</FUNCTION>.
13121316

13131317
<!-- ********************************************************** -->
13141318

1319+
<REFENTRY ID="PGTCL-PGON_CONNECTION_LOSS">
1320+
<REFMETA>
1321+
<REFENTRYTITLE>pg_on_connection_loss</REFENTRYTITLE>
1322+
<REFMISCINFO>PGTCL - Asynchronous Notify</REFMISCINFO>
1323+
</REFMETA>
1324+
<REFNAMEDIV>
1325+
<REFNAME>pg_on_connection_loss
1326+
</REFNAME>
1327+
<REFPURPOSE>set or change a callback for unexpected connection loss
1328+
</REFPURPOSE>
1329+
<INDEXTERM
1330+
ID="IX-PGTCL-PGON_CONNECTION_LOSS-1"><PRIMARY>pgtcl</PRIMARY><SECONDARY>connection loss</SECONDARY></INDEXTERM>
1331+
<INDEXTERM ID="IX-PGTCL-PGON_CONNECTION_LOSS-2"><PRIMARY>connection loss</PRIMARY></INDEXTERM>
1332+
</REFNAMEDIV>
1333+
<REFSYNOPSISDIV>
1334+
<REFSYNOPSISDIVINFO>
1335+
<DATE>2002-09-02</DATE>
1336+
</REFSYNOPSISDIVINFO>
1337+
<SYNOPSIS>
1338+
pg_on_connection_loss <REPLACEABLE CLASS="PARAMETER">dbHandle</REPLACEABLE> <REPLACEABLE CLASS="PARAMETER">callbackCommand</REPLACEABLE>
1339+
</SYNOPSIS>
1340+
1341+
<REFSECT2 ID="R2-PGTCL-PGON_CONNECTION_LOSS-1">
1342+
<REFSECT2INFO>
1343+
<DATE>2002-09-02</DATE>
1344+
</REFSECT2INFO>
1345+
<TITLE>Inputs
1346+
</TITLE>
1347+
<VARIABLELIST>
1348+
<VARLISTENTRY>
1349+
<TERM>
1350+
<REPLACEABLE CLASS="PARAMETER">dbHandle</REPLACEABLE>
1351+
</TERM>
1352+
<LISTITEM>
1353+
<PARA>Specifies a valid database handle.
1354+
</PARA>
1355+
</LISTITEM>
1356+
</VARLISTENTRY>
1357+
<VARLISTENTRY>
1358+
<TERM>
1359+
<REPLACEABLE CLASS="PARAMETER">callbackCommand</REPLACEABLE>
1360+
</TERM>
1361+
<LISTITEM>
1362+
<PARA>If present, provides the command string to execute
1363+
when connection loss is detected.
1364+
</PARA>
1365+
</LISTITEM>
1366+
</VARLISTENTRY>
1367+
</VARIABLELIST>
1368+
</REFSECT2>
1369+
1370+
<REFSECT2 ID="R2-PGTCL-PGON_CONNECTION_LOSS-2">
1371+
<REFSECT2INFO>
1372+
<DATE>2002-09-02</DATE>
1373+
</REFSECT2INFO>
1374+
<TITLE>Outputs
1375+
</TITLE>
1376+
<VARIABLELIST>
1377+
<VARLISTENTRY>
1378+
<TERM>
1379+
None
1380+
</TERM>
1381+
<LISTITEM>
1382+
<PARA>
1383+
</PARA>
1384+
</LISTITEM>
1385+
</VARLISTENTRY>
1386+
</VARIABLELIST>
1387+
</REFSECT2>
1388+
</REFSYNOPSISDIV>
1389+
1390+
<REFSECT1 ID="R1-PGTCL-PGON_CONNECTION_LOSS-1">
1391+
<REFSECT1INFO>
1392+
<DATE>2002-09-02</DATE>
1393+
</REFSECT1INFO>
1394+
<TITLE>Description
1395+
</TITLE>
1396+
<PARA><FUNCTION>pg_on_connection_loss</FUNCTION> creates, changes, or cancels
1397+
a request to execute a callback command if an unexpected loss of connection
1398+
to the database occurs.
1399+
With a <parameter>callbackCommand</>
1400+
parameter, the request is established, or the command string of an already
1401+
existing request is replaced. With no <parameter>callbackCommand</>
1402+
parameter, a prior request is canceled.
1403+
</PARA>
1404+
1405+
<para>
1406+
The callback command string is executed from the Tcl idle loop. That is the
1407+
normal idle state of an application written with Tk. In non-Tk Tcl shells,
1408+
you can
1409+
execute <FUNCTION>update</FUNCTION> or <FUNCTION>vwait</FUNCTION> to cause
1410+
the idle loop to be entered.
1411+
</Para>
1412+
</REFSECT1>
1413+
1414+
</REFENTRY>
1415+
1416+
<!-- ********************************************************** -->
1417+
13151418
<REFENTRY ID="PGTCL-PGLOCREAT">
13161419
<REFMETA>
13171420
<REFENTRYTITLE>pg_lo_creat</REFENTRYTITLE>

src/interfaces/libpgtcl/pgtcl.c

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
*
1111
*
1212
* IDENTIFICATION
13-
* $Header: /cvsroot/pgsql/src/interfaces/libpgtcl/Attic/pgtcl.c,v 1.25 2002/06/20 20:29:53 momjian Exp $
13+
* $Header: /cvsroot/pgsql/src/interfaces/libpgtcl/Attic/pgtcl.c,v 1.26 2002/09/02 21:51:47 tgl Exp $
1414
*
1515
*-------------------------------------------------------------------------
1616
*/
@@ -151,8 +151,13 @@ Pgtcl_Init(Tcl_Interp *interp)
151151
"pg_listen",
152152
Pg_listen,
153153
(ClientData) NULL, (Tcl_CmdDeleteProc *) NULL);
154+
155+
Tcl_CreateCommand(interp,
156+
"pg_on_connection_loss",
157+
Pg_on_connection_loss,
158+
(ClientData) NULL, (Tcl_CmdDeleteProc *) NULL);
154159

155-
Tcl_PkgProvide(interp, "Pgtcl", "1.3");
160+
Tcl_PkgProvide(interp, "Pgtcl", "1.4");
156161

157162
return TCL_OK;
158163
}

src/interfaces/libpgtcl/pgtclCmds.c

Lines changed: 83 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $Header: /cvsroot/pgsql/src/interfaces/libpgtcl/Attic/pgtclCmds.c,v 1.65 2002/09/02 06:11:43 momjian Exp $
11+
* $Header: /cvsroot/pgsql/src/interfaces/libpgtcl/Attic/pgtclCmds.c,v 1.66 2002/09/02 21:51:47 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -1876,6 +1876,7 @@ Pg_listen(ClientData cData, Tcl_Interp *interp, int argc, char *argv[])
18761876
notifies = (Pg_TclNotifies *) ckalloc(sizeof(Pg_TclNotifies));
18771877
notifies->interp = interp;
18781878
Tcl_InitHashTable(&notifies->notify_hash, TCL_STRING_KEYS);
1879+
notifies->conn_loss_cmd = NULL;
18791880
notifies->next = connid->notify_list;
18801881
connid->notify_list = notifies;
18811882
Tcl_CallWhenDeleted(interp, PgNotifyInterpDelete,
@@ -1970,3 +1971,84 @@ Pg_listen(ClientData cData, Tcl_Interp *interp, int argc, char *argv[])
19701971
ckfree(caserelname);
19711972
return TCL_OK;
19721973
}
1974+
1975+
/***********************************
1976+
Pg_on_connection_loss
1977+
create or remove a callback request for unexpected connection loss
1978+
1979+
syntax:
1980+
pg_on_connection_loss conn ?callbackcommand?
1981+
1982+
With a third arg, creates or changes the callback command for
1983+
connection loss; without, cancels the callback request.
1984+
1985+
Callbacks can occur whenever Tcl is executing its event loop.
1986+
This is the normal idle loop in Tk; in plain tclsh applications,
1987+
vwait or update can be used to enter the Tcl event loop.
1988+
***********************************/
1989+
int
1990+
Pg_on_connection_loss(ClientData cData, Tcl_Interp *interp, int argc, char *argv[])
1991+
{
1992+
char *callback = NULL;
1993+
Pg_TclNotifies *notifies;
1994+
Pg_ConnectionId *connid;
1995+
PGconn *conn;
1996+
1997+
if (argc < 2 || argc > 3)
1998+
{
1999+
Tcl_AppendResult(interp, "wrong # args, should be \"",
2000+
argv[0], " connection ?callback?\"", 0);
2001+
return TCL_ERROR;
2002+
}
2003+
2004+
/*
2005+
* Get the command arguments.
2006+
*/
2007+
conn = PgGetConnectionId(interp, argv[1], &connid);
2008+
if (conn == (PGconn *) NULL)
2009+
return TCL_ERROR;
2010+
2011+
if ((argc > 2) && *argv[2])
2012+
{
2013+
callback = (char *) ckalloc((unsigned) (strlen(argv[2]) + 1));
2014+
strcpy(callback, argv[2]);
2015+
}
2016+
2017+
/* Find or make a Pg_TclNotifies struct for this interp and connection */
2018+
2019+
for (notifies = connid->notify_list; notifies; notifies = notifies->next)
2020+
{
2021+
if (notifies->interp == interp)
2022+
break;
2023+
}
2024+
if (notifies == NULL)
2025+
{
2026+
notifies = (Pg_TclNotifies *) ckalloc(sizeof(Pg_TclNotifies));
2027+
notifies->interp = interp;
2028+
Tcl_InitHashTable(&notifies->notify_hash, TCL_STRING_KEYS);
2029+
notifies->conn_loss_cmd = NULL;
2030+
notifies->next = connid->notify_list;
2031+
connid->notify_list = notifies;
2032+
Tcl_CallWhenDeleted(interp, PgNotifyInterpDelete,
2033+
(ClientData) notifies);
2034+
}
2035+
2036+
/* Store new callback setting */
2037+
2038+
if (notifies->conn_loss_cmd)
2039+
ckfree((void *) notifies->conn_loss_cmd);
2040+
notifies->conn_loss_cmd = callback;
2041+
2042+
if (callback)
2043+
{
2044+
/*
2045+
* Start the notify event source if it isn't already running.
2046+
* The notify source will cause Tcl to watch read-ready on the
2047+
* connection socket, so that we find out quickly if the connection
2048+
* drops.
2049+
*/
2050+
PgStartNotifyEventSource(connid);
2051+
}
2052+
2053+
return TCL_OK;
2054+
}

src/interfaces/libpgtcl/pgtclCmds.h

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
77
* Portions Copyright (c) 1994, Regents of the University of California
88
*
9-
* $Id: pgtclCmds.h,v 1.26 2002/06/20 20:29:53 momjian Exp $
9+
* $Id: pgtclCmds.h,v 1.27 2002/09/02 21:51:47 tgl Exp $
1010
*
1111
*-------------------------------------------------------------------------
1212
*/
@@ -21,7 +21,7 @@
2121
#define RES_START 16
2222

2323
/*
24-
* From Tcl verion 8.0 on we can make large object access binary.
24+
* From Tcl version 8.0 on we can make large object access binary.
2525
*/
2626
#ifdef TCL_MAJOR_VERSION
2727
#if (TCL_MAJOR_VERSION >= 8)
@@ -36,6 +36,9 @@
3636
* deleted while the connection remains open. A free side benefit is that
3737
* multiple interpreters can be registered to listen for the same notify
3838
* name. (All their callbacks will be called, but in an unspecified order.)
39+
*
40+
* We use the same approach for pg_on_connection_loss callbacks, but they
41+
* are not kept in a hashtable since there's no name associated.
3942
*/
4043

4144
typedef struct Pg_TclNotifies_s
@@ -48,6 +51,8 @@ typedef struct Pg_TclNotifies_s
4851
* got round to deleting the Pg_TclNotifies structure.
4952
*/
5053
Tcl_HashTable notify_hash; /* Active pg_listen requests */
54+
55+
char *conn_loss_cmd; /* pg_on_connection_loss cmd, or NULL */
5156
} Pg_TclNotifies;
5257

5358
typedef struct Pg_ConnectionId_s
@@ -128,5 +133,7 @@ extern int Pg_lo_export(
128133
ClientData cData, Tcl_Interp *interp, int argc, char *argv[]);
129134
extern int Pg_listen(
130135
ClientData cData, Tcl_Interp *interp, int argc, char *argv[]);
136+
extern int Pg_on_connection_loss(
137+
ClientData cData, Tcl_Interp *interp, int argc, char *argv[]);
131138

132139
#endif /* PGTCLCMDS_H */

0 commit comments

Comments
 (0)