⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 functioncmds.c

📁 PostgreSQL 8.1.4的源码 适用于Linux下的开源数据库系统
💻 C
📖 第 1 页 / 共 3 页
字号:
/*------------------------------------------------------------------------- * * functioncmds.c * *	  Routines for CREATE and DROP FUNCTION commands and CREATE and DROP *	  CAST commands. * * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION *	  $PostgreSQL: pgsql/src/backend/commands/functioncmds.c,v 1.69 2005/10/15 02:49:15 momjian 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/dependency.h"#include "catalog/indexing.h"#include "catalog/namespace.h"#include "catalog/pg_aggregate.h"#include "catalog/pg_cast.h"#include "catalog/pg_language.h"#include "catalog/pg_namespace.h"#include "catalog/pg_proc.h"#include "catalog/pg_type.h"#include "commands/defrem.h"#include "commands/proclang.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 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 parameter list of the CREATE FUNCTION statement. * * Results are stored into output parameters.  parameterTypes must always * be created, but the other arrays are set to NULL if not needed. * requiredResultType is set to InvalidOid if there are no OUT parameters, * else it is set to the OID of the implied result type. */static voidexamine_parameter_list(List *parameters, Oid languageOid,					   oidvector **parameterTypes,					   ArrayType **allParameterTypes,					   ArrayType **parameterModes,					   ArrayType **parameterNames,					   Oid *requiredResultType){	int			parameterCount = list_length(parameters);	Oid		   *inTypes;	int			inCount = 0;	Datum	   *allTypes;	Datum	   *paramModes;	Datum	   *paramNames;	int			outCount = 0;	bool		have_names = false;	ListCell   *x;	int			i;	*requiredResultType = InvalidOid;	/* default result */	inTypes = (Oid *) palloc(parameterCount * sizeof(Oid));	allTypes = (Datum *) palloc(parameterCount * sizeof(Datum));	paramModes = (Datum *) palloc(parameterCount * sizeof(Datum));	paramNames = (Datum *) palloc0(parameterCount * sizeof(Datum));	/* Scan the list and extract data into work arrays */	i = 0;	foreach(x, parameters)	{		FunctionParameter *fp = (FunctionParameter *) lfirst(x);		TypeName   *t = fp->argType;		Oid			toid;		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")));		if (fp->mode != FUNC_PARAM_OUT)			inTypes[inCount++] = toid;		if (fp->mode != FUNC_PARAM_IN)		{			if (outCount == 0)	/* save first OUT param's type */				*requiredResultType = toid;			outCount++;		}		allTypes[i] = ObjectIdGetDatum(toid);		paramModes[i] = CharGetDatum(fp->mode);		if (fp->name && fp->name[0])		{			paramNames[i] = DirectFunctionCall1(textin,												CStringGetDatum(fp->name));			have_names = true;		}		i++;	}	/* Now construct the proper outputs as needed */	*parameterTypes = buildoidvector(inTypes, inCount);	if (outCount > 0)	{		*allParameterTypes = construct_array(allTypes, parameterCount, OIDOID,											 sizeof(Oid), true, 'i');		*parameterModes = construct_array(paramModes, parameterCount, CHAROID,										  1, true, 'c');		if (outCount > 1)			*requiredResultType = RECORDOID;		/* otherwise we set requiredResultType correctly above */	}	else	{		*allParameterTypes = NULL;		*parameterModes = NULL;	}	if (have_names)	{		for (i = 0; i < parameterCount; i++)		{			if (paramNames[i] == PointerGetDatum(NULL))				paramNames[i] = DirectFunctionCall1(textin,													CStringGetDatum(""));		}		*parameterNames = construct_array(paramNames, parameterCount, TEXTOID,										  -1, false, 'i');	}	else		*parameterNames = NULL;}/* * Recognize one of the options that can be passed to both CREATE * FUNCTION and ALTER FUNCTION and return it via one of the out * parameters. Returns true if the passed option was recognized. If * the out parameter we were going to assign to points to non-NULL, * raise a duplicate error. */static boolcompute_common_attribute(DefElem *defel,						 DefElem **volatility_item,						 DefElem **strict_item,						 DefElem **security_item){	if (strcmp(defel->defname, "volatility") == 0)	{		if (*volatility_item)			goto duplicate_error;		*volatility_item = defel;	}	else if (strcmp(defel->defname, "strict") == 0)	{		if (*strict_item)			goto duplicate_error;		*strict_item = defel;	}	else if (strcmp(defel->defname, "security") == 0)	{		if (*security_item)			goto duplicate_error;		*security_item = defel;	}	else		return false;	/* Recognized an option */	return true;duplicate_error:	ereport(ERROR,			(errcode(ERRCODE_SYNTAX_ERROR),			 errmsg("conflicting or redundant options")));	return false;				/* keep compiler quiet */}static charinterpret_func_volatility(DefElem *defel){	char	   *str = strVal(defel->arg);	if (strcmp(str, "immutable") == 0)		return PROVOLATILE_IMMUTABLE;	else if (strcmp(str, "stable") == 0)		return PROVOLATILE_STABLE;	else if (strcmp(str, "volatile") == 0)		return PROVOLATILE_VOLATILE;	else	{		elog(ERROR, "invalid volatility \"%s\"", str);		return 0;				/* keep compiler quiet */	}}/* * Dissect the list of options assembled in gram.y into function * attributes. */static voidcompute_attributes_sql_style(List *options,							 List **as,							 char **language,							 char *volatility_p,							 bool *strict_p,							 bool *security_definer){	ListCell   *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 (compute_common_attribute(defel,										  &volatility_item,										  &strict_item,										  &security_item))		{			/* recognized common option */			continue;		}		else			elog(ERROR, "option \"%s\" not recognized",				 defel->defname);	}	/* process required items */	if (as_item)		*as = (List *) as_item->arg;	else	{		ereport(ERROR,				(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),				 errmsg("no function body specified")));		*as = NIL;				/* keep compiler quiet */	}	if (language_item)		*language = strVal(language_item->arg);	else	{		ereport(ERROR,				(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),				 errmsg("no language specified")));		*language = NULL;		/* keep compiler quiet */	}	/* process optional items */	if (volatility_item)		*volatility_p = interpret_func_volatility(volatility_item);	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 via *	 *isStrict_p and *volatility_p. * *	These parameters supply optional information about a function. *	All have defaults if not specified. Parameters: * *	 * 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. *------------ */static voidcompute_attributes_with_style(List *parameters, bool *isStrict_p, char *volatility_p){	ListCell   *pl;	foreach(pl, parameters)	{		DefElem    *param = (DefElem *) lfirst(pl);		if (pg_strcasecmp(param->defname, "isstrict") == 0)			*isStrict_p = defGetBoolean(param);		else if (pg_strcasecmp(param->defname, "iscachable") == 0)		{			/* obsolete spelling of isImmutable */			if (defGetBoolean(param))				*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, 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(linitial(as));		if (list_length(as) == 1)			*prosrc_str_p = "-";		else			*prosrc_str_p = strVal(lsecond(as));	}	else	{		/* Everything else wants the given string in prosrc. */		*prosrc_str_p = strVal(linitial(as));		*probin_str_p = "-";		if (list_length(as) != 1)			ereport(ERROR,					(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),					 errmsg("only one AS item needed for language \"%s\"",							languageName)));	}}/* * CreateFunction *	 Execute a CREATE FUNCTION utility statement. */voidCreateFunction(CreateFunctionStmt *stmt){	char	   *probin_str;	char	   *prosrc_str;	Oid			prorettype;	bool		returnsSet;	char	   *language;

⌨️ 快捷键说明

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