summaryrefslogtreecommitdiff
path: root/src/interfaces/libpgtcl/pgtclId.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/interfaces/libpgtcl/pgtclId.c')
-rw-r--r--src/interfaces/libpgtcl/pgtclId.c975
1 files changed, 512 insertions, 463 deletions
diff --git a/src/interfaces/libpgtcl/pgtclId.c b/src/interfaces/libpgtcl/pgtclId.c
index 1d3cd29709a..9377e322e7e 100644
--- a/src/interfaces/libpgtcl/pgtclId.c
+++ b/src/interfaces/libpgtcl/pgtclId.c
@@ -1,18 +1,18 @@
/*-------------------------------------------------------------------------
*
* pgtclId.c--
- * useful routines to convert between strings and pointers
- * Needed because everything in tcl is a string, but we want pointers
- * to data structures
+ * useful routines to convert between strings and pointers
+ * Needed because everything in tcl is a string, but we want pointers
+ * to data structures
*
- * ASSUMPTION: sizeof(long) >= sizeof(void*)
+ * ASSUMPTION: sizeof(long) >= sizeof(void*)
*
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/interfaces/libpgtcl/Attic/pgtclId.c,v 1.13 1998/08/22 04:34:22 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/interfaces/libpgtcl/Attic/pgtclId.c,v 1.14 1998/09/01 04:39:58 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -27,129 +27,145 @@
#include "pgtclId.h"
-static int PgEndCopy(Pg_ConnectionId *connid, int *errorCodePtr)
+static int
+PgEndCopy(Pg_ConnectionId * connid, int *errorCodePtr)
{
- connid->res_copyStatus = RES_COPY_NONE;
- if (PQendcopy(connid->conn)) {
- connid->results[connid->res_copy]->resultStatus = PGRES_BAD_RESPONSE;
- connid->res_copy = -1;
- *errorCodePtr = EIO;
- return -1;
- } else {
- connid->results[connid->res_copy]->resultStatus = PGRES_COMMAND_OK;
- connid->res_copy = -1;
- return 0;
- }
+ connid->res_copyStatus = RES_COPY_NONE;
+ if (PQendcopy(connid->conn))
+ {
+ connid->results[connid->res_copy]->resultStatus = PGRES_BAD_RESPONSE;
+ connid->res_copy = -1;
+ *errorCodePtr = EIO;
+ return -1;
+ }
+ else
+ {
+ connid->results[connid->res_copy]->resultStatus = PGRES_COMMAND_OK;
+ connid->res_copy = -1;
+ return 0;
+ }
}
/*
- * Called when reading data (via gets) for a copy <rel> to stdout.
+ * Called when reading data (via gets) for a copy <rel> to stdout.
*
- * NOTE: this routine knows way more than it ought to about libpq's
- * internal buffering mechanisms.
+ * NOTE: this routine knows way more than it ought to about libpq's
+ * internal buffering mechanisms.
*/
-int PgInputProc(DRIVER_INPUT_PROTO)
+int
+PgInputProc(DRIVER_INPUT_PROTO)
{
- Pg_ConnectionId *connid;
- PGconn *conn;
- char c;
- int avail;
-
- connid = (Pg_ConnectionId *)cData;
- conn = connid->conn;
-
- if (connid->res_copy < 0 ||
- connid->results[connid->res_copy]->resultStatus != PGRES_COPY_OUT) {
- *errorCodePtr = EBUSY;
- return -1;
- }
-
- /* Try to load any newly arrived data */
- conn->errorMessage[0] = '\0';
- PQconsumeInput(conn);
- if (conn->errorMessage[0]) {
- *errorCodePtr = EIO;
- return -1;
- }
-
- /* Move data from libpq's buffer to Tcl's.
- * We want to accept data only in units of whole lines,
- * not partial lines. This ensures that we can recognize
- * the terminator line "\\.\n". (Otherwise, if it happened
- * to cross a packet/buffer boundary, we might hand the first
- * one or two characters off to Tcl, which we shouldn't.)
- */
-
- conn->inCursor = conn->inStart;
-
- avail = bufSize;
- while (avail > 0 && conn->inCursor < conn->inEnd) {
- c = conn->inBuffer[conn->inCursor++];
- *buf++ = c;
- --avail;
- if (c == '\n') {
- /* Got a complete line; mark the data removed from libpq */
- conn->inStart = conn->inCursor;
- /* Is it the endmarker line? */
- if (bufSize-avail == 3 && buf[-3] == '\\' && buf[-2] == '.') {
- /* Yes, change state and return 0 */
- return PgEndCopy(connid, errorCodePtr);
- }
- /* No, return the data to Tcl */
- /* fprintf(stderr, "returning %d chars\n", bufSize - avail); */
- return bufSize - avail;
+ Pg_ConnectionId *connid;
+ PGconn *conn;
+ char c;
+ int avail;
+
+ connid = (Pg_ConnectionId *) cData;
+ conn = connid->conn;
+
+ if (connid->res_copy < 0 ||
+ connid->results[connid->res_copy]->resultStatus != PGRES_COPY_OUT)
+ {
+ *errorCodePtr = EBUSY;
+ return -1;
+ }
+
+ /* Try to load any newly arrived data */
+ conn->errorMessage[0] = '\0';
+ PQconsumeInput(conn);
+ if (conn->errorMessage[0])
+ {
+ *errorCodePtr = EIO;
+ return -1;
+ }
+
+ /*
+ * Move data from libpq's buffer to Tcl's. We want to accept data only
+ * in units of whole lines, not partial lines. This ensures that we
+ * can recognize the terminator line "\\.\n". (Otherwise, if it
+ * happened to cross a packet/buffer boundary, we might hand the first
+ * one or two characters off to Tcl, which we shouldn't.)
+ */
+
+ conn->inCursor = conn->inStart;
+
+ avail = bufSize;
+ while (avail > 0 && conn->inCursor < conn->inEnd)
+ {
+ c = conn->inBuffer[conn->inCursor++];
+ *buf++ = c;
+ --avail;
+ if (c == '\n')
+ {
+ /* Got a complete line; mark the data removed from libpq */
+ conn->inStart = conn->inCursor;
+ /* Is it the endmarker line? */
+ if (bufSize - avail == 3 && buf[-3] == '\\' && buf[-2] == '.')
+ {
+ /* Yes, change state and return 0 */
+ return PgEndCopy(connid, errorCodePtr);
+ }
+ /* No, return the data to Tcl */
+ /* fprintf(stderr, "returning %d chars\n", bufSize - avail); */
+ return bufSize - avail;
+ }
}
- }
-
- /* We don't have a complete line.
- * We'd prefer to leave it in libpq's buffer until the rest arrives,
- * but there is a special case: what if the line is longer than the
- * buffer Tcl is offering us? In that case we'd better hand over
- * a partial line, else we'd get into an infinite loop.
- * Do this in a way that ensures we can't misrecognize a terminator
- * line later: leave last 3 characters in libpq buffer.
- */
- if (avail == 0 && bufSize > 3) {
- conn->inStart = conn->inCursor - 3;
- return bufSize - 3;
- }
- return 0;
+
+ /*
+ * We don't have a complete line. We'd prefer to leave it in libpq's
+ * buffer until the rest arrives, but there is a special case: what if
+ * the line is longer than the buffer Tcl is offering us? In that
+ * case we'd better hand over a partial line, else we'd get into an
+ * infinite loop. Do this in a way that ensures we can't misrecognize
+ * a terminator line later: leave last 3 characters in libpq buffer.
+ */
+ if (avail == 0 && bufSize > 3)
+ {
+ conn->inStart = conn->inCursor - 3;
+ return bufSize - 3;
+ }
+ return 0;
}
/*
- * Called when writing data (via puts) for a copy <rel> from stdin
+ * Called when writing data (via puts) for a copy <rel> from stdin
*/
-int PgOutputProc(DRIVER_OUTPUT_PROTO)
+int
+PgOutputProc(DRIVER_OUTPUT_PROTO)
{
- Pg_ConnectionId *connid;
- PGconn *conn;
-
- connid = (Pg_ConnectionId *)cData;
- conn = connid->conn;
-
- if (connid->res_copy < 0 ||
- connid->results[connid->res_copy]->resultStatus != PGRES_COPY_IN) {
- *errorCodePtr = EBUSY;
- return -1;
- }
-
- conn->errorMessage[0] = '\0';
-
- PQputnbytes(conn, buf, bufSize);
-
- if (conn->errorMessage[0]) {
- *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;
+ Pg_ConnectionId *connid;
+ PGconn *conn;
+
+ connid = (Pg_ConnectionId *) cData;
+ conn = connid->conn;
+
+ if (connid->res_copy < 0 ||
+ connid->results[connid->res_copy]->resultStatus != PGRES_COPY_IN)
+ {
+ *errorCodePtr = EBUSY;
+ return -1;
+ }
+
+ conn->errorMessage[0] = '\0';
+
+ PQputnbytes(conn, buf, bufSize);
+
+ if (conn->errorMessage[0])
+ {
+ *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
@@ -157,59 +173,62 @@ int PgOutputProc(DRIVER_OUTPUT_PROTO)
Tcl_File
PgGetFileProc(ClientData cData, int direction)
{
- return (Tcl_File)NULL;
+ return (Tcl_File) NULL;
}
#endif
Tcl_ChannelType Pg_ConnType = {
- "pgsql", /* channel type */
- NULL, /* blockmodeproc */
- PgDelConnectionId, /* closeproc */
- PgInputProc, /* inputproc */
- PgOutputProc, /* outputproc */
- /* Note the additional stuff can be left NULL,
- or is initialized during a PgSetConnectionId */
+ "pgsql", /* channel type */
+ NULL, /* blockmodeproc */
+ PgDelConnectionId, /* closeproc */
+ PgInputProc, /* inputproc */
+ PgOutputProc, /* outputproc */
+
+ /*
+ * Note the additional stuff can be left NULL, or is initialized
+ * during a PgSetConnectionId
+ */
};
/*
* Create and register a new channel for the connection
*/
void
-PgSetConnectionId(Tcl_Interp *interp, PGconn *conn)
+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));
+ 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 == 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);
+ /* 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);
+ /* 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);
+ Tcl_SetChannelOption(interp, conn_chan, "-buffering", "line");
+ Tcl_SetResult(interp, connid->id, TCL_VOLATILE);
+ Tcl_RegisterChannel(interp, conn_chan);
}
@@ -217,22 +236,23 @@ PgSetConnectionId(Tcl_Interp *interp, PGconn *conn)
* Get back the connection from the Id
*/
PGconn *
-PgGetConnectionId(Tcl_Interp *interp, char *id, Pg_ConnectionId **connid_p)
+PgGetConnectionId(Tcl_Interp * interp, char *id, Pg_ConnectionId ** connid_p)
{
- Tcl_Channel conn_chan;
- Pg_ConnectionId *connid;
+ 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);
- return (PGconn *)NULL;
- }
+ 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);
+ return (PGconn *) NULL;
+ }
- connid = (Pg_ConnectionId *)Tcl_GetChannelInstanceData(conn_chan);
- if (connid_p)
- *connid_p = connid;
- return connid->conn;
+ connid = (Pg_ConnectionId *) Tcl_GetChannelInstanceData(conn_chan);
+ if (connid_p)
+ *connid_p = connid;
+ return connid->conn;
}
@@ -240,55 +260,58 @@ PgGetConnectionId(Tcl_Interp *interp, char *id, Pg_ConnectionId **connid_p)
* Remove a connection Id from the hash table and
* close all portals the user forgot.
*/
-int PgDelConnectionId(DRIVER_DEL_PROTO)
+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(&notifies->notify_hash, &hsearch);
- entry != NULL;
- entry = Tcl_NextHashEntry(&hsearch)) {
- ckfree((char*) Tcl_GetHashValue(entry));
+ 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]);
}
- Tcl_DeleteHashTable(&notifies->notify_hash);
- Tcl_DontCallWhenDeleted(notifies->interp, PgNotifyInterpDelete,
- (ClientData) notifies);
- ckfree((void*) notifies);
- }
-
- /* Turn off the Tcl event source for this connection,
- * and delete any pending notify events.
- */
- PgStopNotifyEventSource(connid);
-
- /* Close the libpq connection too */
- PQfinish(connid->conn);
- connid->conn = NULL;
-
- /*
- * 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;
+ ckfree((void *) connid->results);
+
+ /* Release associated notify info */
+ while ((notifies = connid->notify_list) != NULL)
+ {
+ connid->notify_list = notifies->next;
+ for (entry = Tcl_FirstHashEntry(&notifies->notify_hash, &hsearch);
+ entry != NULL;
+ entry = Tcl_NextHashEntry(&hsearch))
+ ckfree((char *) Tcl_GetHashValue(entry));
+ Tcl_DeleteHashTable(&notifies->notify_hash);
+ Tcl_DontCallWhenDeleted(notifies->interp, PgNotifyInterpDelete,
+ (ClientData) notifies);
+ ckfree((void *) notifies);
+ }
+
+ /*
+ * Turn off the Tcl event source for this connection, and delete any
+ * pending notify events.
+ */
+ PgStopNotifyEventSource(connid);
+
+ /* Close the libpq connection too */
+ PQfinish(connid->conn);
+ connid->conn = NULL;
+
+ /*
+ * 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;
}
@@ -298,102 +321,110 @@ int PgDelConnectionId(DRIVER_DEL_PROTO)
* is probably just not clearing result handles like they should.
*/
int
-PgSetResultId(Tcl_Interp *interp, char *connid_c, PGresult *res)
+PgSetResultId(Tcl_Interp * interp, char *connid_c, PGresult *res)
{
- Tcl_Channel conn_chan;
- Pg_ConnectionId *connid;
- int resid, i;
- char buf[32];
+ 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);
+ conn_chan = Tcl_GetChannel(interp, connid_c, 0);
+ if (conn_chan == NULL)
+ return TCL_ERROR;
+ connid = (Pg_ConnectionId *) Tcl_GetChannelInstanceData(conn_chan);
- for (resid = connid->res_last+1; resid != connid->res_last; resid++) {
- if (resid == connid->res_max)
- resid = 0;
- if (!connid->results[resid])
+ for (resid = connid->res_last + 1; resid != connid->res_last; resid++)
{
- connid->res_last = resid;
- break;
+ if (resid == connid->res_max)
+ resid = 0;
+ if (!connid->results[resid])
+ {
+ connid->res_last = resid;
+ break;
+ }
}
- }
- if (connid->results[resid]) {
- if (connid->res_max == connid->res_hardmax) {
- Tcl_SetResult(interp, "hard limit on result handles reached",
- TCL_STATIC);
- return TCL_ERROR;
+ if (connid->results[resid])
+ {
+ if (connid->res_max == connid->res_hardmax)
+ {
+ Tcl_SetResult(interp, "hard limit on result handles reached",
+ TCL_STATIC);
+ return TCL_ERROR;
+ }
+ connid->res_last = connid->res_max;
+ 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->res_last = connid->res_max;
- 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;
+
+ 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, char *id, Pg_ConnectionId **connid_p)
+static int
+getresid(Tcl_Interp * interp, 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;
+ 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, char *id)
+PGresult *
+PgGetResultId(Tcl_Interp * interp, 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];
+ Pg_ConnectionId *connid;
+ int resid;
+
+ if (!id)
+ return NULL;
+ resid = getresid(interp, id, &connid);
+ if (resid == -1)
+ return NULL;
+ return connid->results[resid];
}
@@ -401,15 +432,15 @@ PgGetResultId(Tcl_Interp *interp, char *id)
* Remove a result Id from the hash tables
*/
void
-PgDelResultId(Tcl_Interp *interp, char *id)
+PgDelResultId(Tcl_Interp * interp, char *id)
{
- Pg_ConnectionId *connid;
- int resid;
+ Pg_ConnectionId *connid;
+ int resid;
- resid = getresid(interp, id, &connid);
- if (resid == -1)
- return;
- connid->results[resid] = 0;
+ resid = getresid(interp, id, &connid);
+ if (resid == -1)
+ return;
+ connid->results[resid] = 0;
}
@@ -417,25 +448,26 @@ PgDelResultId(Tcl_Interp *interp, char *id)
* Get the connection Id from the result Id
*/
int
-PgGetConnByResultId(Tcl_Interp *interp, char *resid_c)
+PgGetConnByResultId(Tcl_Interp * interp, 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, 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;
+ 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, 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;
}
@@ -458,137 +490,146 @@ PgGetConnByResultId(Tcl_Interp *interp, char *resid_c)
the channel can outlive the interpreter it was created by!)
Upon closure of the channel, we immediately delete any pending events
that reference it. But for interpreter deletion, we just set any
- matching interp pointers in the Pg_TclNotifies list to NULL. The
+ 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.)
*******************************************/
-typedef struct {
- Tcl_Event header; /* Standard Tcl event info */
- PGnotify info; /* Notify name from SQL server */
- Pg_ConnectionId *connid; /* Connection for server */
-} NotifyEvent;
+typedef struct
+{
+ Tcl_Event header; /* Standard Tcl event info */
+ PGnotify info; /* Notify name from SQL server */
+ Pg_ConnectionId *connid; /* Connection for server */
+} NotifyEvent;
/* Setup before waiting in event loop */
-static void Pg_Notify_SetupProc (ClientData clientData, int flags)
+static void
+Pg_Notify_SetupProc(ClientData clientData, int flags)
{
- Pg_ConnectionId *connid = (Pg_ConnectionId *) clientData;
- Tcl_File handle;
- int pqsock;
-
- /* We classify SQL notifies as Tcl file events. */
- if (!(flags & TCL_FILE_EVENTS)) {
- return;
- }
-
- /* Set up to watch for asynchronous data arrival on backend channel */
- pqsock = PQsocket(connid->conn);
- if (pqsock < 0)
- return;
-
- handle = Tcl_GetFile((ClientData) pqsock, TCL_UNIX_FD);
- Tcl_WatchFile(handle, TCL_READABLE);
+ Pg_ConnectionId *connid = (Pg_ConnectionId *) clientData;
+ Tcl_File handle;
+ int pqsock;
+
+ /* We classify SQL notifies as Tcl file events. */
+ if (!(flags & TCL_FILE_EVENTS))
+ return;
+
+ /* Set up to watch for asynchronous data arrival on backend channel */
+ pqsock = PQsocket(connid->conn);
+ if (pqsock < 0)
+ return;
+
+ handle = Tcl_GetFile((ClientData) pqsock, TCL_UNIX_FD);
+ Tcl_WatchFile(handle, TCL_READABLE);
}
/* Check to see if events have arrived in event loop */
-static void Pg_Notify_CheckProc (ClientData clientData, int flags)
+static void
+Pg_Notify_CheckProc(ClientData clientData, int flags)
{
- Pg_ConnectionId *connid = (Pg_ConnectionId *) clientData;
- Tcl_File handle;
- int pqsock;
-
- /* We classify SQL notifies as Tcl file events. */
- if (!(flags & TCL_FILE_EVENTS)) {
- return;
- }
-
- /* Consume any data available from the SQL server
- * (this just buffers it internally to libpq).
- * We use Tcl_FileReady to avoid a useless kernel call
- * when no data is available.
- */
- pqsock = PQsocket(connid->conn);
- if (pqsock < 0)
- return;
-
- handle = Tcl_GetFile((ClientData) pqsock, TCL_UNIX_FD);
- if (Tcl_FileReady(handle, TCL_READABLE) != 0) {
- PQconsumeInput(connid->conn);
- }
-
- /* Transfer notify events from libpq to Tcl event queue. */
- PgNotifyTransferEvents(connid);
+ Pg_ConnectionId *connid = (Pg_ConnectionId *) clientData;
+ Tcl_File handle;
+ int pqsock;
+
+ /* We classify SQL notifies as Tcl file events. */
+ if (!(flags & TCL_FILE_EVENTS))
+ return;
+
+ /*
+ * Consume any data available from the SQL server (this just buffers
+ * it internally to libpq). We use Tcl_FileReady to avoid a useless
+ * kernel call when no data is available.
+ */
+ pqsock = PQsocket(connid->conn);
+ if (pqsock < 0)
+ return;
+
+ handle = Tcl_GetFile((ClientData) pqsock, TCL_UNIX_FD);
+ if (Tcl_FileReady(handle, TCL_READABLE) != 0)
+ PQconsumeInput(connid->conn);
+
+ /* Transfer notify events from libpq to Tcl event queue. */
+ PgNotifyTransferEvents(connid);
}
/* Dispatch an event that has reached the front of the event queue */
-static int Pg_Notify_EventProc (Tcl_Event *evPtr, int flags)
+static int
+Pg_Notify_EventProc(Tcl_Event * evPtr, int flags)
{
- NotifyEvent *event = (NotifyEvent *) evPtr;
- Pg_TclNotifies *notifies;
- Tcl_HashEntry *entry;
- char *callback;
- char *svcallback;
-
- /* We classify SQL notifies as Tcl file events. */
- if (!(flags & TCL_FILE_EVENTS)) {
- return 0;
- }
-
- /* 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.
- */
- entry = Tcl_FindHashEntry(&notifies->notify_hash,
- event->info.relname);
- if (entry == NULL)
- continue; /* no pg_listen in this interpreter */
- callback = (char *) Tcl_GetHashValue(entry);
- if (callback == NULL)
- continue; /* safety check -- shouldn't happen */
+ NotifyEvent *event = (NotifyEvent *) evPtr;
+ Pg_TclNotifies *notifies;
+ Tcl_HashEntry *entry;
+ char *callback;
+ char *svcallback;
+
+ /* We classify SQL notifies as Tcl file events. */
+ if (!(flags & TCL_FILE_EVENTS))
+ return 0;
+
/*
- * We have to copy the callback string in case the user executes
- * a new pg_listen during the callback.
+ * Preserve/Release to ensure the connection struct doesn't disappear
+ * underneath us.
*/
- svcallback = (char *) ckalloc((unsigned) (strlen(callback) + 1));
- strcpy(svcallback, callback);
+ Tcl_Preserve((ClientData) event->connid);
+
/*
- * Execute the callback.
+ * Loop for each interpreter that has ever registered on the
+ * connection. Each one can get a callback.
*/
- Tcl_Preserve((ClientData) interp);
- if (Tcl_GlobalEval(interp, svcallback) != TCL_OK) {
- Tcl_AddErrorInfo(interp, "\n (\"pg_listen\" script)");
- Tcl_BackgroundError(interp);
+
+ 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.
+ */
+ entry = Tcl_FindHashEntry(&notifies->notify_hash,
+ event->info.relname);
+ if (entry == NULL)
+ continue; /* no pg_listen in this interpreter */
+ callback = (char *) Tcl_GetHashValue(entry);
+ if (callback == NULL)
+ continue; /* safety check -- shouldn't happen */
+
+ /*
+ * We have to copy the callback string in case the user executes a
+ * new pg_listen 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)
+ {
+ Tcl_AddErrorInfo(interp, "\n (\"pg_listen\" 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) interp);
- ckfree(svcallback);
- /*
- * Check for the possibility that the callback closed the connection.
- */
- if (event->connid->conn == NULL)
- break;
- }
- Tcl_Release((ClientData) event->connid);
+ Tcl_Release((ClientData) event->connid);
- return 1;
+ return 1;
}
/*
@@ -598,18 +639,21 @@ static int Pg_Notify_EventProc (Tcl_Event *evPtr, int flags)
* (to capture notifies that arrive when we're idle).
*/
-void PgNotifyTransferEvents (Pg_ConnectionId *connid)
+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->info = *notify;
- event->connid = connid;
- Tcl_QueueEvent((Tcl_Event *) event, TCL_QUEUE_TAIL);
- free(notify);
- }
+ PGnotify *notify;
+
+ while ((notify = PQnotifies(connid->conn)) != NULL)
+ {
+ NotifyEvent *event = (NotifyEvent *) ckalloc(sizeof(NotifyEvent));
+
+ event->header.proc = Pg_Notify_EventProc;
+ event->info = *notify;
+ event->connid = connid;
+ Tcl_QueueEvent((Tcl_Event *) event, TCL_QUEUE_TAIL);
+ free(notify);
+ }
}
/*
@@ -621,27 +665,28 @@ void PgNotifyTransferEvents (Pg_ConnectionId *connid)
* rid of pending Tcl events that reference a dying connection.
*/
-void PgNotifyInterpDelete(ClientData clientData, Tcl_Interp *interp)
+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;
+ /* Mark the interpreter dead, but don't do anything else yet */
+ Pg_TclNotifies *notifies = (Pg_TclNotifies *) clientData;
+
+ notifies->interp = NULL;
}
/* Comparison routine for detecting events to be removed by DeleteEvent */
-static int NotifyEventDeleteProc(Tcl_Event *evPtr, ClientData clientData)
+static int
+NotifyEventDeleteProc(Tcl_Event * evPtr, ClientData clientData)
{
- NotifyEvent *event;
- Pg_ConnectionId *connid = (Pg_ConnectionId *) clientData;
-
- if (evPtr->proc != Pg_Notify_EventProc) {
- return 0;
- }
- event = (NotifyEvent *) evPtr;
- if (event->connid != connid) {
- return 0;
- }
- return 1;
+ NotifyEvent *event;
+ Pg_ConnectionId *connid = (Pg_ConnectionId *) clientData;
+
+ if (evPtr->proc != Pg_Notify_EventProc)
+ return 0;
+ event = (NotifyEvent *) evPtr;
+ if (event->connid != connid)
+ return 0;
+ return 1;
}
/* Start and stop the notify event source for a connection.
@@ -651,24 +696,28 @@ static int NotifyEventDeleteProc(Tcl_Event *evPtr, ClientData clientData)
* closed.
*/
-void PgStartNotifyEventSource(Pg_ConnectionId *connid)
+void
+PgStartNotifyEventSource(Pg_ConnectionId * connid)
{
- /* Start the notify event source if it isn't already running */
- if (! connid->notifier_running) {
- Tcl_CreateEventSource(Pg_Notify_SetupProc, Pg_Notify_CheckProc,
- (ClientData) connid);
- connid->notifier_running = 1;
- }
+ /* Start the notify event source if it isn't already running */
+ if (!connid->notifier_running)
+ {
+ Tcl_CreateEventSource(Pg_Notify_SetupProc, Pg_Notify_CheckProc,
+ (ClientData) connid);
+ connid->notifier_running = 1;
+ }
}
-void PgStopNotifyEventSource(Pg_ConnectionId *connid)
+void
+PgStopNotifyEventSource(Pg_ConnectionId * connid)
{
- /* Remove the event source */
- if (connid->notifier_running) {
- Tcl_DeleteEventSource(Pg_Notify_SetupProc, Pg_Notify_CheckProc,
- (ClientData) connid);
- connid->notifier_running = 0;
- }
- /* Kill any queued Tcl events that reference this channel */
- Tcl_DeleteEvents(NotifyEventDeleteProc, (ClientData) connid);
+ /* Remove the event source */
+ if (connid->notifier_running)
+ {
+ Tcl_DeleteEventSource(Pg_Notify_SetupProc, Pg_Notify_CheckProc,
+ (ClientData) connid);
+ connid->notifier_running = 0;
+ }
+ /* Kill any queued Tcl events that reference this channel */
+ Tcl_DeleteEvents(NotifyEventDeleteProc, (ClientData) connid);
}