mirror of
https://github.com/postgres/postgres.git
synced 2025-04-22 23:02:54 +03:00
From: Randy Kunkee <kunkee@pluto.ops.NeoSoft.com>
It is my hope that the following "patches" to libpgtcl get included in the next release. See the update to the README file to get a full description of the changes. This version of libpgtcl is completely interpreter-safe, implements the database connection handle as a channel (no events yet, but will make it a lot easier to do fileevents on it in the future), and supports the SQL "copy table to stdout" and "copy table from stdin" commands, with the I/O being from and to the connection handle. The connection and result handles are formatted in a way to make access to the tables more efficient.
This commit is contained in:
parent
609026bb6b
commit
6ac2528616
@ -7,7 +7,7 @@
|
||||
#
|
||||
#
|
||||
# IDENTIFICATION
|
||||
# $Header: /cvsroot/pgsql/src/interfaces/libpgtcl/Attic/Makefile.in,v 1.3 1998/02/13 05:09:57 scrappy Exp $
|
||||
# $Header: /cvsroot/pgsql/src/interfaces/libpgtcl/Attic/Makefile.in,v 1.4 1998/03/15 08:02:55 scrappy Exp $
|
||||
#
|
||||
#-------------------------------------------------------------------------
|
||||
|
||||
@ -37,7 +37,7 @@ ifeq ($(PORTNAME), linux)
|
||||
install-shlib-dep := install-shlib
|
||||
shlib := libpgtcl.so.1
|
||||
CFLAGS += $(CFLAGS_SL)
|
||||
LDFLAGS_SL = -shared -L $(SRCDIR)/interfaces/libpq -lpq
|
||||
LDFLAGS_SL = -shared -L$(SRCDIR)/interfaces/libpq -lpq
|
||||
endif
|
||||
endif
|
||||
|
||||
@ -53,14 +53,14 @@ endif
|
||||
ifeq ($(PORTNAME), i386_solaris)
|
||||
install-shlib-dep := install-shlib
|
||||
shlib := libpgtcl.so.1
|
||||
LDFLAGS_SL = -G -z text -L $(SRCDIR)/interfaces/libpq -lpq
|
||||
LDFLAGS_SL = -G -z text -L$(SRCDIR)/interfaces/libpq -lpq
|
||||
CFLAGS += $(CFLAGS_SL)
|
||||
endif
|
||||
|
||||
ifeq ($(PORTNAME), univel)
|
||||
install-shlib-dep := install-shlib
|
||||
shlib := libpgtcl.so.1
|
||||
LDFLAGS_SL = -G -z text -L $(SRCDIR)/interfaces/libpq -lpq
|
||||
LDFLAGS_SL = -G -z text -L$(SRCDIR)/interfaces/libpq -lpq
|
||||
CFLAGS += $(CFLAGS_SL)
|
||||
endif
|
||||
|
||||
|
@ -1,6 +1,38 @@
|
||||
libpgtcl is a library that implements Tcl commands for front-end clients
|
||||
to interact with the PostgreSQL backend. See libpgtcl.doc for details.
|
||||
|
||||
libpgtcl is a library that implements Tcl commands for front-end
|
||||
clients to interact with the Postgresql 6.3 (and perhaps later)
|
||||
backends. See libpgtcl.doc for details.
|
||||
|
||||
For an example of how to build a new tclsh to use libpgtcl, see the
|
||||
directory ../bin/pgtclsh
|
||||
|
||||
Note this version is modified by NeoSoft to have the following additional
|
||||
features:
|
||||
|
||||
1. Postgres connections are a valid Tcl channel, and can therefore
|
||||
be manipulated by the interp command (ie. shared or transfered).
|
||||
A connection handle's results are transfered/shared with it.
|
||||
(Result handles are NOT channels, though it was tempting). Note
|
||||
that a "close $connection" is now functionally identical to a
|
||||
"pg_disconnect $connection", although pg_connect must be used
|
||||
to create a connection.
|
||||
|
||||
2. Result handles are changed in format: ${connection}.<result#>.
|
||||
This just means for a connection 'pgtcl0', they look like pgtcl0.0,
|
||||
pgtcl0.1, etc. Enforcing this syntax makes it easy to look up
|
||||
the real pointer by indexing into an array associated with the
|
||||
connection.
|
||||
|
||||
3. I/O routines are now defined for the connection handle. I/O to/from
|
||||
the connection is only valid under certain circumstances: following
|
||||
the execution of the queries "copy <table> from stdin" or
|
||||
"copy <table> to stdout". In these cases, the result handle obtains
|
||||
an intermediate status of "PGRES_COPY_IN" or "PGRES_COPY_OUT". The
|
||||
programmer is then expected to use Tcl gets or read commands on the
|
||||
database connection (not the result handle) to extract the copy data.
|
||||
For copy outs, read until the standard EOF indication is encountered.
|
||||
For copy ins, puts a single terminator (\.). The statement for this
|
||||
would be
|
||||
puts $conn "\\." or puts $conn {\.}
|
||||
In either case (upon detecting the EOF or putting the `\.', the status
|
||||
of the result handle will change to "PGRES_COMMAND_OK", and any further
|
||||
I/O attempts will cause a Tcl error.
|
||||
|
@ -9,7 +9,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/interfaces/libpgtcl/Attic/pgtcl.c,v 1.9 1997/09/08 02:40:08 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/interfaces/libpgtcl/Attic/pgtcl.c,v 1.10 1998/03/15 08:02:57 scrappy Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -23,163 +23,122 @@
|
||||
#include "pgtclId.h"
|
||||
|
||||
/*
|
||||
* Pgtcl_Init
|
||||
* initialization package for the PGLITE Tcl package
|
||||
* Pgtcl_Init
|
||||
* initialization package for the PGLITE Tcl package
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Tidy up forgotten postgres connection at Tcl_Exit
|
||||
*/
|
||||
static void
|
||||
Pgtcl_AtExit(ClientData cData)
|
||||
{
|
||||
Pg_clientData *cd = (Pg_clientData *) cData;
|
||||
Tcl_HashEntry *hent;
|
||||
Tcl_HashSearch hsearch;
|
||||
Pg_ConnectionId *connid;
|
||||
PGconn *conn;
|
||||
|
||||
while ((hent = Tcl_FirstHashEntry(&(cd->dbh_hash), &hsearch)) != NULL)
|
||||
{
|
||||
connid = (Pg_ConnectionId *) Tcl_GetHashValue(hent);
|
||||
conn = connid->conn;
|
||||
PgDelConnectionId(cd, connid->id);
|
||||
PQfinish(conn);
|
||||
}
|
||||
|
||||
Tcl_DeleteHashTable(&(cd->dbh_hash));
|
||||
Tcl_DeleteHashTable(&(cd->res_hash));
|
||||
Tcl_DeleteHashTable(&(cd->notify_hash));
|
||||
|
||||
Tcl_DeleteExitHandler(Pgtcl_AtExit, cData);
|
||||
}
|
||||
|
||||
/*
|
||||
* Tidy up forgotten postgres connections on Interpreter deletion
|
||||
*/
|
||||
static void
|
||||
Pgtcl_Shutdown(ClientData cData, Tcl_Interp * interp)
|
||||
{
|
||||
Pgtcl_AtExit(cData);
|
||||
}
|
||||
|
||||
int
|
||||
Pgtcl_Init(Tcl_Interp * interp)
|
||||
Pgtcl_Init (Tcl_Interp *interp)
|
||||
{
|
||||
Pg_clientData *cd;
|
||||
|
||||
/* Create and initialize the client data area */
|
||||
cd = (Pg_clientData *) ckalloc(sizeof(Pg_clientData));
|
||||
Tcl_InitHashTable(&(cd->dbh_hash), TCL_STRING_KEYS);
|
||||
Tcl_InitHashTable(&(cd->res_hash), TCL_STRING_KEYS);
|
||||
Tcl_InitHashTable(&(cd->notify_hash), TCL_STRING_KEYS);
|
||||
cd->dbh_count = 0L;
|
||||
cd->res_count = 0L;
|
||||
/* finish off the ChannelType struct. Much easier to do it here then
|
||||
* to guess where it might be by position in the struct. This is needed
|
||||
* for Tcl7.6 and beyond, which have the getfileproc.
|
||||
*/
|
||||
#if (TCL_MAJOR_VERSION == 7 && TCL_MINOR_VERSION == 6)
|
||||
Pg_ConnType.getFileProc = PgGetFileProc;
|
||||
#endif
|
||||
|
||||
/* Arrange for tidy up when interpreter is deleted or Tcl exits */
|
||||
Tcl_CallWhenDeleted(interp, Pgtcl_Shutdown, (ClientData) cd);
|
||||
Tcl_CreateExitHandler(Pgtcl_AtExit, (ClientData) cd);
|
||||
/* register all pgtcl commands */
|
||||
Tcl_CreateCommand(interp,
|
||||
"pg_conndefaults",
|
||||
Pg_conndefaults,
|
||||
(ClientData)NULL, (Tcl_CmdDeleteProc*)NULL);
|
||||
|
||||
/* register all pgtcl commands */
|
||||
Tcl_CreateCommand(interp,
|
||||
"pg_conndefaults",
|
||||
Pg_conndefaults,
|
||||
(ClientData) cd, (Tcl_CmdDeleteProc *) NULL);
|
||||
Tcl_CreateCommand(interp,
|
||||
"pg_connect",
|
||||
Pg_connect,
|
||||
(ClientData)NULL, (Tcl_CmdDeleteProc*)NULL);
|
||||
|
||||
Tcl_CreateCommand(interp,
|
||||
"pg_connect",
|
||||
Pg_connect,
|
||||
(ClientData) cd, (Tcl_CmdDeleteProc *) NULL);
|
||||
Tcl_CreateCommand(interp,
|
||||
"pg_disconnect",
|
||||
Pg_disconnect,
|
||||
(ClientData)NULL, (Tcl_CmdDeleteProc*)NULL);
|
||||
|
||||
Tcl_CreateCommand(interp,
|
||||
"pg_exec",
|
||||
Pg_exec,
|
||||
(ClientData)NULL, (Tcl_CmdDeleteProc*)NULL);
|
||||
|
||||
Tcl_CreateCommand(interp,
|
||||
"pg_select",
|
||||
Pg_select,
|
||||
(ClientData)NULL, (Tcl_CmdDeleteProc*)NULL);
|
||||
|
||||
Tcl_CreateCommand(interp,
|
||||
"pg_result",
|
||||
Pg_result,
|
||||
(ClientData)NULL, (Tcl_CmdDeleteProc*)NULL);
|
||||
|
||||
Tcl_CreateCommand(interp,
|
||||
"pg_lo_open",
|
||||
Pg_lo_open,
|
||||
(ClientData)NULL, (Tcl_CmdDeleteProc*)NULL);
|
||||
|
||||
Tcl_CreateCommand(interp,
|
||||
"pg_lo_close",
|
||||
Pg_lo_close,
|
||||
(ClientData)NULL, (Tcl_CmdDeleteProc*)NULL);
|
||||
|
||||
Tcl_CreateCommand(interp,
|
||||
"pg_disconnect",
|
||||
Pg_disconnect,
|
||||
(ClientData) cd, (Tcl_CmdDeleteProc *) NULL);
|
||||
Tcl_CreateCommand(interp,
|
||||
"pg_lo_read",
|
||||
Pg_lo_read,
|
||||
(ClientData)NULL, (Tcl_CmdDeleteProc*)NULL);
|
||||
|
||||
Tcl_CreateCommand(interp,
|
||||
"pg_exec",
|
||||
Pg_exec,
|
||||
(ClientData) cd, (Tcl_CmdDeleteProc *) NULL);
|
||||
Tcl_CreateCommand(interp,
|
||||
"pg_lo_write",
|
||||
Pg_lo_write,
|
||||
(ClientData)NULL, (Tcl_CmdDeleteProc*)NULL);
|
||||
|
||||
Tcl_CreateCommand(interp,
|
||||
"pg_select",
|
||||
Pg_select,
|
||||
(ClientData) cd, (Tcl_CmdDeleteProc *) NULL);
|
||||
Tcl_CreateCommand(interp,
|
||||
"pg_lo_lseek",
|
||||
Pg_lo_lseek,
|
||||
(ClientData)NULL, (Tcl_CmdDeleteProc*)NULL);
|
||||
|
||||
Tcl_CreateCommand(interp,
|
||||
"pg_result",
|
||||
Pg_result,
|
||||
(ClientData) cd, (Tcl_CmdDeleteProc *) NULL);
|
||||
Tcl_CreateCommand(interp,
|
||||
"pg_lo_creat",
|
||||
Pg_lo_creat,
|
||||
(ClientData)NULL, (Tcl_CmdDeleteProc*)NULL);
|
||||
|
||||
Tcl_CreateCommand(interp,
|
||||
"pg_lo_open",
|
||||
Pg_lo_open,
|
||||
(ClientData) cd, (Tcl_CmdDeleteProc *) NULL);
|
||||
Tcl_CreateCommand(interp,
|
||||
"pg_lo_tell",
|
||||
Pg_lo_tell,
|
||||
(ClientData)NULL, (Tcl_CmdDeleteProc*)NULL);
|
||||
|
||||
Tcl_CreateCommand(interp,
|
||||
"pg_lo_close",
|
||||
Pg_lo_close,
|
||||
(ClientData) cd, (Tcl_CmdDeleteProc *) NULL);
|
||||
Tcl_CreateCommand(interp,
|
||||
"pg_lo_unlink",
|
||||
Pg_lo_unlink,
|
||||
(ClientData)NULL, (Tcl_CmdDeleteProc*)NULL);
|
||||
|
||||
Tcl_CreateCommand(interp,
|
||||
"pg_lo_read",
|
||||
Pg_lo_read,
|
||||
(ClientData) cd, (Tcl_CmdDeleteProc *) NULL);
|
||||
Tcl_CreateCommand(interp,
|
||||
"pg_lo_import",
|
||||
Pg_lo_import,
|
||||
(ClientData)NULL, (Tcl_CmdDeleteProc*)NULL);
|
||||
|
||||
Tcl_CreateCommand(interp,
|
||||
"pg_lo_export",
|
||||
Pg_lo_export,
|
||||
(ClientData)NULL, (Tcl_CmdDeleteProc*)NULL);
|
||||
|
||||
Tcl_CreateCommand(interp,
|
||||
"pg_listen",
|
||||
Pg_listen,
|
||||
(ClientData)NULL, (Tcl_CmdDeleteProc*)NULL);
|
||||
|
||||
Tcl_CreateCommand(interp,
|
||||
"pg_lo_write",
|
||||
Pg_lo_write,
|
||||
(ClientData) cd, (Tcl_CmdDeleteProc *) NULL);
|
||||
Tcl_CreateCommand(interp,
|
||||
"pg_notifies",
|
||||
Pg_notifies,
|
||||
(ClientData)NULL, (Tcl_CmdDeleteProc*)NULL);
|
||||
|
||||
Tcl_CreateCommand(interp,
|
||||
"pg_lo_lseek",
|
||||
Pg_lo_lseek,
|
||||
(ClientData) cd, (Tcl_CmdDeleteProc *) NULL);
|
||||
Tcl_PkgProvide(interp, "Pgtcl", "1.1");
|
||||
|
||||
Tcl_CreateCommand(interp,
|
||||
"pg_lo_creat",
|
||||
Pg_lo_creat,
|
||||
(ClientData) cd, (Tcl_CmdDeleteProc *) NULL);
|
||||
|
||||
Tcl_CreateCommand(interp,
|
||||
"pg_lo_tell",
|
||||
Pg_lo_tell,
|
||||
(ClientData) cd, (Tcl_CmdDeleteProc *) NULL);
|
||||
|
||||
Tcl_CreateCommand(interp,
|
||||
"pg_lo_unlink",
|
||||
Pg_lo_unlink,
|
||||
(ClientData) cd, (Tcl_CmdDeleteProc *) NULL);
|
||||
|
||||
Tcl_CreateCommand(interp,
|
||||
"pg_lo_import",
|
||||
Pg_lo_import,
|
||||
(ClientData) cd, (Tcl_CmdDeleteProc *) NULL);
|
||||
|
||||
Tcl_CreateCommand(interp,
|
||||
"pg_lo_export",
|
||||
Pg_lo_export,
|
||||
(ClientData) cd, (Tcl_CmdDeleteProc *) NULL);
|
||||
|
||||
Tcl_CreateCommand(interp,
|
||||
"pg_listen",
|
||||
Pg_listen,
|
||||
(ClientData) cd, (Tcl_CmdDeleteProc *) NULL);
|
||||
|
||||
Tcl_CreateCommand(interp,
|
||||
"pg_notifies",
|
||||
Pg_notifies,
|
||||
(ClientData) cd, (Tcl_CmdDeleteProc *) NULL);
|
||||
|
||||
Tcl_PkgProvide(interp, "Pgtcl", "1.0");
|
||||
|
||||
return TCL_OK;
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
Pgtcl_SafeInit(Tcl_Interp * interp)
|
||||
Pgtcl_SafeInit (Tcl_Interp *interp)
|
||||
{
|
||||
return Pgtcl_Init(interp);
|
||||
return Pgtcl_Init(interp);
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -5,7 +5,7 @@
|
||||
*
|
||||
* Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Id: pgtclCmds.h,v 1.8 1997/09/08 02:40:16 momjian Exp $
|
||||
* $Id: pgtclCmds.h,v 1.9 1998/03/15 08:02:59 scrappy Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -18,89 +18,69 @@
|
||||
#include "libpq-fe.h"
|
||||
#include "libpq/libpq-fs.h"
|
||||
|
||||
typedef struct Pg_clientData_s
|
||||
{
|
||||
Tcl_HashTable dbh_hash;
|
||||
Tcl_HashTable res_hash;
|
||||
Tcl_HashTable notify_hash;
|
||||
long dbh_count;
|
||||
long res_count;
|
||||
} Pg_clientData;
|
||||
#define RES_HARD_MAX 128
|
||||
#define RES_START 16
|
||||
|
||||
typedef struct Pg_ConnectionId_s {
|
||||
char id[32];
|
||||
PGconn *conn;
|
||||
int res_max; /* Max number of results allocated */
|
||||
int res_hardmax; /* Absolute max to allow */
|
||||
int res_count; /* Current count of active results */
|
||||
int res_last; /* Optimize where to start looking */
|
||||
int res_copy; /* Query result with active copy */
|
||||
int res_copyStatus; /* Copying status */
|
||||
PGresult **results; /* The results */
|
||||
|
||||
Tcl_HashTable notify_hash;
|
||||
} Pg_ConnectionId;
|
||||
|
||||
|
||||
typedef struct Pg_ConnectionId_s
|
||||
{
|
||||
char id[32];
|
||||
PGconn *conn;
|
||||
Tcl_HashTable res_hash;
|
||||
} Pg_ConnectionId;
|
||||
|
||||
|
||||
typedef struct Pg_ResultId_s
|
||||
{
|
||||
char id[32];
|
||||
PGresult *result;
|
||||
Pg_ConnectionId *connection;
|
||||
} Pg_ResultId;
|
||||
#define RES_COPY_NONE 0
|
||||
#define RES_COPY_INPROGRESS 1
|
||||
#define RES_COPY_FIN 2
|
||||
|
||||
|
||||
/* **************************/
|
||||
/* registered Tcl functions */
|
||||
/* **************************/
|
||||
extern int
|
||||
Pg_conndefaults(
|
||||
ClientData cData, Tcl_Interp * interp, int argc, char *argv[]);
|
||||
extern int
|
||||
Pg_connect(
|
||||
ClientData cData, Tcl_Interp * interp, int argc, char *argv[]);
|
||||
extern int
|
||||
Pg_disconnect(
|
||||
ClientData cData, Tcl_Interp * interp, int argc, char *argv[]);
|
||||
extern int
|
||||
Pg_exec(
|
||||
ClientData cData, Tcl_Interp * interp, int argc, char *argv[]);
|
||||
extern int
|
||||
Pg_select(
|
||||
ClientData cData, Tcl_Interp * interp, int argc, char *argv[]);
|
||||
extern int
|
||||
Pg_result(
|
||||
ClientData cData, Tcl_Interp * interp, int argc, char *argv[]);
|
||||
extern int
|
||||
Pg_lo_open(
|
||||
ClientData cData, Tcl_Interp * interp, int argc, char *argv[]);
|
||||
extern int
|
||||
Pg_lo_close(
|
||||
ClientData cData, Tcl_Interp * interp, int argc, char *argv[]);
|
||||
extern int
|
||||
Pg_lo_read(
|
||||
ClientData cData, Tcl_Interp * interp, int argc, char *argv[]);
|
||||
extern int
|
||||
Pg_lo_write(
|
||||
ClientData cData, Tcl_Interp * interp, int argc, char *argv[]);
|
||||
extern int
|
||||
Pg_lo_lseek(
|
||||
ClientData cData, Tcl_Interp * interp, int argc, char *argv[]);
|
||||
extern int
|
||||
Pg_lo_creat(
|
||||
ClientData cData, Tcl_Interp * interp, int argc, char *argv[]);
|
||||
extern int
|
||||
Pg_lo_tell(
|
||||
ClientData cData, Tcl_Interp * interp, int argc, char *argv[]);
|
||||
extern int
|
||||
Pg_lo_unlink(
|
||||
ClientData cData, Tcl_Interp * interp, int argc, char *argv[]);
|
||||
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[]);
|
||||
extern int Pg_conndefaults(
|
||||
ClientData cData, Tcl_Interp *interp, int argc, char* argv[]);
|
||||
extern int Pg_connect(
|
||||
ClientData cData, Tcl_Interp *interp, int argc, char* argv[]);
|
||||
extern int Pg_disconnect(
|
||||
ClientData cData, Tcl_Interp *interp, int argc, char* argv[]);
|
||||
extern int Pg_exec(
|
||||
ClientData cData, Tcl_Interp *interp, int argc, char* argv[]);
|
||||
extern int Pg_select(
|
||||
ClientData cData, Tcl_Interp *interp, int argc, char* argv[]);
|
||||
extern int Pg_result(
|
||||
ClientData cData, Tcl_Interp *interp, int argc, char* argv[]);
|
||||
extern int Pg_lo_open(
|
||||
ClientData cData, Tcl_Interp *interp, int argc, char* argv[]);
|
||||
extern int Pg_lo_close(
|
||||
ClientData cData, Tcl_Interp *interp, int argc, char* argv[]);
|
||||
extern int Pg_lo_read(
|
||||
ClientData cData, Tcl_Interp *interp, int argc, char* argv[]);
|
||||
extern int Pg_lo_write(
|
||||
ClientData cData, Tcl_Interp *interp, int argc, char* argv[]);
|
||||
extern int Pg_lo_lseek(
|
||||
ClientData cData, Tcl_Interp *interp, int argc, char* argv[]);
|
||||
extern int Pg_lo_creat(
|
||||
ClientData cData, Tcl_Interp *interp, int argc, char* argv[]);
|
||||
extern int Pg_lo_tell(
|
||||
ClientData cData, Tcl_Interp *interp, int argc, char* argv[]);
|
||||
extern int Pg_lo_unlink(
|
||||
ClientData cData, Tcl_Interp *interp, int argc, char* argv[]);
|
||||
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 */
|
||||
#endif /*PGTCLCMDS_H*/
|
||||
|
||||
|
@ -1,48 +1,173 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
*
|
||||
* 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.7 1998/02/26 04:44:53 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/interfaces/libpgtcl/Attic/pgtclId.c,v 1.8 1998/03/15 08:03:00 scrappy Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <tcl.h>
|
||||
|
||||
#include "postgres.h"
|
||||
#include "pgtclCmds.h"
|
||||
#include "pgtclId.h"
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Create the Id for a new connection and hash it
|
||||
* Called when reading data (via gets) for a copy <rel> to stdout
|
||||
*/
|
||||
int PgInputProc(DRIVER_INPUT_PROTO)
|
||||
{
|
||||
Pg_ConnectionId *connid;
|
||||
PGconn *conn;
|
||||
int 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;
|
||||
}
|
||||
|
||||
if (connid->res_copyStatus == RES_COPY_FIN) {
|
||||
return PgEndCopy(connid, errorCodePtr);
|
||||
}
|
||||
|
||||
avail = bufSize;
|
||||
while (avail > 0 &&
|
||||
(c = pqGetc(conn->Pfin, conn->Pfdebug)) != EOF) {
|
||||
/* fprintf(stderr, "%d: got char %c\n", bufSize-avail, c); */
|
||||
*buf++ = c;
|
||||
--avail;
|
||||
if (c == '\n' && bufSize-avail > 3) {
|
||||
if ((bufSize-avail == 3 || buf[-4] == '\n') &&
|
||||
buf[-3] == '\\' && buf[-2] == '.') {
|
||||
avail += 3;
|
||||
connid->res_copyStatus = RES_COPY_FIN;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* fprintf(stderr, "returning %d chars\n", bufSize - avail); */
|
||||
return bufSize - 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 ||
|
||||
connid->results[connid->res_copy]->resultStatus != PGRES_COPY_IN) {
|
||||
*errorCodePtr = EBUSY;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
fprintf(stderr, "PgOutputProc called: bufSize=%d: atend:%d <", bufSize,
|
||||
strncmp(buf, "\\.\n", 3));
|
||||
fwrite(buf, 1, bufSize, stderr);
|
||||
fputs(">\n", stderr);
|
||||
*/
|
||||
fwrite(buf, 1, bufSize, conn->Pfout);
|
||||
if (bufSize > 2 && strncmp(&buf[bufSize-3], "\\.\n", 3) == 0) {
|
||||
/* fprintf(stderr,"checking closure\n"); */
|
||||
fflush(conn->Pfout);
|
||||
if (PgEndCopy(connid, errorCodePtr) == -1)
|
||||
return -1;
|
||||
}
|
||||
return bufSize;
|
||||
}
|
||||
|
||||
#if (TCL_MAJOR_VERSION == 7 && TCL_MINOR_VERSION == 6)
|
||||
Tcl_File
|
||||
PgGetFileProc(ClientData cData, int direction)
|
||||
{
|
||||
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 */
|
||||
};
|
||||
|
||||
/*
|
||||
* Create and register a new channel for the connection
|
||||
*/
|
||||
void
|
||||
PgSetConnectionId(Pg_clientData * cd, char *id, PGconn *conn)
|
||||
PgSetConnectionId(Tcl_Interp *interp, PGconn *conn)
|
||||
{
|
||||
Tcl_HashEntry *hent;
|
||||
Pg_ConnectionId *connid;
|
||||
int hnew;
|
||||
Tcl_Channel conn_chan;
|
||||
Pg_ConnectionId *connid;
|
||||
int i;
|
||||
|
||||
connid = (Pg_ConnectionId *) ckalloc(sizeof(Pg_ConnectionId));
|
||||
connid->conn = conn;
|
||||
Tcl_InitHashTable(&(connid->res_hash), TCL_STRING_KEYS);
|
||||
sprintf(connid->id, "pgc%ld", cd->dbh_count++);
|
||||
strcpy(id, connid->id);
|
||||
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;
|
||||
Tcl_InitHashTable(&connid->notify_hash, TCL_STRING_KEYS);
|
||||
|
||||
hent = Tcl_CreateHashEntry(&(cd->dbh_hash), connid->id, &hnew);
|
||||
Tcl_SetHashValue(hent, (ClientData) connid);
|
||||
sprintf(connid->id, "pgsql%d", fileno(conn->Pfout));
|
||||
|
||||
#if TCL_MAJOR_VERSION == 7 && TCL_MINOR_VERSION == 5
|
||||
conn_chan = Tcl_CreateChannel(&Pg_ConnType, connid->id, conn->Pfin, conn->Pfout, (ClientData)connid);
|
||||
#else
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
@ -50,19 +175,22 @@ PgSetConnectionId(Pg_clientData * cd, char *id, PGconn *conn)
|
||||
* Get back the connection from the Id
|
||||
*/
|
||||
PGconn *
|
||||
PgGetConnectionId(Pg_clientData * cd, char *id)
|
||||
PgGetConnectionId(Tcl_Interp *interp, char *id, Pg_ConnectionId **connid_p)
|
||||
{
|
||||
Tcl_HashEntry *hent;
|
||||
Pg_ConnectionId *connid;
|
||||
Tcl_Channel conn_chan;
|
||||
Pg_ConnectionId *connid;
|
||||
|
||||
hent = Tcl_FindHashEntry(&(cd->dbh_hash), id);
|
||||
if (hent == NULL)
|
||||
{
|
||||
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\n", 0);
|
||||
return (PGconn *)NULL;
|
||||
}
|
||||
|
||||
connid = (Pg_ConnectionId *) Tcl_GetHashValue(hent);
|
||||
return connid->conn;
|
||||
connid = (Pg_ConnectionId *)Tcl_GetChannelInstanceData(conn_chan);
|
||||
if (connid_p)
|
||||
*connid_p = connid;
|
||||
return connid->conn;
|
||||
}
|
||||
|
||||
|
||||
@ -70,98 +198,139 @@ PgGetConnectionId(Pg_clientData * cd, char *id)
|
||||
* Remove a connection Id from the hash table and
|
||||
* close all portals the user forgot.
|
||||
*/
|
||||
void
|
||||
PgDelConnectionId(Pg_clientData * cd, char *id)
|
||||
int PgDelConnectionId(DRIVER_DEL_PROTO)
|
||||
{
|
||||
Tcl_HashEntry *hent;
|
||||
Tcl_HashEntry *hent2;
|
||||
Tcl_HashEntry *hent3;
|
||||
Tcl_HashSearch hsearch;
|
||||
Pg_ConnectionId *connid;
|
||||
Pg_ResultId *resid;
|
||||
Tcl_HashEntry *entry;
|
||||
char *hval;
|
||||
Tcl_HashSearch hsearch;
|
||||
Pg_ConnectionId *connid;
|
||||
int i;
|
||||
|
||||
hent = Tcl_FindHashEntry(&(cd->dbh_hash), id);
|
||||
if (hent == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
connid = (Pg_ConnectionId *)cData;
|
||||
|
||||
connid = (Pg_ConnectionId *) Tcl_GetHashValue(hent);
|
||||
for (i = 0; i < connid->res_max; i++) {
|
||||
if (connid->results[i])
|
||||
PQclear(connid->results[i]);
|
||||
}
|
||||
ckfree((void*)connid->results);
|
||||
|
||||
hent2 = Tcl_FirstHashEntry(&(connid->res_hash), &hsearch);
|
||||
while (hent2 != NULL)
|
||||
{
|
||||
resid = (Pg_ResultId *) Tcl_GetHashValue(hent2);
|
||||
PQclear(resid->result);
|
||||
hent3 = Tcl_FindHashEntry(&(cd->res_hash), resid->id);
|
||||
if (hent3 != NULL)
|
||||
{
|
||||
Tcl_DeleteHashEntry(hent3);
|
||||
}
|
||||
ckfree(resid);
|
||||
hent2 = Tcl_NextHashEntry(&hsearch);
|
||||
}
|
||||
Tcl_DeleteHashTable(&(connid->res_hash));
|
||||
Tcl_DeleteHashEntry(hent);
|
||||
ckfree(connid);
|
||||
for (entry = Tcl_FirstHashEntry(&(connid->notify_hash), &hsearch);
|
||||
entry != NULL;
|
||||
entry = Tcl_NextHashEntry(&hsearch))
|
||||
{
|
||||
hval = (char*)Tcl_GetHashValue(entry);
|
||||
ckfree(hval);
|
||||
}
|
||||
|
||||
Tcl_DeleteHashTable(&connid->notify_hash);
|
||||
PQfinish(connid->conn);
|
||||
ckfree((void*)connid);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Create a new result Id and hash it
|
||||
* 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.
|
||||
*/
|
||||
void
|
||||
PgSetResultId(Pg_clientData * cd, char *id, char *connid_c, PGresult *res)
|
||||
int
|
||||
PgSetResultId(Tcl_Interp *interp, char *connid_c, PGresult *res)
|
||||
{
|
||||
Tcl_HashEntry *hent;
|
||||
Pg_ConnectionId *connid;
|
||||
Pg_ResultId *resid;
|
||||
int hnew;
|
||||
Tcl_Channel conn_chan;
|
||||
Pg_ConnectionId *connid;
|
||||
int resid, i;
|
||||
char buf[32];
|
||||
|
||||
hent = Tcl_FindHashEntry(&(cd->dbh_hash), connid_c);
|
||||
if (hent == NULL)
|
||||
|
||||
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])
|
||||
{
|
||||
connid = NULL;
|
||||
connid->res_last = resid;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
connid = (Pg_ConnectionId *) Tcl_GetHashValue(hent);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
resid = (Pg_ResultId *) ckalloc(sizeof(Pg_ResultId));
|
||||
resid->result = res;
|
||||
resid->connection = connid;
|
||||
sprintf(resid->id, "pgr%ld", cd->res_count++);
|
||||
strcpy(id, resid->id);
|
||||
connid->results[resid] = res;
|
||||
sprintf(buf, "%s.%d", connid_c, resid);
|
||||
Tcl_SetResult(interp, buf, TCL_VOLATILE);
|
||||
return resid;
|
||||
}
|
||||
|
||||
hent = Tcl_CreateHashEntry(&(cd->res_hash), resid->id, &hnew);
|
||||
Tcl_SetHashValue(hent, (ClientData) resid);
|
||||
static int getresid(Tcl_Interp *interp, char *id, Pg_ConnectionId **connid_p)
|
||||
{
|
||||
Tcl_Channel conn_chan;
|
||||
char *mark;
|
||||
int resid;
|
||||
Pg_ConnectionId *connid;
|
||||
|
||||
if (connid != NULL)
|
||||
{
|
||||
hent = Tcl_CreateHashEntry(&(connid->res_hash), resid->id, &hnew);
|
||||
Tcl_SetHashValue(hent, (ClientData) resid);
|
||||
}
|
||||
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(Pg_clientData * cd, char *id)
|
||||
PGresult *
|
||||
PgGetResultId(Tcl_Interp *interp, char *id)
|
||||
{
|
||||
Tcl_HashEntry *hent;
|
||||
Pg_ResultId *resid;
|
||||
Pg_ConnectionId *connid;
|
||||
int resid;
|
||||
|
||||
hent = Tcl_FindHashEntry(&(cd->res_hash), id);
|
||||
if (hent == NULL)
|
||||
{
|
||||
return (PGresult *) NULL;
|
||||
}
|
||||
|
||||
resid = (Pg_ResultId *) Tcl_GetHashValue(hent);
|
||||
return resid->result;
|
||||
if (!id)
|
||||
return NULL;
|
||||
resid = getresid(interp, id, &connid);
|
||||
if (resid == -1)
|
||||
return NULL;
|
||||
return connid->results[resid];
|
||||
}
|
||||
|
||||
|
||||
@ -169,51 +338,41 @@ PgGetResultId(Pg_clientData * cd, char *id)
|
||||
* Remove a result Id from the hash tables
|
||||
*/
|
||||
void
|
||||
PgDelResultId(Pg_clientData * cd, char *id)
|
||||
PgDelResultId(Tcl_Interp *interp, char *id)
|
||||
{
|
||||
Tcl_HashEntry *hent;
|
||||
Tcl_HashEntry *hent2;
|
||||
Pg_ResultId *resid;
|
||||
Pg_ConnectionId *connid;
|
||||
int resid;
|
||||
|
||||
hent = Tcl_FindHashEntry(&(cd->res_hash), id);
|
||||
if (hent == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
resid = (Pg_ResultId *) Tcl_GetHashValue(hent);
|
||||
if (resid->connection != NULL)
|
||||
{
|
||||
hent2 = Tcl_FindHashEntry(&(resid->connection->res_hash), id);
|
||||
if (hent2 != NULL)
|
||||
{
|
||||
Tcl_DeleteHashEntry(hent2);
|
||||
}
|
||||
}
|
||||
|
||||
Tcl_DeleteHashEntry(hent);
|
||||
ckfree(resid);
|
||||
resid = getresid(interp, id, &connid);
|
||||
if (resid == -1)
|
||||
return;
|
||||
connid->results[resid] = 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Get the connection Id from the result Id
|
||||
*/
|
||||
void
|
||||
PgGetConnByResultId(Pg_clientData * cd, char *id, char *resid_c)
|
||||
int
|
||||
PgGetConnByResultId(Tcl_Interp *interp, char *resid_c)
|
||||
{
|
||||
Tcl_HashEntry *hent;
|
||||
Pg_ResultId *resid;
|
||||
char *mark;
|
||||
Tcl_Channel conn_chan;
|
||||
|
||||
hent = Tcl_FindHashEntry(&(cd->res_hash), id);
|
||||
if (hent == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
resid = (Pg_ResultId *) Tcl_GetHashValue(hent);
|
||||
if (resid->connection != NULL)
|
||||
{
|
||||
strcpy(id, resid->connection->id);
|
||||
}
|
||||
error_out:
|
||||
Tcl_ResetResult(interp);
|
||||
Tcl_AppendResult(interp, resid_c, " is not a valid connection\n", 0);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
|
||||
|
@ -1,22 +1,47 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
*
|
||||
* pgtclId.h--
|
||||
* useful routines to convert between strings and pointers
|
||||
* Needed because everything in tcl is a string, but often, pointers
|
||||
* to data structures are needed.
|
||||
*
|
||||
*
|
||||
* Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Id: pgtclId.h,v 1.5 1997/09/08 21:55:26 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
*
|
||||
* pgtclId.h--
|
||||
* useful routines to convert between strings and pointers
|
||||
* Needed because everything in tcl is a string, but often, pointers
|
||||
* to data structures are needed.
|
||||
*
|
||||
*
|
||||
* Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Id: pgtclId.h,v 1.6 1998/03/15 08:03:00 scrappy Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
extern void PgSetConnectionId(Tcl_Interp *interp, PGconn *conn);
|
||||
|
||||
extern void PgSetConnectionId(Pg_clientData * cd, char *id, PGconn *conn);
|
||||
extern PGconn *PgGetConnectionId(Pg_clientData * cd, char *id);
|
||||
extern void PgDelConnectionId(Pg_clientData * cd, char *id);
|
||||
extern void PgSetResultId(Pg_clientData * cd, char *id, char *connid, PGresult *res);
|
||||
extern PGresult *PgGetResultId(Pg_clientData * cd, char *id);
|
||||
extern void PgDelResultId(Pg_clientData * cd, char *id);
|
||||
extern void PgGetConnByResultId(Pg_clientData * cd, char *id, char *resid);
|
||||
#if (TCL_MAJOR_VERSION == 7 && TCL_MINOR_VERSION == 5)
|
||||
# define DRIVER_DEL_PROTO ClientData cData, Tcl_Interp *interp, \
|
||||
Tcl_File inFile, Tcl_File outFile
|
||||
# define DRIVER_OUTPUT_PROTO ClientData cData, Tcl_File outFile, char *buf, \
|
||||
int bufSize, int *errorCodePtr
|
||||
# define DRIVER_INPUT_PROTO ClientData cData, Tcl_File inFile, char *buf, \
|
||||
int bufSize, int *errorCodePtr
|
||||
#else
|
||||
# define DRIVER_OUTPUT_PROTO ClientData cData, char *buf, int bufSize, \
|
||||
int *errorCodePtr
|
||||
# define DRIVER_INPUT_PROTO ClientData cData, char *buf, int bufSize, \
|
||||
int *errorCodePtr
|
||||
# define DRIVER_DEL_PROTO ClientData cData, Tcl_Interp *interp
|
||||
#endif
|
||||
|
||||
extern PGconn *PgGetConnectionId(Tcl_Interp *interp, char *id, \
|
||||
Pg_ConnectionId **);
|
||||
extern PgDelConnectionId(DRIVER_DEL_PROTO);
|
||||
extern int PgOutputProc(DRIVER_OUTPUT_PROTO);
|
||||
extern PgInputProc(DRIVER_INPUT_PROTO);
|
||||
extern int PgSetResultId(Tcl_Interp *interp, char *connid, PGresult *res);
|
||||
extern PGresult *PgGetResultId(Tcl_Interp *interp, char *id);
|
||||
extern void PgDelResultId(Tcl_Interp *interp, char *id);
|
||||
extern int PgGetConnByResultId(Tcl_Interp *interp, char *resid);
|
||||
|
||||
#if (TCL_MAJOR_VERSION < 8)
|
||||
extern Tcl_File PgGetFileProc(ClientData cData, int direction);
|
||||
#endif
|
||||
|
||||
extern Tcl_ChannelType Pg_ConnType;
|
||||
|
Loading…
x
Reference in New Issue
Block a user