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