fmgr.c

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

C
1,918
字号
/*------------------------------------------------------------------------- * * fmgr.c *	  The Postgres function manager. * * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION *	  $PostgreSQL: pgsql/src/backend/utils/fmgr/fmgr.c,v 1.97.2.1 2005/11/22 18:23:23 momjian Exp $ * *------------------------------------------------------------------------- */#include "postgres.h"#include "access/tuptoaster.h"#include "catalog/pg_language.h"#include "catalog/pg_proc.h"#include "executor/functions.h"#include "miscadmin.h"#include "parser/parse_expr.h"#include "utils/builtins.h"#include "utils/fmgrtab.h"#include "utils/lsyscache.h"#include "utils/syscache.h"/* * Declaration for old-style function pointer type.  This is now used only * in fmgr_oldstyle() and is no longer exported. * * The m68k SVR4 ABI defines that pointers are returned in %a0 instead of * %d0. So if a function pointer is declared to return a pointer, the * compiler may look only into %a0, but if the called function was declared * to return an integer type, it puts its value only into %d0. So the * caller doesn't pick up the correct return value. The solution is to * declare the function pointer to return int, so the compiler picks up the * return value from %d0. (Functions returning pointers put their value * *additionally* into %d0 for compatibility.) The price is that there are * some warnings about int->pointer conversions... */#if (defined(__mc68000__) || (defined(__m68k__))) && defined(__ELF__)typedef int32 (*func_ptr) ();#elsetypedef char *(*func_ptr) ();#endif/* * For an oldstyle function, fn_extra points to a record like this: */typedef struct{	func_ptr	func;			/* Address of the oldstyle function */	bool		arg_toastable[FUNC_MAX_ARGS];	/* is n'th arg of a toastable												 * datatype? */} Oldstyle_fnextra;/* * Hashtable for fast lookup of external C functions */typedef struct{	/* fn_oid is the hash key and so must be first! */	Oid			fn_oid;			/* OID of an external C function */	TransactionId fn_xmin;		/* for checking up-to-dateness */	CommandId	fn_cmin;	PGFunction	user_fn;		/* the function's address */	Pg_finfo_record *inforec;	/* address of its info record */} CFuncHashTabEntry;static HTAB *CFuncHash = NULL;static void fmgr_info_cxt_security(Oid functionId, FmgrInfo *finfo, MemoryContext mcxt,					   bool ignore_security);static void fmgr_info_C_lang(Oid functionId, FmgrInfo *finfo, HeapTuple procedureTuple);static void fmgr_info_other_lang(Oid functionId, FmgrInfo *finfo, HeapTuple procedureTuple);static CFuncHashTabEntry *lookup_C_func(HeapTuple procedureTuple);static void record_C_func(HeapTuple procedureTuple,			  PGFunction user_fn, Pg_finfo_record *inforec);static Datum fmgr_oldstyle(PG_FUNCTION_ARGS);static Datum fmgr_security_definer(PG_FUNCTION_ARGS);/* * Lookup routines for builtin-function table.	We can search by either Oid * or name, but search by Oid is much faster. */static const FmgrBuiltin *fmgr_isbuiltin(Oid id){	int			low = 0;	int			high = fmgr_nbuiltins - 1;	/*	 * Loop invariant: low is the first index that could contain target entry,	 * and high is the last index that could contain it.	 */	while (low <= high)	{		int			i = (high + low) / 2;		const FmgrBuiltin *ptr = &fmgr_builtins[i];		if (id == ptr->foid)			return ptr;		else if (id > ptr->foid)			low = i + 1;		else			high = i - 1;	}	return NULL;}/* * Lookup a builtin by name.  Note there can be more than one entry in * the array with the same name, but they should all point to the same * routine. */static const FmgrBuiltin *fmgr_lookupByName(const char *name){	int			i;	for (i = 0; i < fmgr_nbuiltins; i++)	{		if (strcmp(name, fmgr_builtins[i].funcName) == 0)			return fmgr_builtins + i;	}	return NULL;}/* * This routine fills a FmgrInfo struct, given the OID * of the function to be called. * * The caller's CurrentMemoryContext is used as the fn_mcxt of the info * struct; this means that any subsidiary data attached to the info struct * (either by fmgr_info itself, or later on by a function call handler) * will be allocated in that context.  The caller must ensure that this * context is at least as long-lived as the info struct itself.  This is * not a problem in typical cases where the info struct is on the stack or * in freshly-palloc'd space.  However, if one intends to store an info * struct in a long-lived table, it's better to use fmgr_info_cxt. */voidfmgr_info(Oid functionId, FmgrInfo *finfo){	fmgr_info_cxt(functionId, finfo, CurrentMemoryContext);}/* * Fill a FmgrInfo struct, specifying a memory context in which its * subsidiary data should go. */voidfmgr_info_cxt(Oid functionId, FmgrInfo *finfo, MemoryContext mcxt){	fmgr_info_cxt_security(functionId, finfo, mcxt, false);}/* * This one does the actual work.  ignore_security is ordinarily false * but is set to true by fmgr_security_definer to avoid infinite * recursive lookups. */static voidfmgr_info_cxt_security(Oid functionId, FmgrInfo *finfo, MemoryContext mcxt,					   bool ignore_security){	const FmgrBuiltin *fbp;	HeapTuple	procedureTuple;	Form_pg_proc procedureStruct;	Datum		prosrcdatum;	bool		isnull;	char	   *prosrc;	/*	 * fn_oid *must* be filled in last.  Some code assumes that if fn_oid is	 * valid, the whole struct is valid.  Some FmgrInfo struct's do survive	 * elogs.	 */	finfo->fn_oid = InvalidOid;	finfo->fn_extra = NULL;	finfo->fn_mcxt = mcxt;	finfo->fn_expr = NULL;		/* caller may set this later */	if ((fbp = fmgr_isbuiltin(functionId)) != NULL)	{		/*		 * Fast path for builtin functions: don't bother consulting pg_proc		 */		finfo->fn_nargs = fbp->nargs;		finfo->fn_strict = fbp->strict;		finfo->fn_retset = fbp->retset;		finfo->fn_addr = fbp->func;		finfo->fn_oid = functionId;		return;	}	/* Otherwise we need the pg_proc entry */	procedureTuple = SearchSysCache(PROCOID,									ObjectIdGetDatum(functionId),									0, 0, 0);	if (!HeapTupleIsValid(procedureTuple))		elog(ERROR, "cache lookup failed for function %u", functionId);	procedureStruct = (Form_pg_proc) GETSTRUCT(procedureTuple);	finfo->fn_nargs = procedureStruct->pronargs;	finfo->fn_strict = procedureStruct->proisstrict;	finfo->fn_retset = procedureStruct->proretset;	if (procedureStruct->prosecdef && !ignore_security)	{		finfo->fn_addr = fmgr_security_definer;		finfo->fn_oid = functionId;		ReleaseSysCache(procedureTuple);		return;	}	switch (procedureStruct->prolang)	{		case INTERNALlanguageId:			/*			 * For an ordinary builtin function, we should never get here			 * because the isbuiltin() search above will have succeeded.			 * However, if the user has done a CREATE FUNCTION to create an			 * alias for a builtin function, we can end up here.  In that case			 * we have to look up the function by name.  The name of the			 * internal function is stored in prosrc (it doesn't have to be			 * the same as the name of the alias!)			 */			prosrcdatum = SysCacheGetAttr(PROCOID, procedureTuple,										  Anum_pg_proc_prosrc, &isnull);			if (isnull)				elog(ERROR, "null prosrc");			prosrc = DatumGetCString(DirectFunctionCall1(textout,														 prosrcdatum));			fbp = fmgr_lookupByName(prosrc);			if (fbp == NULL)				ereport(ERROR,						(errcode(ERRCODE_UNDEFINED_FUNCTION),						 errmsg("internal function \"%s\" is not in internal lookup table",								prosrc)));			pfree(prosrc);			/* Should we check that nargs, strict, retset match the table? */			finfo->fn_addr = fbp->func;			break;		case ClanguageId:			fmgr_info_C_lang(functionId, finfo, procedureTuple);			break;		case SQLlanguageId:			finfo->fn_addr = fmgr_sql;			break;		default:			fmgr_info_other_lang(functionId, finfo, procedureTuple);			break;	}	finfo->fn_oid = functionId;	ReleaseSysCache(procedureTuple);}/* * Special fmgr_info processing for C-language functions.  Note that * finfo->fn_oid is not valid yet. */static voidfmgr_info_C_lang(Oid functionId, FmgrInfo *finfo, HeapTuple procedureTuple){	Form_pg_proc procedureStruct = (Form_pg_proc) GETSTRUCT(procedureTuple);	CFuncHashTabEntry *hashentry;	PGFunction	user_fn;	Pg_finfo_record *inforec;	Oldstyle_fnextra *fnextra;	bool		isnull;	int			i;	/*	 * See if we have the function address cached already	 */	hashentry = lookup_C_func(procedureTuple);	if (hashentry)	{		user_fn = hashentry->user_fn;		inforec = hashentry->inforec;	}	else	{		Datum		prosrcattr,					probinattr;		char	   *prosrcstring,				   *probinstring;		void	   *libraryhandle;		/*		 * Get prosrc and probin strings (link symbol and library filename)		 */		prosrcattr = SysCacheGetAttr(PROCOID, procedureTuple,									 Anum_pg_proc_prosrc, &isnull);		if (isnull)			elog(ERROR, "null prosrc for function %u", functionId);		prosrcstring = DatumGetCString(DirectFunctionCall1(textout,														   prosrcattr));		probinattr = SysCacheGetAttr(PROCOID, procedureTuple,									 Anum_pg_proc_probin, &isnull);		if (isnull)			elog(ERROR, "null probin for function %u", functionId);		probinstring = DatumGetCString(DirectFunctionCall1(textout,														   probinattr));		/* Look up the function itself */		user_fn = load_external_function(probinstring, prosrcstring, true,										 &libraryhandle);		/* Get the function information record (real or default) */		inforec = fetch_finfo_record(libraryhandle, prosrcstring);		/* Cache the addresses for later calls */		record_C_func(procedureTuple, user_fn, inforec);		pfree(prosrcstring);		pfree(probinstring);	}	switch (inforec->api_version)	{		case 0:			/* Old style: need to use a handler */			finfo->fn_addr = fmgr_oldstyle;			fnextra = (Oldstyle_fnextra *)				MemoryContextAllocZero(finfo->fn_mcxt,									   sizeof(Oldstyle_fnextra));			finfo->fn_extra = (void *) fnextra;			fnextra->func = (func_ptr) user_fn;			for (i = 0; i < procedureStruct->pronargs; i++)			{				fnextra->arg_toastable[i] =					TypeIsToastable(procedureStruct->proargtypes.values[i]);			}			break;		case 1:			/* New style: call directly */			finfo->fn_addr = user_fn;			break;		default:			/* Shouldn't get here if fetch_finfo_record did its job */			elog(ERROR, "unrecognized function API version: %d",				 inforec->api_version);			break;	}}/* * Special fmgr_info processing for other-language functions.  Note * that finfo->fn_oid is not valid yet. */static voidfmgr_info_other_lang(Oid functionId, FmgrInfo *finfo, HeapTuple procedureTuple){	Form_pg_proc procedureStruct = (Form_pg_proc) GETSTRUCT(procedureTuple);	Oid			language = procedureStruct->prolang;	HeapTuple	languageTuple;	Form_pg_language languageStruct;	FmgrInfo	plfinfo;	languageTuple = SearchSysCache(LANGOID,								   ObjectIdGetDatum(language),								   0, 0, 0);	if (!HeapTupleIsValid(languageTuple))		elog(ERROR, "cache lookup failed for language %u", language);	languageStruct = (Form_pg_language) GETSTRUCT(languageTuple);	fmgr_info(languageStruct->lanplcallfoid, &plfinfo);	finfo->fn_addr = plfinfo.fn_addr;	/*	 * If lookup of the PL handler function produced nonnull fn_extra,	 * complain --- it must be an oldstyle function! We no longer support	 * oldstyle PL handlers.	 */	if (plfinfo.fn_extra != NULL)		elog(ERROR, "language %u has old-style handler", language);	ReleaseSysCache(languageTuple);}/* * Fetch and validate the information record for the given external function. * The function is specified by a handle for the containing library * (obtained from load_external_function) as well as the function name. * * If no info function exists for the given name, it is not an error. * Instead we return a default info record for a version-0 function. * We want to raise an error here only if the info function returns * something bogus. * * This function is broken out of fmgr_info_C_lang so that fmgr_c_validator * can validate the information record for a function not yet entered into * pg_proc. */Pg_finfo_record *fetch_finfo_record(void *filehandle, char *funcname){	char	   *infofuncname;	PGFInfoFunction infofunc;	Pg_finfo_record *inforec;	static Pg_finfo_record default_inforec = {0};	/* Compute name of info func */	infofuncname = (char *) palloc(strlen(funcname) + 10);	strcpy(infofuncname, "pg_finfo_");	strcat(infofuncname, funcname);	/* Try to look up the info function */	infofunc = (PGFInfoFunction) lookup_external_function(filehandle,														  infofuncname);	if (infofunc == NULL)	{		/* Not found --- assume version 0 */		pfree(infofuncname);		return &default_inforec;	}	/* Found, so call it */	inforec = (*infofunc) ();	/* Validate result as best we can */	if (inforec == NULL)		elog(ERROR, "null result from info function \"%s\"", infofuncname);	switch (inforec->api_version)	{		case 0:		case 1:			/* OK, no additional fields to validate */			break;		default:			ereport(ERROR,					(errcode(ERRCODE_INVALID_PARAMETER_VALUE),					 errmsg("unrecognized API version %d reported by info function \"%s\"",							inforec->api_version, infofuncname)));			break;	}	pfree(infofuncname);	return inforec;}/*------------------------------------------------------------------------- *		Routines for caching lookup information for external C functions. * * The routines in dfmgr.c are relatively slow, so we try to avoid running * them more than once per external function per session.  We use a hash table * with the function OID as the lookup key. *------------------------------------------------------------------------- *//* * lookup_C_func: try to find a C function in the hash table * * If an entry exists and is up to date, return it; else return NULL */static CFuncHashTabEntry *lookup_C_func(HeapTuple procedureTuple){	Oid			fn_oid = HeapTupleGetOid(procedureTuple);	CFuncHashTabEntry *entry;	if (CFuncHash == NULL)		return NULL;			/* no table yet */	entry = (CFuncHashTabEntry *)		hash_search(CFuncHash,					&fn_oid,

⌨️ 快捷键说明

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