parse_coerce.c

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

C
1,605
字号
			if (!OidIsValid(array_typelem))				ereport(ERROR,						(errcode(ERRCODE_DATATYPE_MISMATCH),						 errmsg("argument declared \"anyarray\" is not an array but type %s",								format_type_be(context_actual_type))));			return context_actual_type;		}		else if (context_declared_type == ANYELEMENTOID)		{			/* Use the array type corresponding to actual type */			Oid			array_typeid = get_array_type(context_actual_type);			if (!OidIsValid(array_typeid))				ereport(ERROR,						(errcode(ERRCODE_UNDEFINED_OBJECT),					  errmsg("could not find array type for data type %s",							 format_type_be(context_actual_type))));			return array_typeid;		}	}	else if (declared_type == ANYELEMENTOID)	{		if (context_declared_type == ANYARRAYOID)		{			/* Use the element type corresponding to actual type */			Oid			array_typelem = get_element_type(context_actual_type);			if (!OidIsValid(array_typelem))				ereport(ERROR,						(errcode(ERRCODE_DATATYPE_MISMATCH),						 errmsg("argument declared \"anyarray\" is not an array but type %s",								format_type_be(context_actual_type))));			return array_typelem;		}		else if (context_declared_type == ANYELEMENTOID)		{			/* Use the actual type; it doesn't matter if array or not */			return context_actual_type;		}	}	else	{		/* declared_type isn't polymorphic, so return it as-is */		return declared_type;	}	/* If we get here, declared_type is polymorphic and context isn't */	/* NB: this is a calling-code logic error, not a user error */	elog(ERROR, "could not determine ANYARRAY/ANYELEMENT type because context isn't polymorphic");	return InvalidOid;			/* keep compiler quiet */}/* TypeCategory() *		Assign a category to the specified type OID. * * NB: this must not return INVALID_TYPE. * * XXX This should be moved to system catalog lookups * to allow for better type extensibility. * - thomas 2001-09-30 */CATEGORYTypeCategory(Oid inType){	CATEGORY	result;	switch (inType)	{		case (BOOLOID):			result = BOOLEAN_TYPE;			break;		case (CHAROID):		case (NAMEOID):		case (BPCHAROID):		case (VARCHAROID):		case (TEXTOID):			result = STRING_TYPE;			break;		case (BITOID):		case (VARBITOID):			result = BITSTRING_TYPE;			break;		case (OIDOID):		case (REGPROCOID):		case (REGPROCEDUREOID):		case (REGOPEROID):		case (REGOPERATOROID):		case (REGCLASSOID):		case (REGTYPEOID):		case (INT2OID):		case (INT4OID):		case (INT8OID):		case (FLOAT4OID):		case (FLOAT8OID):		case (NUMERICOID):		case (CASHOID):			result = NUMERIC_TYPE;			break;		case (DATEOID):		case (TIMEOID):		case (TIMETZOID):		case (ABSTIMEOID):		case (TIMESTAMPOID):		case (TIMESTAMPTZOID):			result = DATETIME_TYPE;			break;		case (RELTIMEOID):		case (TINTERVALOID):		case (INTERVALOID):			result = TIMESPAN_TYPE;			break;		case (POINTOID):		case (LSEGOID):		case (PATHOID):		case (BOXOID):		case (POLYGONOID):		case (LINEOID):		case (CIRCLEOID):			result = GEOMETRIC_TYPE;			break;		case (INETOID):		case (CIDROID):			result = NETWORK_TYPE;			break;		case (UNKNOWNOID):		case (InvalidOid):			result = UNKNOWN_TYPE;			break;		case (RECORDOID):		case (CSTRINGOID):		case (ANYOID):		case (ANYARRAYOID):		case (VOIDOID):		case (TRIGGEROID):		case (LANGUAGE_HANDLEROID):		case (INTERNALOID):		case (OPAQUEOID):		case (ANYELEMENTOID):			result = GENERIC_TYPE;			break;		default:			result = USER_TYPE;			break;	}	return result;}	/* TypeCategory() *//* IsPreferredType() *		Check if this type is a preferred type for the given category. * * If category is INVALID_TYPE, then we'll return TRUE for preferred types * of any category; otherwise, only for preferred types of that category. * * XXX This should be moved to system catalog lookups * to allow for better type extensibility. * - thomas 2001-09-30 */boolIsPreferredType(CATEGORY category, Oid type){	Oid			preftype;	if (category == INVALID_TYPE)		category = TypeCategory(type);	else if (category != TypeCategory(type))		return false;	/*	 * This switch should agree with TypeCategory(), above.  Note that at	 * this point, category certainly matches the type.	 */	switch (category)	{		case (UNKNOWN_TYPE):		case (GENERIC_TYPE):			preftype = UNKNOWNOID;			break;		case (BOOLEAN_TYPE):			preftype = BOOLOID;			break;		case (STRING_TYPE):			preftype = TEXTOID;			break;		case (BITSTRING_TYPE):			preftype = VARBITOID;			break;		case (NUMERIC_TYPE):			if (type == OIDOID ||				type == REGPROCOID ||				type == REGPROCEDUREOID ||				type == REGOPEROID ||				type == REGOPERATOROID ||				type == REGCLASSOID ||				type == REGTYPEOID)				preftype = OIDOID;			else				preftype = FLOAT8OID;			break;		case (DATETIME_TYPE):			if (type == DATEOID)				preftype = TIMESTAMPOID;			else				preftype = TIMESTAMPTZOID;			break;		case (TIMESPAN_TYPE):			preftype = INTERVALOID;			break;		case (GEOMETRIC_TYPE):			preftype = type;			break;		case (NETWORK_TYPE):			preftype = INETOID;			break;		case (USER_TYPE):			preftype = type;			break;		default:			elog(ERROR, "unrecognized type category: %d", (int) category);			preftype = UNKNOWNOID;			break;	}	return (type == preftype);}	/* IsPreferredType() *//* IsBinaryCoercible() *		Check if srctype is binary-coercible to targettype. * * This notion allows us to cheat and directly exchange values without * going through the trouble of calling a conversion function.	Note that * in general, this should only be an implementation shortcut.	Before 7.4, * this was also used as a heuristic for resolving overloaded functions and * operators, but that's basically a bad idea. * * As of 7.3, binary coercibility isn't hardwired into the code anymore. * We consider two types binary-coercible if there is an implicitly * invokable, no-function-needed pg_cast entry.  Also, a domain is always * binary-coercible to its base type, though *not* vice versa (in the other * direction, one must apply domain constraint checks before accepting the * value as legitimate).  We also need to special-case the polymorphic * ANYARRAY type. * * This function replaces IsBinaryCompatible(), which was an inherently * symmetric test.	Since the pg_cast entries aren't necessarily symmetric, * the order of the operands is now significant. */boolIsBinaryCoercible(Oid srctype, Oid targettype){	HeapTuple	tuple;	Form_pg_cast castForm;	bool		result;	/* Fast path if same type */	if (srctype == targettype)		return true;	/* If srctype is a domain, reduce to its base type */	if (OidIsValid(srctype))		srctype = getBaseType(srctype);	/* Somewhat-fast path for domain -> base type case */	if (srctype == targettype)		return true;	/* Also accept any array type as coercible to ANYARRAY */	if (targettype == ANYARRAYOID)		if (get_element_type(srctype) != InvalidOid)			return true;	/* Else look in pg_cast */	tuple = SearchSysCache(CASTSOURCETARGET,						   ObjectIdGetDatum(srctype),						   ObjectIdGetDatum(targettype),						   0, 0);	if (!HeapTupleIsValid(tuple))		return false;			/* no cast */	castForm = (Form_pg_cast) GETSTRUCT(tuple);	result = (castForm->castfunc == InvalidOid &&			  castForm->castcontext == COERCION_CODE_IMPLICIT);	ReleaseSysCache(tuple);	return result;}/* * find_coercion_pathway *		Look for a coercion pathway between two types. * * ccontext determines the set of available casts. * * If we find a suitable entry in pg_cast, return TRUE, and set *funcid * to the castfunc value, which may be InvalidOid for a binary-compatible * coercion. * * NOTE: *funcid == InvalidOid does not necessarily mean that no work is * needed to do the coercion; if the target is a domain then we may need to * apply domain constraint checking.  If you want to check for a zero-effort * conversion then use IsBinaryCoercible(). */boolfind_coercion_pathway(Oid targetTypeId, Oid sourceTypeId,					  CoercionContext ccontext,					  Oid *funcid){	bool		result = false;	HeapTuple	tuple;	*funcid = InvalidOid;	/* Perhaps the types are domains; if so, look at their base types */	if (OidIsValid(sourceTypeId))		sourceTypeId = getBaseType(sourceTypeId);	if (OidIsValid(targetTypeId))		targetTypeId = getBaseType(targetTypeId);	/* Domains are always coercible to and from their base type */	if (sourceTypeId == targetTypeId)		return true;	/* Look in pg_cast */	tuple = SearchSysCache(CASTSOURCETARGET,						   ObjectIdGetDatum(sourceTypeId),						   ObjectIdGetDatum(targetTypeId),						   0, 0);	if (HeapTupleIsValid(tuple))	{		Form_pg_cast castForm = (Form_pg_cast) GETSTRUCT(tuple);		CoercionContext castcontext;		/* convert char value for castcontext to CoercionContext enum */		switch (castForm->castcontext)		{			case COERCION_CODE_IMPLICIT:				castcontext = COERCION_IMPLICIT;				break;			case COERCION_CODE_ASSIGNMENT:				castcontext = COERCION_ASSIGNMENT;				break;			case COERCION_CODE_EXPLICIT:				castcontext = COERCION_EXPLICIT;				break;			default:				elog(ERROR, "unrecognized castcontext: %d",					 (int) castForm->castcontext);				castcontext = 0;	/* keep compiler quiet */				break;		}		/* Rely on ordering of enum for correct behavior here */		if (ccontext >= castcontext)		{			*funcid = castForm->castfunc;			result = true;		}		ReleaseSysCache(tuple);	}	else	{		/*		 * If there's no pg_cast entry, perhaps we are dealing with a pair		 * of array types.	If so, and if the element types have a		 * suitable cast, use array_type_coerce().		 */		Oid			targetElemType;		Oid			sourceElemType;		Oid			elemfuncid;		if ((targetElemType = get_element_type(targetTypeId)) != InvalidOid &&		 (sourceElemType = get_element_type(sourceTypeId)) != InvalidOid)		{			if (find_coercion_pathway(targetElemType, sourceElemType,									  ccontext, &elemfuncid))			{				*funcid = F_ARRAY_TYPE_COERCE;				result = true;			}		}	}	return result;}/* * find_typmod_coercion_function -- does the given type need length coercion? * * If the target type possesses a function named for the type * and having parameter signature (targettype, int4), we assume that * the type requires coercion to its own length and that the said * function should be invoked to do that. * * Alternatively, the length-coercing function may have the signature * (targettype, int4, bool).  On success, *nargs is set to report which * signature we found. * * "bpchar" (ie, char(N)) and "numeric" are examples of such types. * * If the given type is a varlena array type, we do not look for a coercion * function associated directly with the array type, but instead look for * one associated with the element type.  If one exists, we report * array_length_coerce() as the coercion function to use. * * This mechanism may seem pretty grotty and in need of replacement by * something in pg_cast, but since typmod is only interesting for datatypes * that have special handling in the grammar, there's not really much * percentage in making it any easier to apply such coercions ... */Oidfind_typmod_coercion_function(Oid typeId, int *nargs){	Oid			funcid = InvalidOid;	bool		isArray = false;	Type		targetType;	Form_pg_type typeForm;	char	   *typname;	Oid			typnamespace;	Oid			oid_array[FUNC_MAX_ARGS];	HeapTuple	ftup;	targetType = typeidType(typeId);	typeForm = (Form_pg_type) GETSTRUCT(targetType);	/* Check for a varlena array type (and not a domain) */	if (typeForm->typelem != InvalidOid &&		typeForm->typlen == -1 &&		typeForm->typtype != 'd')	{		/* Yes, switch our attention to the element type */		typeId = typeForm->typelem;		ReleaseSysCache(targetType);		targetType = typeidType(typeId);		typeForm = (Form_pg_type) GETSTRUCT(targetType);		isArray = true;	}	/* Function name is same as type internal name, and in same namespace */	typname = NameStr(typeForm->typname);	typnamespace = typeForm->typnamespace;	/* First look for parameters (type, int4) */	MemSet(oid_array, 0, FUNC_MAX_ARGS * sizeof(Oid));	oid_array[0] = typeId;	oid_array[1] = INT4OID;	*nargs = 2;	ftup = SearchSysCache(PROCNAMENSP,						  CStringGetDatum(typname),						  Int16GetDatum(2),						  PointerGetDatum(oid_array),						  ObjectIdGetDatum(typnamespace));	if (HeapTupleIsValid(ftup))	{		Form_pg_proc pform = (Form_pg_proc) GETSTRUCT(ftup);		/* Make sure the function's result type is as expected */		if (pform->prorettype == typeId && !pform->proretset &&			!pform->proisagg)		{			/* Okay to use it */			funcid = HeapTupleGetOid(ftup);		}		ReleaseSysCache(ftup);	}	if (!OidIsValid(funcid))	{		/* Didn't find a function, so now try (type, int4, bool) */		oid_array[2] = BOOLOID;		*nargs = 3;		ftup = SearchSysCache(PROCNAMENSP,							  CStringGetDatum(typname),							  Int16GetDatum(3),							  PointerGetDatum(oid_array),							  ObjectIdGetDatum(typnamespace));		if (HeapTupleIsValid(ftup))		{			Form_pg_proc pform = (Form_pg_proc) GETSTRUCT(ftup);			/* Make sure the function's result type is as expected */			if (pform->prorettype == typeId && !pform->proretset &&				!pform->proisagg)			{				/* Okay to use it */				funcid = HeapTupleGetOid(ftup);			}			ReleaseSysCache(ftup);		}	}	ReleaseSysCache(targetType);	/*	 * Now, if we did find a coercion function for an array element type,	 * report array_length_coerce() as the function to use.  We know it	 * takes three arguments always.	 */	if (isArray && OidIsValid(funcid))	{		funcid = F_ARRAY_LENGTH_COERCE;		*nargs = 3;	}	return funcid;}

⌨️ 快捷键说明

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