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

📄 plperl.c

📁 PostgreSQL7.4.6 for Linux
💻 C
📖 第 1 页 / 共 2 页
字号:
/********************************************************************** * plperl.c - perl as a procedural language for PostgreSQL * * IDENTIFICATION * *	  This software is copyrighted by Mark Hollomon *	 but is shameless cribbed from pltcl.c by Jan Weick. * *	  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 *	  $Header: /cvsroot/pgsql/src/pl/plperl/plperl.c,v 1.40 2003/09/04 15:16:39 tgl Exp $ * **********************************************************************/#include "postgres.h"/* system stuff */#include <unistd.h>#include <fcntl.h>#include <setjmp.h>/* postgreSQL stuff */#include "executor/spi.h"#include "commands/trigger.h"#include "fmgr.h"#include "access/heapam.h"#include "tcop/tcopprot.h"#include "utils/syscache.h"#include "catalog/pg_language.h"#include "catalog/pg_proc.h"#include "catalog/pg_type.h"/* perl stuff */#include "EXTERN.h"#include "perl.h"#include "XSUB.h"#include "ppport.h"/* just in case these symbols aren't provided */#ifndef pTHX_#define pTHX_#define pTHX void#endif/********************************************************************** * The information we cache about loaded procedures **********************************************************************/typedef struct plperl_proc_desc{	char	   *proname;	TransactionId fn_xmin;	CommandId	fn_cmin;	bool		lanpltrusted;	FmgrInfo	result_in_func;	Oid			result_in_elem;	int			nargs;	FmgrInfo	arg_out_func[FUNC_MAX_ARGS];	Oid			arg_out_elem[FUNC_MAX_ARGS];	int			arg_is_rel[FUNC_MAX_ARGS];	SV		   *reference;}	plperl_proc_desc;/********************************************************************** * Global data **********************************************************************/static int	plperl_firstcall = 1;static PerlInterpreter *plperl_interp = NULL;static HV  *plperl_proc_hash = NULL;/********************************************************************** * Forward declarations **********************************************************************/static void plperl_init_all(void);static void plperl_init_interp(void);Datum		plperl_call_handler(PG_FUNCTION_ARGS);void		plperl_init(void);static Datum plperl_func_handler(PG_FUNCTION_ARGS);static plperl_proc_desc *compile_plperl_function(Oid fn_oid, bool is_trigger);static SV  *plperl_build_tuple_argument(HeapTuple tuple, TupleDesc tupdesc);static void plperl_init_shared_libs(pTHX);/* * This routine is a crock, and so is everyplace that calls it.  The problem * is that the cached form of plperl 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);}/********************************************************************** * plperl_init()			- Initialize everything that can be *							  safely initialized during postmaster *							  startup. * * DO NOT make this static --- it has to be callable by preload **********************************************************************/voidplperl_init(void){	/************************************************************	 * Do initialization only once	 ************************************************************/	if (!plperl_firstcall)		return;	/************************************************************	 * Free the proc hash table	 ************************************************************/	if (plperl_proc_hash != NULL)	{		hv_undef(plperl_proc_hash);		SvREFCNT_dec((SV *) plperl_proc_hash);		plperl_proc_hash = NULL;	}	/************************************************************	 * Destroy the existing Perl interpreter	 ************************************************************/	if (plperl_interp != NULL)	{		perl_destruct(plperl_interp);		perl_free(plperl_interp);		plperl_interp = NULL;	}	/************************************************************	 * Now recreate a new Perl interpreter	 ************************************************************/	plperl_init_interp();	plperl_firstcall = 0;}/********************************************************************** * plperl_init_all()		- Initialize all **********************************************************************/static voidplperl_init_all(void){	/************************************************************	 * Execute postmaster-startup safe initialization	 ************************************************************/	if (plperl_firstcall)		plperl_init();	/************************************************************	 * Any other initialization that must be done each time a new	 * backend starts -- currently none	 ************************************************************/}/********************************************************************** * plperl_init_interp() - Create the Perl interpreter **********************************************************************/static voidplperl_init_interp(void){	char	   *embedding[3] = {		"", "-e",		/*		 * no commas between the next 5 please. They are supposed to be		 * one string		 */		"require Safe; SPI::bootstrap();"		"sub ::mksafefunc { my $x = new Safe; $x->permit_only(':default');$x->permit(':base_math');"		"$x->share(qw[&elog &DEBUG &LOG &INFO &NOTICE &WARNING &ERROR]);"		" return $x->reval(qq[sub { $_[0] }]); }"		"sub ::mkunsafefunc {return eval(qq[ sub { $_[0] } ]); }"	};	plperl_interp = perl_alloc();	if (!plperl_interp)		elog(ERROR, "could not allocate perl interpreter");	perl_construct(plperl_interp);	perl_parse(plperl_interp, plperl_init_shared_libs, 3, embedding, NULL);	perl_run(plperl_interp);	/************************************************************	 * Initialize the proc and query hash tables	 ************************************************************/	plperl_proc_hash = newHV();}/********************************************************************** * plperl_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 *				  perl procedures. **********************************************************************/PG_FUNCTION_INFO_V1(plperl_call_handler);/* keep non-static */Datumplperl_call_handler(PG_FUNCTION_ARGS){	Datum		retval;	/************************************************************	 * Initialize interpreter	 ************************************************************/	plperl_init_all();	/************************************************************	 * Connect to SPI manager	 ************************************************************/	if (SPI_connect() != SPI_OK_CONNECT)		elog(ERROR, "could not connect to SPI manager");	/************************************************************	 * Determine if called as function or trigger and	 * call appropriate subhandler	 ************************************************************/	if (CALLED_AS_TRIGGER(fcinfo))	{		ereport(ERROR,				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),				 errmsg("cannot use perl in triggers yet")));		/*		 * retval = PointerGetDatum(plperl_trigger_handler(fcinfo));		 */		/* make the compiler happy */		retval = (Datum) 0;	}	else		retval = plperl_func_handler(fcinfo);	return retval;}/********************************************************************** * plperl_create_sub()		- calls the perl interpreter to *		create the anonymous subroutine whose text is in the SV. *		Returns the SV containing the RV to the closure. **********************************************************************/static SV  *plperl_create_sub(char *s, bool trusted){	dSP;	SV		   *subref;	int			count;	ENTER;	SAVETMPS;	PUSHMARK(SP);	XPUSHs(sv_2mortal(newSVpv(s, 0)));	PUTBACK;	/*	 * G_KEEPERR seems to be needed here, else we don't recognize compile	 * errors properly.  Perhaps it's because there's another level of	 * eval inside mksafefunc?	 */	count = perl_call_pv((trusted ? "mksafefunc" : "mkunsafefunc"),						 G_SCALAR | G_EVAL | G_KEEPERR);	SPAGAIN;	if (count != 1)	{		PUTBACK;		FREETMPS;		LEAVE;		elog(ERROR, "didn't get a return item from mksafefunc");	}	if (SvTRUE(ERRSV))	{		POPs;		PUTBACK;		FREETMPS;		LEAVE;		elog(ERROR, "creation of function failed: %s", SvPV(ERRSV, PL_na));	}	/*	 * need to make a deep copy of the return. it comes off the stack as a	 * temporary.	 */	subref = newSVsv(POPs);	if (!SvROK(subref))	{		PUTBACK;		FREETMPS;		LEAVE;		/*		 * subref is our responsibility because it is not mortal		 */		SvREFCNT_dec(subref);		elog(ERROR, "didn't get a code ref");	}	PUTBACK;	FREETMPS;	LEAVE;	return subref;}/********************************************************************** * plperl_init_shared_libs()		- * * We cannot use the DynaLoader directly to get at the Opcode * module (used by Safe.pm). So, we link Opcode into ourselves * and do the initialization behind perl's back. * **********************************************************************/EXTERN_C void boot_DynaLoader(pTHX_ CV * cv);EXTERN_C void boot_SPI(pTHX_ CV * cv);static voidplperl_init_shared_libs(pTHX){	char	   *file = __FILE__;	newXS("DynaLoader::boot_DynaLoader", boot_DynaLoader, file);	newXS("SPI::bootstrap", boot_SPI, file);}/********************************************************************** * plperl_call_perl_func()		- calls a perl function through the RV *			stored in the prodesc structure. massages the input parms properly **********************************************************************/static SV  *plperl_call_perl_func(plperl_proc_desc * desc, FunctionCallInfo fcinfo){	dSP;	SV		   *retval;	int			i;	int			count;	ENTER;	SAVETMPS;	PUSHMARK(SP);	for (i = 0; i < desc->nargs; i++)	{		if (desc->arg_is_rel[i])		{			TupleTableSlot *slot = (TupleTableSlot *) fcinfo->arg[i];			SV		   *hashref;			Assert(slot != NULL && !fcinfo->argnull[i]);			/*			 * plperl_build_tuple_argument better return a mortal SV.			 */			hashref = plperl_build_tuple_argument(slot->val,											  slot->ttc_tupleDescriptor);			XPUSHs(hashref);		}		else		{			if (fcinfo->argnull[i])

⌨️ 快捷键说明

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