⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 typecmds.c

📁 PostgreSQL 8.1.4的源码 适用于Linux下的开源数据库系统
💻 C
📖 第 1 页 / 共 5 页
字号:
/*------------------------------------------------------------------------- * * typecmds.c *	  Routines for SQL commands that manipulate types (and domains). * * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION *	  $PostgreSQL: pgsql/src/backend/commands/typecmds.c,v 1.82.2.1 2005/11/22 18:23:08 momjian Exp $ * * DESCRIPTION *	  The "DefineFoo" routines take the parse tree and pick out the *	  appropriate arguments/flags, passing 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 functions *		"create type": *				type *		"create operator": *				operators * * *------------------------------------------------------------------------- */#include "postgres.h"#include "access/heapam.h"#include "access/genam.h"#include "catalog/dependency.h"#include "catalog/heap.h"#include "catalog/indexing.h"#include "catalog/namespace.h"#include "catalog/pg_constraint.h"#include "catalog/pg_depend.h"#include "catalog/pg_namespace.h"#include "catalog/pg_type.h"#include "commands/defrem.h"#include "commands/tablecmds.h"#include "commands/typecmds.h"#include "executor/executor.h"#include "miscadmin.h"#include "nodes/execnodes.h"#include "nodes/nodes.h"#include "optimizer/clauses.h"#include "optimizer/planmain.h"#include "optimizer/var.h"#include "parser/parse_coerce.h"#include "parser/parse_expr.h"#include "parser/parse_func.h"#include "parser/parse_relation.h"#include "parser/parse_type.h"#include "utils/acl.h"#include "utils/builtins.h"#include "utils/fmgroids.h"#include "utils/lsyscache.h"#include "utils/memutils.h"#include "utils/syscache.h"/* result structure for get_rels_with_domain() */typedef struct{	Relation	rel;			/* opened and locked relation */	int			natts;			/* number of attributes of interest */	int		   *atts;			/* attribute numbers */	/* atts[] is of allocated length RelationGetNumberOfAttributes(rel) */} RelToCheck;static Oid	findTypeInputFunction(List *procname, Oid typeOid);static Oid	findTypeOutputFunction(List *procname, Oid typeOid);static Oid	findTypeReceiveFunction(List *procname, Oid typeOid);static Oid	findTypeSendFunction(List *procname, Oid typeOid);static Oid	findTypeAnalyzeFunction(List *procname, Oid typeOid);static List *get_rels_with_domain(Oid domainOid, LOCKMODE lockmode);static void domainOwnerCheck(HeapTuple tup, TypeName *typename);static char *domainAddConstraint(Oid domainOid, Oid domainNamespace,					Oid baseTypeOid,					int typMod, Constraint *constr,					char *domainName);/* * DefineType *		Registers a new type. */voidDefineType(List *names, List *parameters){	char	   *typeName;	Oid			typeNamespace;	AclResult	aclresult;	int16		internalLength = -1;	/* default: variable-length */	Oid			elemType = InvalidOid;	List	   *inputName = NIL;	List	   *outputName = NIL;	List	   *receiveName = NIL;	List	   *sendName = NIL;	List	   *analyzeName = NIL;	char	   *defaultValue = NULL;	bool		byValue = false;	char		delimiter = DEFAULT_TYPDELIM;	char		alignment = 'i';	/* default alignment */	char		storage = 'p';	/* default TOAST storage method */	Oid			inputOid;	Oid			outputOid;	Oid			receiveOid = InvalidOid;	Oid			sendOid = InvalidOid;	Oid			analyzeOid = InvalidOid;	char	   *shadow_type;	ListCell   *pl;	Oid			typoid;	Oid			resulttype;	/* Convert list of names to a name and namespace */	typeNamespace = QualifiedNameGetCreationNamespace(names, &typeName);	/* Check we have creation rights in target namespace */	aclresult = pg_namespace_aclcheck(typeNamespace, GetUserId(), ACL_CREATE);	if (aclresult != ACLCHECK_OK)		aclcheck_error(aclresult, ACL_KIND_NAMESPACE,					   get_namespace_name(typeNamespace));	/*	 * Type names must be one character shorter than other names, allowing	 * room to create the corresponding array type name with prepended "_".	 */	if (strlen(typeName) > (NAMEDATALEN - 2))		ereport(ERROR,				(errcode(ERRCODE_INVALID_NAME),				 errmsg("type names must be %d characters or less",						NAMEDATALEN - 2)));	foreach(pl, parameters)	{		DefElem    *defel = (DefElem *) lfirst(pl);		if (pg_strcasecmp(defel->defname, "internallength") == 0)			internalLength = defGetTypeLength(defel);		else if (pg_strcasecmp(defel->defname, "externallength") == 0)			;					/* ignored -- remove after 7.3 */		else if (pg_strcasecmp(defel->defname, "input") == 0)			inputName = defGetQualifiedName(defel);		else if (pg_strcasecmp(defel->defname, "output") == 0)			outputName = defGetQualifiedName(defel);		else if (pg_strcasecmp(defel->defname, "receive") == 0)			receiveName = defGetQualifiedName(defel);		else if (pg_strcasecmp(defel->defname, "send") == 0)			sendName = defGetQualifiedName(defel);		else if (pg_strcasecmp(defel->defname, "analyze") == 0 ||				 pg_strcasecmp(defel->defname, "analyse") == 0)			analyzeName = defGetQualifiedName(defel);		else if (pg_strcasecmp(defel->defname, "delimiter") == 0)		{			char	   *p = defGetString(defel);			delimiter = p[0];		}		else if (pg_strcasecmp(defel->defname, "element") == 0)		{			elemType = typenameTypeId(defGetTypeName(defel));			/* disallow arrays of pseudotypes */			if (get_typtype(elemType) == 'p')				ereport(ERROR,						(errcode(ERRCODE_DATATYPE_MISMATCH),						 errmsg("array element type cannot be %s",								format_type_be(elemType))));		}		else if (pg_strcasecmp(defel->defname, "default") == 0)			defaultValue = defGetString(defel);		else if (pg_strcasecmp(defel->defname, "passedbyvalue") == 0)			byValue = defGetBoolean(defel);		else if (pg_strcasecmp(defel->defname, "alignment") == 0)		{			char	   *a = defGetString(defel);			/*			 * Note: if argument was an unquoted identifier, parser will have			 * applied translations to it, so be prepared to recognize			 * translated type names as well as the nominal form.			 */			if (pg_strcasecmp(a, "double") == 0 ||				pg_strcasecmp(a, "float8") == 0 ||				pg_strcasecmp(a, "pg_catalog.float8") == 0)				alignment = 'd';			else if (pg_strcasecmp(a, "int4") == 0 ||					 pg_strcasecmp(a, "pg_catalog.int4") == 0)				alignment = 'i';			else if (pg_strcasecmp(a, "int2") == 0 ||					 pg_strcasecmp(a, "pg_catalog.int2") == 0)				alignment = 's';			else if (pg_strcasecmp(a, "char") == 0 ||					 pg_strcasecmp(a, "pg_catalog.bpchar") == 0)				alignment = 'c';			else				ereport(ERROR,						(errcode(ERRCODE_INVALID_PARAMETER_VALUE),						 errmsg("alignment \"%s\" not recognized", a)));		}		else if (pg_strcasecmp(defel->defname, "storage") == 0)		{			char	   *a = defGetString(defel);			if (pg_strcasecmp(a, "plain") == 0)				storage = 'p';			else if (pg_strcasecmp(a, "external") == 0)				storage = 'e';			else if (pg_strcasecmp(a, "extended") == 0)				storage = 'x';			else if (pg_strcasecmp(a, "main") == 0)				storage = 'm';			else				ereport(ERROR,						(errcode(ERRCODE_INVALID_PARAMETER_VALUE),						 errmsg("storage \"%s\" not recognized", a)));		}		else			ereport(WARNING,					(errcode(ERRCODE_SYNTAX_ERROR),					 errmsg("type attribute \"%s\" not recognized",							defel->defname)));	}	/*	 * make sure we have our required definitions	 */	if (inputName == NIL)		ereport(ERROR,				(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),				 errmsg("type input function must be specified")));	if (outputName == NIL)		ereport(ERROR,				(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),				 errmsg("type output function must be specified")));	/*	 * Look to see if type already exists (presumably as a shell; if not,	 * TypeCreate will complain).  If it doesn't, create it as a shell, so	 * that the OID is known for use in the I/O function definitions.	 */	typoid = GetSysCacheOid(TYPENAMENSP,							CStringGetDatum(typeName),							ObjectIdGetDatum(typeNamespace),							0, 0);	if (!OidIsValid(typoid))	{		typoid = TypeShellMake(typeName, typeNamespace);		/* Make new shell type visible for modification below */		CommandCounterIncrement();	}	/*	 * Convert I/O proc names to OIDs	 */	inputOid = findTypeInputFunction(inputName, typoid);	outputOid = findTypeOutputFunction(outputName, typoid);	if (receiveName)		receiveOid = findTypeReceiveFunction(receiveName, typoid);	if (sendName)		sendOid = findTypeSendFunction(sendName, typoid);	/*	 * Verify that I/O procs return the expected thing.  If we see OPAQUE,	 * complain and change it to the correct type-safe choice.	 */	resulttype = get_func_rettype(inputOid);	if (resulttype != typoid)	{		if (resulttype == OPAQUEOID)		{			/* backwards-compatibility hack */			ereport(WARNING,					(errmsg("changing return type of function %s from \"opaque\" to %s",							NameListToString(inputName), typeName)));			SetFunctionReturnType(inputOid, typoid);		}		else			ereport(ERROR,					(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),					 errmsg("type input function %s must return type %s",							NameListToString(inputName), typeName)));	}	resulttype = get_func_rettype(outputOid);	if (resulttype != CSTRINGOID)	{		if (resulttype == OPAQUEOID)		{			/* backwards-compatibility hack */			ereport(WARNING,					(errmsg("changing return type of function %s from \"opaque\" to \"cstring\"",							NameListToString(outputName))));			SetFunctionReturnType(outputOid, CSTRINGOID);		}		else			ereport(ERROR,					(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),			   errmsg("type output function %s must return type \"cstring\"",					  NameListToString(outputName))));	}	if (receiveOid)	{		resulttype = get_func_rettype(receiveOid);		if (resulttype != typoid)			ereport(ERROR,					(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),					 errmsg("type receive function %s must return type %s",							NameListToString(receiveName), typeName)));	}	if (sendOid)	{		resulttype = get_func_rettype(sendOid);		if (resulttype != BYTEAOID)			ereport(ERROR,					(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),				   errmsg("type send function %s must return type \"bytea\"",						  NameListToString(sendName))));	}	/*	 * Convert analysis function proc name to an OID. If no analysis function	 * is specified, we'll use zero to select the built-in default algorithm.	 */	if (analyzeName)		analyzeOid = findTypeAnalyzeFunction(analyzeName, typoid);	/*	 * now have TypeCreate do all the real work.	 */	typoid =		TypeCreate(typeName,	/* type name */				   typeNamespace,		/* namespace */				   InvalidOid,	/* relation oid (n/a here) */				   0,			/* relation kind (ditto) */				   internalLength,		/* internal size */				   'b',			/* type-type (base type) */				   delimiter,	/* array element delimiter */				   inputOid,	/* input procedure */				   outputOid,	/* output procedure */				   receiveOid,	/* receive procedure */				   sendOid,		/* send procedure */				   analyzeOid,	/* analyze procedure */				   elemType,	/* element type ID */				   InvalidOid,	/* base type ID (only for domains) */				   defaultValue,	/* default type value */				   NULL,		/* no binary form available */				   byValue,		/* passed by value */				   alignment,	/* required alignment */				   storage,		/* TOAST strategy */				   -1,			/* typMod (Domains only) */				   0,			/* Array Dimensions of typbasetype */				   false);		/* Type NOT NULL */	/*	 * When we create a base type (as opposed to a complex type) we need to	 * have an array entry for it in pg_type as well.	 */	shadow_type = makeArrayTypeName(typeName);	/* alignment must be 'i' or 'd' for arrays */	alignment = (alignment == 'd') ? 'd' : 'i';	TypeCreate(shadow_type,		/* type name */			   typeNamespace,	/* namespace */			   InvalidOid,		/* relation oid (n/a here) */			   0,				/* relation kind (ditto) */			   -1,				/* internal size */			   'b',				/* type-type (base type) */			   DEFAULT_TYPDELIM,	/* array element delimiter */			   F_ARRAY_IN,		/* input procedure */			   F_ARRAY_OUT,		/* output procedure */			   F_ARRAY_RECV,	/* receive procedure */			   F_ARRAY_SEND,	/* send procedure */			   InvalidOid,		/* analyze procedure - default */			   typoid,			/* element type ID */			   InvalidOid,		/* base type ID */			   NULL,			/* never a default type value */			   NULL,			/* binary default isn't sent either */			   false,			/* never passed by value */			   alignment,		/* see above */			   'x',				/* ARRAY is always toastable */			   -1,				/* typMod (Domains only) */			   0,				/* Array dimensions of typbasetype */			   false);			/* Type NOT NULL */	pfree(shadow_type);}/* *	RemoveType *		Removes a datatype. */voidRemoveType(List *names, DropBehavior behavior){	TypeName   *typename;	Oid			typeoid;	HeapTuple	tup;	ObjectAddress object;	/* Make a TypeName so we can use standard type lookup machinery */	typename = makeNode(TypeName);	typename->names = names;	typename->typmod = -1;	typename->arrayBounds = NIL;	/* Use LookupTypeName here so that shell types can be removed. */	typeoid = LookupTypeName(typename);	if (!OidIsValid(typeoid))		ereport(ERROR,				(errcode(ERRCODE_UNDEFINED_OBJECT),				 errmsg("type \"%s\" does not exist",						TypeNameToString(typename))));	tup = SearchSysCache(TYPEOID,						 ObjectIdGetDatum(typeoid),						 0, 0, 0);	if (!HeapTupleIsValid(tup))		elog(ERROR, "cache lookup failed for type %u", typeoid);	/* Permission check: must own type or its namespace */	if (!pg_type_ownercheck(typeoid, GetUserId()) &&	  !pg_namespace_ownercheck(((Form_pg_type) GETSTRUCT(tup))->typnamespace,							   GetUserId()))		aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TYPE,					   TypeNameToString(typename));	ReleaseSysCache(tup);	/*	 * Do the deletion	 */	object.classId = TypeRelationId;	object.objectId = typeoid;	object.objectSubId = 0;	performDeletion(&object, behavior);}/* * Guts of type deletion. */voidRemoveTypeById(Oid typeOid){	Relation	relation;	HeapTuple	tup;	relation = heap_open(TypeRelationId, RowExclusiveLock);	tup = SearchSysCache(TYPEOID,						 ObjectIdGetDatum(typeOid),

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -