functioncmds.c

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

C
1,115
字号
		if (lnext(as) != NIL)			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;	char	   *languageName;	Oid			languageOid;	Oid			languageValidator;	char	   *funcname;	Oid			namespaceId;	AclResult	aclresult;	int			parameterCount;	Oid			parameterTypes[FUNC_MAX_ARGS];	bool		isStrict,				security;	char		volatility;	HeapTuple	languageTuple;	Form_pg_language languageStruct;	List	   *as_clause;	/* Convert list of names to a name and namespace */	namespaceId = QualifiedNameGetCreationNamespace(stmt->funcname,													&funcname);	/* Check we have creation rights in target namespace */	aclresult = pg_namespace_aclcheck(namespaceId, GetUserId(), ACL_CREATE);	if (aclresult != ACLCHECK_OK)		aclcheck_error(aclresult, ACL_KIND_NAMESPACE,					   get_namespace_name(namespaceId));	/* defaults attributes */	isStrict = false;	security = false;	volatility = PROVOLATILE_VOLATILE;	/* override attributes from explicit list */	compute_attributes_sql_style(stmt->options,			   &as_clause, &language, &volatility, &isStrict, &security);	/* Convert language name to canonical case */	languageName = case_translate_language_name(language);	/* Look up the language and validate permissions */	languageTuple = SearchSysCache(LANGNAME,								   PointerGetDatum(languageName),								   0, 0, 0);	if (!HeapTupleIsValid(languageTuple))		/* Add any new languages to this list to invoke the hint. */		ereport(ERROR,				(errcode(ERRCODE_UNDEFINED_OBJECT),				 errmsg("language \"%s\" does not exist", languageName),				   (strcmp(languageName, "plperl") == 0 ||					strcmp(languageName, "plperlu") == 0 ||					strcmp(languageName, "plpgsql") == 0 ||					strcmp(languageName, "plpythonu") == 0 ||					strcmp(languageName, "pltcl") == 0 ||					strcmp(languageName, "pltclu") == 0) ?				 errhint("You need to use \"createlang\" to load the language into the database.") : 0));		languageOid = HeapTupleGetOid(languageTuple);	languageStruct = (Form_pg_language) GETSTRUCT(languageTuple);	if (languageStruct->lanpltrusted)	{		/* if trusted language, need USAGE privilege */		AclResult	aclresult;		aclresult = pg_language_aclcheck(languageOid, GetUserId(), ACL_USAGE);		if (aclresult != ACLCHECK_OK)			aclcheck_error(aclresult, ACL_KIND_LANGUAGE,						   NameStr(languageStruct->lanname));	}	else	{		/* if untrusted language, must be superuser */		if (!superuser())			aclcheck_error(ACLCHECK_NO_PRIV, ACL_KIND_LANGUAGE,						   NameStr(languageStruct->lanname));	}	languageValidator = languageStruct->lanvalidator;	ReleaseSysCache(languageTuple);	/*	 * Convert remaining parameters of CREATE to form wanted by	 * ProcedureCreate.	 */	compute_return_type(stmt->returnType, languageOid,						&prorettype, &returnsSet);	parameterCount = compute_parameter_types(stmt->argTypes, languageOid,											 parameterTypes);	compute_attributes_with_style(stmt->withClause, &isStrict, &volatility);	interpret_AS_clause(languageOid, languageName, as_clause,						&prosrc_str, &probin_str);	if (languageOid == INTERNALlanguageId)	{		/*		 * In PostgreSQL versions before 6.5, the SQL name of the created		 * function could not be different from the internal name, and		 * "prosrc" wasn't used.  So there is code out there that does		 * CREATE FUNCTION xyz AS '' LANGUAGE 'internal'. To preserve some		 * modicum of backwards compatibility, accept an empty "prosrc"		 * value as meaning the supplied SQL function name.		 */		if (strlen(prosrc_str) == 0)			prosrc_str = funcname;	}	if (languageOid == ClanguageId)	{		/* If link symbol is specified as "-", substitute procedure name */		if (strcmp(prosrc_str, "-") == 0)			prosrc_str = funcname;	}	/*	 * And now that we have all the parameters, and know we're permitted	 * to do so, go ahead and create the function.	 */	ProcedureCreate(funcname,					namespaceId,					stmt->replace,					returnsSet,					prorettype,					languageOid,					languageValidator,					prosrc_str, /* converted to text later */					probin_str, /* converted to text later */					false,		/* not an aggregate */					security,					isStrict,					volatility,					parameterCount,					parameterTypes);}/* * RemoveFunction *		Deletes a function. */voidRemoveFunction(RemoveFuncStmt *stmt){	List	   *functionName = stmt->funcname;	List	   *argTypes = stmt->args;	/* list of TypeName nodes */	Oid			funcOid;	HeapTuple	tup;	ObjectAddress object;	/*	 * Find the function, do permissions and validity checks	 */	funcOid = LookupFuncNameTypeNames(functionName, argTypes, false);	tup = SearchSysCache(PROCOID,						 ObjectIdGetDatum(funcOid),						 0, 0, 0);	if (!HeapTupleIsValid(tup)) /* should not happen */		elog(ERROR, "cache lookup failed for function %u", funcOid);	/* Permission check: must own func or its namespace */	if (!pg_proc_ownercheck(funcOid, GetUserId()) &&		!pg_namespace_ownercheck(((Form_pg_proc) GETSTRUCT(tup))->pronamespace,								 GetUserId()))		aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,					   NameListToString(functionName));	if (((Form_pg_proc) GETSTRUCT(tup))->proisagg)		ereport(ERROR,				(errcode(ERRCODE_WRONG_OBJECT_TYPE),				 errmsg("\"%s\" is an aggregate function",						NameListToString(functionName)),			errhint("Use DROP AGGREGATE to drop aggregate functions.")));	if (((Form_pg_proc) GETSTRUCT(tup))->prolang == INTERNALlanguageId)	{		/* "Helpful" NOTICE when removing a builtin function ... */		ereport(NOTICE,				(errcode(ERRCODE_WARNING),				 errmsg("removing built-in function \"%s\"",						NameListToString(functionName))));	}	ReleaseSysCache(tup);	/*	 * Do the deletion	 */	object.classId = RelOid_pg_proc;	object.objectId = funcOid;	object.objectSubId = 0;	performDeletion(&object, stmt->behavior);}/* * Guts of function deletion. * * Note: this is also used for aggregate deletion, since the OIDs of * both functions and aggregates point to pg_proc. */voidRemoveFunctionById(Oid funcOid){	Relation	relation;	HeapTuple	tup;	bool		isagg;	/*	 * Delete the pg_proc tuple.	 */	relation = heap_openr(ProcedureRelationName, RowExclusiveLock);	tup = SearchSysCache(PROCOID,						 ObjectIdGetDatum(funcOid),						 0, 0, 0);	if (!HeapTupleIsValid(tup)) /* should not happen */		elog(ERROR, "cache lookup failed for function %u", funcOid);	isagg = ((Form_pg_proc) GETSTRUCT(tup))->proisagg;	simple_heap_delete(relation, &tup->t_self);	ReleaseSysCache(tup);	heap_close(relation, RowExclusiveLock);	/*	 * If there's a pg_aggregate tuple, delete that too.	 */	if (isagg)	{		relation = heap_openr(AggregateRelationName, RowExclusiveLock);		tup = SearchSysCache(AGGFNOID,							 ObjectIdGetDatum(funcOid),							 0, 0, 0);		if (!HeapTupleIsValid(tup))		/* should not happen */			elog(ERROR, "cache lookup failed for pg_aggregate tuple for function %u", funcOid);		simple_heap_delete(relation, &tup->t_self);		ReleaseSysCache(tup);		heap_close(relation, RowExclusiveLock);	}}/* * Rename function */voidRenameFunction(List *name, List *argtypes, const char *newname){	Oid			procOid;	Oid			namespaceOid;	HeapTuple	tup;	Form_pg_proc procForm;	Relation	rel;	AclResult	aclresult;	rel = heap_openr(ProcedureRelationName, RowExclusiveLock);	procOid = LookupFuncNameTypeNames(name, argtypes, false);	tup = SearchSysCacheCopy(PROCOID,							 ObjectIdGetDatum(procOid),							 0, 0, 0);	if (!HeapTupleIsValid(tup)) /* should not happen */		elog(ERROR, "cache lookup failed for function %u", procOid);	procForm = (Form_pg_proc) GETSTRUCT(tup);	if (procForm->proisagg)		ereport(ERROR,				(errcode(ERRCODE_WRONG_OBJECT_TYPE),				 errmsg("\"%s\" is an aggregate function",						NameListToString(name)),		 errhint("Use ALTER AGGREGATE to rename aggregate functions.")));	namespaceOid = procForm->pronamespace;	/* make sure the new name doesn't exist */	if (SearchSysCacheExists(PROCNAMENSP,							 CStringGetDatum(newname),							 Int16GetDatum(procForm->pronargs),							 PointerGetDatum(procForm->proargtypes),							 ObjectIdGetDatum(namespaceOid)))	{		ereport(ERROR,				(errcode(ERRCODE_DUPLICATE_FUNCTION),				 errmsg("function %s already exists in schema \"%s\"",						funcname_signature_string(newname,												  procForm->pronargs,												  procForm->proargtypes),						get_namespace_name(namespaceOid))));	}	/* must be owner */	if (!pg_proc_ownercheck(procOid, GetUserId()))		aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,					   NameListToString(name));	/* must have CREATE privilege on namespace */	aclresult = pg_namespace_aclcheck(namespaceOid, GetUserId(), ACL_CREATE);	if (aclresult != ACLCHECK_OK)		aclcheck_error(aclresult, ACL_KIND_NAMESPACE,					   get_namespace_name(namespaceOid));	/* rename */	namestrcpy(&(procForm->proname), newname);	simple_heap_update(rel, &tup->t_self, tup);	CatalogUpdateIndexes(rel, tup);	heap_close(rel, NoLock);	heap_freetuple(tup);}/* * SetFunctionReturnType - change declared return type of a function * * This is presently only used for adjusting legacy functions that return * OPAQUE to return whatever we find their correct definition should be. * The caller should emit a suitable warning explaining what we did. */voidSetFunctionReturnType(Oid funcOid, Oid newRetType){	Relation	pg_proc_rel;	HeapTuple	tup;	Form_pg_proc procForm;	pg_proc_rel = heap_openr(ProcedureRelationName, RowExclusiveLock);	tup = SearchSysCacheCopy(PROCOID,							 ObjectIdGetDatum(funcOid),							 0, 0, 0);	if (!HeapTupleIsValid(tup)) /* should not happen */		elog(ERROR, "cache lookup failed for function %u", funcOid);	procForm = (Form_pg_proc) GETSTRUCT(tup);	if (procForm->prorettype != OPAQUEOID)		/* caller messed up */		elog(ERROR, "function %u doesn't return OPAQUE", funcOid);	/* okay to overwrite copied tuple */	procForm->prorettype = newRetType;

⌨️ 快捷键说明

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