51130912b7563d13a1a6987bbfd1b8e318b400cd
[mono.git] / mcs / class / referencesource / System.Data.Entity / System / Data / Common / EntitySql / SemanticAnalyzer.cs
1 //---------------------------------------------------------------------
2 // <copyright file="SemanticAnalyzer.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.Common.CommandTrees;
15     using System.Data.Common.CommandTrees.ExpressionBuilder;
16     using System.Data.Entity;
17     using System.Data.Mapping;
18     using System.Data.Metadata.Edm;
19     using System.Diagnostics;
20     using System.Globalization;
21     using System.Linq;
22
23     /// <summary>
24     /// Implements Semantic Analysis and Conversion
25     /// Provides the translation service between an abstract syntax tree to a canonical command tree
26     /// For complete documentation of the language syntax and semantics, refer to http://sqlweb/default.asp?specDirId=764
27     /// The class was designed to be type system agnostic by delegating to a given SemanticResolver instance all type related services as well as to TypeHelper class, however
28     /// we rely on the assumption that metadata was pre-loaded and is relevant to the query.
29     /// </summary>
30     internal sealed class SemanticAnalyzer
31     {
32         private SemanticResolver _sr;
33
34         /// <summary>
35         /// Initializes semantic analyzer
36         /// </summary>
37         /// <param name="sr">initialized SemanticResolver instance for a given typespace/type system</param>
38         internal SemanticAnalyzer(SemanticResolver sr)
39         {
40             Debug.Assert(sr != null, "sr must not be null");
41             _sr = sr;
42         }
43
44         /// <summary>
45         /// Entry point to semantic analysis. Converts AST into a <see cref="DbCommandTree"/>.
46         /// </summary>
47         /// <param name="astExpr">ast command tree</param>
48         /// <remarks>
49         /// <exception cref="System.Data.EntityException">Thrown when Syntatic or Semantic rules are violated and the query cannot be accepted</exception>
50         /// <exception cref="System.Data.MetadataException">Thrown when metadata related service requests fail</exception>
51         /// <exception cref="System.Data.MappingException">Thrown when mapping related service requests fail</exception>
52         /// </remarks>
53         /// <returns>ParseResult with a valid DbCommandTree</returns>
54         internal ParseResult AnalyzeCommand(AST.Node astExpr)
55         {
56             //
57             // Ensure that the AST expression is a valid Command expression
58             //
59             AST.Command astCommandExpr = ValidateQueryCommandAst(astExpr);
60
61             //
62             // Convert namespace imports and add them to _sr.TypeResolver.
63             //
64             ConvertAndRegisterNamespaceImports(astCommandExpr.NamespaceImportList, astCommandExpr.ErrCtx, _sr);
65
66             //
67             // Convert the AST command root expression to a command tree using the appropriate converter
68             //
69             ParseResult parseResult = ConvertStatement(astCommandExpr.Statement, _sr);
70
71             Debug.Assert(parseResult != null, "ConvertStatement produced null parse result");
72             Debug.Assert(parseResult.CommandTree != null, "ConvertStatement returned null command tree");
73
74             return parseResult;
75         }
76
77         /// <summary>
78         /// Converts query command AST into a <see cref="DbExpression"/>.
79         /// </summary>
80         /// <param name="astExpr">ast command tree</param>
81         /// <remarks>
82         /// <exception cref="System.Data.EntityException">Thrown when Syntatic or Semantic rules are violated and the query cannot be accepted</exception>
83         /// <exception cref="System.Data.MetadataException">Thrown when metadata related service requests fail</exception>
84         /// <exception cref="System.Data.MappingException">Thrown when mapping related service requests fail</exception>
85         /// </remarks>
86         /// <returns>DbExpression</returns>
87         internal DbLambda AnalyzeQueryCommand(AST.Node astExpr)
88         {
89             //
90             // Ensure that the AST expression is a valid query command expression
91             // (only a query command root expression can produce a standalone DbExpression)
92             //
93             AST.Command astQueryCommandExpr = ValidateQueryCommandAst(astExpr);
94
95             //
96             // Convert namespace imports and add them to _sr.TypeResolver.
97             //
98             ConvertAndRegisterNamespaceImports(astQueryCommandExpr.NamespaceImportList, astQueryCommandExpr.ErrCtx, _sr);
99
100             //
101             // Convert the AST of the query command root expression into a DbExpression
102             //
103             List<FunctionDefinition> functionDefs;
104             DbExpression expression = ConvertQueryStatementToDbExpression(astQueryCommandExpr.Statement, _sr, out functionDefs);
105
106             // Construct DbLambda from free variables and the expression
107             DbLambda lambda = DbExpressionBuilder.Lambda(expression, _sr.Variables.Values);
108
109             Debug.Assert(lambda != null, "AnalyzeQueryCommand returned null");
110
111             return lambda;
112         }
113
114         private AST.Command ValidateQueryCommandAst(AST.Node astExpr)
115         {
116             AST.Command astCommandExpr = astExpr as AST.Command;
117             if (null == astCommandExpr)
118             {
119                 throw EntityUtil.Argument(Strings.UnknownAstCommandExpression);
120             }
121
122             if (!(astCommandExpr.Statement is AST.QueryStatement))
123                 throw EntityUtil.Argument(Strings.UnknownAstExpressionType);
124
125             return astCommandExpr;
126         }
127
128         /// <summary>
129         /// Converts namespace imports and adds them to the type resolver.
130         /// </summary>
131         private static void ConvertAndRegisterNamespaceImports(AST.NodeList<AST.NamespaceImport> nsImportList, ErrorContext cmdErrCtx, SemanticResolver sr)
132         {
133             List<Tuple<string, MetadataNamespace, ErrorContext>> aliasedNamespaceImports = new List<Tuple<string, MetadataNamespace, ErrorContext>>();
134             List<Tuple<MetadataNamespace, ErrorContext>> namespaceImports = new List<Tuple<MetadataNamespace, ErrorContext>>();
135
136             //
137             // Resolve all user-defined namespace imports to MetadataMember objects _before_ adding them to the type resolver,
138             // this is needed to keep resolution within the command prolog unaffected by previously resolved imports.
139             //
140             if (nsImportList != null)
141             {
142                 foreach (AST.NamespaceImport namespaceImport in nsImportList)
143                 {
144                     string[] name = null;
145
146                     AST.Identifier identifier = namespaceImport.NamespaceName as AST.Identifier;
147                     if (identifier != null)
148                     {
149                         name = new string[] { identifier.Name };
150                     }
151
152                     AST.DotExpr dotExpr = namespaceImport.NamespaceName as AST.DotExpr;
153                     if (dotExpr != null && dotExpr.IsMultipartIdentifier(out name))
154                     {
155                         Debug.Assert(name != null, "name != null");
156                     }
157
158                     if (name == null)
159                     {
160                         throw EntityUtil.EntitySqlError(namespaceImport.NamespaceName.ErrCtx, Strings.InvalidMetadataMemberName);
161                     }
162
163                     string alias = namespaceImport.Alias != null ? namespaceImport.Alias.Name : null;
164
165                     MetadataMember metadataMember = sr.ResolveMetadataMemberName(name, namespaceImport.NamespaceName.ErrCtx);
166                     Debug.Assert(metadataMember != null, "metadata member name resolution must not return null");
167
168                     if (metadataMember.MetadataMemberClass == MetadataMemberClass.Namespace)
169                     {
170                         if (alias != null)
171                         {
172                             aliasedNamespaceImports.Add(Tuple.Create(alias, (MetadataNamespace)metadataMember, namespaceImport.ErrCtx));
173                         }
174                         else
175                         {
176                             namespaceImports.Add(Tuple.Create((MetadataNamespace)metadataMember, namespaceImport.ErrCtx));
177                         }
178                     }
179                     else
180                     {
181                         throw EntityUtil.EntitySqlError(namespaceImport.NamespaceName.ErrCtx, Strings.InvalidMetadataMemberClassResolution(
182                             metadataMember.Name, metadataMember.MetadataMemberClassName, MetadataNamespace.NamespaceClassName));
183                     }
184                 }
185             }
186
187             //
188             // Add resolved user-defined imports to the type resolver.
189             // Before adding user-defined namespace imports, add EDM namespace import to make canonical functions and types available in the command text.
190             //
191             sr.TypeResolver.AddNamespaceImport(new MetadataNamespace(EdmConstants.EdmNamespace), nsImportList != null ? nsImportList.ErrCtx : cmdErrCtx);
192             foreach (var resolvedAliasedNamespaceImport in aliasedNamespaceImports)
193             {
194                 sr.TypeResolver.AddAliasedNamespaceImport(resolvedAliasedNamespaceImport.Item1, resolvedAliasedNamespaceImport.Item2, resolvedAliasedNamespaceImport.Item3);
195             }
196             foreach (var resolvedNamespaceImport in namespaceImports)
197             {
198                 sr.TypeResolver.AddNamespaceImport(resolvedNamespaceImport.Item1, resolvedNamespaceImport.Item2);
199             }
200         }
201
202         /// <summary>
203         /// Dispatches/Converts statement expressions.
204         /// </summary>
205         /// <param name="astStatement"></param>
206         /// <param name="sr">SemanticResolver instance relative to a especif typespace/system</param>
207         /// <returns></returns>
208         private static ParseResult ConvertStatement(AST.Statement astStatement, SemanticResolver sr)
209         {
210             Debug.Assert(astStatement != null, "astStatement must not be null");
211
212             StatementConverter statementConverter;
213             if (astStatement is AST.QueryStatement)
214             {
215                 statementConverter = new StatementConverter(ConvertQueryStatementToDbCommandTree);
216             }
217             else
218             {
219                 throw EntityUtil.Argument(Strings.UnknownAstExpressionType);
220             }
221
222             ParseResult converted = statementConverter(astStatement, sr);
223
224             Debug.Assert(converted != null, "statementConverter returned null");
225             Debug.Assert(converted.CommandTree != null, "statementConverter produced null command tree");
226
227             return converted;
228         }
229         private delegate ParseResult StatementConverter(AST.Statement astExpr, SemanticResolver sr);
230
231         /// <summary>
232         /// Converts query statement AST to a <see cref="DbQueryCommandTree"/>
233         /// </summary>
234         /// <param name="sr">SemanticResolver instance relative to a especif typespace/system</param>
235         private static ParseResult ConvertQueryStatementToDbCommandTree(AST.Statement astStatement, SemanticResolver sr)
236         {
237             Debug.Assert(astStatement != null, "astStatement must not be null");
238
239             List<FunctionDefinition> functionDefs;
240             DbExpression converted = ConvertQueryStatementToDbExpression(astStatement, sr, out functionDefs);
241
242             Debug.Assert(converted != null, "ConvertQueryStatementToDbExpression returned null");
243             Debug.Assert(functionDefs != null, "ConvertQueryStatementToDbExpression produced null functionDefs");
244
245             return new ParseResult(
246                 DbQueryCommandTree.FromValidExpression(sr.TypeResolver.Perspective.MetadataWorkspace, sr.TypeResolver.Perspective.TargetDataspace, converted),
247                 functionDefs);
248         }
249
250         /// <summary>
251         /// Converts the query statement to a normalized and validated <see cref="DbExpression"/>. 
252         /// This entry point to the semantic analysis phase is used when producing a
253         /// query command tree or producing only a <see cref="DbExpression"/>.
254         /// </summary>
255         /// <param name="astStatement">The query statement</param>
256         /// <param name="sr">The <see cref="SemanticResolver"/>instance to use</param>
257         /// <returns>
258         ///     An instance of <see cref="DbExpression"/>, adjusted to handle 'inline' projections
259         ///     and validated to produce a result type appropriate for the root of a query command tree.
260         /// </returns>
261         private static DbExpression ConvertQueryStatementToDbExpression(AST.Statement astStatement, SemanticResolver sr, out List<FunctionDefinition> functionDefs)
262         {
263             Debug.Assert(astStatement != null, "astStatement must not be null");
264
265             AST.QueryStatement queryStatement = astStatement as AST.QueryStatement;
266
267             if (queryStatement == null)
268             {
269                 throw EntityUtil.Argument(Strings.UnknownAstExpressionType);
270             }
271
272             //
273             // Convert query inline definitions and create parse result. 
274             // Converted inline definitions are also added to the semantic resolver.
275             //
276             functionDefs = ConvertInlineFunctionDefinitions(queryStatement.FunctionDefList, sr);
277
278             //
279             // Convert top level expression
280             //
281             DbExpression converted = ConvertValueExpressionAllowUntypedNulls(queryStatement.Expr, sr);
282             if (converted == null)
283             {
284                 //
285                 // Ensure converted expression is not untyped null.
286                 // Use error context of the top-level expression.
287                 //
288                 throw EntityUtil.EntitySqlError(queryStatement.Expr.ErrCtx, Strings.ResultingExpressionTypeCannotBeNull);
289             }
290
291             //
292             // Handle the "inline" projection case
293             //
294             if (converted is DbScanExpression)
295             {
296                 DbExpressionBinding source = converted.BindAs(sr.GenerateInternalName("extent"));
297
298                 converted = source.Project(source.Variable);
299             }
300
301             //
302             // Ensure return type is valid for query. For V1, association types are the only 
303             // type that cannot be at 'top' level result. Note that this is only applicable in
304             // general queries and association types are valid in view gen mode queries.
305             // Use error context of the top-level expression.
306             //
307             if (sr.ParserOptions.ParserCompilationMode == ParserOptions.CompilationMode.NormalMode)
308             {
309                 ValidateQueryResultType(converted.ResultType, queryStatement.Expr.ErrCtx);
310             }
311
312             Debug.Assert(null != converted, "null != converted");
313
314             return converted;
315         }
316
317         /// <summary>
318         /// Ensures that the result of a query expression is valid.
319         /// </summary>
320         private static void ValidateQueryResultType(TypeUsage resultType, ErrorContext errCtx)
321         {
322             if (Helper.IsCollectionType(resultType.EdmType))
323             {
324                 ValidateQueryResultType(((CollectionType)resultType.EdmType).TypeUsage, errCtx);
325             }
326             else if (Helper.IsRowType(resultType.EdmType))
327             {
328                 foreach (EdmProperty property in ((RowType)resultType.EdmType).Properties)
329                 {
330                     ValidateQueryResultType(property.TypeUsage, errCtx);
331                 }
332             }
333             else if (Helper.IsAssociationType(resultType.EdmType))
334             {
335                 throw EntityUtil.EntitySqlError(errCtx, Strings.InvalidQueryResultType(resultType.EdmType.FullName));
336             }
337         }
338
339
340         /// <summary>
341         /// Converts query inline function defintions. Returns empty list in case of no definitions.
342         /// </summary>
343         private static List<FunctionDefinition> ConvertInlineFunctionDefinitions(AST.NodeList<AST.FunctionDefinition> functionDefList, SemanticResolver sr)
344         {
345             List<FunctionDefinition> functionDefinitions = new List<FunctionDefinition>();
346
347             if (functionDefList != null)
348             {
349                 //
350                 // Process inline function signatures, declare functions in the type resolver.
351                 //
352                 List<InlineFunctionInfo> inlineFunctionInfos = new List<InlineFunctionInfo>();
353                 foreach (AST.FunctionDefinition functionDefAst in functionDefList)
354                 {
355                     //
356                     // Get and validate function name.
357                     //
358                     string name = functionDefAst.Name;
359                     Debug.Assert(!String.IsNullOrEmpty(name), "function name must not be null or empty");
360
361                     //
362                     // Process function parameters
363                     //
364                     List<DbVariableReferenceExpression> parameters = ConvertInlineFunctionParameterDefs(functionDefAst.Parameters, sr);
365                     Debug.Assert(parameters != null, "parameters must not be null"); // should be empty collection if no parameters
366
367                     //
368                     // Register new function in the type resolver.
369                     //
370                     InlineFunctionInfo functionInfo = new InlineFunctionInfoImpl(functionDefAst, parameters);
371                     inlineFunctionInfos.Add(functionInfo);
372                     sr.TypeResolver.DeclareInlineFunction(name, functionInfo);
373                 }
374                 Debug.Assert(functionDefList.Count == inlineFunctionInfos.Count);
375
376                 //
377                 // Convert function defintions.
378                 //
379                 foreach (InlineFunctionInfo functionInfo in inlineFunctionInfos)
380                 {
381                     functionDefinitions.Add(new FunctionDefinition(
382                         functionInfo.FunctionDefAst.Name,
383                         functionInfo.GetLambda(sr),
384                         functionInfo.FunctionDefAst.StartPosition,
385                         functionInfo.FunctionDefAst.EndPosition));
386                 }
387             }
388
389             return functionDefinitions;
390         }
391
392         private static List<DbVariableReferenceExpression> ConvertInlineFunctionParameterDefs(AST.NodeList<AST.PropDefinition> parameterDefs, SemanticResolver sr)
393         {
394             List<DbVariableReferenceExpression> paramList = new List<DbVariableReferenceExpression>();
395             if (parameterDefs != null)
396             {
397                 foreach (AST.PropDefinition paramDef in parameterDefs)
398                 {
399                     string name = paramDef.Name.Name;
400
401                     //
402                     // Validate param name
403                     //
404                     if (paramList.Exists((DbVariableReferenceExpression arg) =>
405                                           sr.NameComparer.Compare(arg.VariableName, name) == 0))
406                     {
407                         throw EntityUtil.EntitySqlError(
408                             paramDef.ErrCtx,
409                             Strings.MultipleDefinitionsOfParameter(name));
410                     }
411
412                     //
413                     // Convert parameter type
414                     //
415                     TypeUsage typeUsage = ConvertTypeDefinition(paramDef.Type, sr);
416                     Debug.Assert(typeUsage != null, "typeUsage must not be null");
417
418                     //
419                     // Create function parameter ref expression
420                     //
421                     DbVariableReferenceExpression paramRefExpr = new DbVariableReferenceExpression(typeUsage, name);
422                     paramList.Add(paramRefExpr);
423                 }
424             }
425             return paramList;
426         }
427
428         private sealed class InlineFunctionInfoImpl : InlineFunctionInfo
429         {
430             private DbLambda _convertedDefinition = null;
431             private bool _convertingDefinition = false;
432
433             internal InlineFunctionInfoImpl(AST.FunctionDefinition functionDef, List<DbVariableReferenceExpression> parameters)
434                 : base(functionDef, parameters)
435             {
436             }
437
438             internal override DbLambda GetLambda(SemanticResolver sr)
439             {
440                 if (_convertedDefinition == null)
441                 {
442                     //
443                     // Check for recursive definitions.
444                     //
445                     if (_convertingDefinition)
446                     {
447                         throw EntityUtil.EntitySqlError(FunctionDefAst.ErrCtx, Strings.Cqt_UDF_FunctionDefinitionWithCircularReference(FunctionDefAst.Name));
448                     }
449
450                     //
451                     // Create a copy of semantic resolver without query scope entries to guarantee proper variable bindings inside the function body.
452                     // The srSandbox shares InlineFunctionInfo objects with the original semantic resolver (sr), hence all the indirect conversions of
453                     // inline functions (in addition to this direct one) will also be visible in the original semantic resolver.
454                     //
455                     SemanticResolver srSandbox = sr.CloneForInlineFunctionConversion();
456
457                     _convertingDefinition = true;
458                     _convertedDefinition = SemanticAnalyzer.ConvertInlineFunctionDefinition(this, srSandbox);
459                     _convertingDefinition = false;
460                 }
461                 return _convertedDefinition;
462             }
463         }
464
465         private static DbLambda ConvertInlineFunctionDefinition(InlineFunctionInfo functionInfo, SemanticResolver sr)
466         {
467             //
468             // Push function definition scope.
469             //
470             sr.EnterScope();
471
472             //
473             // Add function parameters to the scope.
474             //
475             functionInfo.Parameters.ForEach(p => sr.CurrentScope.Add(p.VariableName, new FreeVariableScopeEntry(p)));
476
477             //
478             // Convert function body expression
479             //
480             DbExpression body = ConvertValueExpression(functionInfo.FunctionDefAst.Body, sr);
481
482             //
483             // Pop function definition scope
484             //
485             sr.LeaveScope();
486
487             //
488             // Create and return lambda representing the function body.
489             //
490             return DbExpressionBuilder.Lambda(body, functionInfo.Parameters);
491         }
492
493         /// <summary>
494         /// Converts general expressions (AST.Node)
495         /// </summary>
496         private static ExpressionResolution Convert(AST.Node astExpr, SemanticResolver sr)
497         {
498             AstExprConverter converter = _astExprConverters[astExpr.GetType()];
499             if (converter == null)
500             {
501                 throw EntityUtil.EntitySqlError(Strings.UnknownAstExpressionType);
502             }
503             return converter(astExpr, sr);
504         }
505
506         /// <summary>
507         /// Converts general expressions (AST.Node) to a <see cref="ValueExpression"/>.
508         /// Returns <see cref="ValueExpression.Value"/>.
509         /// Throws if conversion resulted an a non <see cref="ValueExpression"/> resolution.
510         /// Throws if conversion resulted in the untyped null.
511         /// </summary>
512         private static DbExpression ConvertValueExpression(AST.Node astExpr, SemanticResolver sr)
513         {
514             var expr = ConvertValueExpressionAllowUntypedNulls(astExpr, sr);
515             if (expr == null)
516             {
517                 throw EntityUtil.EntitySqlError(astExpr.ErrCtx, Strings.ExpressionCannotBeNull);
518             }
519             return expr;
520         }
521
522         /// <summary>
523         /// Converts general expressions (AST.Node) to a <see cref="ValueExpression"/>.
524         /// Returns <see cref="ValueExpression.Value"/>.
525         /// Returns null if expression is the untyped null.
526         /// Throws if conversion resulted an a non <see cref="ValueExpression"/> resolution.
527         /// </summary>
528         private static DbExpression ConvertValueExpressionAllowUntypedNulls(AST.Node astExpr, SemanticResolver sr)
529         {
530             ExpressionResolution resolution = Convert(astExpr, sr);
531             if (resolution.ExpressionClass == ExpressionResolutionClass.Value)
532             {
533                 return ((ValueExpression)resolution).Value;
534             }
535             else if (resolution.ExpressionClass == ExpressionResolutionClass.MetadataMember)
536             {
537                 var metadataMember = (MetadataMember)resolution;
538                 if (metadataMember.MetadataMemberClass == MetadataMemberClass.EnumMember)
539                 {
540                     var enumMember = (MetadataEnumMember)metadataMember;
541                     return enumMember.EnumType.Constant(enumMember.EnumMember.Value);
542                 }
543             }
544
545             //
546             // The resolution is not a value and can not be converted to a value: report an error.
547             //
548
549             string errorMessage = Strings.InvalidExpressionResolutionClass(resolution.ExpressionClassName, ValueExpression.ValueClassName);
550
551             AST.Identifier identifier = astExpr as AST.Identifier;
552             if (identifier != null)
553             {
554                 errorMessage = Strings.CouldNotResolveIdentifier(identifier.Name);
555             }
556
557             AST.DotExpr dotExpr = astExpr as AST.DotExpr;
558             string[] names;
559             if (dotExpr != null && dotExpr.IsMultipartIdentifier(out names))
560             {
561                 errorMessage = Strings.CouldNotResolveIdentifier(TypeResolver.GetFullName(names));
562             }
563
564             throw EntityUtil.EntitySqlError(astExpr.ErrCtx, errorMessage);
565         }
566
567         /// <summary>
568         /// Converts left and right expressions. If any of them is the untyped null, derives the type and converts to a typed null.
569         /// Throws <see cref="EntitySqlException"/> if conversion is not possible.
570         /// </summary>
571         private static Pair<DbExpression, DbExpression> ConvertValueExpressionsWithUntypedNulls(AST.Node leftAst,
572                                                                                                 AST.Node rightAst,
573                                                                                                 ErrorContext errCtx,
574                                                                                                 Func<string> formatMessage,
575                                                                                                 SemanticResolver sr)
576         {
577             var leftExpr = leftAst != null ? ConvertValueExpressionAllowUntypedNulls(leftAst, sr) : null;
578             var rightExpr = rightAst != null ? ConvertValueExpressionAllowUntypedNulls(rightAst, sr) : null;
579
580             if (leftExpr == null)
581             {
582                 if (rightExpr == null)
583                 {
584                     throw EntityUtil.EntitySqlError(errCtx, formatMessage());
585                 }
586                 else
587                 {
588                     leftExpr = DbExpressionBuilder.Null(rightExpr.ResultType);
589                 }
590             }
591             else if (rightExpr == null)
592             {
593                 rightExpr = DbExpressionBuilder.Null(leftExpr.ResultType);
594             }
595
596             return new Pair<DbExpression, DbExpression>(leftExpr, rightExpr);
597         }
598
599         /// <summary>
600         /// Converts literal expression (AST.Literal)
601         /// </summary>
602         private static ExpressionResolution ConvertLiteral(AST.Node expr, SemanticResolver sr)
603         {
604             AST.Literal literal = (AST.Literal)expr;
605
606             if (literal.IsNullLiteral)
607             {
608                 //
609                 // If it is literal null, return the untyped null: the type will be inferred depending on the specific expression in which it participates.
610                 //
611                 return new ValueExpression(null);
612             }
613             else
614             {
615                 return new ValueExpression(DbExpressionBuilder.Constant(GetLiteralTypeUsage(literal), literal.Value));
616             }
617         }
618
619         private static TypeUsage GetLiteralTypeUsage(AST.Literal literal)
620         {
621             PrimitiveType primitiveType = null;
622
623             if (!ClrProviderManifest.Instance.TryGetPrimitiveType(literal.Type, out primitiveType))
624             {
625                 throw EntityUtil.EntitySqlError(literal.ErrCtx, Strings.LiteralTypeNotFoundInMetadata(literal.OriginalValue));
626             }
627             TypeUsage literalTypeUsage = TypeHelpers.GetLiteralTypeUsage(primitiveType.PrimitiveTypeKind, literal.IsUnicodeString);
628
629             return literalTypeUsage;
630         }
631
632         /// <summary>
633         /// Converts identifier expression (Identifier)
634         /// </summary>
635         private static ExpressionResolution ConvertIdentifier(AST.Node expr, SemanticResolver sr)
636         {
637             return ConvertIdentifier(((AST.Identifier)expr), false /* leftHandSideOfMemberAccess */, sr);
638         }
639
640         private static ExpressionResolution ConvertIdentifier(AST.Identifier identifier, bool leftHandSideOfMemberAccess, SemanticResolver sr)
641         {
642             return sr.ResolveSimpleName(((AST.Identifier)identifier).Name, leftHandSideOfMemberAccess, identifier.ErrCtx);
643         }
644
645         /// <summary>
646         /// Converts member access expression (AST.DotExpr)
647         /// </summary>
648         private static ExpressionResolution ConvertDotExpr(AST.Node expr, SemanticResolver sr)
649         {
650             AST.DotExpr dotExpr = (AST.DotExpr)expr;
651
652             ValueExpression groupKeyResolution;
653             if (sr.TryResolveDotExprAsGroupKeyAlternativeName(dotExpr, out groupKeyResolution))
654             {
655                 return groupKeyResolution;
656             }
657
658             //
659             // If dotExpr.Left is an identifier, then communicate to the resolution mechanism 
660             // that the identifier might be an unqualified name in the context of a qualified name.
661             // Otherwise convert the expr normally.
662             //
663             ExpressionResolution leftResolution;
664             AST.Identifier leftIdentifier = dotExpr.Left as AST.Identifier;
665             if (leftIdentifier != null)
666             {
667                 leftResolution = ConvertIdentifier(leftIdentifier, true /* leftHandSideOfMemberAccess */, sr);
668             }
669             else
670             {
671                 leftResolution = Convert(dotExpr.Left, sr);
672             }
673
674             switch (leftResolution.ExpressionClass)
675             {
676                 case ExpressionResolutionClass.Value:
677                     return sr.ResolvePropertyAccess(((ValueExpression)leftResolution).Value, dotExpr.Identifier.Name, dotExpr.Identifier.ErrCtx);
678
679                 case ExpressionResolutionClass.EntityContainer:
680                     return sr.ResolveEntityContainerMemberAccess(((EntityContainerExpression)leftResolution).EntityContainer, dotExpr.Identifier.Name, dotExpr.Identifier.ErrCtx);
681
682                 case ExpressionResolutionClass.MetadataMember:
683                     return sr.ResolveMetadataMemberAccess((MetadataMember)leftResolution, dotExpr.Identifier.Name, dotExpr.Identifier.ErrCtx);
684
685                 default:
686                     throw EntityUtil.EntitySqlError(dotExpr.Left.ErrCtx, Strings.UnknownExpressionResolutionClass(leftResolution.ExpressionClass));
687             }
688         }
689
690         /// <summary>
691         /// Converts paren expression (AST.ParenExpr)
692         /// </summary>
693         private static ExpressionResolution ConvertParenExpr(AST.Node astExpr, SemanticResolver sr)
694         {
695             AST.Node innerExpr = ((AST.ParenExpr)astExpr).Expr;
696
697             //
698             // Convert the inner expression.
699             // Note that we allow it to be an untyped null: the consumer of this expression will handle it. 
700             // The reason to allow untyped nulls is that "(null)" is a common construct for tool-generated eSQL.
701             //
702             DbExpression converted = ConvertValueExpressionAllowUntypedNulls(innerExpr, sr);
703             return new ValueExpression(converted);
704         }
705
706         /// <summary>
707         /// Converts GROUPPARTITION expression (AST.GroupPartitionExpr).
708         /// </summary>
709         private static ExpressionResolution ConvertGroupPartitionExpr(AST.Node astExpr, SemanticResolver sr)
710         {
711             AST.GroupPartitionExpr groupAggregateExpr = (AST.GroupPartitionExpr)astExpr;
712
713             DbExpression converted = null;
714
715             //
716             // If ast node was annotated in a previous pass, means it contains a ready-to-use expression.
717             //
718             if (!TryConvertAsResolvedGroupAggregate(groupAggregateExpr, sr, out converted))
719             {
720                 //
721                 // GROUPPARTITION is allowed only in the context of a group operation provided by a query expression (SELECT ...).
722                 //
723                 if (!sr.IsInAnyGroupScope())
724                 {
725                     throw EntityUtil.EntitySqlError(astExpr.ErrCtx, Strings.GroupPartitionOutOfContext);
726                 }
727
728                 //
729                 // Process aggregate argument.
730                 //
731                 DbExpression arg;
732                 GroupPartitionInfo aggregateInfo;
733                 using (sr.EnterGroupPartition(groupAggregateExpr, groupAggregateExpr.ErrCtx, out aggregateInfo))
734                 {
735                     //
736                     // Convert aggregate argument.
737                     //
738                     arg = ConvertValueExpressionAllowUntypedNulls(groupAggregateExpr.ArgExpr, sr);
739                 }
740
741                 //
742                 // Ensure converted GROUPPARTITION argument expression is not untyped null.
743                 //
744                 if (arg == null)
745                 {
746                     throw EntityUtil.EntitySqlError(groupAggregateExpr.ArgExpr.ErrCtx, Strings.ResultingExpressionTypeCannotBeNull);
747                 }
748
749                 //
750                 // Project the argument off the DbGroupAggregate binding.
751                 //
752                 DbExpression definition = aggregateInfo.EvaluatingScopeRegion.GroupAggregateBinding.Project(arg);
753
754                 if (groupAggregateExpr.DistinctKind == AST.DistinctKind.Distinct)
755                 {
756                     ValidateDistinctProjection(definition.ResultType, groupAggregateExpr.ArgExpr.ErrCtx, null);
757                     definition = definition.Distinct();
758                 }
759
760                 //
761                 // Add aggregate to aggreate list.
762                 //
763                 aggregateInfo.AttachToAstNode(sr.GenerateInternalName("groupPartition"), definition);
764                 aggregateInfo.EvaluatingScopeRegion.GroupAggregateInfos.Add(aggregateInfo);
765
766                 //
767                 // Return stub expression with same type as the group aggregate.
768                 //
769                 converted = aggregateInfo.AggregateStubExpression;
770             }
771
772             Debug.Assert(null != converted, "null != converted");
773
774             return new ValueExpression(converted);
775         }
776
777         #region ConvertMethodExpr implementation
778         /// <summary>
779         /// Converts invocation expression (AST.MethodExpr)
780         /// </summary>
781         private static ExpressionResolution ConvertMethodExpr(AST.Node expr, SemanticResolver sr)
782         {
783             return ConvertMethodExpr((AST.MethodExpr)expr, true /* includeInlineFunctions */, sr);
784         }
785
786         private static ExpressionResolution ConvertMethodExpr(AST.MethodExpr methodExpr, bool includeInlineFunctions, SemanticResolver sr)
787         {
788             //
789             // Resolve methodExpr.Expr
790             //
791             ExpressionResolution leftResolution;
792             using (sr.TypeResolver.EnterFunctionNameResolution(includeInlineFunctions))
793             {
794                 AST.Identifier simpleFunctionName = methodExpr.Expr as AST.Identifier;
795                 if (simpleFunctionName != null)
796                 {
797                     leftResolution = sr.ResolveSimpleFunctionName(simpleFunctionName.Name, simpleFunctionName.ErrCtx);
798                 }
799                 else
800                 {
801                     //
802                     // Convert methodExpr.Expr optionally entering special resolution modes. See ConvertMethodExpr_TryEnter methods for more info.
803                     //
804                     AST.DotExpr dotExpr = methodExpr.Expr as AST.DotExpr;
805                     using (ConvertMethodExpr_TryEnterIgnoreEntityContainerNameResolution(dotExpr, sr))
806                     {
807                         using (ConvertMethodExpr_TryEnterV1ViewGenBackwardCompatibilityResolution(dotExpr, sr))
808                         {
809                             leftResolution = Convert(methodExpr.Expr, sr);
810                         }
811                     }
812                 }
813             }
814
815             if (leftResolution.ExpressionClass == ExpressionResolutionClass.MetadataMember)
816             {
817                 MetadataMember metadataMember = (MetadataMember)leftResolution;
818
819                 //
820                 // Try converting as inline function call. If it fails, continue and try to convert as a model-defined function/function import call.
821                 //
822                 ValueExpression inlineFunctionCall;
823                 if (metadataMember.MetadataMemberClass == MetadataMemberClass.InlineFunctionGroup)
824                 {
825                     Debug.Assert(includeInlineFunctions, "includeInlineFunctions must be true, otherwise recursion does not stop");
826
827                     methodExpr.ErrCtx.ErrorContextInfo = Strings.CtxFunction(metadataMember.Name);
828                     methodExpr.ErrCtx.UseContextInfoAsResourceIdentifier = false;
829                     if (TryConvertInlineFunctionCall((InlineFunctionGroup)metadataMember, methodExpr, sr, out inlineFunctionCall))
830                     {
831                         return inlineFunctionCall;
832                     }
833                     else
834                     {
835                         // Make another try ignoring inline functions.
836                         return ConvertMethodExpr(methodExpr, false /* includeInlineFunctions */, sr);
837                     }
838                 }
839
840                 switch (metadataMember.MetadataMemberClass)
841                 {
842                     case MetadataMemberClass.Type:
843                         methodExpr.ErrCtx.ErrorContextInfo = Strings.CtxTypeCtor(metadataMember.Name);
844                         methodExpr.ErrCtx.UseContextInfoAsResourceIdentifier = false;
845                         return ConvertTypeConstructorCall((MetadataType)metadataMember, methodExpr, sr);
846
847                     case MetadataMemberClass.FunctionGroup:
848                         methodExpr.ErrCtx.ErrorContextInfo = Strings.CtxFunction(metadataMember.Name);
849                         methodExpr.ErrCtx.UseContextInfoAsResourceIdentifier = false;
850                         return ConvertModelFunctionCall((MetadataFunctionGroup)metadataMember, methodExpr, sr);
851
852                     default:
853                         throw EntityUtil.EntitySqlError(methodExpr.Expr.ErrCtx, Strings.CannotResolveNameToTypeOrFunction(metadataMember.Name));
854                 }
855             }
856             else
857             {
858                 throw EntityUtil.EntitySqlError(methodExpr.ErrCtx, Strings.MethodInvocationNotSupported);
859             }
860         }
861
862         /// <summary>
863         /// If methodExpr.Expr is in the form of "Name1.Name2(...)" then ignore entity containers during resolution of the left expression 
864         /// in the context of the invocation: "EntityContainer.EntitySet(...)" is not a valid expression and it should not shadow 
865         /// a potentially valid interpretation as "Namespace.EntityType/Function(...)".
866         /// </summary>
867         private static IDisposable ConvertMethodExpr_TryEnterIgnoreEntityContainerNameResolution(AST.DotExpr leftExpr, SemanticResolver sr)
868         {
869             return leftExpr != null && leftExpr.Left is AST.Identifier ? sr.EnterIgnoreEntityContainerNameResolution() : null;
870         }
871
872         /// <summary>
873         /// If methodExpr.Expr is in the form of "Name1.Name2(...)"
874         /// and we are in the view generation mode
875         /// and schema version is less than V2
876         /// then ignore types in the resolution of Name1.
877         /// This is needed in order to support the following V1 case:
878         ///     C-space type: AdventureWorks.Store
879         ///     S-space type: [AdventureWorks.Store].Customer
880         ///     query: select [AdventureWorks.Store].Customer(1, 2, 3) from ...
881         /// </summary>
882         private static IDisposable ConvertMethodExpr_TryEnterV1ViewGenBackwardCompatibilityResolution(AST.DotExpr leftExpr, SemanticResolver sr)
883         {
884             if (leftExpr != null && leftExpr.Left is AST.Identifier &&
885                 (sr.ParserOptions.ParserCompilationMode == ParserOptions.CompilationMode.RestrictedViewGenerationMode ||
886                 sr.ParserOptions.ParserCompilationMode == ParserOptions.CompilationMode.UserViewGenerationMode))
887             {
888                 var mappingCollection = 
889                     sr.TypeResolver.Perspective.MetadataWorkspace.GetItemCollection(DataSpace.CSSpace) as StorageMappingItemCollection;
890
891                 Debug.Assert(mappingCollection != null, "mappingCollection != null");
892
893                 if (mappingCollection.MappingVersion < XmlConstants.EdmVersionForV2)
894                 {
895                     return sr.TypeResolver.EnterBackwardCompatibilityResolution();
896                 }
897             }
898             return null;
899         }
900
901         /// <summary>
902         /// Attempts to create a <see cref="ValueExpression"/> representing the inline function call.
903         /// Returns false if <paramref name="methodExpr"/>.DistinctKind != <see see="AST.Method.DistinctKind"/>.None.
904         /// Returns false if no one of the overloads matched the given arguments.
905         /// Throws if given arguments cause overload resolution ambiguity.
906         /// </summary>
907         private static bool TryConvertInlineFunctionCall(
908             InlineFunctionGroup inlineFunctionGroup,
909             AST.MethodExpr methodExpr,
910             SemanticResolver sr,
911             out ValueExpression inlineFunctionCall)
912         {
913             inlineFunctionCall = null;
914
915             //
916             // An inline function can't be a group aggregate, so if DistinctKind is specified then it is not an inline function call.
917             //
918             if (methodExpr.DistinctKind != AST.DistinctKind.None)
919             {
920                 return false;
921             }
922
923             //
924             // Convert function arguments.
925             //
926             List<TypeUsage> argTypes;
927             var args = ConvertFunctionArguments(methodExpr.Args, sr, out argTypes);
928
929             //
930             // Find function overload match for the given argument types.
931             //
932             bool isAmbiguous = false;
933             InlineFunctionInfo overload = SemanticResolver.ResolveFunctionOverloads(
934                 inlineFunctionGroup.FunctionMetadata,
935                 argTypes,
936                 (lambdaOverload) => lambdaOverload.Parameters,
937                 (varRef) => varRef.ResultType,
938                 (varRef) => ParameterMode.In,
939                 false /* isGroupAggregateFunction */,
940                 out isAmbiguous);
941
942             //
943             // If there is more than one overload that matches the given arguments, throw.
944             //
945             if (isAmbiguous)
946             {
947                 throw EntityUtil.EntitySqlError(methodExpr.ErrCtx, Strings.AmbiguousFunctionArguments);
948             }
949
950             //
951             // If null, means no overload matched.
952             //
953             if (overload == null)
954             {
955                 return false;
956             }
957
958             //
959             // Convert untyped NULLs in arguments to typed nulls inferred from formals.
960             //
961             ConvertUntypedNullsInArguments(args, overload.Parameters, (formal) => formal.ResultType);
962
963             inlineFunctionCall = new ValueExpression(DbExpressionBuilder.Invoke(overload.GetLambda(sr), args));
964             return true;
965         }
966
967         private static ValueExpression ConvertTypeConstructorCall(MetadataType metadataType, AST.MethodExpr methodExpr, SemanticResolver sr)
968         {
969             //
970             // Ensure type has a contructor.
971             //
972             if (!TypeSemantics.IsComplexType(metadataType.TypeUsage) &&
973                 !TypeSemantics.IsEntityType(metadataType.TypeUsage) &&
974                 !TypeSemantics.IsRelationshipType(metadataType.TypeUsage))
975             {
976                 throw EntityUtil.EntitySqlError(methodExpr.ErrCtx, Strings.InvalidCtorUseOnType(metadataType.TypeUsage.EdmType.FullName));
977             }
978
979             //
980             // Abstract types cannot be instantiated.
981             //
982             if (metadataType.TypeUsage.EdmType.Abstract)
983             {
984                 throw EntityUtil.EntitySqlError(methodExpr.ErrCtx, Strings.CannotInstantiateAbstractType(metadataType.TypeUsage.EdmType.FullName));
985             }
986
987             //
988             // DistinctKind must not be specified on a type constructor.
989             //
990             if (methodExpr.DistinctKind != AST.DistinctKind.None)
991             {
992                 throw EntityUtil.EntitySqlError(methodExpr.ErrCtx, Strings.InvalidDistinctArgumentInCtor);
993             }
994
995             //
996             // Convert relationships if present.
997             //
998             List<DbRelatedEntityRef> relshipExprList = null;
999             if (methodExpr.HasRelationships)
1000             {
1001                 if (!(sr.ParserOptions.ParserCompilationMode == ParserOptions.CompilationMode.RestrictedViewGenerationMode ||
1002                       sr.ParserOptions.ParserCompilationMode == ParserOptions.CompilationMode.UserViewGenerationMode))
1003                 {
1004                     throw EntityUtil.EntitySqlError(methodExpr.Relationships.ErrCtx, Strings.InvalidModeForWithRelationshipClause);
1005                 }
1006
1007                 EntityType driverEntityType = metadataType.TypeUsage.EdmType as EntityType;
1008                 if (driverEntityType == null)
1009                 {
1010                     throw EntityUtil.EntitySqlError(methodExpr.Relationships.ErrCtx, Strings.InvalidTypeForWithRelationshipClause);
1011                 }
1012
1013                 HashSet<string> targetEnds = new HashSet<string>();
1014                 relshipExprList = new List<DbRelatedEntityRef>(methodExpr.Relationships.Count);
1015                 for (int i = 0; i < methodExpr.Relationships.Count; i++)
1016                 {
1017                     AST.RelshipNavigationExpr relshipExpr = methodExpr.Relationships[i];
1018
1019                     DbRelatedEntityRef relshipTarget = ConvertRelatedEntityRef(relshipExpr, driverEntityType, sr);
1020
1021                     string targetEndId = String.Join(":", new String[] { relshipTarget.TargetEnd.DeclaringType.Identity, relshipTarget.TargetEnd.Identity });
1022                     if (targetEnds.Contains(targetEndId))
1023                     {
1024                         throw EntityUtil.EntitySqlError(relshipExpr.ErrCtx, Strings.RelationshipTargetMustBeUnique(targetEndId));
1025                     }
1026
1027                     targetEnds.Add(targetEndId);
1028
1029                     relshipExprList.Add(relshipTarget);
1030                 }
1031             }
1032
1033             List<TypeUsage> argTypes;
1034             return new ValueExpression(CreateConstructorCallExpression(methodExpr,
1035                                                                        metadataType.TypeUsage,
1036                                                                        ConvertFunctionArguments(methodExpr.Args, sr, out argTypes),
1037                                                                        relshipExprList,
1038                                                                        sr));
1039         }
1040
1041         private static ValueExpression ConvertModelFunctionCall(MetadataFunctionGroup metadataFunctionGroup, AST.MethodExpr methodExpr, SemanticResolver sr)
1042         {
1043             if (metadataFunctionGroup.FunctionMetadata.Any(f => !f.IsComposableAttribute))
1044             {
1045                 throw EntityUtil.EntitySqlError(methodExpr.ErrCtx, Strings.CannotCallNoncomposableFunction(metadataFunctionGroup.Name));
1046             }
1047
1048             //
1049             // Decide if it is an ordinary function or group aggregate
1050             //
1051             if (TypeSemantics.IsAggregateFunction(metadataFunctionGroup.FunctionMetadata[0]) && sr.IsInAnyGroupScope())
1052             {
1053                 //
1054                 // If it is an aggreagate function inside a group scope, dispatch to the expensive ConvertAggregateFunctionInGroupScope()...
1055                 //
1056                 return new ValueExpression(ConvertAggregateFunctionInGroupScope(methodExpr, metadataFunctionGroup, sr));
1057             }
1058             else
1059             {
1060                 //
1061                 // Otherwise, it is just an ordinary function call (including aggregate functions outside of a group scope)
1062                 //
1063                 return new ValueExpression(CreateModelFunctionCallExpression(methodExpr, metadataFunctionGroup, sr));
1064             }
1065         }
1066
1067         #region ConvertAggregateFunctionInGroupScope implementation
1068         /// <summary>
1069         /// Converts group aggregates.
1070         /// </summary>
1071         /// <remarks>
1072         /// This method converts group aggregates in two phases:
1073         /// Phase 1 - it will resolve the actual inner (argument) expression and then anotate the ast node and add the resolved aggregate
1074         /// to the scope
1075         /// Phase 2 - if ast node was annotated, just extract the precomputed expression from the scope.
1076         /// </remarks>
1077         private static DbExpression ConvertAggregateFunctionInGroupScope(AST.MethodExpr methodExpr, MetadataFunctionGroup metadataFunctionGroup, SemanticResolver sr)
1078         {
1079             DbExpression converted = null;
1080
1081             //
1082             // First, check if methodExpr is already resolved as an aggregate...
1083             //
1084             if (TryConvertAsResolvedGroupAggregate(methodExpr, sr, out converted))
1085             {
1086                 return converted;
1087             }
1088
1089             //
1090             // ... then, try to convert as a collection function.
1091             //
1092             // Note that if methodExpr represents a group aggregate, 
1093             // then the argument conversion performed inside of TryConvertAsCollectionFunction(...) is thrown away.
1094             // Throwing the argument conversion however is not possible in a clean way as the argument conversion has few side-effects:
1095             // 1. For each group aggregate within the argument a new GroupAggregateInfo object is created and:
1096             //    a. Some of the aggregates are assigned to outer scope regions for evaluation, which means their aggregate info objects are
1097             //         - enlisted in the outer scope regions,
1098             //         - remain attached to the corresponding AST nodes, see GroupAggregateInfo.AttachToAstNode(...) for more info.
1099             //       These aggregate info objects will be reused when the aggregates are revisited, see TryConvertAsResolvedGroupAggregate(...) method for more info.
1100             //    b. The aggregate info objects of closest aggregates are wired to sr.CurrentGroupAggregateInfo object as contained/containing.
1101             // 2. sr.CurrentGroupAggregateInfo.InnermostReferencedScopeRegion value is adjusted with all the scope entry references outside of nested aggregates.
1102             // Hence when the conversion as a collection function fails, these side-effects must be mitigated:
1103             // (1.a) does not cause any issues.
1104             // (1.b) requires rewiring which is handled by the GroupAggregateInfo.SetContainingAggregate(...) mechanism invoked by 
1105             //       TryConvertAsResolvedGroupAggregate(...) method.
1106             // (2) requires saving and restoring the InnermostReferencedScopeRegion value, which is handled in the code below.
1107             //
1108             // Note: we also do a throw-away conversions in other places, such as inline function attempt and processing of projection items in order by clause,
1109             // but this method is the only place where conversion attempts differ in the way how converted argument expression is processed.
1110             // This method is the only place that affects sr.CurrentGroupAggregateInfo with regard to the converted argument expression.
1111             // Hence the side-effect mitigation is needed only here.
1112             //
1113             ScopeRegion savedInnermostReferencedScopeRegion = sr.CurrentGroupAggregateInfo != null ? sr.CurrentGroupAggregateInfo.InnermostReferencedScopeRegion : null;
1114             List<TypeUsage> argTypes;
1115             if (TryConvertAsCollectionFunction(methodExpr, metadataFunctionGroup, sr, out argTypes, out converted))
1116             {
1117                 return converted;
1118             }
1119             else if (sr.CurrentGroupAggregateInfo != null)
1120             {
1121                 sr.CurrentGroupAggregateInfo.InnermostReferencedScopeRegion = savedInnermostReferencedScopeRegion;
1122             }
1123             Debug.Assert(argTypes != null, "argTypes != null");
1124
1125             //
1126             // Finally, try to convert as a function group aggregate.
1127             //
1128             if (TryConvertAsFunctionAggregate(methodExpr, metadataFunctionGroup, argTypes, sr, out converted))
1129             {
1130                 return converted;
1131             }
1132
1133             //
1134             // If we reach this point, means the resolution failed.
1135             //
1136             throw EntityUtil.EntitySqlError(methodExpr.ErrCtx, Strings.FailedToResolveAggregateFunction(metadataFunctionGroup.Name));
1137         }
1138
1139         /// <summary>
1140         /// Try to convert as pre resolved group aggregate.
1141         /// </summary>
1142         private static bool TryConvertAsResolvedGroupAggregate(AST.GroupAggregateExpr groupAggregateExpr, SemanticResolver sr, out DbExpression converted)
1143         {
1144             converted = null;
1145
1146             //
1147             // If ast node was annotated in a previous pass, means it contains a ready-to-use expression,
1148             // otherwise exit.
1149             //
1150             if (groupAggregateExpr.AggregateInfo == null)
1151             {
1152                 return false;
1153             }
1154
1155             //
1156             // Wire up groupAggregateExpr.AggregateInfo to the sr.CurrentGroupAggregateInfo.
1157             // This is needed in the following case:  ... select max(x + max(b)) ...
1158             // The outer max(...) is first processed as collection function, so when the nested max(b) is processed as an aggregate, it does not
1159             // see the outer function as a containing aggregate, so it does not wire to it. 
1160             // Later, when the outer max(...) is processed as an aggregate, processing of the inner max(...) gets into TryConvertAsResolvedGroupAggregate(...)
1161             // and at this point we finally wire up the two aggregates.
1162             //
1163             groupAggregateExpr.AggregateInfo.SetContainingAggregate(sr.CurrentGroupAggregateInfo);
1164
1165             if (!sr.TryResolveInternalAggregateName(groupAggregateExpr.AggregateInfo.AggregateName, groupAggregateExpr.AggregateInfo.ErrCtx, out converted))
1166             {
1167                 Debug.Assert(groupAggregateExpr.AggregateInfo.AggregateStubExpression != null, "Resolved aggregate stub expression must not be null.");
1168                 converted = groupAggregateExpr.AggregateInfo.AggregateStubExpression;
1169             }
1170
1171             Debug.Assert(converted != null, "converted != null");
1172
1173             return true;
1174         }
1175
1176         /// <summary>
1177         /// Try convert method expr in a group scope as a collection aggregate
1178         /// </summary>
1179         /// <param name="argTypes">argTypes are returned regardless of the function result</param>
1180         private static bool TryConvertAsCollectionFunction(AST.MethodExpr methodExpr,
1181                                                            MetadataFunctionGroup metadataFunctionGroup,
1182                                                            SemanticResolver sr,
1183                                                            out List<TypeUsage> argTypes,
1184                                                            out DbExpression converted)
1185         {
1186             //
1187             // Convert aggregate arguments.
1188             //
1189             var args = ConvertFunctionArguments(methodExpr.Args, sr, out argTypes);
1190
1191             //
1192             // Try to see if there is an overload match.
1193             //
1194             bool isAmbiguous = false;
1195             EdmFunction functionType = SemanticResolver.ResolveFunctionOverloads(
1196                 metadataFunctionGroup.FunctionMetadata,
1197                 argTypes,
1198                 false /* isGroupAggregateFunction */,
1199                 out isAmbiguous);
1200
1201             //
1202             // If there is more then one overload that matches given arguments, throw.
1203             //
1204             if (isAmbiguous)
1205             {
1206                 throw EntityUtil.EntitySqlError(methodExpr.ErrCtx, Strings.AmbiguousFunctionArguments);
1207             }
1208
1209             //
1210             // If not null, means a match was found as a collection aggregate (ordinary function).
1211             //
1212             if (functionType != null)
1213             {
1214                 //
1215                 // Convert untyped NULLs in arguments to typed nulls inferred from function parameters.
1216                 //
1217                 ConvertUntypedNullsInArguments(args, functionType.Parameters, (parameter) => parameter.TypeUsage);
1218                 converted = functionType.Invoke(args);
1219                 return true;
1220             }
1221             else
1222             {
1223                 converted = null;
1224                 return false;
1225             }
1226         }
1227
1228         private static bool TryConvertAsFunctionAggregate(AST.MethodExpr methodExpr,
1229                                                           MetadataFunctionGroup metadataFunctionGroup,
1230                                                           List<TypeUsage> argTypes,
1231                                                           SemanticResolver sr,
1232                                                           out DbExpression converted)
1233         {
1234             Debug.Assert(argTypes != null, "argTypes != null");
1235
1236             converted = null;
1237
1238             //
1239             // Try to find an overload match as group aggregate
1240             //
1241             bool isAmbiguous = false;
1242             EdmFunction functionType = SemanticResolver.ResolveFunctionOverloads(
1243                 metadataFunctionGroup.FunctionMetadata,
1244                 argTypes,
1245                 true /* isGroupAggregateFunction */,
1246                 out isAmbiguous);
1247
1248             //
1249             // If there is more then one overload that matches given arguments, throw.
1250             //
1251             if (isAmbiguous)
1252             {
1253                 throw EntityUtil.EntitySqlError(methodExpr.ErrCtx, Strings.AmbiguousFunctionArguments);
1254             }
1255
1256             //
1257             // If it still null, then there is no overload as a group aggregate function.
1258             //
1259             if (null == functionType)
1260             {
1261                 CqlErrorHelper.ReportFunctionOverloadError(methodExpr, metadataFunctionGroup.FunctionMetadata[0], argTypes);
1262             }
1263             //
1264             // Process aggregate argument.
1265             //
1266             List<DbExpression> args;
1267             FunctionAggregateInfo aggregateInfo;
1268             using (sr.EnterFunctionAggregate(methodExpr, methodExpr.ErrCtx, out aggregateInfo))
1269             {
1270                 List<TypeUsage> aggArgTypes;
1271                 args = ConvertFunctionArguments(methodExpr.Args, sr, out aggArgTypes);
1272                 // Sanity check - argument types must agree.
1273                 Debug.Assert(
1274                     argTypes.Count == aggArgTypes.Count &&
1275                     argTypes.Zip(aggArgTypes).All(types => types.Key == null && types.Value == null || TypeSemantics.IsStructurallyEqual(types.Key, types.Value)),
1276                     "argument types resolved for the collection aggregate calls must match");
1277             }
1278
1279             //
1280             // Aggregate functions can have only one argument and of collection type
1281             //
1282             Debug.Assert((1 == functionType.Parameters.Count), "(1 == functionType.Parameters.Count)"); // we only support monadic aggregate functions
1283             Debug.Assert(TypeSemantics.IsCollectionType(functionType.Parameters[0].TypeUsage), "functionType.Parameters[0].Type is CollectionType");
1284
1285             //
1286             // Convert untyped NULLs in arguments to typed nulls inferred from function parameters.
1287             //
1288             ConvertUntypedNullsInArguments(args, functionType.Parameters, (parameter) => TypeHelpers.GetElementTypeUsage(parameter.TypeUsage));
1289
1290             //
1291             // Create function aggregate expression.
1292             //
1293             DbFunctionAggregate functionAggregate;
1294             if (methodExpr.DistinctKind == AST.DistinctKind.Distinct)
1295             {
1296                 functionAggregate = DbExpressionBuilder.AggregateDistinct(functionType, args[0]);
1297             }
1298             else
1299             {
1300                 functionAggregate = DbExpressionBuilder.Aggregate(functionType, args[0]);
1301             }
1302
1303             //
1304             // Add aggregate to aggreate list.
1305             //
1306             aggregateInfo.AttachToAstNode(sr.GenerateInternalName("groupAgg" + functionType.Name), functionAggregate);
1307             aggregateInfo.EvaluatingScopeRegion.GroupAggregateInfos.Add(aggregateInfo);
1308
1309             //
1310             // Return stub expression with same type as the aggregate function.
1311             //
1312             converted = aggregateInfo.AggregateStubExpression;
1313
1314             Debug.Assert(converted != null, "converted != null");
1315
1316             return true;
1317         }
1318         #endregion ConvertAggregateFunctionInGroupScope implementation
1319
1320         /// <summary>
1321         /// Creates <see cref="DbExpression"/> representing a new instance of the given type.
1322         /// Validates and infers argument types.
1323         /// </summary>
1324         private static DbExpression CreateConstructorCallExpression(AST.MethodExpr methodExpr,
1325                                                                     TypeUsage type,
1326                                                                     List<DbExpression> args,
1327                                                                     List<DbRelatedEntityRef> relshipExprList,
1328                                                                     SemanticResolver sr)
1329         {
1330             Debug.Assert(TypeSemantics.IsComplexType(type) || TypeSemantics.IsEntityType(type) || TypeSemantics.IsRelationshipType(type), "type must have a constructor");
1331
1332             DbExpression newInstance = null;
1333             int idx = 0;
1334             int argCount = args.Count;
1335
1336             //
1337             // Find overloads by searching members in order of its definition.
1338             // Each member will be considered as a formal argument type in the order of its definition.
1339             //
1340             StructuralType stype = (StructuralType)type.EdmType;
1341             foreach (EdmMember member in TypeHelpers.GetAllStructuralMembers(stype))
1342             {
1343                 TypeUsage memberModelTypeUsage = Helper.GetModelTypeUsage(member);
1344
1345                 Debug.Assert(memberModelTypeUsage.EdmType.DataSpace == DataSpace.CSpace, "member space must be CSpace");
1346
1347                 //
1348                 // Ensure given arguments are not less than 'formal' constructor arguments.
1349                 //
1350                 if (argCount <= idx)
1351                 {
1352                     throw EntityUtil.EntitySqlError(methodExpr.ErrCtx, Strings.NumberOfTypeCtorIsLessThenFormalSpec(member.Name));
1353                 }
1354
1355                 //
1356                 // If the given argument is the untyped null, infer type from the ctor formal argument type.
1357                 //
1358                 if (args[idx] == null)
1359                 {
1360                     EdmProperty edmProperty = member as EdmProperty;
1361                     if (edmProperty != null && !edmProperty.Nullable)
1362                     {
1363                         throw EntityUtil.EntitySqlError(methodExpr.Args[idx].ErrCtx,
1364                             Strings.InvalidNullLiteralForNonNullableMember(member.Name, stype.FullName));
1365                     }
1366                     args[idx] = DbExpressionBuilder.Null(memberModelTypeUsage);
1367                 }
1368
1369                 //
1370                 // Ensure the given argument type is promotable to the formal ctor argument type.
1371                 //
1372                 bool isPromotable = TypeSemantics.IsPromotableTo(args[idx].ResultType, memberModelTypeUsage);
1373                 if (ParserOptions.CompilationMode.RestrictedViewGenerationMode == sr.ParserOptions.ParserCompilationMode ||
1374                     ParserOptions.CompilationMode.UserViewGenerationMode == sr.ParserOptions.ParserCompilationMode)
1375                 {
1376                     if (!isPromotable && !TypeSemantics.IsPromotableTo(memberModelTypeUsage, args[idx].ResultType))
1377                     {
1378                         throw EntityUtil.EntitySqlError(methodExpr.Args[idx].ErrCtx,
1379                             Strings.InvalidCtorArgumentType(
1380                                                        args[idx].ResultType.EdmType.FullName,
1381                                                        member.Name,
1382                                                        memberModelTypeUsage.EdmType.FullName));
1383                     }
1384
1385                     if (Helper.IsPrimitiveType(memberModelTypeUsage.EdmType) &&
1386                         !TypeSemantics.IsSubTypeOf(args[idx].ResultType, memberModelTypeUsage))
1387                     {
1388                         args[idx] = args[idx].CastTo(memberModelTypeUsage);
1389                     }
1390                 }
1391                 else
1392                 {
1393                     if (!isPromotable)
1394                     {
1395                         throw EntityUtil.EntitySqlError(methodExpr.Args[idx].ErrCtx,
1396                             Strings.InvalidCtorArgumentType(
1397                                                        args[idx].ResultType.EdmType.FullName,
1398                                                        member.Name,
1399                                                        memberModelTypeUsage.EdmType.FullName));
1400                     }
1401                 }
1402
1403                 idx++;
1404             }
1405
1406             //
1407             // Ensure all given arguments and all ctor formals were considered and properly checked.
1408             //
1409             if (idx != argCount)
1410             {
1411                 throw EntityUtil.EntitySqlError(methodExpr.ErrCtx, Strings.NumberOfTypeCtorIsMoreThenFormalSpec(stype.FullName));
1412             }
1413
1414             //
1415             // Finally, create expression
1416             //
1417             if (relshipExprList != null && relshipExprList.Count > 0)
1418             {
1419                 EntityType entityType = (EntityType)type.EdmType;
1420                 newInstance = DbExpressionBuilder.CreateNewEntityWithRelationshipsExpression(entityType, args, relshipExprList);
1421             }
1422             else
1423             {
1424                 newInstance = DbExpressionBuilder.New(TypeHelpers.GetReadOnlyType(type), args);
1425             }
1426             Debug.Assert(null != newInstance, "null != newInstance");
1427
1428             return newInstance;
1429         }
1430
1431         /// <summary>
1432         /// Creates <see cref="DbFunctionExpression"/> representing a model function call.
1433         /// Validates overloads.
1434         /// </summary>
1435         private static DbFunctionExpression CreateModelFunctionCallExpression(AST.MethodExpr methodExpr,
1436                                                                               MetadataFunctionGroup metadataFunctionGroup,
1437                                                                               SemanticResolver sr)
1438         {
1439             DbFunctionExpression functionExpression = null;
1440             bool isAmbiguous = false;
1441
1442             //
1443             // DistinctKind must not be specified on a regular function call.
1444             //
1445             if (methodExpr.DistinctKind != AST.DistinctKind.None)
1446             {
1447                 throw EntityUtil.EntitySqlError(methodExpr.ErrCtx, Strings.InvalidDistinctArgumentInNonAggFunction);
1448             }
1449
1450             //
1451             // Convert function arguments.
1452             //
1453             List<TypeUsage> argTypes;
1454             var args = ConvertFunctionArguments(methodExpr.Args, sr, out argTypes);
1455
1456             //
1457             // Find function overload match for given argument types.
1458             //
1459             EdmFunction functionType = SemanticResolver.ResolveFunctionOverloads(
1460                 metadataFunctionGroup.FunctionMetadata,
1461                 argTypes,
1462                 false /* isGroupAggregateFunction */,
1463                 out isAmbiguous);
1464
1465             //
1466             // If there is more than one overload that matches given arguments, throw.
1467             //
1468             if (isAmbiguous)
1469             {
1470                 throw EntityUtil.EntitySqlError(methodExpr.ErrCtx, Strings.AmbiguousFunctionArguments);
1471             }
1472
1473             //
1474             // If null, means no overload matched.
1475             //
1476             if (null == functionType)
1477             {
1478                 CqlErrorHelper.ReportFunctionOverloadError(methodExpr, metadataFunctionGroup.FunctionMetadata[0], argTypes);
1479             }
1480
1481             //
1482             // Convert untyped NULLs in arguments to typed nulls inferred from function parameters.
1483             //
1484             ConvertUntypedNullsInArguments(args, functionType.Parameters, (parameter) => parameter.TypeUsage);
1485
1486             //
1487             // Finally, create expression
1488             //
1489             functionExpression = functionType.Invoke(args);
1490
1491             Debug.Assert(null != functionExpression, "null != functionExpression");
1492
1493             return functionExpression;
1494         }
1495
1496         /// <summary>
1497         /// Converts function call arguments into a list of <see cref="DbExpression"/>s.
1498         /// In case of no arguments returns an empty list.
1499         /// </summary>
1500         private static List<DbExpression> ConvertFunctionArguments(AST.NodeList<AST.Node> astExprList, SemanticResolver sr, out List<TypeUsage> argTypes)
1501         {
1502             List<DbExpression> convertedArgs = new List<DbExpression>();
1503
1504             if (null != astExprList)
1505             {
1506                 for (int i = 0; i < astExprList.Count; i++)
1507                 {
1508                     convertedArgs.Add(ConvertValueExpressionAllowUntypedNulls(astExprList[i], sr));
1509                 }
1510             }
1511
1512             argTypes = convertedArgs.Select(a => a != null ? a.ResultType : null).ToList();
1513             return convertedArgs;
1514         }
1515
1516         private static void ConvertUntypedNullsInArguments<TParameterMetadata>(
1517             List<DbExpression> args,
1518             IList<TParameterMetadata> parametersMetadata,
1519             Func<TParameterMetadata, TypeUsage> getParameterTypeUsage)
1520         {
1521             for (int i = 0; i < args.Count; i++)
1522             {
1523                 if (args[i] == null)
1524                 {
1525                     args[i] = DbExpressionBuilder.Null(getParameterTypeUsage(parametersMetadata[i]));
1526                 }
1527             }
1528         }
1529         #endregion ConvertMethodExpr implementation
1530
1531         /// <summary>
1532         /// Converts command parameter reference expression (AST.QueryParameter)
1533         /// </summary>
1534         private static ExpressionResolution ConvertParameter(AST.Node expr, SemanticResolver sr)
1535         {
1536             AST.QueryParameter parameter = (AST.QueryParameter)expr;
1537
1538             DbParameterReferenceExpression paramRef;
1539             if (null == sr.Parameters || !sr.Parameters.TryGetValue(parameter.Name, out paramRef))
1540             {
1541                 throw EntityUtil.EntitySqlError(parameter.ErrCtx, Strings.ParameterWasNotDefined(parameter.Name));
1542             }
1543
1544             return new ValueExpression(paramRef);
1545         }
1546
1547         /// <summary>
1548         /// Converts WITH RELATIONSHIP (AST.RelshipNavigationExpr)
1549         /// </summary>
1550         /// <param name="driverEntityType">The entity that is being constructed for with this RELATIONSHIP clause is processed.</param>
1551         /// <param name="relshipExpr">the ast expression</param>
1552         /// <param name="sr">the Semantic Resolver context</param>
1553         /// <returns>a DbRelatedEntityRef instance</returns>
1554         private static DbRelatedEntityRef ConvertRelatedEntityRef(AST.RelshipNavigationExpr relshipExpr, EntityType driverEntityType, SemanticResolver sr)
1555         {
1556             //
1557             // Resolve relationship type name.
1558             //
1559             var edmType = ConvertTypeName(relshipExpr.TypeName, sr).EdmType;
1560             var relationshipType = edmType as RelationshipType;
1561             if (relationshipType == null)
1562             {
1563                 throw EntityUtil.EntitySqlError(relshipExpr.TypeName.ErrCtx, Strings.RelationshipTypeExpected(edmType.FullName));
1564             }
1565
1566             //
1567             // Convert target instance expression.
1568             //
1569             var targetEntityRef = ConvertValueExpression(relshipExpr.RefExpr, sr);
1570
1571             //
1572             // Make sure it is a ref type.
1573             //
1574             var refType = targetEntityRef.ResultType.EdmType as RefType;
1575             if (refType == null)
1576             {
1577                 throw EntityUtil.EntitySqlError(relshipExpr.RefExpr.ErrCtx, Strings.RelatedEndExprTypeMustBeReference);
1578             }
1579
1580             //
1581             // Convert To end if explicitly defined, derive if implicit.
1582             //
1583             RelationshipEndMember toEnd;
1584             if (relshipExpr.ToEndIdentifier != null)
1585             {
1586                 toEnd = (RelationshipEndMember)relationshipType.Members.FirstOrDefault(m => m.Name.Equals(relshipExpr.ToEndIdentifier.Name, StringComparison.OrdinalIgnoreCase));
1587                 if (toEnd == null)
1588                 {
1589                     throw EntityUtil.EntitySqlError(relshipExpr.ToEndIdentifier.ErrCtx, Strings.InvalidRelationshipMember(relshipExpr.ToEndIdentifier.Name, relationshipType.FullName));
1590                 }
1591                 //
1592                 // ensure is *..{0|1}
1593                 //
1594                 if (toEnd.RelationshipMultiplicity != RelationshipMultiplicity.One && toEnd.RelationshipMultiplicity != RelationshipMultiplicity.ZeroOrOne)
1595                 {
1596                     throw EntityUtil.EntitySqlError(relshipExpr.ToEndIdentifier.ErrCtx,
1597                         Strings.InvalidWithRelationshipTargetEndMultiplicity(toEnd.Name, toEnd.RelationshipMultiplicity.ToString()));
1598                 }
1599                 if (!TypeSemantics.IsStructurallyEqualOrPromotableTo(refType, toEnd.TypeUsage.EdmType))
1600                 {
1601                     throw EntityUtil.EntitySqlError(relshipExpr.RefExpr.ErrCtx, Strings.RelatedEndExprTypeMustBePromotoableToToEnd(refType.FullName, toEnd.TypeUsage.EdmType.FullName));
1602                 }
1603             }
1604             else
1605             {
1606                 var toEndCandidates = relationshipType.Members.Select(m => (RelationshipEndMember)m)
1607                                                               .Where (e => TypeSemantics.IsStructurallyEqualOrPromotableTo(refType, e.TypeUsage.EdmType) &&
1608                                                                            (e.RelationshipMultiplicity == RelationshipMultiplicity.One ||
1609                                                                             e.RelationshipMultiplicity == RelationshipMultiplicity.ZeroOrOne)).ToArray();
1610                 switch (toEndCandidates.Length)
1611                 {
1612                     case 1:
1613                         toEnd = toEndCandidates[0];
1614                         break;
1615                     case 0:
1616                         throw EntityUtil.EntitySqlError(relshipExpr.ErrCtx, Strings.InvalidImplicitRelationshipToEnd(relationshipType.FullName));
1617                     default:
1618                         throw EntityUtil.EntitySqlError(relshipExpr.ErrCtx, Strings.RelationshipToEndIsAmbiguos);
1619                 }
1620             }
1621             Debug.Assert(toEnd != null, "toEnd must be resolved.");
1622
1623             //
1624             // Convert From end if explicitly defined, derive if implicit.
1625             //
1626             RelationshipEndMember fromEnd;
1627             if (relshipExpr.FromEndIdentifier != null)
1628             {
1629                 fromEnd = (RelationshipEndMember)relationshipType.Members.FirstOrDefault(m => m.Name.Equals(relshipExpr.FromEndIdentifier.Name, StringComparison.OrdinalIgnoreCase));
1630                 if (fromEnd == null)
1631                 {
1632                     throw EntityUtil.EntitySqlError(relshipExpr.FromEndIdentifier.ErrCtx, Strings.InvalidRelationshipMember(relshipExpr.FromEndIdentifier.Name, relationshipType.FullName));
1633                 }
1634                 if (!TypeSemantics.IsStructurallyEqualOrPromotableTo(driverEntityType.GetReferenceType(), fromEnd.TypeUsage.EdmType))
1635                 {
1636                     throw EntityUtil.EntitySqlError(relshipExpr.FromEndIdentifier.ErrCtx,
1637                         Strings.SourceTypeMustBePromotoableToFromEndRelationType(driverEntityType.FullName, fromEnd.TypeUsage.EdmType.FullName));
1638                 }
1639                 if (fromEnd.EdmEquals(toEnd))
1640                 {
1641                     throw EntityUtil.EntitySqlError(relshipExpr.ErrCtx, Strings.RelationshipFromEndIsAmbiguos);
1642                 }
1643             }
1644             else
1645             {
1646                 var fromEndCandidates = relationshipType.Members.Select(m => (RelationshipEndMember)m)
1647                                                                 .Where(e => TypeSemantics.IsStructurallyEqualOrPromotableTo(driverEntityType.GetReferenceType(), e.TypeUsage.EdmType) &&
1648                                                                              !e.EdmEquals(toEnd)).ToArray();
1649                 switch (fromEndCandidates.Length)
1650                 {
1651                     case 1:
1652                         fromEnd = fromEndCandidates[0];
1653                         break;
1654                     case 0:
1655                         throw EntityUtil.EntitySqlError(relshipExpr.ErrCtx, Strings.InvalidImplicitRelationshipFromEnd(relationshipType.FullName));
1656                     default:
1657                         Debug.Fail("N-ary relationship? N > 2");
1658                         throw EntityUtil.EntitySqlError(relshipExpr.ErrCtx, Strings.RelationshipFromEndIsAmbiguos);
1659                 }
1660             }
1661             Debug.Assert(fromEnd != null, "fromEnd must be resolved.");
1662
1663             return DbExpressionBuilder.CreateRelatedEntityRef(fromEnd, toEnd, targetEntityRef);
1664         }
1665
1666         /// <summary>
1667         /// Converts relationship navigation expression (AST.RelshipNavigationExpr)
1668         /// </summary>
1669         private static ExpressionResolution ConvertRelshipNavigationExpr(AST.Node astExpr, SemanticResolver sr)
1670         {
1671             AST.RelshipNavigationExpr relshipExpr = (AST.RelshipNavigationExpr)astExpr;
1672
1673             //
1674             // Resolve relationship type name.
1675             //
1676             var edmType = ConvertTypeName(relshipExpr.TypeName, sr).EdmType;
1677             var relationshipType = edmType as RelationshipType;
1678             if (relationshipType == null)
1679             {
1680                 throw EntityUtil.EntitySqlError(relshipExpr.TypeName.ErrCtx, Strings.RelationshipTypeExpected(edmType.FullName));
1681             }
1682
1683             //
1684             // Convert source instance expression.
1685             //
1686             var sourceEntityRef = ConvertValueExpression(relshipExpr.RefExpr, sr);
1687
1688             //
1689             // Make sure it is a ref type. Convert to ref if possible.
1690             //
1691             var sourceRefType = sourceEntityRef.ResultType.EdmType as RefType;
1692             if (sourceRefType == null)
1693             {
1694                 var entityType = sourceEntityRef.ResultType.EdmType as EntityType;
1695                 if (entityType != null)
1696                 {
1697                     sourceEntityRef = DbExpressionBuilder.GetEntityRef(sourceEntityRef);
1698                     sourceRefType = (RefType)sourceEntityRef.ResultType.EdmType;
1699                 }
1700                 else
1701                 {
1702                     throw EntityUtil.EntitySqlError(relshipExpr.RefExpr.ErrCtx, Strings.RelatedEndExprTypeMustBeReference);
1703                 }
1704             }
1705
1706             //
1707             // Convert To end if explicitly defined. Derive if implicit later, after From end processing.
1708             //
1709             RelationshipEndMember toEnd;
1710             if (relshipExpr.ToEndIdentifier != null)
1711             {
1712                 toEnd = (RelationshipEndMember)relationshipType.Members.FirstOrDefault(m => m.Name.Equals(relshipExpr.ToEndIdentifier.Name, StringComparison.OrdinalIgnoreCase));
1713                 if (toEnd == null)
1714                 {
1715                     throw EntityUtil.EntitySqlError(relshipExpr.ToEndIdentifier.ErrCtx, Strings.InvalidRelationshipMember(relshipExpr.ToEndIdentifier.Name, relationshipType.FullName));
1716                 }
1717             }
1718             else
1719             {
1720                 toEnd = null;
1721             }
1722
1723             //
1724             // Convert From end if explicitly defined, derive if implicit.
1725             //
1726             RelationshipEndMember fromEnd;
1727             if (relshipExpr.FromEndIdentifier != null)
1728             {
1729                 fromEnd = (RelationshipEndMember)relationshipType.Members.FirstOrDefault(m => m.Name.Equals(relshipExpr.FromEndIdentifier.Name, StringComparison.OrdinalIgnoreCase));
1730                 if (fromEnd == null)
1731                 {
1732                     throw EntityUtil.EntitySqlError(relshipExpr.FromEndIdentifier.ErrCtx, Strings.InvalidRelationshipMember(relshipExpr.FromEndIdentifier.Name, relationshipType.FullName));
1733                 }
1734                 if (!TypeSemantics.IsStructurallyEqualOrPromotableTo(sourceRefType, fromEnd.TypeUsage.EdmType))
1735                 {
1736                     throw EntityUtil.EntitySqlError(relshipExpr.FromEndIdentifier.ErrCtx,
1737                         Strings.SourceTypeMustBePromotoableToFromEndRelationType(sourceRefType.FullName, fromEnd.TypeUsage.EdmType.FullName));
1738                 }
1739                 if (toEnd != null && fromEnd.EdmEquals(toEnd))
1740                 {
1741                     throw EntityUtil.EntitySqlError(relshipExpr.ErrCtx, Strings.RelationshipFromEndIsAmbiguos);
1742                 }
1743             }
1744             else
1745             {
1746                 var fromEndCandidates = relationshipType.Members.Select(m => (RelationshipEndMember)m)
1747                                                                 .Where (e => TypeSemantics.IsStructurallyEqualOrPromotableTo(sourceRefType, e.TypeUsage.EdmType) &&
1748                                                                         (toEnd == null || !e.EdmEquals(toEnd))).ToArray();
1749                 switch (fromEndCandidates.Length)
1750                 {
1751                     case 1:
1752                         fromEnd = fromEndCandidates[0];
1753                         break;
1754                     case 0:
1755                         throw EntityUtil.EntitySqlError(relshipExpr.ErrCtx, Strings.InvalidImplicitRelationshipFromEnd(relationshipType.FullName));
1756                     default:
1757                         Debug.Assert(toEnd == null, "N-ary relationship? N > 2");
1758                         throw EntityUtil.EntitySqlError(relshipExpr.ErrCtx, Strings.RelationshipFromEndIsAmbiguos);
1759                 }
1760             }
1761             Debug.Assert(fromEnd != null, "fromEnd must be resolved.");
1762
1763             //
1764             // Derive To end if implicit.
1765             //
1766             if (toEnd == null)
1767             {
1768                 var toEndCandidates = relationshipType.Members.Select(m => (RelationshipEndMember)m)
1769                                                               .Where (e => !e.EdmEquals(fromEnd)).ToArray();
1770                 switch (toEndCandidates.Length)
1771                 {
1772                     case 1:
1773                         toEnd = toEndCandidates[0];
1774                         break;
1775                     case 0:
1776                         throw EntityUtil.EntitySqlError(relshipExpr.ErrCtx, Strings.InvalidImplicitRelationshipToEnd(relationshipType.FullName));
1777                     default:
1778                         Debug.Fail("N-ary relationship? N > 2");
1779                         throw EntityUtil.EntitySqlError(relshipExpr.ErrCtx, Strings.RelationshipToEndIsAmbiguos);
1780                 }
1781             }
1782             Debug.Assert(toEnd != null, "toEnd must be resolved.");
1783
1784             //
1785             // Create cqt expression.
1786             //
1787             DbExpression converted = sourceEntityRef.Navigate(fromEnd, toEnd);
1788             Debug.Assert(null != converted, "null != converted");
1789
1790             return new ValueExpression(converted);
1791         }
1792
1793         /// <summary>
1794         /// Converts REF expression (AST.RefExpr)
1795         /// </summary>
1796         private static ExpressionResolution ConvertRefExpr(AST.Node astExpr, SemanticResolver sr)
1797         {
1798             AST.RefExpr refExpr = (AST.RefExpr)astExpr;
1799
1800             DbExpression converted = ConvertValueExpression(refExpr.ArgExpr, sr);
1801
1802             //
1803             // check if is entity type
1804             //
1805             if (!TypeSemantics.IsEntityType(converted.ResultType))
1806             {
1807                 throw EntityUtil.EntitySqlError(refExpr.ArgExpr.ErrCtx, Strings.RefArgIsNotOfEntityType(converted.ResultType.EdmType.FullName));
1808             }
1809
1810             //
1811             // create ref expression
1812             //
1813             converted = converted.GetEntityRef();
1814             Debug.Assert(null != converted, "null != converted");
1815
1816             return new ValueExpression(converted);
1817         }
1818
1819         /// <summary>
1820         /// Converts DEREF expression (AST.DerefExpr)
1821         /// </summary>
1822         private static ExpressionResolution ConvertDeRefExpr(AST.Node astExpr, SemanticResolver sr)
1823         {
1824             AST.DerefExpr deRefExpr = (AST.DerefExpr)astExpr;
1825
1826             DbExpression converted = null;
1827
1828             converted = ConvertValueExpression(deRefExpr.ArgExpr, sr);
1829
1830             //
1831             // check if return type is RefType
1832             //
1833             if (!TypeSemantics.IsReferenceType(converted.ResultType))
1834             {
1835                 throw EntityUtil.EntitySqlError(deRefExpr.ArgExpr.ErrCtx, Strings.DeRefArgIsNotOfRefType(converted.ResultType.EdmType.FullName));
1836             }
1837
1838             //
1839             // create DeRef expression
1840             //
1841             converted = converted.Deref();
1842             Debug.Assert(null != converted, "null != converted");
1843
1844             return new ValueExpression(converted);
1845         }
1846
1847         /// <summary>
1848         /// Converts CREATEREF expression (AST.CreateRefExpr)
1849         /// </summary>
1850         private static ExpressionResolution ConvertCreateRefExpr(AST.Node astExpr, SemanticResolver sr)
1851         {
1852             AST.CreateRefExpr createRefExpr = (AST.CreateRefExpr)astExpr;
1853
1854             DbExpression converted = null;
1855
1856             //
1857             // Convert the entity set, also, ensure that we get back an extent expression
1858             //
1859             DbScanExpression entitySetExpr = ConvertValueExpression(createRefExpr.EntitySet, sr) as DbScanExpression;
1860             if (entitySetExpr == null)
1861             {
1862                 throw EntityUtil.EntitySqlError(createRefExpr.EntitySet.ErrCtx, Strings.ExprIsNotValidEntitySetForCreateRef);
1863             }
1864
1865             //
1866             // Ensure that the extent is an entity set
1867             //
1868             EntitySet entitySet = entitySetExpr.Target as EntitySet;
1869             if (entitySet == null)
1870             {
1871                 throw EntityUtil.EntitySqlError(createRefExpr.EntitySet.ErrCtx, Strings.ExprIsNotValidEntitySetForCreateRef);
1872             }
1873
1874             DbExpression keyRowExpression = ConvertValueExpression(createRefExpr.Keys, sr);
1875
1876             RowType inputKeyRowType = keyRowExpression.ResultType.EdmType as RowType;
1877             if (null == inputKeyRowType)
1878             {
1879                 throw EntityUtil.EntitySqlError(createRefExpr.Keys.ErrCtx, Strings.InvalidCreateRefKeyType);
1880             }
1881
1882             RowType entityKeyRowType = TypeHelpers.CreateKeyRowType(entitySet.ElementType);
1883
1884             if (entityKeyRowType.Members.Count != inputKeyRowType.Members.Count)
1885             {
1886                 throw EntityUtil.EntitySqlError(createRefExpr.Keys.ErrCtx, Strings.ImcompatibleCreateRefKeyType);
1887             }
1888
1889             if (!TypeSemantics.IsStructurallyEqualOrPromotableTo(keyRowExpression.ResultType, TypeUsage.Create(entityKeyRowType)))
1890             {
1891                 throw EntityUtil.EntitySqlError(createRefExpr.Keys.ErrCtx, Strings.ImcompatibleCreateRefKeyElementType);
1892             }
1893
1894             //
1895             // if CREATEREF specifies a type, resolve and validate the type
1896             //
1897             if (null != createRefExpr.TypeIdentifier)
1898             {
1899                 TypeUsage targetTypeUsage = ConvertTypeName(createRefExpr.TypeIdentifier, sr);
1900
1901                 //
1902                 // ensure type is entity
1903                 //
1904                 if (!TypeSemantics.IsEntityType(targetTypeUsage))
1905                 {
1906
1907                     throw EntityUtil.EntitySqlError(createRefExpr.TypeIdentifier.ErrCtx,
1908                         Strings.CreateRefTypeIdentifierMustSpecifyAnEntityType(
1909                                                                     targetTypeUsage.EdmType.FullName,
1910                                                                     targetTypeUsage.EdmType.BuiltInTypeKind.ToString()));
1911                 }
1912
1913                 if (!TypeSemantics.IsValidPolymorphicCast(entitySet.ElementType, targetTypeUsage.EdmType))
1914                 {
1915                     throw EntityUtil.EntitySqlError(createRefExpr.TypeIdentifier.ErrCtx,
1916                         Strings.CreateRefTypeIdentifierMustBeASubOrSuperType(
1917                                                                     entitySet.ElementType.FullName,
1918                                                                     targetTypeUsage.EdmType.FullName));
1919                 }
1920
1921                 converted = DbExpressionBuilder.RefFromKey(entitySet, keyRowExpression, (EntityType)targetTypeUsage.EdmType);
1922             }
1923             else
1924             {
1925                 //
1926                 // finally creates the expression
1927                 //
1928                 converted = DbExpressionBuilder.RefFromKey(entitySet, keyRowExpression);
1929             }
1930
1931             Debug.Assert(null != converted, "null != converted");
1932
1933             return new ValueExpression(converted);
1934         }
1935
1936         /// <summary>
1937         /// Converts KEY expression (AST.KeyExpr)
1938         /// </summary>
1939         private static ExpressionResolution ConvertKeyExpr(AST.Node astExpr, SemanticResolver sr)
1940         {
1941             AST.KeyExpr keyExpr = (AST.KeyExpr)astExpr;
1942
1943             DbExpression converted = ConvertValueExpression(keyExpr.ArgExpr, sr);
1944
1945             if (TypeSemantics.IsEntityType(converted.ResultType))
1946             {
1947                 converted = converted.GetEntityRef();
1948             }
1949             else if (!TypeSemantics.IsReferenceType(converted.ResultType))
1950             {
1951                 throw EntityUtil.EntitySqlError(keyExpr.ArgExpr.ErrCtx, Strings.InvalidKeyArgument(converted.ResultType.EdmType.FullName));
1952             }
1953
1954             converted = converted.GetRefKey();
1955             Debug.Assert(null != converted, "null != converted");
1956
1957             return new ValueExpression(converted);
1958         }
1959
1960         /// <summary>
1961         /// Converts a builtin expression (AST.BuiltInExpr).
1962         /// </summary>
1963         private static ExpressionResolution ConvertBuiltIn(AST.Node astExpr, SemanticResolver sr)
1964         {
1965             AST.BuiltInExpr bltInExpr = (AST.BuiltInExpr)astExpr;
1966
1967             BuiltInExprConverter builtInConverter = _builtInExprConverter[bltInExpr.Kind];
1968             if (builtInConverter == null)
1969             {
1970                 throw EntityUtil.EntitySqlError(Strings.UnknownBuiltInAstExpressionType);
1971             }
1972
1973             return new ValueExpression(builtInConverter(bltInExpr, sr));
1974         }
1975
1976         /// <summary>
1977         /// Converts Arithmetic Expressions Args
1978         /// </summary>
1979         /// <param name="astBuiltInExpr"></param>
1980         /// <param name="sr">SemanticResolver instance relative to a especif typespace/system</param>
1981         /// <returns></returns>
1982         private static Pair<DbExpression, DbExpression> ConvertArithmeticArgs(AST.BuiltInExpr astBuiltInExpr, SemanticResolver sr)
1983         {
1984             var operands = ConvertValueExpressionsWithUntypedNulls(
1985                 astBuiltInExpr.Arg1,
1986                 astBuiltInExpr.Arg2,
1987                 astBuiltInExpr.ErrCtx,
1988                 () => Strings.InvalidNullArithmetic,
1989                 sr);
1990
1991             if (!TypeSemantics.IsNumericType(operands.Left.ResultType))
1992             {
1993                 throw EntityUtil.EntitySqlError(astBuiltInExpr.Arg1.ErrCtx, Strings.ExpressionMustBeNumericType);
1994             }
1995
1996             if (operands.Right != null)
1997             {
1998                 if (!TypeSemantics.IsNumericType(operands.Right.ResultType))
1999                 {
2000                     throw EntityUtil.EntitySqlError(astBuiltInExpr.Arg2.ErrCtx, Strings.ExpressionMustBeNumericType);
2001                 }
2002
2003                 if (null == TypeHelpers.GetCommonTypeUsage(operands.Left.ResultType, operands.Right.ResultType))
2004                 {
2005                     throw EntityUtil.EntitySqlError(astBuiltInExpr.ErrCtx, Strings.ArgumentTypesAreIncompatible(
2006                         operands.Left.ResultType.EdmType.FullName, operands.Right.ResultType.EdmType.FullName));
2007                 }
2008             }
2009
2010             return operands;
2011         }
2012
2013         /// <summary>
2014         /// Converts Plus Args - specific case since string type is an allowed type for '+'
2015         /// </summary>
2016         /// <param name="astBuiltInExpr"></param>
2017         /// <param name="sr">SemanticResolver instance relative to a especif typespace/system</param>
2018         /// <returns></returns>
2019         private static Pair<DbExpression, DbExpression> ConvertPlusOperands(AST.BuiltInExpr astBuiltInExpr, SemanticResolver sr)
2020         {
2021             var operands = ConvertValueExpressionsWithUntypedNulls(
2022                 astBuiltInExpr.Arg1,
2023                 astBuiltInExpr.Arg2,
2024                 astBuiltInExpr.ErrCtx,
2025                 () => Strings.InvalidNullArithmetic,
2026                 sr);
2027
2028             if (!TypeSemantics.IsNumericType(operands.Left.ResultType) && !TypeSemantics.IsPrimitiveType(operands.Left.ResultType, PrimitiveTypeKind.String))
2029             {
2030                 throw EntityUtil.EntitySqlError(astBuiltInExpr.Arg1.ErrCtx, Strings.PlusLeftExpressionInvalidType);
2031             }
2032
2033             if (!TypeSemantics.IsNumericType(operands.Right.ResultType) && !TypeSemantics.IsPrimitiveType(operands.Right.ResultType, PrimitiveTypeKind.String))
2034             {
2035                 throw EntityUtil.EntitySqlError(astBuiltInExpr.Arg2.ErrCtx, Strings.PlusRightExpressionInvalidType);
2036             }
2037
2038             if (TypeHelpers.GetCommonTypeUsage(operands.Left.ResultType, operands.Right.ResultType) == null)
2039             {
2040                 throw EntityUtil.EntitySqlError(astBuiltInExpr.ErrCtx, Strings.ArgumentTypesAreIncompatible(
2041                     operands.Left.ResultType.EdmType.FullName, operands.Right.ResultType.EdmType.FullName));
2042             }
2043
2044             return operands;
2045         }
2046
2047         /// <summary>
2048         /// Converts Logical Expression Args
2049         /// </summary>
2050         /// <param name="astBuiltInExpr"></param>
2051         /// <param name="sr">SemanticResolver instance relative to a especif typespace/system</param>
2052         /// <returns></returns>
2053         private static Pair<DbExpression, DbExpression> ConvertLogicalArgs(AST.BuiltInExpr astBuiltInExpr, SemanticResolver sr)
2054         {
2055             DbExpression leftExpr = ConvertValueExpressionAllowUntypedNulls(astBuiltInExpr.Arg1, sr);
2056             if (leftExpr == null)
2057             {
2058                 leftExpr = DbExpressionBuilder.Null(sr.TypeResolver.BooleanType);
2059             }
2060
2061             DbExpression rightExpr = null;
2062             if (astBuiltInExpr.Arg2 != null)
2063             {
2064                 rightExpr = ConvertValueExpressionAllowUntypedNulls(astBuiltInExpr.Arg2, sr);
2065                 if (rightExpr == null)
2066                 {
2067                     rightExpr = DbExpressionBuilder.Null(sr.TypeResolver.BooleanType);
2068                 }
2069             }
2070
2071             //
2072             // ensure left expression type is boolean
2073             //
2074             if (!IsBooleanType(leftExpr.ResultType))
2075             {
2076                 throw EntityUtil.EntitySqlError(astBuiltInExpr.Arg1.ErrCtx, Strings.ExpressionTypeMustBeBoolean);
2077             }
2078
2079             //
2080             // ensure right expression type is boolean
2081             //
2082             if (null != rightExpr && !IsBooleanType(rightExpr.ResultType))
2083             {
2084                 throw EntityUtil.EntitySqlError(astBuiltInExpr.Arg2.ErrCtx, Strings.ExpressionTypeMustBeBoolean);
2085             }
2086
2087             return new Pair<DbExpression, DbExpression>(leftExpr, rightExpr);
2088         }
2089
2090         /// <summary>
2091         /// Converts Equal Comparison Expression Args
2092         /// </summary>
2093         /// <param name="astBuiltInExpr"></param>
2094         /// <param name="sr">SemanticResolver instance relative to a especif typespace/system</param>
2095         /// <returns></returns>
2096         private static Pair<DbExpression, DbExpression> ConvertEqualCompArgs(AST.BuiltInExpr astBuiltInExpr, SemanticResolver sr)
2097         {
2098             //
2099             // convert left and right types and infer null types
2100             //
2101             Pair<DbExpression, DbExpression> compArgs = ConvertValueExpressionsWithUntypedNulls(
2102                 astBuiltInExpr.Arg1,
2103                 astBuiltInExpr.Arg2,
2104                 astBuiltInExpr.ErrCtx,
2105                 () => Strings.InvalidNullComparison,
2106                 sr);
2107
2108             //
2109             // ensure both operand types are equal-comparable
2110             //
2111             if (!TypeSemantics.IsEqualComparableTo(compArgs.Left.ResultType, compArgs.Right.ResultType))
2112             {
2113                 throw EntityUtil.EntitySqlError(astBuiltInExpr.ErrCtx, Strings.ArgumentTypesAreIncompatible(
2114                     compArgs.Left.ResultType.EdmType.FullName, compArgs.Right.ResultType.EdmType.FullName));
2115             }
2116
2117             return compArgs;
2118         }
2119
2120         /// <summary>
2121         /// Converts Order Comparison Expression Args
2122         /// </summary>
2123         /// <param name="astBuiltInExpr"></param>
2124         /// <param name="sr">SemanticResolver instance relative to a especif typespace/system</param>
2125         /// <returns></returns>
2126         private static Pair<DbExpression, DbExpression> ConvertOrderCompArgs(AST.BuiltInExpr astBuiltInExpr, SemanticResolver sr)
2127         {
2128             Pair<DbExpression, DbExpression> compArgs = ConvertValueExpressionsWithUntypedNulls(
2129                 astBuiltInExpr.Arg1,
2130                 astBuiltInExpr.Arg2,
2131                 astBuiltInExpr.ErrCtx,
2132                 () => Strings.InvalidNullComparison,
2133                 sr);
2134
2135             //
2136             // ensure both operand types are order-comparable
2137             //
2138             if (!TypeSemantics.IsOrderComparableTo(compArgs.Left.ResultType, compArgs.Right.ResultType))
2139             {
2140                 throw EntityUtil.EntitySqlError(astBuiltInExpr.ErrCtx, Strings.ArgumentTypesAreIncompatible(
2141                     compArgs.Left.ResultType.EdmType.FullName, compArgs.Right.ResultType.EdmType.FullName));
2142             }
2143
2144             return compArgs;
2145         }
2146
2147         /// <summary>
2148         /// Converts Set Expression Args
2149         /// </summary>
2150         /// <param name="astBuiltInExpr"></param>
2151         /// <param name="sr">SemanticResolver instance relative to a especif typespace/system</param>
2152         /// <returns></returns>
2153         private static Pair<DbExpression, DbExpression> ConvertSetArgs(AST.BuiltInExpr astBuiltInExpr, SemanticResolver sr)
2154         {
2155             //
2156             // convert left expression
2157             //
2158             DbExpression leftExpr = ConvertValueExpression(astBuiltInExpr.Arg1, sr);
2159
2160             //
2161             // convert right expression if binary set op kind
2162             //
2163             DbExpression rightExpr = null;
2164             if (null != astBuiltInExpr.Arg2)
2165             {
2166                 //
2167                 // binary set op
2168                 //
2169
2170                 //
2171                 // make sure left expression type is of sequence type (ICollection or Extent)
2172                 //
2173                 if (!TypeSemantics.IsCollectionType(leftExpr.ResultType))
2174                 {
2175                     throw EntityUtil.EntitySqlError(astBuiltInExpr.Arg1.ErrCtx, Strings.LeftSetExpressionArgsMustBeCollection);
2176                 }
2177
2178                 //
2179                 // convert right expression
2180                 //
2181                 rightExpr = ConvertValueExpression(astBuiltInExpr.Arg2, sr);
2182
2183                 //
2184                 // make sure right expression type is of sequence type (ICollection or Extent)
2185                 //
2186                 if (!TypeSemantics.IsCollectionType(rightExpr.ResultType))
2187                 {
2188                     throw EntityUtil.EntitySqlError(astBuiltInExpr.Arg2.ErrCtx, Strings.RightSetExpressionArgsMustBeCollection);
2189                 }
2190
2191                 TypeUsage commonType;
2192                 TypeUsage leftElemType = TypeHelpers.GetElementTypeUsage(leftExpr.ResultType);
2193                 TypeUsage rightElemType = TypeHelpers.GetElementTypeUsage(rightExpr.ResultType);
2194                 if (!TypeSemantics.TryGetCommonType(leftElemType, rightElemType, out commonType))
2195                 {
2196                     CqlErrorHelper.ReportIncompatibleCommonType(astBuiltInExpr.ErrCtx, leftElemType, rightElemType);
2197                 }
2198
2199                 if (astBuiltInExpr.Kind != AST.BuiltInKind.UnionAll)
2200                 {
2201                     //
2202                     // ensure left argument is set op comparable
2203                     //
2204                     if (!TypeHelpers.IsSetComparableOpType(TypeHelpers.GetElementTypeUsage(leftExpr.ResultType)))
2205                     {
2206                         throw EntityUtil.EntitySqlError(astBuiltInExpr.Arg1.ErrCtx,
2207                             Strings.PlaceholderSetArgTypeIsNotEqualComparable(
2208                                                            Strings.LocalizedLeft,
2209                                                            astBuiltInExpr.Kind.ToString().ToUpperInvariant(),
2210                                                            TypeHelpers.GetElementTypeUsage(leftExpr.ResultType).EdmType.FullName));
2211                     }
2212
2213                     //
2214                     // ensure right argument is set op comparable
2215                     //
2216                     if (!TypeHelpers.IsSetComparableOpType(TypeHelpers.GetElementTypeUsage(rightExpr.ResultType)))
2217                     {
2218                         throw EntityUtil.EntitySqlError(astBuiltInExpr.Arg2.ErrCtx,
2219                             Strings.PlaceholderSetArgTypeIsNotEqualComparable(
2220                                                            Strings.LocalizedRight,
2221                                                            astBuiltInExpr.Kind.ToString().ToUpperInvariant(),
2222                                                            TypeHelpers.GetElementTypeUsage(rightExpr.ResultType).EdmType.FullName));
2223                     }
2224                 }
2225                 else
2226                 {
2227                     if (Helper.IsAssociationType(leftElemType.EdmType))
2228                     {
2229                         throw EntityUtil.EntitySqlError(astBuiltInExpr.Arg1.ErrCtx, Strings.InvalidAssociationTypeForUnion(leftElemType.EdmType.FullName));
2230                     }
2231
2232                     if (Helper.IsAssociationType(rightElemType.EdmType))
2233                     {
2234                         throw EntityUtil.EntitySqlError(astBuiltInExpr.Arg2.ErrCtx, Strings.InvalidAssociationTypeForUnion(rightElemType.EdmType.FullName));
2235                     }
2236                 }
2237             }
2238             else
2239             {
2240                 //
2241                 // unary set op
2242                 //
2243
2244                 //
2245                 // make sure expression type is of sequence type (ICollection or Extent)
2246                 //
2247                 if (!TypeSemantics.IsCollectionType(leftExpr.ResultType))
2248                 {
2249                     throw EntityUtil.EntitySqlError(astBuiltInExpr.Arg1.ErrCtx, Strings.InvalidUnarySetOpArgument(astBuiltInExpr.Name));
2250                 }
2251
2252                 //
2253                 // make sure that if is distinct unary operator, arg element type must be equal-comparable
2254                 //
2255                 if (astBuiltInExpr.Kind == AST.BuiltInKind.Distinct && !TypeHelpers.IsValidDistinctOpType(TypeHelpers.GetElementTypeUsage(leftExpr.ResultType)))
2256                 {
2257                     throw EntityUtil.EntitySqlError(astBuiltInExpr.Arg1.ErrCtx, Strings.ExpressionTypeMustBeEqualComparable);
2258                 }
2259             }
2260
2261             return new Pair<DbExpression, DbExpression>(leftExpr, rightExpr);
2262         }
2263
2264
2265         /// <summary>
2266         /// Converts Set 'IN' expression args
2267         /// </summary>
2268         /// <param name="astBuiltInExpr"></param>
2269         /// <param name="sr">SemanticResolver instance relative to a especif typespace/system</param>
2270         /// <returns></returns>
2271         private static Pair<DbExpression, DbExpression> ConvertInExprArgs(AST.BuiltInExpr astBuiltInExpr, SemanticResolver sr)
2272         {
2273             DbExpression rightExpr = ConvertValueExpression(astBuiltInExpr.Arg2, sr);
2274             if (!TypeSemantics.IsCollectionType(rightExpr.ResultType))
2275             {
2276                 throw EntityUtil.EntitySqlError(astBuiltInExpr.Arg2.ErrCtx, Strings.RightSetExpressionArgsMustBeCollection);
2277             }
2278
2279             DbExpression leftExpr = ConvertValueExpressionAllowUntypedNulls(astBuiltInExpr.Arg1, sr);
2280             if (leftExpr == null)
2281             {
2282                 //
2283                 // If left expression type is null, infer its type from the collection element type.
2284                 //
2285                 TypeUsage elementType = TypeHelpers.GetElementTypeUsage(rightExpr.ResultType);
2286                 ValidateTypeForNullExpression(elementType, astBuiltInExpr.Arg1.ErrCtx);
2287                 leftExpr = DbExpressionBuilder.Null(elementType);
2288             }
2289
2290             if (TypeSemantics.IsCollectionType(leftExpr.ResultType))
2291             {
2292                 throw EntityUtil.EntitySqlError(astBuiltInExpr.Arg1.ErrCtx, Strings.ExpressionTypeMustNotBeCollection);
2293             }
2294
2295             //
2296             // Ensure that if left and right are typed expressions then their types must be comparable for IN op.
2297             //
2298             TypeUsage commonElemType = TypeHelpers.GetCommonTypeUsage(leftExpr.ResultType, TypeHelpers.GetElementTypeUsage(rightExpr.ResultType));
2299             if (null == commonElemType || !TypeHelpers.IsValidInOpType(commonElemType))
2300             {
2301                 throw EntityUtil.EntitySqlError(astBuiltInExpr.ErrCtx, Strings.InvalidInExprArgs(leftExpr.ResultType.EdmType.FullName, rightExpr.ResultType.EdmType.FullName));
2302             }
2303
2304             return new Pair<DbExpression, DbExpression>(leftExpr, rightExpr);
2305         }
2306
2307         private static void ValidateTypeForNullExpression(TypeUsage type, ErrorContext errCtx)
2308         {
2309             if (TypeSemantics.IsCollectionType(type))
2310             {
2311                 throw EntityUtil.EntitySqlError(errCtx, Strings.NullLiteralCannotBePromotedToCollectionOfNulls);
2312             }
2313         }
2314
2315         /// <summary>
2316         /// Converts a type name.
2317         /// Type name can be represented by
2318         ///     - AST.Identifier, such as "Product"
2319         ///     - AST.DotExpr, such as "Northwind.Product"
2320         ///     - AST.MethodExpr, such as "Edm.Decimal(10,4)", where "10" and "4" are type arguments.
2321         /// </summary>
2322         private static TypeUsage ConvertTypeName(AST.Node typeName, SemanticResolver sr)
2323         {
2324             Debug.Assert(typeName != null, "typeName != null");
2325
2326             string[] name = null;
2327             AST.NodeList<AST.Node> typeSpecArgs = null;
2328
2329             //
2330             // Process AST.MethodExpr - reduce it to an identifier with type spec arguments
2331             //
2332             AST.MethodExpr methodExpr = typeName as AST.MethodExpr;
2333             if (methodExpr != null)
2334             {
2335                 typeName = methodExpr.Expr;
2336                 typeName.ErrCtx.ErrorContextInfo = methodExpr.ErrCtx.ErrorContextInfo;
2337                 typeName.ErrCtx.UseContextInfoAsResourceIdentifier = methodExpr.ErrCtx.UseContextInfoAsResourceIdentifier;
2338
2339                 typeSpecArgs = methodExpr.Args;
2340             }
2341
2342             //
2343             // Try as AST.Identifier
2344             //
2345             AST.Identifier identifier = typeName as AST.Identifier;
2346             if (identifier != null)
2347             {
2348                 name = new string[] { identifier.Name };
2349             }
2350
2351             //
2352             // Try as AST.DotExpr
2353             //
2354             AST.DotExpr dotExpr = typeName as AST.DotExpr;
2355             if (dotExpr != null && dotExpr.IsMultipartIdentifier(out name))
2356             {
2357                 Debug.Assert(name != null, "name != null for a multipart identifier");
2358             }
2359
2360             if (name == null)
2361             {
2362                 Debug.Fail("Unexpected AST.Node in the type name");
2363                 throw EntityUtil.EntitySqlError(typeName.ErrCtx, Strings.InvalidMetadataMemberName);
2364             }
2365
2366             MetadataMember metadataMember = sr.ResolveMetadataMemberName(name, typeName.ErrCtx);
2367             Debug.Assert(metadataMember != null, "metadata member name resolution must not return null");
2368
2369             switch (metadataMember.MetadataMemberClass)
2370             {
2371                 case MetadataMemberClass.Type:
2372                     {
2373                         TypeUsage typeUsage = ((MetadataType)metadataMember).TypeUsage;
2374
2375                         if (typeSpecArgs != null)
2376                         {
2377                             typeUsage = ConvertTypeSpecArgs(typeUsage, typeSpecArgs, typeName.ErrCtx, sr);
2378                         }
2379
2380                         return typeUsage;
2381                     }
2382
2383                 case MetadataMemberClass.Namespace:
2384                     throw EntityUtil.EntitySqlError(typeName.ErrCtx, Strings.TypeNameNotFound(metadataMember.Name));
2385
2386                 default:
2387                     throw EntityUtil.EntitySqlError(typeName.ErrCtx, Strings.InvalidMetadataMemberClassResolution(
2388                         metadataMember.Name, metadataMember.MetadataMemberClassName, MetadataType.TypeClassName));
2389             }
2390         }
2391
2392         private static TypeUsage ConvertTypeSpecArgs(TypeUsage parameterizedType, AST.NodeList<AST.Node> typeSpecArgs, ErrorContext errCtx, SemanticResolver sr)
2393         {
2394             Debug.Assert(typeSpecArgs != null && typeSpecArgs.Count > 0, "typeSpecArgs must be null or a non-empty list");
2395
2396             //
2397             // Type arguments must be literals.
2398             //
2399             foreach (AST.Node arg in typeSpecArgs)
2400             {
2401                 if (!(arg is AST.Literal))
2402                 {
2403                     throw EntityUtil.EntitySqlError(arg.ErrCtx, Strings.TypeArgumentMustBeLiteral);
2404                 }
2405             }
2406
2407             //
2408             // The only parameterized type supported is Edm.Decimal
2409             //
2410             PrimitiveType primitiveType = parameterizedType.EdmType as PrimitiveType;
2411             if (primitiveType == null || primitiveType.PrimitiveTypeKind != PrimitiveTypeKind.Decimal)
2412             {
2413                 throw EntityUtil.EntitySqlError(errCtx, Strings.TypeDoesNotSupportSpec(primitiveType.FullName));
2414             }
2415
2416             //
2417             // Edm.Decimal has two optional parameters: precision and scale.
2418             //
2419             if (typeSpecArgs.Count > 2)
2420             {
2421                 throw EntityUtil.EntitySqlError(errCtx, Strings.TypeArgumentCountMismatch(primitiveType.FullName, 2));
2422             }
2423
2424             //
2425             // Get precision value for Edm.Decimal
2426             //
2427             byte precision;
2428             ConvertTypeFacetValue(primitiveType, (AST.Literal)typeSpecArgs[0], DbProviderManifest.PrecisionFacetName, out precision);
2429
2430             //
2431             // Get scale value for Edm.Decimal
2432             //
2433             byte scale = 0;
2434             if (typeSpecArgs.Count == 2)
2435             {
2436                 ConvertTypeFacetValue(primitiveType, (AST.Literal)typeSpecArgs[1], DbProviderManifest.ScaleFacetName, out scale);
2437             }
2438
2439             //
2440             // Ensure P >= S
2441             //
2442             if (precision < scale)
2443             {
2444                 throw EntityUtil.EntitySqlError(typeSpecArgs[0].ErrCtx, Strings.PrecisionMustBeGreaterThanScale(precision, scale));
2445             }
2446
2447             return TypeUsage.CreateDecimalTypeUsage(primitiveType, precision, scale);
2448         }
2449
2450         private static void ConvertTypeFacetValue(PrimitiveType type, AST.Literal value, string facetName, out byte byteValue)
2451         {
2452             FacetDescription facetDescription = Helper.GetFacet(type.ProviderManifest.GetFacetDescriptions(type), facetName);
2453             if (facetDescription == null)
2454             {
2455                 throw EntityUtil.EntitySqlError(value.ErrCtx, Strings.TypeDoesNotSupportFacet(type.FullName, facetName));
2456             }
2457
2458             if (value.IsNumber && Byte.TryParse(value.OriginalValue, out byteValue))
2459             {
2460                 if (facetDescription.MaxValue.HasValue && byteValue > facetDescription.MaxValue.Value)
2461                 {
2462                     throw EntityUtil.EntitySqlError(value.ErrCtx, Strings.TypeArgumentExceedsMax(facetName));
2463                 }
2464
2465                 if (facetDescription.MinValue.HasValue && byteValue < facetDescription.MinValue.Value)
2466                 {
2467                     throw EntityUtil.EntitySqlError(value.ErrCtx, Strings.TypeArgumentBelowMin(facetName));
2468                 }
2469             }
2470             else
2471             {
2472                 throw EntityUtil.EntitySqlError(value.ErrCtx, Strings.TypeArgumentIsNotValid);
2473             }
2474         }
2475
2476         private static TypeUsage ConvertTypeDefinition(AST.Node typeDefinitionExpr, SemanticResolver sr)
2477         {
2478             Debug.Assert(typeDefinitionExpr != null, "typeDefinitionExpr != null");
2479
2480             TypeUsage converted = null;
2481
2482             AST.CollectionTypeDefinition collTypeDefExpr = typeDefinitionExpr as AST.CollectionTypeDefinition;
2483             AST.RefTypeDefinition refTypeDefExpr = typeDefinitionExpr as AST.RefTypeDefinition;
2484             AST.RowTypeDefinition rowTypeDefExpr = typeDefinitionExpr as AST.RowTypeDefinition;
2485
2486             if (collTypeDefExpr != null)
2487             {
2488                 TypeUsage elementType = ConvertTypeDefinition(collTypeDefExpr.ElementTypeDef, sr);
2489                 converted = TypeHelpers.CreateCollectionTypeUsage(elementType, true /* readOnly */);
2490             }
2491             else if (refTypeDefExpr != null)
2492             {
2493                 TypeUsage targetTypeUsage = ConvertTypeName(refTypeDefExpr.RefTypeIdentifier, sr);
2494
2495                 //
2496                 // Ensure type is entity
2497                 //
2498                 if (!TypeSemantics.IsEntityType(targetTypeUsage))
2499                 {
2500
2501                     throw EntityUtil.EntitySqlError(refTypeDefExpr.RefTypeIdentifier.ErrCtx,
2502                         Strings.RefTypeIdentifierMustSpecifyAnEntityType(
2503                                                     targetTypeUsage.EdmType.FullName,
2504                                                     targetTypeUsage.EdmType.BuiltInTypeKind.ToString()));
2505                 }
2506
2507                 converted = TypeHelpers.CreateReferenceTypeUsage((EntityType)targetTypeUsage.EdmType);
2508             }
2509             else if (rowTypeDefExpr != null)
2510             {
2511                 Debug.Assert(rowTypeDefExpr.Properties != null && rowTypeDefExpr.Properties.Count > 0, "rowTypeDefExpr.Properties must be a non-empty collection");
2512
2513                 converted = TypeHelpers.CreateRowTypeUsage(
2514                     rowTypeDefExpr.Properties.Select(p => new KeyValuePair<string, TypeUsage>(p.Name.Name, ConvertTypeDefinition(p.Type, sr))),
2515                     true /* readOnly */);
2516             }
2517             else
2518             {
2519                 converted = ConvertTypeName(typeDefinitionExpr, sr);
2520             }
2521
2522             Debug.Assert(converted != null, "Type definition conversion yielded null");
2523
2524             return converted;
2525         }
2526
2527         /// <summary>
2528         /// Converts row constructor expression (AST.RowConstructorExpr)
2529         /// </summary>
2530         private static ExpressionResolution ConvertRowConstructor(AST.Node expr, SemanticResolver sr)
2531         {
2532             AST.RowConstructorExpr rowExpr = (AST.RowConstructorExpr)expr;
2533
2534             Dictionary<string, TypeUsage> rowColumns = new Dictionary<string, TypeUsage>(sr.NameComparer);
2535             List<DbExpression> fieldExprs = new List<DbExpression>(rowExpr.AliasedExprList.Count);
2536
2537             for (int i = 0; i < rowExpr.AliasedExprList.Count; i++)
2538             {
2539                 AST.AliasedExpr aliasExpr = rowExpr.AliasedExprList[i];
2540
2541                 DbExpression colExpr = ConvertValueExpressionAllowUntypedNulls(aliasExpr.Expr, sr);
2542                 if (colExpr == null)
2543                 {
2544                     throw EntityUtil.EntitySqlError(aliasExpr.Expr.ErrCtx, Strings.RowCtorElementCannotBeNull);
2545                 }
2546
2547                 string aliasName = sr.InferAliasName(aliasExpr, colExpr);
2548
2549                 if (rowColumns.ContainsKey(aliasName))
2550                 {
2551                     if (aliasExpr.Alias != null)
2552                     {
2553                         CqlErrorHelper.ReportAliasAlreadyUsedError(aliasName, aliasExpr.Alias.ErrCtx, Strings.InRowCtor);
2554                     }
2555                     else
2556                     {
2557                         aliasName = sr.GenerateInternalName("autoRowCol");
2558                     }
2559                 }
2560
2561                 rowColumns.Add(aliasName, colExpr.ResultType);
2562
2563                 fieldExprs.Add(colExpr);
2564             }
2565
2566             return new ValueExpression(DbExpressionBuilder.New(TypeHelpers.CreateRowTypeUsage(rowColumns, true /* readOnly */), fieldExprs));
2567         }
2568
2569         /// <summary>
2570         /// Converts multiset constructor expression (AST.MultisetConstructorExpr)
2571         /// </summary>
2572         private static ExpressionResolution ConvertMultisetConstructor(AST.Node expr, SemanticResolver sr)
2573         {
2574             AST.MultisetConstructorExpr msetCtor = (AST.MultisetConstructorExpr)expr;
2575
2576             if (null == msetCtor.ExprList)
2577             {
2578                 throw EntityUtil.EntitySqlError(expr.ErrCtx, Strings.CannotCreateEmptyMultiset);
2579             }
2580
2581             var mSetExprs = msetCtor.ExprList.Select(e => ConvertValueExpressionAllowUntypedNulls(e, sr)).ToArray();
2582
2583             var multisetTypes = mSetExprs.Where(e => e != null).Select(e => e.ResultType).ToArray();
2584
2585             //
2586             // Ensure common type is not an untyped null.
2587             //
2588             if (multisetTypes.Length == 0)
2589             {
2590                 throw EntityUtil.EntitySqlError(expr.ErrCtx, Strings.CannotCreateMultisetofNulls);
2591             }
2592
2593             TypeUsage commonType = TypeHelpers.GetCommonTypeUsage(multisetTypes);
2594             
2595             //
2596             // Ensure all elems have a common type.
2597             //
2598             if (commonType == null)
2599             {
2600                 throw EntityUtil.EntitySqlError(expr.ErrCtx, Strings.MultisetElemsAreNotTypeCompatible);
2601             }
2602
2603             commonType = TypeHelpers.GetReadOnlyType(commonType);
2604
2605             //
2606             // Fixup untyped nulls.
2607             //
2608             for (int i = 0; i < mSetExprs.Length; i++)
2609             {
2610                 if (mSetExprs[i] == null)
2611                 {
2612                     ValidateTypeForNullExpression(commonType, msetCtor.ExprList[i].ErrCtx);
2613                     mSetExprs[i] = DbExpressionBuilder.Null(commonType);
2614                 }
2615             }
2616
2617             return new ValueExpression(DbExpressionBuilder.New(TypeHelpers.CreateCollectionTypeUsage(commonType, true /* readOnly */), mSetExprs));
2618         }
2619
2620         /// <summary>
2621         /// Converts case-when-then expression (AST.CaseExpr)
2622         /// </summary>
2623         private static ExpressionResolution ConvertCaseExpr(AST.Node expr, SemanticResolver sr)
2624         {
2625             AST.CaseExpr caseExpr = (AST.CaseExpr)expr;
2626
2627             List<DbExpression> whenExprList = new List<DbExpression>(caseExpr.WhenThenExprList.Count);
2628             List<DbExpression> thenExprList = new List<DbExpression>(caseExpr.WhenThenExprList.Count);
2629
2630             //
2631             // Convert when/then expressions.
2632             //
2633             for (int i = 0; i < caseExpr.WhenThenExprList.Count; i++)
2634             {
2635                 AST.WhenThenExpr whenThenExpr = caseExpr.WhenThenExprList[i];
2636
2637                 DbExpression whenExpression = ConvertValueExpression(whenThenExpr.WhenExpr, sr);
2638
2639                 if (!IsBooleanType(whenExpression.ResultType))
2640                 {
2641                     throw EntityUtil.EntitySqlError(whenThenExpr.WhenExpr.ErrCtx, Strings.ExpressionTypeMustBeBoolean);
2642                 }
2643
2644                 whenExprList.Add(whenExpression);
2645
2646                 DbExpression thenExpression = ConvertValueExpressionAllowUntypedNulls(whenThenExpr.ThenExpr, sr);
2647
2648                 thenExprList.Add(thenExpression);
2649             }
2650
2651             //
2652             // Convert else if present.
2653             //
2654             DbExpression elseExpr = caseExpr.ElseExpr != null ? ConvertValueExpressionAllowUntypedNulls(caseExpr.ElseExpr, sr) : null;
2655
2656             //
2657             // Collect result types from THENs and the ELSE.
2658             //
2659             var resultTypes = thenExprList.Where(e => e != null).Select(e => e.ResultType).ToList();
2660             if (elseExpr != null)
2661             {
2662                 resultTypes.Add(elseExpr.ResultType);
2663             }
2664             if (resultTypes.Count == 0)
2665             {
2666                 throw EntityUtil.EntitySqlError(caseExpr.ElseExpr.ErrCtx, Strings.InvalidCaseWhenThenNullType);
2667             }
2668
2669             //
2670             // Derive common return type.
2671             //
2672             TypeUsage resultType = TypeHelpers.GetCommonTypeUsage(resultTypes);
2673             if (resultType == null)
2674             {
2675                 throw EntityUtil.EntitySqlError(caseExpr.WhenThenExprList[0].ThenExpr.ErrCtx, Strings.InvalidCaseResultTypes);
2676             }
2677
2678             //
2679             // Fixup untyped nulls
2680             //
2681             for (int i = 0; i < thenExprList.Count; i++)
2682             {
2683                 if (thenExprList[i] == null)
2684                 {
2685                     ValidateTypeForNullExpression(resultType, caseExpr.WhenThenExprList[i].ThenExpr.ErrCtx);
2686                     thenExprList[i] = DbExpressionBuilder.Null(resultType);
2687                 }
2688             }
2689             if (elseExpr == null)
2690             {
2691                 if (caseExpr.ElseExpr == null && TypeSemantics.IsCollectionType(resultType))
2692                 {
2693                     //
2694                     // If ELSE was omitted and common return type is a collection,
2695                     // then use empty collection for elseExpr.
2696                     //
2697                     elseExpr = DbExpressionBuilder.NewEmptyCollection(resultType);
2698                 }
2699                 else
2700                 {
2701                     ValidateTypeForNullExpression(resultType, (caseExpr.ElseExpr ?? caseExpr).ErrCtx);
2702                     elseExpr = DbExpressionBuilder.Null(resultType);
2703                 }
2704             }
2705
2706             return new ValueExpression(DbExpressionBuilder.Case(whenExprList, thenExprList, elseExpr));
2707         }
2708
2709         /// <summary>
2710         /// Converts query expression (AST.QueryExpr)
2711         /// </summary>
2712         private static ExpressionResolution ConvertQueryExpr(AST.Node expr, SemanticResolver sr)
2713         {
2714             AST.QueryExpr queryExpr = (AST.QueryExpr)expr;
2715
2716             DbExpression converted = null;
2717
2718             bool isRestrictedViewGenerationMode = (ParserOptions.CompilationMode.RestrictedViewGenerationMode == sr.ParserOptions.ParserCompilationMode);
2719
2720             //
2721             // Validate & Compensate Query
2722             //
2723             if (null != queryExpr.HavingClause && null == queryExpr.GroupByClause)
2724             {
2725                 throw EntityUtil.EntitySqlError(queryExpr.ErrCtx, Strings.HavingRequiresGroupClause);
2726             }
2727             if (queryExpr.SelectClause.TopExpr != null)
2728             {
2729                 if (queryExpr.OrderByClause != null && queryExpr.OrderByClause.LimitSubClause != null)
2730                 {
2731                     throw EntityUtil.EntitySqlError(queryExpr.SelectClause.TopExpr.ErrCtx, Strings.TopAndLimitCannotCoexist);
2732                 }
2733
2734                 if (queryExpr.OrderByClause != null && queryExpr.OrderByClause.SkipSubClause != null)
2735                 {
2736                     throw EntityUtil.EntitySqlError(queryExpr.SelectClause.TopExpr.ErrCtx, Strings.TopAndSkipCannotCoexist);
2737                 }
2738             }
2739
2740             //
2741             // Create Source Scope Region
2742             //
2743             using (sr.EnterScopeRegion())
2744             {
2745                 //
2746                 // Process From Clause
2747                 //
2748                 DbExpressionBinding sourceExpr = ProcessFromClause(queryExpr.FromClause, sr);
2749
2750                 //
2751                 // Process Where Clause
2752                 //
2753                 sourceExpr = ProcessWhereClause(sourceExpr, queryExpr.WhereClause, sr);
2754
2755                 Debug.Assert(isRestrictedViewGenerationMode ? null == queryExpr.GroupByClause : true, "GROUP BY clause must be null in RestrictedViewGenerationMode");
2756                 Debug.Assert(isRestrictedViewGenerationMode ? null == queryExpr.HavingClause : true, "HAVING clause must be null in RestrictedViewGenerationMode");
2757                 Debug.Assert(isRestrictedViewGenerationMode ? null == queryExpr.OrderByClause : true, "ORDER BY clause must be null in RestrictedViewGenerationMode");
2758
2759                 bool queryProjectionProcessed = false;
2760                 if (!isRestrictedViewGenerationMode)
2761                 {
2762                     //
2763                     // Process GroupBy Clause
2764                     //
2765                     sourceExpr = ProcessGroupByClause(sourceExpr, queryExpr, sr);
2766
2767                     //
2768                     // Process Having Clause
2769                     //
2770                     sourceExpr = ProcessHavingClause(sourceExpr, queryExpr.HavingClause, sr);
2771
2772                     //
2773                     // Process OrderBy Clause
2774                     //
2775                     sourceExpr = ProcessOrderByClause(sourceExpr, queryExpr, out queryProjectionProcessed, sr);
2776                 }
2777
2778                 //
2779                 // Process Projection Clause
2780                 //
2781                 converted = ProcessSelectClause(sourceExpr, queryExpr, queryProjectionProcessed, sr);
2782
2783             } // end query scope region
2784
2785             return new ValueExpression(converted);
2786         }
2787
2788         /// <summary>
2789         /// Process Select Clause
2790         /// </summary>
2791         private static DbExpression ProcessSelectClause(DbExpressionBinding source, AST.QueryExpr queryExpr, bool queryProjectionProcessed, SemanticResolver sr)
2792         {
2793             AST.SelectClause selectClause = queryExpr.SelectClause;
2794
2795             DbExpression projectExpression;
2796             if (queryProjectionProcessed)
2797             {
2798                 projectExpression = source.Expression;
2799             }
2800             else
2801             {
2802                 //
2803                 // Convert projection items.
2804                 //
2805                 var projectionItems = ConvertSelectClauseItems(queryExpr, sr);
2806
2807                 //
2808                 // Create project expression off the projectionItems.
2809                 //
2810                 projectExpression = CreateProjectExpression(source, selectClause, projectionItems);
2811             }
2812
2813             //
2814             // Handle TOP/LIMIT sub-clauses.
2815             //
2816             if (selectClause.TopExpr != null || (queryExpr.OrderByClause != null && queryExpr.OrderByClause.LimitSubClause != null))
2817             {
2818                 AST.Node limitExpr;
2819                 string exprName;
2820                 if (selectClause.TopExpr != null)
2821                 {
2822                     Debug.Assert(queryExpr.OrderByClause == null || queryExpr.OrderByClause.LimitSubClause == null, "TOP and LIMIT in the same query are not allowed");
2823                     limitExpr = selectClause.TopExpr;
2824                     exprName = "TOP";
2825                 }
2826                 else
2827                 {
2828                     limitExpr = queryExpr.OrderByClause.LimitSubClause;
2829                     exprName = "LIMIT";
2830                 }
2831
2832                 //
2833                 // Convert the expression.
2834                 //
2835                 DbExpression convertedLimit = ConvertValueExpression(limitExpr, sr);
2836
2837                 //
2838                 // Ensure the converted expression is in the range of values.
2839                 //
2840                 ValidateExpressionIsCommandParamOrNonNegativeIntegerConstant(convertedLimit, limitExpr.ErrCtx, exprName, sr);
2841
2842                 //
2843                 // Create the project expression with the limit.
2844                 //
2845                 projectExpression = projectExpression.Limit(convertedLimit);
2846             }
2847
2848             Debug.Assert(null != projectExpression, "null != projectExpression");
2849             return projectExpression;
2850         }
2851
2852         private static List<KeyValuePair<string, DbExpression>> ConvertSelectClauseItems(AST.QueryExpr queryExpr, SemanticResolver sr)
2853         {
2854             AST.SelectClause selectClause = queryExpr.SelectClause;
2855
2856             //
2857             // Validate SELECT VALUE projection list.
2858             // 
2859             if (selectClause.SelectKind == AST.SelectKind.Value)
2860             {
2861                 if (selectClause.Items.Count != 1)
2862                 {
2863                     throw EntityUtil.EntitySqlError(selectClause.ErrCtx, Strings.InvalidSelectValueList);
2864                 }
2865
2866                 //
2867                 // Aliasing is not allowed in the SELECT VALUE case, except when the ORDER BY clause is present.
2868                 //
2869                 if (selectClause.Items[0].Alias != null && queryExpr.OrderByClause == null)
2870                 {
2871                     throw EntityUtil.EntitySqlError(selectClause.Items[0].ErrCtx, Strings.InvalidSelectValueAliasedExpression);
2872                 }
2873             }
2874
2875             //
2876             // Converts projection list
2877             //
2878             HashSet<string> projectionAliases = new HashSet<string>(sr.NameComparer);
2879             List<KeyValuePair<string, DbExpression>> projectionItems = new List<KeyValuePair<string, DbExpression>>(selectClause.Items.Count);
2880             for (int i = 0; i < selectClause.Items.Count; i++)
2881             {
2882                 AST.AliasedExpr projectionItem = selectClause.Items[i];
2883
2884                 DbExpression converted = ConvertValueExpression(projectionItem.Expr, sr);
2885
2886                 //
2887                 // Infer projection item alias.
2888                 //
2889                 string aliasName = sr.InferAliasName(projectionItem, converted);
2890
2891                 //
2892                 // Ensure the alias is not already used.
2893                 //
2894                 if (projectionAliases.Contains(aliasName))
2895                 {
2896                     if (projectionItem.Alias != null)
2897                     {
2898                         CqlErrorHelper.ReportAliasAlreadyUsedError(aliasName, projectionItem.Alias.ErrCtx, Strings.InSelectProjectionList);
2899                     }
2900                     else
2901                     {
2902                         aliasName = sr.GenerateInternalName("autoProject");
2903                     }
2904                 }
2905
2906                 projectionAliases.Add(aliasName);
2907                 projectionItems.Add(new KeyValuePair<string, DbExpression>(aliasName, converted));
2908             }
2909
2910             Debug.Assert(projectionItems.Count > 0, "projectionItems.Count > 0");
2911             return projectionItems;
2912         }
2913
2914         private static DbExpression CreateProjectExpression(DbExpressionBinding source, AST.SelectClause selectClause, List<KeyValuePair<string, DbExpression>> projectionItems)
2915         {
2916             //
2917             // Create DbProjectExpression off the projectionItems.
2918             //
2919             DbExpression projectExpression;
2920             if (selectClause.SelectKind == AST.SelectKind.Value)
2921             {
2922                 Debug.Assert(projectionItems.Count == 1, "projectionItems.Count must be 1 for SELECT VALUE");
2923                 projectExpression = source.Project(projectionItems[0].Value);
2924             }
2925             else
2926             {
2927                 projectExpression = source.Project(DbExpressionBuilder.NewRow(projectionItems));
2928             }
2929
2930             //
2931             // Handle DISTINCT modifier - create DbDistinctExpression over the current projectExpression.
2932             //
2933             if (selectClause.DistinctKind == AST.DistinctKind.Distinct)
2934             {
2935                 //
2936                 // Ensure element type is equal-comparable.
2937                 //
2938                 ValidateDistinctProjection(projectExpression.ResultType, selectClause);
2939
2940                 //
2941                 // Create distinct expression.
2942                 //
2943                 projectExpression = projectExpression.Distinct();
2944             }
2945
2946             return projectExpression;
2947         }
2948
2949         private static void ValidateDistinctProjection(TypeUsage projectExpressionResultType, AST.SelectClause selectClause)
2950         {
2951             ValidateDistinctProjection(
2952                 projectExpressionResultType,
2953                 selectClause.Items[0].Expr.ErrCtx,
2954                 selectClause.SelectKind == System.Data.Common.EntitySql.AST.SelectKind.Row ?
2955                     new List<ErrorContext>(selectClause.Items.Select(item => item.Expr.ErrCtx)) : null);
2956         }
2957
2958         private static void ValidateDistinctProjection(TypeUsage projectExpressionResultType, ErrorContext defaultErrCtx, List<ErrorContext> projectionItemErrCtxs)
2959         {
2960             TypeUsage projectionType = TypeHelpers.GetElementTypeUsage(projectExpressionResultType);
2961             if (!TypeHelpers.IsValidDistinctOpType(projectionType))
2962             {
2963                 ErrorContext errCtx = defaultErrCtx;
2964                 if (projectionItemErrCtxs != null && TypeSemantics.IsRowType(projectionType))
2965                 {
2966                     RowType rowType = projectionType.EdmType as RowType;
2967                     Debug.Assert(projectionItemErrCtxs.Count == rowType.Members.Count);
2968                     for (int i = 0; i < rowType.Members.Count; i++)
2969                     {
2970                         if (!TypeHelpers.IsValidDistinctOpType(rowType.Members[i].TypeUsage))
2971                         {
2972                             errCtx = projectionItemErrCtxs[i];
2973                             break;
2974                         }
2975                     }
2976                 }
2977                 throw EntityUtil.EntitySqlError(errCtx, Strings.SelectDistinctMustBeEqualComparable);
2978             }
2979         }
2980
2981         private static void ValidateExpressionIsCommandParamOrNonNegativeIntegerConstant(DbExpression expr, ErrorContext errCtx, string exprName, SemanticResolver sr)
2982         {
2983             if (expr.ExpressionKind != DbExpressionKind.Constant &&
2984                 expr.ExpressionKind != DbExpressionKind.ParameterReference)
2985             {
2986                 throw EntityUtil.EntitySqlError(errCtx, Strings.PlaceholderExpressionMustBeConstant(exprName));
2987             }
2988
2989             if (!TypeSemantics.IsPromotableTo(expr.ResultType, sr.TypeResolver.Int64Type))
2990             {
2991                 throw EntityUtil.EntitySqlError(errCtx, Strings.PlaceholderExpressionMustBeCompatibleWithEdm64(exprName, expr.ResultType.EdmType.FullName));
2992             }
2993
2994             DbConstantExpression constExpr = expr as DbConstantExpression;
2995             if (constExpr != null && System.Convert.ToInt64(constExpr.Value, CultureInfo.InvariantCulture) < 0)
2996             {
2997                 throw EntityUtil.EntitySqlError(errCtx, Strings.PlaceholderExpressionMustBeGreaterThanOrEqualToZero(exprName));
2998             }
2999         }
3000
3001         /// <summary>
3002         /// Process FROM clause.
3003         /// </summary>
3004         private static DbExpressionBinding ProcessFromClause(AST.FromClause fromClause, SemanticResolver sr)
3005         {
3006             DbExpressionBinding fromBinding = null;
3007
3008             //
3009             // Process each FROM clause item.
3010             // If there is more than one of them, then assemble them in a string from APPLYs.
3011             //
3012             List<SourceScopeEntry> fromClauseEntries = new List<SourceScopeEntry>();
3013             for (int i = 0; i < fromClause.FromClauseItems.Count; i++)
3014             {
3015                 //
3016                 // Convert FROM clause item.
3017                 //
3018                 List<SourceScopeEntry> fromClauseItemEntries;
3019                 DbExpressionBinding currentItemBinding = ProcessFromClauseItem(fromClause.FromClauseItems[i], sr, out fromClauseItemEntries);
3020                 fromClauseEntries.AddRange(fromClauseItemEntries);
3021
3022                 if (fromBinding == null)
3023                 {
3024                     fromBinding = currentItemBinding;
3025                 }
3026                 else
3027                 {
3028                     fromBinding = fromBinding.CrossApply(currentItemBinding).BindAs(sr.GenerateInternalName("lcapply"));
3029
3030                     //
3031                     // Adjust scope entries with the new binding.
3032                     //
3033                     fromClauseEntries.ForEach(scopeEntry => scopeEntry.AddParentVar(fromBinding.Variable));
3034                 }
3035             }
3036
3037             Debug.Assert(fromBinding != null, "fromBinding != null");
3038
3039             return fromBinding;
3040         }
3041
3042         /// <summary>
3043         /// Process generic FROM clause item: aliasedExpr, JoinClauseItem or ApplyClauseItem.
3044         /// Returns <see cref="DbExpressionBinding"/> and the <paramref name="scopeEntries"/> list with entries created by the clause item.
3045         /// </summary>
3046         private static DbExpressionBinding ProcessFromClauseItem(AST.FromClauseItem fromClauseItem, SemanticResolver sr, out List<SourceScopeEntry> scopeEntries)
3047         {
3048             DbExpressionBinding fromItemBinding = null;
3049
3050             switch (fromClauseItem.FromClauseItemKind)
3051             {
3052                 case AST.FromClauseItemKind.AliasedFromClause:
3053                     fromItemBinding = ProcessAliasedFromClauseItem((AST.AliasedExpr)fromClauseItem.FromExpr, sr, out scopeEntries);
3054                     break;
3055
3056                 case AST.FromClauseItemKind.JoinFromClause:
3057                     fromItemBinding = ProcessJoinClauseItem((AST.JoinClauseItem)fromClauseItem.FromExpr, sr, out scopeEntries);
3058                     break;
3059
3060                 default:
3061                     Debug.Assert(fromClauseItem.FromClauseItemKind == AST.FromClauseItemKind.ApplyFromClause, "AST.FromClauseItemKind.ApplyFromClause expected");
3062                     fromItemBinding = ProcessApplyClauseItem((AST.ApplyClauseItem)fromClauseItem.FromExpr, sr, out scopeEntries);
3063                     break;
3064             }
3065
3066             Debug.Assert(fromItemBinding != null, "fromItemBinding != null");
3067
3068             return fromItemBinding;
3069         }
3070
3071         /// <summary>
3072         /// Process a simple FROM clause item.
3073         /// Returns <see cref="DbExpressionBinding"/> and the <paramref name="scopeEntries"/> list with a single entry created for the clause item.
3074         /// </summary>
3075         private static DbExpressionBinding ProcessAliasedFromClauseItem(AST.AliasedExpr aliasedExpr, SemanticResolver sr, out List<SourceScopeEntry> scopeEntries)
3076         {
3077             DbExpressionBinding aliasedBinding = null;
3078
3079             //
3080             // Convert the item expression.
3081             //
3082             DbExpression converted = ConvertValueExpression(aliasedExpr.Expr, sr);
3083
3084             //
3085             // Validate it is of collection type.
3086             //
3087             if (!TypeSemantics.IsCollectionType(converted.ResultType))
3088             {
3089                 throw EntityUtil.EntitySqlError(aliasedExpr.Expr.ErrCtx, Strings.ExpressionMustBeCollection);
3090             }
3091
3092             //
3093             // Infer source var alias name.
3094             //
3095             string aliasName = sr.InferAliasName(aliasedExpr, converted);
3096
3097             //
3098             // Validate the name was not used yet.
3099             //
3100             if (sr.CurrentScope.Contains(aliasName))
3101             {
3102                 if (aliasedExpr.Alias != null)
3103                 {
3104                     CqlErrorHelper.ReportAliasAlreadyUsedError(aliasName, aliasedExpr.Alias.ErrCtx, Strings.InFromClause);
3105                 }
3106                 else
3107                 {
3108                     aliasName = sr.GenerateInternalName("autoFrom");
3109                 }
3110             }
3111
3112             //
3113             // Create CQT expression.
3114             //
3115             aliasedBinding = converted.BindAs(aliasName);
3116
3117             //
3118             // Add source var to the _scopeEntries list and to the current scope.
3119             //
3120             SourceScopeEntry sourceScopeEntry = new SourceScopeEntry(aliasedBinding.Variable);
3121             sr.CurrentScope.Add(aliasedBinding.Variable.VariableName, sourceScopeEntry);
3122             scopeEntries = new List<SourceScopeEntry>();
3123             scopeEntries.Add(sourceScopeEntry);
3124
3125             Debug.Assert(aliasedBinding != null, "aliasedBinding != null");
3126
3127             return aliasedBinding;
3128         }
3129
3130         /// <summary>
3131         /// Process a JOIN clause item.
3132         /// Returns <see cref="DbExpressionBinding"/> and the <paramref name="scopeEntries"/> list with a join-left and join-right entries created for the clause item.
3133         /// </summary>
3134         private static DbExpressionBinding ProcessJoinClauseItem(AST.JoinClauseItem joinClause, SemanticResolver sr, out List<SourceScopeEntry> scopeEntries)
3135         {
3136             DbExpressionBinding joinBinding = null;
3137
3138             //
3139             // Make sure inner join has ON predicate AND cross join has no ON predicate.
3140             //
3141             if (null == joinClause.OnExpr)
3142             {
3143                 if (AST.JoinKind.Inner == joinClause.JoinKind)
3144                 {
3145                     throw EntityUtil.EntitySqlError(joinClause.ErrCtx, Strings.InnerJoinMustHaveOnPredicate);
3146                 }
3147             }
3148             else
3149             {
3150                 if (AST.JoinKind.Cross == joinClause.JoinKind)
3151                 {
3152                     throw EntityUtil.EntitySqlError(joinClause.OnExpr.ErrCtx, Strings.InvalidPredicateForCrossJoin);
3153                 }
3154             }
3155
3156             //
3157             // Process left expression.
3158             //
3159             List<SourceScopeEntry> leftExprScopeEntries;
3160             DbExpressionBinding leftBindingExpr = ProcessFromClauseItem(joinClause.LeftExpr, sr, out leftExprScopeEntries);
3161
3162             //
3163             // Mark scope entries from the left expression as such. This will disallow their usage inside of the right expression.
3164             // The left and right expressions of a join must be independent (they can not refer to variables in the other expression).
3165             // Join ON predicate may refer to variables defined in both expressions.
3166             // Examples:
3167             //     Select ... From A JOIN B JOIN A.x             -> invalid
3168             //     Select ... From A JOIN B JOIN C ON A.x = C.x  -> valid
3169             //     Select ... From A JOIN B, C JOIN A.x ...      -> valid
3170             //
3171             leftExprScopeEntries.ForEach(scopeEntry => scopeEntry.IsJoinClauseLeftExpr = true);
3172
3173             //
3174             // Process right expression
3175             //
3176             List<SourceScopeEntry> rightExprScopeEntries;
3177             DbExpressionBinding rightBindingExpr = ProcessFromClauseItem(joinClause.RightExpr, sr, out rightExprScopeEntries);
3178
3179             //
3180             // Unmark scope entries from the left expression to allow their usage.
3181             //
3182             leftExprScopeEntries.ForEach(scopeEntry => scopeEntry.IsJoinClauseLeftExpr = false);
3183
3184
3185             //
3186             // Switch right outer to left outer.
3187             //
3188             if (joinClause.JoinKind == AST.JoinKind.RightOuter)
3189             {
3190                 joinClause.JoinKind = AST.JoinKind.LeftOuter;
3191                 DbExpressionBinding tmpExpr = leftBindingExpr;
3192                 leftBindingExpr = rightBindingExpr;
3193                 rightBindingExpr = tmpExpr;
3194             }
3195
3196             //
3197             // Resolve JoinType.
3198             //
3199             DbExpressionKind joinKind = MapJoinKind(joinClause.JoinKind);
3200
3201             //
3202             // Resolve ON.
3203             //
3204             DbExpression onExpr = null;
3205             if (null == joinClause.OnExpr)
3206             {
3207                 if (DbExpressionKind.CrossJoin != joinKind)
3208                 {
3209                     onExpr = DbExpressionBuilder.True;
3210                 }
3211             }
3212             else
3213             {
3214                 onExpr = ConvertValueExpression(joinClause.OnExpr, sr);
3215             }
3216
3217             //
3218             // Create New Join
3219             //
3220             joinBinding =
3221                 DbExpressionBuilder.CreateJoinExpressionByKind(
3222                     joinKind, onExpr, leftBindingExpr, rightBindingExpr).BindAs(sr.GenerateInternalName("join"));
3223
3224             //
3225             // Combine left and right scope entries and adjust with the new binding.
3226             //
3227             scopeEntries = leftExprScopeEntries;
3228             scopeEntries.AddRange(rightExprScopeEntries);
3229             scopeEntries.ForEach(scopeEntry => scopeEntry.AddParentVar(joinBinding.Variable));
3230
3231             Debug.Assert(joinBinding != null, "joinBinding != null");
3232
3233             return joinBinding;
3234         }
3235
3236         /// <summary>
3237         /// Maps <see cref="AST.JoinKind"/> to <see cref="DbExpressionKind"/>.
3238         /// </summary>
3239         private static DbExpressionKind MapJoinKind(AST.JoinKind joinKind)
3240         {
3241             Debug.Assert(joinKind != AST.JoinKind.RightOuter, "joinKind != JoinKind.RightOuter");
3242             return joinMap[(int)joinKind];
3243         }
3244         private static readonly DbExpressionKind[] joinMap = { DbExpressionKind.CrossJoin, DbExpressionKind.InnerJoin, DbExpressionKind.LeftOuterJoin, DbExpressionKind.FullOuterJoin };
3245
3246         /// <summary>
3247         /// Process an APPLY clause item.
3248         /// Returns <see cref="DbExpressionBinding"/> and the <paramref name="scopeEntries"/> list with an apply-left and apply-right entries created for the clause item.
3249         /// </summary>
3250         private static DbExpressionBinding ProcessApplyClauseItem(AST.ApplyClauseItem applyClause, SemanticResolver sr, out List<SourceScopeEntry> scopeEntries)
3251         {
3252             DbExpressionBinding applyBinding = null;
3253
3254             //
3255             // Resolve left expression.
3256             //
3257             List<SourceScopeEntry> leftExprScopeEntries;
3258             DbExpressionBinding leftBindingExpr = ProcessFromClauseItem(applyClause.LeftExpr, sr, out leftExprScopeEntries);
3259
3260             //
3261             // Resolve right expression.
3262             //
3263             List<SourceScopeEntry> rightExprScopeEntries;
3264             DbExpressionBinding rightBindingExpr = ProcessFromClauseItem(applyClause.RightExpr, sr, out rightExprScopeEntries);
3265
3266             //
3267             // Create Apply.
3268             //
3269             applyBinding =
3270                 DbExpressionBuilder.CreateApplyExpressionByKind(
3271                     MapApplyKind(applyClause.ApplyKind),
3272                     leftBindingExpr,
3273                     rightBindingExpr).BindAs(sr.GenerateInternalName("apply"));
3274
3275             //
3276             // Combine left and right scope entries and adjust with the new binding.
3277             //
3278             scopeEntries = leftExprScopeEntries;
3279             scopeEntries.AddRange(rightExprScopeEntries);
3280             scopeEntries.ForEach(scopeEntry => scopeEntry.AddParentVar(applyBinding.Variable));
3281
3282             Debug.Assert(applyBinding != null, "applyBinding != null");
3283
3284             return applyBinding;
3285         }
3286
3287         /// <summary>
3288         /// Maps <see cref="AST.ApplyKind"/> to <see cref="DbExpressionKind"/>.
3289         /// </summary>
3290         private static DbExpressionKind MapApplyKind(AST.ApplyKind applyKind)
3291         {
3292             return applyMap[(int)applyKind];
3293         }
3294         private static readonly DbExpressionKind[] applyMap = { DbExpressionKind.CrossApply, DbExpressionKind.OuterApply };
3295
3296         /// <summary>
3297         /// Process WHERE clause.
3298         /// </summary>
3299         private static DbExpressionBinding ProcessWhereClause(DbExpressionBinding source, AST.Node whereClause, SemanticResolver sr)
3300         {
3301             if (whereClause == null)
3302             {
3303                 return source;
3304             }
3305             return ProcessWhereHavingClausePredicate(source, whereClause, whereClause.ErrCtx, "where", sr);
3306         }
3307
3308         /// <summary>
3309         /// Process HAVING clause.
3310         /// </summary>
3311         private static DbExpressionBinding ProcessHavingClause(DbExpressionBinding source, AST.HavingClause havingClause, SemanticResolver sr)
3312         {
3313             if (havingClause == null)
3314             {
3315                 return source;
3316             }
3317             return ProcessWhereHavingClausePredicate(source, havingClause.HavingPredicate, havingClause.ErrCtx, "having", sr);
3318         }
3319
3320         /// <summary>
3321         /// Process WHERE or HAVING clause predicate.
3322         /// </summary>
3323         private static DbExpressionBinding ProcessWhereHavingClausePredicate(DbExpressionBinding source, AST.Node predicate, ErrorContext errCtx, string bindingNameTemplate, SemanticResolver sr)
3324         {
3325             Debug.Assert(predicate != null, "predicate != null");
3326
3327             DbExpressionBinding whereBinding = null;
3328
3329             //
3330             // Convert the predicate.
3331             //
3332             DbExpression filterConditionExpr = ConvertValueExpression(predicate, sr);
3333
3334             //
3335             // Ensure the predicate type is boolean.
3336             //
3337             if (!IsBooleanType(filterConditionExpr.ResultType))
3338             {
3339                 throw EntityUtil.EntitySqlError(errCtx, Strings.ExpressionTypeMustBeBoolean);
3340             }
3341
3342             //
3343             // Create new filter binding.
3344             //
3345             whereBinding = source.Filter(filterConditionExpr).BindAs(sr.GenerateInternalName(bindingNameTemplate));
3346
3347             //
3348             // Fixup Bindings.
3349             //
3350             sr.CurrentScopeRegion.ApplyToScopeEntries(scopeEntry =>
3351             {
3352                 Debug.Assert(scopeEntry.EntryKind == ScopeEntryKind.SourceVar || scopeEntry.EntryKind == ScopeEntryKind.InvalidGroupInputRef,
3353                     "scopeEntry.EntryKind == ScopeEntryKind.SourceVar || scopeEntry.EntryKind == ScopeEntryKind.InvalidGroupInputRef");
3354
3355                 if (scopeEntry.EntryKind == ScopeEntryKind.SourceVar)
3356                 {
3357                     ((SourceScopeEntry)scopeEntry).ReplaceParentVar(whereBinding.Variable);
3358                 }
3359             });
3360
3361             Debug.Assert(whereBinding != null, "whereBinding != null");
3362
3363             return whereBinding;
3364         }
3365
3366         /// <summary>
3367         /// Process Group By Clause
3368         /// </summary>
3369         private static DbExpressionBinding ProcessGroupByClause(DbExpressionBinding source, AST.QueryExpr queryExpr, SemanticResolver sr)
3370         {
3371             AST.GroupByClause groupByClause = queryExpr.GroupByClause;
3372
3373             Debug.Assert((sr.ParserOptions.ParserCompilationMode == ParserOptions.CompilationMode.RestrictedViewGenerationMode) ? null == groupByClause : true, "GROUP BY clause must be null in RestrictedViewGenerationMode");
3374
3375             //
3376             // If group expression is null, assume an implicit group and speculate that there are group aggregates in the remaining query expression.
3377             // If no group aggregate are found after partial evaluation of HAVING, ORDER BY and SELECT, rollback the implicit group.
3378             //
3379             int groupKeysCount = groupByClause != null ? groupByClause.GroupItems.Count : 0;
3380             bool isImplicitGroup = groupKeysCount == 0;
3381             if (isImplicitGroup && !queryExpr.HasMethodCall)
3382             {
3383                 return source;
3384             }
3385
3386             //
3387             // Create input binding for DbGroupByExpression.
3388             //
3389             DbGroupExpressionBinding groupInputBinding = source.Expression.GroupBindAs(sr.GenerateInternalName("geb"), sr.GenerateInternalName("group"));
3390
3391             //
3392             // Create group partition (DbGroupAggregate) and projection template.
3393             //
3394             DbGroupAggregate groupAggregateDefinition = groupInputBinding.GroupAggregate;
3395             DbVariableReferenceExpression groupAggregateVarRef = groupAggregateDefinition.ResultType.Variable(sr.GenerateInternalName("groupAggregate"));
3396             DbExpressionBinding groupAggregateBinding = groupAggregateVarRef.BindAs(sr.GenerateInternalName("groupPartitionItem"));
3397
3398             //
3399             // Flag that we perform group operation.
3400             //
3401             sr.CurrentScopeRegion.EnterGroupOperation(groupAggregateBinding);
3402
3403             //
3404             // Update group input bindings.
3405             //
3406             sr.CurrentScopeRegion.ApplyToScopeEntries((scopeEntry) =>
3407             {
3408                 Debug.Assert(scopeEntry.EntryKind == ScopeEntryKind.SourceVar, "scopeEntry.EntryKind == ScopeEntryKind.SourceVar");
3409                 ((SourceScopeEntry)scopeEntry).AdjustToGroupVar(groupInputBinding.Variable, groupInputBinding.GroupVariable, groupAggregateBinding.Variable);
3410             });
3411
3412             //
3413             // This set will include names of keys, aggregates and the group partition name if specified.
3414             // All these properties become field names of the row type returned by the DbGroupByExpression.
3415             //
3416             HashSet<string> groupPropertyNames = new HashSet<string>(sr.NameComparer);
3417
3418             //
3419             // Convert group keys.
3420             //
3421             #region Convert group key definitions
3422             List<GroupKeyInfo> groupKeys = new List<GroupKeyInfo>(groupKeysCount);
3423             if (!isImplicitGroup)
3424             {
3425                 Debug.Assert(null != groupByClause, "groupByClause must not be null at this point");
3426                 for (int i = 0; i < groupKeysCount; i++)
3427                 {
3428                     AST.AliasedExpr aliasedExpr = groupByClause.GroupItems[i];
3429
3430                     sr.CurrentScopeRegion.WasResolutionCorrelated = false;
3431
3432                     //
3433                     // Convert key expression relative to groupInputBinding.Variable.
3434                     // This expression will be used as key definition during construction of DbGroupByExpression.
3435                     //
3436                     DbExpression keyExpr;
3437                     GroupKeyAggregateInfo groupKeyAggregateInfo;
3438                     using (sr.EnterGroupKeyDefinition(GroupAggregateKind.GroupKey, aliasedExpr.ErrCtx, out groupKeyAggregateInfo))
3439                     {
3440                         keyExpr = ConvertValueExpression(aliasedExpr.Expr, sr);
3441                     }
3442
3443                     //
3444                     // Ensure group key expression is correlated.
3445                     // If resolution was correlated, then the following should be true for groupKeyAggregateInfo: ESR == DSR
3446                     //
3447                     if (!sr.CurrentScopeRegion.WasResolutionCorrelated)
3448                     {
3449                         throw EntityUtil.EntitySqlError(aliasedExpr.Expr.ErrCtx, Strings.KeyMustBeCorrelated("GROUP BY"));
3450                     }
3451                     Debug.Assert(groupKeyAggregateInfo.EvaluatingScopeRegion == groupKeyAggregateInfo.DefiningScopeRegion, "Group key must evaluate on the scope it was defined on.");
3452
3453                     //
3454                     // Ensure key is valid.
3455                     //
3456                     if (!TypeHelpers.IsValidGroupKeyType(keyExpr.ResultType))
3457                     {
3458                         throw EntityUtil.EntitySqlError(aliasedExpr.Expr.ErrCtx, Strings.GroupingKeysMustBeEqualComparable);
3459                     }
3460
3461                     //
3462                     // Convert key expression relative to groupInputBinding.GroupVariable.
3463                     // keyExprForFunctionAggregates will be used inside of definitions of group aggregates resolved to the current scope region.
3464                     //
3465                     DbExpression keyExprForFunctionAggregates;
3466                     GroupKeyAggregateInfo functionAggregateInfo;
3467                     using (sr.EnterGroupKeyDefinition(GroupAggregateKind.Function, aliasedExpr.ErrCtx, out functionAggregateInfo))
3468                     {
3469                         keyExprForFunctionAggregates = ConvertValueExpression(aliasedExpr.Expr, sr);
3470                     }
3471                     Debug.Assert(functionAggregateInfo.EvaluatingScopeRegion == functionAggregateInfo.DefiningScopeRegion, "Group key must evaluate on the scope it was defined on.");
3472
3473                     //
3474                     // Convert key expression relative to groupAggregateBinding.Variable.
3475                     // keyExprForGroupPartitions will be used inside of definitions of GROUPPARTITION aggregates resolved to the current scope region.
3476                     //
3477                     DbExpression keyExprForGroupPartitions;
3478                     GroupKeyAggregateInfo groupPartitionInfo;
3479                     using (sr.EnterGroupKeyDefinition(GroupAggregateKind.Partition, aliasedExpr.ErrCtx, out groupPartitionInfo))
3480                     {
3481                         keyExprForGroupPartitions = ConvertValueExpression(aliasedExpr.Expr, sr);
3482                     }
3483                     Debug.Assert(groupPartitionInfo.EvaluatingScopeRegion == groupPartitionInfo.DefiningScopeRegion, "Group key must evaluate on the scope it was defined on.");
3484
3485                     //
3486                     // Infer group key alias name.
3487                     //
3488                     string groupKeyAlias = sr.InferAliasName(aliasedExpr, keyExpr);
3489
3490                     //
3491                     // Check if alias was already used.
3492                     //
3493                     if (groupPropertyNames.Contains(groupKeyAlias))
3494                     {
3495                         if (aliasedExpr.Alias != null)
3496                         {
3497                             CqlErrorHelper.ReportAliasAlreadyUsedError(groupKeyAlias, aliasedExpr.Alias.ErrCtx, Strings.InGroupClause);
3498                         }
3499                         else
3500                         {
3501                             groupKeyAlias = sr.GenerateInternalName("autoGroup");
3502                         }
3503                     }
3504
3505                     //
3506                     // Add alias to dictionary.
3507                     //
3508                     groupPropertyNames.Add(groupKeyAlias);
3509
3510                     //
3511                     // Add key to keys collection.
3512                     //
3513                     GroupKeyInfo groupKeyInfo = new GroupKeyInfo(groupKeyAlias, keyExpr, keyExprForFunctionAggregates, keyExprForGroupPartitions);
3514                     groupKeys.Add(groupKeyInfo);
3515
3516                     //
3517                     // Group keys should be visible by their 'original' key expression name. The following three forms should be allowed:
3518                     //   SELECT k       FROM ... as p GROUP BY p.Price as k (explicit key alias) - handled above by InferAliasName()
3519                     //   SELECT Price   FROM ... as p GROUP BY p.Price      (implicit alias - leading name) - handled above by InferAliasName()
3520                     //   SELECT p.Price FROM ... as p GROUP BY p.Price      (original key expression) - case handled in the code bellow
3521                     //
3522                     if (aliasedExpr.Alias == null)
3523                     {
3524                         AST.DotExpr dotExpr = aliasedExpr.Expr as AST.DotExpr;
3525                         string[] alternativeName;
3526                         if (null != dotExpr && dotExpr.IsMultipartIdentifier(out alternativeName))
3527                         {
3528                             groupKeyInfo.AlternativeName = alternativeName;
3529
3530                             string alternativeFullName = TypeResolver.GetFullName(alternativeName);
3531                             if (groupPropertyNames.Contains(alternativeFullName))
3532                             {
3533                                 CqlErrorHelper.ReportAliasAlreadyUsedError(alternativeFullName, dotExpr.ErrCtx, Strings.InGroupClause);
3534                             }
3535
3536                             groupPropertyNames.Add(alternativeFullName);
3537                         }
3538                     }
3539                 }
3540             }
3541             #endregion
3542
3543             //
3544             // Save scope. It will be used to rollback the temporary group scope created below.
3545             //
3546             int groupInputScope = sr.CurrentScopeIndex;
3547
3548             //
3549             // Push temporary group scope.
3550             //
3551             sr.EnterScope();
3552
3553             //
3554             // Add scope entries for group keys and the group partition to the current scope,
3555             // this is needed for the aggregate search phase during which keys may be referenced.
3556             //
3557             foreach (GroupKeyInfo groupKeyInfo in groupKeys)
3558             {
3559                 sr.CurrentScope.Add(
3560                     groupKeyInfo.Name,
3561                     new GroupKeyDefinitionScopeEntry(
3562                         groupKeyInfo.VarBasedKeyExpr,
3563                         groupKeyInfo.GroupVarBasedKeyExpr,
3564                         groupKeyInfo.GroupAggBasedKeyExpr,
3565                         null));
3566
3567                 if (groupKeyInfo.AlternativeName != null)
3568                 {
3569                     string strAlternativeName = TypeResolver.GetFullName(groupKeyInfo.AlternativeName);
3570                     sr.CurrentScope.Add(
3571                         strAlternativeName,
3572                         new GroupKeyDefinitionScopeEntry(
3573                             groupKeyInfo.VarBasedKeyExpr,
3574                             groupKeyInfo.GroupVarBasedKeyExpr,
3575                             groupKeyInfo.GroupAggBasedKeyExpr,
3576                             groupKeyInfo.AlternativeName));
3577                 }
3578             }
3579
3580             //
3581             // Convert/Search Aggregates
3582             // since aggregates can be defined in Having, OrderBy and/or Select clauses must be resolved as part of the group expression.
3583             // The resolution of these clauses result in potential collection of resolved group aggregates and the actual resulting
3584             // expression is ignored. These clauses will be then resolved as usual on a second pass.
3585             //
3586
3587             #region Search for group aggregates (functions and GROUPPARTITIONs)
3588             //
3589             // Search for aggregates in HAVING clause.
3590             //
3591             if (null != queryExpr.HavingClause && queryExpr.HavingClause.HasMethodCall)
3592             {
3593                 DbExpression converted = ConvertValueExpression(queryExpr.HavingClause.HavingPredicate, sr);
3594             }
3595
3596             //
3597             // Search for aggregates in SELECT clause.
3598             //
3599             Dictionary<string, DbExpression> projectionExpressions = null;
3600             if (null != queryExpr.OrderByClause || queryExpr.SelectClause.HasMethodCall)
3601             {
3602                 projectionExpressions = new Dictionary<string, DbExpression>(queryExpr.SelectClause.Items.Count, sr.NameComparer);
3603                 for (int i = 0; i < queryExpr.SelectClause.Items.Count; i++)
3604                 {
3605                     AST.AliasedExpr aliasedExpr = queryExpr.SelectClause.Items[i];
3606
3607                     //
3608                     // Convert projection item expression.
3609                     //
3610                     DbExpression converted = ConvertValueExpression(aliasedExpr.Expr, sr);
3611
3612                     //
3613                     // Create Null Expression with actual type.
3614                     //
3615                     converted = converted.ExpressionKind == CommandTrees.DbExpressionKind.Null ? converted : converted.ResultType.Null();
3616
3617                     //
3618                     // Infer alias.
3619                     //
3620                     string aliasName = sr.InferAliasName(aliasedExpr, converted);
3621
3622                     if (projectionExpressions.ContainsKey(aliasName))
3623                     {
3624                         if (aliasedExpr.Alias != null)
3625                         {
3626                             CqlErrorHelper.ReportAliasAlreadyUsedError(aliasName,
3627                                                                        aliasedExpr.Alias.ErrCtx,
3628                                                                        Strings.InSelectProjectionList);
3629                         }
3630                         else
3631                         {
3632                             aliasName = sr.GenerateInternalName("autoProject");
3633                         }
3634                     }
3635
3636                     projectionExpressions.Add(aliasName, converted);
3637                 }
3638             }
3639
3640             //
3641             // Search for aggregates in ORDER BY clause.
3642             //
3643             if (null != queryExpr.OrderByClause && queryExpr.OrderByClause.HasMethodCall)
3644             {
3645                 //
3646                 // Push temporary projection scope.
3647                 //
3648                 sr.EnterScope();
3649
3650                 //
3651                 // Add projection items to the temporary scope (items may be used in ORDER BY).
3652                 //
3653                 foreach (KeyValuePair<string, DbExpression> kvp in projectionExpressions)
3654                 {
3655                     sr.CurrentScope.Add(kvp.Key, new ProjectionItemDefinitionScopeEntry(kvp.Value));
3656                 }
3657
3658                 //
3659                 // Search for aggregates in ORDER BY clause.
3660                 //
3661                 for (int i = 0; i < queryExpr.OrderByClause.OrderByClauseItem.Count; i++)
3662                 {
3663                     AST.OrderByClauseItem orderItem = queryExpr.OrderByClause.OrderByClauseItem[i];
3664
3665                     sr.CurrentScopeRegion.WasResolutionCorrelated = false;
3666
3667                     DbExpression converted = ConvertValueExpression(orderItem.OrderExpr, sr);
3668
3669                     //
3670                     // Ensure key expression is correlated.
3671                     //
3672                     if (!sr.CurrentScopeRegion.WasResolutionCorrelated)
3673                     {
3674                         throw EntityUtil.EntitySqlError(orderItem.ErrCtx, Strings.KeyMustBeCorrelated("ORDER BY"));
3675                     }
3676                 }
3677
3678                 //
3679                 // Pop temporary projection scope.
3680                 //
3681                 sr.LeaveScope();
3682             }
3683             #endregion
3684
3685             //
3686             // If we introduced a fake group but did not find any group aggregates
3687             // on the first pass, then there is no need for creating an implicit group.
3688             // Rollback to the status before entering ProcessGroupByClause().
3689             // If we did find group aggregates, make sure all non-group aggregate function
3690             // expressions refer to group scope variables only.
3691             //
3692             if (isImplicitGroup)
3693             {
3694                 if (0 == sr.CurrentScopeRegion.GroupAggregateInfos.Count)
3695                 {
3696                     #region Implicit Group Rollback
3697                     //
3698                     // Rollback the temporary group scope.
3699                     //
3700                     sr.RollbackToScope(groupInputScope);
3701
3702                     //
3703                     // Undo any group source fixups: re-applying the source var and remove the group var.
3704                     //
3705                     sr.CurrentScopeRegion.ApplyToScopeEntries((scopeEntry) =>
3706                     {
3707                         Debug.Assert(scopeEntry.EntryKind == ScopeEntryKind.SourceVar, "scopeEntry.EntryKind == ScopeEntryKind.SourceVar");
3708                         ((SourceScopeEntry)scopeEntry).RollbackAdjustmentToGroupVar(source.Variable);
3709                     });
3710
3711                     //
3712                     // Remove the group operation flag.
3713                     //
3714                     sr.CurrentScopeRegion.RollbackGroupOperation();
3715                     #endregion
3716                     //
3717                     // Return the original source var binding.
3718                     //
3719                     return source;
3720                 }
3721             }
3722
3723             //
3724             // Prepare list of aggregate definitions and their internal names.
3725             //
3726             List<KeyValuePair<string, DbAggregate>> aggregates = new List<KeyValuePair<string, DbAggregate>>(sr.CurrentScopeRegion.GroupAggregateInfos.Count);
3727             bool groupPartitionRefFound = false;
3728             foreach (GroupAggregateInfo groupAggregateInfo in sr.CurrentScopeRegion.GroupAggregateInfos)
3729             {
3730                 switch (groupAggregateInfo.AggregateKind)
3731                 {
3732                     case GroupAggregateKind.Function:
3733                         aggregates.Add(new KeyValuePair<string, DbAggregate>(
3734                             groupAggregateInfo.AggregateName,
3735                             ((FunctionAggregateInfo)groupAggregateInfo).AggregateDefinition));
3736                         break;
3737
3738                     case GroupAggregateKind.Partition:
3739                         groupPartitionRefFound = true;
3740                         break;
3741
3742                     default:
3743                         Debug.Fail("Unexpected group aggregate kind:" + groupAggregateInfo.AggregateKind.ToString());
3744                         break;
3745                 }
3746             }
3747             if (groupPartitionRefFound)
3748             {
3749                 //
3750                 // Add DbAggregate to support GROUPPARTITION definitions.
3751                 //
3752                 aggregates.Add(new KeyValuePair<string, DbAggregate>(groupAggregateVarRef.VariableName, groupAggregateDefinition));
3753             }
3754
3755             //
3756             // Create GroupByExpression and a binding to it.
3757             //
3758             DbGroupByExpression groupBy = groupInputBinding.GroupBy(
3759                 groupKeys.Select(keyInfo => new KeyValuePair<string, DbExpression>(keyInfo.Name, keyInfo.VarBasedKeyExpr)),
3760                 aggregates);
3761             DbExpressionBinding groupBinding = groupBy.BindAs(sr.GenerateInternalName("group"));
3762
3763             //
3764             // If there are GROUPPARTITION expressions, then add an extra projection off the groupBinding to
3765             //  - project all the keys and aggregates, except the DbGroupAggregate,
3766             //  - project definitions of GROUPPARTITION expressions.
3767             //
3768             if (groupPartitionRefFound)
3769             {
3770                 //
3771                 // All GROUPPARTITION definitions reference groupAggregateVarRef, make sure the variable is properly defined in the groupBy expression.
3772                 //
3773                 Debug.Assert(aggregates.Any((aggregate) => String.CompareOrdinal(aggregate.Key, groupAggregateVarRef.VariableName) == 0),
3774                     "DbAggregate is not defined");
3775
3776                 //
3777                 // Get projection of GROUPPARTITION definitions.
3778                 // This method may return null if all GROUPPARTITION definitions are reduced to the value of groupAggregateVarRef.
3779                 //
3780                 List<KeyValuePair<string, DbExpression>> projectionItems = ProcessGroupPartitionDefinitions(
3781                     sr.CurrentScopeRegion.GroupAggregateInfos,
3782                     groupAggregateVarRef,
3783                     groupBinding);
3784
3785                 if (projectionItems != null)
3786                 {
3787                     //
3788                     // Project group keys along with GROUPPARTITION definitions.
3789                     //
3790                     projectionItems.AddRange(groupKeys.Select(keyInfo =>
3791                         new KeyValuePair<string, DbExpression>(keyInfo.Name, groupBinding.Variable.Property(keyInfo.Name))));
3792
3793                     // 
3794                     // Project function group aggregates along with GROUPPARTITION definitions and group keys.
3795                     //
3796                     projectionItems.AddRange(sr.CurrentScopeRegion.GroupAggregateInfos
3797                         .Where(groupAggregateInfo => groupAggregateInfo.AggregateKind == GroupAggregateKind.Function)
3798                         .Select(groupAggregateInfo => new KeyValuePair<string, DbExpression>(
3799                             groupAggregateInfo.AggregateName,
3800                             groupBinding.Variable.Property(groupAggregateInfo.AggregateName))));
3801
3802                     DbExpression projectExpression = DbExpressionBuilder.NewRow(projectionItems);
3803                     groupBinding = groupBinding.Project(projectExpression).BindAs(sr.GenerateInternalName("groupPartitionDefs"));
3804                 }
3805             }
3806
3807             //
3808             // Remove the temporary group scope with group key definitions,
3809             // Replace all existing pre-group scope entries with InvalidGroupInputRefScopeEntry stubs - 
3810             // they are no longer available for proper referencing and only to be used for user error messages.
3811             //
3812             sr.RollbackToScope(groupInputScope);
3813             sr.CurrentScopeRegion.ApplyToScopeEntries((scopeEntry) =>
3814             {
3815                 Debug.Assert(scopeEntry.EntryKind == ScopeEntryKind.SourceVar, "scopeEntry.EntryKind == ScopeEntryKind.SourceVar");
3816                 return new InvalidGroupInputRefScopeEntry();
3817             });
3818
3819             //
3820             // Add final group scope.
3821             //
3822             sr.EnterScope();
3823
3824             //
3825             // Add group keys to the group scope.
3826             //
3827             foreach (GroupKeyInfo groupKeyInfo in groupKeys)
3828             {
3829                 //
3830                 // Add new scope entry 
3831                 //
3832                 sr.CurrentScope.Add(
3833                     groupKeyInfo.VarRef.VariableName,
3834                     new SourceScopeEntry(groupKeyInfo.VarRef).AddParentVar(groupBinding.Variable));
3835
3836                 //
3837                 // Handle the alternative name entry.
3838                 //
3839                 if (groupKeyInfo.AlternativeName != null)
3840                 {
3841                     //
3842                     // We want two scope entries with keys as groupKeyInfo.VarRef.VariableName and groupKeyInfo.AlternativeName, 
3843                     // both pointing to the same variable (groupKeyInfo.VarRef).
3844                     //
3845                     string strAlternativeName = TypeResolver.GetFullName(groupKeyInfo.AlternativeName);
3846                     sr.CurrentScope.Add(
3847                         strAlternativeName,
3848                         new SourceScopeEntry(groupKeyInfo.VarRef, groupKeyInfo.AlternativeName).AddParentVar(groupBinding.Variable));
3849                 }
3850             }
3851
3852             //
3853             // Add group aggregates to the scope.
3854             //
3855             foreach (GroupAggregateInfo groupAggregateInfo in sr.CurrentScopeRegion.GroupAggregateInfos)
3856             {
3857                 DbVariableReferenceExpression aggVarRef = groupAggregateInfo.AggregateStubExpression.ResultType.Variable(groupAggregateInfo.AggregateName);
3858
3859                 Debug.Assert(
3860                     !sr.CurrentScope.Contains(aggVarRef.VariableName) ||
3861                     groupAggregateInfo.AggregateKind == GroupAggregateKind.Partition, "DbFunctionAggregate's with duplicate names are not allowed.");
3862
3863                 if (!sr.CurrentScope.Contains(aggVarRef.VariableName))
3864                 {
3865                     sr.CurrentScope.Add(
3866                         aggVarRef.VariableName,
3867                         new SourceScopeEntry(aggVarRef).AddParentVar(groupBinding.Variable));
3868                     sr.CurrentScopeRegion.RegisterGroupAggregateName(aggVarRef.VariableName);
3869                 }
3870
3871                 //
3872                 // Cleanup the stub expression as it must not be used after this point.
3873                 //
3874                 groupAggregateInfo.AggregateStubExpression = null;
3875             }
3876
3877             return groupBinding;
3878         }
3879
3880         /// <summary>
3881         /// Generates the list of projections for GROUPPARTITION definitions.
3882         /// All GROUPPARTITION definitions over the trivial projection of input are reduced to the value of groupAggregateVarRef,
3883         /// only one projection item is created for such definitions.
3884         /// Returns null if all GROUPPARTITION definitions are reduced to the value of groupAggregateVarRef.
3885         /// </summary>
3886         private static List<KeyValuePair<string, DbExpression>> ProcessGroupPartitionDefinitions(
3887             List<GroupAggregateInfo> groupAggregateInfos,
3888             DbVariableReferenceExpression groupAggregateVarRef,
3889             DbExpressionBinding groupBinding)
3890         {
3891             var gpExpressionLambdaVariables = new System.Collections.ObjectModel.ReadOnlyCollection<DbVariableReferenceExpression>(
3892                 new DbVariableReferenceExpression[] { groupAggregateVarRef });
3893
3894             List<KeyValuePair<string, DbExpression>> groupPartitionDefinitions = new List<KeyValuePair<string, DbExpression>>();
3895             bool foundTrivialGroupAggregateProjection = false;
3896             foreach (GroupAggregateInfo groupAggregateInfo in groupAggregateInfos)
3897             {
3898                 if (groupAggregateInfo.AggregateKind == GroupAggregateKind.Partition)
3899                 {
3900                     DbExpression aggregateDefinition = ((GroupPartitionInfo)groupAggregateInfo).AggregateDefinition;
3901                     if (IsTrivialInputProjection(groupAggregateVarRef, aggregateDefinition))
3902                     {
3903                         //
3904                         // Reduce the case of the trivial projection of input to the value of groupAggregateVarRef.
3905                         //
3906                         groupAggregateInfo.AggregateName = groupAggregateVarRef.VariableName;
3907                         foundTrivialGroupAggregateProjection = true;
3908                     }
3909                     else
3910                     {
3911                         //
3912                         // Build a projection item for the non-trivial definition.
3913                         //
3914                         DbLambda gpExpressionLambda = new DbLambda(gpExpressionLambdaVariables, ((GroupPartitionInfo)groupAggregateInfo).AggregateDefinition);
3915                         groupPartitionDefinitions.Add(new KeyValuePair<string, DbExpression>(
3916                             groupAggregateInfo.AggregateName,
3917                             gpExpressionLambda.Invoke(groupBinding.Variable.Property(groupAggregateVarRef.VariableName))));
3918                     }
3919                 }
3920             }
3921
3922             if (foundTrivialGroupAggregateProjection)
3923             {
3924                 if (groupPartitionDefinitions.Count > 0)
3925                 {
3926                     //
3927                     // Add projection item for groupAggregateVarRef if there are reduced definitions.
3928                     //
3929                     groupPartitionDefinitions.Add(new KeyValuePair<string, DbExpression>(
3930                         groupAggregateVarRef.VariableName,
3931                         groupBinding.Variable.Property(groupAggregateVarRef.VariableName)));
3932                 }
3933                 else
3934                 {
3935                     //
3936                     // If all GROUPPARTITION definitions have been reduced, return null.
3937                     // In this case the wrapping projection will not be created and 
3938                     // groupAggregateVarRef will be projected directly from the DbGroupByExpression.
3939                     //
3940                     groupPartitionDefinitions = null;
3941                 }
3942             }
3943
3944             return groupPartitionDefinitions;
3945         }
3946
3947         /// <summary>
3948         /// Returns true if lambda accepts a collection variable and trivially projects out its elements. 
3949         /// </summary>
3950         private static bool IsTrivialInputProjection(DbVariableReferenceExpression lambdaVariable, DbExpression lambdaBody)
3951         {
3952             if (lambdaBody.ExpressionKind != DbExpressionKind.Project)
3953             {
3954                 return false;
3955             }
3956             DbProjectExpression projectExpression = (DbProjectExpression)lambdaBody;
3957
3958             if (projectExpression.Input.Expression != lambdaVariable)
3959             {
3960                 return false;
3961             }
3962
3963             Debug.Assert(TypeSemantics.IsCollectionType(lambdaVariable.ResultType));
3964
3965             if (projectExpression.Projection.ExpressionKind == DbExpressionKind.VariableReference)
3966             {
3967                 DbVariableReferenceExpression projectionExpression = (DbVariableReferenceExpression)projectExpression.Projection;
3968                 return projectionExpression == projectExpression.Input.Variable;
3969             }
3970             else if (projectExpression.Projection.ExpressionKind == DbExpressionKind.NewInstance &&
3971                      TypeSemantics.IsRowType(projectExpression.Projection.ResultType))
3972             {
3973                 if (!TypeSemantics.IsEqual(projectExpression.Projection.ResultType, projectExpression.Input.Variable.ResultType))
3974                 {
3975                     return false;
3976                 }
3977
3978                 IBaseList<EdmMember> inputVariableTypeProperties = TypeHelpers.GetAllStructuralMembers(projectExpression.Input.Variable.ResultType);
3979
3980                 DbNewInstanceExpression projectionExpression = (DbNewInstanceExpression)projectExpression.Projection;
3981
3982                 Debug.Assert(projectionExpression.Arguments.Count == inputVariableTypeProperties.Count, "projectionExpression.Arguments.Count == inputVariableTypeProperties.Count");
3983                 for (int i = 0; i < projectionExpression.Arguments.Count; ++i)
3984                 {
3985                     if (projectionExpression.Arguments[i].ExpressionKind != DbExpressionKind.Property)
3986                     {
3987                         return false;
3988                     }
3989                     DbPropertyExpression propertyRef = (DbPropertyExpression)projectionExpression.Arguments[i];
3990
3991                     if (propertyRef.Instance != projectExpression.Input.Variable ||
3992                         propertyRef.Property != inputVariableTypeProperties[i])
3993                     {
3994                         return false;
3995                     }
3996                 }
3997
3998                 return true;
3999             }
4000
4001             return false;
4002         }
4003
4004         private sealed class GroupKeyInfo
4005         {
4006             internal GroupKeyInfo(string name, DbExpression varBasedKeyExpr, DbExpression groupVarBasedKeyExpr, DbExpression groupAggBasedKeyExpr)
4007             {
4008                 Name = name;
4009                 VarRef = varBasedKeyExpr.ResultType.Variable(name);
4010                 VarBasedKeyExpr = varBasedKeyExpr;
4011                 GroupVarBasedKeyExpr = groupVarBasedKeyExpr;
4012                 GroupAggBasedKeyExpr = groupAggBasedKeyExpr;
4013             }
4014
4015             /// <summary>
4016             /// The primary name of the group key. It is used to refer to the key from other expressions.
4017             /// </summary>
4018             internal readonly string Name;
4019
4020             /// <summary>
4021             /// Optional alternative name of the group key. 
4022             /// Used to support the following scenario: 
4023             ///   SELECT Price, p.Price   FROM ... as p GROUP BY p.Price
4024             /// In this case the group key Name is "Price" and the AlternativeName is "p.Price" as if it is coming as an escaped identifier.
4025             /// </summary>
4026             internal string[] AlternativeName
4027             {
4028                 get { return _alternativeName; }
4029                 set
4030                 {
4031                     Debug.Assert(_alternativeName == null, "GroupKeyInfo.AlternativeName can not be reset");
4032                     _alternativeName = value;
4033                 }
4034             }
4035             private string[] _alternativeName;
4036
4037             internal readonly DbVariableReferenceExpression VarRef;
4038
4039             internal readonly DbExpression VarBasedKeyExpr;
4040
4041             internal readonly DbExpression GroupVarBasedKeyExpr;
4042
4043             internal readonly DbExpression GroupAggBasedKeyExpr;
4044         }
4045
4046         /// <summary>
4047         /// Process ORDER BY clause.
4048         /// </summary>
4049         private static DbExpressionBinding ProcessOrderByClause(DbExpressionBinding source, AST.QueryExpr queryExpr, out bool queryProjectionProcessed, SemanticResolver sr)
4050         {
4051             Debug.Assert((sr.ParserOptions.ParserCompilationMode == ParserOptions.CompilationMode.RestrictedViewGenerationMode) ? null == queryExpr.OrderByClause : true, "ORDER BY clause must be null in RestrictedViewGenerationMode");
4052
4053             queryProjectionProcessed = false;
4054
4055             if (queryExpr.OrderByClause == null)
4056             {
4057                 return source;
4058             }
4059
4060             DbExpressionBinding sortBinding = null;
4061             AST.OrderByClause orderByClause = queryExpr.OrderByClause;
4062             AST.SelectClause selectClause = queryExpr.SelectClause;
4063
4064             //
4065             // Convert SKIP sub-clause if exists before adding projection expressions to the scope.
4066             //
4067             DbExpression convertedSkip = null;
4068             #region
4069             if (orderByClause.SkipSubClause != null)
4070             {
4071                 //
4072                 // Convert the skip expression.
4073                 //
4074                 convertedSkip = ConvertValueExpression(orderByClause.SkipSubClause, sr);
4075
4076                 //
4077                 // Ensure the converted expression is in the range of values.
4078                 //
4079                 ValidateExpressionIsCommandParamOrNonNegativeIntegerConstant(convertedSkip, orderByClause.SkipSubClause.ErrCtx, "SKIP", sr);
4080             }
4081             #endregion
4082
4083             //
4084             // Convert SELECT clause items before processing the rest of the ORDER BY clause:
4085             //      - If it is the SELECT DISTINCT case:
4086             //          SELECT clause item definitions will be used to create DbDistinctExpression, which becomes the new source expression.
4087             //          Sort keys can only reference:
4088             //              a. SELECT clause items by their aliases (only these aliases are projected by the new source expression),
4089             //              b. entries from outer scopes.
4090             //      - Otherwise:
4091             //          Sort keys may references any available scope entries, including SELECT clause items.
4092             //          If a sort key references a SELECT clause item, the item _definition_ will be used as the sort key definition (not a variable ref).
4093             //
4094             var projectionItems = ConvertSelectClauseItems(queryExpr, sr);
4095
4096             if (selectClause.DistinctKind == AST.DistinctKind.Distinct)
4097             {
4098                 //
4099                 // SELECT DISTINCT ... ORDER BY case:
4100                 //      - All scope entries created below SELECT DISTINCT are not valid above it in this query, even for error messages, so remove them.
4101                 //      - The scope entries created by SELECT DISTINCT (the SELECT clause items) will be added to a temporary scope in the code below,
4102                 //        this will make them available for sort keys.
4103                 //
4104                 sr.CurrentScopeRegion.RollbackAllScopes();
4105             }
4106
4107             //
4108             // Create temporary scope for SELECT clause items and add the items to the scope.
4109             //
4110             int savedScope = sr.CurrentScopeIndex;
4111             sr.EnterScope();
4112             projectionItems.ForEach(projectionItem => sr.CurrentScope.Add(projectionItem.Key, new ProjectionItemDefinitionScopeEntry(projectionItem.Value)));
4113
4114             //
4115             // Process SELECT DISTINCT ... ORDER BY case:
4116             //      - create projection expression: new Row(SELECT clause item defintions) or just the single SELECT clause item defintion;
4117             //      - create DbDistinctExpression over the projection expression;
4118             //      - set source expression to the binding to the distinct.
4119             //
4120             if (selectClause.DistinctKind == AST.DistinctKind.Distinct)
4121             {
4122                 //
4123                 // Create distinct projection expression and bind to it.
4124                 //
4125                 DbExpression projectExpression = CreateProjectExpression(source, selectClause, projectionItems);
4126                 Debug.Assert(projectExpression is DbDistinctExpression, "projectExpression is DbDistinctExpression");
4127                 source = projectExpression.BindAs(sr.GenerateInternalName("distinct"));
4128
4129                 //
4130                 // Replace SELECT clause item definitions with regular source scope entries pointing into the new source binding.
4131                 //
4132                 if (selectClause.SelectKind == AST.SelectKind.Value)
4133                 {
4134                     Debug.Assert(projectionItems.Count == 1, "projectionItems.Count == 1");
4135                     sr.CurrentScope.Replace(projectionItems[0].Key, new SourceScopeEntry(source.Variable));
4136                 }
4137                 else
4138                 {
4139                     Debug.Assert(selectClause.SelectKind == AST.SelectKind.Row, "selectClause.SelectKind == AST.SelectKind.Row");
4140                     foreach (var projectionExpression in projectionItems)
4141                     {
4142                         DbVariableReferenceExpression projectionExpressionRef = projectionExpression.Value.ResultType.Variable(projectionExpression.Key);
4143
4144                         sr.CurrentScope.Replace(projectionExpressionRef.VariableName,
4145                             new SourceScopeEntry(projectionExpressionRef).AddParentVar(source.Variable));
4146                     }
4147                 }
4148
4149                 //
4150                 // At this point source contains all projected items, so query processing is mostly complete,
4151                 // the only task remaining is processing of TOP/LIMIT subclauses, which happens in ProcessSelectClause(...) method.
4152                 //
4153                 queryProjectionProcessed = true;
4154             }
4155
4156             //
4157             // Convert sort keys.
4158             //
4159             List<DbSortClause> sortKeys = new List<DbSortClause>(orderByClause.OrderByClauseItem.Count);
4160             #region
4161             for (int i = 0; i < orderByClause.OrderByClauseItem.Count; i++)
4162             {
4163                 AST.OrderByClauseItem orderClauseItem = orderByClause.OrderByClauseItem[i];
4164
4165                 sr.CurrentScopeRegion.WasResolutionCorrelated = false;
4166
4167                 //
4168                 // Convert order key expression.
4169                 //
4170                 DbExpression keyExpr = ConvertValueExpression(orderClauseItem.OrderExpr, sr);
4171
4172                 //
4173                 // Ensure key expression is correlated.
4174                 //
4175                 if (!sr.CurrentScopeRegion.WasResolutionCorrelated)
4176                 {
4177                     throw EntityUtil.EntitySqlError(orderClauseItem.ErrCtx, Strings.KeyMustBeCorrelated("ORDER BY"));
4178                 }
4179
4180                 //
4181                 // Ensure key is order comparable.
4182                 //
4183                 if (!TypeHelpers.IsValidSortOpKeyType(keyExpr.ResultType))
4184                 {
4185                     throw EntityUtil.EntitySqlError(orderClauseItem.OrderExpr.ErrCtx, Strings.OrderByKeyIsNotOrderComparable);
4186                 }
4187
4188                 //
4189                 // Convert order direction.
4190                 //
4191                 bool ascSort = (orderClauseItem.OrderKind == AST.OrderKind.None) || (orderClauseItem.OrderKind == AST.OrderKind.Asc);
4192
4193                 //
4194                 // Convert collation.
4195                 //
4196                 string collation = null;
4197                 if (orderClauseItem.Collation != null)
4198                 {
4199                     if (!IsStringType(keyExpr.ResultType))
4200                     {
4201                         throw EntityUtil.EntitySqlError(orderClauseItem.OrderExpr.ErrCtx, Strings.InvalidKeyTypeForCollation(keyExpr.ResultType.EdmType.FullName));
4202                     }
4203
4204                     collation = orderClauseItem.Collation.Name;
4205                 }
4206
4207                 //
4208                 // Finish key conversion and add converted keys to key collection.
4209                 //
4210                 if (string.IsNullOrEmpty(collation))
4211                 {
4212                     sortKeys.Add(ascSort ? keyExpr.ToSortClause() : keyExpr.ToSortClauseDescending());
4213                 }
4214                 else
4215                 {
4216                     sortKeys.Add(ascSort ? keyExpr.ToSortClause(collation) : keyExpr.ToSortClauseDescending(collation));
4217                 }
4218             }
4219             #endregion
4220
4221             //
4222             // Remove the temporary projection scope with all the SELECT clause items on it.
4223             //
4224             sr.RollbackToScope(savedScope);
4225
4226             //
4227             // Create sort expression.
4228             //
4229             DbExpression sortSourceExpr = null;
4230             if (convertedSkip != null)
4231             {
4232                 sortSourceExpr = source.Skip(sortKeys, convertedSkip);
4233             }
4234             else
4235             {
4236                 sortSourceExpr = source.Sort(sortKeys);
4237             }
4238
4239             //
4240             // Create Sort Binding.
4241             //
4242             sortBinding = sortSourceExpr.BindAs(sr.GenerateInternalName("sort"));
4243
4244             //
4245             // Fixup Bindings.
4246             //
4247             if (queryProjectionProcessed)
4248             {
4249                 Debug.Assert(sr.CurrentScopeIndex < sr.CurrentScopeRegion.FirstScopeIndex, "Current scope region is expected to have no scopes.");
4250
4251                 /*
4252                  * The following code illustrates definition of the projected output in the case of DISTINCT ORDER BY.
4253                  * There is nothing above this point that should reference any scope entries produced by this query, 
4254                  * so we do not really add them to the scope region (hence the code is commented out).
4255                  * 
4256
4257                 //
4258                 // All the scopes of this current scope region have been rolled back.
4259                 // Add new scope with all the projected items on it.
4260                 //
4261                 sr.EnterScope();
4262                 if (selectClause.SelectKind == AST.SelectKind.SelectRow)
4263                 {
4264                     foreach (var projectionExpression in projectionItems)
4265                     {
4266                         DbVariableReferenceExpression projectionExpressionRef = projectionExpression.Value.ResultType.Variable(projectionExpression.Key);
4267                         sr.CurrentScope.Add(projectionExpressionRef.VariableName, 
4268                             new SourceScopeEntry(projectionExpressionRef).AddParentVar(sortBinding.Variable));
4269                     }
4270                 }
4271                 else
4272                 {
4273                     Debug.Assert(selectClause.SelectKind == AST.SelectKind.SelectValue, "selectClause.SelectKind == AST.SelectKind.SelectValue");
4274                     Debug.Assert(projectionItems.Count == 1, "projectionItems.Count == 1");
4275
4276                     sr.CurrentScope.Add(projectionItems[0].Key, new SourceScopeEntry(sortBinding.Variable));
4277                 }*/
4278             }
4279             else
4280             {
4281                 sr.CurrentScopeRegion.ApplyToScopeEntries(scopeEntry =>
4282                 {
4283                     Debug.Assert(scopeEntry.EntryKind == ScopeEntryKind.SourceVar || scopeEntry.EntryKind == ScopeEntryKind.InvalidGroupInputRef,
4284                         "scopeEntry.EntryKind == ScopeEntryKind.SourceVar || scopeEntry.EntryKind == ScopeEntryKind.InvalidGroupInputRef");
4285
4286                     if (scopeEntry.EntryKind == ScopeEntryKind.SourceVar)
4287                     {
4288                         ((SourceScopeEntry)scopeEntry).ReplaceParentVar(sortBinding.Variable);
4289                     }
4290                 });
4291             }
4292
4293             Debug.Assert(null != sortBinding, "null != sortBinding");
4294
4295             return sortBinding;
4296         }
4297
4298         /// <summary>
4299         /// Convert "x in multiset(y1, y2, ..., yn)" into
4300         /// x = y1 or x = y2 or x = y3 ...
4301         /// </summary>
4302         /// <param name="sr">semantic resolver</param>
4303         /// <param name="left">left-expression (the probe)</param>
4304         /// <param name="right">right expression (the collection)</param>
4305         /// <returns>Or tree of equality comparisons</returns>
4306         private static DbExpression ConvertSimpleInExpression(SemanticResolver sr, DbExpression left, DbExpression right)
4307         {
4308             // Only handle cases when the right-side is a new instance expression
4309             Debug.Assert(right.ExpressionKind == DbExpressionKind.NewInstance, "right.ExpressionKind == DbExpressionKind.NewInstance");
4310             DbNewInstanceExpression rightColl = (DbNewInstanceExpression)right;
4311
4312             if (rightColl.Arguments.Count == 0)
4313             {
4314                 return DbExpressionBuilder.False;
4315             }
4316
4317             var predicates = rightColl.Arguments.Select(arg => left.Equal(arg));
4318             List<DbExpression> args = new List<DbExpression>(predicates);
4319             DbExpression orExpr = Utils.Helpers.BuildBalancedTreeInPlace(args, (prev, next) => prev.Or(next));
4320
4321             return orExpr;
4322         }
4323
4324         private static bool IsStringType(TypeUsage type)
4325         {
4326             return TypeSemantics.IsPrimitiveType(type, PrimitiveTypeKind.String);
4327         }
4328
4329         private static bool IsBooleanType(TypeUsage type)
4330         {
4331             return TypeSemantics.IsPrimitiveType(type, PrimitiveTypeKind.Boolean);
4332         }
4333
4334         private static bool IsSubOrSuperType(TypeUsage type1, TypeUsage type2)
4335         {
4336             return TypeSemantics.IsStructurallyEqual(type1, type2) || type1.IsSubtypeOf(type2) || type2.IsSubtypeOf(type1);
4337         }
4338
4339         #region Expression converters
4340
4341         private delegate ExpressionResolution AstExprConverter(AST.Node astExpr, SemanticResolver sr);
4342         private static readonly Dictionary<Type, AstExprConverter> _astExprConverters = CreateAstExprConverters();
4343         private delegate DbExpression BuiltInExprConverter(AST.BuiltInExpr astBltInExpr, SemanticResolver sr);
4344         private static readonly Dictionary<AST.BuiltInKind, BuiltInExprConverter> _builtInExprConverter = CreateBuiltInExprConverter();
4345
4346         private static Dictionary<Type, AstExprConverter> CreateAstExprConverters()
4347         {
4348             const int NumberOfElements = 17;  // number of elements initialized by the dictionary
4349             Dictionary<Type, AstExprConverter> astExprConverters = new Dictionary<Type, AstExprConverter>(NumberOfElements);
4350             astExprConverters.Add(typeof(AST.Literal), new AstExprConverter(ConvertLiteral));
4351             astExprConverters.Add(typeof(AST.QueryParameter), new AstExprConverter(ConvertParameter));
4352             astExprConverters.Add(typeof(AST.Identifier), new AstExprConverter(ConvertIdentifier));
4353             astExprConverters.Add(typeof(AST.DotExpr), new AstExprConverter(ConvertDotExpr));
4354             astExprConverters.Add(typeof(AST.BuiltInExpr), new AstExprConverter(ConvertBuiltIn));
4355             astExprConverters.Add(typeof(AST.QueryExpr), new AstExprConverter(ConvertQueryExpr));
4356             astExprConverters.Add(typeof(AST.ParenExpr), new AstExprConverter(ConvertParenExpr));
4357             astExprConverters.Add(typeof(AST.RowConstructorExpr), new AstExprConverter(ConvertRowConstructor));
4358             astExprConverters.Add(typeof(AST.MultisetConstructorExpr), new AstExprConverter(ConvertMultisetConstructor));
4359             astExprConverters.Add(typeof(AST.CaseExpr), new AstExprConverter(ConvertCaseExpr));
4360             astExprConverters.Add(typeof(AST.RelshipNavigationExpr), new AstExprConverter(ConvertRelshipNavigationExpr));
4361             astExprConverters.Add(typeof(AST.RefExpr), new AstExprConverter(ConvertRefExpr));
4362             astExprConverters.Add(typeof(AST.DerefExpr), new AstExprConverter(ConvertDeRefExpr));
4363             astExprConverters.Add(typeof(AST.MethodExpr), new AstExprConverter(ConvertMethodExpr));
4364             astExprConverters.Add(typeof(AST.CreateRefExpr), new AstExprConverter(ConvertCreateRefExpr));
4365             astExprConverters.Add(typeof(AST.KeyExpr), new AstExprConverter(ConvertKeyExpr));
4366             astExprConverters.Add(typeof(AST.GroupPartitionExpr), new AstExprConverter(ConvertGroupPartitionExpr));
4367             Debug.Assert(NumberOfElements == astExprConverters.Count, "The number of elements and initial capacity don't match");
4368             return astExprConverters;
4369         }
4370
4371         private static Dictionary<AST.BuiltInKind, BuiltInExprConverter> CreateBuiltInExprConverter()
4372         {
4373             Dictionary<AST.BuiltInKind, BuiltInExprConverter> builtInExprConverter = new Dictionary<AST.BuiltInKind, BuiltInExprConverter>(sizeof(AST.BuiltInKind));
4374
4375             ////////////////////////////
4376             // Arithmetic Expressions
4377             ////////////////////////////
4378
4379             //
4380             // e1 + e2
4381             //
4382             #region e1 + e2
4383             builtInExprConverter.Add(AST.BuiltInKind.Plus, delegate(AST.BuiltInExpr bltInExpr, SemanticResolver sr)
4384             {
4385                 Pair<DbExpression, DbExpression> args = ConvertPlusOperands(bltInExpr, sr);
4386
4387                 if (TypeSemantics.IsNumericType(args.Left.ResultType))
4388                 {
4389                     return args.Left.Plus(args.Right);
4390                 }
4391                 else
4392                 {
4393                     //
4394                     // fold '+' operator into concat canonical function
4395                     //
4396                     MetadataFunctionGroup function;
4397                     if (!sr.TypeResolver.TryGetFunctionFromMetadata("Edm", "Concat", out function))
4398                     {
4399                         throw EntityUtil.EntitySqlError(bltInExpr.ErrCtx, Strings.ConcatBuiltinNotSupported);
4400                     }
4401
4402                     List<TypeUsage> argTypes = new List<TypeUsage>(2);
4403                     argTypes.Add(args.Left.ResultType);
4404                     argTypes.Add(args.Right.ResultType);
4405
4406                     bool isAmbiguous = false;
4407                     EdmFunction concatFunction = SemanticResolver.ResolveFunctionOverloads(
4408                         function.FunctionMetadata,
4409                         argTypes,
4410                         false /* isGroupAggregate */,
4411                         out isAmbiguous);
4412
4413                     if (null == concatFunction || isAmbiguous)
4414                     {
4415                         throw EntityUtil.EntitySqlError(bltInExpr.ErrCtx, Strings.ConcatBuiltinNotSupported);
4416                     }
4417
4418                     return concatFunction.Invoke(new[] { args.Left, args.Right });
4419                 }
4420
4421             });
4422             #endregion
4423
4424             //
4425             // e1 - e2
4426             //
4427             #region e1 - e2
4428             builtInExprConverter.Add(AST.BuiltInKind.Minus, delegate(AST.BuiltInExpr bltInExpr, SemanticResolver sr)
4429             {
4430                 Pair<DbExpression, DbExpression> args = ConvertArithmeticArgs(bltInExpr, sr);
4431
4432                 return args.Left.Minus(args.Right);
4433             });
4434             #endregion
4435
4436             //
4437             // e1 * e2
4438             //
4439             #region e1 * e2
4440             builtInExprConverter.Add(AST.BuiltInKind.Multiply, delegate(AST.BuiltInExpr bltInExpr, SemanticResolver sr)
4441             {
4442                 Pair<DbExpression, DbExpression> args = ConvertArithmeticArgs(bltInExpr, sr);
4443
4444                 return args.Left.Multiply(args.Right);
4445             });
4446             #endregion
4447
4448             //
4449             // e1 / e2
4450             //
4451             #region e1 / e2
4452             builtInExprConverter.Add(AST.BuiltInKind.Divide, delegate(AST.BuiltInExpr bltInExpr, SemanticResolver sr)
4453             {
4454                 Pair<DbExpression, DbExpression> args = ConvertArithmeticArgs(bltInExpr, sr);
4455
4456                 return args.Left.Divide(args.Right);
4457             });
4458             #endregion
4459
4460             //
4461             // e1 % e2
4462             //
4463             #region e1 % e2
4464             builtInExprConverter.Add(AST.BuiltInKind.Modulus, delegate(AST.BuiltInExpr bltInExpr, SemanticResolver sr)
4465             {
4466                 Pair<DbExpression, DbExpression> args = ConvertArithmeticArgs(bltInExpr, sr);
4467
4468                 return args.Left.Modulo(args.Right);
4469             });
4470             #endregion
4471
4472             //
4473             // - e
4474             //
4475             #region - e
4476             builtInExprConverter.Add(AST.BuiltInKind.UnaryMinus, delegate(AST.BuiltInExpr bltInExpr, SemanticResolver sr)
4477             {
4478                 DbExpression argument = ConvertArithmeticArgs(bltInExpr, sr).Left;
4479                 if (TypeSemantics.IsUnsignedNumericType(argument.ResultType))
4480                 {
4481                     TypeUsage closestPromotableType = null;
4482                     if (!TypeHelpers.TryGetClosestPromotableType(argument.ResultType, out closestPromotableType))
4483                     {
4484                         throw EntityUtil.EntitySqlError(Strings.InvalidUnsignedTypeForUnaryMinusOperation(argument.ResultType.EdmType.FullName));
4485                     }
4486                 }
4487
4488                 DbExpression unaryExpr = argument.UnaryMinus();
4489                 return unaryExpr;
4490             });
4491             #endregion
4492
4493             //
4494             // + e
4495             //
4496             #region + e
4497             builtInExprConverter.Add(AST.BuiltInKind.UnaryPlus, delegate(AST.BuiltInExpr bltInExpr, SemanticResolver sr)
4498             {
4499                 return ConvertArithmeticArgs(bltInExpr, sr).Left;
4500             });
4501             #endregion
4502
4503             ////////////////////////////
4504             // Logical Expressions
4505             ////////////////////////////
4506
4507             //
4508             // e1 AND e2
4509             // e1 && e2
4510             //
4511             #region e1 AND e2
4512             builtInExprConverter.Add(AST.BuiltInKind.And, delegate(AST.BuiltInExpr bltInExpr, SemanticResolver sr)
4513             {
4514                 Pair<DbExpression, DbExpression> args = SemanticAnalyzer.ConvertLogicalArgs(bltInExpr, sr);
4515
4516                 return args.Left.And(args.Right);
4517             });
4518             #endregion
4519
4520             //
4521             // e1 OR e2
4522             // e1 || e2
4523             //
4524             #region e1 OR e2
4525             builtInExprConverter.Add(AST.BuiltInKind.Or, delegate(AST.BuiltInExpr bltInExpr, SemanticResolver sr)
4526             {
4527                 Pair<DbExpression, DbExpression> args = SemanticAnalyzer.ConvertLogicalArgs(bltInExpr, sr);
4528
4529                 return args.Left.Or(args.Right);
4530             });
4531             #endregion
4532
4533             //
4534             // NOT e
4535             // ! e
4536             //
4537             #region NOT e
4538             builtInExprConverter.Add(AST.BuiltInKind.Not, delegate(AST.BuiltInExpr bltInExpr, SemanticResolver sr)
4539             {
4540                 return ConvertLogicalArgs(bltInExpr, sr).Left.Not();
4541             });
4542             #endregion
4543
4544             ////////////////////////////
4545             // Comparison Expressions
4546             ////////////////////////////
4547
4548             //
4549             // e1 == e2 | e1 = e2
4550             //
4551             #region e1 == e2
4552             builtInExprConverter.Add(AST.BuiltInKind.Equal, delegate(AST.BuiltInExpr bltInExpr, SemanticResolver sr)
4553             {
4554                 Pair<DbExpression, DbExpression> args = ConvertEqualCompArgs(bltInExpr, sr);
4555
4556                 return args.Left.Equal(args.Right);
4557             });
4558             #endregion
4559
4560             //
4561             // e1 != e2 | e1 <> e2
4562             //
4563             #region e1 != e2
4564             builtInExprConverter.Add(AST.BuiltInKind.NotEqual, delegate(AST.BuiltInExpr bltInExpr, SemanticResolver sr)
4565             {
4566                 Pair<DbExpression, DbExpression> args = ConvertEqualCompArgs(bltInExpr, sr);
4567
4568                 // 
4569
4570                 return args.Left.Equal(args.Right).Not();
4571             });
4572             #endregion
4573
4574             //
4575             // e1 >= e2
4576             //
4577             #region e1 >= e2
4578             builtInExprConverter.Add(AST.BuiltInKind.GreaterEqual, delegate(AST.BuiltInExpr bltInExpr, SemanticResolver sr)
4579             {
4580                 Pair<DbExpression, DbExpression> args = ConvertOrderCompArgs(bltInExpr, sr);
4581
4582                 return args.Left.GreaterThanOrEqual(args.Right);
4583             });
4584             #endregion
4585
4586             //
4587             // e1 > e2
4588             //
4589             #region e1 > e2
4590             builtInExprConverter.Add(AST.BuiltInKind.GreaterThan, delegate(AST.BuiltInExpr bltInExpr, SemanticResolver sr)
4591             {
4592                 Pair<DbExpression, DbExpression> args = ConvertOrderCompArgs(bltInExpr, sr);
4593
4594                 return args.Left.GreaterThan(args.Right);
4595             });
4596             #endregion
4597
4598             //
4599             // e1 <= e2
4600             //
4601             #region e1 <= e2
4602             builtInExprConverter.Add(AST.BuiltInKind.LessEqual, delegate(AST.BuiltInExpr bltInExpr, SemanticResolver sr)
4603             {
4604                 Pair<DbExpression, DbExpression> args = ConvertOrderCompArgs(bltInExpr, sr);
4605
4606                 return args.Left.LessThanOrEqual(args.Right);
4607             });
4608             #endregion
4609
4610             //
4611             // e1 < e2
4612             //
4613             #region e1 < e2
4614             builtInExprConverter.Add(AST.BuiltInKind.LessThan, delegate(AST.BuiltInExpr bltInExpr, SemanticResolver sr)
4615             {
4616                 Pair<DbExpression, DbExpression> args = ConvertOrderCompArgs(bltInExpr, sr);
4617
4618                 return args.Left.LessThan(args.Right);
4619             });
4620             #endregion
4621
4622
4623             ////////////////////////////
4624             //    SET EXPRESSIONS
4625             ////////////////////////////
4626
4627
4628             //
4629             // e1 UNION e2
4630             //
4631             #region e1 UNION e2
4632             builtInExprConverter.Add(AST.BuiltInKind.Union, delegate(AST.BuiltInExpr bltInExpr, SemanticResolver sr)
4633             {
4634                 Pair<DbExpression, DbExpression> args = ConvertSetArgs(bltInExpr, sr);
4635
4636                 return args.Left.UnionAll(args.Right).Distinct();
4637             });
4638             #endregion
4639
4640             //
4641             // e1 UNION ALL e2
4642             //
4643             #region e1 UNION ALL e2
4644             builtInExprConverter.Add(AST.BuiltInKind.UnionAll, delegate(AST.BuiltInExpr bltInExpr, SemanticResolver sr)
4645             {
4646                 Pair<DbExpression, DbExpression> args = ConvertSetArgs(bltInExpr, sr);
4647
4648                 return args.Left.UnionAll(args.Right);
4649             });
4650             #endregion
4651
4652             //
4653             // e1 INTERSECT e2
4654             //
4655             #region e1 INTERSECT e2
4656             builtInExprConverter.Add(AST.BuiltInKind.Intersect, delegate(AST.BuiltInExpr bltInExpr, SemanticResolver sr)
4657             {
4658                 Pair<DbExpression, DbExpression> args = ConvertSetArgs(bltInExpr, sr);
4659
4660                 return args.Left.Intersect(args.Right);
4661             });
4662             #endregion
4663
4664             //
4665             // e1 OVERLAPS e2
4666             //
4667             #region e1 OVERLAPS e1
4668             builtInExprConverter.Add(AST.BuiltInKind.Overlaps, delegate(AST.BuiltInExpr bltInExpr, SemanticResolver sr)
4669             {
4670                 Pair<DbExpression, DbExpression> args = ConvertSetArgs(bltInExpr, sr);
4671
4672                 return args.Left.Intersect(args.Right).IsEmpty().Not();
4673             });
4674             #endregion
4675
4676             //
4677             // ANYELEMENT( e )
4678             //
4679             #region ANYELEMENT( e )
4680             builtInExprConverter.Add(AST.BuiltInKind.AnyElement, delegate(AST.BuiltInExpr bltInExpr, SemanticResolver sr)
4681             {
4682                 return ConvertSetArgs(bltInExpr, sr).Left.Element();
4683             });
4684             #endregion
4685
4686             //
4687             // ELEMENT( e )
4688             //
4689             #region ELEMENT( e ) - NOT SUPPORTED IN ORCAS TIMEFRAME
4690             builtInExprConverter.Add(AST.BuiltInKind.Element, delegate(AST.BuiltInExpr bltInExpr, SemanticResolver sr)
4691             {
4692                 throw EntityUtil.NotSupported(Strings.ElementOperatorIsNotSupported);
4693             });
4694             #endregion
4695
4696             //
4697             // e1 EXCEPT e2
4698             //
4699             #region e1 EXCEPT e2
4700             builtInExprConverter.Add(AST.BuiltInKind.Except, delegate(AST.BuiltInExpr bltInExpr, SemanticResolver sr)
4701             {
4702                 Pair<DbExpression, DbExpression> args = ConvertSetArgs(bltInExpr, sr);
4703
4704                 return args.Left.Except(args.Right);
4705             });
4706             #endregion
4707
4708             //
4709             // EXISTS( e )
4710             //
4711             #region EXISTS( e )
4712             builtInExprConverter.Add(AST.BuiltInKind.Exists, delegate(AST.BuiltInExpr bltInExpr, SemanticResolver sr)
4713             {
4714                 return ConvertSetArgs(bltInExpr, sr).Left.IsEmpty().Not();
4715             });
4716             #endregion
4717
4718             //
4719             // FLATTEN( e )
4720             //
4721             #region FLATTEN( e )
4722             builtInExprConverter.Add(AST.BuiltInKind.Flatten, delegate(AST.BuiltInExpr bltInExpr, SemanticResolver sr)
4723             {
4724                 DbExpression elemExpr = ConvertValueExpression(bltInExpr.Arg1, sr);
4725
4726                 if (!TypeSemantics.IsCollectionType(elemExpr.ResultType))
4727                 {
4728                     throw EntityUtil.EntitySqlError(bltInExpr.Arg1.ErrCtx, Strings.InvalidFlattenArgument);
4729                 }
4730
4731                 if (!TypeSemantics.IsCollectionType(TypeHelpers.GetElementTypeUsage(elemExpr.ResultType)))
4732                 {
4733                     throw EntityUtil.EntitySqlError(bltInExpr.Arg1.ErrCtx, Strings.InvalidFlattenArgument);
4734                 }
4735
4736                 DbExpressionBinding leftExpr = elemExpr.BindAs(sr.GenerateInternalName("l_flatten"));
4737
4738                 DbExpressionBinding rightExpr = leftExpr.Variable.BindAs(sr.GenerateInternalName("r_flatten"));
4739
4740                 DbExpressionBinding applyBinding = leftExpr.CrossApply(rightExpr).BindAs(sr.GenerateInternalName("flatten"));
4741
4742                 return applyBinding.Project(applyBinding.Variable.Property(rightExpr.VariableName));
4743             });
4744             #endregion
4745
4746             //
4747             // e1 IN e2
4748             //
4749             #region e1 IN e2
4750             builtInExprConverter.Add(AST.BuiltInKind.In, delegate(AST.BuiltInExpr bltInExpr, SemanticResolver sr)
4751             {
4752                 Pair<DbExpression, DbExpression> args = ConvertInExprArgs(bltInExpr, sr);
4753
4754                 //
4755                 // Convert "x in multiset(y1, y2, ..., yn)" into x = y1 or x = y2 or x = y3 ...
4756                 //
4757                 if (args.Right.ExpressionKind == DbExpressionKind.NewInstance)
4758                 {
4759                     return ConvertSimpleInExpression(sr, args.Left, args.Right);
4760                 }
4761                 else
4762                 {
4763                     DbExpressionBinding rSet = args.Right.BindAs(sr.GenerateInternalName("in-filter"));
4764
4765                     DbExpression leftIn = args.Left;
4766                     DbExpression rightSet = rSet.Variable;
4767
4768                     DbExpression exists = rSet.Filter(leftIn.Equal(rightSet)).IsEmpty().Not();
4769
4770                     List<DbExpression> whenExpr = new List<DbExpression>(1);
4771                     whenExpr.Add(leftIn.IsNull());
4772                     List<DbExpression> thenExpr = new List<DbExpression>(1);
4773                     thenExpr.Add(DbExpressionBuilder.Null(sr.TypeResolver.BooleanType));
4774
4775                     DbExpression left = DbExpressionBuilder.Case(whenExpr, thenExpr, DbExpressionBuilder.False);
4776
4777                     DbExpression converted = left.Or(exists);
4778
4779                     return converted;
4780                 }
4781             });
4782             #endregion
4783
4784             //
4785             // e1 NOT IN e1
4786             //
4787             #region e1 NOT IN e1
4788             builtInExprConverter.Add(AST.BuiltInKind.NotIn, delegate(AST.BuiltInExpr bltInExpr, SemanticResolver sr)
4789             {
4790                 Pair<DbExpression, DbExpression> args = ConvertInExprArgs(bltInExpr, sr);
4791
4792                 if (args.Right.ExpressionKind == DbExpressionKind.NewInstance)
4793                 {
4794                     return ConvertSimpleInExpression(sr, args.Left, args.Right).Not();
4795                 }
4796                 else
4797                 {
4798                     DbExpressionBinding rSet = args.Right.BindAs(sr.GenerateInternalName("in-filter"));
4799
4800                     DbExpression leftIn = args.Left;
4801                     DbExpression rightSet = rSet.Variable;
4802
4803                     DbExpression exists = rSet.Filter(leftIn.Equal(rightSet)).IsEmpty();
4804
4805                     List<DbExpression> whenExpr = new List<DbExpression>(1);
4806                     whenExpr.Add(leftIn.IsNull());
4807                     List<DbExpression> thenExpr = new List<DbExpression>(1);
4808                     thenExpr.Add(DbExpressionBuilder.Null(sr.TypeResolver.BooleanType));
4809
4810                     DbExpression left = DbExpressionBuilder.Case(whenExpr, thenExpr, DbExpressionBuilder.True);
4811
4812                     DbExpression converted = left.And(exists);
4813
4814                     return converted;
4815                 }
4816             });
4817             #endregion
4818
4819             //
4820             // SET( e ) - DISTINCT( e ) before
4821             //
4822             #region SET( e )
4823             builtInExprConverter.Add(AST.BuiltInKind.Distinct, delegate(AST.BuiltInExpr bltInExpr, SemanticResolver sr)
4824             {
4825                 Pair<DbExpression, DbExpression> args = ConvertSetArgs(bltInExpr, sr);
4826
4827                 return args.Left.Distinct();
4828             });
4829             #endregion
4830
4831
4832             ////////////////////////////
4833             // Nullabity Expressions
4834             ////////////////////////////
4835
4836             //
4837             // e IS NULL
4838             //
4839             #region e IS NULL
4840             builtInExprConverter.Add(AST.BuiltInKind.IsNull, delegate(AST.BuiltInExpr bltInExpr, SemanticResolver sr)
4841             {
4842                 DbExpression isNullExpr = ConvertValueExpressionAllowUntypedNulls(bltInExpr.Arg1, sr);
4843
4844                 //
4845                 // Ensure expression type is valid for this operation.
4846                 //
4847                 if (isNullExpr != null && !TypeHelpers.IsValidIsNullOpType(isNullExpr.ResultType))
4848                 {
4849                     throw EntityUtil.EntitySqlError(bltInExpr.Arg1.ErrCtx, Strings.IsNullInvalidType);
4850                 }
4851
4852                 return isNullExpr != null ? (DbExpression)isNullExpr.IsNull() : DbExpressionBuilder.True;
4853             });
4854             #endregion
4855
4856             //
4857             // e IS NOT NULL
4858             //
4859             #region e IS NOT NULL
4860             builtInExprConverter.Add(AST.BuiltInKind.IsNotNull, delegate(AST.BuiltInExpr bltInExpr, SemanticResolver sr)
4861             {
4862                 DbExpression isNullExpr = ConvertValueExpressionAllowUntypedNulls(bltInExpr.Arg1, sr);
4863
4864                 //
4865                 // Ensure expression type is valid for this operation.
4866                 //
4867                 if (isNullExpr != null && !TypeHelpers.IsValidIsNullOpType(isNullExpr.ResultType))
4868                 {
4869                     throw EntityUtil.EntitySqlError(bltInExpr.Arg1.ErrCtx, Strings.IsNullInvalidType);
4870                 }
4871
4872                 return isNullExpr != null ? (DbExpression)isNullExpr.IsNull().Not() : DbExpressionBuilder.False;
4873             });
4874             #endregion
4875
4876             ////////////////////////////
4877             //    Type Expressions
4878             ////////////////////////////
4879
4880             //
4881             // e IS OF ( [ONLY] T )
4882             //
4883             #region e IS OF ( [ONLY] T )
4884             builtInExprConverter.Add(AST.BuiltInKind.IsOf, delegate(AST.BuiltInExpr bltInExpr, SemanticResolver sr)
4885             {
4886                 var exprToFilter = ConvertValueExpression(bltInExpr.Arg1, sr);
4887                 var typeToFilterTo = ConvertTypeName(bltInExpr.Arg2, sr);
4888
4889                 bool isOnly = (bool)((AST.Literal)bltInExpr.Arg3).Value;
4890                 bool isNot = (bool)((AST.Literal)bltInExpr.Arg4).Value;
4891                 bool isNominalTypeAllowed = sr.ParserOptions.ParserCompilationMode == ParserOptions.CompilationMode.RestrictedViewGenerationMode;
4892
4893                 if (!isNominalTypeAllowed && !TypeSemantics.IsEntityType(exprToFilter.ResultType))
4894                 {
4895                     throw EntityUtil.EntitySqlError(bltInExpr.Arg1.ErrCtx,
4896                         Strings.ExpressionTypeMustBeEntityType(Strings.CtxIsOf,
4897                                                                exprToFilter.ResultType.EdmType.BuiltInTypeKind.ToString(),
4898                                                                exprToFilter.ResultType.EdmType.FullName));
4899                 }
4900                 else if (isNominalTypeAllowed && !TypeSemantics.IsNominalType(exprToFilter.ResultType))
4901                 {
4902                     throw EntityUtil.EntitySqlError(bltInExpr.Arg1.ErrCtx,
4903                         Strings.ExpressionTypeMustBeNominalType(Strings.CtxIsOf,
4904                                                                 exprToFilter.ResultType.EdmType.BuiltInTypeKind.ToString(),
4905                                                                 exprToFilter.ResultType.EdmType.FullName));
4906                 }
4907
4908                 if (!isNominalTypeAllowed && !TypeSemantics.IsEntityType(typeToFilterTo))
4909                 {
4910                     throw EntityUtil.EntitySqlError(bltInExpr.Arg2.ErrCtx, Strings.TypeMustBeEntityType(Strings.CtxIsOf,
4911                                                                                                         typeToFilterTo.EdmType.BuiltInTypeKind.ToString(),
4912                                                                                                         typeToFilterTo.EdmType.FullName));
4913                 }
4914                 else if (isNominalTypeAllowed && !TypeSemantics.IsNominalType(typeToFilterTo))
4915                 {
4916                     throw EntityUtil.EntitySqlError(bltInExpr.Arg2.ErrCtx, Strings.TypeMustBeNominalType(Strings.CtxIsOf,
4917                                                                                                          typeToFilterTo.EdmType.BuiltInTypeKind.ToString(),
4918                                                                                                          typeToFilterTo.EdmType.FullName));
4919                 }
4920
4921                 if (!TypeSemantics.IsPolymorphicType(exprToFilter.ResultType))
4922                 {
4923                     throw EntityUtil.EntitySqlError(bltInExpr.Arg1.ErrCtx, Strings.TypeMustBeInheritableType);
4924                 }
4925
4926                 if (!TypeSemantics.IsPolymorphicType(typeToFilterTo))
4927                 {
4928                     throw EntityUtil.EntitySqlError(bltInExpr.Arg2.ErrCtx, Strings.TypeMustBeInheritableType);
4929                 }
4930
4931                 if (!IsSubOrSuperType(exprToFilter.ResultType, typeToFilterTo))
4932                 {
4933                     throw EntityUtil.EntitySqlError(bltInExpr.ErrCtx, Strings.NotASuperOrSubType(exprToFilter.ResultType.EdmType.FullName,
4934                                                                                                  typeToFilterTo.EdmType.FullName));
4935                 }
4936
4937                 typeToFilterTo = TypeHelpers.GetReadOnlyType(typeToFilterTo);
4938
4939                 DbExpression retExpr = null;
4940                 if (isOnly)
4941                 {
4942                     retExpr = exprToFilter.IsOfOnly(typeToFilterTo);
4943                 }
4944                 else
4945                 {
4946                     retExpr = exprToFilter.IsOf(typeToFilterTo);
4947                 }
4948
4949                 if (isNot)
4950                 {
4951                     retExpr = retExpr.Not();
4952                 }
4953
4954                 return retExpr;
4955             });
4956             #endregion
4957
4958             //
4959             // TREAT( e as T )
4960             //
4961             #region TREAT( e as T )
4962             builtInExprConverter.Add(AST.BuiltInKind.Treat, delegate(AST.BuiltInExpr bltInExpr, SemanticResolver sr)
4963             {
4964                 var exprToTreat = ConvertValueExpressionAllowUntypedNulls(bltInExpr.Arg1, sr);
4965                 var typeToTreatTo = ConvertTypeName(bltInExpr.Arg2, sr);
4966
4967                 bool isNominalTypeAllowed = sr.ParserOptions.ParserCompilationMode == ParserOptions.CompilationMode.RestrictedViewGenerationMode;
4968
4969                 if (!isNominalTypeAllowed && !TypeSemantics.IsEntityType(typeToTreatTo))
4970                 {
4971                     throw EntityUtil.EntitySqlError(bltInExpr.Arg2.ErrCtx,
4972                         Strings.TypeMustBeEntityType(Strings.CtxTreat,
4973                                                      typeToTreatTo.EdmType.BuiltInTypeKind.ToString(),
4974                                                      typeToTreatTo.EdmType.FullName));
4975                 }
4976                 else if (isNominalTypeAllowed && !TypeSemantics.IsNominalType(typeToTreatTo))
4977                 {
4978                     throw EntityUtil.EntitySqlError(bltInExpr.Arg2.ErrCtx,
4979                         Strings.TypeMustBeNominalType(Strings.CtxTreat,
4980                                                       typeToTreatTo.EdmType.BuiltInTypeKind.ToString(),
4981                                                       typeToTreatTo.EdmType.FullName));
4982                 }
4983
4984                 if (exprToTreat == null)
4985                 {
4986                     exprToTreat = DbExpressionBuilder.Null(typeToTreatTo);
4987                 }
4988                 else if (!isNominalTypeAllowed && !TypeSemantics.IsEntityType(exprToTreat.ResultType))
4989                 {
4990                     throw EntityUtil.EntitySqlError(bltInExpr.Arg1.ErrCtx,
4991                         Strings.ExpressionTypeMustBeEntityType(Strings.CtxTreat,
4992                                                                exprToTreat.ResultType.EdmType.BuiltInTypeKind.ToString(),
4993                                                                exprToTreat.ResultType.EdmType.FullName));
4994                 }
4995                 else if (isNominalTypeAllowed && !TypeSemantics.IsNominalType(exprToTreat.ResultType))
4996                 {
4997                     throw EntityUtil.EntitySqlError(bltInExpr.Arg1.ErrCtx,
4998                         Strings.ExpressionTypeMustBeNominalType(Strings.CtxTreat,
4999                                                                 exprToTreat.ResultType.EdmType.BuiltInTypeKind.ToString(),
5000                                                                 exprToTreat.ResultType.EdmType.FullName));
5001                 }
5002
5003                 if (!TypeSemantics.IsPolymorphicType(exprToTreat.ResultType))
5004                 {
5005                     throw EntityUtil.EntitySqlError(bltInExpr.Arg1.ErrCtx, Strings.TypeMustBeInheritableType);
5006                 }
5007
5008                 if (!TypeSemantics.IsPolymorphicType(typeToTreatTo))
5009                 {
5010                     throw EntityUtil.EntitySqlError(bltInExpr.Arg2.ErrCtx, Strings.TypeMustBeInheritableType);
5011                 }
5012
5013                 if (!IsSubOrSuperType(exprToTreat.ResultType, typeToTreatTo))
5014                 {
5015                     throw EntityUtil.EntitySqlError(bltInExpr.Arg1.ErrCtx, Strings.NotASuperOrSubType(exprToTreat.ResultType.EdmType.FullName,
5016                                                                                                       typeToTreatTo.EdmType.FullName));
5017                 }
5018
5019                 return exprToTreat.TreatAs(TypeHelpers.GetReadOnlyType(typeToTreatTo));
5020             });
5021             #endregion
5022
5023             //
5024             // CAST( e AS T )
5025             //
5026             #region CAST( e AS T )
5027             builtInExprConverter.Add(AST.BuiltInKind.Cast, delegate(AST.BuiltInExpr bltInExpr, SemanticResolver sr)
5028             {
5029                 var exprToCast = ConvertValueExpressionAllowUntypedNulls(bltInExpr.Arg1, sr);
5030                 var typeToCastTo = ConvertTypeName(bltInExpr.Arg2, sr);
5031
5032                 //
5033                 // Ensure CAST target type is scalar.
5034                 //
5035                 if (!TypeSemantics.IsScalarType(typeToCastTo))
5036                 {
5037                     throw EntityUtil.EntitySqlError(bltInExpr.Arg2.ErrCtx, Strings.InvalidCastType);
5038                 }
5039
5040                 if (exprToCast == null)
5041                 {
5042                     return DbExpressionBuilder.Null(typeToCastTo);
5043                 }
5044
5045                 //
5046                 // Ensure CAST source type is scalar.
5047                 //
5048                 if (!TypeSemantics.IsScalarType(exprToCast.ResultType))
5049                 {
5050                     throw EntityUtil.EntitySqlError(bltInExpr.Arg1.ErrCtx, Strings.InvalidCastExpressionType);
5051                 }
5052
5053                 if (!TypeSemantics.IsCastAllowed(exprToCast.ResultType, typeToCastTo))
5054                 {
5055                     throw EntityUtil.EntitySqlError(bltInExpr.Arg1.ErrCtx, Strings.InvalidCast(exprToCast.ResultType.EdmType.FullName, typeToCastTo.EdmType.FullName));
5056                 }
5057
5058                 return exprToCast.CastTo(TypeHelpers.GetReadOnlyType(typeToCastTo));
5059             });
5060             #endregion
5061
5062             //
5063             // OFTYPE( [ONLY] e, T )
5064             //
5065             #region OFTYPE( [ONLY] e, T )
5066             builtInExprConverter.Add(AST.BuiltInKind.OfType, delegate(AST.BuiltInExpr bltInExpr, SemanticResolver sr)
5067             {
5068                 var exprToFilter = ConvertValueExpression(bltInExpr.Arg1, sr);
5069                 var typeToFilterTo = ConvertTypeName(bltInExpr.Arg2, sr);
5070
5071                 bool isOnly = (bool)((AST.Literal)bltInExpr.Arg3).Value;
5072
5073                 bool isNominalTypeAllowed = sr.ParserOptions.ParserCompilationMode == ParserOptions.CompilationMode.RestrictedViewGenerationMode;
5074
5075                 if (!TypeSemantics.IsCollectionType(exprToFilter.ResultType))
5076                 {
5077                     throw EntityUtil.EntitySqlError(bltInExpr.Arg1.ErrCtx, Strings.ExpressionMustBeCollection);
5078                 }
5079
5080                 TypeUsage elementType = TypeHelpers.GetElementTypeUsage(exprToFilter.ResultType);
5081                 if (!isNominalTypeAllowed && !TypeSemantics.IsEntityType(elementType))
5082                 {
5083                     throw EntityUtil.EntitySqlError(bltInExpr.Arg1.ErrCtx,
5084                         Strings.OfTypeExpressionElementTypeMustBeEntityType(elementType.EdmType.BuiltInTypeKind.ToString(), elementType));
5085                 }
5086                 else if (isNominalTypeAllowed && !TypeSemantics.IsNominalType(elementType))
5087                 {
5088                     throw EntityUtil.EntitySqlError(bltInExpr.Arg1.ErrCtx,
5089                         Strings.OfTypeExpressionElementTypeMustBeNominalType(elementType.EdmType.BuiltInTypeKind.ToString(), elementType));
5090                 }
5091
5092                 if (!isNominalTypeAllowed && !TypeSemantics.IsEntityType(typeToFilterTo))
5093                 {
5094                     throw EntityUtil.EntitySqlError(bltInExpr.Arg2.ErrCtx,
5095                         Strings.TypeMustBeEntityType(Strings.CtxOfType, typeToFilterTo.EdmType.BuiltInTypeKind.ToString(), typeToFilterTo.EdmType.FullName));
5096                 }
5097                 else if (isNominalTypeAllowed && !TypeSemantics.IsNominalType(typeToFilterTo))
5098                 {
5099                     throw EntityUtil.EntitySqlError(bltInExpr.Arg2.ErrCtx,
5100                         Strings.TypeMustBeNominalType(Strings.CtxOfType, typeToFilterTo.EdmType.BuiltInTypeKind.ToString(), typeToFilterTo.EdmType.FullName));
5101                 }
5102
5103                 if (isOnly && typeToFilterTo.EdmType.Abstract)
5104                 {
5105                     throw EntityUtil.EntitySqlError(bltInExpr.Arg2.ErrCtx, Strings.OfTypeOnlyTypeArgumentCannotBeAbstract(typeToFilterTo.EdmType.FullName));
5106                 }
5107
5108                 if (!IsSubOrSuperType(elementType, typeToFilterTo))
5109                 {
5110                     throw EntityUtil.EntitySqlError(bltInExpr.Arg1.ErrCtx, Strings.NotASuperOrSubType(elementType.EdmType.FullName, typeToFilterTo.EdmType.FullName));
5111                 }
5112
5113                 DbExpression ofTypeExpression = null;
5114                 if (isOnly)
5115                 {
5116                     ofTypeExpression = exprToFilter.OfTypeOnly(TypeHelpers.GetReadOnlyType(typeToFilterTo));
5117                 }
5118                 else
5119                 {
5120                     ofTypeExpression = exprToFilter.OfType(TypeHelpers.GetReadOnlyType(typeToFilterTo));
5121                 }
5122
5123                 return ofTypeExpression;
5124             });
5125             #endregion
5126
5127             //
5128             // e LIKE pattern [ESCAPE escape]
5129             //
5130             #region e LIKE pattern [ESCAPE escape]
5131             builtInExprConverter.Add(AST.BuiltInKind.Like, delegate(AST.BuiltInExpr bltInExpr, SemanticResolver sr)
5132             {
5133                 DbExpression likeExpr = null;
5134
5135                 DbExpression matchExpr = ConvertValueExpressionAllowUntypedNulls(bltInExpr.Arg1, sr);
5136                 if (matchExpr == null)
5137                 {
5138                     matchExpr = DbExpressionBuilder.Null(sr.TypeResolver.StringType);
5139                 }
5140                 else if (!IsStringType(matchExpr.ResultType))
5141                 {
5142                     throw EntityUtil.EntitySqlError(bltInExpr.Arg1.ErrCtx, Strings.LikeArgMustBeStringType);
5143                 }
5144
5145                 DbExpression patternExpr = ConvertValueExpressionAllowUntypedNulls(bltInExpr.Arg2, sr);
5146                 if (patternExpr == null)
5147                 {
5148                     patternExpr = DbExpressionBuilder.Null(sr.TypeResolver.StringType);
5149                 }
5150                 else if (!IsStringType(patternExpr.ResultType))
5151                 {
5152                     throw EntityUtil.EntitySqlError(bltInExpr.Arg2.ErrCtx, Strings.LikeArgMustBeStringType);
5153                 }
5154
5155                 if (3 == bltInExpr.ArgCount)
5156                 {
5157                     DbExpression escapeExpr = ConvertValueExpressionAllowUntypedNulls(bltInExpr.Arg3, sr);
5158                     if (escapeExpr == null)
5159                     {
5160                         escapeExpr = DbExpressionBuilder.Null(sr.TypeResolver.StringType);
5161                     }
5162                     else if (!IsStringType(escapeExpr.ResultType))
5163                     {
5164                         throw EntityUtil.EntitySqlError(bltInExpr.Arg3.ErrCtx, Strings.LikeArgMustBeStringType);
5165                     }
5166
5167                     likeExpr = matchExpr.Like(patternExpr, escapeExpr);
5168                 }
5169                 else
5170                 {
5171                     likeExpr = matchExpr.Like(patternExpr);
5172                 }
5173
5174                 return likeExpr;
5175             });
5176             #endregion
5177
5178             //
5179             // e BETWEEN e1 AND e2
5180             //
5181             #region e BETWEEN e1 AND e2
5182             builtInExprConverter.Add(AST.BuiltInKind.Between, ConvertBetweenExpr);
5183             #endregion
5184
5185             //
5186             // e NOT BETWEEN e1 AND e2
5187             //
5188             #region e NOT BETWEEN e1 AND e2
5189             builtInExprConverter.Add(AST.BuiltInKind.NotBetween, delegate(AST.BuiltInExpr bltInExpr, SemanticResolver sr)
5190             {
5191                 return ConvertBetweenExpr(bltInExpr, sr).Not();
5192             });
5193             #endregion
5194
5195             return builtInExprConverter;
5196         }
5197
5198         private static DbExpression ConvertBetweenExpr(AST.BuiltInExpr bltInExpr, SemanticResolver sr)
5199         {
5200             Debug.Assert(bltInExpr.Kind == AST.BuiltInKind.Between || bltInExpr.Kind == AST.BuiltInKind.NotBetween, "bltInExpr.Kind must be Between or NotBetween");
5201             Debug.Assert(bltInExpr.ArgCount == 3, "bltInExpr.ArgCount == 3");
5202
5203             //
5204             // convert lower and upper limits
5205             //
5206             Pair<DbExpression, DbExpression> limitsExpr = ConvertValueExpressionsWithUntypedNulls(
5207                 bltInExpr.Arg2,
5208                 bltInExpr.Arg3,
5209                 bltInExpr.Arg1.ErrCtx,
5210                 () => Strings.BetweenLimitsCannotBeUntypedNulls,
5211                 sr);
5212
5213             //
5214             // Get and check common type for limits
5215             //
5216             TypeUsage rangeCommonType = TypeHelpers.GetCommonTypeUsage(limitsExpr.Left.ResultType, limitsExpr.Right.ResultType);
5217             if (null == rangeCommonType)
5218             {
5219                 throw EntityUtil.EntitySqlError(bltInExpr.Arg1.ErrCtx, Strings.BetweenLimitsTypesAreNotCompatible(limitsExpr.Left.ResultType.EdmType.FullName, limitsExpr.Right.ResultType.EdmType.FullName));
5220             }
5221
5222             //
5223             // check if limit types are order-comp
5224             //
5225             if (!TypeSemantics.IsOrderComparableTo(limitsExpr.Left.ResultType, limitsExpr.Right.ResultType))
5226             {
5227                 throw EntityUtil.EntitySqlError(bltInExpr.Arg1.ErrCtx, Strings.BetweenLimitsTypesAreNotOrderComparable(limitsExpr.Left.ResultType.EdmType.FullName, limitsExpr.Right.ResultType.EdmType.FullName));
5228             }
5229
5230             //
5231             // convert value expression
5232             //
5233             DbExpression valueExpr = ConvertValueExpressionAllowUntypedNulls(bltInExpr.Arg1, sr);
5234             if (valueExpr == null)
5235             {
5236                 valueExpr = DbExpressionBuilder.Null(rangeCommonType);
5237             }
5238
5239             //
5240             // check if valueExpr is order-comparable to limits
5241             //
5242             if (!TypeSemantics.IsOrderComparableTo(valueExpr.ResultType, rangeCommonType))
5243             {
5244                 throw EntityUtil.EntitySqlError(bltInExpr.Arg1.ErrCtx, Strings.BetweenValueIsNotOrderComparable(valueExpr.ResultType.EdmType.FullName, rangeCommonType.EdmType.FullName));
5245             }
5246
5247             return valueExpr.GreaterThanOrEqual(limitsExpr.Left).And(valueExpr.LessThanOrEqual(limitsExpr.Right));
5248         }
5249         #endregion
5250     }
5251 }