fmgr.c

来自「postgresql8.3.4源码,开源数据库」· C语言 代码 · 共 2,224 行 · 第 1/4 页

C
2,224
字号
 * This is inherently somewhat bogus since we can't reliably duplicate * language-dependent subsidiary info.	We cheat by zeroing fn_extra, * instead, meaning that subsidiary info will have to be recomputed. */voidfmgr_info_copy(FmgrInfo *dstinfo, FmgrInfo *srcinfo,			   MemoryContext destcxt){	memcpy(dstinfo, srcinfo, sizeof(FmgrInfo));	dstinfo->fn_mcxt = destcxt;	if (dstinfo->fn_addr == fmgr_oldstyle)	{		/* For oldstyle functions we must copy fn_extra */		Oldstyle_fnextra *fnextra;		fnextra = (Oldstyle_fnextra *)			MemoryContextAlloc(destcxt, sizeof(Oldstyle_fnextra));		memcpy(fnextra, srcinfo->fn_extra, sizeof(Oldstyle_fnextra));		dstinfo->fn_extra = (void *) fnextra;	}	else		dstinfo->fn_extra = NULL;}/* * Specialized lookup routine for fmgr_internal_validator: given the alleged * name of an internal function, return the OID of the function. * If the name is not recognized, return InvalidOid. */Oidfmgr_internal_function(const char *proname){	const FmgrBuiltin *fbp = fmgr_lookupByName(proname);	if (fbp == NULL)		return InvalidOid;	return fbp->foid;}/* * Handler for old-style "C" language functions */static Datumfmgr_oldstyle(PG_FUNCTION_ARGS){	Oldstyle_fnextra *fnextra;	int			n_arguments = fcinfo->nargs;	int			i;	bool		isnull;	func_ptr	user_fn;	char	   *returnValue;	if (fcinfo->flinfo == NULL || fcinfo->flinfo->fn_extra == NULL)		elog(ERROR, "fmgr_oldstyle received NULL pointer");	fnextra = (Oldstyle_fnextra *) fcinfo->flinfo->fn_extra;	/*	 * Result is NULL if any argument is NULL, but we still call the function	 * (peculiar, but that's the way it worked before, and after all this is a	 * backwards-compatibility wrapper).  Note, however, that we'll never get	 * here with NULL arguments if the function is marked strict.	 *	 * We also need to detoast any TOAST-ed inputs, since it's unlikely that	 * an old-style function knows about TOASTing.	 */	isnull = false;	for (i = 0; i < n_arguments; i++)	{		if (PG_ARGISNULL(i))			isnull = true;		else if (fnextra->arg_toastable[i])			fcinfo->arg[i] = PointerGetDatum(PG_DETOAST_DATUM(fcinfo->arg[i]));	}	fcinfo->isnull = isnull;	user_fn = fnextra->func;	switch (n_arguments)	{		case 0:			returnValue = (char *) (*user_fn) ();			break;		case 1:			/*			 * nullvalue() used to use isNull to check if arg is NULL; perhaps			 * there are other functions still out there that also rely on			 * this undocumented hack?			 */			returnValue = (char *) (*user_fn) (fcinfo->arg[0],											   &fcinfo->isnull);			break;		case 2:			returnValue = (char *) (*user_fn) (fcinfo->arg[0],											   fcinfo->arg[1]);			break;		case 3:			returnValue = (char *) (*user_fn) (fcinfo->arg[0],											   fcinfo->arg[1],											   fcinfo->arg[2]);			break;		case 4:			returnValue = (char *) (*user_fn) (fcinfo->arg[0],											   fcinfo->arg[1],											   fcinfo->arg[2],											   fcinfo->arg[3]);			break;		case 5:			returnValue = (char *) (*user_fn) (fcinfo->arg[0],											   fcinfo->arg[1],											   fcinfo->arg[2],											   fcinfo->arg[3],											   fcinfo->arg[4]);			break;		case 6:			returnValue = (char *) (*user_fn) (fcinfo->arg[0],											   fcinfo->arg[1],											   fcinfo->arg[2],											   fcinfo->arg[3],											   fcinfo->arg[4],											   fcinfo->arg[5]);			break;		case 7:			returnValue = (char *) (*user_fn) (fcinfo->arg[0],											   fcinfo->arg[1],											   fcinfo->arg[2],											   fcinfo->arg[3],											   fcinfo->arg[4],											   fcinfo->arg[5],											   fcinfo->arg[6]);			break;		case 8:			returnValue = (char *) (*user_fn) (fcinfo->arg[0],											   fcinfo->arg[1],											   fcinfo->arg[2],											   fcinfo->arg[3],											   fcinfo->arg[4],											   fcinfo->arg[5],											   fcinfo->arg[6],											   fcinfo->arg[7]);			break;		case 9:			returnValue = (char *) (*user_fn) (fcinfo->arg[0],											   fcinfo->arg[1],											   fcinfo->arg[2],											   fcinfo->arg[3],											   fcinfo->arg[4],											   fcinfo->arg[5],											   fcinfo->arg[6],											   fcinfo->arg[7],											   fcinfo->arg[8]);			break;		case 10:			returnValue = (char *) (*user_fn) (fcinfo->arg[0],											   fcinfo->arg[1],											   fcinfo->arg[2],											   fcinfo->arg[3],											   fcinfo->arg[4],											   fcinfo->arg[5],											   fcinfo->arg[6],											   fcinfo->arg[7],											   fcinfo->arg[8],											   fcinfo->arg[9]);			break;		case 11:			returnValue = (char *) (*user_fn) (fcinfo->arg[0],											   fcinfo->arg[1],											   fcinfo->arg[2],											   fcinfo->arg[3],											   fcinfo->arg[4],											   fcinfo->arg[5],											   fcinfo->arg[6],											   fcinfo->arg[7],											   fcinfo->arg[8],											   fcinfo->arg[9],											   fcinfo->arg[10]);			break;		case 12:			returnValue = (char *) (*user_fn) (fcinfo->arg[0],											   fcinfo->arg[1],											   fcinfo->arg[2],											   fcinfo->arg[3],											   fcinfo->arg[4],											   fcinfo->arg[5],											   fcinfo->arg[6],											   fcinfo->arg[7],											   fcinfo->arg[8],											   fcinfo->arg[9],											   fcinfo->arg[10],											   fcinfo->arg[11]);			break;		case 13:			returnValue = (char *) (*user_fn) (fcinfo->arg[0],											   fcinfo->arg[1],											   fcinfo->arg[2],											   fcinfo->arg[3],											   fcinfo->arg[4],											   fcinfo->arg[5],											   fcinfo->arg[6],											   fcinfo->arg[7],											   fcinfo->arg[8],											   fcinfo->arg[9],											   fcinfo->arg[10],											   fcinfo->arg[11],											   fcinfo->arg[12]);			break;		case 14:			returnValue = (char *) (*user_fn) (fcinfo->arg[0],											   fcinfo->arg[1],											   fcinfo->arg[2],											   fcinfo->arg[3],											   fcinfo->arg[4],											   fcinfo->arg[5],											   fcinfo->arg[6],											   fcinfo->arg[7],											   fcinfo->arg[8],											   fcinfo->arg[9],											   fcinfo->arg[10],											   fcinfo->arg[11],											   fcinfo->arg[12],											   fcinfo->arg[13]);			break;		case 15:			returnValue = (char *) (*user_fn) (fcinfo->arg[0],											   fcinfo->arg[1],											   fcinfo->arg[2],											   fcinfo->arg[3],											   fcinfo->arg[4],											   fcinfo->arg[5],											   fcinfo->arg[6],											   fcinfo->arg[7],											   fcinfo->arg[8],											   fcinfo->arg[9],											   fcinfo->arg[10],											   fcinfo->arg[11],											   fcinfo->arg[12],											   fcinfo->arg[13],											   fcinfo->arg[14]);			break;		case 16:			returnValue = (char *) (*user_fn) (fcinfo->arg[0],											   fcinfo->arg[1],											   fcinfo->arg[2],											   fcinfo->arg[3],											   fcinfo->arg[4],											   fcinfo->arg[5],											   fcinfo->arg[6],											   fcinfo->arg[7],											   fcinfo->arg[8],											   fcinfo->arg[9],											   fcinfo->arg[10],											   fcinfo->arg[11],											   fcinfo->arg[12],											   fcinfo->arg[13],											   fcinfo->arg[14],											   fcinfo->arg[15]);			break;		default:			/*			 * Increasing FUNC_MAX_ARGS doesn't automatically add cases to the			 * above code, so mention the actual value in this error not			 * FUNC_MAX_ARGS.  You could add cases to the above if you needed			 * to support old-style functions with many arguments, but making			 * 'em be new-style is probably a better idea.			 */			ereport(ERROR,					(errcode(ERRCODE_TOO_MANY_ARGUMENTS),			 errmsg("function %u has too many arguments (%d, maximum is %d)",					fcinfo->flinfo->fn_oid, n_arguments, 16)));			returnValue = NULL; /* keep compiler quiet */			break;	}	return (Datum) returnValue;}/* * Support for security-definer and proconfig-using functions.	We support * both of these features using the same call handler, because they are * often used together and it would be inefficient (as well as notationally * messy) to have two levels of call handler involved. */struct fmgr_security_definer_cache{	FmgrInfo	flinfo;			/* lookup info for target function */	Oid			userid;			/* userid to set, or InvalidOid */	ArrayType  *proconfig;		/* GUC values to set, or NULL */};/* * Function handler for security-definer/proconfig functions.  We extract the * OID of the actual function and do a fmgr lookup again.  Then we fetch the * pg_proc row and copy the owner ID and proconfig fields.	(All this info * is cached for the duration of the current query.)  To execute a call, * we temporarily replace the flinfo with the cached/looked-up one, while * keeping the outer fcinfo (which contains all the actual arguments, etc.) * intact.	This is not re-entrant, but then the fcinfo itself can't be used * re-entrantly anyway. */static Datumfmgr_security_definer(PG_FUNCTION_ARGS){	Datum		result;	struct fmgr_security_definer_cache *volatile fcache;	FmgrInfo   *save_flinfo;	Oid			save_userid;	bool		save_secdefcxt;	volatile int save_nestlevel;	if (!fcinfo->flinfo->fn_extra)	{		HeapTuple	tuple;		Form_pg_proc procedureStruct;		Datum		datum;		bool		isnull;		MemoryContext oldcxt;		fcache = MemoryContextAllocZero(fcinfo->flinfo->fn_mcxt,										sizeof(*fcache));		fmgr_info_cxt_security(fcinfo->flinfo->fn_oid, &fcache->flinfo,							   fcinfo->flinfo->fn_mcxt, true);		fcache->flinfo.fn_expr = fcinfo->flinfo->fn_expr;		tuple = SearchSysCache(PROCOID,							   ObjectIdGetDatum(fcinfo->flinfo->fn_oid),							   0, 0, 0);		if (!HeapTupleIsValid(tuple))			elog(ERROR, "cache lookup failed for function %u",				 fcinfo->flinfo->fn_oid);		procedureStruct = (Form_pg_proc) GETSTRUCT(tuple);		if (procedureStruct->prosecdef)			fcache->userid = procedureStruct->proowner;		datum = SysCacheGetAttr(PROCOID, tuple, Anum_pg_proc_proconfig,								&isnull);		if (!isnull)		{			oldcxt = MemoryContextSwitchTo(fcinfo->flinfo->fn_mcxt);			fcache->proconfig = DatumGetArrayTypePCopy(datum);			MemoryContextSwitchTo(oldcxt);		}		ReleaseSysCache(tuple);		fcinfo->flinfo->fn_extra = fcache;	}	else		fcache = fcinfo->flinfo->fn_extra;	/* GetUserIdAndContext is cheap enough that no harm in a wasted call */	GetUserIdAndContext(&save_userid, &save_secdefcxt);	if (fcache->proconfig)		/* Need a new GUC nesting level */		save_nestlevel = NewGUCNestLevel();	else		save_nestlevel = 0;		/* keep compiler quiet */	if (OidIsValid(fcache->userid))		SetUserIdAndContext(fcache->userid, true);	if (fcache->proconfig)	{		ProcessGUCArray(fcache->proconfig,						(superuser() ? PGC_SUSET : PGC_USERSET),						PGC_S_SESSION,						GUC_ACTION_SAVE);	}	/*	 * We don't need to restore GUC or userid settings on error, because the	 * ensuing xact or subxact abort will do that.  The PG_TRY block is only	 * needed to clean up the flinfo link.	 */	save_flinfo = fcinfo->flinfo;	PG_TRY();	{		fcinfo->flinfo = &fcache->flinfo;		result = FunctionCallInvoke(fcinfo);	}	PG_CATCH();	{		fcinfo->flinfo = save_flinfo;		PG_RE_THROW();	}	PG_END_TRY();	fcinfo->flinfo = save_flinfo;	if (fcache->proconfig)		AtEOXact_GUC(true, save_nestlevel);	if (OidIsValid(fcache->userid))		SetUserIdAndContext(save_userid, save_secdefcxt);	return result;}/*------------------------------------------------------------------------- *		Support routines for callers of fmgr-compatible functions *------------------------------------------------------------------------- *//* * These are for invocation of a specifically named function with a * directly-computed parameter list.  Note that neither arguments nor result * are allowed to be NULL.	Also, the function cannot be one that needs to * look at FmgrInfo, since there won't be any. */DatumDirectFunctionCall1(PGFunction func, Datum arg1){	FunctionCallInfoData fcinfo;	Datum		result;	InitFunctionCallInfoData(fcinfo, NULL, 1, NULL, NULL);	fcinfo.arg[0] = arg1;	fcinfo.argnull[0] = false;	result = (*func) (&fcinfo);	/* Check for null result, since caller is clearly not expecting one */	if (fcinfo.isnull)		elog(ERROR, "function %p returned NULL", (void *) func);	return result;}DatumDirectFunctionCall2(PGFunction func, Datum arg1, Datum arg2){	FunctionCallInfoData fcinfo;	Datum		result;	InitFunctionCallInfoData(fcinfo, NULL, 2, NULL, NULL);	fcinfo.arg[0] = arg1;	fcinfo.arg[1] = arg2;	fcinfo.argnull[0] = false;	fcinfo.argnull[1] = false;	result = (*func) (&fcinfo);	/* Check for null result, since caller is clearly not expecting one */	if (fcinfo.isnull)		elog(ERROR, "function %p returned NULL", (void *) func);	return result;}DatumDirectFunctionCall3(PGFunction func, Datum arg1, Datum arg2,					Datum arg3){	FunctionCallInfoData fcinfo;	Datum		result;	InitFunctionCallInfoData(fcinfo, NULL, 3, NULL, NULL);	fcinfo.arg[0] = arg1;	fcinfo.arg[1] = arg2;	fcinfo.arg[2] = arg3;	fcinfo.argnull[0] = false;	fcinfo.argnull[1] = false;	fcinfo.argnull[2] = false;	result = (*func) (&fcinfo);	/* Check for null result, since caller is clearly not expecting one */	if (fcinfo.isnull)		elog(ERROR, "function %p returned NULL", (void *) func);	return result;}DatumDirectFunctionCall4(PGFunction func, Datum arg1, Datum arg2,					Datum arg3, Datum arg4){	FunctionCallInfoData fcinfo;	Datum		result;	InitFunctionCallInfoData(fcinfo, NULL, 4, NULL, NULL);	fcinfo.arg[0] = arg1;	fcinfo.arg[1] = arg2;	fcinfo.arg[2] = arg3;	fcinfo.arg[3] = arg4;	fcinfo.argnull[0] = false;	fcinfo.argnull[1] = false;	fcinfo.argnull[2] = false;	fcinfo.argnull[3] = false;	result = (*func) (&fcinfo);	/* Check for null result, since caller is clearly not expecting one */	if (fcinfo.isnull)		elog(ERROR, "function %p returned NULL", (void *) func);	return result;}DatumDirectFunctionCall5(PGFunction func, Datum arg1, Datum arg2,					Datum arg3, Datum arg4, Datum arg5){	FunctionCallInfoData fcinfo;	Datum		result;	InitFunctionCallInfoData(fcinfo, NULL, 5, NULL, NULL);	fcinfo.arg[0] = arg1;	fcinfo.arg[1] = arg2;	fcinfo.arg[2] = arg3;	fcinfo.arg[3] = arg4;	fcinfo.arg[4] = arg5;	fcinfo.argnull[0] = false;	fcinfo.argnull[1] = false;	fcinfo.argnull[2] = false;	fcinfo.argnull[3] = false;	fcinfo.argnull[4] = false;	result = (*func) (&fcinfo);	/* Check for null result, since caller is clearly not expecting one */	if (fcinfo.isnull)		elog(ERROR, "function %p returned NULL", (void *) func);	return result;}DatumDirectFunctionCall6(PGFunction func, Datum arg1, Datum arg2,					Datum arg3, Datum arg4, Datum arg5,					Datum arg6){	FunctionCallInfoData fcinfo;	Datum		result;	InitFunctionCallInfoData(fcinfo, NULL, 6, NULL, NULL);	fcinfo.arg[0] = arg1;	fcinfo.arg[1] = arg2;	fcinfo.arg[2] = arg3;	fcinfo.arg[3] = arg4;	fcinfo.arg[4] = arg5;	fcinfo.arg[5] = arg6;	fcinfo.argnull[0] = false;	fcinfo.argnull[1] = false;

⌨️ 快捷键说明

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