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

📄 functioncmds.c

📁 PostgreSQL 8.1.4的源码 适用于Linux下的开源数据库系统
💻 C
📖 第 1 页 / 共 3 页
字号:
	char	   *languageName;	Oid			languageOid;	Oid			languageValidator;	char	   *funcname;	Oid			namespaceId;	AclResult	aclresult;	oidvector  *parameterTypes;	ArrayType  *allParameterTypes;	ArrayType  *parameterModes;	ArrayType  *parameterNames;	Oid			requiredResultType;	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));	/* default 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))		ereport(ERROR,				(errcode(ERRCODE_UNDEFINED_OBJECT),				 errmsg("language \"%s\" does not exist", languageName),				 (PLTemplateExists(languageName) ?				  errhint("Use CREATE LANGUAGE 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.	 */	examine_parameter_list(stmt->parameters, languageOid,						   &parameterTypes,						   &allParameterTypes,						   &parameterModes,						   &parameterNames,						   &requiredResultType);	if (stmt->returnType)	{		/* explicit RETURNS clause */		compute_return_type(stmt->returnType, languageOid,							&prorettype, &returnsSet);		if (OidIsValid(requiredResultType) && prorettype != requiredResultType)			ereport(ERROR,					(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),					 errmsg("function result type must be %s because of OUT parameters",							format_type_be(requiredResultType))));	}	else if (OidIsValid(requiredResultType))	{		/* default RETURNS clause from OUT parameters */		prorettype = requiredResultType;		returnsSet = false;	}	else	{		ereport(ERROR,				(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),				 errmsg("function result type must be specified")));		/* Alternative possibility: default to RETURNS VOID */		prorettype = VOIDOID;		returnsSet = false;	}	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,					parameterTypes,					PointerGetDatum(allParameterTypes),					PointerGetDatum(parameterModes),					PointerGetDatum(parameterNames));}/* * 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 = ProcedureRelationId;	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_open(ProcedureRelationId, 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_open(AggregateRelationId, 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_open(ProcedureRelationId, 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(PROCNAMEARGSNSP,							 CStringGetDatum(newname),							 PointerGetDatum(&procForm->proargtypes),							 ObjectIdGetDatum(namespaceOid),							 0))	{		ereport(ERROR,				(errcode(ERRCODE_DUPLICATE_FUNCTION),				 errmsg("function %s already exists in schema \"%s\"",						funcname_signature_string(newname,												  procForm->pronargs,											   procForm->proargtypes.values),						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);}/* * Change function owner */voidAlterFunctionOwner(List *name, List *argtypes, Oid newOwnerId){	Oid			procOid;	HeapTuple	tup;	Form_pg_proc procForm;	Relation	rel;	AclResult	aclresult;	rel = heap_open(ProcedureRelationId, RowExclusiveLock);	procOid = LookupFuncNameTypeNames(name, argtypes, false);	tup = SearchSysCache(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 change owner of aggregate functions.")));	/*	 * If the new owner is the same as the existing owner, consider the	 * command to have succeeded.  This is for dump restoration purposes.	 */	if (procForm->proowner != newOwnerId)	{		Datum		repl_val[Natts_pg_proc];		char		repl_null[Natts_pg_proc];		char		repl_repl[Natts_pg_proc];		Acl		   *newAcl;		Datum		aclDatum;		bool		isNull;		HeapTuple	newtuple;		/* Superusers can always do it */		if (!superuser())		{			/* Otherwise, must be owner of the existing object */			if (!pg_proc_ownercheck(procOid, GetUserId()))				aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,							   NameListToString(name));			/* Must be able to become new owner */			check_is_member_of_role(GetUserId(), newOwnerId);			/* New owner must have CREATE privilege on namespace */			aclresult = pg_namespace_aclcheck(procForm->pronamespace,											  newOwnerId,											  ACL_CREATE);			if (aclresult != ACLCHECK_OK)				aclcheck_error(aclresult, ACL_KIND_NAMESPACE,							   get_namespace_name(procForm->pronamespace));		}		memset(repl_null, ' ', sizeof(repl_null));		memset(repl_repl, ' ', sizeof(repl_repl));		repl_repl[Anum_pg_proc_proowner - 1] = 'r';		repl_val[Anum_pg_proc_proowner - 1] = ObjectIdGetDatum(newOwnerId);		/*		 * Determine the modified ACL for the new owner.  This is only		 * necessary when the ACL is non-null.		 */		aclDatum = SysCacheGetAttr(PROCOID, tup,								   Anum_pg_proc_proacl,								   &isNull);		if (!isNull)		{			newAcl = aclnewowner(DatumGetAclP(aclDatum),								 procForm->proowner, newOwnerId);			repl_repl[Anum_pg_proc_proacl - 1] = 'r';			repl_val[Anum_pg_proc_proacl - 1] = PointerGetDatum(newAcl);		}		newtuple = heap_modifytuple(tup, RelationGetDescr(rel), repl_val, repl_null, repl_repl);		simple_heap_update(rel, &newtuple->t_self, newtuple);		CatalogUpdateIndexes(rel, newtuple);		heap_freetuple(newtuple);		/* Update owner dependency reference */		changeDependencyOnOwner(ProcedureRelationId, procOid, newOwnerId);	}	ReleaseSysCache(tup);	heap_close(rel, NoLock);}/* * Implements the ALTER FUNCTION utility command (except for the * RENAME and OWNER clauses, which are handled as part of the generic * ALTER framework). */voidAlterFunction(AlterFunctionStmt *stmt){	HeapTuple	tup;	Oid			funcOid;	Form_pg_proc procForm;	Relation	rel;	ListCell   *l;	DefElem    *volatility_item = NULL;	DefElem    *strict_item = NULL;	DefElem    *security_def_item = NULL;	rel = heap_open(ProcedureRelationId, RowExclusiveLock);	funcOid = LookupFuncNameTypeNames(stmt->func->funcname,									  stmt->func->funcargs,									  false);	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);	/* Permission check: must own function */	if (!pg_proc_ownercheck(funcOid, GetUserId()))		aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,					   NameListToString(stmt->func->funcname));	if (procForm->proisagg)		ereport(ERROR,				(errcode(ERRCODE_WRONG_OBJECT_TYPE),				 errmsg("\"%s\" is an aggregate function",						NameListToString(stmt->func->funcname))));	/* Examine requested actions. */	foreach(l, stmt->actions)	{		DefElem    *defel = (DefElem *) lfirst(l);		if (compute_common_attribute(defel,									 &volatility_item,									 &strict_item,									 &security_def_item) == false)			elog(ERROR, "option \"%s\" not recognized", defel->defname);	}	if (volatility_item)		procForm->provolatile = interpret_func_volatility(volatility_item);	if (strict_item)		procForm->proisstrict = intVal(strict_item->arg);	if (security_def_item)		procForm->prosecdef = intVal(security_def_item->arg);	/* Do the update */

⌨️ 快捷键说明

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