diff options
Diffstat (limited to 'src/backend/commands/functioncmds.c')
-rw-r--r-- | src/backend/commands/functioncmds.c | 587 |
1 files changed, 0 insertions, 587 deletions
diff --git a/src/backend/commands/functioncmds.c b/src/backend/commands/functioncmds.c deleted file mode 100644 index 638fd19a8eb..00000000000 --- a/src/backend/commands/functioncmds.c +++ /dev/null @@ -1,587 +0,0 @@ -/*------------------------------------------------------------------------- - * - * functioncmds.c - * - * Routines for CREATE and DROP FUNCTION commands - * - * Portions Copyright (c) 1996-2002, 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.7 2002/06/20 20:29:27 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/heapam.h" -#include "catalog/catname.h" -#include "catalog/namespace.h" -#include "catalog/pg_language.h" -#include "catalog/pg_proc.h" -#include "catalog/pg_type.h" -#include "commands/comment.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/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. - */ -static void -compute_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) - elog(ERROR, "SQL functions cannot return shell types"); - else - elog(WARNING, "Return type \"%s\" is only a shell", - TypeNameToString(returnType)); - } - } - else - { - char *typnam = TypeNameToString(returnType); - - if (strcmp(typnam, "opaque") == 0) - rettype = InvalidOid; - else - { - Oid namespaceId; - AclResult aclresult; - char *typname; - - if (languageOid == SQLlanguageId) - elog(ERROR, "Type \"%s\" does not exist", typnam); - elog(WARNING, "ProcedureCreate: type %s is not yet defined", - typnam); - namespaceId = QualifiedNameGetCreationNamespace(returnType->names, - &typname); - aclresult = pg_namespace_aclcheck(namespaceId, GetUserId(), - ACL_CREATE); - if (aclresult != ACLCHECK_OK) - aclcheck_error(aclresult, get_namespace_name(namespaceId)); - rettype = TypeShellMake(typname, namespaceId); - if (!OidIsValid(rettype)) - elog(ERROR, "could not create type %s", typnam); - } - } - - *prorettype_p = rettype; - *returnsSet_p = returnType->setof; -} - -/* - * Interpret the argument-types list of the CREATE FUNCTION statement. - */ -static int -compute_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) - elog(ERROR, "functions cannot have more than %d arguments", - FUNC_MAX_ARGS); - - toid = LookupTypeName(t); - if (OidIsValid(toid)) - { - if (!get_typisdefined(toid)) - elog(WARNING, "Argument type \"%s\" is only a shell", - TypeNameToString(t)); - } - else - { - char *typnam = TypeNameToString(t); - - if (strcmp(typnam, "opaque") == 0) - { - if (languageOid == SQLlanguageId) - elog(ERROR, "SQL functions cannot have arguments of type \"opaque\""); - toid = InvalidOid; - } - else - elog(ERROR, "Type \"%s\" does not exist", typnam); - } - - if (t->setof) - elog(ERROR, "functions cannot accept set arguments"); - - parameterTypes[parameterCount++] = toid; - } - - return parameterCount; -} - - -/* - * Dissect the list of options assembled in gram.y into function - * attributes. - */ - -static void -compute_attributes_sql_style(const List *options, - List **as, - char **language, - char *volatility_p, - bool *strict_p, - bool *security_definer, - bool *implicit_cast) -{ - const List *option; - DefElem *as_item = NULL; - DefElem *language_item = NULL; - DefElem *volatility_item = NULL; - DefElem *strict_item = NULL; - DefElem *security_item = NULL; - DefElem *implicit_item = NULL; - - foreach(option, options) - { - DefElem *defel = (DefElem *) lfirst(option); - - if (strcmp(defel->defname, "as")==0) - { - if (as_item) - elog(ERROR, "conflicting or redundant options"); - as_item = defel; - } - else if (strcmp(defel->defname, "language")==0) - { - if (language_item) - elog(ERROR, "conflicting or redundant options"); - language_item = defel; - } - else if (strcmp(defel->defname, "volatility")==0) - { - if (volatility_item) - elog(ERROR, "conflicting or redundant options"); - volatility_item = defel; - } - else if (strcmp(defel->defname, "strict")==0) - { - if (strict_item) - elog(ERROR, "conflicting or redundant options"); - strict_item = defel; - } - else if (strcmp(defel->defname, "security")==0) - { - if (security_item) - elog(ERROR, "conflicting or redundant options"); - security_item = defel; - } - else if (strcmp(defel->defname, "implicit")==0) - { - if (implicit_item) - elog(ERROR, "conflicting or redundant options"); - implicit_item = defel; - } - else - elog(ERROR, "invalid CREATE FUNCTION option"); - } - - if (as_item) - *as = (List *)as_item->arg; - else - elog(ERROR, "no function body specified"); - - if (language_item) - *language = strVal(language_item->arg); - else - elog(ERROR, "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"); - } - - if (strict_item) - *strict_p = intVal(strict_item->arg); - if (security_item) - *security_definer = intVal(security_item->arg); - if (implicit_item) - *implicit_cast = intVal(implicit_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 three of these parameters actually do anything: - * - * * isImplicit means the function may be used as an implicit type - * coercion. - * - * * 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 void -compute_attributes_with_style(List *parameters, - int32 *byte_pct_p, int32 *perbyte_cpu_p, - int32 *percall_cpu_p, int32 *outin_ratio_p, - bool *isImplicit_p, bool *isStrict_p, - char *volatility_p) -{ - List *pl; - - foreach(pl, parameters) - { - DefElem *param = (DefElem *) lfirst(pl); - - if (strcasecmp(param->defname, "implicitcoercion") == 0) - *isImplicit_p = true; - else if (strcasecmp(param->defname, "isstrict") == 0) - *isStrict_p = true; - else if (strcasecmp(param->defname, "isimmutable") == 0) - *volatility_p = PROVOLATILE_IMMUTABLE; - else if (strcasecmp(param->defname, "isstable") == 0) - *volatility_p = PROVOLATILE_STABLE; - else if (strcasecmp(param->defname, "isvolatile") == 0) - *volatility_p = PROVOLATILE_VOLATILE; - else if (strcasecmp(param->defname, "iscachable") == 0) - { - /* obsolete spelling of isImmutable */ - *volatility_p = PROVOLATILE_IMMUTABLE; - } - else if (strcasecmp(param->defname, "trusted") == 0) - { - /* - * we don't have untrusted functions any more. The 4.2 - * implementation is lousy anyway so I took it out. -ay 10/94 - */ - elog(ERROR, "untrusted function has been decommissioned."); - } - else if (strcasecmp(param->defname, "byte_pct") == 0) - *byte_pct_p = (int) defGetNumeric(param); - else if (strcasecmp(param->defname, "perbyte_cpu") == 0) - *perbyte_cpu_p = (int) defGetNumeric(param); - else if (strcasecmp(param->defname, "percall_cpu") == 0) - *percall_cpu_p = (int) defGetNumeric(param); - else if (strcasecmp(param->defname, "outin_ratio") == 0) - *outin_ratio_p = (int) defGetNumeric(param); - else - elog(WARNING, "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 void -interpret_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 = "-"; - - if (lnext(as) != NIL) - elog(ERROR, "CREATE FUNCTION: only one AS item needed for %s language", - languageName); - } -} - - - -/* - * CreateFunction - * Execute a CREATE FUNCTION utility statement. - */ -void -CreateFunction(CreateFunctionStmt *stmt) -{ - char *probin_str; - char *prosrc_str; - Oid prorettype; - bool returnsSet; - char *language; - char languageName[NAMEDATALEN]; - Oid languageOid; - Oid languageValidator; - char *funcname; - Oid namespaceId; - AclResult aclresult; - int parameterCount; - Oid parameterTypes[FUNC_MAX_ARGS]; - int32 byte_pct, - perbyte_cpu, - percall_cpu, - outin_ratio; - bool isImplicit, - 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, get_namespace_name(namespaceId)); - - /* defaults attributes */ - byte_pct = BYTE_PCT; - perbyte_cpu = PERBYTE_CPU; - percall_cpu = PERCALL_CPU; - outin_ratio = OUTIN_RATIO; - isImplicit = false; - isStrict = false; - security = false; - volatility = PROVOLATILE_VOLATILE; - - /* override attributes from explicit list */ - compute_attributes_sql_style(stmt->options, - &as_clause, &language, &volatility, &isStrict, &security, &isImplicit); - - /* Convert language name to canonical case */ - case_translate_language_name(language, languageName); - - /* Look up the language and validate permissions */ - languageTuple = SearchSysCache(LANGNAME, - PointerGetDatum(languageName), - 0, 0, 0); - if (!HeapTupleIsValid(languageTuple)) - elog(ERROR, "language \"%s\" does not exist", languageName); - - languageOid = languageTuple->t_data->t_oid; - 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, NameStr(languageStruct->lanname)); - } - else - { - /* if untrusted language, must be superuser */ - if (!superuser()) - aclcheck_error(ACLCHECK_NO_PRIV, 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, - &byte_pct, &perbyte_cpu, &percall_cpu, - &outin_ratio, &isImplicit, &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, - isImplicit, - isStrict, - volatility, - byte_pct, - perbyte_cpu, - percall_cpu, - outin_ratio, - parameterCount, - parameterTypes); -} - - -/* - * RemoveFunction - * Deletes a function. - * - * Exceptions: - * BadArg if name is invalid. - * "ERROR" if function nonexistent. - * ... - */ -void -RemoveFunction(List *functionName, /* function name to be removed */ - List *argTypes) /* list of TypeName nodes */ -{ - Oid funcOid; - Relation relation; - HeapTuple tup; - - funcOid = LookupFuncNameTypeNames(functionName, argTypes, - true, "RemoveFunction"); - - relation = heap_openr(ProcedureRelationName, RowExclusiveLock); - - tup = SearchSysCache(PROCOID, - ObjectIdGetDatum(funcOid), - 0, 0, 0); - if (!HeapTupleIsValid(tup)) /* should not happen */ - elog(ERROR, "RemoveFunction: couldn't find tuple for function %s", - NameListToString(functionName)); - - /* 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, NameListToString(functionName)); - - if (((Form_pg_proc) GETSTRUCT(tup))->proisagg) - elog(ERROR, "RemoveFunction: function '%s' is an aggregate" - "\n\tUse DROP AGGREGATE to remove it", - NameListToString(functionName)); - - if (((Form_pg_proc) GETSTRUCT(tup))->prolang == INTERNALlanguageId) - { - /* "Helpful" WARNING when removing a builtin function ... */ - elog(WARNING, "Removing built-in function \"%s\"", - NameListToString(functionName)); - } - - /* Delete any comments associated with this function */ - DeleteComments(funcOid, RelationGetRelid(relation)); - - simple_heap_delete(relation, &tup->t_self); - - ReleaseSysCache(tup); - - heap_close(relation, RowExclusiveLock); -} |