functioncmds.c

来自「PostgreSQL7.4.6 for Linux」· C语言 代码 · 共 1,115 行 · 第 1/3 页

C
1,115
字号
/*------------------------------------------------------------------------- * * functioncmds.c * *	  Routines for CREATE and DROP FUNCTION commands * * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION *	  $Header: /cvsroot/pgsql/src/backend/commands/functioncmds.c,v 1.38.2.1 2004/02/21 00:35:13 tgl Exp $ * * DESCRIPTION *	  These routines take the parse tree and pick out the *	  appropriate arguments/flags, and pass the results to the *	  corresponding "FooDefine" routines (in src/catalog) that do *	  the actual catalog-munging.  These routines also verify permission *	  of the user to execute the command. * * NOTES *	  These things must be defined and committed in the following order: *		"create function": *				input/output, recv/send procedures *		"create type": *				type *		"create operator": *				operators * *------------------------------------------------------------------------- */#include "postgres.h"#include "access/genam.h"#include "access/heapam.h"#include "catalog/catname.h"#include "catalog/dependency.h"#include "catalog/indexing.h"#include "catalog/namespace.h"#include "catalog/pg_cast.h"#include "catalog/pg_language.h"#include "catalog/pg_proc.h"#include "catalog/pg_type.h"#include "commands/defrem.h"#include "miscadmin.h"#include "optimizer/cost.h"#include "parser/parse_func.h"#include "parser/parse_type.h"#include "utils/acl.h"#include "utils/builtins.h"#include "utils/fmgroids.h"#include "utils/lsyscache.h"#include "utils/syscache.h"/* *	 Examine the "returns" clause returnType of the CREATE FUNCTION statement *	 and return information about it as *prorettype_p and *returnsSet. * * This is more complex than the average typename lookup because we want to * allow a shell type to be used, or even created if the specified return type * doesn't exist yet.  (Without this, there's no way to define the I/O procs * for a new type.)  But SQL function creation won't cope, so error out if * the target language is SQL.	(We do this here, not in the SQL-function * validator, so as not to produce a NOTICE and then an ERROR for the same * condition.) */static voidcompute_return_type(TypeName *returnType, Oid languageOid,					Oid *prorettype_p, bool *returnsSet_p){	Oid			rettype;	rettype = LookupTypeName(returnType);	if (OidIsValid(rettype))	{		if (!get_typisdefined(rettype))		{			if (languageOid == SQLlanguageId)				ereport(ERROR,						(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),					   errmsg("SQL function cannot return shell type %s",							  TypeNameToString(returnType))));			else				ereport(NOTICE,						(errcode(ERRCODE_WRONG_OBJECT_TYPE),						 errmsg("return type %s is only a shell",								TypeNameToString(returnType))));		}	}	else	{		char	   *typnam = TypeNameToString(returnType);		Oid			namespaceId;		AclResult	aclresult;		char	   *typname;		/*		 * Only C-coded functions can be I/O functions.  We enforce this		 * restriction here mainly to prevent littering the catalogs with		 * shell types due to simple typos in user-defined function		 * definitions.		 */		if (languageOid != INTERNALlanguageId &&			languageOid != ClanguageId)			ereport(ERROR,					(errcode(ERRCODE_UNDEFINED_OBJECT),					 errmsg("type \"%s\" does not exist", typnam)));		/* Otherwise, go ahead and make a shell type */		ereport(NOTICE,				(errcode(ERRCODE_UNDEFINED_OBJECT),				 errmsg("type \"%s\" is not yet defined", typnam),				 errdetail("Creating a shell type definition.")));		namespaceId = QualifiedNameGetCreationNamespace(returnType->names,														&typname);		aclresult = pg_namespace_aclcheck(namespaceId, GetUserId(),										  ACL_CREATE);		if (aclresult != ACLCHECK_OK)			aclcheck_error(aclresult, ACL_KIND_NAMESPACE,						   get_namespace_name(namespaceId));		rettype = TypeShellMake(typname, namespaceId);		Assert(OidIsValid(rettype));	}	*prorettype_p = rettype;	*returnsSet_p = returnType->setof;}/* * Interpret the argument-types list of the CREATE FUNCTION statement. */static intcompute_parameter_types(List *argTypes, Oid languageOid,						Oid *parameterTypes){	int			parameterCount = 0;	List	   *x;	MemSet(parameterTypes, 0, FUNC_MAX_ARGS * sizeof(Oid));	foreach(x, argTypes)	{		TypeName   *t = (TypeName *) lfirst(x);		Oid			toid;		if (parameterCount >= FUNC_MAX_ARGS)			ereport(ERROR,					(errcode(ERRCODE_TOO_MANY_ARGUMENTS),				   errmsg("functions cannot have more than %d arguments",						  FUNC_MAX_ARGS)));		toid = LookupTypeName(t);		if (OidIsValid(toid))		{			if (!get_typisdefined(toid))			{				/* As above, hard error if language is SQL */				if (languageOid == SQLlanguageId)					ereport(ERROR,							(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),					   errmsg("SQL function cannot accept shell type %s",							  TypeNameToString(t))));				else					ereport(NOTICE,							(errcode(ERRCODE_WRONG_OBJECT_TYPE),							 errmsg("argument type %s is only a shell",									TypeNameToString(t))));			}		}		else		{			ereport(ERROR,					(errcode(ERRCODE_UNDEFINED_OBJECT),					 errmsg("type %s does not exist",							TypeNameToString(t))));		}		if (t->setof)			ereport(ERROR,					(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),					 errmsg("functions cannot accept set arguments")));		parameterTypes[parameterCount++] = toid;	}	return parameterCount;}/* * Dissect the list of options assembled in gram.y into function * attributes. */static voidcompute_attributes_sql_style(const List *options,							 List **as,							 char **language,							 char *volatility_p,							 bool *strict_p,							 bool *security_definer){	const List *option;	DefElem    *as_item = NULL;	DefElem    *language_item = NULL;	DefElem    *volatility_item = NULL;	DefElem    *strict_item = NULL;	DefElem    *security_item = NULL;	foreach(option, options)	{		DefElem    *defel = (DefElem *) lfirst(option);		if (strcmp(defel->defname, "as") == 0)		{			if (as_item)				ereport(ERROR,						(errcode(ERRCODE_SYNTAX_ERROR),						 errmsg("conflicting or redundant options")));			as_item = defel;		}		else if (strcmp(defel->defname, "language") == 0)		{			if (language_item)				ereport(ERROR,						(errcode(ERRCODE_SYNTAX_ERROR),						 errmsg("conflicting or redundant options")));			language_item = defel;		}		else if (strcmp(defel->defname, "volatility") == 0)		{			if (volatility_item)				ereport(ERROR,						(errcode(ERRCODE_SYNTAX_ERROR),						 errmsg("conflicting or redundant options")));			volatility_item = defel;		}		else if (strcmp(defel->defname, "strict") == 0)		{			if (strict_item)				ereport(ERROR,						(errcode(ERRCODE_SYNTAX_ERROR),						 errmsg("conflicting or redundant options")));			strict_item = defel;		}		else if (strcmp(defel->defname, "security") == 0)		{			if (security_item)				ereport(ERROR,						(errcode(ERRCODE_SYNTAX_ERROR),						 errmsg("conflicting or redundant options")));			security_item = defel;		}		else			elog(ERROR, "option \"%s\" not recognized",				 defel->defname);	}	if (as_item)		*as = (List *) as_item->arg;	else		ereport(ERROR,				(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),				 errmsg("no function body specified")));	if (language_item)		*language = strVal(language_item->arg);	else		ereport(ERROR,				(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),				 errmsg("no language specified")));	if (volatility_item)	{		if (strcmp(strVal(volatility_item->arg), "immutable") == 0)			*volatility_p = PROVOLATILE_IMMUTABLE;		else if (strcmp(strVal(volatility_item->arg), "stable") == 0)			*volatility_p = PROVOLATILE_STABLE;		else if (strcmp(strVal(volatility_item->arg), "volatile") == 0)			*volatility_p = PROVOLATILE_VOLATILE;		else			elog(ERROR, "invalid volatility \"%s\"",				 strVal(volatility_item->arg));	}	if (strict_item)		*strict_p = intVal(strict_item->arg);	if (security_item)		*security_definer = intVal(security_item->arg);}/*------------- *	 Interpret the parameters *parameters and return their contents as *	 *byte_pct_p, etc. * *	These parameters supply optional information about a function. *	All have defaults if not specified. * *	Note: currently, only two of these parameters actually do anything: * *	 * isStrict means the function should not be called when any NULL *	   inputs are present; instead a NULL result value should be assumed. * *	 * volatility tells the optimizer whether the function's result can *	   be assumed to be repeatable over multiple evaluations. * *	The other four parameters are not used anywhere.	They used to be *	used in the "expensive functions" optimizer, but that's been dead code *	for a long time. *------------ */static voidcompute_attributes_with_style(List *parameters, bool *isStrict_p, char *volatility_p){	List	   *pl;	foreach(pl, parameters)	{		DefElem    *param = (DefElem *) lfirst(pl);		if (strcasecmp(param->defname, "isstrict") == 0)			*isStrict_p = true;		else if (strcasecmp(param->defname, "iscachable") == 0)		{			/* obsolete spelling of isImmutable */			*volatility_p = PROVOLATILE_IMMUTABLE;		}		else			ereport(WARNING,					(errcode(ERRCODE_SYNTAX_ERROR),				 errmsg("unrecognized function attribute \"%s\" ignored",						param->defname)));	}}/* * For a dynamically linked C language object, the form of the clause is * *	   AS <object file name> [, <link symbol name> ] * * In all other cases * *	   AS <object reference, or sql code> * */static voidinterpret_AS_clause(Oid languageOid, const char *languageName, const List *as,					char **prosrc_str_p, char **probin_str_p){	Assert(as != NIL);	if (languageOid == ClanguageId)	{		/*		 * For "C" language, store the file name in probin and, when		 * given, the link symbol name in prosrc.		 */		*probin_str_p = strVal(lfirst(as));		if (lnext(as) == NULL)			*prosrc_str_p = "-";		else			*prosrc_str_p = strVal(lsecond(as));	}	else	{		/* Everything else wants the given string in prosrc. */		*prosrc_str_p = strVal(lfirst(as));		*probin_str_p = "-";

⌨️ 快捷键说明

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