pg_proc.c
来自「PostgreSQL7.4.6 for Linux」· C语言 代码 · 共 739 行 · 第 1/2 页
C
739 行
/*------------------------------------------------------------------------- * * pg_proc.c * routines to support manipulation of the pg_proc relation * * 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/catalog/pg_proc.c,v 1.109 2003/10/03 19:26:49 tgl Exp $ * *------------------------------------------------------------------------- */#include "postgres.h"#include "access/heapam.h"#include "catalog/catname.h"#include "catalog/dependency.h"#include "catalog/indexing.h"#include "catalog/pg_language.h"#include "catalog/pg_proc.h"#include "executor/executor.h"#include "fmgr.h"#include "miscadmin.h"#include "parser/parse_coerce.h"#include "parser/parse_expr.h"#include "parser/parse_type.h"#include "tcop/tcopprot.h"#include "utils/acl.h"#include "utils/builtins.h"#include "utils/lsyscache.h"#include "utils/sets.h"#include "utils/syscache.h"/* GUC parameter */bool check_function_bodies = true;Datum fmgr_internal_validator(PG_FUNCTION_ARGS);Datum fmgr_c_validator(PG_FUNCTION_ARGS);Datum fmgr_sql_validator(PG_FUNCTION_ARGS);/* ---------------------------------------------------------------- * ProcedureCreate * ---------------------------------------------------------------- */OidProcedureCreate(const char *procedureName, Oid procNamespace, bool replace, bool returnsSet, Oid returnType, Oid languageObjectId, Oid languageValidator, const char *prosrc, const char *probin, bool isAgg, bool security_definer, bool isStrict, char volatility, int parameterCount, const Oid *parameterTypes){ int i; Relation rel; HeapTuple tup; HeapTuple oldtup; char nulls[Natts_pg_proc]; Datum values[Natts_pg_proc]; char replaces[Natts_pg_proc]; Oid typev[FUNC_MAX_ARGS]; Oid relid; NameData procname; TupleDesc tupDesc; Oid retval; bool is_update; ObjectAddress myself, referenced; /* * sanity checks */ Assert(PointerIsValid(prosrc)); Assert(PointerIsValid(probin)); if (parameterCount < 0 || parameterCount > FUNC_MAX_ARGS) ereport(ERROR, (errcode(ERRCODE_TOO_MANY_ARGUMENTS), errmsg("functions cannot have more than %d arguments", FUNC_MAX_ARGS))); /* * Do not allow return type ANYARRAY or ANYELEMENT unless at least one * argument is also ANYARRAY or ANYELEMENT */ if (returnType == ANYARRAYOID || returnType == ANYELEMENTOID) { bool genericParam = false; for (i = 0; i < parameterCount; i++) { if (parameterTypes[i] == ANYARRAYOID || parameterTypes[i] == ANYELEMENTOID) { genericParam = true; break; } } if (!genericParam) ereport(ERROR, (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION), errmsg("cannot determine result data type"), errdetail("A function returning \"anyarray\" or \"anyelement\" must have at least one argument of either type."))); } /* Make sure we have a zero-padded param type array */ MemSet(typev, 0, FUNC_MAX_ARGS * sizeof(Oid)); if (parameterCount > 0) memcpy(typev, parameterTypes, parameterCount * sizeof(Oid)); if (languageObjectId == SQLlanguageId) { /* * If this call is defining a set, check if the set is already * defined by looking to see whether this call's function text * matches a function already in pg_proc. If so just return the * OID of the existing set. */ if (strcmp(procedureName, GENERICSETNAME) == 0) {#ifdef SETS_FIXED /* * The code below doesn't work any more because the PROSRC * system cache and the pg_proc_prosrc_index have been * removed. Instead a sequential heap scan or something better * must get implemented. The reason for removing is that * nbtree index crashes if sources exceed 2K --- what's likely * for procedural languages. * * 1999/09/30 Jan */ text *prosrctext; prosrctext = DatumGetTextP(DirectFunctionCall1(textin, CStringGetDatum(prosrc))); retval = GetSysCacheOid(PROSRC, PointerGetDatum(prosrctext), 0, 0, 0); pfree(prosrctext); if (OidIsValid(retval)) return retval;#else elog(ERROR, "lookup for procedure by source needs fix (Jan)");#endif /* SETS_FIXED */ } } /* * don't allow functions of complex types that have the same name as * existing attributes of the type */ if (parameterCount == 1 && OidIsValid(typev[0]) && (relid = typeidTypeRelid(typev[0])) != InvalidOid && get_attnum(relid, (char *) procedureName) != InvalidAttrNumber) ereport(ERROR, (errcode(ERRCODE_DUPLICATE_COLUMN), errmsg("\"%s\" is already an attribute of type %s", procedureName, format_type_be(typev[0])))); /* * All seems OK; prepare the data to be inserted into pg_proc. */ for (i = 0; i < Natts_pg_proc; ++i) { nulls[i] = ' '; values[i] = (Datum) NULL; replaces[i] = 'r'; } i = 0; namestrcpy(&procname, procedureName); values[i++] = NameGetDatum(&procname); /* proname */ values[i++] = ObjectIdGetDatum(procNamespace); /* pronamespace */ values[i++] = Int32GetDatum(GetUserId()); /* proowner */ values[i++] = ObjectIdGetDatum(languageObjectId); /* prolang */ values[i++] = BoolGetDatum(isAgg); /* proisagg */ values[i++] = BoolGetDatum(security_definer); /* prosecdef */ values[i++] = BoolGetDatum(isStrict); /* proisstrict */ values[i++] = BoolGetDatum(returnsSet); /* proretset */ values[i++] = CharGetDatum(volatility); /* provolatile */ values[i++] = UInt16GetDatum(parameterCount); /* pronargs */ values[i++] = ObjectIdGetDatum(returnType); /* prorettype */ values[i++] = PointerGetDatum(typev); /* proargtypes */ values[i++] = DirectFunctionCall1(textin, /* prosrc */ CStringGetDatum(prosrc)); values[i++] = DirectFunctionCall1(textin, /* probin */ CStringGetDatum(probin)); /* proacl will be handled below */ rel = heap_openr(ProcedureRelationName, RowExclusiveLock); tupDesc = rel->rd_att; /* Check for pre-existing definition */ oldtup = SearchSysCache(PROCNAMENSP, PointerGetDatum(procedureName), UInt16GetDatum(parameterCount), PointerGetDatum(typev), ObjectIdGetDatum(procNamespace)); if (HeapTupleIsValid(oldtup)) { /* There is one; okay to replace it? */ Form_pg_proc oldproc = (Form_pg_proc) GETSTRUCT(oldtup); if (!replace) ereport(ERROR, (errcode(ERRCODE_DUPLICATE_FUNCTION), errmsg("function \"%s\" already exists with same argument types", procedureName))); if (GetUserId() != oldproc->proowner && !superuser()) aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC, procedureName); /* * Not okay to change the return type of the existing proc, since * existing rules, views, etc may depend on the return type. */ if (returnType != oldproc->prorettype || returnsSet != oldproc->proretset) ereport(ERROR, (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION), errmsg("cannot change return type of existing function"), errhint("Use DROP FUNCTION first."))); /* Can't change aggregate status, either */ if (oldproc->proisagg != isAgg) { if (oldproc->proisagg) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("function \"%s\" is an aggregate", procedureName))); else ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("function \"%s\" is not an aggregate", procedureName))); } /* do not change existing ownership or permissions, either */ replaces[Anum_pg_proc_proowner - 1] = ' '; replaces[Anum_pg_proc_proacl - 1] = ' '; /* Okay, do it... */ tup = heap_modifytuple(oldtup, rel, values, nulls, replaces); simple_heap_update(rel, &tup->t_self, tup); ReleaseSysCache(oldtup); is_update = true; } else { /* Creating a new procedure */ /* start out with empty permissions */ nulls[Anum_pg_proc_proacl - 1] = 'n'; tup = heap_formtuple(tupDesc, values, nulls); simple_heap_insert(rel, tup); is_update = false; } /* Need to update indexes for either the insert or update case */ CatalogUpdateIndexes(rel, tup); retval = HeapTupleGetOid(tup); /* * Create dependencies for the new function. If we are updating an * existing function, first delete any existing pg_depend entries. */ if (is_update) deleteDependencyRecordsFor(RelOid_pg_proc, retval); myself.classId = RelOid_pg_proc; myself.objectId = retval; myself.objectSubId = 0; /* dependency on namespace */ referenced.classId = get_system_catalog_relid(NamespaceRelationName); referenced.objectId = procNamespace; referenced.objectSubId = 0; recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); /* dependency on implementation language */ referenced.classId = get_system_catalog_relid(LanguageRelationName); referenced.objectId = languageObjectId; referenced.objectSubId = 0; recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); /* dependency on return type */ referenced.classId = RelOid_pg_type; referenced.objectId = returnType; referenced.objectSubId = 0; recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); /* dependency on input types */ for (i = 0; i < parameterCount; i++) { referenced.classId = RelOid_pg_type; referenced.objectId = typev[i]; referenced.objectSubId = 0; recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); } heap_freetuple(tup); heap_close(rel, RowExclusiveLock); /* Verify function body */ if (OidIsValid(languageValidator)) { /* Advance command counter so new tuple can be seen by validator */ CommandCounterIncrement(); OidFunctionCall1(languageValidator, ObjectIdGetDatum(retval)); } return retval;}/* * check_sql_fn_retval() -- check return value of a list of sql parse trees. * * The return value of a sql function is the value returned by * the final query in the function. We do some ad-hoc type checking here * to be sure that the user is returning the type he claims. * * This is normally applied during function definition, but in the case * of a function with polymorphic arguments, we instead apply it during * function execution startup. The rettype is then the actual resolved * output type of the function, rather than the declared type. (Therefore, * we should never see ANYARRAY or ANYELEMENT as rettype.) */voidcheck_sql_fn_retval(Oid rettype, char fn_typtype, List *queryTreeList){ Query *parse; int cmd; List *tlist; List *tlistitem; int tlistlen; Oid typerelid; Oid restype; Relation reln; int relnatts; /* physical number of columns in rel */ int rellogcols; /* # of nondeleted columns in rel */ int colindex; /* physical column index */ /* guard against empty function body; OK only if void return type */ if (queryTreeList == NIL) { if (rettype != VOIDOID) ereport(ERROR, (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?