diff options
Diffstat (limited to 'src/interfaces/libpgtcl/pgtclId.c')
-rw-r--r-- | src/interfaces/libpgtcl/pgtclId.c | 862 |
1 files changed, 0 insertions, 862 deletions
diff --git a/src/interfaces/libpgtcl/pgtclId.c b/src/interfaces/libpgtcl/pgtclId.c deleted file mode 100644 index 1cdd85b975b..00000000000 --- a/src/interfaces/libpgtcl/pgtclId.c +++ /dev/null @@ -1,862 +0,0 @@ -/*------------------------------------------------------------------------- - * - * pgtclId.c - * - * Contains Tcl "channel" interface routines, plus useful routines - * to convert between strings and pointers. These are needed because - * everything in Tcl is a string, but in C, pointers to data structures - * are needed. - * - * ASSUMPTION: sizeof(long) >= sizeof(void*) - * - * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group - * Portions Copyright (c) 1994, Regents of the University of California - * - * IDENTIFICATION - * $PostgreSQL: pgsql/src/interfaces/libpgtcl/pgtclId.c,v 1.45 2004/01/07 18:56:29 neilc Exp $ - * - *------------------------------------------------------------------------- - */ -#include "postgres_fe.h" - -#include <errno.h> - -#include "pgtclCmds.h" -#include "pgtclId.h" - - -static int -PgEndCopy(Pg_ConnectionId * connid, int *errorCodePtr) -{ - connid->res_copyStatus = RES_COPY_NONE; - if (PQendcopy(connid->conn)) - { - PQclear(connid->results[connid->res_copy]); - connid->results[connid->res_copy] = - PQmakeEmptyPGresult(connid->conn, PGRES_BAD_RESPONSE); - connid->res_copy = -1; - *errorCodePtr = EIO; - return -1; - } - else - { - PQclear(connid->results[connid->res_copy]); - connid->results[connid->res_copy] = - PQmakeEmptyPGresult(connid->conn, 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 avail; - - connid = (Pg_ConnectionId *) cData; - conn = connid->conn; - - if (connid->res_copy < 0 || - PQresultStatus(connid->results[connid->res_copy]) != PGRES_COPY_OUT) - { - *errorCodePtr = EBUSY; - return -1; - } - - /* - * Read any newly arrived data into libpq's buffer, thereby clearing - * the socket's read-ready condition. - */ - if (!PQconsumeInput(conn)) - { - *errorCodePtr = EIO; - return -1; - } - - /* Move data from libpq's buffer to Tcl's. */ - - avail = PQgetlineAsync(conn, buf, bufSize); - - if (avail < 0) - { - /* Endmarker detected, change state and return 0 */ - return PgEndCopy(connid, errorCodePtr); - } - - return 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 || - PQresultStatus(connid->results[connid->res_copy]) != PGRES_COPY_IN) - { - *errorCodePtr = EBUSY; - return -1; - } - - if (PQputnbytes(conn, buf, bufSize)) - { - *errorCodePtr = EIO; - return -1; - } - - /* - * This assumes Tcl script will write the terminator line in a single - * operation; maybe not such a good assumption? - */ - if (bufSize >= 3 && strncmp(&buf[bufSize - 3], "\\.\n", 3) == 0) - { - if (PgEndCopy(connid, errorCodePtr) == -1) - return -1; - } - return bufSize; -} - -#if HAVE_TCL_GETFILEPROC - -Tcl_File -PgGetFileProc(ClientData cData, int direction) -{ - return NULL; -} -#endif - -/* - * The WatchProc and GetHandleProc are no-ops but must be present. - */ -static void -PgWatchProc(ClientData instanceData, int mask) -{ -} - -static int -PgGetHandleProc(ClientData instanceData, int direction, - ClientData *handlePtr) -{ - return TCL_ERROR; -} - -Tcl_ChannelType Pg_ConnType = { - "pgsql", /* channel type */ - NULL, /* blockmodeproc */ - PgDelConnectionId, /* closeproc */ - PgInputProc, /* inputproc */ - PgOutputProc, /* outputproc */ - NULL, /* SeekProc, Not used */ - NULL, /* SetOptionProc, Not used */ - NULL, /* GetOptionProc, Not used */ - PgWatchProc, /* WatchProc, must be defined */ - PgGetHandleProc, /* GetHandleProc, must be defined */ - NULL /* Close2Proc, Not used */ -}; - -/* - * Create and register a new channel for the connection - */ -void -PgSetConnectionId(Tcl_Interp *interp, PGconn *conn) -{ - 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; - connid->notify_list = NULL; - connid->notifier_running = 0; - - sprintf(connid->id, "pgsql%d", PQsocket(conn)); - -#if TCL_MAJOR_VERSION >= 8 - connid->notifier_channel = Tcl_MakeTcpClientChannel((ClientData) PQsocket(conn)); - Tcl_RegisterChannel(NULL, connid->notifier_channel); -#else - connid->notifier_socket = -1; -#endif - -#if TCL_MAJOR_VERSION == 7 && TCL_MINOR_VERSION == 5 - /* Original signature (only seen in Tcl 7.5) */ - conn_chan = Tcl_CreateChannel(&Pg_ConnType, connid->id, NULL, NULL, (ClientData) connid); -#else - /* Tcl 7.6 and later use this */ - 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); -} - - -/* - * Get back the connection from the Id - */ -PGconn * -PgGetConnectionId(Tcl_Interp *interp, CONST84 char *id, - Pg_ConnectionId ** connid_p) -{ - 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", 0); - if (connid_p) - *connid_p = NULL; - return NULL; - } - - connid = (Pg_ConnectionId *) Tcl_GetChannelInstanceData(conn_chan); - if (connid_p) - *connid_p = connid; - return connid->conn; -} - - -/* - * Remove a connection Id from the hash table and - * close all portals the user forgot. - */ -int -PgDelConnectionId(DRIVER_DEL_PROTO) -{ - Tcl_HashEntry *entry; - Tcl_HashSearch hsearch; - Pg_ConnectionId *connid; - Pg_TclNotifies *notifies; - 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); - - /* Release associated notify info */ - while ((notifies = connid->notify_list) != NULL) - { - connid->notify_list = notifies->next; - for (entry = Tcl_FirstHashEntry(¬ifies->notify_hash, &hsearch); - entry != NULL; - entry = Tcl_NextHashEntry(&hsearch)) - ckfree((char *) Tcl_GetHashValue(entry)); - Tcl_DeleteHashTable(¬ifies->notify_hash); - if (notifies->conn_loss_cmd) - ckfree((void *) notifies->conn_loss_cmd); - if (notifies->interp) - Tcl_DontCallWhenDeleted(notifies->interp, PgNotifyInterpDelete, - (ClientData) notifies); - ckfree((void *) notifies); - } - - /* - * Turn off the Tcl event source for this connection, and delete any - * pending notify and connection-loss events. - */ - PgStopNotifyEventSource(connid, true); - - /* Close the libpq connection too */ - PQfinish(connid->conn); - connid->conn = NULL; - - /* - * Kill the notifier channel, too. We must not do this until after - * we've closed the libpq connection, because Tcl will try to close - * the socket itself! - * - * XXX Unfortunately, while this works fine if we are closing due to - * explicit pg_disconnect, all Tcl versions through 8.4.1 dump core if - * we try to do it during interpreter shutdown. Not clear why. For - * now, we kill the channel during pg_disconnect, but during interp - * shutdown we just accept leakage of the (fairly small) amount of - * memory taken for the channel state representation. (Note we are not - * leaking a socket, since libpq closed that already.) We tell the - * difference between pg_disconnect and interpreter shutdown by - * testing for interp != NULL, which is an undocumented but apparently - * safe way to tell. - */ -#if TCL_MAJOR_VERSION >= 8 - if (connid->notifier_channel != NULL && interp != NULL) - Tcl_UnregisterChannel(NULL, connid->notifier_channel); -#endif - - /* - * We must use Tcl_EventuallyFree because we don't want the connid - * struct to vanish instantly if Pg_Notify_EventProc is active for it. - * (Otherwise, closing the connection from inside a pg_listen callback - * could lead to coredump.) Pg_Notify_EventProc can detect that the - * connection has been deleted from under it by checking connid->conn. - */ - Tcl_EventuallyFree((ClientData) connid, TCL_DYNAMIC); - - return 0; -} - - -/* - * 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. - */ -int -PgSetResultId(Tcl_Interp *interp, CONST84 char *connid_c, PGresult *res) -{ - Tcl_Channel conn_chan; - Pg_ConnectionId *connid; - int resid, - i; - char buf[32]; - - - conn_chan = Tcl_GetChannel(interp, connid_c, 0); - if (conn_chan == NULL) - return TCL_ERROR; - connid = (Pg_ConnectionId *) Tcl_GetChannelInstanceData(conn_chan); - - /* search, starting at slot after the last one used */ - resid = connid->res_last; - for (;;) - { - /* advance, with wraparound */ - if (++resid >= connid->res_max) - resid = 0; - /* this slot empty? */ - if (!connid->results[resid]) - { - connid->res_last = resid; - break; /* success exit */ - } - /* checked all slots? */ - if (resid == connid->res_last) - break; /* failure exit */ - } - - if (connid->results[resid]) - { - /* no free slot found, so try to enlarge array */ - if (connid->res_max >= connid->res_hardmax) - { - Tcl_SetResult(interp, "hard limit on result handles reached", - TCL_STATIC); - return TCL_ERROR; - } - connid->res_last = 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, CONST84 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(Tcl_Interp *interp, CONST84 char *id) -{ - Pg_ConnectionId *connid; - int resid; - - if (!id) - return NULL; - resid = getresid(interp, id, &connid); - if (resid == -1) - return NULL; - return connid->results[resid]; -} - - -/* - * Remove a result Id from the hash tables - */ -void -PgDelResultId(Tcl_Interp *interp, CONST84 char *id) -{ - Pg_ConnectionId *connid; - int resid; - - resid = getresid(interp, id, &connid); - if (resid == -1) - return; - connid->results[resid] = 0; -} - - -/* - * Get the connection Id from the result Id - */ -int -PgGetConnByResultId(Tcl_Interp *interp, CONST84 char *resid_c) -{ - 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, (char *) 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; -} - - - - -/*------------------------------------------- - Notify event source - - These functions allow asynchronous notify messages arriving from - the SQL server to be dispatched as Tcl events. See the Tcl - Notifier(3) man page for more info. - - The main trick in this code is that we have to cope with status changes - between the queueing and the execution of a Tcl event. For example, - if the user changes or cancels the pg_listen callback command, we should - use the new setting; we do that by not resolving the notify relation - name until the last possible moment. - We also have to handle closure of the channel or deletion of the interpreter - to be used for the callback (note that with multiple interpreters, - the channel can outlive the interpreter it was created by!) - Upon closure of the channel, we immediately delete the file event handler - for it, which has the effect of disabling any file-ready events that might - be hanging about in the Tcl event queue. But for interpreter deletion, - we just set any matching interp pointers in the Pg_TclNotifies list to NULL. - The list item stays around until the connection is deleted. (This avoids - trouble with walking through a list whose members may get deleted under us.) - - Another headache is that Ousterhout keeps changing the Tcl I/O interfaces. - libpgtcl currently claims to work with Tcl 7.5, 7.6, and 8.0, and each of - 'em is different. Worse, the Tcl_File type went away in 8.0, which means - there is no longer any platform-independent way of waiting for file ready. - So we now have to use a Unix-specific interface. Grumble. - - In the current design, Pg_Notify_FileHandler is a file handler that - we establish by calling Tcl_CreateFileHandler(). It gets invoked from - the Tcl event loop whenever the underlying PGconn's socket is read-ready. - We suck up any available data (to clear the OS-level read-ready condition) - and then transfer any available PGnotify events into the Tcl event queue. - Eventually these events will be dispatched to Pg_Notify_EventProc. When - we do an ordinary PQexec, we must also transfer PGnotify events into Tcl's - event queue, since libpq might have read them when we weren't looking. - ------------------------------------------*/ - -typedef struct -{ - Tcl_Event header; /* Standard Tcl event info */ - PGnotify *notify; /* Notify event from libpq, or NULL */ - /* We use a NULL notify pointer to denote a connection-loss event */ - Pg_ConnectionId *connid; /* Connection for server */ -} NotifyEvent; - -/* Dispatch a NotifyEvent that has reached the front of the event queue */ - -static int -Pg_Notify_EventProc(Tcl_Event *evPtr, int flags) -{ - NotifyEvent *event = (NotifyEvent *) evPtr; - Pg_TclNotifies *notifies; - char *callback; - char *svcallback; - - /* We classify SQL notifies as Tcl file events. */ - if (!(flags & TCL_FILE_EVENTS)) - return 0; - - /* If connection's been closed, just forget the whole thing. */ - if (event->connid == NULL) - { - if (event->notify) - PQfreemem(event->notify); - return 1; - } - - /* - * Preserve/Release to ensure the connection struct doesn't disappear - * underneath us. - */ - Tcl_Preserve((ClientData) event->connid); - - /* - * Loop for each interpreter that has ever registered on the - * connection. Each one can get a callback. - */ - - for (notifies = event->connid->notify_list; - notifies != NULL; - notifies = notifies->next) - { - Tcl_Interp *interp = notifies->interp; - - if (interp == NULL) - continue; /* ignore deleted interpreter */ - - /* - * Find the callback to be executed for this interpreter, if any. - */ - if (event->notify) - { - /* Ordinary NOTIFY event */ - Tcl_HashEntry *entry; - - entry = Tcl_FindHashEntry(¬ifies->notify_hash, - event->notify->relname); - if (entry == NULL) - continue; /* no pg_listen in this interpreter */ - callback = (char *) Tcl_GetHashValue(entry); - } - else - { - /* Connection-loss event */ - callback = notifies->conn_loss_cmd; - } - - if (callback == NULL) - continue; /* nothing to do for this interpreter */ - - /* - * We have to copy the callback string in case the user executes a - * new pg_listen or pg_on_connection_loss during the callback. - */ - svcallback = (char *) ckalloc((unsigned) (strlen(callback) + 1)); - strcpy(svcallback, callback); - - /* - * Execute the callback. - */ - Tcl_Preserve((ClientData) interp); - if (Tcl_GlobalEval(interp, svcallback) != TCL_OK) - { - if (event->notify) - Tcl_AddErrorInfo(interp, "\n (\"pg_listen\" script)"); - else - Tcl_AddErrorInfo(interp, "\n (\"pg_on_connection_loss\" script)"); - Tcl_BackgroundError(interp); - } - Tcl_Release((ClientData) interp); - ckfree(svcallback); - - /* - * Check for the possibility that the callback closed the - * connection. - */ - if (event->connid->conn == NULL) - break; - } - - Tcl_Release((ClientData) event->connid); - - if (event->notify) - PQfreemem(event->notify); - - return 1; -} - -/* - * Transfer any notify events available from libpq into the Tcl event queue. - * Note that this must be called after each PQexec (to capture notifies - * that arrive during command execution) as well as in Pg_Notify_FileHandler - * (to capture notifies that arrive when we're idle). - */ - -void -PgNotifyTransferEvents(Pg_ConnectionId * connid) -{ - PGnotify *notify; - - while ((notify = PQnotifies(connid->conn)) != NULL) - { - NotifyEvent *event = (NotifyEvent *) ckalloc(sizeof(NotifyEvent)); - - event->header.proc = Pg_Notify_EventProc; - event->notify = notify; - event->connid = connid; - Tcl_QueueEvent((Tcl_Event *) event, TCL_QUEUE_TAIL); - } - - /* - * This is also a good place to check for unexpected closure of the - * connection (ie, backend crash), in which case we must shut down the - * notify event source to keep Tcl from trying to select() on the now- - * closed socket descriptor. But don't kill on-connection-loss - * events; in fact, register one. - */ - if (PQsocket(connid->conn) < 0) - PgConnLossTransferEvents(connid); -} - -/* - * Handle a connection-loss event - */ -void -PgConnLossTransferEvents(Pg_ConnectionId * connid) -{ - if (connid->notifier_running) - { - /* Put the on-connection-loss event in the Tcl queue */ - NotifyEvent *event = (NotifyEvent *) ckalloc(sizeof(NotifyEvent)); - - event->header.proc = Pg_Notify_EventProc; - event->notify = NULL; - event->connid = connid; - Tcl_QueueEvent((Tcl_Event *) event, TCL_QUEUE_TAIL); - } - - /* - * Shut down the notify event source to keep Tcl from trying to - * select() on the now-closed socket descriptor. And zap any - * unprocessed notify events ... but not, of course, the - * connection-loss event. - */ - PgStopNotifyEventSource(connid, false); -} - -/* - * Cleanup code for coping when an interpreter or a channel is deleted. - * - * PgNotifyInterpDelete is registered as an interpreter deletion callback - * for each extant Pg_TclNotifies structure. - * NotifyEventDeleteProc is used by PgStopNotifyEventSource to cancel - * pending Tcl NotifyEvents that reference a dying connection. - */ - -void -PgNotifyInterpDelete(ClientData clientData, Tcl_Interp *interp) -{ - /* Mark the interpreter dead, but don't do anything else yet */ - Pg_TclNotifies *notifies = (Pg_TclNotifies *) clientData; - - notifies->interp = NULL; -} - -/* - * Comparison routines for detecting events to be removed by Tcl_DeleteEvents. - * NB: In (at least) Tcl versions 7.6 through 8.0.3, there is a serious - * bug in Tcl_DeleteEvents: if there are multiple events on the queue and - * you tell it to delete the last one, the event list pointers get corrupted, - * with the result that events queued immediately thereafter get lost. - * Therefore we daren't tell Tcl_DeleteEvents to actually delete anything! - * We simply use it as a way of scanning the event queue. Events matching - * the about-to-be-deleted connid are marked dead by setting their connid - * fields to NULL. Then Pg_Notify_EventProc will do nothing when those - * events are executed. - */ -static int -NotifyEventDeleteProc(Tcl_Event *evPtr, ClientData clientData) -{ - Pg_ConnectionId *connid = (Pg_ConnectionId *) clientData; - - if (evPtr->proc == Pg_Notify_EventProc) - { - NotifyEvent *event = (NotifyEvent *) evPtr; - - if (event->connid == connid && event->notify != NULL) - event->connid = NULL; - } - return 0; -} - -/* This version deletes on-connection-loss events too */ -static int -AllNotifyEventDeleteProc(Tcl_Event *evPtr, ClientData clientData) -{ - Pg_ConnectionId *connid = (Pg_ConnectionId *) clientData; - - if (evPtr->proc == Pg_Notify_EventProc) - { - NotifyEvent *event = (NotifyEvent *) evPtr; - - if (event->connid == connid) - event->connid = NULL; - } - return 0; -} - -/* - * File handler callback: called when Tcl has detected read-ready on socket. - * The clientData is a pointer to the associated connection. - * We can ignore the condition mask since we only ever ask about read-ready. - */ - -static void -Pg_Notify_FileHandler(ClientData clientData, int mask) -{ - Pg_ConnectionId *connid = (Pg_ConnectionId *) clientData; - - /* - * Consume any data available from the SQL server (this just buffers - * it internally to libpq; but it will clear the read-ready - * condition). - */ - if (PQconsumeInput(connid->conn)) - { - /* Transfer notify events from libpq to Tcl event queue. */ - PgNotifyTransferEvents(connid); - } - else - { - /* - * If there is no input but we have read-ready, assume this means - * we lost the connection. - */ - PgConnLossTransferEvents(connid); - } -} - - -/* - * Start and stop the notify event source for a connection. - * - * We do not bother to run the notifier unless at least one pg_listen - * or pg_on_connection_loss has been executed on the connection. Currently, - * once started the notifier is run until the connection is closed. - * - * FIXME: if PQreset is executed on the underlying PGconn, the active - * socket number could change. How and when should we test for this - * and update the Tcl file handler linkage? (For that matter, we'd - * also have to reissue LISTEN commands for active LISTENs, since the - * new backend won't know about 'em. I'm leaving this problem for - * another day.) - */ - -void -PgStartNotifyEventSource(Pg_ConnectionId * connid) -{ - /* Start the notify event source if it isn't already running */ - if (!connid->notifier_running) - { - int pqsock = PQsocket(connid->conn); - - if (pqsock >= 0) - { -#if TCL_MAJOR_VERSION >= 8 - Tcl_CreateChannelHandler(connid->notifier_channel, - TCL_READABLE, - Pg_Notify_FileHandler, - (ClientData) connid); -#else - /* In Tcl 7.5 and 7.6, we need to gin up a Tcl_File. */ - Tcl_File tclfile = Tcl_GetFile((ClientData) pqsock, TCL_UNIX_FD); - - Tcl_CreateFileHandler(tclfile, TCL_READABLE, - Pg_Notify_FileHandler, (ClientData) connid); - connid->notifier_socket = pqsock; -#endif - connid->notifier_running = 1; - } - } -} - -void -PgStopNotifyEventSource(Pg_ConnectionId * connid, bool allevents) -{ - /* Remove the event source */ - if (connid->notifier_running) - { -#if TCL_MAJOR_VERSION >= 8 - Tcl_DeleteChannelHandler(connid->notifier_channel, - Pg_Notify_FileHandler, - (ClientData) connid); -#else - /* In Tcl 7.5 and 7.6, we need to gin up a Tcl_File. */ - Tcl_File tclfile = Tcl_GetFile((ClientData) connid->notifier_socket, - TCL_UNIX_FD); - - Tcl_DeleteFileHandler(tclfile); -#endif - connid->notifier_running = 0; - } - - /* Kill queued Tcl events that reference this channel */ - if (allevents) - Tcl_DeleteEvents(AllNotifyEventDeleteProc, (ClientData) connid); - else - Tcl_DeleteEvents(NotifyEventDeleteProc, (ClientData) connid); -} |