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 + -
显示快捷键?