//--------------------------------------------------------------------- // // Copyright (c) Microsoft Corporation. All rights reserved. // // // @owner [....] // @backupOwner [....] //--------------------------------------------------------------------- namespace System.Data.Common.EntitySql { using System; using System.Collections.Generic; using System.Data.Metadata.Edm; using System.Globalization; /// /// Error reporting Helper /// internal static class CqlErrorHelper { /// /// Reports function overload resolution error. /// internal static void ReportFunctionOverloadError(AST.MethodExpr functionExpr, EdmFunction functionType, List argTypes) { string strDelim = ""; System.Text.StringBuilder sb = new System.Text.StringBuilder(); sb.Append(functionType.Name).Append("("); for (int i = 0 ; i < argTypes.Count ; i++) { sb.Append(strDelim); sb.Append(argTypes[i] != null ? argTypes[i].EdmType.FullName : "NULL"); strDelim = ", "; } sb.Append(")"); Func formatString; if (TypeSemantics.IsAggregateFunction(functionType)) { formatString = TypeHelpers.IsCanonicalFunction(functionType) ? (Func)System.Data.Entity.Strings.NoCanonicalAggrFunctionOverloadMatch : (Func)System.Data.Entity.Strings.NoAggrFunctionOverloadMatch; } else { formatString = TypeHelpers.IsCanonicalFunction(functionType) ? (Func)System.Data.Entity.Strings.NoCanonicalFunctionOverloadMatch : (Func)System.Data.Entity.Strings.NoFunctionOverloadMatch; } throw EntityUtil.EntitySqlError(functionExpr.ErrCtx.CommandText, formatString(functionType.NamespaceName, functionType.Name, sb.ToString()), functionExpr.ErrCtx.InputPosition, System.Data.Entity.Strings.CtxFunction(functionType.Name), false /* loadContextInfoFromResource */); } /// /// provides error feedback for aliases already used in a given context /// /// /// /// internal static void ReportAliasAlreadyUsedError( string aliasName, ErrorContext errCtx, string contextMessage ) { throw EntityUtil.EntitySqlError(errCtx, String.Format(CultureInfo.InvariantCulture, "{0} {1}", System.Data.Entity.Strings.AliasNameAlreadyUsed(aliasName), contextMessage)); } /// /// Reports incompatible type error /// /// /// /// internal static void ReportIncompatibleCommonType( ErrorContext errCtx, TypeUsage leftType, TypeUsage rightType ) { // // 'navigate' through the type structure in order to find where the incompability is // ReportIncompatibleCommonType(errCtx, leftType, rightType, leftType, rightType); // // if we hit this point, throw the generic incompatible type error message // throw EntityUtil.EntitySqlError(errCtx, System.Data.Entity.Strings.ArgumentTypesAreIncompatible(leftType.Identity, rightType.Identity)); } /// /// navigates through the type structure to find where the incompatibility happens /// /// /// /// /// /// private static void ReportIncompatibleCommonType( ErrorContext errCtx, TypeUsage rootLeftType, TypeUsage rootRightType, TypeUsage leftType, TypeUsage rightType ) { TypeUsage commonType = null; bool isRootType = (rootLeftType == leftType); string errorMessage = String.Empty; if (leftType.EdmType.BuiltInTypeKind != rightType.EdmType.BuiltInTypeKind) { throw EntityUtil.EntitySqlError(errCtx, System.Data.Entity.Strings.TypeKindMismatch( GetReadableTypeKind(leftType), GetReadableTypeName(leftType), GetReadableTypeKind(rightType), GetReadableTypeName(rightType))); } switch( leftType.EdmType.BuiltInTypeKind ) { case BuiltInTypeKind.RowType: RowType leftRow = (RowType)leftType.EdmType; RowType rightRow = (RowType)rightType.EdmType; if (leftRow.Members.Count != rightRow.Members.Count) { if (isRootType) { errorMessage = System.Data.Entity.Strings.InvalidRootRowType( GetReadableTypeName(leftRow), GetReadableTypeName(rightRow)); } else { errorMessage = System.Data.Entity.Strings.InvalidRowType( GetReadableTypeName(leftRow), GetReadableTypeName(rootLeftType), GetReadableTypeName(rightRow), GetReadableTypeName(rootRightType)); } throw EntityUtil.EntitySqlError(errCtx, errorMessage); } for (int i = 0 ; i < leftRow.Members.Count ; i++) { ReportIncompatibleCommonType(errCtx, rootLeftType, rootRightType, leftRow.Members[i].TypeUsage, rightRow.Members[i].TypeUsage); } break; case BuiltInTypeKind.CollectionType: case BuiltInTypeKind.RefType: ReportIncompatibleCommonType(errCtx, rootLeftType, rootRightType, TypeHelpers.GetElementTypeUsage(leftType), TypeHelpers.GetElementTypeUsage(rightType)); break; case BuiltInTypeKind.EntityType: if (!TypeSemantics.TryGetCommonType(leftType, rightType, out commonType)) { if (isRootType) { errorMessage = System.Data.Entity.Strings.InvalidEntityRootTypeArgument( GetReadableTypeName(leftType), GetReadableTypeName(rightType)); } else { errorMessage = System.Data.Entity.Strings.InvalidEntityTypeArgument( GetReadableTypeName(leftType), GetReadableTypeName(rootLeftType), GetReadableTypeName(rightType), GetReadableTypeName(rootRightType)); } throw EntityUtil.EntitySqlError(errCtx, errorMessage); } break; case BuiltInTypeKind.ComplexType: ComplexType leftComplex = (ComplexType)leftType.EdmType; ComplexType rightComplex = (ComplexType)rightType.EdmType; if (leftComplex.Members.Count != rightComplex.Members.Count) { if (isRootType) { errorMessage = System.Data.Entity.Strings.InvalidRootComplexType( GetReadableTypeName(leftComplex), GetReadableTypeName(rightComplex)); } else { errorMessage = System.Data.Entity.Strings.InvalidComplexType( GetReadableTypeName(leftComplex), GetReadableTypeName(rootLeftType), GetReadableTypeName(rightComplex), GetReadableTypeName(rootRightType)); } throw EntityUtil.EntitySqlError(errCtx, errorMessage); } for (int i = 0 ; i < leftComplex.Members.Count ; i++) { ReportIncompatibleCommonType(errCtx, rootLeftType, rootRightType, leftComplex.Members[i].TypeUsage, rightComplex.Members[i].TypeUsage); } break; default: if (!TypeSemantics.TryGetCommonType(leftType, rightType, out commonType)) { if (isRootType) { errorMessage = System.Data.Entity.Strings.InvalidPlaceholderRootTypeArgument( GetReadableTypeKind(leftType), GetReadableTypeName(leftType), GetReadableTypeKind(rightType), GetReadableTypeName(rightType)); } else { errorMessage = System.Data.Entity.Strings.InvalidPlaceholderTypeArgument( GetReadableTypeKind(leftType), GetReadableTypeName(leftType), GetReadableTypeName(rootLeftType), GetReadableTypeKind(rightType), GetReadableTypeName(rightType), GetReadableTypeName(rootRightType)); } throw EntityUtil.EntitySqlError(errCtx, errorMessage); } break; } } #region Private Type Name Helpers private static string GetReadableTypeName( TypeUsage type ) { return GetReadableTypeName(type.EdmType); } private static string GetReadableTypeName( EdmType type ) { if (type.BuiltInTypeKind == BuiltInTypeKind.RowType || type.BuiltInTypeKind == BuiltInTypeKind.CollectionType || type.BuiltInTypeKind == BuiltInTypeKind.RefType) { return type.Name; } return type.FullName; } private static string GetReadableTypeKind( TypeUsage type ) { return GetReadableTypeKind(type.EdmType); } private static string GetReadableTypeKind( EdmType type ) { string typeKindName = String.Empty; switch( type.BuiltInTypeKind) { case BuiltInTypeKind.RowType: typeKindName = System.Data.Entity.Strings.LocalizedRow; break; case BuiltInTypeKind.CollectionType: typeKindName = System.Data.Entity.Strings.LocalizedCollection; break; case BuiltInTypeKind.RefType: typeKindName = System.Data.Entity.Strings.LocalizedReference; break; case BuiltInTypeKind.EntityType: typeKindName = System.Data.Entity.Strings.LocalizedEntity; break; case BuiltInTypeKind.ComplexType: typeKindName = System.Data.Entity.Strings.LocalizedComplex; break; case BuiltInTypeKind.PrimitiveType: typeKindName = System.Data.Entity.Strings.LocalizedPrimitive; break; default: typeKindName = type.BuiltInTypeKind.ToString(); break; } return typeKindName + " " + System.Data.Entity.Strings.LocalizedType; } #endregion } }