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

📄 pltcl.c

📁 PostgreSQL 8.1.4的源码 适用于Linux下的开源数据库系统
💻 C
📖 第 1 页 / 共 5 页
字号:
/********************************************************************** * pltcl.c		- PostgreSQL support for Tcl as *				  procedural language (PL) * *	  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. * * IDENTIFICATION *	  $PostgreSQL: pgsql/src/pl/tcl/pltcl.c,v 1.98.2.2 2006/01/17 17:33:23 tgl Exp $ * **********************************************************************/#include "postgres.h"#include <tcl.h>#include <unistd.h>#include <fcntl.h>/* Hack to deal with Tcl 8.4 const-ification without losing compatibility */#ifndef CONST84#define CONST84#endif#include "access/heapam.h"#include "catalog/pg_language.h"#include "catalog/pg_proc.h"#include "commands/trigger.h"#include "executor/spi.h"#include "fmgr.h"#include "nodes/makefuncs.h"#include "parser/parse_type.h"#include "tcop/tcopprot.h"#include "utils/builtins.h"#include "utils/lsyscache.h"#include "utils/memutils.h"#include "utils/syscache.h"#include "utils/typcache.h"#if defined(UNICODE_CONVERSION) && TCL_MAJOR_VERSION == 8 \	&& TCL_MINOR_VERSION > 0#include "mb/pg_wchar.h"static unsigned char *utf_u2e(unsigned char *src){	return pg_do_encoding_conversion(src, strlen(src), PG_UTF8, GetDatabaseEncoding());}static unsigned char *utf_e2u(unsigned char *src){	return pg_do_encoding_conversion(src, strlen(src), GetDatabaseEncoding(), PG_UTF8);}#define PLTCL_UTF#define UTF_BEGIN	 do { \					unsigned char *_pltcl_utf_src; \					unsigned char *_pltcl_utf_dst#define UTF_END		 if (_pltcl_utf_src!=_pltcl_utf_dst) \					pfree(_pltcl_utf_dst); } while (0)#define UTF_U2E(x)	 (_pltcl_utf_dst=utf_u2e(_pltcl_utf_src=(x)))#define UTF_E2U(x)	 (_pltcl_utf_dst=utf_e2u(_pltcl_utf_src=(x)))#else							/* !PLTCL_UTF */#define  UTF_BEGIN#define  UTF_END#define  UTF_U2E(x)  (x)#define  UTF_E2U(x)  (x)#endif   /* PLTCL_UTF *//********************************************************************** * The information we cache about loaded procedures **********************************************************************/typedef struct pltcl_proc_desc{	char	   *proname;	TransactionId fn_xmin;	CommandId	fn_cmin;	bool		fn_readonly;	bool		lanpltrusted;	FmgrInfo	result_in_func;	Oid			result_typioparam;	int			nargs;	FmgrInfo	arg_out_func[FUNC_MAX_ARGS];	bool		arg_is_rowtype[FUNC_MAX_ARGS];} 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		   *argtypioparams;} pltcl_query_desc;/********************************************************************** * Global data **********************************************************************/static bool pltcl_pm_init_done = false;static bool pltcl_be_init_done = false;static Tcl_Interp *pltcl_hold_interp = NULL;static Tcl_Interp *pltcl_norm_interp = NULL;static Tcl_Interp *pltcl_safe_interp = NULL;static Tcl_HashTable *pltcl_proc_hash = NULL;static Tcl_HashTable *pltcl_norm_query_hash = NULL;static Tcl_HashTable *pltcl_safe_query_hash = NULL;/* these are saved and restored by pltcl_call_handler */static FunctionCallInfo pltcl_current_fcinfo = NULL;static pltcl_proc_desc *pltcl_current_prodesc = NULL;/********************************************************************** * Forward declarations **********************************************************************/static void pltcl_init_all(void);static void pltcl_init_interp(Tcl_Interp *interp);static void pltcl_init_load_unknown(Tcl_Interp *interp);Datum		pltcl_call_handler(PG_FUNCTION_ARGS);Datum		pltclu_call_handler(PG_FUNCTION_ARGS);void		pltcl_init(void);static Datum pltcl_func_handler(PG_FUNCTION_ARGS);static HeapTuple pltcl_trigger_handler(PG_FUNCTION_ARGS);static pltcl_proc_desc *compile_pltcl_function(Oid fn_oid, Oid tgreloid);static int pltcl_elog(ClientData cdata, Tcl_Interp *interp,		   int argc, CONST84 char *argv[]);static int pltcl_quote(ClientData cdata, Tcl_Interp *interp,			int argc, CONST84 char *argv[]);static int pltcl_argisnull(ClientData cdata, Tcl_Interp *interp,				int argc, CONST84 char *argv[]);static int pltcl_returnnull(ClientData cdata, Tcl_Interp *interp,				 int argc, CONST84 char *argv[]);static int pltcl_SPI_execute(ClientData cdata, Tcl_Interp *interp,				  int argc, CONST84 char *argv[]);static int pltcl_process_SPI_result(Tcl_Interp *interp,						 CONST84 char *arrayname,						 CONST84 char *loop_body,						 int spi_rc,						 SPITupleTable *tuptable,						 int ntuples);static int pltcl_SPI_prepare(ClientData cdata, Tcl_Interp *interp,				  int argc, CONST84 char *argv[]);static int pltcl_SPI_execute_plan(ClientData cdata, Tcl_Interp *interp,					   int argc, CONST84 char *argv[]);static int pltcl_SPI_lastoid(ClientData cdata, Tcl_Interp *interp,				  int argc, CONST84 char *argv[]);static void pltcl_set_tuple_values(Tcl_Interp *interp, CONST84 char *arrayname,					   int tupno, HeapTuple tuple, TupleDesc tupdesc);static void pltcl_build_tuple_argument(HeapTuple tuple, TupleDesc tupdesc,						   Tcl_DString *retval);/* * This routine is a crock, and so is everyplace that calls it.  The problem * is that the cached form of pltcl functions/queries is allocated permanently * (mostly via malloc()) and never released until backend exit.  Subsidiary * data structures such as fmgr info records therefore must live forever * as well.  A better implementation would store all this stuff in a per- * function memory context that could be reclaimed at need.  In the meantime, * fmgr_info_cxt must be called specifying TopMemoryContext so that whatever * it might allocate, and whatever the eventual function might allocate using * fn_mcxt, will live forever too. */static voidperm_fmgr_info(Oid functionId, FmgrInfo *finfo){	fmgr_info_cxt(functionId, finfo, TopMemoryContext);}/********************************************************************** * pltcl_init()		- Initialize all that's safe to do in the postmaster * * DO NOT make this static --- it has to be callable by preload **********************************************************************/voidpltcl_init(void){	/************************************************************	 * Do initialization only once	 ************************************************************/	if (pltcl_pm_init_done)		return;#ifdef WIN32	/* Required on win32 to prevent error loading init.tcl */	Tcl_FindExecutable("");#endif	/************************************************************	 * Create the dummy hold interpreter to prevent close of	 * stdout and stderr on DeleteInterp	 ************************************************************/	if ((pltcl_hold_interp = Tcl_CreateInterp()) == NULL)		elog(ERROR, "could not create \"hold\" interpreter");	/************************************************************	 * Create the two interpreters	 ************************************************************/	if ((pltcl_norm_interp =		 Tcl_CreateSlave(pltcl_hold_interp, "norm", 0)) == NULL)		elog(ERROR, "could not create \"normal\" interpreter");	pltcl_init_interp(pltcl_norm_interp);	if ((pltcl_safe_interp =		 Tcl_CreateSlave(pltcl_hold_interp, "safe", 1)) == NULL)		elog(ERROR, "could not create \"safe\" interpreter");	pltcl_init_interp(pltcl_safe_interp);	/************************************************************	 * Initialize the proc and query hash tables	 ************************************************************/	pltcl_proc_hash = (Tcl_HashTable *) malloc(sizeof(Tcl_HashTable));	pltcl_norm_query_hash = (Tcl_HashTable *) malloc(sizeof(Tcl_HashTable));	pltcl_safe_query_hash = (Tcl_HashTable *) malloc(sizeof(Tcl_HashTable));	Tcl_InitHashTable(pltcl_proc_hash, TCL_STRING_KEYS);	Tcl_InitHashTable(pltcl_norm_query_hash, TCL_STRING_KEYS);	Tcl_InitHashTable(pltcl_safe_query_hash, TCL_STRING_KEYS);	pltcl_pm_init_done = true;}/********************************************************************** * pltcl_init_all()		- Initialize all **********************************************************************/static voidpltcl_init_all(void){	/************************************************************	 * Execute postmaster-startup safe initialization	 ************************************************************/	if (!pltcl_pm_init_done)		pltcl_init();	/************************************************************	 * Any other initialization that must be done each time a new	 * backend starts:	 * - Try to load the unknown procedure from pltcl_modules	 ************************************************************/	if (!pltcl_be_init_done)	{		if (SPI_connect() != SPI_OK_CONNECT)			elog(ERROR, "SPI_connect failed");		pltcl_init_load_unknown(pltcl_norm_interp);		pltcl_init_load_unknown(pltcl_safe_interp);		if (SPI_finish() != SPI_OK_FINISH)			elog(ERROR, "SPI_finish failed");		pltcl_be_init_done = true;	}}/********************************************************************** * pltcl_init_interp() - initialize a Tcl interpreter **********************************************************************/static voidpltcl_init_interp(Tcl_Interp *interp){	/************************************************************	 * Install the commands for SPI support in the interpreter	 ************************************************************/	Tcl_CreateCommand(interp, "elog",					  pltcl_elog, NULL, NULL);	Tcl_CreateCommand(interp, "quote",					  pltcl_quote, NULL, NULL);	Tcl_CreateCommand(interp, "argisnull",					  pltcl_argisnull, NULL, NULL);	Tcl_CreateCommand(interp, "return_null",					  pltcl_returnnull, NULL, NULL);	Tcl_CreateCommand(interp, "spi_exec",					  pltcl_SPI_execute, NULL, NULL);	Tcl_CreateCommand(interp, "spi_prepare",					  pltcl_SPI_prepare, NULL, NULL);	Tcl_CreateCommand(interp, "spi_execp",					  pltcl_SPI_execute_plan, NULL, NULL);	Tcl_CreateCommand(interp, "spi_lastoid",					  pltcl_SPI_lastoid, NULL, NULL);}/********************************************************************** * pltcl_init_load_unknown()	- Load the unknown procedure from *				  table pltcl_modules (if it exists) **********************************************************************/static voidpltcl_init_load_unknown(Tcl_Interp *interp){	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_execute("select 1 from pg_catalog.pg_class "						 "where relname = 'pltcl_modules'",						 false, 1);	SPI_freetuptable(SPI_tuptable);	if (spi_rc != SPI_OK_SELECT)		elog(ERROR, "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_execute("select modseq, modsrc from pltcl_modules "						 "where modname = 'unknown' "						 "order by modseq",						 false, 0);	if (spi_rc != SPI_OK_SELECT)		elog(ERROR, "select from pltcl_modules failed");	/************************************************************	 * If there's nothing, module unknown doesn't exist	 ************************************************************/	if (SPI_processed == 0)	{		Tcl_DStringFree(&unknown_src);		SPI_freetuptable(SPI_tuptable);		elog(WARNING, "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 Tcl 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)		{			UTF_BEGIN;			Tcl_DStringAppend(&unknown_src, UTF_E2U(part), -1);			UTF_END;			pfree(part);		}	}	tcl_rc = Tcl_GlobalEval(interp, Tcl_DStringValue(&unknown_src));	Tcl_DStringFree(&unknown_src);	SPI_freetuptable(SPI_tuptable);}/********************************************************************** * 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. **********************************************************************/PG_FUNCTION_INFO_V1(pltcl_call_handler);/* keep non-static */Datumpltcl_call_handler(PG_FUNCTION_ARGS){	Datum		retval;	FunctionCallInfo save_fcinfo;	pltcl_proc_desc *save_prodesc;	/*	 * Initialize interpreters if first time through	 */	pltcl_init_all();	/*	 * Ensure that static pointers are saved/restored properly	 */	save_fcinfo = pltcl_current_fcinfo;	save_prodesc = pltcl_current_prodesc;	PG_TRY();	{		/*		 * Determine if called as function or trigger and call appropriate		 * subhandler		 */		if (CALLED_AS_TRIGGER(fcinfo))		{			pltcl_current_fcinfo = NULL;			retval = PointerGetDatum(pltcl_trigger_handler(fcinfo));		}		else		{			pltcl_current_fcinfo = fcinfo;			retval = pltcl_func_handler(fcinfo);

⌨️ 快捷键说明

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