typecmds.c

来自「PostgreSQL7.4.6 for Linux」· C语言 代码 · 共 2,044 行 · 第 1/4 页

C
2,044
字号
	 * presently useless since the parser will have truncated the name to	 * fit.  But leave it here since we may someday support arrays of	 * domains, in which case we'll be back to needing to enforce	 * NAMEDATALEN-2.)	 */	if (strlen(domainName) > (NAMEDATALEN - 1))		ereport(ERROR,				(errcode(ERRCODE_INVALID_NAME),				 errmsg("domain names must be %d characters or less",						NAMEDATALEN - 1)));	/*	 * Look up the base type.	 */	typeTup = typenameType(stmt->typename);	baseType = (Form_pg_type) GETSTRUCT(typeTup);	basetypeoid = HeapTupleGetOid(typeTup);	/*	 * Base type must be a plain base type.  Domains over pseudo types	 * would create a security hole.  Domains of domains might be made to	 * work in the future, but not today.  Ditto for domains over complex	 * types.	 */	typtype = baseType->typtype;	if (typtype != 'b')		ereport(ERROR,				(errcode(ERRCODE_DATATYPE_MISMATCH),				 errmsg("\"%s\" is not a valid base type for a domain",						TypeNameToString(stmt->typename))));	/* passed by value */	byValue = baseType->typbyval;	/* Required Alignment */	alignment = baseType->typalign;	/* TOAST Strategy */	storage = baseType->typstorage;	/* Storage Length */	internalLength = baseType->typlen;	/* Array element Delimiter */	delimiter = baseType->typdelim;	/* I/O Functions */	inputProcedure = baseType->typinput;	outputProcedure = baseType->typoutput;	receiveProcedure = baseType->typreceive;	sendProcedure = baseType->typsend;	/* Inherited default value */	datum = SysCacheGetAttr(TYPEOID, typeTup,							Anum_pg_type_typdefault, &isnull);	if (!isnull)		defaultValue = DatumGetCString(DirectFunctionCall1(textout, datum));	/* Inherited default binary value */	datum = SysCacheGetAttr(TYPEOID, typeTup,							Anum_pg_type_typdefaultbin, &isnull);	if (!isnull)		defaultValueBin = DatumGetCString(DirectFunctionCall1(textout, datum));	/*	 * Pull out the typelem name of the parent OID.	 *	 * This is what enables us to make a domain of an array	 */	basetypelem = baseType->typelem;	/*	 * Run through constraints manually to avoid the additional processing	 * conducted by DefineRelation() and friends.	 */	foreach(listptr, schema)	{		Node	   *newConstraint = lfirst(listptr);		Constraint *constr;		ParseState *pstate;		/* Check for unsupported constraint types */		if (IsA(newConstraint, FkConstraint))			ereport(ERROR,					(errcode(ERRCODE_SYNTAX_ERROR),			errmsg("foreign key constraints not possible for domains")));		/* otherwise it should be a plain Constraint */		if (!IsA(newConstraint, Constraint))			elog(ERROR, "unrecognized node type: %d",				 (int) nodeTag(newConstraint));		constr = (Constraint *) newConstraint;		switch (constr->contype)		{			case CONSTR_DEFAULT:				/*				 * The inherited default value may be overridden by the				 * user with the DEFAULT <expr> statement.				 */				if (defaultExpr)					ereport(ERROR,							(errcode(ERRCODE_SYNTAX_ERROR),							 errmsg("multiple default expressions")));				/* Create a dummy ParseState for transformExpr */				pstate = make_parsestate(NULL);				/*				 * Cook the constr->raw_expr into an expression. Note:				 * Name is strictly for error message				 */				defaultExpr = cookDefault(pstate, constr->raw_expr,										  basetypeoid,										  stmt->typename->typmod,										  domainName);				/*				 * Expression must be stored as a nodeToString result, but				 * we also require a valid textual representation (mainly				 * to make life easier for pg_dump).				 */				defaultValue = deparse_expression(defaultExpr,										  deparse_context_for(domainName,															  InvalidOid),												  false, false);				defaultValueBin = nodeToString(defaultExpr);				break;			case CONSTR_NOTNULL:				if (nullDefined && !typNotNull)					ereport(ERROR,							(errcode(ERRCODE_SYNTAX_ERROR),					   errmsg("conflicting NULL/NOT NULL constraints")));				typNotNull = true;				nullDefined = true;				break;			case CONSTR_NULL:				if (nullDefined && typNotNull)					ereport(ERROR,							(errcode(ERRCODE_SYNTAX_ERROR),					   errmsg("conflicting NULL/NOT NULL constraints")));				typNotNull = false;				nullDefined = true;				break;			case CONSTR_CHECK:				/*				 * Check constraints are handled after domain creation, as				 * they require the Oid of the domain				 */				break;				/*				 * All else are error cases				 */			case CONSTR_UNIQUE:				ereport(ERROR,						(errcode(ERRCODE_SYNTAX_ERROR),				errmsg("unique constraints not possible for domains")));				break;			case CONSTR_PRIMARY:				ereport(ERROR,						(errcode(ERRCODE_SYNTAX_ERROR),						 errmsg("primary key constraints not possible for domains")));				break;			case CONSTR_ATTR_DEFERRABLE:			case CONSTR_ATTR_NOT_DEFERRABLE:			case CONSTR_ATTR_DEFERRED:			case CONSTR_ATTR_IMMEDIATE:				ereport(ERROR,						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),						 errmsg("specifying constraint deferrability not supported for domains")));				break;			default:				elog(ERROR, "unrecognized constraint subtype: %d",					 (int) constr->contype);				break;		}	}	/*	 * Have TypeCreate do all the real work.	 */	domainoid =		TypeCreate(domainName,	/* type name */				   domainNamespace,		/* namespace */				   InvalidOid,	/* preassigned type oid (none here) */				   InvalidOid,	/* relation oid (n/a here) */				   0,			/* relation kind (ditto) */				   internalLength,		/* internal size */				   'd',			/* type-type (domain type) */				   delimiter,	/* array element delimiter */				   inputProcedure,		/* input procedure */				   outputProcedure,		/* output procedure */				   receiveProcedure,	/* receive procedure */				   sendProcedure,		/* send procedure */				   basetypelem, /* element type ID */				   basetypeoid, /* base type ID */				   defaultValue,	/* default type value (text) */				   defaultValueBin,		/* default type value (binary) */				   byValue,		/* passed by value */				   alignment,	/* required alignment */				   storage,		/* TOAST strategy */				   stmt->typename->typmod,		/* typeMod value */				   typNDims,	/* Array dimensions for base type */				   typNotNull); /* Type NOT NULL */	/*	 * Process constraints which refer to the domain ID returned by	 * TypeCreate	 */	foreach(listptr, schema)	{		Constraint *constr = lfirst(listptr);		/* it must be a Constraint, per check above */		switch (constr->contype)		{			case CONSTR_CHECK:				domainAddConstraint(domainoid, domainNamespace,									basetypeoid, stmt->typename->typmod,									constr, &counter, domainName);				break;				/* Other constraint types were fully processed above */			default:				break;		}	}	/*	 * Now we can clean up.	 */	ReleaseSysCache(typeTup);}/* *	RemoveDomain *		Removes a domain. * * This is identical to RemoveType except we insist it be a domain. */voidRemoveDomain(List *names, DropBehavior behavior){	TypeName   *typename;	Oid			typeoid;	HeapTuple	tup;	char		typtype;	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));	/* Check that this is actually a domain */	typtype = ((Form_pg_type) GETSTRUCT(tup))->typtype;	if (typtype != 'd')		ereport(ERROR,				(errcode(ERRCODE_WRONG_OBJECT_TYPE),				 errmsg("\"%s\" is not a domain",						TypeNameToString(typename))));	ReleaseSysCache(tup);	/*	 * Do the deletion	 */	object.classId = RelOid_pg_type;	object.objectId = typeoid;	object.objectSubId = 0;	performDeletion(&object, behavior);}/* * Find suitable I/O functions for a type. * * typeOid is the type's OID (which will already exist, if only as a shell * type). */static OidfindTypeInputFunction(List *procname, Oid typeOid){	Oid			argList[FUNC_MAX_ARGS];	Oid			procOid;	/*	 * Input functions can take a single argument of type CSTRING, or	 * three arguments (string, element OID, typmod).	 *	 * For backwards compatibility we allow OPAQUE in place of CSTRING; if we	 * see this, we issue a warning and fix up the pg_proc entry.	 */	MemSet(argList, 0, FUNC_MAX_ARGS * sizeof(Oid));	argList[0] = CSTRINGOID;	procOid = LookupFuncName(procname, 1, argList, true);	if (OidIsValid(procOid))		return procOid;	argList[1] = OIDOID;	argList[2] = INT4OID;	procOid = LookupFuncName(procname, 3, argList, true);	if (OidIsValid(procOid))		return procOid;	/* No luck, try it with OPAQUE */	MemSet(argList, 0, FUNC_MAX_ARGS * sizeof(Oid));	argList[0] = OPAQUEOID;	procOid = LookupFuncName(procname, 1, argList, true);	if (!OidIsValid(procOid))	{		argList[1] = OIDOID;		argList[2] = INT4OID;		procOid = LookupFuncName(procname, 3, argList, true);	}	if (OidIsValid(procOid))	{		/* Found, but must complain and fix the pg_proc entry */		ereport(WARNING,				(errmsg("changing argument type of function %s from \"opaque\" to \"cstring\"",						NameListToString(procname))));		SetFunctionArgType(procOid, 0, CSTRINGOID);		/*		 * Need CommandCounterIncrement since DefineType will likely try		 * to alter the pg_proc tuple again.		 */		CommandCounterIncrement();		return procOid;	}	/* Use CSTRING (preferred) in the error message */	argList[0] = CSTRINGOID;	ereport(ERROR,			(errcode(ERRCODE_UNDEFINED_FUNCTION),			 errmsg("function %s does not exist",					func_signature_string(procname, 1, argList))));	return InvalidOid;			/* keep compiler quiet */}static OidfindTypeOutputFunction(List *procname, Oid typeOid){	Oid			argList[FUNC_MAX_ARGS];	Oid			procOid;	/*	 * Output functions can take a single argument of the type, or two	 * arguments (data value, element OID).	 *	 * For backwards compatibility we allow OPAQUE in place of the actual	 * type name; if we see this, we issue a warning and fix up the pg_proc	 * entry.	 */	MemSet(argList, 0, FUNC_MAX_ARGS * sizeof(Oid));	argList[0] = typeOid;	procOid = LookupFuncName(procname, 1, argList, true);	if (OidIsValid(procOid))		return procOid;	argList[1] = OIDOID;	procOid = LookupFuncName(procname, 2, argList, true);	if (OidIsValid(procOid))		return procOid;	/* No luck, try it with OPAQUE */	MemSet(argList, 0, FUNC_MAX_ARGS * sizeof(Oid));	argList[0] = OPAQUEOID;	procOid = LookupFuncName(procname, 1, argList, true);	if (!OidIsValid(procOid))	{		argList[1] = OIDOID;		procOid = LookupFuncName(procname, 2, argList, true);	}	if (OidIsValid(procOid))	{		/* Found, but must complain and fix the pg_proc entry */		ereport(WARNING,		(errmsg("changing argument type of function %s from \"opaque\" to %s",				NameListToString(procname), format_type_be(typeOid))));		SetFunctionArgType(procOid, 0, typeOid);		/*		 * Need CommandCounterIncrement since DefineType will likely try		 * to alter the pg_proc tuple again.		 */		CommandCounterIncrement();		return procOid;	}	/* Use type name, not OPAQUE, in the failure message. */	argList[0] = typeOid;	ereport(ERROR,			(errcode(ERRCODE_UNDEFINED_FUNCTION),			 errmsg("function %s does not exist",					func_signature_string(procname, 1, argList))));	return InvalidOid;			/* keep compiler quiet */}static OidfindTypeReceiveFunction(List *procname, Oid typeOid){	Oid			argList[FUNC_MAX_ARGS];	Oid			procOid;	/*	 * Receive functions can take a single argument of type INTERNAL, or	 * two arguments (internal, oid).	 */	MemSet(argList, 0, FUNC_MAX_ARGS * sizeof(Oid));	argList[0] = INTERNALOID;	procOid = LookupFuncName(procname, 1, argList, true);	if (OidIsValid(procOid))		return procOid;	argList[1] = OIDOID;	procOid = LookupFuncName(procname, 2, argList, true);	if (OidIsValid(procOid))		return procOid;	ereport(ERROR,			(errcode(ERRCODE_UNDEFINED_FUNCTION),			 errmsg("function %s does not exist",					func_signature_string(procname, 1, argList))));	return InvalidOid;			/* keep compiler quiet */}static OidfindTypeSendFunction(List *procname, Oid typeOid){	Oid			argList[FUNC_MAX_ARGS];	Oid			procOid;	/*	 * Send functions can take a single argument of the type, or two	 * arguments (data value, element OID).	 */	MemSet(argList, 0, FUNC_MAX_ARGS * sizeof(Oid));	argList[0] = typeOid;	procOid = LookupFuncName(procname, 1, argList, true);	if (OidIsValid(procOid))		return procOid;	argList[1] = OIDOID;

⌨️ 快捷键说明

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