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

📄 plperl.c

📁 PostgreSQL7.4.6 for Linux
💻 C
📖 第 1 页 / 共 2 页
字号:
				XPUSHs(&PL_sv_undef);			else			{				char	   *tmp;				tmp = DatumGetCString(FunctionCall3(&(desc->arg_out_func[i]),													fcinfo->arg[i],								 ObjectIdGetDatum(desc->arg_out_elem[i]),													Int32GetDatum(-1)));				XPUSHs(sv_2mortal(newSVpv(tmp, 0)));				pfree(tmp);			}		}	}	PUTBACK;	/* Do NOT use G_KEEPERR here */	count = perl_call_sv(desc->reference, G_SCALAR | G_EVAL);	SPAGAIN;	if (count != 1)	{		PUTBACK;		FREETMPS;		LEAVE;		elog(ERROR, "didn't get a return item from function");	}	if (SvTRUE(ERRSV))	{		POPs;		PUTBACK;		FREETMPS;		LEAVE;		elog(ERROR, "error from function: %s", SvPV(ERRSV, PL_na));	}	retval = newSVsv(POPs);	PUTBACK;	FREETMPS;	LEAVE;	return retval;}/********************************************************************** * plperl_func_handler()		- Handler for regular function calls **********************************************************************/static Datumplperl_func_handler(PG_FUNCTION_ARGS){	plperl_proc_desc *prodesc;	SV		   *perlret;	Datum		retval;	/* Find or compile the function */	prodesc = compile_plperl_function(fcinfo->flinfo->fn_oid, false);	/************************************************************	 * Call the Perl function	 ************************************************************/	perlret = plperl_call_perl_func(prodesc, fcinfo);	/************************************************************	 * Disconnect from SPI manager and then create the return	 * values datum (if the input function does a palloc for it	 * this must not be allocated in the SPI memory context	 * because SPI_finish would free it).	 ************************************************************/	if (SPI_finish() != SPI_OK_FINISH)		elog(ERROR, "SPI_finish() failed");	if (!(perlret && SvOK(perlret)))	{		/* return NULL if Perl code returned undef */		retval = (Datum) 0;		fcinfo->isnull = true;	}	else	{		retval = FunctionCall3(&prodesc->result_in_func,							   PointerGetDatum(SvPV(perlret, PL_na)),							   ObjectIdGetDatum(prodesc->result_in_elem),							   Int32GetDatum(-1));	}	SvREFCNT_dec(perlret);	return retval;}/********************************************************************** * compile_plperl_function	- compile (or hopefully just look up) function **********************************************************************/static plperl_proc_desc *compile_plperl_function(Oid fn_oid, bool is_trigger){	HeapTuple	procTup;	Form_pg_proc procStruct;	char		internal_proname[64];	int			proname_len;	plperl_proc_desc *prodesc = NULL;	int			i;	/* We'll need the pg_proc tuple in any case... */	procTup = SearchSysCache(PROCOID,							 ObjectIdGetDatum(fn_oid),							 0, 0, 0);	if (!HeapTupleIsValid(procTup))		elog(ERROR, "cache lookup failed for function %u", fn_oid);	procStruct = (Form_pg_proc) GETSTRUCT(procTup);	/************************************************************	 * Build our internal proc name from the functions Oid	 ************************************************************/	if (!is_trigger)		sprintf(internal_proname, "__PLPerl_proc_%u", fn_oid);	else		sprintf(internal_proname, "__PLPerl_proc_%u_trigger", fn_oid);	proname_len = strlen(internal_proname);	/************************************************************	 * Lookup the internal proc name in the hashtable	 ************************************************************/	if (hv_exists(plperl_proc_hash, internal_proname, proname_len))	{		bool		uptodate;		prodesc = (plperl_proc_desc *) SvIV(*hv_fetch(plperl_proc_hash,									  internal_proname, proname_len, 0));		/************************************************************		 * If it's present, must check whether it's still up to date.		 * This is needed because CREATE OR REPLACE FUNCTION can modify the		 * function's pg_proc entry without changing its OID.		 ************************************************************/		uptodate = (prodesc->fn_xmin == HeapTupleHeaderGetXmin(procTup->t_data) &&			prodesc->fn_cmin == HeapTupleHeaderGetCmin(procTup->t_data));		if (!uptodate)		{			/* need we delete old entry? */			prodesc = NULL;		}	}	/************************************************************	 * If we haven't found it in the hashtable, we analyze	 * the functions arguments and returntype and store	 * the in-/out-functions in the prodesc block and create	 * a new hashtable entry for it.	 *	 * Then we load the procedure into the Perl interpreter.	 ************************************************************/	if (prodesc == NULL)	{		HeapTuple	langTup;		HeapTuple	typeTup;		Form_pg_language langStruct;		Form_pg_type typeStruct;		char	   *proc_source;		/************************************************************		 * Allocate a new procedure description block		 ************************************************************/		prodesc = (plperl_proc_desc *) malloc(sizeof(plperl_proc_desc));		if (prodesc == NULL)			ereport(ERROR,					(errcode(ERRCODE_OUT_OF_MEMORY),					 errmsg("out of memory")));		MemSet(prodesc, 0, sizeof(plperl_proc_desc));		prodesc->proname = strdup(internal_proname);		prodesc->fn_xmin = HeapTupleHeaderGetXmin(procTup->t_data);		prodesc->fn_cmin = HeapTupleHeaderGetCmin(procTup->t_data);		/************************************************************		 * Lookup the pg_language tuple by Oid		 ************************************************************/		langTup = SearchSysCache(LANGOID,								 ObjectIdGetDatum(procStruct->prolang),								 0, 0, 0);		if (!HeapTupleIsValid(langTup))		{			free(prodesc->proname);			free(prodesc);			elog(ERROR, "cache lookup failed for language %u",				 procStruct->prolang);		}		langStruct = (Form_pg_language) GETSTRUCT(langTup);		prodesc->lanpltrusted = langStruct->lanpltrusted;		ReleaseSysCache(langTup);		/************************************************************		 * Get the required information for input conversion of the		 * return value.		 ************************************************************/		if (!is_trigger)		{			typeTup = SearchSysCache(TYPEOID,								ObjectIdGetDatum(procStruct->prorettype),									 0, 0, 0);			if (!HeapTupleIsValid(typeTup))			{				free(prodesc->proname);				free(prodesc);				elog(ERROR, "cache lookup failed for type %u",					 procStruct->prorettype);			}			typeStruct = (Form_pg_type) GETSTRUCT(typeTup);			/* Disallow pseudotype result, except VOID */			if (typeStruct->typtype == 'p')			{				if (procStruct->prorettype == VOIDOID)					 /* okay */ ;				else if (procStruct->prorettype == TRIGGEROID)				{					free(prodesc->proname);					free(prodesc);					ereport(ERROR,							(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),							 errmsg("trigger functions may only be called as triggers")));				}				else				{					free(prodesc->proname);					free(prodesc);					ereport(ERROR,							(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),						 errmsg("plperl functions cannot return type %s",								format_type_be(procStruct->prorettype))));				}			}			if (typeStruct->typrelid != InvalidOid)			{				free(prodesc->proname);				free(prodesc);				ereport(ERROR,						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),				   errmsg("plperl functions cannot return tuples yet")));			}			perm_fmgr_info(typeStruct->typinput, &(prodesc->result_in_func));			prodesc->result_in_elem = typeStruct->typelem;			ReleaseSysCache(typeTup);		}		/************************************************************		 * Get the required information for output conversion		 * of all procedure arguments		 ************************************************************/		if (!is_trigger)		{			prodesc->nargs = procStruct->pronargs;			for (i = 0; i < prodesc->nargs; i++)			{				typeTup = SearchSysCache(TYPEOID,							ObjectIdGetDatum(procStruct->proargtypes[i]),										 0, 0, 0);				if (!HeapTupleIsValid(typeTup))				{					free(prodesc->proname);					free(prodesc);					elog(ERROR, "cache lookup failed for type %u",						 procStruct->proargtypes[i]);				}				typeStruct = (Form_pg_type) GETSTRUCT(typeTup);				/* Disallow pseudotype argument */				if (typeStruct->typtype == 'p')				{					free(prodesc->proname);					free(prodesc);					ereport(ERROR,							(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),						   errmsg("plperl functions cannot take type %s",						   format_type_be(procStruct->proargtypes[i]))));				}				if (typeStruct->typrelid != InvalidOid)					prodesc->arg_is_rel[i] = 1;				else					prodesc->arg_is_rel[i] = 0;				perm_fmgr_info(typeStruct->typoutput, &(prodesc->arg_out_func[i]));				prodesc->arg_out_elem[i] = typeStruct->typelem;				ReleaseSysCache(typeTup);			}		}		/************************************************************		 * create the text of the anonymous subroutine.		 * we do not use a named subroutine so that we can call directly		 * through the reference.		 *		 ************************************************************/		proc_source = DatumGetCString(DirectFunctionCall1(textout,								  PointerGetDatum(&procStruct->prosrc)));		/************************************************************		 * Create the procedure in the interpreter		 ************************************************************/		prodesc->reference = plperl_create_sub(proc_source, prodesc->lanpltrusted);		pfree(proc_source);		if (!prodesc->reference)		{			free(prodesc->proname);			free(prodesc);			elog(ERROR, "could not create internal procedure \"%s\"",				 internal_proname);		}		/************************************************************		 * Add the proc description block to the hashtable		 ************************************************************/		hv_store(plperl_proc_hash, internal_proname, proname_len,				 newSViv((IV) prodesc), 0);	}	ReleaseSysCache(procTup);	return prodesc;}/********************************************************************** * plperl_build_tuple_argument() - Build a string for a ref to a hash *				  from all attributes of a given tuple **********************************************************************/static SV  *plperl_build_tuple_argument(HeapTuple tuple, TupleDesc tupdesc){	int			i;	SV		   *output;	Datum		attr;	bool		isnull;	char	   *attname;	char	   *outputstr;	HeapTuple	typeTup;	Oid			typoutput;	Oid			typelem;	output = sv_2mortal(newSVpv("{", 0));	for (i = 0; i < tupdesc->natts; i++)	{		/* ignore dropped attributes */		if (tupdesc->attrs[i]->attisdropped)			continue;		/************************************************************		 * Get the attribute name		 ************************************************************/		attname = tupdesc->attrs[i]->attname.data;		/************************************************************		 * Get the attributes value		 ************************************************************/		attr = heap_getattr(tuple, i + 1, tupdesc, &isnull);		/************************************************************		 *	If it is null it will be set to undef in the hash.		 ************************************************************/		if (isnull)		{			sv_catpvf(output, "'%s' => undef,", attname);			continue;		}		/************************************************************		 * Lookup the attribute type in the syscache		 * for the output function		 ************************************************************/		typeTup = SearchSysCache(TYPEOID,						   ObjectIdGetDatum(tupdesc->attrs[i]->atttypid),								 0, 0, 0);		if (!HeapTupleIsValid(typeTup))			elog(ERROR, "cache lookup failed for type %u",				 tupdesc->attrs[i]->atttypid);		typoutput = ((Form_pg_type) GETSTRUCT(typeTup))->typoutput;		typelem = ((Form_pg_type) GETSTRUCT(typeTup))->typelem;		ReleaseSysCache(typeTup);		/************************************************************		 * Append the attribute name and the value to the list.		 ************************************************************/		outputstr = DatumGetCString(OidFunctionCall3(typoutput,													 attr,											   ObjectIdGetDatum(typelem),						   Int32GetDatum(tupdesc->attrs[i]->atttypmod)));		sv_catpvf(output, "'%s' => '%s',", attname, outputstr);		pfree(outputstr);	}	sv_catpv(output, "}");	output = perl_eval_pv(SvPV(output, PL_na), TRUE);	return output;}

⌨️ 快捷键说明

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