pg_proc.c

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

C
814
字号
/* * Validator for internal functions * * Check that the given internal function name (the "prosrc" value) is * a known builtin function. */Datumfmgr_internal_validator(PG_FUNCTION_ARGS){	Oid			funcoid = PG_GETARG_OID(0);	HeapTuple	tuple;	Form_pg_proc proc;	bool		isnull;	Datum		tmp;	char	   *prosrc;	/*	 * We do not honor check_function_bodies since it's unlikely the function	 * name will be found later if it isn't there now.	 */	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);	tmp = SysCacheGetAttr(PROCOID, tuple, Anum_pg_proc_prosrc, &isnull);	if (isnull)		elog(ERROR, "null prosrc");	prosrc = DatumGetCString(DirectFunctionCall1(textout, tmp));	if (fmgr_internal_function(prosrc) == InvalidOid)		ereport(ERROR,				(errcode(ERRCODE_UNDEFINED_FUNCTION),				 errmsg("there is no built-in function named \"%s\"",						prosrc)));	ReleaseSysCache(tuple);	PG_RETURN_VOID();}/* * Validator for C language functions * * Make sure that the library file exists, is loadable, and contains * the specified link symbol. Also check for a valid function * information record. */Datumfmgr_c_validator(PG_FUNCTION_ARGS){	Oid			funcoid = PG_GETARG_OID(0);	void	   *libraryhandle;	HeapTuple	tuple;	Form_pg_proc proc;	bool		isnull;	Datum		tmp;	char	   *prosrc;	char	   *probin;	/*	 * It'd be most consistent to skip the check if !check_function_bodies,	 * but the purpose of that switch is to be helpful for pg_dump loading,	 * and for pg_dump loading it's much better if we *do* check.	 */	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);	tmp = SysCacheGetAttr(PROCOID, tuple, Anum_pg_proc_prosrc, &isnull);	if (isnull)		elog(ERROR, "null prosrc");	prosrc = DatumGetCString(DirectFunctionCall1(textout, tmp));	tmp = SysCacheGetAttr(PROCOID, tuple, Anum_pg_proc_probin, &isnull);	if (isnull)		elog(ERROR, "null probin");	probin = DatumGetCString(DirectFunctionCall1(textout, tmp));	(void) load_external_function(probin, prosrc, true, &libraryhandle);	(void) fetch_finfo_record(libraryhandle, prosrc);	ReleaseSysCache(tuple);	PG_RETURN_VOID();}/* * Validator for SQL language functions * * Parse it here in order to be sure that it contains no syntax errors. */Datumfmgr_sql_validator(PG_FUNCTION_ARGS){	Oid			funcoid = PG_GETARG_OID(0);	HeapTuple	tuple;	Form_pg_proc proc;	List	   *querytree_list;	bool		isnull;	Datum		tmp;	char	   *prosrc;	ErrorContextCallback sqlerrcontext;	bool		haspolyarg;	int			i;	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);	/* Disallow pseudotype result */	/* except for RECORD, VOID, ANYARRAY, or ANYELEMENT */	if (get_typtype(proc->prorettype) == 'p' &&		proc->prorettype != RECORDOID &&		proc->prorettype != VOIDOID &&		proc->prorettype != ANYARRAYOID &&		proc->prorettype != ANYELEMENTOID)		ereport(ERROR,				(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),				 errmsg("SQL functions cannot return type %s",						format_type_be(proc->prorettype))));	/* Disallow pseudotypes in arguments */	/* except for ANYARRAY or ANYELEMENT */	haspolyarg = false;	for (i = 0; i < proc->pronargs; i++)	{		if (get_typtype(proc->proargtypes.values[i]) == 'p')		{			if (proc->proargtypes.values[i] == ANYARRAYOID ||				proc->proargtypes.values[i] == ANYELEMENTOID)				haspolyarg = true;			else				ereport(ERROR,						(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),					 errmsg("SQL functions cannot have arguments of type %s",							format_type_be(proc->proargtypes.values[i]))));		}	}	/* Postpone body checks if !check_function_bodies */	if (check_function_bodies)	{		tmp = SysCacheGetAttr(PROCOID, tuple, Anum_pg_proc_prosrc, &isnull);		if (isnull)			elog(ERROR, "null prosrc");		prosrc = DatumGetCString(DirectFunctionCall1(textout, tmp));		/*		 * Setup error traceback support for ereport().		 */		sqlerrcontext.callback = sql_function_parse_error_callback;		sqlerrcontext.arg = tuple;		sqlerrcontext.previous = error_context_stack;		error_context_stack = &sqlerrcontext;		/*		 * We can't do full prechecking of the function definition if there		 * are any polymorphic input types, because actual datatypes of		 * expression results will be unresolvable.  The check will be done at		 * runtime instead.		 *		 * We can run the text through the raw parser though; this will at		 * least catch silly syntactic errors.		 */		if (!haspolyarg)		{			querytree_list = pg_parse_and_rewrite(prosrc,												  proc->proargtypes.values,												  proc->pronargs);			(void) check_sql_fn_retval(funcoid, proc->prorettype,									   querytree_list, NULL);		}		else			querytree_list = pg_parse_query(prosrc);		error_context_stack = sqlerrcontext.previous;	}	ReleaseSysCache(tuple);	PG_RETURN_VOID();}/* * Error context callback for handling errors in SQL function definitions */static voidsql_function_parse_error_callback(void *arg){	HeapTuple	tuple = (HeapTuple) arg;	Form_pg_proc proc = (Form_pg_proc) GETSTRUCT(tuple);	bool		isnull;	Datum		tmp;	char	   *prosrc;	/* See if it's a syntax error; if so, transpose to CREATE FUNCTION */	tmp = SysCacheGetAttr(PROCOID, tuple, Anum_pg_proc_prosrc, &isnull);	if (isnull)		elog(ERROR, "null prosrc");	prosrc = DatumGetCString(DirectFunctionCall1(textout, tmp));	if (!function_parse_error_transpose(prosrc))	{		/* If it's not a syntax error, push info onto context stack */		errcontext("SQL function \"%s\"", NameStr(proc->proname));	}	pfree(prosrc);}/* * Adjust a syntax error occurring inside the function body of a CREATE * FUNCTION command.  This can be used by any function validator, not only * for SQL-language functions.	It is assumed that the syntax error position * is initially relative to the function body string (as passed in).  If * possible, we adjust the position to reference the original CREATE command; * if we can't manage that, we set up an "internal query" syntax error instead. * * Returns true if a syntax error was processed, false if not. */boolfunction_parse_error_transpose(const char *prosrc){	int			origerrposition;	int			newerrposition;	const char *queryText;	/*	 * Nothing to do unless we are dealing with a syntax error that has a	 * cursor position.	 *	 * Some PLs may prefer to report the error position as an internal error	 * to begin with, so check that too.	 */	origerrposition = geterrposition();	if (origerrposition <= 0)	{		origerrposition = getinternalerrposition();		if (origerrposition <= 0)			return false;	}	/* We can get the original query text from the active portal (hack...) */	Assert(ActivePortal && ActivePortal->status == PORTAL_ACTIVE);	queryText = ActivePortal->sourceText;	/* Try to locate the prosrc in the original text */	newerrposition = match_prosrc_to_query(prosrc, queryText, origerrposition);	if (newerrposition > 0)	{		/* Successful, so fix error position to reference original query */		errposition(newerrposition);		/* Get rid of any report of the error as an "internal query" */		internalerrposition(0);		internalerrquery(NULL);	}	else	{		/*		 * If unsuccessful, convert the position to an internal position		 * marker and give the function text as the internal query.		 */		errposition(0);		internalerrposition(origerrposition);		internalerrquery(prosrc);	}	return true;}/* * Try to locate the string literal containing the function body in the * given text of the CREATE FUNCTION command.  If successful, return the * character (not byte) index within the command corresponding to the * given character index within the literal.  If not successful, return 0. */static intmatch_prosrc_to_query(const char *prosrc, const char *queryText,					  int cursorpos){	/*	 * Rather than fully parsing the CREATE FUNCTION command, we just scan the	 * command looking for $prosrc$ or 'prosrc'.  This could be fooled (though	 * not in any very probable scenarios), so fail if we find more than one	 * match.	 */	int			prosrclen = strlen(prosrc);	int			querylen = strlen(queryText);	int			matchpos = 0;	int			curpos;	int			newcursorpos;	for (curpos = 0; curpos < querylen - prosrclen; curpos++)	{		if (queryText[curpos] == '$' &&			strncmp(prosrc, &queryText[curpos + 1], prosrclen) == 0 &&			queryText[curpos + 1 + prosrclen] == '$')		{			/*			 * Found a $foo$ match.  Since there are no embedded quoting			 * characters in a dollar-quoted literal, we don't have to do any			 * fancy arithmetic; just offset by the starting position.			 */			if (matchpos)				return 0;		/* multiple matches, fail */			matchpos = pg_mbstrlen_with_len(queryText, curpos + 1)				+ cursorpos;		}		else if (queryText[curpos] == '\'' &&				 match_prosrc_to_literal(prosrc, &queryText[curpos + 1],										 cursorpos, &newcursorpos))		{			/*			 * Found a 'foo' match.  match_prosrc_to_literal() has adjusted			 * for any quotes or backslashes embedded in the literal.			 */			if (matchpos)				return 0;		/* multiple matches, fail */			matchpos = pg_mbstrlen_with_len(queryText, curpos + 1)				+ newcursorpos;		}	}	return matchpos;}/* * Try to match the given source text to a single-quoted literal. * If successful, adjust newcursorpos to correspond to the character * (not byte) index corresponding to cursorpos in the source text. * * At entry, literal points just past a ' character.  We must check for the * trailing quote. */static boolmatch_prosrc_to_literal(const char *prosrc, const char *literal,						int cursorpos, int *newcursorpos){	int			newcp = cursorpos;	int			chlen;	/*	 * This implementation handles backslashes and doubled quotes in the	 * string literal.	It does not handle the SQL syntax for literals	 * continued across line boundaries.	 *	 * We do the comparison a character at a time, not a byte at a time, so	 * that we can do the correct cursorpos math.	 */	while (*prosrc)	{		cursorpos--;			/* characters left before cursor */		/*		 * Check for backslashes and doubled quotes in the literal; adjust		 * newcp when one is found before the cursor.		 */		if (*literal == '\\')		{			literal++;			if (cursorpos > 0)				newcp++;		}		else if (*literal == '\'')		{			if (literal[1] != '\'')				goto fail;			literal++;			if (cursorpos > 0)				newcp++;		}		chlen = pg_mblen(prosrc);		if (strncmp(prosrc, literal, chlen) != 0)			goto fail;		prosrc += chlen;		literal += chlen;	}	if (*literal == '\'' && literal[1] != '\'')	{		/* success */		*newcursorpos = newcp;		return true;	}fail:	/* Must set *newcursorpos to suppress compiler warning */	*newcursorpos = newcp;	return false;}

⌨️ 快捷键说明

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