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

📄 pltcl.c

📁 关系型数据库 Postgresql 6.5.2
💻 C
📖 第 1 页 / 共 5 页
字号:
/********************************************************************** * pltcl.c		- PostgreSQL support for Tcl as *			  procedural language (PL) * * IDENTIFICATION *	  $Header: /usr/local/cvsroot/pgsql/src/pl/tcl/pltcl.c,v 1.12 1999/05/26 12:57:23 momjian Exp $ * *	  This software is copyrighted by Jan Wieck - Hamburg. * *	  The author hereby grants permission  to  use,  copy,	modify, *	  distribute,  and	license this software and its documentation *	  for any purpose, provided that existing copyright notices are *	  retained	in	all  copies  and  that	this notice is included *	  verbatim in any distributions. No written agreement, license, *	  or  royalty  fee	is required for any of the authorized uses. *	  Modifications to this software may be  copyrighted  by  their *	  author  and  need  not  follow  the licensing terms described *	  here, provided that the new terms are  clearly  indicated  on *	  the first page of each file where they apply. * *	  IN NO EVENT SHALL THE AUTHOR OR DISTRIBUTORS BE LIABLE TO ANY *	  PARTY  FOR  DIRECT,	INDIRECT,	SPECIAL,   INCIDENTAL,	 OR *	  CONSEQUENTIAL   DAMAGES  ARISING	OUT  OF  THE  USE  OF  THIS *	  SOFTWARE, ITS DOCUMENTATION, OR ANY DERIVATIVES THEREOF, EVEN *	  IF  THE  AUTHOR  HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH *	  DAMAGE. * *	  THE  AUTHOR  AND	DISTRIBUTORS  SPECIFICALLY	 DISCLAIM	ANY *	  WARRANTIES,  INCLUDING,  BUT	NOT  LIMITED  TO,  THE	IMPLIED *	  WARRANTIES  OF  MERCHANTABILITY,	FITNESS  FOR  A  PARTICULAR *	  PURPOSE,	AND NON-INFRINGEMENT.  THIS SOFTWARE IS PROVIDED ON *	  AN "AS IS" BASIS, AND THE AUTHOR	AND  DISTRIBUTORS  HAVE  NO *	  OBLIGATION   TO	PROVIDE   MAINTENANCE,	 SUPPORT,  UPDATES, *	  ENHANCEMENTS, OR MODIFICATIONS. * **********************************************************************/#include <tcl.h>#include <stdio.h>#include <stdlib.h>#include <stdarg.h>#include <unistd.h>#include <fcntl.h>#include <string.h>#include <setjmp.h>#include "executor/spi.h"#include "commands/trigger.h"#include "utils/elog.h"#include "utils/builtins.h"#include "fmgr.h"#include "access/heapam.h"#include "tcop/tcopprot.h"#include "utils/syscache.h"#include "catalog/pg_proc.h"#include "catalog/pg_type.h"/********************************************************************** * The information we cache about loaded procedures **********************************************************************/typedef struct pltcl_proc_desc{	char	   *proname;	FmgrInfo	result_in_func;	Oid			result_in_elem;	int			result_in_len;	int			nargs;	FmgrInfo	arg_out_func[MAXFMGRARGS];	Oid			arg_out_elem[MAXFMGRARGS];	int			arg_out_len[MAXFMGRARGS];	int			arg_is_rel[MAXFMGRARGS];}			pltcl_proc_desc;/********************************************************************** * The information we cache about prepared and saved plans **********************************************************************/typedef struct pltcl_query_desc{	char		qname[20];	void	   *plan;	int			nargs;	Oid		   *argtypes;	FmgrInfo   *arginfuncs;	Oid		   *argtypelems;	Datum	   *argvalues;	int		   *arglen;}			pltcl_query_desc;/********************************************************************** * Global data **********************************************************************/static int	pltcl_firstcall = 1;static int	pltcl_call_level = 0;static int	pltcl_restart_in_progress = 0;static Tcl_Interp *pltcl_hold_interp = NULL;static Tcl_Interp *pltcl_safe_interp = NULL;static Tcl_HashTable *pltcl_proc_hash = NULL;static Tcl_HashTable *pltcl_query_hash = NULL;/********************************************************************** * Forward declarations **********************************************************************/static void pltcl_init_all(void);static void pltcl_init_safe_interp(void);#ifdef PLTCL_UNKNOWN_SUPPORTstatic void pltcl_init_load_unknown(void);#endif	 /* PLTCL_UNKNOWN_SUPPORT */Datum pltcl_call_handler(FmgrInfo *proinfo,						 FmgrValues *proargs, bool *isNull);static Datum pltcl_func_handler(FmgrInfo *proinfo,				   FmgrValues *proargs, bool *isNull);static HeapTuple pltcl_trigger_handler(FmgrInfo *proinfo);static int pltcl_elog(ClientData cdata, Tcl_Interp *interp,		   int argc, char *argv[]);static int pltcl_quote(ClientData cdata, Tcl_Interp *interp,			int argc, char *argv[]);static int pltcl_SPI_exec(ClientData cdata, Tcl_Interp *interp,			   int argc, char *argv[]);static int pltcl_SPI_prepare(ClientData cdata, Tcl_Interp *interp,				  int argc, char *argv[]);static int pltcl_SPI_execp(ClientData cdata, Tcl_Interp *interp,				int argc, char *argv[]);static void pltcl_set_tuple_values(Tcl_Interp *interp, char *arrayname,					   int tupno, HeapTuple tuple, TupleDesc tupdesc);static void pltcl_build_tuple_argument(HeapTuple tuple, TupleDesc tupdesc,						   Tcl_DString *retval);/********************************************************************** * pltcl_init_all()		- Initialize all **********************************************************************/static voidpltcl_init_all(void){	Tcl_HashEntry *hashent;	Tcl_HashSearch hashsearch;	pltcl_proc_desc *prodesc;	pltcl_query_desc *querydesc;	/************************************************************	 * Do initialization only once	 ************************************************************/	if (!pltcl_firstcall)		return;	/************************************************************	 * Create the dummy hold interpreter to prevent close of	 * stdout and stderr on DeleteInterp	 ************************************************************/	if (pltcl_hold_interp == NULL)	{		if ((pltcl_hold_interp = Tcl_CreateInterp()) == NULL)		{			elog(ERROR, "pltcl: internal error - cannot create 'hold' "				 "interpreter");		}	}	/************************************************************	 * Destroy the existing safe interpreter	 ************************************************************/	if (pltcl_safe_interp != NULL)	{		Tcl_DeleteInterp(pltcl_safe_interp);		pltcl_safe_interp = NULL;	}	/************************************************************	 * Free the proc hash table	 ************************************************************/	if (pltcl_proc_hash != NULL)	{		hashent = Tcl_FirstHashEntry(pltcl_proc_hash, &hashsearch);		while (hashent != NULL)		{			prodesc = (pltcl_proc_desc *) Tcl_GetHashValue(hashent);			free(prodesc->proname);			free(prodesc);			hashent = Tcl_NextHashEntry(&hashsearch);		}		Tcl_DeleteHashTable(pltcl_proc_hash);		free(pltcl_proc_hash);		pltcl_proc_hash = NULL;	}	/************************************************************	 * Free the prepared query hash table	 ************************************************************/	if (pltcl_query_hash != NULL)	{		hashent = Tcl_FirstHashEntry(pltcl_query_hash, &hashsearch);		while (hashent != NULL)		{			querydesc = (pltcl_query_desc *) Tcl_GetHashValue(hashent);			free(querydesc->argtypes);			free(querydesc);			hashent = Tcl_NextHashEntry(&hashsearch);		}		Tcl_DeleteHashTable(pltcl_query_hash);		free(pltcl_query_hash);		pltcl_query_hash = NULL;	}	/************************************************************	 * Now recreate a new safe interpreter	 ************************************************************/	pltcl_init_safe_interp();	pltcl_firstcall = 0;	return;}/********************************************************************** * pltcl_init_safe_interp() - Create the safe Tcl interpreter **********************************************************************/static voidpltcl_init_safe_interp(void){	/************************************************************	 * Create the interpreter as a safe slave of the hold interp.	 ************************************************************/	if ((pltcl_safe_interp =		 Tcl_CreateSlave(pltcl_hold_interp, "safe", 1)) == NULL)	{		elog(ERROR,			 "pltcl: internal error - cannot create 'safe' interpreter");	}	/************************************************************	 * Enable debugging output from the Tcl bytecode compiler	 * To see the trace, the interpreter must be created unsafe	 * USE ONLY FOR DEBUGGING!!!	 ************************************************************/	/*	 * Tcl_SetVar(pltcl_safe_interp, "tcl_traceCompile", "1", 0);	 */	/************************************************************	 * Initialize the proc and query hash tables	 ************************************************************/	pltcl_proc_hash = (Tcl_HashTable *) malloc(sizeof(Tcl_HashTable));	pltcl_query_hash = (Tcl_HashTable *) malloc(sizeof(Tcl_HashTable));	Tcl_InitHashTable(pltcl_proc_hash, TCL_STRING_KEYS);	Tcl_InitHashTable(pltcl_query_hash, TCL_STRING_KEYS);	/************************************************************	 * Install the commands for SPI support in the safe interpreter	 ************************************************************/	Tcl_CreateCommand(pltcl_safe_interp, "elog",					  pltcl_elog, NULL, NULL);	Tcl_CreateCommand(pltcl_safe_interp, "quote",					  pltcl_quote, NULL, NULL);	Tcl_CreateCommand(pltcl_safe_interp, "spi_exec",					  pltcl_SPI_exec, NULL, NULL);	Tcl_CreateCommand(pltcl_safe_interp, "spi_prepare",					  pltcl_SPI_prepare, NULL, NULL);	Tcl_CreateCommand(pltcl_safe_interp, "spi_execp",					  pltcl_SPI_execp, NULL, NULL);#ifdef PLTCL_UNKNOWN_SUPPORT	/************************************************************	 * Try to load the unknown procedure from pltcl_modules	 ************************************************************/	if (SPI_connect() != SPI_OK_CONNECT)		elog(ERROR, "pltcl_init_safe_interp(): SPI_connect failed");	pltcl_init_load_unknown();	if (SPI_finish() != SPI_OK_FINISH)		elog(ERROR, "pltcl_init_safe_interp(): SPI_finish failed");#endif	 /* PLTCL_UNKNOWN_SUPPORT */}#ifdef PLTCL_UNKNOWN_SUPPORT/********************************************************************** * pltcl_init_load_unknown()	- Load the unknown procedure from *				  table pltcl_modules (if it exists) **********************************************************************/static voidpltcl_init_load_unknown(void){	int			spi_rc;	int			tcl_rc;	Tcl_DString unknown_src;	char	   *part;	int			i;	int			fno;	/************************************************************	 * Check if table pltcl_modules exists	 ************************************************************/	spi_rc = SPI_exec("select 1 from pg_class "					  "where relname = 'pltcl_modules'", 1);	if (spi_rc != SPI_OK_SELECT)		elog(ERROR, "pltcl_init_load_unknown(): select from pg_class failed");	if (SPI_processed == 0)		return;	/************************************************************	 * Read all the row's from it where modname = 'unknown' in	 * the order of modseq	 ************************************************************/	Tcl_DStringInit(&unknown_src);	spi_rc = SPI_exec("select modseq, modsrc from pltcl_modules "					  "where modname = 'unknown' "					  "order by modseq", 0);	if (spi_rc != SPI_OK_SELECT)	{		elog(ERROR, "pltcl_init_load_unknown(): select from pltcl_modules "			 "failed");	}	/************************************************************	 * If there's nothing, module unknown doesn't exist	 ************************************************************/	if (SPI_processed == 0)	{		Tcl_DStringFree(&unknown_src);		elog(NOTICE, "pltcl: Module unknown not found in pltcl_modules");		return;	}	/************************************************************	 * There is a module named unknown. Resemble the	 * source from the modsrc attributes and evaluate	 * it in the safe interpreter	 ************************************************************/	fno = SPI_fnumber(SPI_tuptable->tupdesc, "modsrc");	for (i = 0; i < SPI_processed; i++)	{		part = SPI_getvalue(SPI_tuptable->vals[i],							SPI_tuptable->tupdesc, fno);		if (part != NULL)		{			Tcl_DStringAppend(&unknown_src, part, -1);			pfree(part);		}	}	tcl_rc = Tcl_GlobalEval(pltcl_safe_interp, Tcl_DStringValue(&unknown_src));	Tcl_DStringFree(&unknown_src);}#endif	 /* PLTCL_UNKNOWN_SUPPORT *//********************************************************************** * pltcl_call_handler		- This is the only visible function *				  of the PL interpreter. The PostgreSQL *				  function manager and trigger manager *				  call this function for execution of *				  PL/Tcl procedures. **********************************************************************//* keep non-static */Datumpltcl_call_handler(FmgrInfo *proinfo,				   FmgrValues *proargs,				   bool *isNull){	Datum		retval;	/************************************************************	 * Initialize interpreters on first call	 ************************************************************/	if (pltcl_firstcall)		pltcl_init_all();	/************************************************************	 * Connect to SPI manager	 ************************************************************/	if (SPI_connect() != SPI_OK_CONNECT)		elog(ERROR, "pltcl: cannot connect to SPI manager");	/************************************************************	 * Keep track about the nesting of Tcl-SPI-Tcl-... calls	 ************************************************************/	pltcl_call_level++;	/************************************************************	 * Determine if called as function or trigger and	 * call appropriate subhandler	 ************************************************************/	if (CurrentTriggerData == NULL)		retval = pltcl_func_handler(proinfo, proargs, isNull);	else		retval = (Datum) pltcl_trigger_handler(proinfo);	pltcl_call_level--;	return retval;}/********************************************************************** * pltcl_func_handler()		- Handler for regular function calls **********************************************************************/static Datum

⌨️ 快捷键说明

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