functioncmds.c
来自「PostgreSQL7.4.6 for Linux」· C语言 代码 · 共 1,115 行 · 第 1/3 页
C
1,115 行
/*------------------------------------------------------------------------- * * functioncmds.c * * Routines for CREATE and DROP FUNCTION commands * * Portions Copyright (c) 1996-2003, 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.38.2.1 2004/02/21 00:35:13 tgl 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/catname.h"#include "catalog/dependency.h"#include "catalog/indexing.h"#include "catalog/namespace.h"#include "catalog/pg_cast.h"#include "catalog/pg_language.h"#include "catalog/pg_proc.h"#include "catalog/pg_type.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/builtins.h"#include "utils/fmgroids.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. (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 argument-types list of the CREATE FUNCTION statement. */static intcompute_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) ereport(ERROR, (errcode(ERRCODE_TOO_MANY_ARGUMENTS), errmsg("functions cannot have more than %d arguments", FUNC_MAX_ARGS))); 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"))); parameterTypes[parameterCount++] = toid; } return parameterCount;}/* * Dissect the list of options assembled in gram.y into function * attributes. */static voidcompute_attributes_sql_style(const List *options, List **as, char **language, char *volatility_p, bool *strict_p, bool *security_definer){ const List *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 (strcmp(defel->defname, "volatility") == 0) { if (volatility_item) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("conflicting or redundant options"))); volatility_item = defel; } else if (strcmp(defel->defname, "strict") == 0) { if (strict_item) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("conflicting or redundant options"))); strict_item = defel; } else if (strcmp(defel->defname, "security") == 0) { if (security_item) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("conflicting or redundant options"))); security_item = defel; } else elog(ERROR, "option \"%s\" not recognized", defel->defname); } if (as_item) *as = (List *) as_item->arg; else ereport(ERROR, (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION), errmsg("no function body specified"))); if (language_item) *language = strVal(language_item->arg); else ereport(ERROR, (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION), errmsg("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 \"%s\"", strVal(volatility_item->arg)); } 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 as * *byte_pct_p, etc. * * These parameters supply optional information about a function. * All have defaults if not specified. * * Note: currently, only two of these parameters actually do anything: * * * 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 voidcompute_attributes_with_style(List *parameters, bool *isStrict_p, char *volatility_p){ List *pl; foreach(pl, parameters) { DefElem *param = (DefElem *) lfirst(pl); if (strcasecmp(param->defname, "isstrict") == 0) *isStrict_p = true; else if (strcasecmp(param->defname, "iscachable") == 0) { /* obsolete spelling of isImmutable */ *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, 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 = "-";
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?