fmgr.c

来自「PostgreSQL 8.1.4的源码 适用于Linux下的开源数据库系统」· C语言 代码 · 共 1,918 行 · 第 1/4 页

C
1,918
字号
					HASH_FIND,					NULL);	if (entry == NULL)		return NULL;			/* no such entry */	if (entry->fn_xmin == HeapTupleHeaderGetXmin(procedureTuple->t_data) &&		entry->fn_cmin == HeapTupleHeaderGetCmin(procedureTuple->t_data))		return entry;			/* OK */	return NULL;				/* entry is out of date */}/* * record_C_func: enter (or update) info about a C function in the hash table */static voidrecord_C_func(HeapTuple procedureTuple,			  PGFunction user_fn, Pg_finfo_record *inforec){	Oid			fn_oid = HeapTupleGetOid(procedureTuple);	CFuncHashTabEntry *entry;	bool		found;	/* Create the hash table if it doesn't exist yet */	if (CFuncHash == NULL)	{		HASHCTL		hash_ctl;		MemSet(&hash_ctl, 0, sizeof(hash_ctl));		hash_ctl.keysize = sizeof(Oid);		hash_ctl.entrysize = sizeof(CFuncHashTabEntry);		hash_ctl.hash = oid_hash;		CFuncHash = hash_create("CFuncHash",								100,								&hash_ctl,								HASH_ELEM | HASH_FUNCTION);	}	entry = (CFuncHashTabEntry *)		hash_search(CFuncHash,					&fn_oid,					HASH_ENTER,					&found);	/* OID is already filled in */	entry->fn_xmin = HeapTupleHeaderGetXmin(procedureTuple->t_data);	entry->fn_cmin = HeapTupleHeaderGetCmin(procedureTuple->t_data);	entry->user_fn = user_fn;	entry->inforec = inforec;}/* * clear_external_function_hash: remove entries for a library being closed * * Presently we just zap the entire hash table, but later it might be worth * the effort to remove only the entries associated with the given handle. */voidclear_external_function_hash(void *filehandle){	if (CFuncHash)		hash_destroy(CFuncHash);	CFuncHash = NULL;}/* * Copy an FmgrInfo struct * * 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 = (*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 = (*user_fn) (fcinfo->arg[0], &fcinfo->isnull);			break;		case 2:			returnValue = (*user_fn) (fcinfo->arg[0], fcinfo->arg[1]);			break;		case 3:			returnValue = (*user_fn) (fcinfo->arg[0], fcinfo->arg[1],									  fcinfo->arg[2]);			break;		case 4:			returnValue = (*user_fn) (fcinfo->arg[0], fcinfo->arg[1],									  fcinfo->arg[2], fcinfo->arg[3]);			break;		case 5:			returnValue = (*user_fn) (fcinfo->arg[0], fcinfo->arg[1],									  fcinfo->arg[2], fcinfo->arg[3],									  fcinfo->arg[4]);			break;		case 6:			returnValue = (*user_fn) (fcinfo->arg[0], fcinfo->arg[1],									  fcinfo->arg[2], fcinfo->arg[3],									  fcinfo->arg[4], fcinfo->arg[5]);			break;		case 7:			returnValue = (*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 = (*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 = (*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 = (*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 = (*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 = (*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 = (*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 = (*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 = (*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 = (*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 functions */struct fmgr_security_definer_cache{	FmgrInfo	flinfo;	Oid			userid;};/* * Function handler for security definer functions.  We extract the * OID of the actual function and do a fmgr lookup again.  Then we * look up the owner of the function and cache both the fmgr info and * the owner ID.  During the 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. */static Datumfmgr_security_definer(PG_FUNCTION_ARGS){	Datum		result;	FmgrInfo   *save_flinfo;	struct fmgr_security_definer_cache *volatile fcache;	Oid			save_userid;	HeapTuple	tuple;	if (!fcinfo->flinfo->fn_extra)	{		fcache = MemoryContextAllocZero(fcinfo->flinfo->fn_mcxt,										sizeof(*fcache));		fmgr_info_cxt_security(fcinfo->flinfo->fn_oid, &fcache->flinfo,							   fcinfo->flinfo->fn_mcxt, true);		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);		fcache->userid = ((Form_pg_proc) GETSTRUCT(tuple))->proowner;		ReleaseSysCache(tuple);		fcinfo->flinfo->fn_extra = fcache;	}	else		fcache = fcinfo->flinfo->fn_extra;	save_flinfo = fcinfo->flinfo;	save_userid = GetUserId();	PG_TRY();	{		fcinfo->flinfo = &fcache->flinfo;		SetUserId(fcache->userid);		result = FunctionCallInvoke(fcinfo);	}	PG_CATCH();	{		fcinfo->flinfo = save_flinfo;		SetUserId(save_userid);		PG_RE_THROW();	}	PG_END_TRY();	fcinfo->flinfo = save_flinfo;	SetUserId(save_userid);	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;

⌨️ 快捷键说明

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