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

📄 plperl.c

📁 PostgreSQL 8.1.4的源码 适用于Linux下的开源数据库系统
💻 C
📖 第 1 页 / 共 4 页
字号:
{	TriggerData *tdata;	TupleDesc	tupdesc;	int			i;	char	   *level;	char	   *event;	char	   *relid;	char	   *when;	HV		   *hv;	hv = newHV();	tdata = (TriggerData *) fcinfo->context;	tupdesc = tdata->tg_relation->rd_att;	relid = DatumGetCString(							DirectFunctionCall1(oidout,								  ObjectIdGetDatum(tdata->tg_relation->rd_id)												)		);	hv_store(hv, "name", 4, newSVpv(tdata->tg_trigger->tgname, 0), 0);	hv_store(hv, "relid", 5, newSVpv(relid, 0), 0);	if (TRIGGER_FIRED_BY_INSERT(tdata->tg_event))	{		event = "INSERT";		if (TRIGGER_FIRED_FOR_ROW(tdata->tg_event))			hv_store(hv, "new", 3,					 plperl_hash_from_tuple(tdata->tg_trigtuple, tupdesc),					 0);	}	else if (TRIGGER_FIRED_BY_DELETE(tdata->tg_event))	{		event = "DELETE";		if (TRIGGER_FIRED_FOR_ROW(tdata->tg_event))			hv_store(hv, "old", 3,					 plperl_hash_from_tuple(tdata->tg_trigtuple, tupdesc),					 0);	}	else if (TRIGGER_FIRED_BY_UPDATE(tdata->tg_event))	{		event = "UPDATE";		if (TRIGGER_FIRED_FOR_ROW(tdata->tg_event))		{			hv_store(hv, "old", 3,					 plperl_hash_from_tuple(tdata->tg_trigtuple, tupdesc),					 0);			hv_store(hv, "new", 3,					 plperl_hash_from_tuple(tdata->tg_newtuple, tupdesc),					 0);		}	}	else		event = "UNKNOWN";	hv_store(hv, "event", 5, newSVpv(event, 0), 0);	hv_store(hv, "argc", 4, newSViv(tdata->tg_trigger->tgnargs), 0);	if (tdata->tg_trigger->tgnargs > 0)	{		AV		   *av = newAV();		for (i = 0; i < tdata->tg_trigger->tgnargs; i++)			av_push(av, newSVpv(tdata->tg_trigger->tgargs[i], 0));		hv_store(hv, "args", 4, newRV_noinc((SV *) av), 0);	}	hv_store(hv, "relname", 7,			 newSVpv(SPI_getrelname(tdata->tg_relation), 0), 0);	if (TRIGGER_FIRED_BEFORE(tdata->tg_event))		when = "BEFORE";	else if (TRIGGER_FIRED_AFTER(tdata->tg_event))		when = "AFTER";	else		when = "UNKNOWN";	hv_store(hv, "when", 4, newSVpv(when, 0), 0);	if (TRIGGER_FIRED_FOR_ROW(tdata->tg_event))		level = "ROW";	else if (TRIGGER_FIRED_FOR_STATEMENT(tdata->tg_event))		level = "STATEMENT";	else		level = "UNKNOWN";	hv_store(hv, "level", 5, newSVpv(level, 0), 0);	return newRV_noinc((SV *) hv);}/* Set up the new tuple returned from a trigger. */static HeapTupleplperl_modify_tuple(HV *hvTD, TriggerData *tdata, HeapTuple otup){	SV		  **svp;	HV		   *hvNew;	HeapTuple	rtup;	SV		   *val;	char	   *key;	I32			klen;	int			slotsused;	int		   *modattrs;	Datum	   *modvalues;	char	   *modnulls;	TupleDesc	tupdesc;	tupdesc = tdata->tg_relation->rd_att;	svp = hv_fetch(hvTD, "new", 3, FALSE);	if (!svp)		ereport(ERROR,				(errcode(ERRCODE_UNDEFINED_COLUMN),				 errmsg("$_TD->{new} does not exist")));	if (!SvOK(*svp) || SvTYPE(*svp) != SVt_RV || SvTYPE(SvRV(*svp)) != SVt_PVHV)		ereport(ERROR,				(errcode(ERRCODE_DATATYPE_MISMATCH),				 errmsg("$_TD->{new} is not a hash reference")));	hvNew = (HV *) SvRV(*svp);	modattrs = palloc(tupdesc->natts * sizeof(int));	modvalues = palloc(tupdesc->natts * sizeof(Datum));	modnulls = palloc(tupdesc->natts * sizeof(char));	slotsused = 0;	hv_iterinit(hvNew);	while ((val = hv_iternextsv(hvNew, &key, &klen)))	{		int			attn = SPI_fnumber(tupdesc, key);		if (attn <= 0 || tupdesc->attrs[attn - 1]->attisdropped)			ereport(ERROR,					(errcode(ERRCODE_UNDEFINED_COLUMN),					 errmsg("Perl hash contains nonexistent column \"%s\"",							key)));		if (SvOK(val) && SvTYPE(val) != SVt_NULL)		{			Oid			typinput;			Oid			typioparam;			FmgrInfo	finfo;			/* XXX would be better to cache these lookups */			getTypeInputInfo(tupdesc->attrs[attn - 1]->atttypid,							 &typinput, &typioparam);			fmgr_info(typinput, &finfo);			modvalues[slotsused] = FunctionCall3(&finfo,										   CStringGetDatum(SvPV(val, PL_na)),												 ObjectIdGetDatum(typioparam),						 Int32GetDatum(tupdesc->attrs[attn - 1]->atttypmod));			modnulls[slotsused] = ' ';		}		else		{			modvalues[slotsused] = (Datum) 0;			modnulls[slotsused] = 'n';		}		modattrs[slotsused] = attn;		slotsused++;	}	hv_iterinit(hvNew);	rtup = SPI_modifytuple(tdata->tg_relation, otup, slotsused,						   modattrs, modvalues, modnulls);	pfree(modattrs);	pfree(modvalues);	pfree(modnulls);	if (rtup == NULL)		elog(ERROR, "SPI_modifytuple failed: %s",			 SPI_result_code_string(SPI_result));	return rtup;}/* * This is the only externally-visible part of the plperl call interface. * The Postgres function and trigger managers call it to execute a * perl function. */PG_FUNCTION_INFO_V1(plperl_call_handler);Datumplperl_call_handler(PG_FUNCTION_ARGS){	Datum		retval;	plperl_call_data *save_call_data;	plperl_init_all();	save_call_data = current_call_data;	PG_TRY();	{		if (CALLED_AS_TRIGGER(fcinfo))			retval = PointerGetDatum(plperl_trigger_handler(fcinfo));		else			retval = plperl_func_handler(fcinfo);	}	PG_CATCH();	{		current_call_data = save_call_data;		PG_RE_THROW();	}	PG_END_TRY();	current_call_data = save_call_data;	return retval;}/* * This is the other externally visible function - it is called when CREATE * FUNCTION is issued to validate the function being created/replaced. */PG_FUNCTION_INFO_V1(plperl_validator);Datumplperl_validator(PG_FUNCTION_ARGS){	Oid			funcoid = PG_GETARG_OID(0);	HeapTuple	tuple;	Form_pg_proc proc;	bool		istrigger = false;	plperl_proc_desc *prodesc;	plperl_init_all();	/* Get the new function's pg_proc entry */	tuple = SearchSysCache(PROCOID,						   ObjectIdGetDatum(funcoid),						   0, 0, 0);	if (!HeapTupleIsValid(tuple))		elog(ERROR, "cache lookup failed for function %u", funcoid);	proc = (Form_pg_proc) GETSTRUCT(tuple);	/* we assume OPAQUE with no arguments means a trigger */	if (proc->prorettype == TRIGGEROID ||		(proc->prorettype == OPAQUEOID && proc->pronargs == 0))		istrigger = true;	ReleaseSysCache(tuple);	prodesc = compile_plperl_function(funcoid, istrigger);	/* the result of a validator is ignored */	PG_RETURN_VOID();}/* Uses mksafefunc/mkunsafefunc to create an anonymous sub whose text is * supplied in s, and returns a reference to the closure. */static SV  *plperl_create_sub(char *s, bool trusted){	dSP;	SV		   *subref;	int			count;	char	   *compile_sub;	if (trusted && !plperl_safe_init_done)	{		plperl_safe_init();		SPAGAIN;	}	ENTER;	SAVETMPS;	PUSHMARK(SP);	XPUSHs(sv_2mortal(newSVpv("my $_TD=$_[0]; shift;", 0)));	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?	 */	if (trusted && plperl_use_strict)		compile_sub = "::mk_strict_safefunc";	else if (plperl_use_strict)		compile_sub = "::mk_strict_unsafefunc";	else if (trusted)		compile_sub = "::mksafefunc";	else		compile_sub = "::mkunsafefunc";	count = perl_call_pv(compile_sub, 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))	{		(void) POPs;		PUTBACK;		FREETMPS;		LEAVE;		ereport(ERROR,				(errcode(ERRCODE_SYNTAX_ERROR),				 errmsg("creation of Perl function failed: %s",						strip_trailing_ws(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) || SvTYPE(SvRV(subref)) != SVt_PVCV)	{		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);}static SV  *plperl_call_perl_func(plperl_proc_desc *desc, FunctionCallInfo fcinfo){	dSP;	SV		   *retval;	int			i;	int			count;	SV		   *sv;	ENTER;	SAVETMPS;	PUSHMARK(SP);	XPUSHs(&PL_sv_undef);		/* no trigger data */	for (i = 0; i < desc->nargs; i++)	{		if (fcinfo->argnull[i])			XPUSHs(&PL_sv_undef);		else if (desc->arg_is_rowtype[i])		{			HeapTupleHeader td;			Oid			tupType;			int32		tupTypmod;			TupleDesc	tupdesc;			HeapTupleData tmptup;			SV		   *hashref;			td = DatumGetHeapTupleHeader(fcinfo->arg[i]);			/* Extract rowtype info and find a tupdesc */			tupType = HeapTupleHeaderGetTypeId(td);			tupTypmod = HeapTupleHeaderGetTypMod(td);			tupdesc = lookup_rowtype_tupdesc(tupType, tupTypmod);			tupdesc = CreateTupleDescCopy(tupdesc);			/* Build a temporary HeapTuple control structure */			tmptup.t_len = HeapTupleHeaderGetDatumLength(td);			tmptup.t_data = td;			hashref = plperl_hash_from_tuple(&tmptup, tupdesc);			XPUSHs(sv_2mortal(hashref));			FreeTupleDesc(tupdesc);		}		else		{			char	   *tmp;			tmp = DatumGetCString(FunctionCall1(&(desc->arg_out_func[i]),												fcinfo->arg[i]));			sv = newSVpv(tmp, 0);#if PERL_BCDVERSION >= 0x5006000L			if (GetDatabaseEncoding() == PG_UTF8)				SvUTF8_on(sv);#endif			XPUSHs(sv_2mortal(sv));			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))	{		(void) POPs;		PUTBACK;		FREETMPS;		LEAVE;		/* XXX need to find a way to assign an errcode here */		ereport(ERROR,				(errmsg("error from Perl function: %s",						strip_trailing_ws(SvPV(ERRSV, PL_na)))));	}	retval = newSVsv(POPs);	PUTBACK;	FREETMPS;	LEAVE;	return retval;}static SV  *plperl_call_perl_trigger_func(plperl_proc_desc *desc, FunctionCallInfo fcinfo,							  SV *td){	dSP;	SV		   *retval;	Trigger    *tg_trigger;	int			i;	int			count;	ENTER;	SAVETMPS;	PUSHMARK(sp);	XPUSHs(td);	tg_trigger = ((TriggerData *) fcinfo->context)->tg_trigger;	for (i = 0; i < tg_trigger->tgnargs; i++)		XPUSHs(sv_2mortal(newSVpv(tg_trigger->tgargs[i], 0)));	PUTBACK;	/* Do NOT use G_KEEPERR here */	count = perl_call_sv(desc->reference, G_SCALAR | G_EVAL);

⌨️ 快捷键说明

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