1 //--------------------------------------------------------------------- 2 // <copyright file="CqlQuery.cs" company="Microsoft"> 3 // Copyright (c) Microsoft Corporation. All rights reserved. 4 // </copyright> 5 // 6 // @owner Microsoft 7 // @backupOwner Microsoft 8 //--------------------------------------------------------------------- 9 10 namespace System.Data.Common.EntitySql 11 { 12 using System; 13 using System.Collections.Generic; 14 using System.Data.Metadata.Edm; 15 using System.Globalization; 16 17 /// <summary> 18 /// Error reporting Helper 19 /// </summary> 20 internal static class CqlErrorHelper 21 { 22 /// <summary> 23 /// Reports function overload resolution error. 24 /// </summary> ReportFunctionOverloadError(AST.MethodExpr functionExpr, EdmFunction functionType, List<TypeUsage> argTypes)25 internal static void ReportFunctionOverloadError(AST.MethodExpr functionExpr, EdmFunction functionType, List<TypeUsage> argTypes) 26 { 27 string strDelim = ""; 28 System.Text.StringBuilder sb = new System.Text.StringBuilder(); 29 sb.Append(functionType.Name).Append("("); 30 for (int i = 0 ; i < argTypes.Count ; i++) 31 { 32 sb.Append(strDelim); 33 sb.Append(argTypes[i] != null ? argTypes[i].EdmType.FullName : "NULL"); 34 strDelim = ", "; 35 } 36 sb.Append(")"); 37 38 Func<object, object, object, string> formatString; 39 if (TypeSemantics.IsAggregateFunction(functionType)) 40 { 41 formatString = TypeHelpers.IsCanonicalFunction(functionType) ? 42 (Func<object, object, object, string>)System.Data.Entity.Strings.NoCanonicalAggrFunctionOverloadMatch : 43 (Func<object, object, object, string>)System.Data.Entity.Strings.NoAggrFunctionOverloadMatch; 44 } 45 else 46 { 47 formatString = TypeHelpers.IsCanonicalFunction(functionType) ? 48 (Func<object, object, object, string>)System.Data.Entity.Strings.NoCanonicalFunctionOverloadMatch : 49 (Func<object, object, object, string>)System.Data.Entity.Strings.NoFunctionOverloadMatch; 50 } 51 52 throw EntityUtil.EntitySqlError(functionExpr.ErrCtx.CommandText, 53 formatString(functionType.NamespaceName, functionType.Name, sb.ToString()), 54 functionExpr.ErrCtx.InputPosition, 55 System.Data.Entity.Strings.CtxFunction(functionType.Name), 56 false /* loadContextInfoFromResource */); 57 } 58 59 /// <summary> 60 /// provides error feedback for aliases already used in a given context 61 /// </summary> 62 /// <param name="aliasName"></param> 63 /// <param name="errCtx"></param> 64 /// <param name="contextMessage"></param> ReportAliasAlreadyUsedError( string aliasName, ErrorContext errCtx, string contextMessage )65 internal static void ReportAliasAlreadyUsedError( string aliasName, ErrorContext errCtx, string contextMessage ) 66 { 67 throw EntityUtil.EntitySqlError(errCtx, String.Format(CultureInfo.InvariantCulture, "{0} {1}", System.Data.Entity.Strings.AliasNameAlreadyUsed(aliasName), contextMessage)); 68 } 69 70 /// <summary> 71 /// Reports incompatible type error 72 /// </summary> 73 /// <param name="errCtx"></param> 74 /// <param name="leftType"></param> 75 /// <param name="rightType"></param> ReportIncompatibleCommonType( ErrorContext errCtx, TypeUsage leftType, TypeUsage rightType )76 internal static void ReportIncompatibleCommonType( ErrorContext errCtx, TypeUsage leftType, TypeUsage rightType ) 77 { 78 // 79 // 'navigate' through the type structure in order to find where the incompability is 80 // 81 ReportIncompatibleCommonType(errCtx, leftType, rightType, leftType, rightType); 82 83 // 84 // if we hit this point, throw the generic incompatible type error message 85 // 86 throw EntityUtil.EntitySqlError(errCtx, System.Data.Entity.Strings.ArgumentTypesAreIncompatible(leftType.Identity, rightType.Identity)); 87 } 88 89 /// <summary> 90 /// navigates through the type structure to find where the incompatibility happens 91 /// </summary> 92 /// <param name="errCtx"></param> 93 /// <param name="rootLeftType"></param> 94 /// <param name="rootRightType"></param> 95 /// <param name="leftType"></param> 96 /// <param name="rightType"></param> ReportIncompatibleCommonType( ErrorContext errCtx, TypeUsage rootLeftType, TypeUsage rootRightType, TypeUsage leftType, TypeUsage rightType )97 private static void ReportIncompatibleCommonType( ErrorContext errCtx, TypeUsage rootLeftType, TypeUsage rootRightType, TypeUsage leftType, TypeUsage rightType ) 98 { 99 TypeUsage commonType = null; 100 bool isRootType = (rootLeftType == leftType); 101 string errorMessage = String.Empty; 102 103 if (leftType.EdmType.BuiltInTypeKind != rightType.EdmType.BuiltInTypeKind) 104 { 105 throw EntityUtil.EntitySqlError(errCtx, 106 System.Data.Entity.Strings.TypeKindMismatch( 107 GetReadableTypeKind(leftType), 108 GetReadableTypeName(leftType), 109 GetReadableTypeKind(rightType), 110 GetReadableTypeName(rightType))); 111 } 112 113 switch( leftType.EdmType.BuiltInTypeKind ) 114 { 115 case BuiltInTypeKind.RowType: 116 RowType leftRow = (RowType)leftType.EdmType; 117 RowType rightRow = (RowType)rightType.EdmType; 118 119 if (leftRow.Members.Count != rightRow.Members.Count) 120 { 121 if (isRootType) 122 { 123 errorMessage = System.Data.Entity.Strings.InvalidRootRowType( 124 GetReadableTypeName(leftRow), 125 GetReadableTypeName(rightRow)); 126 } 127 else 128 { 129 errorMessage = System.Data.Entity.Strings.InvalidRowType( 130 GetReadableTypeName(leftRow), 131 GetReadableTypeName(rootLeftType), 132 GetReadableTypeName(rightRow), 133 GetReadableTypeName(rootRightType)); 134 } 135 136 throw EntityUtil.EntitySqlError(errCtx, errorMessage); 137 } 138 139 for (int i = 0 ; i < leftRow.Members.Count ; i++) 140 { 141 ReportIncompatibleCommonType(errCtx, rootLeftType, rootRightType, leftRow.Members[i].TypeUsage, rightRow.Members[i].TypeUsage); 142 } 143 break; 144 145 case BuiltInTypeKind.CollectionType: 146 case BuiltInTypeKind.RefType: 147 ReportIncompatibleCommonType(errCtx, 148 rootLeftType, 149 rootRightType, 150 TypeHelpers.GetElementTypeUsage(leftType), 151 TypeHelpers.GetElementTypeUsage(rightType)); 152 break; 153 154 case BuiltInTypeKind.EntityType: 155 if (!TypeSemantics.TryGetCommonType(leftType, rightType, out commonType)) 156 { 157 if (isRootType) 158 { 159 errorMessage = System.Data.Entity.Strings.InvalidEntityRootTypeArgument( 160 GetReadableTypeName(leftType), 161 GetReadableTypeName(rightType)); 162 } 163 else 164 { 165 errorMessage = System.Data.Entity.Strings.InvalidEntityTypeArgument( 166 GetReadableTypeName(leftType), 167 GetReadableTypeName(rootLeftType), 168 GetReadableTypeName(rightType), 169 GetReadableTypeName(rootRightType)); 170 } 171 throw EntityUtil.EntitySqlError(errCtx, errorMessage); 172 } 173 break; 174 175 case BuiltInTypeKind.ComplexType: 176 ComplexType leftComplex = (ComplexType)leftType.EdmType; 177 ComplexType rightComplex = (ComplexType)rightType.EdmType; 178 if (leftComplex.Members.Count != rightComplex.Members.Count) 179 { 180 if (isRootType) 181 { 182 errorMessage = System.Data.Entity.Strings.InvalidRootComplexType( 183 GetReadableTypeName(leftComplex), 184 GetReadableTypeName(rightComplex)); 185 } 186 else 187 { 188 errorMessage = System.Data.Entity.Strings.InvalidComplexType( 189 GetReadableTypeName(leftComplex), 190 GetReadableTypeName(rootLeftType), 191 GetReadableTypeName(rightComplex), 192 GetReadableTypeName(rootRightType)); 193 } 194 throw EntityUtil.EntitySqlError(errCtx, errorMessage); 195 } 196 197 for (int i = 0 ; i < leftComplex.Members.Count ; i++) 198 { 199 ReportIncompatibleCommonType(errCtx, 200 rootLeftType, 201 rootRightType, 202 leftComplex.Members[i].TypeUsage, 203 rightComplex.Members[i].TypeUsage); 204 } 205 break; 206 207 default: 208 if (!TypeSemantics.TryGetCommonType(leftType, rightType, out commonType)) 209 { 210 if (isRootType) 211 { 212 errorMessage = System.Data.Entity.Strings.InvalidPlaceholderRootTypeArgument( 213 GetReadableTypeKind(leftType), 214 GetReadableTypeName(leftType), 215 GetReadableTypeKind(rightType), 216 GetReadableTypeName(rightType)); 217 } 218 else 219 { 220 errorMessage = System.Data.Entity.Strings.InvalidPlaceholderTypeArgument( 221 GetReadableTypeKind(leftType), 222 GetReadableTypeName(leftType), 223 GetReadableTypeName(rootLeftType), 224 GetReadableTypeKind(rightType), 225 GetReadableTypeName(rightType), 226 GetReadableTypeName(rootRightType)); 227 } 228 throw EntityUtil.EntitySqlError(errCtx, errorMessage); 229 } 230 break; 231 } 232 } 233 234 #region Private Type Name Helpers GetReadableTypeName( TypeUsage type )235 private static string GetReadableTypeName( TypeUsage type ) 236 { 237 return GetReadableTypeName(type.EdmType); 238 } 239 GetReadableTypeName( EdmType type )240 private static string GetReadableTypeName( EdmType type ) 241 { 242 if (type.BuiltInTypeKind == BuiltInTypeKind.RowType || 243 type.BuiltInTypeKind == BuiltInTypeKind.CollectionType || 244 type.BuiltInTypeKind == BuiltInTypeKind.RefType) 245 { 246 return type.Name; 247 } 248 return type.FullName; 249 } 250 GetReadableTypeKind( TypeUsage type )251 private static string GetReadableTypeKind( TypeUsage type ) 252 { 253 return GetReadableTypeKind(type.EdmType); 254 } 255 GetReadableTypeKind( EdmType type )256 private static string GetReadableTypeKind( EdmType type ) 257 { 258 string typeKindName = String.Empty; 259 switch( type.BuiltInTypeKind) 260 { 261 case BuiltInTypeKind.RowType: 262 typeKindName = System.Data.Entity.Strings.LocalizedRow; 263 break; 264 case BuiltInTypeKind.CollectionType: 265 typeKindName = System.Data.Entity.Strings.LocalizedCollection; 266 break; 267 case BuiltInTypeKind.RefType: 268 typeKindName = System.Data.Entity.Strings.LocalizedReference; 269 break; 270 case BuiltInTypeKind.EntityType: 271 typeKindName = System.Data.Entity.Strings.LocalizedEntity; 272 break; 273 case BuiltInTypeKind.ComplexType: 274 typeKindName = System.Data.Entity.Strings.LocalizedComplex; 275 break; 276 case BuiltInTypeKind.PrimitiveType: 277 typeKindName = System.Data.Entity.Strings.LocalizedPrimitive; 278 break; 279 default: 280 typeKindName = type.BuiltInTypeKind.ToString(); 281 break; 282 } 283 return typeKindName + " " + System.Data.Entity.Strings.LocalizedType; 284 } 285 #endregion 286 } 287 288 } 289