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