⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pgtclid.c

📁 关系型数据库 Postgresql 6.5.2
💻 C
📖 第 1 页 / 共 2 页
字号:
/*------------------------------------------------------------------------- * * 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*) * * Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION *	  $Header: /usr/local/cvsroot/pgsql/src/interfaces/libpgtcl/pgtclId.c,v 1.20 1999/05/25 22:43:46 momjian Exp $ * *------------------------------------------------------------------------- */#include <stdlib.h>#include <string.h>#include <errno.h>#include "postgres.h"#include "pgtclCmds.h"#include "pgtclId.h"static intPgEndCopy(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. */intPgInputProc(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 */intPgOutputProc(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_GETFILEPROCTcl_FilePgGetFileProc(ClientData cData, int direction){	return (Tcl_File) NULL;}#endifTcl_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 */voidPgSetConnectionId(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;	connid->notifier_socket = -1;	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);#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, 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);		return (PGconn *) 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. */intPgDelConnectionId(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_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;}/* * 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. */intPgSetResultId(Tcl_Interp *interp, 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);	for (resid = connid->res_last + 1; resid != connid->res_last; resid++)	{		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;		}		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;}static intgetresid(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);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -