Code:
/ Dotnetfx_Vista_SP2 / Dotnetfx_Vista_SP2 / 8.0.50727.4016 / DEVDIV / depot / DevDiv / releases / Orcas / QFE / ndp / fx / src / DataEntity / System / Data / Common / EntitySql / SemanticAnalyzer.cs / 2 / SemanticAnalyzer.cs
//---------------------------------------------------------------------- //// Copyright (c) Microsoft Corporation. All rights reserved. // // // @owner [....] // @backup [....] //--------------------------------------------------------------------- namespace System.Data.Common.EntitySql { using System; using System.Globalization; using System.Collections.Generic; using System.Diagnostics; using System.Data.Common.CommandTrees; using System.Data.Metadata.Edm; using System.Data.Entity; ////// Implements Semantic Analysis and Conversion /// Provides the translation service between an abstract syntax tree to a canonical command tree /// For complete documentation of the language syntax and semantics, refer to http://sqlweb/default.asp?specDirId=764 /// 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 /// we rely on the assumption that metadata was pre-loaded and is relevant to the query. /// internal sealed class SemanticAnalyzer { private SemanticResolver _sr; ////// Initializes semantic analyzer /// /// initialized SemanticResolver instance for a given typespace/type system internal SemanticAnalyzer( SemanticResolver sr ) { EntityUtil.CheckArgumentNull(sr, "sr"); _sr = sr; } ////// Entry point to semantic analysis. Converts astTree into DbExpression. /// /// ast tree /// command tree to build the expression ////// ///Thrown when Syntatic or Semantic rules are violated and the query cannot be accepted ///Thrown when metadata related service requests fail ///Thrown when mapping related service requests fail ///DbExpression internal DbExpression Analyze(Expr astExpr, DbCommandTree commandTree) { CommandExpr command = Initialize(astExpr, commandTree); DbExpression converted = ConvertRootExpression(command.QueryExpr, _sr); return converted; } ////// Entry point to semantic analysis. Converts astTree into command tree. /// /// ast tree ////// ///Thrown when Syntatic or Semantic rules are violated and the query cannot be accepted ///Thrown when metadata related service requests fail ///Thrown when mapping related service requests fail ///DbCommandTree internal DbCommandTree Analyze( Expr astExpr ) { CommandExpr astCommandExpr = Initialize(astExpr, null); // // Convert query Expression // DbCommandTree commandTree = ConvertCommand(astCommandExpr, _sr); Debug.Assert(null != commandTree,"null != commandTree"); return commandTree; } ////// Common initialization required whether the semantic analysis process /// is producing a command tree or only an expression. Validates that the /// parse phase did in fact produce a command AST. /// /// The root of the abstract syntax tree produced by the parse phase /// /// An optional command tree to use, only provided when constructing an expression. /// When constructing a command tree, an instance of the appropriate command tree /// class will be created and returned by semantic analysis. /// ///The private CommandExpr Initialize(Expr astExpr, DbCommandTree tree) { CommandExpr astCommandExpr = astExpr as CommandExpr; if (null == astCommandExpr) { throw EntityUtil.Argument(System.Data.Entity.Strings.UnknownAstCommandExpression); } // // Sets DbCommandTree Factory // if (tree == null) { _sr.SetCommandTreeFactory(astCommandExpr); } else { _sr.SetCommandTreeFactory(astCommandExpr, tree); } // // Declare Canonical Namespace // _sr.DeclareCanonicalNamespace(); // // Declare Namespaces // _sr.DeclareNamespaces(astCommandExpr.NamespaceDeclList); return astCommandExpr; } #region command converter delegates delegate DbCommandTree CommandConverter( Expr astExpr, SemanticResolver sr ); static CommandConverter[] commandConverters = { /* ExprKind.Generic */ ConvertGeneralExpression, /* ExprKind.Query */ ConvertGeneralExpression, }; #endregion ///that is the root of the AST specified by /// Dispatches/Converts top command expressions. /// /// /// SemanticResolver instance relative to a especif typespace/system ///private static DbCommandTree ConvertCommand( CommandExpr astCommandExpr, SemanticResolver sr ) { EntityUtil.CheckArgumentNull(astCommandExpr, "astCommandExpr"); Expr queryExpr = astCommandExpr.QueryExpr; return commandConverters[(int)queryExpr.ExprKind](queryExpr, sr); } /// /// Converts {Query|General} Expression /// /// /// SemanticResolver instance relative to a especif typespace/system ///private static DbCommandTree ConvertGeneralExpression( Expr astExpr, SemanticResolver sr ) { DbExpression converted = ConvertRootExpression(astExpr, sr); DbQueryCommandTree qryCmdTree = (DbQueryCommandTree)sr.CmdTree; qryCmdTree.Query = converted; Debug.Assert(null != qryCmdTree,"null != qryCmdTree"); return qryCmdTree; } /// /// Converts the expression that is the 'root' of a query AST to a /// normalized and validated /// The root AST node for this query /// The. This entry /// point to the semantic analysis phase is used when producing a /// query command tree (from a Query or General AST expression) or /// producing only a . /// instance to use /// /// An instance of private static DbExpression ConvertRootExpression(Expr astExpr, SemanticResolver sr) { DbExpression converted = Convert(astExpr, sr); // // ensure converted expression is not untyped-null // if (TypeSemantics.IsNullType(converted.ResultType)) { throw EntityUtil.EntitySqlError(astExpr.ErrCtx, System.Data.Entity.Strings.ResultingExpressionTypeCannotBeNull); } // // Handles the "inline" projection case // if (converted is DbScanExpression) { DbExpressionBinding source = sr.CmdTree.CreateExpressionBinding(converted, sr.GenerateInternalName("extent")); converted = sr.CmdTree.CreateProjectExpression(source, source.Variable); } // // ensure return type is valid for query. for V1, association types are the only // type that cannot be at 'top' level result. Note that this is only applicable in // general queries and association types are valid in view gen mode queries // if (sr.ParserOptions.ParserCompilationMode == ParserOptions.CompilationMode.NormalMode) { SemanticResolver.ValidateQueryResultType(converted.ResultType, astExpr.ErrCtx); } return converted; } ///, adjusted to handle 'inline' projections /// and validated to produce a result type appropriate for the root of a query command tree. /// /// Dispatches/Converts general expressions /// /// /// SemanticResolver instance relative to a especif typespace/system ///private static DbExpression Convert( Expr astExpr, SemanticResolver sr ) { if (null == astExpr) { return null; } AstExprConverter converter = _astExprConverters[astExpr.GetType()]; if (null == converter) { throw EntityUtil.Argument(System.Data.Entity.Strings.UnknownAstExpressionType); } DbExpression converted = converter(astExpr, sr); Debug.Assert(null != converted,"null != converted"); return converted; } /// /// Converts Literal Expression /// /// /// SemanticResolver instance relative to a especif typespace/system ///private static DbExpression ConvertLiteral( Expr expr, SemanticResolver sr ) { Literal literal = (Literal)expr; if (literal.IsNullLiteral) { // // if it is literal null, return untyped null // untyped nulls will later have their type inferred depending on the // especific expression in which it participates // return new UntypedNullExpression(sr.CmdTree); } else { return sr.CmdTree.CreateConstantExpression(literal.Value, sr.TypeResolver.GetLiteralTypeUsage(literal)); } } /// /// Converts Simple Identifier /// /// /// SemanticResolver instance relative to a especif typespace/system ///private static DbExpression ConvertIdentifier( Expr expr, SemanticResolver sr ) { Identifier idExpr = (Identifier)expr; DbExpression converted = sr.ResolveIdentifier(new string[] { idExpr.Name }, expr.ErrCtx); if (null == converted) { CqlErrorHelper.ReportIdentifierError(expr, sr); } return converted; } /// /// Converts DotExpression /// /// /// SemanticResolver instance relative to a especif typespace/system ///private static DbExpression ConvertDotExpr( Expr expr, SemanticResolver sr ) { DotExpr dotExpr = (DotExpr)expr; DbExpression converted = null; if (dotExpr.IsDottedIdentifier) { converted = sr.ResolveIdentifier(dotExpr.Names, dotExpr.ErrCtx); if (null == converted) { CqlErrorHelper.ReportIdentifierError(expr, sr); } } else { converted = ConvertDotExpressionProcess(dotExpr, sr); } Debug.Assert(null != converted,"null != converted"); return converted; } /// /// converts dot expression. dotted id case is handled by resolveId /// /// /// SemanticResolver instance relative to a especif typespace/system ////// ////// /// static private DbExpression ConvertDotExpressionProcess( DotExpr dotExpr, SemanticResolver sr ) { Debug.Assert(!dotExpr.IsDottedIdentifier,"!dotExpr.IsDottedIdentifier"); return sr.ResolveIdentifierChain(dotExpr.Names, 0, Convert(dotExpr.LeftMostExpression, sr), dotExpr.ErrCtx); } /// /// Converts methods, functions and type constructors /// methods (instance or static) can be in the form: (expr).chain.of.names(args) or chain.of.names(args) /// Functions are chain.of.names(args) /// /// /// SemanticResolver instance relative to a especif typespace/system ///private static DbExpression ConvertMethodExpr( Expr expr, SemanticResolver sr ) { MethodExpr methodExpr = (MethodExpr)expr; DbExpression converted = null; DotExpr dotExpr = methodExpr.MethodPrefixExpr; // // resolve base expression if one exists // DbExpression baseExpr = (null != dotExpr.LeftMostExpression) ? Convert(dotExpr.LeftMostExpression, sr) : null; // // If base expression is still unresolved, check if leftmost name element is in in scope // int prefixIndex = 0; KeyValuePair varInfo; if (null == baseExpr && dotExpr.IsDottedIdentifier && dotExpr.Names.Length > 0) { ScopeEntry scopeEntry; if (sr.TryScopeLookup(dotExpr.Names[0], out scopeEntry)) { // // make sure is a valid type for method call // if (TypeResolver.IsValidTypeForMethodCall(scopeEntry.Expression.ResultType)) { baseExpr = scopeEntry.Expression; prefixIndex = 1; } else { throw EntityUtil.EntitySqlError(methodExpr.ErrCtx, System.Data.Entity.Strings.DefiningTypeDoesNotSupportMethodCalls); } } else if (sr.Variables.TryGetValue(dotExpr.Names[0], out varInfo)) { baseExpr = sr.CmdTree.CreateVariableReferenceExpression(varInfo.Key, varInfo.Value); prefixIndex = 1; } } // // check if base expression if is untyped null // if (baseExpr is UntypedNullExpression) { throw EntityUtil.EntitySqlError(dotExpr.LeftMostExpression.ErrCtx, System.Data.Entity.Strings.ExpressionCannotBeNull); } // // dispatches methodExpr to static or instance kind of method conversion // if (null == baseExpr) { // // if base expression is still unresolved, it should be a function(aggregates included), static method or type constructor // converted = ConvertStaticMethodOrFunction(methodExpr, sr); } else { // // otherwise, should be an instance method invocation // converted = ConvertMethodInstance(baseExpr, methodExpr, prefixIndex, sr); } Debug.Assert(null != converted,"null != converted"); return converted; } /// /// Converts a method expr into a Static Method, Type Constructor or EdmFunction call (including aggregates) /// /// /// ///private static DbExpression ConvertStaticMethodOrFunction( MethodExpr methodExpr, SemanticResolver sr ) { DbExpression converted = null; // // Find out if given name path is a Static Method, Type Constructor or EdmFunction call (including aggregates) // TypeUsage constructorType; TypeUsage staticMethodType; IList functionType; // // Resolve methodExpr // sr.ResolveNameAsStaticMethodOrFunction(methodExpr, out constructorType, out staticMethodType, out functionType); // // at this point, only one of the three must be not null // that is ensured by ResolveNameAsStaticMethodOrFunction() // Debug.Assert(constructorType != null || staticMethodType != null || functionType != null,"constructorType != null || staticMethodType != null || functionType != null"); // // if it is a constructorType, create an instance of it // if (null != constructorType) { List relshipExprList = null; // // convert relationships if present // if (methodExpr.HasRelationships) { if (ParserOptions.CompilationMode.NormalMode == sr.ParserOptions.ParserCompilationMode) { throw EntityUtil.EntitySqlError(methodExpr.Relationships.ErrCtx, System.Data.Entity.Strings.InvalidModeForWithRelationshipClause); } HashSet targetEnds = new HashSet (); relshipExprList = new List (methodExpr.Relationships.Count); for (int i = 0; i < methodExpr.Relationships.Count; i++) { RelshipNavigationExpr relshipExpr = methodExpr.Relationships[i]; DbRelatedEntityRef relshipTarget = ConvertRelatedEntityRef(relshipExpr, sr); string targetEndId = String.Join(":", new String[] { relshipTarget.TargetEnd.DeclaringType.Identity, relshipTarget.TargetEnd.Identity }); if (targetEnds.Contains(targetEndId)) { throw EntityUtil.EntitySqlError(relshipExpr.ErrCtx, System.Data.Entity.Strings.RelationshipTargetMustBeUnique(relshipTarget.TargetEntityReference.ResultType.EdmType.Identity)); } targetEnds.Add(targetEndId); relshipExprList.Add(relshipTarget); } } converted = sr.CreateInstanceOfType(constructorType, ConvertFunctionArguments(methodExpr.Args, sr), relshipExprList, methodExpr); } // // if it is staticMethodType, create method call expression // else if (null != staticMethodType) { converted = SemanticResolver.CreateStaticMethod(staticMethodType, ConvertFunctionArguments(methodExpr.Args, sr), methodExpr); } // // if it is functionType // else if (null != functionType && 0 < functionType.Count) { // // decide if it is an ordinary function or group aggreagate // if (TypeSemantics.IsAggregateFunction(functionType[0]) && sr.IsInAnyGroupScope()) { // // if it is an aggreagate function inside a group scope, dispatch to ConvertGroupAggregate() // converted = ConvertAggregateFunctionInGroupScope(methodExpr, functionType, sr); } else { // // else, is just an ordinary function call (including collection aggregates) // converted = sr.CreateFunction(functionType, ConvertFunctionArguments(methodExpr.Args, sr), methodExpr); } } else { throw EntityUtil.EntitySqlError(methodExpr.ErrCtx, System.Data.Entity.Strings.CannotResolveNameToFunction(methodExpr.MethodPrefixExpr.FullName)); } Debug.Assert(null != converted,"null != converted"); return converted; } /// /// Converts Group Aggregates /// /// /// /// ////// /// This method convert group aggregates in two phases: /// Phase 1 - it will resolve the actual inner (argument) expression and then anotate the ast node and add the resolved aggregate /// to the scope /// Phase 2 - if ast node was annotated, just extract the precomputed expression from the scope. /// private static DbExpression ConvertAggregateFunctionInGroupScope( MethodExpr methodExpr, IListfunctionTypes, SemanticResolver sr ) { DbExpression converted = null; // // first, try if aggregate was already pre resolved // if (TryConvertAsResolvedGroupAggregate(methodExpr, sr, out converted)) { return converted; } // // then, try to resolve as Ordinary function (collection aggregate) // if (TryConvertAsOrdinaryFunctionInGroup(methodExpr, functionTypes, sr, out converted)) { return converted; } // // finally, try to convert as group aggregate // if (TryConvertAsGroupAggregateFunction(methodExpr, functionTypes, sr, out converted)) { return converted; } // // if we reach this point, means the resolution failed // throw EntityUtil.EntitySqlError(methodExpr.ErrCtx, System.Data.Entity.Strings.FailedToResolveAggregateFunction(methodExpr.MethodPrefixExpr.FullName)); } /// /// try to convert as pre resolved aggregate function /// /// /// /// ///private static bool TryConvertAsResolvedGroupAggregate( MethodExpr methodExpr, SemanticResolver sr, out DbExpression converted ) { converted = null; // // if ast node was annotated in a previous pass, means it was already resolved and should be in scope // if (methodExpr.WasResolved) { sr.CurrentScopeRegionFlags.DecrementGroupAggregateNestingCount(); ScopeEntry scopeEntry; SemanticResolver.ScopeViewKind saveScopeView = sr.GetScopeView(); sr.SetScopeView(SemanticResolver.ScopeViewKind.All); int scopeIndex; if (!sr.TryScopeLookup(methodExpr.InternalAggregateName, out scopeEntry, out scopeIndex)) { Debug.Assert(methodExpr.DummyExpression != null, "resolved aggregate dummy expression must not be null"); converted = methodExpr.DummyExpression; return true; } else { // // Sets correlation flag // sr.SetScopeRegionCorrelationFlag(scopeIndex); } sr.SetScopeView(saveScopeView); converted = scopeEntry.Expression; return true; } return false; } /// /// Try convert method expr in a group scope as an ordinary function (collection aggregate) /// /// /// /// /// ///private static bool TryConvertAsOrdinaryFunctionInGroup( MethodExpr methodExpr , IList functionTypes , SemanticResolver sr , out DbExpression converted ) { converted = null; // // save scope view // SemanticResolver.ScopeViewKind saveScopeView = sr.GetScopeView(); // // convert aggregate arguments // List args = ConvertFunctionArguments(methodExpr.Args, sr); // // collect argument types // List argTypes = new List (args.Count); for (int i = 0 ; i < args.Count ; i++) { argTypes.Add(args[i].ResultType); } // // try to see if there is a overload match // bool isAmbiguous = false; EdmFunction functionType = TypeResolver.ResolveFunctionOverloads( functionTypes, argTypes, false /* isGroupAggregateFunction */, out isAmbiguous); // // if there is more then one overload that matches given arguments, throw // if (isAmbiguous) { throw EntityUtil.EntitySqlError(methodExpr.ErrCtx, System.Data.Entity.Strings.AmbiguousFunctionArguments); } // // if not null, means a match was found as an ordinary function // if (null != functionType) { // // make sure all referenced vars are from group scope only // if (!sr.CurrentScopeRegionFlags.IsImplicitGroup) { sr.SetScopeView(SemanticResolver.ScopeViewKind.CurrentScope); } // // convert aggregate arguments // args = ConvertFunctionArguments(methodExpr.Args, sr); // // restore previous scope view // sr.SetScopeView(saveScopeView); // // return function // converted = sr.CmdTree.CreateFunctionExpression(functionType, args); } return (null != functionType); } /// /// /// /// /// /// /// ///private static bool TryConvertAsGroupAggregateFunction( MethodExpr methodExpr, IList functionTypeList, SemanticResolver sr, out DbExpression converted ) { converted = null; // // save scope view // SemanticResolver.ScopeViewKind saveScopeView = sr.GetScopeView(); // // Aggregates in groups can refer to all scopes // sr.SetScopeView(SemanticResolver.ScopeViewKind.All); // // flag that it is inside a group aggregate // sr.CurrentScopeRegionFlags.IsInsideGroupAggregate = true; // // reset nested references flag // sr.CurrentScopeRegionFlags.WasNestedGroupAggregateReferredByInnerExpressions = false; // // pushes candidate aggregate ast node // sr.PushAggregateAstNode(methodExpr); sr.CurrentScopeRegionFlags.DecrementGroupAggregateNestingCount(); // // convert aggregate arguments // List args = ConvertFunctionArguments(methodExpr.Args, sr); // // clear inside group aggregate flag // sr.CurrentScopeRegionFlags.IsInsideGroupAggregate = false; // // collect argument types // List argTypes = new List (args.Count); for (int i = 0 ; i < args.Count ; i++) { argTypes.Add(args[i].ResultType); } // // try to find an overload match as group aggregate // bool isAmbiguous = false; EdmFunction functionType = TypeResolver.ResolveFunctionOverloads(functionTypeList, argTypes, true /* isGroupAggregateFunction */, out isAmbiguous); // // if there is more then one overload that matches given arguments, throw // if (isAmbiguous) { throw EntityUtil.EntitySqlError(methodExpr.ErrCtx, System.Data.Entity.Strings.AmbiguousFunctionArguments); } // // if it still null, then there is no overload as an ordinary function or group aggregate function // if (null == functionType) { CqlErrorHelper.ReportFunctionOverloadError(methodExpr, functionTypeList[0], argTypes); } // // ensure that group aggregate was not referenced by inner sub-expression // if (sr.CurrentScopeRegionFlags.WasNestedGroupAggregateReferredByInnerExpressions) { throw EntityUtil.EntitySqlError(methodExpr.ErrCtx, System.Data.Entity.Strings.NestedAggregatesCannotBeUsedInAggregateFunctions); } // // ensure it is not a nested group aggregate call // if (sr.CurrentScopeRegionFlags.GroupAggregateNestingCount < -1) { throw EntityUtil.EntitySqlError(methodExpr.MethodIdentifier.ErrCtx, System.Data.Entity.Strings.InvalidNestedGroupAggregateCall); } // // aggregate functions in the current release can have only one argument and must of of collectio type // Debug.Assert((1 == functionType.Parameters.Count), "(1 == functionType.Parameters.Count)"); // we only support monadic aggregate functions Debug.Assert(TypeSemantics.IsCollectionType(functionType.Parameters[0].TypeUsage), "functionType.Parameters[0].Type is CollectionType"); TypeUsage argumentType = TypeHelpers.GetElementTypeUsage(functionType.Parameters[0].TypeUsage); if (TypeSemantics.IsNullType(args[0].ResultType)) { args[0] = sr.CmdTree.CreateNullExpression(argumentType); } // // create function aggregate expression // DbFunctionAggregate functionAggregate; // create distinct expression if espeficied if (methodExpr.DistinctKind == DistinctKind.Distinct) { functionAggregate = sr.CmdTree.CreateDistinctFunctionAggregate(functionType, args[0]); } else { functionAggregate = sr.CmdTree.CreateFunctionAggregate(functionType, args[0]); } // // generate name for the aggregate 'property'. this name will the internal name of the pre-computed expression in the scope and // annotated ast node in the ast tree // string internalAggregateName = sr.GenerateInternalName("groupAgg" + functionType.Name); // // add aggreate to aggreate list // AggregateAstNodeInfo aggrAstInfo = sr.PopAggregateAstNode(); aggrAstInfo.AssertMethodExprEquivalent(methodExpr); sr.AddGroupAggregateInfoToScopeRegion(methodExpr, internalAggregateName, functionAggregate, aggrAstInfo.ScopeIndex); // // return 'dummy' expression with same type as aggregate function // converted = sr.CmdTree.CreateNullExpression(functionType.ReturnParameter.TypeUsage); // // anotate method expression node as aggregate // methodExpr.SetAggregateInfo(internalAggregateName, converted); // // restore visibility to group scope only // sr.SetScopeView(saveScopeView); // // increment nesting count // sr.CurrentScopeRegionFlags.IncrementGroupAggregateNestingCount(); return true; } /// /// Converted a instance method. /// /// /// /// /// ///private static DbExpression ConvertMethodInstance( DbExpression baseExpr, MethodExpr methodExpr, int prefixIndex, SemanticResolver sr ) { DbExpression converted = null; Debug.Assert(null != baseExpr,"null != baseExpr"); DotExpr dotExpr = methodExpr.MethodPrefixExpr; // // ensure methods are not called on Scalar type instances // if (TypeSemantics.IsPrimitiveType(baseExpr.ResultType)) { throw EntityUtil.EntitySqlError(dotExpr.LeftMostExpression.ErrCtx, System.Data.Entity.Strings.MethodNotAllowedOnScalars); } // // build the instance property references chain up to the method name // DbExpression innerExpression = baseExpr; for (int i = prefixIndex ; i < dotExpr.Length - 1 ; i++) { innerExpression = sr.ResolveIdentifierElement(innerExpression.ResultType, innerExpression, dotExpr.Names[i], dotExpr.ErrCtx); // // if this point is reached, means that an element in the path name is not a valid property // such as name[ i + 1 ] is not a valid property/member of defining type resolved previosly for name[ i ] // if (null == innerExpression) { throw EntityUtil.EntitySqlError(methodExpr.ErrCtx, System.Data.Entity.Strings.InvalidMethodPathElement(dotExpr.Names[i], innerExpression.ResultType.EdmType.FullName)); } } // // convert method arguments // List args = ConvertFunctionArguments(methodExpr.Args, sr); // // Resolve/Validate overloads and create method expression // converted = SemanticResolver.CreateInstanceMethod(innerExpression, args, methodExpr); Debug.Assert(null != converted,"null != converted"); return converted; } /// /// Converts EdmFunction Arguments representes a list of astExpr nodes /// /// /// ///private static List ConvertFunctionArguments( ExprList astExprList, SemanticResolver sr ) { List convertedArgs = new List (); if (null != astExprList) { for (int i = 0 ; i < astExprList.Count ; i++) { convertedArgs.Add(Convert(astExprList[i], sr)); } } return convertedArgs; } /// /// Convert Paramerters /// /// /// SemanticResolver instance relative to a especif typespace/system ///private static DbExpression ConvertParameter( Expr expr, SemanticResolver sr ) { Parameter parameter = (Parameter)expr; TypeUsage paramType = null; KeyValuePair varInfo; if (sr.Variables != null && sr.Variables.TryGetValue(parameter.Name, out varInfo)) { return sr.CmdTree.CreateVariableReferenceExpression(varInfo.Key, varInfo.Value); } if (null == sr.Parameters || !sr.Parameters.TryGetValue(parameter.Name, out paramType)) { throw EntityUtil.EntitySqlError(parameter.ErrCtx, System.Data.Entity.Strings.ParameterWasNotDefined(parameter.Name)); } sr.CmdTree.AddParameter(parameter.Name, TypeHelpers.GetReadOnlyType(paramType)); return sr.CmdTree.CreateParameterReferenceExpression(parameter.Name); } /// /// Validate a relationship-traversal - used for both Navigate expressions /// and for entity construction with related entity refs. /// /// For "related entity refs", "isTargetEnd" is true - for Navigate expressions, /// this parameter is "false". /// /// /// the relationshipExpr AST /// /// resolver context /// the source/target expression /// the relationship type /// from end of the relationship /// to-end of the relationship private static void ValidateRelationshipTraversal(RelshipNavigationExpr relshipExpr, bool isTargetEnd, SemanticResolver sr, out DbExpression refExpr, out RelationshipType relationshipType, out RelationshipEndMember refEnd, out RelationshipEndMember otherEnd) { relationshipType = null; refEnd = null; otherEnd = null; refExpr = null; // // resolve relationship type // relationshipType = sr.ResolveNameAsType(relshipExpr.RelationTypeNames, relshipExpr.RelationTypeNameIdentifier).EdmType as RelationshipType; if (null == relationshipType) { throw EntityUtil.EntitySqlError(relshipExpr.RelationTypeNameIdentifier.ErrCtx, System.Data.Entity.Strings.InvalidRelationshipTypeName(relshipExpr.RelationTypeFullName)); } // // convert relationship 'instance' expression // refExpr = Convert(relshipExpr.RelationshipSource, sr); // // if is entity, create entity ref out if it // if (!isTargetEnd && TypeSemantics.IsEntityType(refExpr.ResultType)) { refExpr = sr.CmdTree.CreateEntityRefExpression(refExpr); } // // make sure is ref type // if (!TypeSemantics.IsReferenceType(refExpr.ResultType)) { throw EntityUtil.EntitySqlError(relshipExpr.RelationshipSource.ErrCtx, System.Data.Entity.Strings.InvalidRelationshipSourceType); } // // ensure entity 'participates' in the given relationship type // if (!TypeSemantics.IsTypeValidForRelationship(TypeHelpers.GetElementTypeUsage(refExpr.ResultType), relationshipType)) { throw EntityUtil.EntitySqlError(relshipExpr.RelationTypeNameIdentifier.ErrCtx, System.Data.Entity.Strings.RelationshipTypeIsNotCompatibleWithEntity( TypeHelpers.GetFullName(TypeHelpers.GetElementTypeUsage(refExpr.ResultType)), TypeHelpers.GetFullName(relationshipType))); } // // ensure relationship ends are valid // metadata ensures that there will never happen to have two equal end names // TypeUsage fromEndType = null; int fromEndMatchCount = 0; TypeUsage elementType = TypeHelpers.GetElementTypeUsage(refExpr.ResultType); for (int i = 0; i < relationshipType.Members.Count; i++) { // // check 'to' end // if (relationshipType.Members[i].Name.Equals(relshipExpr.ToEndIdentifierName, StringComparison.OrdinalIgnoreCase)) { otherEnd = (RelationshipEndMember)relationshipType.Members[i]; continue; } // // check 'from' end // if ( (null != relshipExpr.FromEndIdentifier && relationshipType.Members[i].Name.Equals(relshipExpr.FromEndIdentifierName, StringComparison.OrdinalIgnoreCase)) || (null == relshipExpr.FromEndIdentifier && TypeSemantics.IsEquivalentOrPromotableTo(elementType, TypeHelpers.GetElementTypeUsage(relationshipType.Members[i].TypeUsage))) ) { fromEndMatchCount++; if (fromEndMatchCount > 1) { ErrorContext errCtx = (null == relshipExpr.FromEndIdentifier) ? relshipExpr.ErrCtx : relshipExpr.FromEndIdentifier.ErrCtx; throw EntityUtil.EntitySqlError(errCtx, System.Data.Entity.Strings.RelationshipFromEndIsAmbiguos); } refEnd = (RelationshipEndMember)relationshipType.Members[i]; fromEndType = relationshipType.Members[i].TypeUsage; } } // // ensure relationship 'To' end contains given property // if (null == otherEnd) { if (null != relshipExpr.ToEndIdentifier) { throw EntityUtil.EntitySqlError(relshipExpr.ToEndIdentifier.ErrCtx, System.Data.Entity.Strings.InvalidRelationshipMember(relshipExpr.ToEndIdentifierName, relshipExpr.RelationTypeFullName)); } if (2 != relationshipType.Members.Count) { throw EntityUtil.EntitySqlError(relshipExpr.ErrCtx, System.Data.Entity.Strings.InvalidImplicitRelationshipToEnd(relshipExpr.RelationTypeFullName)); } Debug.Assert(null != refEnd, "null!=fromEnd"); otherEnd = (RelationshipEndMember)(refEnd.Name.Equals(relationshipType.Members[0].Name, StringComparison.OrdinalIgnoreCase) ? relationshipType.Members[1] : relationshipType.Members[0]); } // // ensure relationship 'From' end contains given entity // if (null == refEnd || null == fromEndType) { ErrorContext errCtx = (null == relshipExpr.FromEndIdentifier) ? relshipExpr.ErrCtx : relshipExpr.FromEndIdentifier.ErrCtx; if (null == relshipExpr.FromEndIdentifier) { throw EntityUtil.EntitySqlError(errCtx, System.Data.Entity.Strings.InvalidImplicitRelationshipFromEnd(relshipExpr.RelationTypeFullName)); } else { throw EntityUtil.EntitySqlError(errCtx, System.Data.Entity.Strings.InvalidRelationshipMember(relshipExpr.FromEndIdentifierName, relshipExpr.RelationTypeFullName)); } } // // check if source is promotable to from end type // if (!TypeSemantics.IsValidPolymorphicCast(TypeHelpers.GetElementTypeUsage(refExpr.ResultType), TypeHelpers.GetElementTypeUsage(refEnd.TypeUsage))) { ErrorContext errCtx = (null == relshipExpr.FromEndIdentifier) ? relshipExpr.ErrCtx : relshipExpr.FromEndIdentifier.ErrCtx; throw EntityUtil.EntitySqlError(errCtx, System.Data.Entity.Strings.SourceTypeMustBePromotoableToFromEndRelationType(TypeHelpers.GetElementTypeUsage(refExpr.ResultType).EdmType.FullName, TypeHelpers.GetElementTypeUsage(fromEndType).EdmType.FullName)); } return; } ////// Build out a RelatedEntityRef /// /// the ast expression /// the Semantic Resolver context ///a DbRelatedEntityRef instance private static DbRelatedEntityRef ConvertRelatedEntityRef(RelshipNavigationExpr relshipExpr, SemanticResolver sr) { // // Validate the relationship traversal // DbExpression targetRef; RelationshipEndMember targetRefEnd; RelationshipEndMember otherEnd; RelationshipType relationshipType; ValidateRelationshipTraversal(relshipExpr, true /* targetEnd */ , sr, out targetRef, out relationshipType, out targetRefEnd, out otherEnd); // // ensure is *..{0|1} // if (RelationshipMultiplicity.One != targetRefEnd.RelationshipMultiplicity && RelationshipMultiplicity.ZeroOrOne != targetRefEnd.RelationshipMultiplicity) { throw EntityUtil.EntitySqlError(relshipExpr.ErrCtx, System.Data.Entity.Strings.InvalidWithRelationshipTargetEndMultiplicity(targetRefEnd.Identity, targetRefEnd.RelationshipMultiplicity.ToString())); } DbRelatedEntityRef relatedEntityRef = sr.CmdTree.CreateRelatedEntityRef(otherEnd, targetRefEnd, targetRef); return relatedEntityRef; } ////// converts Relationship Navigation operator /// /// /// SemanticResolver instance relative to a especif typespace/system ///private static DbExpression ConvertRelshipNavigationExpr( Expr astExpr, SemanticResolver sr ) { RelshipNavigationExpr relshipExpr = (RelshipNavigationExpr)astExpr; // // Validate the relationship traversal // DbExpression relationshipSource; RelationshipEndMember fromEnd; RelationshipEndMember toEnd; RelationshipType relationshipType; ValidateRelationshipTraversal(relshipExpr, false /* !targetEnd */, sr, out relationshipSource, out relationshipType, out fromEnd, out toEnd); // // create cqt expression // DbExpression converted = sr.CmdTree.CreateRelationshipNavigationExpression(fromEnd, toEnd, relationshipSource); Debug.Assert(null != converted,"null != converted"); return converted; } /// /// converts REF operator /// /// /// SemanticResolver instance relative to a especif typespace/system ///private static DbExpression ConvertRefExpr( Expr astExpr, SemanticResolver sr ) { RefExpr refExpr = (RefExpr)astExpr; DbExpression converted = Convert(refExpr.RefArgExpr, sr); // // check if is entity type // if (!TypeSemantics.IsEntityType(converted.ResultType)) { throw EntityUtil.EntitySqlError(refExpr.RefArgExpr.ErrCtx, System.Data.Entity.Strings.RefArgIsNotOfEntityType(converted.ResultType.EdmType.FullName)); } // // create ref expression // converted = sr.CmdTree.CreateEntityRefExpression(converted); Debug.Assert(null != converted,"null != converted"); return converted; } /// /// converts DEREF operator /// /// /// SemanticResolver instance relative to a especif typespace/system ///private static DbExpression ConvertDeRefExpr( Expr astExpr, SemanticResolver sr ) { DerefExpr deRefExpr = (DerefExpr)astExpr; DbExpression converted = null; converted = Convert(deRefExpr.RefExpr, sr); // // check if return type is RefType // if (!TypeSemantics.IsReferenceType(converted.ResultType)) { throw EntityUtil.EntitySqlError(deRefExpr.RefExpr.ErrCtx, System.Data.Entity.Strings.DeRefArgIsNotOfRefType(converted.ResultType.EdmType.FullName)); } // // create DeRef expression // converted = sr.CmdTree.CreateDerefExpression(converted); Debug.Assert(null != converted,"null != converted"); return converted; } /// /// converts CREATEREF operator /// /// /// SemanticResolver instance relative to a especif typespace/system ///private static DbExpression ConvertCreateRefExpr( Expr astExpr, SemanticResolver sr ) { CreateRefExpr createRefExpr = (CreateRefExpr)astExpr; DbExpression converted = null; // // Convert the entity set, also, ensure that we get back an extent expression // DbScanExpression entitySetExpr = Convert(createRefExpr.EntitySet, sr) as DbScanExpression; if (entitySetExpr == null) { throw EntityUtil.EntitySqlError(createRefExpr.EntitySet.ErrCtx, System.Data.Entity.Strings.ExprIsNotValidEntitySetForCreateRef); } // // Ensure that the extent is an entity set // EntitySet entitySet = entitySetExpr.Target as EntitySet; if (entitySet == null) { throw EntityUtil.EntitySqlError(createRefExpr.EntitySet.ErrCtx, System.Data.Entity.Strings.ExprIsNotValidEntitySetForCreateRef); } DbExpression keyRowExpression = Convert(createRefExpr.Keys, sr); SemanticResolver.EnsureIsNotUntypedNull(keyRowExpression, createRefExpr.Keys.ErrCtx); RowType inputKeyRowType = keyRowExpression.ResultType.EdmType as RowType; if (null == inputKeyRowType) { throw EntityUtil.EntitySqlError(createRefExpr.Keys.ErrCtx,System.Data.Entity.Strings.InvalidCreateRefKeyType); } RowType entityKeyRowType = TypeHelpers.CreateKeyRowType(entitySet.ElementType, sr.CmdTree.MetadataWorkspace); if (entityKeyRowType.Members.Count != inputKeyRowType.Members.Count) { throw EntityUtil.EntitySqlError(createRefExpr.Keys.ErrCtx, System.Data.Entity.Strings.ImcompatibleCreateRefKeyType); } if (!TypeSemantics.IsEquivalentOrPromotableTo(keyRowExpression.ResultType, TypeUsage.Create(entityKeyRowType))) { throw EntityUtil.EntitySqlError(createRefExpr.Keys.ErrCtx, System.Data.Entity.Strings.ImcompatibleCreateRefKeyElementType); } // // if CREATEREF specifies a type, resolve and validate the type // if (null != createRefExpr.TypeIdentifier) { TypeUsage targetTypeUsage = ConvertTypeIdentifier(createRefExpr.TypeIdentifier, sr); // // ensure type is entity // if (!TypeSemantics.IsEntityType(targetTypeUsage)) { throw EntityUtil.EntitySqlError(createRefExpr.TypeIdentifier.ErrCtx, System.Data.Entity.Strings.CreateRefTypeIdentifierMustSpecifyAnEntityType( targetTypeUsage.EdmType.Identity, targetTypeUsage.EdmType.BuiltInTypeKind.ToString())); } if (!TypeSemantics.IsValidPolymorphicCast(entitySet.ElementType, targetTypeUsage.EdmType)) { throw EntityUtil.EntitySqlError(createRefExpr.TypeIdentifier.ErrCtx, System.Data.Entity.Strings.CreateRefTypeIdentifierMustBeASubOrSuperType( entitySet.ElementType.Identity, targetTypeUsage.EdmType.FullName)); } converted = sr.CmdTree.CreateRefExpression(entitySet, keyRowExpression, (EntityType)targetTypeUsage.EdmType); } else { // // finally creates the expression // converted = sr.CmdTree.CreateRefExpression(entitySet, keyRowExpression); } Debug.Assert(null != converted,"null != converted"); return converted; } /// /// converts KEY operator /// /// /// SemanticResolver instance relative to a especif typespace/system ///private static DbExpression ConvertKeyExpr( Expr astExpr, SemanticResolver sr ) { KeyExpr keyExpr = (KeyExpr)astExpr; DbExpression converted = Convert(keyExpr.RefExpr, sr); SemanticResolver.EnsureIsNotUntypedNull(converted, keyExpr.RefExpr.ErrCtx); if (TypeSemantics.IsEntityType(converted.ResultType)) { converted = sr.CmdTree.CreateEntityRefExpression(converted); } else if (!TypeSemantics.IsReferenceType(converted.ResultType)) { throw EntityUtil.EntitySqlError(keyExpr.RefExpr.ErrCtx,System.Data.Entity.Strings.InvalidKeyArgument(TypeHelpers.GetFullName(converted.ResultType))); } converted = sr.CmdTree.CreateRefKeyExpression(converted); Debug.Assert(null != converted, "null != converted"); return converted; } /// /// Dispatches/Converts BuiltIn Expressions /// /// /// SemanticResolver instance relative to a especif typespace/system ///private static DbExpression ConvertBuiltIn( Expr astExpr, SemanticResolver sr ) { if (null == astExpr) { return null; } BuiltInExpr bltInExpr = (BuiltInExpr)astExpr; BuiltInExprConverter builtInConverter = _builtInExprConverter[bltInExpr.Kind]; if (null == builtInConverter) { throw EntityUtil.Argument(System.Data.Entity.Strings.UnknownBuiltInAstExpressionType); } DbExpression converted = builtInConverter(bltInExpr, sr); Debug.Assert(null != converted,"null != converted"); return converted; } /// /// Converts Arithmetic Expressions Args /// /// /// SemanticResolver instance relative to a especif typespace/system ///private static Pair ConvertArithmeticArgs( BuiltInExpr astBuiltInExpr, SemanticResolver sr ) { DbExpression leftExpr = Convert(astBuiltInExpr.Arg1, sr); if (!(TypeSemantics.IsNumericType(leftExpr.ResultType) || SemanticResolver.IsNullExpression(leftExpr))) { throw EntityUtil.EntitySqlError(astBuiltInExpr.Arg1.ErrCtx, System.Data.Entity.Strings.ExpressionMustBeNumericType); } DbExpression rightExpr = null; if (null != astBuiltInExpr.Arg2) { rightExpr = Convert(astBuiltInExpr.Arg2, sr); if (!(TypeSemantics.IsNumericType(rightExpr.ResultType) || SemanticResolver.IsNullExpression(rightExpr))) { throw EntityUtil.EntitySqlError(astBuiltInExpr.Arg2.ErrCtx, System.Data.Entity.Strings.ExpressionMustBeNumericType); } if (null == TypeHelpers.GetCommonTypeUsage(leftExpr.ResultType, rightExpr.ResultType)) { throw EntityUtil.EntitySqlError(astBuiltInExpr.ErrCtx, System.Data.Entity.Strings.ArgumentTypesAreIncompatible(leftExpr.ResultType.EdmType.FullName, rightExpr.ResultType.EdmType.FullName)); } } return sr.EnsureTypedNulls(leftExpr, rightExpr, astBuiltInExpr.ErrCtx, () => Strings.InvalidNullArithmetic); } /// /// Converts Plus Args - specific case since string type is an allowed type for '+' /// /// /// SemanticResolver instance relative to a especif typespace/system ///private static Pair ConvertPlusOperands( BuiltInExpr astBuiltInExpr, SemanticResolver sr ) { DbExpression leftExpr = Convert(astBuiltInExpr.Arg1, sr); if (!(TypeSemantics.IsNumericType(leftExpr.ResultType) || TypeSemantics.IsPrimitiveType(leftExpr.ResultType,PrimitiveTypeKind.String) || SemanticResolver.IsNullExpression(leftExpr))) { throw EntityUtil.EntitySqlError(astBuiltInExpr.Arg1.ErrCtx, System.Data.Entity.Strings.PlusLeftExpressionInvalidType); } DbExpression rightExpr = Convert(astBuiltInExpr.Arg2, sr); if (!(TypeSemantics.IsNumericType(rightExpr.ResultType) || TypeSemantics.IsPrimitiveType(rightExpr.ResultType, PrimitiveTypeKind.String) || SemanticResolver.IsNullExpression(rightExpr))) { throw EntityUtil.EntitySqlError(astBuiltInExpr.Arg2.ErrCtx, System.Data.Entity.Strings.PlusRightExpressionInvalidType); } if (null == TypeHelpers.GetCommonTypeUsage(leftExpr.ResultType, rightExpr.ResultType)) { throw EntityUtil.EntitySqlError(astBuiltInExpr.ErrCtx, System.Data.Entity.Strings.ArgumentTypesAreIncompatible(leftExpr.ResultType.EdmType.FullName, rightExpr.ResultType.EdmType.FullName)); } return sr.EnsureTypedNulls(leftExpr, rightExpr, astBuiltInExpr.ErrCtx, () => Strings.InvalidNullArithmetic); } /// /// Converts Logical Expression Args /// /// /// SemanticResolver instance relative to a especif typespace/system ///private static Pair ConvertLogicalArgs( BuiltInExpr astBuiltInExpr, SemanticResolver sr ) { DbExpression leftExpr = Convert(astBuiltInExpr.Arg1, sr); if (leftExpr is UntypedNullExpression) { leftExpr = sr.CmdTree.CreateNullExpression(sr.TypeResolver.BooleanType); } DbExpression rightExpr = Convert(astBuiltInExpr.Arg2, sr); if (rightExpr is UntypedNullExpression) { rightExpr = sr.CmdTree.CreateNullExpression(sr.TypeResolver.BooleanType); } // // ensure left expression type is boolean // if (!TypeResolver.IsBooleanType(leftExpr.ResultType)) { throw EntityUtil.EntitySqlError(astBuiltInExpr.Arg1.ErrCtx, System.Data.Entity.Strings.ExpressionTypeMustBeBoolean); } // // ensure right expression type is boolean // if (null != rightExpr && !TypeResolver.IsBooleanType(rightExpr.ResultType)) { throw EntityUtil.EntitySqlError(astBuiltInExpr.Arg2.ErrCtx, System.Data.Entity.Strings.ExpressionTypeMustBeBoolean); } return new Pair (leftExpr, rightExpr); } /// /// Converts Equal Comparison Expression Args /// /// /// SemanticResolver instance relative to a especif typespace/system ///private static Pair ConvertEqualCompArgs( BuiltInExpr astBuiltInExpr, SemanticResolver sr ) { // // convert left and right types and infer null types // Pair compArgs = sr.EnsureTypedNulls( Convert(astBuiltInExpr.Arg1, sr), Convert(astBuiltInExpr.Arg2, sr), astBuiltInExpr.ErrCtx, () => Strings.InvalidNullComparison); // // ensure both operand types are equal-comparable // if (!TypeSemantics.IsEqualComparableTo(compArgs.Left.ResultType, compArgs.Right.ResultType)) { throw EntityUtil.EntitySqlError(astBuiltInExpr.ErrCtx, System.Data.Entity.Strings.ArgumentTypesAreIncompatible(compArgs.Left.ResultType.EdmType.FullName, compArgs.Right.ResultType.EdmType.FullName)); } return compArgs; } /// /// Converts Order Comparison Expression Args /// /// /// SemanticResolver instance relative to a especif typespace/system ///private static Pair ConvertOrderCompArgs( BuiltInExpr astBuiltInExpr, SemanticResolver sr ) { Pair compArgs = sr.EnsureTypedNulls( Convert(astBuiltInExpr.Arg1, sr), Convert(astBuiltInExpr.Arg2, sr), astBuiltInExpr.ErrCtx, () => Strings.InvalidNullComparison); // // ensure both operand types are order-comparable // if (!TypeSemantics.IsOrderComparableTo(compArgs.Left.ResultType, compArgs.Right.ResultType)) { throw EntityUtil.EntitySqlError(astBuiltInExpr.ErrCtx, System.Data.Entity.Strings.ArgumentTypesAreIncompatible(compArgs.Left.ResultType.EdmType.FullName, compArgs.Right.ResultType.EdmType.FullName)); } return compArgs; } /// /// Converts Set Expression Args /// /// /// SemanticResolver instance relative to a especif typespace/system ///private static Pair ConvertSetArgs( BuiltInExpr astBuiltInExpr, SemanticResolver sr ) { // // convert left expression // DbExpression leftExpr = Convert(astBuiltInExpr.Arg1, sr); // // convert right expression if binary set op kind // DbExpression rightExpr = null; if (null != astBuiltInExpr.Arg2) { // // binary set op // // // make sure left expression type is of sequence type (ICollection or Extent) // if (!TypeSemantics.IsCollectionType(leftExpr.ResultType)) { throw EntityUtil.EntitySqlError(astBuiltInExpr.Arg1.ErrCtx, System.Data.Entity.Strings.LeftSetExpressionArgsMustBeCollection); } // // convert right expression // rightExpr = Convert(astBuiltInExpr.Arg2, sr); // // make sure right expression type is of sequence type (ICollection or Extent) // if (!TypeSemantics.IsCollectionType(rightExpr.ResultType)) { throw EntityUtil.EntitySqlError(astBuiltInExpr.Arg2.ErrCtx, System.Data.Entity.Strings.RightSetExpressionArgsMustBeCollection); } TypeUsage commonType; TypeUsage leftElemType = TypeHelpers.GetElementTypeUsage(leftExpr.ResultType); TypeUsage rightElemType = TypeHelpers.GetElementTypeUsage(rightExpr.ResultType); if (!TypeSemantics.TryGetCommonType(leftElemType, rightElemType, out commonType)) { CqlErrorHelper.ReportIncompatibleCommonType(astBuiltInExpr.ErrCtx, leftElemType, rightElemType); } if (astBuiltInExpr.Kind != BuiltInKind.UnionAll) { // // ensure left argument is set op comparable // if (!TypeHelpers.IsSetComparableOpType(TypeHelpers.GetElementTypeUsage(leftExpr.ResultType))) { throw EntityUtil.EntitySqlError(astBuiltInExpr.Arg1.ErrCtx, System.Data.Entity.Strings.PlaceholderSetArgTypeIsNotEqualComparable( astBuiltInExpr.Kind.ToString().ToUpperInvariant(), System.Data.Entity.Strings.LocalizedLeft, TypeHelpers.GetElementTypeUsage(leftExpr.ResultType).EdmType.FullName)); } // // ensure right argument is set op comparable // if (!TypeHelpers.IsSetComparableOpType(TypeHelpers.GetElementTypeUsage(rightExpr.ResultType))) { throw EntityUtil.EntitySqlError(astBuiltInExpr.Arg2.ErrCtx, System.Data.Entity.Strings.PlaceholderSetArgTypeIsNotEqualComparable( astBuiltInExpr.Kind.ToString().ToUpperInvariant(), System.Data.Entity.Strings.LocalizedRight, TypeHelpers.GetElementTypeUsage(rightExpr.ResultType).EdmType.FullName)); } } else { if (Helper.IsAssociationType(leftElemType.EdmType)) { throw EntityUtil.EntitySqlError(astBuiltInExpr.Arg1.ErrCtx, System.Data.Entity.Strings.InvalidAssociationTypeForUnion(leftElemType.Identity)); } if (Helper.IsAssociationType(rightElemType.EdmType)) { throw EntityUtil.EntitySqlError(astBuiltInExpr.Arg2.ErrCtx, System.Data.Entity.Strings.InvalidAssociationTypeForUnion(rightElemType.Identity)); } } } else { // // unary set op // // // make sure expression type is of sequence type (ICollection or Extent) // if (!TypeSemantics.IsCollectionType(leftExpr.ResultType)) { throw EntityUtil.EntitySqlError(astBuiltInExpr.Arg1.ErrCtx, System.Data.Entity.Strings.InvalidUnarySetOpArgument(astBuiltInExpr.Name)); } // // make sure that if is distinct unary operator, arg element type must be equal-comparable // if (astBuiltInExpr.Kind == BuiltInKind.Distinct && !TypeHelpers.IsValidDistinctOpType(TypeHelpers.GetElementTypeUsage(leftExpr.ResultType))) { throw EntityUtil.EntitySqlError(astBuiltInExpr.Arg1.ErrCtx, System.Data.Entity.Strings.ExpressionTypeMustBeEqualComparable); } } return new Pair (leftExpr, rightExpr); } /// /// Converts Set 'IN' expression args /// /// /// SemanticResolver instance relative to a especif typespace/system ///private static Pair ConvertInExprArgs( BuiltInExpr astBuiltInExpr, SemanticResolver sr ) { DbExpression leftExpr = Convert(astBuiltInExpr.Arg1, sr); if (TypeSemantics.IsCollectionType(leftExpr.ResultType)) { throw EntityUtil.EntitySqlError(astBuiltInExpr.Arg1.ErrCtx, System.Data.Entity.Strings.ExpressionTypeMustNotBeCollection); } DbExpression rightExpr = Convert(astBuiltInExpr.Arg2, sr); if (!TypeSemantics.IsCollectionType(rightExpr.ResultType)) { throw EntityUtil.EntitySqlError(astBuiltInExpr.Arg2.ErrCtx, System.Data.Entity.Strings.RightSetExpressionArgsMustBeCollection); } // // if left expression type is null, infer its type from the collection element type // if (SemanticResolver.IsNullExpression(leftExpr)) { TypeUsage elementType = TypeHelpers.GetElementTypeUsage(rightExpr.ResultType); SemanticResolver.EnsureValidTypeForNullExpression(elementType, astBuiltInExpr.Arg1.ErrCtx); leftExpr = sr.CmdTree.CreateNullExpression(elementType); } else { // // ensure that if left and right are typed expressions then their types must be comparable for IN op // TypeUsage commonElemType = TypeHelpers.GetCommonTypeUsage(leftExpr.ResultType, TypeHelpers.GetElementTypeUsage(rightExpr.ResultType)); if (null == commonElemType || !TypeHelpers.IsValidInOpType(commonElemType)) { throw EntityUtil.EntitySqlError(astBuiltInExpr.ErrCtx, System.Data.Entity.Strings.InvalidInExprArgs(leftExpr.ResultType.EdmType.FullName, rightExpr.ResultType.EdmType.FullName)); } } return new Pair (leftExpr, rightExpr); } /// /// Converts Type Expression Args /// /// /// SemanticResolver instance relative to a specific typespace/system ///private static Pair ConvertTypeExprArgs( BuiltInExpr astBuiltInExpr, SemanticResolver sr ) { return new Pair (Convert(astBuiltInExpr.Arg1, sr), ConvertTypeIdentifier(astBuiltInExpr.Arg2, sr)); } /// /// Converts TypeIdentifier /// TypeIdentifier can have the 'shape' of a simple identifier (product), a dotted identifier (namespace.bar) or a methodExpr ( edm.decimal(10,4) ) /// /// /// ///private static TypeUsage ConvertTypeIdentifier(Expr typeIdentifierExpr, SemanticResolver sr) { MethodExpr methodExpr = null; string[] typeNames; // // if it is dot id get full id name // DotExpr dotExpr = typeIdentifierExpr as DotExpr; if (null != dotExpr && dotExpr.IsDottedIdentifier) { typeNames = dotExpr.Names; } else { // // method expression, type with parameters // methodExpr = typeIdentifierExpr as MethodExpr; if (null != methodExpr) { typeNames = methodExpr.MethodPrefixExpr.Names; Debug.Assert(methodExpr.Args.Count == 1 || methodExpr.Args.Count == 2, "decimal type must have one or two arguments"); Debug.Assert(methodExpr.Args[0] is Literal, "type expression must have literal arg"); Debug.Assert((methodExpr.Args.Count == 2) ? methodExpr.Args[1] is Literal : true, "type expression must have literal arg"); } else { // // if it is single id, get it is name // Identifier id = typeIdentifierExpr as Identifier; if (null != id) { typeNames = new string[] { id.Name }; } else { throw EntityUtil.EntitySqlError(typeIdentifierExpr.ErrCtx, System.Data.Entity.Strings.InvalidTypeNameExpression); } } } // // Resolve type // TypeUsage typeUsage = sr.ResolveNameAsType(typeNames, typeIdentifierExpr); return typeUsage; } /// /// Converts Row type constructor expression /// /// /// SemanticResolver instance relative to a especif typespace/system ///private static DbExpression ConvertRowConstructor( Expr expr, SemanticResolver sr ) { RowConstructorExpr rowExpr = (RowConstructorExpr)expr; Dictionary rowColumns = new Dictionary (sr.ScopeStringComparer); List fieldExprs = new List (rowExpr.AliasExprList.Count); for (int i = 0 ; i < rowExpr.AliasExprList.Count ; i++) { AliasExpr aliasExpr = rowExpr.AliasExprList[i]; DbExpression colExpr = Convert(aliasExpr.Expr, sr); string aliasName = sr.InferAliasName(aliasExpr, colExpr); if (rowColumns.ContainsKey(aliasName)) { if (aliasExpr.HasAlias) { CqlErrorHelper.ReportAliasAlreadyUsedError(aliasName, aliasExpr.AliasIdentifier.ErrCtx, System.Data.Entity.Strings.InRowConstructor); } else { aliasName = sr.GenerateInternalName("autoRowCol"); } } if (SemanticResolver.IsNullExpression(colExpr)) { throw EntityUtil.EntitySqlError(aliasExpr.Expr.ErrCtx, System.Data.Entity.Strings.RowCtorElementCannotBeNull); } rowColumns.Add(aliasName, colExpr.ResultType); fieldExprs.Add(colExpr); } return sr.CmdTree.CreateNewInstanceExpression(TypeHelpers.CreateRowTypeUsage(rowColumns, true /* readOnly */), fieldExprs); } /// /// Converts Multiset type constructor expression /// /// /// SemanticResolver instance relative to a especif typespace/system ///private static DbExpression ConvertMultisetConstructor( Expr expr, SemanticResolver sr ) { MultisetConstructorExpr msetCtor = (MultisetConstructorExpr)expr; if (null == msetCtor.ExprList) { throw EntityUtil.EntitySqlError(expr.ErrCtx, System.Data.Entity.Strings.CannotCreateEmptyMultiset); } PairOfLists mSetExprs = ProcessExprList(msetCtor.ExprList, sr); TypeUsage commonType = TypeHelpers.GetCommonTypeUsage(mSetExprs.Left); // // ensure all elems have a common type // if (null == commonType) { throw EntityUtil.EntitySqlError(expr.ErrCtx, System.Data.Entity.Strings.MultisetElemsAreNotTypeCompatible); } // // ensure common type is not an untyped null // if (TypeSemantics.IsNullType(commonType)) { throw EntityUtil.EntitySqlError(expr.ErrCtx, System.Data.Entity.Strings.CannotCreateMultisetofNulls); } commonType = TypeHelpers.GetReadOnlyType(commonType); // // fixup untyped nulls // for (int i = 0 ; i < mSetExprs.Count ; i++) { if (SemanticResolver.IsNullExpression(mSetExprs.Right[i])) { SemanticResolver.EnsureValidTypeForNullExpression(commonType, msetCtor.ExprList[i].ErrCtx); mSetExprs.Right[i] = sr.CmdTree.CreateNullExpression(commonType); } } return sr.CmdTree.CreateNewInstanceExpression(TypeHelpers.CreateCollectionTypeUsage(commonType, true /* readOnly */), mSetExprs.Right); } /// /// converts case-when-then expression /// /// /// SemanticResolver instance relative to a especif typespace/system ///private static DbExpression ConvertCaseExpr( Expr expr, SemanticResolver sr ) { CaseExpr caseExpr = (CaseExpr)expr; List whenExprList = new List (caseExpr.WhenThenExprList.Count); PairOfLists thenExprList = new PairOfLists (); // // Resolve then expressions // for (int i = 0 ; i < caseExpr.WhenThenExprList.Count ; i++) { WhenThenExpr whenThenExpr = caseExpr.WhenThenExprList[i]; DbExpression whenExpression = Convert(whenThenExpr.WhenExpr, sr); if (!TypeResolver.IsBooleanType(whenExpression.ResultType)) { throw EntityUtil.EntitySqlError(whenThenExpr.WhenExpr.ErrCtx, System.Data.Entity.Strings.ExpressionTypeMustBeBoolean); } whenExprList.Add(whenExpression); DbExpression thenExpression = Convert(whenThenExpr.ThenExpr, sr); thenExprList.Add(thenExpression, thenExpression.ResultType); } TypeUsage resultType = TypeHelpers.GetCommonTypeUsage(thenExprList.Right); if (null == resultType) { throw EntityUtil.EntitySqlError(caseExpr.WhenThenExprList.Expressions[0].ThenExpr.ErrCtx, System.Data.Entity.Strings.InvalidCaseThenTypes); } if ((null == caseExpr.ElseExpr) && TypeSemantics.IsNullType(resultType)) { throw EntityUtil.EntitySqlError(caseExpr.WhenThenExprList.Expressions[0].ThenExpr.ErrCtx, System.Data.Entity.Strings.InvalidCaseThenNullType); } // // Converts else if present // DbExpression elseExpr = null; if (null != caseExpr.ElseExpr) { elseExpr = Convert(caseExpr.ElseExpr, sr); resultType = TypeHelpers.GetCommonTypeUsage(resultType, elseExpr.ResultType); if (null == resultType) { throw EntityUtil.EntitySqlError(caseExpr.ElseExpr.ErrCtx, System.Data.Entity.Strings.InvalidCaseElseType); } if (TypeSemantics.IsNullType(resultType)) { throw EntityUtil.EntitySqlError(caseExpr.ElseExpr.ErrCtx, System.Data.Entity.Strings.InvalidCaseWhenThenNullType); } if (SemanticResolver.IsNullExpression(elseExpr)) { SemanticResolver.EnsureValidTypeForNullExpression(resultType, caseExpr.ElseExpr.ErrCtx); elseExpr = sr.CmdTree.CreateNullExpression(resultType); } } else { if (TypeSemantics.IsCollectionType(resultType)) { elseExpr = sr.CmdTree.CreateNewEmptyCollectionExpression(resultType); } else { SemanticResolver.EnsureValidTypeForNullExpression(resultType, caseExpr.ErrCtx); elseExpr = sr.CmdTree.CreateNullExpression(resultType); } } // // fixup untyped nulls // for (int i = 0 ; i < thenExprList.Count ; i++) { if (SemanticResolver.IsNullExpression(thenExprList.Left[i])) { SemanticResolver.EnsureValidTypeForNullExpression(resultType, caseExpr.WhenThenExprList[i].ThenExpr.ErrCtx); thenExprList[i] = new Pair (sr.CmdTree.CreateNullExpression(resultType), resultType); } } return sr.CmdTree.CreateCaseExpression(whenExprList, thenExprList.Left, elseExpr); } /// /// Converts Query Expression /// /// /// SemanticResolver instance relative to a especif typespace/system ///private static DbExpression ConvertQuery( Expr expr, SemanticResolver sr ) { QueryExpr queryExpr = (QueryExpr)expr; DbExpression converted = null; bool isRestrictedViewGenerationMode = (ParserOptions.CompilationMode.RestrictedViewGenerationMode == sr.ParserOptions.ParserCompilationMode); // // Validate & Compensate Query // ValidateAndCompensateQuery(queryExpr); // // Create Source Scope Region // using (sr.EnterScopeRegion()) { // // Process From Clause // DbExpressionBinding sourceExpr = ProcessFromClause(queryExpr.FromClause, sr); // // Process Where Clause // sourceExpr = ProcessWhereClause(sourceExpr, queryExpr.WhereClause, sr); Debug.Assert(isRestrictedViewGenerationMode ? null == queryExpr.GroupByClause : true, "GROUP BY clause must be null in RestrictedViewGenerationMode"); Debug.Assert(isRestrictedViewGenerationMode ? null == queryExpr.HavingClause : true, "HAVING clause must be null in RestrictedViewGenerationMode"); Debug.Assert(isRestrictedViewGenerationMode ? null == queryExpr.OrderByClause : true, "ORDER BY clause must be null in RestrictedViewGenerationMode"); if ( !isRestrictedViewGenerationMode ) { // // Process GroupBy Clause // sourceExpr = ProcessGroupByClause(sourceExpr, queryExpr, sr); // // Process Having Clause // sourceExpr = ProcessHavingClause(sourceExpr, queryExpr.HavingClause, sr); // // Process OrderBy Clause // sourceExpr = ProcessOrderByClause(sourceExpr, queryExpr, sr); } // // Process Projection Clause // converted = ProcessSelectClause(sourceExpr, queryExpr, sr); } // end query scope region return converted; } /// /// Validates and Compensates query expression /// /// private static void ValidateAndCompensateQuery( QueryExpr queryExpr ) { if (null != queryExpr.HavingClause && null == queryExpr.GroupByClause) { throw EntityUtil.EntitySqlError(queryExpr.ErrCtx, System.Data.Entity.Strings.HavingRequiresGroupClause); } if (queryExpr.SelectClause.HasTopClause) { if ((null != queryExpr.OrderByClause) && queryExpr.OrderByClause.HasLimitSubClause) { throw EntityUtil.EntitySqlError(queryExpr.SelectClause.TopExpr.ErrCtx, System.Data.Entity.Strings.TopAndLimitCannotCoexist); } if ((null != queryExpr.OrderByClause) && queryExpr.OrderByClause.HasSkipSubClause) { throw EntityUtil.EntitySqlError(queryExpr.SelectClause.TopExpr.ErrCtx, System.Data.Entity.Strings.TopAndSkipCannotCoexist); } } } ////// Process Select Clause /// /// /// /// SemanticResolver instance relative to a especific typespace/system ///private static DbExpression ProcessSelectClause( DbExpressionBinding source, QueryExpr queryExpr, SemanticResolver sr ) { DbExpression projectExpression = null; SelectClause selectClause = queryExpr.SelectClause; HashSet projectionAliases = new HashSet (sr.ScopeStringComparer); List > projFields = new List >(selectClause.Items.Count); // // if source is sort/skip expression, then skip projection conversion since it was already // performed // if (queryExpr.OrderByClause != null && selectClause.DistinctKind == DistinctKind.Distinct) { projectExpression = source.Expression; } else { // // Converts projection list // #region Process projection list for (int i = 0; i < selectClause.Items.Count; i++) { AliasExpr selectExprItem = selectClause.Items[i]; DbExpression converted = Convert(selectExprItem.Expr, sr); // // ensure expression is typed // SemanticResolver.EnsureIsNotUntypedNull(converted, selectExprItem.Expr.ErrCtx); // // infer projection expression alias // string aliasName = sr.InferAliasName(selectExprItem, converted); // // ensure the alias was not used already // if (projectionAliases.Contains(aliasName)) { if (selectExprItem.HasAlias) { CqlErrorHelper.ReportAliasAlreadyUsedError(aliasName, selectExprItem.AliasIdentifier.ErrCtx, System.Data.Entity.Strings.InSelectProjectionList); } else { aliasName = sr.GenerateInternalName("autoProject"); } } projectionAliases.Add(aliasName); projFields.Add(new KeyValuePair (aliasName, converted)); } #endregion // // VALUE projection // #region handles VALUE modifier if (selectClause.SelectKind == SelectKind.SelectValue) { if (projFields.Count > 1) { throw EntityUtil.EntitySqlError(selectClause.ErrCtx, System.Data.Entity.Strings.InvalidSelectItem); } projectExpression = sr.CmdTree.CreateProjectExpression(source, projFields[0].Value); } else { projectExpression = sr.CmdTree.CreateProjectExpression(source, sr.CmdTree.CreateNewRowExpression(projFields)); } #endregion // // handle DISTINCT modifier // #region DISTINCT if (selectClause.DistinctKind == DistinctKind.Distinct) { // // ensure element type is equal-comparable // SemanticResolver.ValidateDistinctProjection(selectClause, projectExpression.ResultType); // // create distinct expression // projectExpression = sr.CmdTree.CreateDistinctExpression(projectExpression); } #endregion } // // TOP sub-clause // NOTE: WITH TIES is not supported in M3.2 // #region TOP/LIMIT sub-clause if (selectClause.HasTopClause || ((null != queryExpr.OrderByClause) && queryExpr.OrderByClause.HasLimitSubClause)) { ErrorContext errCtx = (selectClause.HasTopClause) ? selectClause.TopExpr.ErrCtx : queryExpr.OrderByClause.LimitSubClause.ErrCtx; // // convert top argument // DbExpression limitExpr = Convert((selectClause.HasTopClause) ? selectClause.TopExpr : queryExpr.OrderByClause.LimitSubClause, sr); // // ensure is not NULL expr // SemanticResolver.EnsureIsNotUntypedNull(limitExpr, errCtx); Debug.Assert(limitExpr is DbConstantExpression || limitExpr is DbParameterReferenceExpression, "TOP/LIMIT inner expression must be a parameter or numeric literal in this release"); // // ensure proper pre-conditions hold for TOP expression // sr.EnsureValidLimitExpression( errCtx, limitExpr, (selectClause.HasTopClause) ? "TOP" : "LIMIT"); // create expression - WITH TIES is not supported in M3.2 projectExpression = sr.CmdTree.CreateLimitExpression(projectExpression, limitExpr); } #endregion Debug.Assert(null != projectExpression,"null != projectExpr"); return projectExpression; } /// /// Process From Clause /// /// /// SemanticResolver instance relative to a especif typespace/system ///private static DbExpressionBinding ProcessFromClause( FromClause fromClause, SemanticResolver sr ) { DbExpressionBinding fromBinding = null; DbExpressionBinding fromBindingAux = null; // // Process Each From Clause Item // for (int i = 0 ; i < fromClause.FromClauseItems.Count ; i++ ) { // // Set Scope Source Var Kind // sr.SetCurrentScopeVarKind(fromClause.FromClauseItems[i].FromClauseItemKind); // // Convert From Clause // fromBindingAux = ProcessFromClauseItem(fromClause.FromClauseItems[i], sr); // // Reset All Vars to SourceVar Kind // sr.ResetCurrentScopeVarKind(); if (null == fromBinding) { fromBinding = fromBindingAux; } else { fromBinding = sr.CmdTree.CreateExpressionBinding( sr.CmdTree.CreateCrossApplyExpression(fromBinding, fromBindingAux), sr.GenerateInternalName("lcapply")); sr.FixupNamedSourceVarBindings(fromBinding.Variable); } } Debug.Assert(null != fromBinding,"null != fromBinding"); return fromBinding; } /// /// Process Generic From Clause Item /// /// /// SemanticResolver instance relative to a especif typespace/system ///private static DbExpressionBinding ProcessFromClauseItem( FromClauseItem fromClauseItem, SemanticResolver sr ) { DbExpressionBinding fromItemBinding = null; AliasExpr aliasExpr = fromClauseItem.FromExpr as AliasExpr; if (null != aliasExpr) { fromItemBinding = ProcessAliasedFromClauseItem(aliasExpr, sr); } else { JoinClauseItem joinClauseItem = fromClauseItem.FromExpr as JoinClauseItem; if (null != joinClauseItem) { fromItemBinding = ProcessJoinClauseItem(joinClauseItem, sr); } else { fromItemBinding = ProcessApplyClauseItem((ApplyClauseItem)fromClauseItem.FromExpr, sr); } } Debug.Assert(null != fromItemBinding,"null != fromItemBinding"); return fromItemBinding; } /// /// Process 'Simple' From Clause Item /// /// /// SemanticResolver instance relative to a especif typespace/system ///private static DbExpressionBinding ProcessAliasedFromClauseItem( AliasExpr aliasedExpr, SemanticResolver sr ) { DbExpressionBinding aliasedBinding = null; // // converts from item expression // DbExpression converted = Convert(aliasedExpr.Expr, sr); // // ensure expression is typed // SemanticResolver.EnsureIsNotUntypedNull(converted, aliasedExpr.Expr.ErrCtx); // // validate it is of sequence type (Extent || ICollection) // if (!TypeSemantics.IsCollectionType(converted.ResultType)) { throw EntityUtil.EntitySqlError(aliasedExpr.Expr.ErrCtx, System.Data.Entity.Strings.ExpressionMustBeCollection); } // // infer source var alias name // string aliasName = sr.InferAliasName(aliasedExpr, converted); // // validate the name was not used yet. // if (sr.IsInCurrentScope(aliasName)) { if (aliasedExpr.HasAlias) { CqlErrorHelper.ReportAliasAlreadyUsedError(aliasName, aliasedExpr.AliasIdentifier.ErrCtx, System.Data.Entity.Strings.InFromClause); } else { aliasName = sr.GenerateInternalName("autoFrom"); } } // // create cqt expression // aliasedBinding = sr.CmdTree.CreateExpressionBinding(converted, aliasName); // // add source var to scope // sr.AddSourceBinding(aliasedBinding); Debug.Assert(null != aliasedBinding,"null != aliasedBinding"); return aliasedBinding; } /// /// process join clause item /// /// /// SemanticResolver instance relative to a especif typespace/system ///private static DbExpressionBinding ProcessJoinClauseItem( JoinClauseItem joinClause, SemanticResolver sr ) { DbExpressionBinding joinBinding = null; // // make sure inner join have on predicate AND cross join has no ON predicate // if (null == joinClause.OnExpr) { if (JoinKind.Inner == joinClause.JoinKind) { throw EntityUtil.EntitySqlError(joinClause.ErrCtx, System.Data.Entity.Strings.InnerJoinMustHaveOnPredicate); } } else { if (JoinKind.Cross == joinClause.JoinKind) { throw EntityUtil.EntitySqlError(joinClause.OnExpr.ErrCtx, System.Data.Entity.Strings.InvalidPredicateForCrossJoin); } } // // Resolve Left Expression // sr.CurrentScopeRegionFlags.PathTagger.VisitLeftNode(); DbExpressionBinding leftBindingExpr = ProcessFromClauseItem(joinClause.LeftExpr, sr); sr.CurrentScopeRegionFlags.PathTagger.LeaveNode(); // // Resolve Right Expression // sr.CurrentScopeRegionFlags.IsInsideJoinOnPredicate = false; sr.CurrentScopeRegionFlags.PathTagger.VisitRightNode(); DbExpressionBinding rightBindingExpr = ProcessFromClauseItem(joinClause.RightExpr, sr); sr.CurrentScopeRegionFlags.PathTagger.LeaveNode(); // // convert right outer to left outer // if (joinClause.JoinKind == JoinKind.RightOuter) { joinClause.JoinKind = JoinKind.LeftOuter; DbExpressionBinding tmpExpr = leftBindingExpr; leftBindingExpr = rightBindingExpr; rightBindingExpr = tmpExpr; } // // Resolve JoinType // DbExpressionKind joinKind = SemanticResolver.MapJoinKind(joinClause.JoinKind); // // Resolve ON // sr.CurrentScopeRegionFlags.IsInsideJoinOnPredicate = true; DbExpression onExpr = null; if (null == joinClause.OnExpr) { if (DbExpressionKind.CrossJoin != joinKind) { onExpr = sr.CmdTree.CreateTrueExpression(); } } else { onExpr = Convert(joinClause.OnExpr, sr); // // ensure expression is typed // SemanticResolver.EnsureIsNotUntypedNull(onExpr, joinClause.OnExpr.ErrCtx); } sr.CurrentScopeRegionFlags.IsInsideJoinOnPredicate = false; // // Create New Join // joinBinding = sr.CmdTree.CreateExpressionBinding( sr.CmdTree.CreateJoinExpressionByKind(joinKind, onExpr, leftBindingExpr, rightBindingExpr), sr.GenerateInternalName("join")); // // Fixup Join Source Vars in Scope // sr.FixupNamedSourceVarBindings(joinBinding.Variable); Debug.Assert(null != joinBinding,"null != joinBinding"); return joinBinding; } /// /// Process apply clause item /// /// /// SemanticResolver instance relative to a especif typespace/system ///private static DbExpressionBinding ProcessApplyClauseItem( ApplyClauseItem applyClause, SemanticResolver sr ) { DbExpressionBinding applyBinding = null; // // Resolve Left Expression // sr.CurrentScopeRegionFlags.PathTagger.VisitLeftNode(); DbExpressionBinding leftBindingExpr = ProcessFromClauseItem(applyClause.LeftExpr, sr); sr.CurrentScopeRegionFlags.PathTagger.LeaveNode(); // // Resolve Right Expression // sr.CurrentScopeRegionFlags.PathTagger.VisitRightNode(); DbExpressionBinding rightBindingExpr = ProcessFromClauseItem(applyClause.RightExpr, sr); sr.CurrentScopeRegionFlags.PathTagger.LeaveNode(); // // Create Apply // applyBinding = sr.CmdTree.CreateExpressionBinding( sr.CmdTree.CreateApplyExpressionByKind(SemanticResolver.MapApplyKind(applyClause.ApplyKind), leftBindingExpr, rightBindingExpr), sr.GenerateInternalName("apply")); // // Fixup Apply Source Vars in Scope // sr.FixupNamedSourceVarBindings(applyBinding.Variable); Debug.Assert(null != applyBinding,"null != applyBinding"); return applyBinding; } /// /// Process Where Expression /// /// /// /// SemanticResolver instance relative to a especif typespace/system ///private static DbExpressionBinding ProcessWhereClause( DbExpressionBinding source, Expr whereClause, SemanticResolver sr ) { if (null == whereClause) { return source; } DbExpressionBinding whereBinding = null; // // Convert Where Condition // DbExpression filterConditionExpr = Convert(whereClause, sr); // // ensure expression is typed // SemanticResolver.EnsureIsNotUntypedNull(filterConditionExpr, whereClause.ErrCtx); // // ensure the predicate type is boolean // if (!TypeResolver.IsBooleanType(filterConditionExpr.ResultType)) { throw EntityUtil.EntitySqlError(whereClause.ErrCtx, System.Data.Entity.Strings.ExpressionTypeMustBeBoolean); } // // Create New Filter Binding // whereBinding = sr.CmdTree.CreateExpressionBinding( sr.CmdTree.CreateFilterExpression(source, filterConditionExpr), sr.GenerateInternalName("where")); // // Fixup Bindings // sr.FixupSourceVarBindings(whereBinding.Variable); Debug.Assert(null != whereBinding,"null != whereBinding"); return whereBinding; } /// /// Process Group By Clause /// /// /// /// SemanticResolver instance relative to a especif typespace/system ///private static DbExpressionBinding ProcessGroupByClause( DbExpressionBinding source, QueryExpr queryExpr, SemanticResolver sr ) { SemanticResolver.ScopeViewKind saveScopeView = sr.GetScopeView(); GroupByClause groupByClause = queryExpr.GroupByClause; Debug.Assert((sr.ParserOptions.ParserCompilationMode == ParserOptions.CompilationMode.RestrictedViewGenerationMode) ? null == groupByClause : true, "GROUP BY clause must be null in RestrictedViewGenerationMode"); // // if group expression is null, create a dummy and speculate that there are group aggregates in the remaining query expression // if no group aggregate if found after partial evaluation of Having, OrderBy and Select in the 1st pass, rollback what we did // and return source expression. // #region Define Implicit Group if needed if (null == queryExpr.GroupByClause) { if (!queryExpr.HasMethodCall) { return source; } // // if group expression is null create a dummy and speculate that there are group aggregates in the remaining query expression // if no group aggregate if found after partial evaluation of Having, OrderBy and Select in the 1st pass, rollback what we did // and return source expression. // sr.CurrentScopeRegionFlags.IsImplicitGroup = true; } else { sr.CurrentScopeRegionFlags.IsImplicitGroup = false; } #endregion DbExpressionBinding groupBinding = null; // // Create Group Binding // DbGroupExpressionBinding groupExprBinding = sr.CmdTree.CreateGroupExpressionBinding( source.Expression, sr.GenerateInternalName("geb"), sr.GenerateInternalName("group")); // // Update source scope vars // sr.FixupGroupSourceVarBindings(groupExprBinding.Variable, groupExprBinding.GroupVariable); // // convert group elements // #region Convert Group Key/Expressions int groupKeysCount = (null != groupByClause ) ? groupByClause.GroupItems.Count : 0; List > groupKeys = new List >(groupKeysCount); HashSet groupKeyNames = new HashSet (sr.ScopeStringComparer); List groupKeysForAggregates = new List (8); if (!sr.CurrentScopeRegionFlags.IsImplicitGroup) { Debug.Assert(null != groupByClause, "groupByClause must not be null at this point"); for (int i = 0 ; i < groupKeysCount ; i++) { AliasExpr aliasedExpr = groupByClause.GroupItems[i]; sr.ResetScopeRegionCorrelationFlag(); // // convert key expression (relative to DbGroupExpressionBinding.Var) // DbExpression converted = Convert(aliasedExpr.Expr, sr); // // ensure expression is typed // SemanticResolver.EnsureIsNotUntypedNull(converted, aliasedExpr.Expr.ErrCtx); // // ensure group key expression is correlated // if (!sr.CurrentScopeRegionFlags.WasResolutionCorrelated) { throw EntityUtil.EntitySqlError(aliasedExpr.Expr.ErrCtx, System.Data.Entity.Strings.KeyMustBeCorrelated("GROUP BY")); } // // convert key expression (relative to DbGroupExpressionBinding.GroupVar) // this is only needed because during the search for groupaggregates, group aggregates may // refer to group keys. // sr.CurrentScopeRegionFlags.IsInsideGroupAggregate = true; DbExpression groupKeyAggExpr = Convert(aliasedExpr.Expr, sr); groupKeysForAggregates.Add(groupKeyAggExpr); sr.CurrentScopeRegionFlags.IsInsideGroupAggregate = false; // // ensure keys are valid // if (!TypeHelpers.IsValidGroupKeyType(converted.ResultType)) { throw EntityUtil.EntitySqlError(aliasedExpr.Expr.ErrCtx, System.Data.Entity.Strings.GroupingKeysMustBeEqualComparable); } // // infer alias name // string groupKeyAlias = sr.InferAliasName(aliasedExpr, converted); // // check if alias was already used // if (groupKeyNames.Contains(groupKeyAlias)) { if (aliasedExpr.HasAlias) { CqlErrorHelper.ReportAliasAlreadyUsedError(groupKeyAlias, aliasedExpr.AliasIdentifier.ErrCtx, System.Data.Entity.Strings.InGroupClause); } else { groupKeyAlias = sr.GenerateInternalName("autoGroup"); } } // // add key name to alias dictionary // groupKeyNames.Add(groupKeyAlias); // // add key to keys collection // groupKeys.Add(new KeyValuePair (groupKeyAlias, converted)); // // group keys should visible by their 'original' key expression name. All forms should be allowed: // SELECT k FROM ... as p GROUP BY p.Price as k (explicit key alias) - handled above by InferAliasName() // SELECT Price FROM ... as p GROUP BY p.Price (implicit alias - leading name) - handled above by InferAliasName() // SELECT p.Price FROM ... as p GROUP BY p.Price (original key expression) - case handled in the code bellow // if (!aliasedExpr.HasAlias) { DotExpr dotExpr = aliasedExpr.Expr as DotExpr; if (null != dotExpr && dotExpr.IsDottedIdentifier) { groupKeyAlias = dotExpr.FullName; if (groupKeyNames.Contains(groupKeyAlias)) { CqlErrorHelper.ReportAliasAlreadyUsedError(groupKeyAlias, dotExpr.ErrCtx, System.Data.Entity.Strings.InGroupClause); } groupKeyNames.Add(groupKeyAlias); groupKeys.Add(new KeyValuePair (groupKeyAlias, converted)); groupKeysForAggregates.Add(groupKeyAggExpr); } } } } #endregion // // save scope status // SavePoint savePoint = sr.CreateSavePoint(); // // Push Group scope // sr.EnterScope(); // // Add converted group variables/expressions to group scope // #region Add Converted Group Variables to Scope // // add 'dummy' keys to scope. // this is needed since during the aggreagate search phase, keys may be referenced. // for (int i = 0 ; i < groupKeys.Count ; i++) { sr.AddDummyGroupKeyToScope(groupKeys[i].Key, groupKeys[i].Value, groupKeysForAggregates[i]); } // // flags that we are inside a group scope // sr.CurrentScopeRegionFlags.IsInGroupScope = true; #endregion // // Convert/Search Aggregates // since aggregates can be defined in Having, OrderBy and/or Select clauses must be resolved as part of the group expression. // The resolution of these clauses result in potential collection of resolved group aggregates and the actual resulting // expression is ignored. These clauses will be then resolved as usual on a second pass. // #region Search for group Aggregates // // search for aggregates in HAVING clause // if (null != queryExpr.HavingClause && queryExpr.HavingClause.HasMethodCall) { sr.CurrentScopeRegionFlags.ResetGroupAggregateNestingCount(); DbExpression converted = Convert(queryExpr.HavingClause.HavingPredicate, sr); // // ensure expression is typed // SemanticResolver.EnsureIsNotUntypedNull(converted, queryExpr.HavingClause.ErrCtx); } // // search for aggregates in SELECT clause // Dictionary sortExpr = null; if ( null != queryExpr.OrderByClause || queryExpr.SelectClause.HasMethodCall ) { sortExpr = new Dictionary (queryExpr.SelectClause.Items.Count, sr.ScopeStringComparer); for ( int i = 0 ; i < queryExpr.SelectClause.Items.Count ; i++ ) { AliasExpr aliasedExpr = queryExpr.SelectClause.Items[i]; // // Reset Group aggregate nesting count // sr.CurrentScopeRegionFlags.ResetGroupAggregateNestingCount(); // // convert projection item expression // DbExpression converted = Convert(aliasedExpr.Expr, sr); // // ensure expression is typed // SemanticResolver.EnsureIsNotUntypedNull(converted, aliasedExpr.Expr.ErrCtx); // // create Null Expression with actual type // converted = sr.CmdTree.CreateNullExpression(converted.ResultType); // // infer alias // string aliasName = sr.InferAliasName(aliasedExpr, converted); if ( sortExpr.ContainsKey(aliasName) ) { if ( aliasedExpr.HasAlias ) { CqlErrorHelper.ReportAliasAlreadyUsedError(aliasName, aliasedExpr.AliasIdentifier.ErrCtx, System.Data.Entity.Strings.InSelectProjectionList); } else { aliasName = sr.GenerateInternalName("autoProject"); } } sortExpr.Add(aliasName, converted); } } // // search for aggregates in ORDER BY clause // if (null != queryExpr.OrderByClause && queryExpr.OrderByClause.HasMethodCall) { // // push projection key scope // sr.EnterScope(); // // Add projection items to scope (it may be used in ORDER BY) // foreach ( KeyValuePair kvp in sortExpr ) { sr.AddToScope(kvp.Key, new ProjectionScopeEntry(kvp.Key, kvp.Value)); } // // search for aggregates in ORDER BY clause // for (int i = 0 ; i < queryExpr.OrderByClause.OrderByClauseItem.Count ; i++) { OrderByClauseItem orderItem = queryExpr.OrderByClause.OrderByClauseItem[i]; sr.CurrentScopeRegionFlags.ResetGroupAggregateNestingCount(); sr.ResetScopeRegionCorrelationFlag(); DbExpression converted = Convert(orderItem.OrderExpr, sr); // // ensure expression is typed // SemanticResolver.EnsureIsNotUntypedNull(converted, orderItem.OrderExpr.ErrCtx); // // ensure key expression is correlated // if (!sr.CurrentScopeRegionFlags.WasResolutionCorrelated) { throw EntityUtil.EntitySqlError(orderItem.ErrCtx, System.Data.Entity.Strings.KeyMustBeCorrelated("ORDER BY")); } } // // pop projection scope // sr.LeaveScope(); } #endregion // // if we introduced a fake group but did not 'found' any group aggregate // on the first pass, then there is no need for creating an implicit group. // rollback to the status before entering ProcessGroupByClause(). // if we did find group aggregates, make sure all non-group aggregate function // expressions refer to group scope variables only // #region Implicit Group Rollback if (sr.CurrentScopeRegionFlags.IsImplicitGroup) { if (0 == sr.CurrentScopeRegionFlags.GroupAggregatesInfo.Count) { // // rolls back scope status // sr.RollbackToSavepoint(savePoint); // // undo any group source fixups, re-applying the source var // sr.UndoFixupGroupSourceVarBindings(source.Variable); // // reset is inside group scope flag // sr.CurrentScopeRegionFlags.IsInGroupScope = false; //// //// reset implict group flag //// sr.CurrentScopeRegionFlags.IsImplicitGroup = false; // // restore scope view kind // sr.SetScopeView(saveScopeView); // // return the original source var binding // return source; } // // now that we know that there are group aggregates in other expression, reset implict group flag to false // since it is now considered a legitimate group // sr.CurrentScopeRegionFlags.IsImplicitGroup = false; } #endregion // // extract list of aggregates and names // List > aggregates = new List >(sr.CurrentScopeRegionFlags.GroupAggregatesInfo.Count); foreach(KeyValuePair kvp in sr.CurrentScopeRegionFlags.GroupAggregatesInfo) { aggregates.Add(new KeyValuePair (kvp.Value.AggregateName, kvp.Value.AggregateExpression)); kvp.Key.ResetDummyExpression(); } // // Create Group Expression // groupBinding = sr.CmdTree.CreateExpressionBinding( sr.CmdTree.CreateGroupByExpression( groupExprBinding, groupKeys, aggregates), sr.GenerateInternalName("group")); // // replace dummy keys with real keys // for (int i = 0 ; i < groupKeys.Count ; i++) { sr.ReplaceGroupVarInScope(groupKeys[i].Key, groupBinding.Variable); } // // add aggregates to scope // for (int i = 0 ; i < aggregates.Count ; i++ ) { sr.CurrentScopeRegionFlags.AddGroupAggregateToScopeFlags(aggregates[i].Key); sr.AddGroupAggregateToScope(aggregates[i].Key, groupBinding.Variable); } // // restrict group scope visibility // sr.SetScopeView(SemanticResolver.ScopeViewKind.GroupScope); // // fixup all source vars // sr.FixupNamedSourceVarBindings(groupBinding.Variable); // // Mark source vars as group input vars // sr.MarkGroupInputVars(); Debug.Assert(null != groupBinding,"null != groupBinding"); return groupBinding; } /// /// Process Having Clause /// /// /// /// SemanticResolver instance relative to a especif typespace/system ///private static DbExpressionBinding ProcessHavingClause( DbExpressionBinding source, HavingClause havingClause, SemanticResolver sr ) { Debug.Assert((sr.ParserOptions.ParserCompilationMode == ParserOptions.CompilationMode.RestrictedViewGenerationMode) ? null == havingClause : true, "HAVING clause must be null in RestrictedViewGenerationMode"); if (null == havingClause) { return source; } DbExpressionBinding havingBinding = null; // // Convert Having Expression // DbExpression filterConditionExpr = Convert(havingClause.HavingPredicate, sr); // // ensure expression is typed // SemanticResolver.EnsureIsNotUntypedNull(filterConditionExpr, havingClause.ErrCtx); // // ensure having predicate of boolean type // if (!TypeResolver.IsBooleanType(filterConditionExpr.ResultType)) { throw EntityUtil.EntitySqlError(havingClause.ErrCtx, System.Data.Entity.Strings.ExpressionTypeMustBeBoolean); } // // Create New Filter Binding // havingBinding = sr.CmdTree.CreateExpressionBinding( sr.CmdTree.CreateFilterExpression(source, filterConditionExpr), sr.GenerateInternalName("having")); // // Fixup Bindings // sr.FixupSourceVarBindings(havingBinding.Variable); Debug.Assert(null != havingBinding,"null != havingBinding"); return havingBinding; } /// /// Process Order By Clause /// /// /// /// SemanticResolver instance relative to a especif typespace/system ///private static DbExpressionBinding ProcessOrderByClause( DbExpressionBinding source, QueryExpr queryExpr, SemanticResolver sr ) { Debug.Assert((sr.ParserOptions.ParserCompilationMode == ParserOptions.CompilationMode.RestrictedViewGenerationMode) ? null == queryExpr.OrderByClause : true, "ORDER BY clause must be null in RestrictedViewGenerationMode"); if (null == queryExpr.OrderByClause) { return source; } DbExpressionBinding sortBinding = null; OrderByClause orderByClause = queryExpr.OrderByClause; SelectClause selectClause = queryExpr.SelectClause; // // Create a savepoint // SavePoint savePoint = sr.CreateSavePoint(); // // perform partial conversion of SELECT statements // Dictionary projectionExpressions = new Dictionary (selectClause.Items.Count, sr.ScopeStringComparer); for (int i = 0 ; i < selectClause.Items.Count ; i++) { AliasExpr aliasedExpr = selectClause.Items[i]; DbExpression converted = Convert(aliasedExpr.Expr, sr); // // ensure expression is typed // SemanticResolver.EnsureIsNotUntypedNull(converted, aliasedExpr.Expr.ErrCtx); // // infer projection alias // string aliasName = sr.InferAliasName(aliasedExpr, converted); if (projectionExpressions.ContainsKey(aliasName)) { if (aliasedExpr.HasAlias) { CqlErrorHelper.ReportAliasAlreadyUsedError(aliasName, aliasedExpr.AliasIdentifier.ErrCtx, System.Data.Entity.Strings.InSelectProjectionList); } else { aliasName = sr.GenerateInternalName("autoProject"); } } projectionExpressions.Add(aliasName, converted); } // // convert paging sub-clauses they if exists before adding projection list to scope // NOTE: TOP, LIMIT and SKIP have nearly the same constraints in M3.2. in the future this is likely to change by allowing // these sub-clauses to have generic expressions. // #region Handles SKIP sub-clause DbExpression skipExpr = null; if (orderByClause.HasSkipSubClause) { skipExpr = Convert(orderByClause.SkipSubClause, sr); // // ensure is not NULL expr // SemanticResolver.EnsureIsNotUntypedNull(skipExpr, orderByClause.SkipSubClause.ErrCtx); DbConstantExpression constantExpr = skipExpr as DbConstantExpression; Debug.Assert(constantExpr!=null || skipExpr is DbParameterReferenceExpression, "SKIP inner expression must be a parameter or numeric literal in this release"); // // ensure SKIP expression have the right type // if (!TypeSemantics.IsPromotableTo(skipExpr.ResultType, sr.TypeResolver.Int64Type)) { throw EntityUtil.EntitySqlError(orderByClause.SkipSubClause.ErrCtx, System.Data.Entity.Strings.PlaceholderExpressionMustBeCompatibleWithEdm64("SKIP", skipExpr.ResultType.EdmType.FullName)); } // // if it is a literal, make sure it has the correct value // if (null != constantExpr && System.Convert.ToInt64(constantExpr.Value, CultureInfo.InvariantCulture) < 0) { throw EntityUtil.EntitySqlError(orderByClause.SkipSubClause.ErrCtx, System.Data.Entity.Strings.PlaceholderExpressionMustBeGreaterThanOrEqualToZero("SKIP")); } } #endregion // // Push scope for projection items // sr.EnterScope(); // // Add projection items to scope // foreach (KeyValuePair kvp in projectionExpressions) { // // if the reference expression is a group aggregate, then there is no need to add to scope // if (!sr.CurrentScopeRegionFlags.ContainsGroupAggregate(kvp.Key)) { sr.AddToScope(kvp.Key, new ProjectionScopeEntry(kvp.Key, kvp.Value)); } } // // save scope view // SemanticResolver.ScopeViewKind saveScopeView = sr.GetScopeView(); // // If DISTICT was especified set visibility to current scope only // if DISTINCT modifier is present, push the projection and distinct expression down bellow // sort/skip expressions // if (selectClause.DistinctKind == DistinctKind.Distinct) { sr.SetScopeView(SemanticResolver.ScopeViewKind.CurrentScope); List > projectionExpressionList = new List >(projectionExpressions); // // Create projection // DbExpression projectExpression; if (selectClause.SelectKind == SelectKind.SelectRow) { projectExpression = sr.CmdTree.CreateNewRowExpression(projectionExpressionList); } else { Debug.Assert(selectClause.Items.Count == 1, "SELECT VALUE must have only one argument"); projectExpression = projectionExpressionList[0].Value; } projectExpression = sr.CmdTree.CreateProjectExpression(source, projectExpression); // // Ensure Projection is valid for DISTINCT modifier // SemanticResolver.ValidateDistinctProjection(selectClause, projectExpression.ResultType); // // create new source binding // source = sr.CmdTree.CreateExpressionBinding(sr.CmdTree.CreateDistinctExpression(projectExpression), sr.GenerateInternalName("distinct")); // // replace Projection scope with new expression bindings // for (int i = 0; i < projectionExpressionList.Count; i++) { if (!sr.CurrentScopeRegionFlags.ContainsGroupAggregate(projectionExpressionList[i].Key)) { // remove old scope var sr.RemoveFromScope(projectionExpressionList[i].Key); // create and add new source var to scope SourceScopeEntry sce = new SourceScopeEntry(ScopeEntryKind.SourceVar, projectionExpressionList[i].Key, source.Variable); if (selectClause.SelectKind == SelectKind.SelectRow) { sce.AddBindingPrefix(projectionExpressionList[i].Key); } sr.AddToScope(projectionExpressionList[i].Key, sce); } } } // // if is not DISTINCT, but is a group scope, then should be the group scope and the // projection list // else if (sr.CurrentScopeRegionFlags.IsInGroupScope) { sr.SetScopeView(SemanticResolver.ScopeViewKind.CurrentAndPreviousScope); } // // convert sort keys // List sortKeys = new List (orderByClause.OrderByClauseItem.Expressions.Count); for (int i = 0 ; i < orderByClause.OrderByClauseItem.Expressions.Count ; i++) { OrderByClauseItem orderClauseItem = orderByClause.OrderByClauseItem.Expressions[i]; sr.CurrentScopeRegionFlags.ResetGroupAggregateNestingCount(); sr.ResetScopeRegionCorrelationFlag(); // // convert order key expression // DbExpression keyExpr = Convert(orderClauseItem.OrderExpr, sr); // // ensure expression is typed // SemanticResolver.EnsureIsNotUntypedNull(keyExpr, orderClauseItem.OrderExpr.ErrCtx); // // ensure key expression is correlated. if group by is present, then the check was already performed // if (!sr.CurrentScopeRegionFlags.WasResolutionCorrelated) { throw EntityUtil.EntitySqlError(orderClauseItem.ErrCtx, System.Data.Entity.Strings.KeyMustBeCorrelated("ORDER BY")); } // // ensure key is order comparable // if (!TypeHelpers.IsValidSortOpKeyType(keyExpr.ResultType)) { throw EntityUtil.EntitySqlError(orderClauseItem.OrderExpr.ErrCtx, System.Data.Entity.Strings.OrderByKeyIsNotOrderComparable); } // // define order // bool ascSort = (orderClauseItem.OrderKind == OrderKind.None) || (orderClauseItem.OrderKind == OrderKind.Asc); // // define collation // string collation = null; if (orderClauseItem.IsCollated) { if (!TypeResolver.IsKeyValidForCollation(keyExpr.ResultType)) { throw EntityUtil.EntitySqlError(orderClauseItem.OrderExpr.ErrCtx, System.Data.Entity.Strings.InvalidKeyTypeForCollation(keyExpr.ResultType.EdmType.FullName)); } collation = orderClauseItem.CollateIdentifier.Name; } // // if orderby has no collation defined, check if a default was given through ParserOptions // else if (sr.ParserOptions.DefaultOrderByCollation.Length > 0 && TypeResolver.IsKeyValidForCollation(keyExpr.ResultType)) { collation = sr.ParserOptions.DefaultOrderByCollation; } // // add keys to key collection // if (string.IsNullOrEmpty(collation)) { sortKeys.Add(sr.CmdTree.CreateSortClause(keyExpr, ascSort)); } else { sortKeys.Add(sr.CmdTree.CreateSortClause(keyExpr, ascSort, collation)); } } DbExpression sortSourceExpr = null; if (orderByClause.HasSkipSubClause) { sortSourceExpr = sr.CmdTree.CreateSkipExpression(source, sortKeys, skipExpr); } else { sortSourceExpr = sr.CmdTree.CreateSortExpression(source, sortKeys); } // // Create Sort Binding // sortBinding = sr.CmdTree.CreateExpressionBinding( sortSourceExpr, sr.GenerateInternalName("sort")); // // Fixup Bindings // sr.FixupSourceVarBindings(sortBinding.Variable); // // pops projection keys from scope // sr.RollbackToSavepoint(savePoint); // // restore scope view // sr.SetScopeView(saveScopeView); Debug.Assert(null != sortBinding,"null != sortBinding"); return sortBinding; } /// /// Converts a list of ast expression nodes /// /// /// SemanticResolver instance relative to a especif typespace/system ///private static PairOfLists ProcessExprList( ExprList astExprList, SemanticResolver sr ) { List types = new List (astExprList.Count); List convertedExprs = new List (astExprList.Count); for (int i = 0 ; i < astExprList.Count ; i++) { DbExpression e = Convert(astExprList[i], sr); types.Add(e.ResultType); convertedExprs.Add(e); } return new PairOfLists (types, convertedExprs); } /// /// [....]: Temporary workaround for 2/3 milestone. /// Convert "x in multiset(y1, y2, ..., yn)" into /// x = y1 or x = y2 or x = y3 ... /// /// semantic resolver /// left-expression (the probe) /// right expression (the collection) ///Or chain of equality comparisons private static DbExpression ConvertSimpleInExpression( SemanticResolver sr, DbExpression left, DbExpression right ) { // Only handle cases when the right-side is a new instance expression Debug.Assert(right.ExpressionKind == DbExpressionKind.NewInstance,"right.ExpressionKind == DbExpressionKind.NewInstance"); DbNewInstanceExpression rightColl = (DbNewInstanceExpression)right; if (rightColl.Arguments.Count == 0) { return sr.CmdTree.CreateConstantExpression(false); } DbExpression orExpr = null; foreach (DbExpression e in rightColl.Arguments) { DbExpression leftClone = (DbExpression)left.Clone(); DbExpression eqExpr = sr.CmdTree.CreateEqualsExpression(leftClone, e); if (orExpr == null) { orExpr = eqExpr; } else { orExpr = sr.CmdTree.CreateOrExpression(orExpr, eqExpr); } } return orExpr; } #region Conversion Delegate Mappings private delegate DbExpression AstExprConverter( Expr astExpr, SemanticResolver sr ); private static readonly Dictionary_astExprConverters = CreateAstExprConverters(); private delegate DbExpression BuiltInExprConverter( BuiltInExpr astBltInExpr, SemanticResolver sr ); private static readonly Dictionary _builtInExprConverter = CreateBuiltInExprConverter(); #region Define converter delegates private static Dictionary CreateAstExprConverters() { const int NumberOfElements = 15; // number of elements initialized by the dictionary Dictionary astExprConverters = new Dictionary (NumberOfElements); astExprConverters.Add(typeof(Literal), new AstExprConverter(ConvertLiteral)); astExprConverters.Add(typeof(Parameter), new AstExprConverter(ConvertParameter)); astExprConverters.Add(typeof(Identifier), new AstExprConverter(ConvertIdentifier)); astExprConverters.Add(typeof(DotExpr), new AstExprConverter(ConvertDotExpr)); astExprConverters.Add(typeof(BuiltInExpr), new AstExprConverter(ConvertBuiltIn)); astExprConverters.Add(typeof(QueryExpr), new AstExprConverter(ConvertQuery)); astExprConverters.Add(typeof(RowConstructorExpr), new AstExprConverter(ConvertRowConstructor)); astExprConverters.Add(typeof(MultisetConstructorExpr), new AstExprConverter(ConvertMultisetConstructor)); astExprConverters.Add(typeof(CaseExpr), new AstExprConverter(ConvertCaseExpr)); astExprConverters.Add(typeof(RelshipNavigationExpr), new AstExprConverter(ConvertRelshipNavigationExpr)); astExprConverters.Add(typeof(RefExpr), new AstExprConverter(ConvertRefExpr)); astExprConverters.Add(typeof(DerefExpr), new AstExprConverter(ConvertDeRefExpr)); astExprConverters.Add(typeof(MethodExpr), new AstExprConverter(ConvertMethodExpr)); astExprConverters.Add(typeof(CreateRefExpr), new AstExprConverter(ConvertCreateRefExpr)); astExprConverters.Add(typeof(KeyExpr), new AstExprConverter(ConvertKeyExpr)); Debug.Assert(NumberOfElements == astExprConverters.Count, "The number of elements and initial capacity don't match"); return astExprConverters; } private static Dictionary CreateBuiltInExprConverter() { Dictionary builtInExprConverter = new Dictionary (sizeof(BuiltInKind)); //////////////////////////// // Arithmetic Expressions //////////////////////////// // // e1 + e2 // #region e1 + e2 builtInExprConverter.Add(BuiltInKind.Plus, delegate( BuiltInExpr bltInExpr, SemanticResolver sr ) { Pair args = ConvertPlusOperands(bltInExpr, sr); if (TypeSemantics.IsNumericType(args.Left.ResultType)) { return sr.CmdTree.CreatePlusExpression(args.Left, args.Right); } else { // // fold '+' operator into concat canonical function // IList functions; if (!sr.TypeResolver.TryGetFunctionFromMetadata("Concat","Edm", true /* ignoreCase */, out functions)) { throw EntityUtil.EntitySqlError(bltInExpr.ErrCtx, System.Data.Entity.Strings.ConcatBuiltinNotSupported); } List argTypes = new List (2); argTypes.Add(args.Left.ResultType); argTypes.Add(args.Right.ResultType); bool isAmbiguous = false; EdmFunction concatFunction = TypeResolver.ResolveFunctionOverloads(functions, argTypes, false /* isGroupAggregate */, out isAmbiguous); if (null == concatFunction || isAmbiguous) { throw EntityUtil.EntitySqlError(bltInExpr.ErrCtx, System.Data.Entity.Strings.ConcatBuiltinNotSupported); } return sr.CmdTree.CreateFunctionExpression(concatFunction, new DbExpression[] { args.Left, args.Right }); } }); #endregion // // e1 - e2 // #region e1 - e2 builtInExprConverter.Add(BuiltInKind.Minus, delegate( BuiltInExpr bltInExpr, SemanticResolver sr ) { Pair args = ConvertArithmeticArgs(bltInExpr, sr); return sr.CmdTree.CreateMinusExpression(args.Left, args.Right); }); #endregion // // e1 * e2 // #region e1 * e2 builtInExprConverter.Add(BuiltInKind.Multiply, delegate( BuiltInExpr bltInExpr, SemanticResolver sr ) { Pair args = ConvertArithmeticArgs(bltInExpr, sr); return sr.CmdTree.CreateMultiplyExpression(args.Left, args.Right); }); #endregion // // e1 / e2 // #region e1 / e2 builtInExprConverter.Add(BuiltInKind.Divide, delegate( BuiltInExpr bltInExpr, SemanticResolver sr ) { Pair args = ConvertArithmeticArgs(bltInExpr, sr); return sr.CmdTree.CreateDivideExpression(args.Left, args.Right); }); #endregion // // e1 % e2 // #region e1 % e2 builtInExprConverter.Add(BuiltInKind.Modulus, delegate( BuiltInExpr bltInExpr, SemanticResolver sr ) { Pair args = ConvertArithmeticArgs(bltInExpr, sr); return sr.CmdTree.CreateModuloExpression(args.Left, args.Right); }); #endregion // // - e // #region - e builtInExprConverter.Add(BuiltInKind.UnaryMinus, delegate( BuiltInExpr bltInExpr, SemanticResolver sr ) { DbExpression unaryExpr = sr.CmdTree.CreateUnaryMinusExpression(ConvertArithmeticArgs(bltInExpr, sr).Left); if (TypeSemantics.IsUnsignedNumericType(unaryExpr.ResultType)) { TypeUsage closestPromotableType = null; if (TypeHelpers.TryGetClosestPromotableType(unaryExpr.ResultType, out closestPromotableType)) { unaryExpr = sr.CmdTree.CreateCastExpression(unaryExpr, closestPromotableType); } else { throw EntityUtil.EntitySqlError(System.Data.Entity.Strings.InvalidUnsignedTypeForUnaryMinusOperation(unaryExpr.ResultType.EdmType.FullName)); } } return unaryExpr; }); #endregion // // + e // #region + e builtInExprConverter.Add(BuiltInKind.UnaryPlus, delegate( BuiltInExpr bltInExpr, SemanticResolver sr ) { return ConvertArithmeticArgs(bltInExpr, sr).Left; }); #endregion //////////////////////////// // Logical Expressions //////////////////////////// // // e1 AND e2 // e1 && e2 // #region e1 AND e2 builtInExprConverter.Add(BuiltInKind.And, delegate( BuiltInExpr bltInExpr, SemanticResolver sr ) { Pair args = SemanticAnalyzer.ConvertLogicalArgs(bltInExpr, sr); return sr.CmdTree.CreateAndExpression(args.Left, args.Right); }); #endregion // // e1 OR e2 // e1 || e2 // #region e1 OR e2 builtInExprConverter.Add(BuiltInKind.Or, delegate( BuiltInExpr bltInExpr, SemanticResolver sr ) { Pair args = SemanticAnalyzer.ConvertLogicalArgs(bltInExpr, sr); return sr.CmdTree.CreateOrExpression(args.Left, args.Right); }); #endregion // // NOT e // ! e // #region NOT e builtInExprConverter.Add(BuiltInKind.Not, delegate( BuiltInExpr bltInExpr, SemanticResolver sr ) { return sr.CmdTree.CreateNotExpression(ConvertLogicalArgs(bltInExpr, sr).Left); }); #endregion //////////////////////////// // Comparison Expressions //////////////////////////// // // e1 == e2 | e1 = e2 // #region e1 == e2 builtInExprConverter.Add(BuiltInKind.Equal, delegate( BuiltInExpr bltInExpr, SemanticResolver sr ) { Pair args = ConvertEqualCompArgs(bltInExpr, sr); return sr.CmdTree.CreateEqualsExpression(args.Left, args.Right); }); #endregion // // e1 != e2 | e1 <> e2 // #region e1 != e2 builtInExprConverter.Add(BuiltInKind.NotEqual, delegate( BuiltInExpr bltInExpr, SemanticResolver sr ) { Pair args = ConvertEqualCompArgs(bltInExpr, sr); return sr.CmdTree.CreateNotExpression( sr.CmdTree.CreateEqualsExpression(args.Left, args.Right)); }); #endregion // // e1 >= e2 // #region e1 >= e2 builtInExprConverter.Add(BuiltInKind.GreaterEqual, delegate( BuiltInExpr bltInExpr, SemanticResolver sr ) { Pair args = ConvertOrderCompArgs(bltInExpr, sr); return sr.CmdTree.CreateGreaterThanOrEqualsExpression(args.Left, args.Right); }); #endregion // // e1 > e2 // #region e1 > e2 builtInExprConverter.Add(BuiltInKind.GreaterThan, delegate( BuiltInExpr bltInExpr, SemanticResolver sr ) { Pair args = ConvertOrderCompArgs(bltInExpr, sr); return sr.CmdTree.CreateGreaterThanExpression(args.Left, args.Right); }); #endregion // // e1 <= e2 // #region e1 <= e2 builtInExprConverter.Add(BuiltInKind.LessEqual, delegate( BuiltInExpr bltInExpr, SemanticResolver sr ) { Pair args = ConvertOrderCompArgs(bltInExpr, sr); return sr.CmdTree.CreateLessThanOrEqualsExpression(args.Left, args.Right); }); #endregion // // e1 < e2 // #region e1 < e2 builtInExprConverter.Add(BuiltInKind.LessThan, delegate( BuiltInExpr bltInExpr, SemanticResolver sr ) { Pair args = ConvertOrderCompArgs(bltInExpr, sr); return sr.CmdTree.CreateLessThanExpression(args.Left, args.Right); }); #endregion //////////////////////////// // SET EXPRESSIONS //////////////////////////// // // e1 UNION e2 // #region e1 UNION e2 builtInExprConverter.Add(BuiltInKind.Union, delegate( BuiltInExpr bltInExpr, SemanticResolver sr ) { Pair args = ConvertSetArgs(bltInExpr, sr); return sr.CmdTree.CreateDistinctExpression(sr.CmdTree.CreateUnionAllExpression(args.Left, args.Right)); }); #endregion // // e1 UNION ALL e2 // #region e1 UNION ALL e2 builtInExprConverter.Add(BuiltInKind.UnionAll, delegate( BuiltInExpr bltInExpr, SemanticResolver sr ) { Pair args = ConvertSetArgs(bltInExpr, sr); return sr.CmdTree.CreateUnionAllExpression(args.Left, args.Right); }); #endregion // // e1 INTERSECT e2 // #region e1 INTERSECT e2 builtInExprConverter.Add(BuiltInKind.Intersect, delegate( BuiltInExpr bltInExpr, SemanticResolver sr ) { Pair args = ConvertSetArgs(bltInExpr, sr); return sr.CmdTree.CreateIntersectExpression(args.Left, args.Right); }); #endregion // // e1 OVERLAPS e2 // #region e1 OVERLAPS e1 builtInExprConverter.Add(BuiltInKind.Overlaps, delegate( BuiltInExpr bltInExpr, SemanticResolver sr ) { Pair args = ConvertSetArgs(bltInExpr, sr); return sr.CmdTree.CreateNotExpression( sr.CmdTree.CreateIsEmptyExpression( sr.CmdTree.CreateIntersectExpression(args.Left, args.Right))); }); #endregion // // ANYELEMENT( e ) // #region ANYELEMENT( e ) builtInExprConverter.Add(BuiltInKind.AnyElement, delegate( BuiltInExpr bltInExpr, SemanticResolver sr ) { return sr.CmdTree.CreateElementExpression(ConvertSetArgs(bltInExpr, sr).Left); }); #endregion // // ELEMENT( e ) // #region ELEMENT( e ) - NOT SUPPORTED IN ORCAS TIMEFRAME builtInExprConverter.Add(BuiltInKind.Element, delegate( BuiltInExpr bltInExpr, SemanticResolver sr ) { throw EntityUtil.NotSupported(System.Data.Entity.Strings.ElementOperatorIsNotSupported); }); #endregion // // e1 EXCEPT e2 // #region e1 EXCEPT e2 builtInExprConverter.Add(BuiltInKind.Except, delegate( BuiltInExpr bltInExpr, SemanticResolver sr ) { Pair args = ConvertSetArgs(bltInExpr, sr); return sr.CmdTree.CreateExceptExpression(args.Left, args.Right); }); #endregion // // EXISTS( e ) // #region EXISTS( e ) builtInExprConverter.Add(BuiltInKind.Exists, delegate( BuiltInExpr bltInExpr, SemanticResolver sr ) { return sr.CmdTree.CreateNotExpression( sr.CmdTree.CreateIsEmptyExpression(ConvertSetArgs(bltInExpr, sr).Left)); }); #endregion // // FLATTEN( e ) // #region FLATTEN( e ) builtInExprConverter.Add(BuiltInKind.Flatten, delegate( BuiltInExpr bltInExpr, SemanticResolver sr ) { DbExpression elemExpr = Convert(bltInExpr.Arg1, sr); if (!TypeSemantics.IsCollectionType(elemExpr.ResultType)) { throw EntityUtil.EntitySqlError(bltInExpr.Arg1.ErrCtx, System.Data.Entity.Strings.InvalidFlattenArgument); } if (!TypeSemantics.IsCollectionType(TypeHelpers.GetElementTypeUsage(elemExpr.ResultType))) { throw EntityUtil.EntitySqlError(bltInExpr.Arg1.ErrCtx, System.Data.Entity.Strings.InvalidFlattenArgument); } DbExpressionBinding leftExpr = sr.CmdTree.CreateExpressionBinding(elemExpr, sr.GenerateInternalName("l_flatten")); DbExpressionBinding rightExpr = sr.CmdTree.CreateExpressionBinding(leftExpr.Variable, sr.GenerateInternalName("r_flatten")); DbExpressionBinding applyBinding = sr.CmdTree.CreateExpressionBinding( sr.CmdTree.CreateCrossApplyExpression(leftExpr, rightExpr), sr.GenerateInternalName("flatten")); return sr.CmdTree.CreateProjectExpression(applyBinding, sr.CmdTree.CreatePropertyExpression(rightExpr.VariableName, applyBinding.Variable)); }); #endregion // // e1 IN e2 // #region e1 IN e2 builtInExprConverter.Add(BuiltInKind.In, delegate( BuiltInExpr bltInExpr, SemanticResolver sr ) { Pair args = ConvertInExprArgs(bltInExpr, sr); // [....]: Temporary workaround for 2/3 milestone. // Convert "x in multiset(y1, y2, ..., yn)" into // x = y1 or x = y2 or x = y3 ... // if (args.Right.ExpressionKind == DbExpressionKind.NewInstance) { return ConvertSimpleInExpression(sr, args.Left, args.Right); } else { DbExpressionBinding rSet = sr.CmdTree.CreateExpressionBinding(args.Right, sr.GenerateInternalName("in-filter")); DbExpression leftIn = args.Left; DbExpression rightSet = rSet.Variable; DbExpression exists = sr.CmdTree.CreateNotExpression( sr.CmdTree.CreateIsEmptyExpression( sr.CmdTree.CreateFilterExpression( rSet, sr.CmdTree.CreateEqualsExpression(leftIn, rightSet)))); List whenExpr = new List (1); whenExpr.Add(sr.CmdTree.CreateIsNullExpression(leftIn)); List thenExpr = new List (1); thenExpr.Add(sr.CmdTree.CreateNullExpression(sr.TypeResolver.BooleanType)); DbExpression left = sr.CmdTree.CreateCaseExpression( whenExpr, thenExpr, sr.CmdTree.CreateFalseExpression()); DbExpression converted = sr.CmdTree.CreateOrExpression(left, exists); return converted; } }); #endregion // // e1 NOT IN e1 // #region e1 NOT IN e1 builtInExprConverter.Add(BuiltInKind.NotIn, delegate( BuiltInExpr bltInExpr, SemanticResolver sr ) { Pair args = ConvertInExprArgs(bltInExpr, sr); if (args.Right.ExpressionKind == DbExpressionKind.NewInstance) { return sr.CmdTree.CreateNotExpression( ConvertSimpleInExpression(sr, args.Left, args.Right)); } else { DbExpressionBinding rSet = sr.CmdTree.CreateExpressionBinding(args.Right, sr.GenerateInternalName("in-filter")); DbExpression leftIn = args.Left; DbExpression rightSet = rSet.Variable; DbExpression exists = sr.CmdTree.CreateIsEmptyExpression( sr.CmdTree.CreateFilterExpression( rSet, sr.CmdTree.CreateEqualsExpression(leftIn, rightSet))); List whenExpr = new List (1); whenExpr.Add(sr.CmdTree.CreateIsNullExpression(leftIn)); List thenExpr = new List (1); thenExpr.Add(sr.CmdTree.CreateNullExpression(sr.TypeResolver.BooleanType)); DbExpression left = sr.CmdTree.CreateCaseExpression( whenExpr, thenExpr, sr.CmdTree.CreateTrueExpression()); DbExpression converted = sr.CmdTree.CreateAndExpression(left, exists); return converted; } }); #endregion // // SET( e ) - DISTINCT( e ) before // #region SET( e ) builtInExprConverter.Add(BuiltInKind.Distinct, delegate( BuiltInExpr bltInExpr, SemanticResolver sr ) { Pair args = ConvertSetArgs(bltInExpr, sr); return sr.CmdTree.CreateDistinctExpression(args.Left); }); #endregion //////////////////////////// // Nullabity Expressions //////////////////////////// // // e IS NULL // #region e IS NULL builtInExprConverter.Add(BuiltInKind.IsNull, delegate(BuiltInExpr bltInExpr, SemanticResolver sr) { DbExpression isNullExpr = Convert(bltInExpr.Arg1, sr); // // ensure expression type is valid for this operation // if (!TypeHelpers.IsValidIsNullOpType(isNullExpr.ResultType)) { throw EntityUtil.EntitySqlError(bltInExpr.Arg1.ErrCtx, System.Data.Entity.Strings.IsNullInvalidType); } return SemanticResolver.IsNullExpression(isNullExpr) ? sr.CmdTree.CreateTrueExpression() : (DbExpression)sr.CmdTree.CreateIsNullExpression(isNullExpr); }); #endregion // // e IS NOT NULL // #region e IS NOT NULL builtInExprConverter.Add(BuiltInKind.IsNotNull, delegate(BuiltInExpr bltInExpr, SemanticResolver sr) { DbExpression isNullExpr = Convert(bltInExpr.Arg1, sr); // // ensure expression type is valid for this operation // if (!TypeHelpers.IsValidIsNullOpType(isNullExpr.ResultType)) { throw EntityUtil.EntitySqlError(bltInExpr.Arg1.ErrCtx, System.Data.Entity.Strings.IsNullInvalidType); } isNullExpr = SemanticResolver.IsNullExpression(isNullExpr) ? sr.CmdTree.CreateTrueExpression() : (DbExpression)sr.CmdTree.CreateIsNullExpression(isNullExpr); return sr.CmdTree.CreateNotExpression(isNullExpr); }); #endregion //////////////////////////// // Type Expressions //////////////////////////// // // e IS OF ( [ONLY] T ) // #region e IS OF ( [ONLY] T ) builtInExprConverter.Add(BuiltInKind.IsOf, delegate(BuiltInExpr bltInExpr, SemanticResolver sr) { Pair args = ConvertTypeExprArgs(bltInExpr, sr); bool isOnly = (bool)((Literal)bltInExpr.ArgList[2]).Value; bool isNot = (bool)((Literal)bltInExpr.ArgList[3]).Value; bool isNominalTypeAllowed = sr.ParserOptions.ParserCompilationMode == ParserOptions.CompilationMode.RestrictedViewGenerationMode; if (TypeSemantics.IsNullType(args.Left.ResultType)) { throw EntityUtil.EntitySqlError(bltInExpr.Arg1.ErrCtx, System.Data.Entity.Strings.ExpressionCannotBeNull); } if (!isNominalTypeAllowed && !TypeSemantics.IsEntityType(args.Left.ResultType)) { throw EntityUtil.EntitySqlError(bltInExpr.Arg1.ErrCtx, System.Data.Entity.Strings.ExpressionTypeMustBeEntityType(System.Data.Entity.Strings.CtxIsOf, args.Left.ResultType.EdmType.BuiltInTypeKind.ToString(), args.Left.ResultType.EdmType.FullName)); } else if (isNominalTypeAllowed && !TypeSemantics.IsNominalType(args.Left.ResultType)) { throw EntityUtil.EntitySqlError(bltInExpr.Arg1.ErrCtx, System.Data.Entity.Strings.ExpressionTypeMustBeNominalType(System.Data.Entity.Strings.CtxIsOf, args.Left.ResultType.EdmType.BuiltInTypeKind.ToString(), args.Left.ResultType.EdmType.FullName)); } if (!isNominalTypeAllowed && !TypeSemantics.IsEntityType(args.Right)) { throw EntityUtil.EntitySqlError(bltInExpr.Arg2.ErrCtx, System.Data.Entity.Strings.TypeMustBeEntityType(System.Data.Entity.Strings.CtxIsOf, args.Right.EdmType.BuiltInTypeKind.ToString(), args.Right.EdmType.FullName)); } else if (isNominalTypeAllowed && !TypeSemantics.IsNominalType(args.Right)) { throw EntityUtil.EntitySqlError(bltInExpr.Arg2.ErrCtx, System.Data.Entity.Strings.TypeMustBeNominalType(System.Data.Entity.Strings.CtxIsOf, args.Right.EdmType.BuiltInTypeKind.ToString(), args.Right.EdmType.FullName)); } if (!TypeSemantics.IsPolymorphicType(args.Left.ResultType)) { throw EntityUtil.EntitySqlError(bltInExpr.Arg1.ErrCtx, System.Data.Entity.Strings.TypeMustBeInheritableType); } if (!TypeSemantics.IsPolymorphicType(args.Right)) { throw EntityUtil.EntitySqlError(bltInExpr.Arg2.ErrCtx, System.Data.Entity.Strings.TypeMustBeInheritableType); } if (!TypeResolver.IsSubOrSuperType(args.Left.ResultType, args.Right)) { throw EntityUtil.EntitySqlError(bltInExpr.ErrCtx, System.Data.Entity.Strings.NotASuperOrSubType(args.Left.ResultType.EdmType.FullName, args.Right.EdmType.FullName)); } args.Right = TypeHelpers.GetReadOnlyType(args.Right); DbExpression retExpr = null; if (isOnly) { retExpr = sr.CmdTree.CreateIsOfOnlyExpression(args.Left, args.Right); } else { retExpr = sr.CmdTree.CreateIsOfExpression(args.Left, args.Right); } if (isNot) { retExpr = sr.CmdTree.CreateNotExpression(retExpr); } return retExpr; }); #endregion // // TREAT( e as T ) // #region TREAT( e as T ) builtInExprConverter.Add(BuiltInKind.Treat, delegate( BuiltInExpr bltInExpr, SemanticResolver sr ) { Pair args = ConvertTypeExprArgs(bltInExpr, sr); bool isNominalTypeAllowed = sr.ParserOptions.ParserCompilationMode == ParserOptions.CompilationMode.RestrictedViewGenerationMode; if (!isNominalTypeAllowed && !TypeSemantics.IsEntityType(args.Right)) { throw EntityUtil.EntitySqlError(bltInExpr.Arg2.ErrCtx, System.Data.Entity.Strings.TypeMustBeEntityType(System.Data.Entity.Strings.CtxTreat, args.Right.EdmType.BuiltInTypeKind.ToString(), args.Right.EdmType.FullName)); } else if (isNominalTypeAllowed && !TypeSemantics.IsNominalType(args.Right)) { throw EntityUtil.EntitySqlError(bltInExpr.Arg2.ErrCtx, System.Data.Entity.Strings.TypeMustBeNominalType(System.Data.Entity.Strings.CtxTreat, args.Right.EdmType.BuiltInTypeKind.ToString(), args.Right.EdmType.FullName)); } if (TypeSemantics.IsNullType(args.Left.ResultType)) { args.Left = sr.CmdTree.CreateNullExpression(args.Right); } else if (!isNominalTypeAllowed && !TypeSemantics.IsEntityType(args.Left.ResultType)) { throw EntityUtil.EntitySqlError(bltInExpr.Arg1.ErrCtx, System.Data.Entity.Strings.ExpressionTypeMustBeEntityType(System.Data.Entity.Strings.CtxTreat, args.Left.ResultType.EdmType.BuiltInTypeKind.ToString(), args.Left.ResultType.EdmType.FullName)); } else if (isNominalTypeAllowed && !TypeSemantics.IsNominalType(args.Left.ResultType)) { throw EntityUtil.EntitySqlError(bltInExpr.Arg1.ErrCtx, System.Data.Entity.Strings.ExpressionTypeMustBeNominalType(System.Data.Entity.Strings.CtxTreat, args.Left.ResultType.EdmType.BuiltInTypeKind.ToString(), args.Left.ResultType.EdmType.FullName)); } if (!TypeSemantics.IsPolymorphicType(args.Left.ResultType)) { throw EntityUtil.EntitySqlError(bltInExpr.Arg1.ErrCtx, System.Data.Entity.Strings.TypeMustBeInheritableType); } if (!TypeSemantics.IsPolymorphicType(args.Right)) { throw EntityUtil.EntitySqlError(bltInExpr.Arg2.ErrCtx, System.Data.Entity.Strings.TypeMustBeInheritableType); } if (!TypeResolver.IsSubOrSuperType(args.Left.ResultType, args.Right)) { throw EntityUtil.EntitySqlError(bltInExpr.Arg1.ErrCtx, System.Data.Entity.Strings.NotASuperOrSubType(args.Left.ResultType.EdmType.FullName, args.Right.EdmType.FullName)); } return sr.CmdTree.CreateTreatExpression(args.Left, TypeHelpers.GetReadOnlyType(args.Right)); }); #endregion // // CAST( e AS T ) // #region CAST( e AS T ) builtInExprConverter.Add(BuiltInKind.Cast, delegate( BuiltInExpr bltInExpr, SemanticResolver sr ) { Pair args = ConvertTypeExprArgs(bltInExpr, sr); // // ensure CAST target type is Scalar // if (!TypeSemantics.IsPrimitiveType(args.Right)) { throw EntityUtil.EntitySqlError(bltInExpr.Arg2.ErrCtx, System.Data.Entity.Strings.InvalidCastType); } if (SemanticResolver.IsNullExpression(args.Left)) { return sr.CmdTree.CreateCastExpression( sr.CmdTree.CreateNullExpression(args.Right), args.Right); } if (args.Left.ResultType.BuiltInTypeKind != BuiltInTypeKind.EnumType) { if (!TypeSemantics.IsPrimitiveType(args.Left.ResultType)) { throw EntityUtil.EntitySqlError(bltInExpr.Arg1.ErrCtx, System.Data.Entity.Strings.InvalidCastExpressionType); } if (!TypeSemantics.IsCastAllowed(args.Left.ResultType, args.Right)) { throw EntityUtil.EntitySqlError(bltInExpr.Arg1.ErrCtx, System.Data.Entity.Strings.InvalidCast( args.Left.ResultType.EdmType, args.Right.EdmType.FullName)); } } return sr.CmdTree.CreateCastExpression(args.Left, TypeHelpers.GetReadOnlyType(args.Right)); }); #endregion // // OFTYPE( [ONLY] e, T ) // #region OFTYPE( [ONLY] e, T ) builtInExprConverter.Add(BuiltInKind.OfType, delegate(BuiltInExpr bltInExpr, SemanticResolver sr) { Pair args = ConvertTypeExprArgs(bltInExpr, sr); bool isOnly = (bool)((Literal)bltInExpr.ArgList[2]).Value; bool isNominalTypeAllowed = sr.ParserOptions.ParserCompilationMode == ParserOptions.CompilationMode.RestrictedViewGenerationMode; if (!TypeSemantics.IsCollectionType(args.Left.ResultType)) { throw EntityUtil.EntitySqlError(bltInExpr.Arg1.ErrCtx, System.Data.Entity.Strings.ExpressionMustBeCollection); } TypeUsage elementType = TypeHelpers.GetElementTypeUsage(args.Left.ResultType); if (!isNominalTypeAllowed && !TypeSemantics.IsEntityType(elementType)) { throw EntityUtil.EntitySqlError(bltInExpr.Arg1.ErrCtx, System.Data.Entity.Strings.OfTypeExpressionElementTypeMustBeEntityType(elementType.EdmType.BuiltInTypeKind.ToString(), elementType)); } else if (isNominalTypeAllowed && !TypeSemantics.IsNominalType(elementType)) { throw EntityUtil.EntitySqlError(bltInExpr.Arg1.ErrCtx, System.Data.Entity.Strings.OfTypeExpressionElementTypeMustBeNominalType(elementType.EdmType.BuiltInTypeKind.ToString(), elementType)); } if (!isNominalTypeAllowed && !TypeSemantics.IsEntityType(args.Right)) { throw EntityUtil.EntitySqlError(bltInExpr.Arg2.ErrCtx, System.Data.Entity.Strings.TypeMustBeEntityType(System.Data.Entity.Strings.CtxOfType, args.Right.EdmType.BuiltInTypeKind.ToString(), args.Right.EdmType.FullName)); } else if (isNominalTypeAllowed && !TypeSemantics.IsNominalType(args.Right)) { throw EntityUtil.EntitySqlError(bltInExpr.Arg2.ErrCtx, System.Data.Entity.Strings.TypeMustBeNominalType(System.Data.Entity.Strings.CtxOfType, args.Right.EdmType.BuiltInTypeKind.ToString(), args.Right.EdmType.FullName)); } if (isOnly && args.Right.EdmType.Abstract) { throw EntityUtil.EntitySqlError(bltInExpr.Arg2.ErrCtx, System.Data.Entity.Strings.OfTypeOnlyTypeArgumentCannotBeAbstract(args.Right.EdmType.FullName)); } if (!TypeResolver.IsSubOrSuperType(elementType, args.Right)) { throw EntityUtil.EntitySqlError(bltInExpr.Arg1.ErrCtx, System.Data.Entity.Strings.NotASuperOrSubType(elementType.EdmType.FullName, args.Right.EdmType.FullName)); } DbExpression ofTypeExpression = null; if (isOnly) { ofTypeExpression = sr.CmdTree.CreateOfTypeOnlyExpression(args.Left, TypeHelpers.GetReadOnlyType(args.Right)); } else { ofTypeExpression = sr.CmdTree.CreateOfTypeExpression(args.Left, TypeHelpers.GetReadOnlyType(args.Right)); } return ofTypeExpression; }); #endregion // // e LIKE pattern [ESCAPE escape] // #region e LIKE pattern [ESCAPE escape] builtInExprConverter.Add(BuiltInKind.Like, delegate( BuiltInExpr bltInExpr, SemanticResolver sr ) { DbExpression likeExpr = null; DbExpression matchExpr = Convert(bltInExpr.Arg1, sr); if (TypeSemantics.IsNullType(matchExpr.ResultType)) { matchExpr = sr.CmdTree.CreateNullExpression(sr.TypeResolver.StringType); } else if (!TypeResolver.IsStringType(matchExpr.ResultType)) { throw EntityUtil.EntitySqlError(bltInExpr.Arg1.ErrCtx, System.Data.Entity.Strings.LikeArgMustBeStringType); } DbExpression patternExpr = Convert(bltInExpr.Arg2, sr); if (patternExpr is UntypedNullExpression) { patternExpr = sr.CmdTree.CreateNullExpression(sr.TypeResolver.StringType); } else if (!TypeResolver.IsStringType(patternExpr.ResultType)) { throw EntityUtil.EntitySqlError(bltInExpr.Arg2.ErrCtx, System.Data.Entity.Strings.LikeArgMustBeStringType); } if (3 == bltInExpr.ArgCount) { DbExpression escapeExpr = Convert(bltInExpr.ArgList[2], sr); if (escapeExpr is UntypedNullExpression) { escapeExpr = sr.CmdTree.CreateNullExpression(sr.TypeResolver.StringType); } else if (!TypeResolver.IsStringType(escapeExpr.ResultType)) { throw EntityUtil.EntitySqlError(bltInExpr.ArgList[2].ErrCtx, System.Data.Entity.Strings.LikeArgMustBeStringType); } likeExpr = sr.CmdTree.CreateLikeExpression(matchExpr, patternExpr, escapeExpr); } else { likeExpr = sr.CmdTree.CreateLikeExpression(matchExpr, patternExpr); } return likeExpr; }); #endregion // // e BETWEEN e1 AND e2 // #region e BETWEEN e1 AND e2 builtInExprConverter.Add(BuiltInKind.Between, delegate( BuiltInExpr bltInExpr, SemanticResolver sr ) { Debug.Assert(bltInExpr.ArgCount == 3); // // convert lower and upper limits // Pair limitsExpr = sr.EnsureTypedNulls( Convert(bltInExpr.ArgList[1], sr), Convert(bltInExpr.ArgList[2], sr), bltInExpr.ArgList[0].ErrCtx, () => Strings.BetweenLimitsCannotBeUntypedNulls); // // Get and check common type for limits // TypeUsage rangeCommonType = TypeHelpers.GetCommonTypeUsage(limitsExpr.Left.ResultType, limitsExpr.Right.ResultType); if (null == rangeCommonType) { throw EntityUtil.EntitySqlError(bltInExpr.ArgList[0].ErrCtx, System.Data.Entity.Strings.BetweenLimitsTypesAreNotCompatible(limitsExpr.Left.ResultType.EdmType.FullName, limitsExpr.Right.ResultType.EdmType.FullName)); } // // check if limit types are order-comp // if (!TypeSemantics.IsOrderComparableTo(limitsExpr.Left.ResultType, limitsExpr.Right.ResultType)) { throw EntityUtil.EntitySqlError(bltInExpr.ArgList[0].ErrCtx, System.Data.Entity.Strings.BetweenLimitsTypesAreNotOrderComparable(limitsExpr.Left.ResultType.EdmType.FullName, limitsExpr.Right.ResultType.EdmType.FullName)); } // // convert value expression // DbExpression valueExpr = Convert(bltInExpr.ArgList[0], sr); // // Fixup value type if untyped // if (TypeSemantics.IsNullType(valueExpr.ResultType)) { valueExpr = sr.CmdTree.CreateNullExpression(rangeCommonType); } // // check if valueExpr is order-comparable to limits // if (!TypeSemantics.IsOrderComparableTo(valueExpr.ResultType, rangeCommonType)) { throw EntityUtil.EntitySqlError(bltInExpr.ArgList[0].ErrCtx, System.Data.Entity.Strings.BetweenValueIsNotOrderComparable(valueExpr.ResultType.EdmType.FullName, rangeCommonType.EdmType.FullName)); } return sr.CmdTree.CreateAndExpression( sr.CmdTree.CreateGreaterThanOrEqualsExpression(valueExpr, limitsExpr.Left), sr.CmdTree.CreateLessThanOrEqualsExpression(valueExpr, limitsExpr.Right)); }); #endregion // // e NOT BETWEEN e1 AND e2 // #region e NOT BETWEEN e1 AND e2 builtInExprConverter.Add(BuiltInKind.NotBetween, delegate( BuiltInExpr bltInExpr, SemanticResolver sr ) { bltInExpr.Kind = BuiltInKind.Between; DbExpression converted = sr.CmdTree.CreateNotExpression(ConvertBuiltIn(bltInExpr, sr)); bltInExpr.Kind = BuiltInKind.NotBetween; return converted; }); #endregion return builtInExprConverter; } #endregion #endregion } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. //---------------------------------------------------------------------- // // Copyright (c) Microsoft Corporation. All rights reserved. // // // @owner [....] // @backup [....] //--------------------------------------------------------------------- namespace System.Data.Common.EntitySql { using System; using System.Globalization; using System.Collections.Generic; using System.Diagnostics; using System.Data.Common.CommandTrees; using System.Data.Metadata.Edm; using System.Data.Entity; ////// Implements Semantic Analysis and Conversion /// Provides the translation service between an abstract syntax tree to a canonical command tree /// For complete documentation of the language syntax and semantics, refer to http://sqlweb/default.asp?specDirId=764 /// 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 /// we rely on the assumption that metadata was pre-loaded and is relevant to the query. /// internal sealed class SemanticAnalyzer { private SemanticResolver _sr; ////// Initializes semantic analyzer /// /// initialized SemanticResolver instance for a given typespace/type system internal SemanticAnalyzer( SemanticResolver sr ) { EntityUtil.CheckArgumentNull(sr, "sr"); _sr = sr; } ////// Entry point to semantic analysis. Converts astTree into DbExpression. /// /// ast tree /// command tree to build the expression ////// ///Thrown when Syntatic or Semantic rules are violated and the query cannot be accepted ///Thrown when metadata related service requests fail ///Thrown when mapping related service requests fail ///DbExpression internal DbExpression Analyze(Expr astExpr, DbCommandTree commandTree) { CommandExpr command = Initialize(astExpr, commandTree); DbExpression converted = ConvertRootExpression(command.QueryExpr, _sr); return converted; } ////// Entry point to semantic analysis. Converts astTree into command tree. /// /// ast tree ////// ///Thrown when Syntatic or Semantic rules are violated and the query cannot be accepted ///Thrown when metadata related service requests fail ///Thrown when mapping related service requests fail ///DbCommandTree internal DbCommandTree Analyze( Expr astExpr ) { CommandExpr astCommandExpr = Initialize(astExpr, null); // // Convert query Expression // DbCommandTree commandTree = ConvertCommand(astCommandExpr, _sr); Debug.Assert(null != commandTree,"null != commandTree"); return commandTree; } ////// Common initialization required whether the semantic analysis process /// is producing a command tree or only an expression. Validates that the /// parse phase did in fact produce a command AST. /// /// The root of the abstract syntax tree produced by the parse phase /// /// An optional command tree to use, only provided when constructing an expression. /// When constructing a command tree, an instance of the appropriate command tree /// class will be created and returned by semantic analysis. /// ///The private CommandExpr Initialize(Expr astExpr, DbCommandTree tree) { CommandExpr astCommandExpr = astExpr as CommandExpr; if (null == astCommandExpr) { throw EntityUtil.Argument(System.Data.Entity.Strings.UnknownAstCommandExpression); } // // Sets DbCommandTree Factory // if (tree == null) { _sr.SetCommandTreeFactory(astCommandExpr); } else { _sr.SetCommandTreeFactory(astCommandExpr, tree); } // // Declare Canonical Namespace // _sr.DeclareCanonicalNamespace(); // // Declare Namespaces // _sr.DeclareNamespaces(astCommandExpr.NamespaceDeclList); return astCommandExpr; } #region command converter delegates delegate DbCommandTree CommandConverter( Expr astExpr, SemanticResolver sr ); static CommandConverter[] commandConverters = { /* ExprKind.Generic */ ConvertGeneralExpression, /* ExprKind.Query */ ConvertGeneralExpression, }; #endregion ///that is the root of the AST specified by /// Dispatches/Converts top command expressions. /// /// /// SemanticResolver instance relative to a especif typespace/system ///private static DbCommandTree ConvertCommand( CommandExpr astCommandExpr, SemanticResolver sr ) { EntityUtil.CheckArgumentNull(astCommandExpr, "astCommandExpr"); Expr queryExpr = astCommandExpr.QueryExpr; return commandConverters[(int)queryExpr.ExprKind](queryExpr, sr); } /// /// Converts {Query|General} Expression /// /// /// SemanticResolver instance relative to a especif typespace/system ///private static DbCommandTree ConvertGeneralExpression( Expr astExpr, SemanticResolver sr ) { DbExpression converted = ConvertRootExpression(astExpr, sr); DbQueryCommandTree qryCmdTree = (DbQueryCommandTree)sr.CmdTree; qryCmdTree.Query = converted; Debug.Assert(null != qryCmdTree,"null != qryCmdTree"); return qryCmdTree; } /// /// Converts the expression that is the 'root' of a query AST to a /// normalized and validated /// The root AST node for this query /// The. This entry /// point to the semantic analysis phase is used when producing a /// query command tree (from a Query or General AST expression) or /// producing only a . /// instance to use /// /// An instance of private static DbExpression ConvertRootExpression(Expr astExpr, SemanticResolver sr) { DbExpression converted = Convert(astExpr, sr); // // ensure converted expression is not untyped-null // if (TypeSemantics.IsNullType(converted.ResultType)) { throw EntityUtil.EntitySqlError(astExpr.ErrCtx, System.Data.Entity.Strings.ResultingExpressionTypeCannotBeNull); } // // Handles the "inline" projection case // if (converted is DbScanExpression) { DbExpressionBinding source = sr.CmdTree.CreateExpressionBinding(converted, sr.GenerateInternalName("extent")); converted = sr.CmdTree.CreateProjectExpression(source, source.Variable); } // // ensure return type is valid for query. for V1, association types are the only // type that cannot be at 'top' level result. Note that this is only applicable in // general queries and association types are valid in view gen mode queries // if (sr.ParserOptions.ParserCompilationMode == ParserOptions.CompilationMode.NormalMode) { SemanticResolver.ValidateQueryResultType(converted.ResultType, astExpr.ErrCtx); } return converted; } ///, adjusted to handle 'inline' projections /// and validated to produce a result type appropriate for the root of a query command tree. /// /// Dispatches/Converts general expressions /// /// /// SemanticResolver instance relative to a especif typespace/system ///private static DbExpression Convert( Expr astExpr, SemanticResolver sr ) { if (null == astExpr) { return null; } AstExprConverter converter = _astExprConverters[astExpr.GetType()]; if (null == converter) { throw EntityUtil.Argument(System.Data.Entity.Strings.UnknownAstExpressionType); } DbExpression converted = converter(astExpr, sr); Debug.Assert(null != converted,"null != converted"); return converted; } /// /// Converts Literal Expression /// /// /// SemanticResolver instance relative to a especif typespace/system ///private static DbExpression ConvertLiteral( Expr expr, SemanticResolver sr ) { Literal literal = (Literal)expr; if (literal.IsNullLiteral) { // // if it is literal null, return untyped null // untyped nulls will later have their type inferred depending on the // especific expression in which it participates // return new UntypedNullExpression(sr.CmdTree); } else { return sr.CmdTree.CreateConstantExpression(literal.Value, sr.TypeResolver.GetLiteralTypeUsage(literal)); } } /// /// Converts Simple Identifier /// /// /// SemanticResolver instance relative to a especif typespace/system ///private static DbExpression ConvertIdentifier( Expr expr, SemanticResolver sr ) { Identifier idExpr = (Identifier)expr; DbExpression converted = sr.ResolveIdentifier(new string[] { idExpr.Name }, expr.ErrCtx); if (null == converted) { CqlErrorHelper.ReportIdentifierError(expr, sr); } return converted; } /// /// Converts DotExpression /// /// /// SemanticResolver instance relative to a especif typespace/system ///private static DbExpression ConvertDotExpr( Expr expr, SemanticResolver sr ) { DotExpr dotExpr = (DotExpr)expr; DbExpression converted = null; if (dotExpr.IsDottedIdentifier) { converted = sr.ResolveIdentifier(dotExpr.Names, dotExpr.ErrCtx); if (null == converted) { CqlErrorHelper.ReportIdentifierError(expr, sr); } } else { converted = ConvertDotExpressionProcess(dotExpr, sr); } Debug.Assert(null != converted,"null != converted"); return converted; } /// /// converts dot expression. dotted id case is handled by resolveId /// /// /// SemanticResolver instance relative to a especif typespace/system ////// ////// /// static private DbExpression ConvertDotExpressionProcess( DotExpr dotExpr, SemanticResolver sr ) { Debug.Assert(!dotExpr.IsDottedIdentifier,"!dotExpr.IsDottedIdentifier"); return sr.ResolveIdentifierChain(dotExpr.Names, 0, Convert(dotExpr.LeftMostExpression, sr), dotExpr.ErrCtx); } /// /// Converts methods, functions and type constructors /// methods (instance or static) can be in the form: (expr).chain.of.names(args) or chain.of.names(args) /// Functions are chain.of.names(args) /// /// /// SemanticResolver instance relative to a especif typespace/system ///private static DbExpression ConvertMethodExpr( Expr expr, SemanticResolver sr ) { MethodExpr methodExpr = (MethodExpr)expr; DbExpression converted = null; DotExpr dotExpr = methodExpr.MethodPrefixExpr; // // resolve base expression if one exists // DbExpression baseExpr = (null != dotExpr.LeftMostExpression) ? Convert(dotExpr.LeftMostExpression, sr) : null; // // If base expression is still unresolved, check if leftmost name element is in in scope // int prefixIndex = 0; KeyValuePair varInfo; if (null == baseExpr && dotExpr.IsDottedIdentifier && dotExpr.Names.Length > 0) { ScopeEntry scopeEntry; if (sr.TryScopeLookup(dotExpr.Names[0], out scopeEntry)) { // // make sure is a valid type for method call // if (TypeResolver.IsValidTypeForMethodCall(scopeEntry.Expression.ResultType)) { baseExpr = scopeEntry.Expression; prefixIndex = 1; } else { throw EntityUtil.EntitySqlError(methodExpr.ErrCtx, System.Data.Entity.Strings.DefiningTypeDoesNotSupportMethodCalls); } } else if (sr.Variables.TryGetValue(dotExpr.Names[0], out varInfo)) { baseExpr = sr.CmdTree.CreateVariableReferenceExpression(varInfo.Key, varInfo.Value); prefixIndex = 1; } } // // check if base expression if is untyped null // if (baseExpr is UntypedNullExpression) { throw EntityUtil.EntitySqlError(dotExpr.LeftMostExpression.ErrCtx, System.Data.Entity.Strings.ExpressionCannotBeNull); } // // dispatches methodExpr to static or instance kind of method conversion // if (null == baseExpr) { // // if base expression is still unresolved, it should be a function(aggregates included), static method or type constructor // converted = ConvertStaticMethodOrFunction(methodExpr, sr); } else { // // otherwise, should be an instance method invocation // converted = ConvertMethodInstance(baseExpr, methodExpr, prefixIndex, sr); } Debug.Assert(null != converted,"null != converted"); return converted; } /// /// Converts a method expr into a Static Method, Type Constructor or EdmFunction call (including aggregates) /// /// /// ///private static DbExpression ConvertStaticMethodOrFunction( MethodExpr methodExpr, SemanticResolver sr ) { DbExpression converted = null; // // Find out if given name path is a Static Method, Type Constructor or EdmFunction call (including aggregates) // TypeUsage constructorType; TypeUsage staticMethodType; IList functionType; // // Resolve methodExpr // sr.ResolveNameAsStaticMethodOrFunction(methodExpr, out constructorType, out staticMethodType, out functionType); // // at this point, only one of the three must be not null // that is ensured by ResolveNameAsStaticMethodOrFunction() // Debug.Assert(constructorType != null || staticMethodType != null || functionType != null,"constructorType != null || staticMethodType != null || functionType != null"); // // if it is a constructorType, create an instance of it // if (null != constructorType) { List relshipExprList = null; // // convert relationships if present // if (methodExpr.HasRelationships) { if (ParserOptions.CompilationMode.NormalMode == sr.ParserOptions.ParserCompilationMode) { throw EntityUtil.EntitySqlError(methodExpr.Relationships.ErrCtx, System.Data.Entity.Strings.InvalidModeForWithRelationshipClause); } HashSet targetEnds = new HashSet (); relshipExprList = new List (methodExpr.Relationships.Count); for (int i = 0; i < methodExpr.Relationships.Count; i++) { RelshipNavigationExpr relshipExpr = methodExpr.Relationships[i]; DbRelatedEntityRef relshipTarget = ConvertRelatedEntityRef(relshipExpr, sr); string targetEndId = String.Join(":", new String[] { relshipTarget.TargetEnd.DeclaringType.Identity, relshipTarget.TargetEnd.Identity }); if (targetEnds.Contains(targetEndId)) { throw EntityUtil.EntitySqlError(relshipExpr.ErrCtx, System.Data.Entity.Strings.RelationshipTargetMustBeUnique(relshipTarget.TargetEntityReference.ResultType.EdmType.Identity)); } targetEnds.Add(targetEndId); relshipExprList.Add(relshipTarget); } } converted = sr.CreateInstanceOfType(constructorType, ConvertFunctionArguments(methodExpr.Args, sr), relshipExprList, methodExpr); } // // if it is staticMethodType, create method call expression // else if (null != staticMethodType) { converted = SemanticResolver.CreateStaticMethod(staticMethodType, ConvertFunctionArguments(methodExpr.Args, sr), methodExpr); } // // if it is functionType // else if (null != functionType && 0 < functionType.Count) { // // decide if it is an ordinary function or group aggreagate // if (TypeSemantics.IsAggregateFunction(functionType[0]) && sr.IsInAnyGroupScope()) { // // if it is an aggreagate function inside a group scope, dispatch to ConvertGroupAggregate() // converted = ConvertAggregateFunctionInGroupScope(methodExpr, functionType, sr); } else { // // else, is just an ordinary function call (including collection aggregates) // converted = sr.CreateFunction(functionType, ConvertFunctionArguments(methodExpr.Args, sr), methodExpr); } } else { throw EntityUtil.EntitySqlError(methodExpr.ErrCtx, System.Data.Entity.Strings.CannotResolveNameToFunction(methodExpr.MethodPrefixExpr.FullName)); } Debug.Assert(null != converted,"null != converted"); return converted; } /// /// Converts Group Aggregates /// /// /// /// ////// /// This method convert group aggregates in two phases: /// Phase 1 - it will resolve the actual inner (argument) expression and then anotate the ast node and add the resolved aggregate /// to the scope /// Phase 2 - if ast node was annotated, just extract the precomputed expression from the scope. /// private static DbExpression ConvertAggregateFunctionInGroupScope( MethodExpr methodExpr, IListfunctionTypes, SemanticResolver sr ) { DbExpression converted = null; // // first, try if aggregate was already pre resolved // if (TryConvertAsResolvedGroupAggregate(methodExpr, sr, out converted)) { return converted; } // // then, try to resolve as Ordinary function (collection aggregate) // if (TryConvertAsOrdinaryFunctionInGroup(methodExpr, functionTypes, sr, out converted)) { return converted; } // // finally, try to convert as group aggregate // if (TryConvertAsGroupAggregateFunction(methodExpr, functionTypes, sr, out converted)) { return converted; } // // if we reach this point, means the resolution failed // throw EntityUtil.EntitySqlError(methodExpr.ErrCtx, System.Data.Entity.Strings.FailedToResolveAggregateFunction(methodExpr.MethodPrefixExpr.FullName)); } /// /// try to convert as pre resolved aggregate function /// /// /// /// ///private static bool TryConvertAsResolvedGroupAggregate( MethodExpr methodExpr, SemanticResolver sr, out DbExpression converted ) { converted = null; // // if ast node was annotated in a previous pass, means it was already resolved and should be in scope // if (methodExpr.WasResolved) { sr.CurrentScopeRegionFlags.DecrementGroupAggregateNestingCount(); ScopeEntry scopeEntry; SemanticResolver.ScopeViewKind saveScopeView = sr.GetScopeView(); sr.SetScopeView(SemanticResolver.ScopeViewKind.All); int scopeIndex; if (!sr.TryScopeLookup(methodExpr.InternalAggregateName, out scopeEntry, out scopeIndex)) { Debug.Assert(methodExpr.DummyExpression != null, "resolved aggregate dummy expression must not be null"); converted = methodExpr.DummyExpression; return true; } else { // // Sets correlation flag // sr.SetScopeRegionCorrelationFlag(scopeIndex); } sr.SetScopeView(saveScopeView); converted = scopeEntry.Expression; return true; } return false; } /// /// Try convert method expr in a group scope as an ordinary function (collection aggregate) /// /// /// /// /// ///private static bool TryConvertAsOrdinaryFunctionInGroup( MethodExpr methodExpr , IList functionTypes , SemanticResolver sr , out DbExpression converted ) { converted = null; // // save scope view // SemanticResolver.ScopeViewKind saveScopeView = sr.GetScopeView(); // // convert aggregate arguments // List args = ConvertFunctionArguments(methodExpr.Args, sr); // // collect argument types // List argTypes = new List (args.Count); for (int i = 0 ; i < args.Count ; i++) { argTypes.Add(args[i].ResultType); } // // try to see if there is a overload match // bool isAmbiguous = false; EdmFunction functionType = TypeResolver.ResolveFunctionOverloads( functionTypes, argTypes, false /* isGroupAggregateFunction */, out isAmbiguous); // // if there is more then one overload that matches given arguments, throw // if (isAmbiguous) { throw EntityUtil.EntitySqlError(methodExpr.ErrCtx, System.Data.Entity.Strings.AmbiguousFunctionArguments); } // // if not null, means a match was found as an ordinary function // if (null != functionType) { // // make sure all referenced vars are from group scope only // if (!sr.CurrentScopeRegionFlags.IsImplicitGroup) { sr.SetScopeView(SemanticResolver.ScopeViewKind.CurrentScope); } // // convert aggregate arguments // args = ConvertFunctionArguments(methodExpr.Args, sr); // // restore previous scope view // sr.SetScopeView(saveScopeView); // // return function // converted = sr.CmdTree.CreateFunctionExpression(functionType, args); } return (null != functionType); } /// /// /// /// /// /// /// ///private static bool TryConvertAsGroupAggregateFunction( MethodExpr methodExpr, IList functionTypeList, SemanticResolver sr, out DbExpression converted ) { converted = null; // // save scope view // SemanticResolver.ScopeViewKind saveScopeView = sr.GetScopeView(); // // Aggregates in groups can refer to all scopes // sr.SetScopeView(SemanticResolver.ScopeViewKind.All); // // flag that it is inside a group aggregate // sr.CurrentScopeRegionFlags.IsInsideGroupAggregate = true; // // reset nested references flag // sr.CurrentScopeRegionFlags.WasNestedGroupAggregateReferredByInnerExpressions = false; // // pushes candidate aggregate ast node // sr.PushAggregateAstNode(methodExpr); sr.CurrentScopeRegionFlags.DecrementGroupAggregateNestingCount(); // // convert aggregate arguments // List args = ConvertFunctionArguments(methodExpr.Args, sr); // // clear inside group aggregate flag // sr.CurrentScopeRegionFlags.IsInsideGroupAggregate = false; // // collect argument types // List argTypes = new List (args.Count); for (int i = 0 ; i < args.Count ; i++) { argTypes.Add(args[i].ResultType); } // // try to find an overload match as group aggregate // bool isAmbiguous = false; EdmFunction functionType = TypeResolver.ResolveFunctionOverloads(functionTypeList, argTypes, true /* isGroupAggregateFunction */, out isAmbiguous); // // if there is more then one overload that matches given arguments, throw // if (isAmbiguous) { throw EntityUtil.EntitySqlError(methodExpr.ErrCtx, System.Data.Entity.Strings.AmbiguousFunctionArguments); } // // if it still null, then there is no overload as an ordinary function or group aggregate function // if (null == functionType) { CqlErrorHelper.ReportFunctionOverloadError(methodExpr, functionTypeList[0], argTypes); } // // ensure that group aggregate was not referenced by inner sub-expression // if (sr.CurrentScopeRegionFlags.WasNestedGroupAggregateReferredByInnerExpressions) { throw EntityUtil.EntitySqlError(methodExpr.ErrCtx, System.Data.Entity.Strings.NestedAggregatesCannotBeUsedInAggregateFunctions); } // // ensure it is not a nested group aggregate call // if (sr.CurrentScopeRegionFlags.GroupAggregateNestingCount < -1) { throw EntityUtil.EntitySqlError(methodExpr.MethodIdentifier.ErrCtx, System.Data.Entity.Strings.InvalidNestedGroupAggregateCall); } // // aggregate functions in the current release can have only one argument and must of of collectio type // Debug.Assert((1 == functionType.Parameters.Count), "(1 == functionType.Parameters.Count)"); // we only support monadic aggregate functions Debug.Assert(TypeSemantics.IsCollectionType(functionType.Parameters[0].TypeUsage), "functionType.Parameters[0].Type is CollectionType"); TypeUsage argumentType = TypeHelpers.GetElementTypeUsage(functionType.Parameters[0].TypeUsage); if (TypeSemantics.IsNullType(args[0].ResultType)) { args[0] = sr.CmdTree.CreateNullExpression(argumentType); } // // create function aggregate expression // DbFunctionAggregate functionAggregate; // create distinct expression if espeficied if (methodExpr.DistinctKind == DistinctKind.Distinct) { functionAggregate = sr.CmdTree.CreateDistinctFunctionAggregate(functionType, args[0]); } else { functionAggregate = sr.CmdTree.CreateFunctionAggregate(functionType, args[0]); } // // generate name for the aggregate 'property'. this name will the internal name of the pre-computed expression in the scope and // annotated ast node in the ast tree // string internalAggregateName = sr.GenerateInternalName("groupAgg" + functionType.Name); // // add aggreate to aggreate list // AggregateAstNodeInfo aggrAstInfo = sr.PopAggregateAstNode(); aggrAstInfo.AssertMethodExprEquivalent(methodExpr); sr.AddGroupAggregateInfoToScopeRegion(methodExpr, internalAggregateName, functionAggregate, aggrAstInfo.ScopeIndex); // // return 'dummy' expression with same type as aggregate function // converted = sr.CmdTree.CreateNullExpression(functionType.ReturnParameter.TypeUsage); // // anotate method expression node as aggregate // methodExpr.SetAggregateInfo(internalAggregateName, converted); // // restore visibility to group scope only // sr.SetScopeView(saveScopeView); // // increment nesting count // sr.CurrentScopeRegionFlags.IncrementGroupAggregateNestingCount(); return true; } /// /// Converted a instance method. /// /// /// /// /// ///private static DbExpression ConvertMethodInstance( DbExpression baseExpr, MethodExpr methodExpr, int prefixIndex, SemanticResolver sr ) { DbExpression converted = null; Debug.Assert(null != baseExpr,"null != baseExpr"); DotExpr dotExpr = methodExpr.MethodPrefixExpr; // // ensure methods are not called on Scalar type instances // if (TypeSemantics.IsPrimitiveType(baseExpr.ResultType)) { throw EntityUtil.EntitySqlError(dotExpr.LeftMostExpression.ErrCtx, System.Data.Entity.Strings.MethodNotAllowedOnScalars); } // // build the instance property references chain up to the method name // DbExpression innerExpression = baseExpr; for (int i = prefixIndex ; i < dotExpr.Length - 1 ; i++) { innerExpression = sr.ResolveIdentifierElement(innerExpression.ResultType, innerExpression, dotExpr.Names[i], dotExpr.ErrCtx); // // if this point is reached, means that an element in the path name is not a valid property // such as name[ i + 1 ] is not a valid property/member of defining type resolved previosly for name[ i ] // if (null == innerExpression) { throw EntityUtil.EntitySqlError(methodExpr.ErrCtx, System.Data.Entity.Strings.InvalidMethodPathElement(dotExpr.Names[i], innerExpression.ResultType.EdmType.FullName)); } } // // convert method arguments // List args = ConvertFunctionArguments(methodExpr.Args, sr); // // Resolve/Validate overloads and create method expression // converted = SemanticResolver.CreateInstanceMethod(innerExpression, args, methodExpr); Debug.Assert(null != converted,"null != converted"); return converted; } /// /// Converts EdmFunction Arguments representes a list of astExpr nodes /// /// /// ///private static List ConvertFunctionArguments( ExprList astExprList, SemanticResolver sr ) { List convertedArgs = new List (); if (null != astExprList) { for (int i = 0 ; i < astExprList.Count ; i++) { convertedArgs.Add(Convert(astExprList[i], sr)); } } return convertedArgs; } /// /// Convert Paramerters /// /// /// SemanticResolver instance relative to a especif typespace/system ///private static DbExpression ConvertParameter( Expr expr, SemanticResolver sr ) { Parameter parameter = (Parameter)expr; TypeUsage paramType = null; KeyValuePair varInfo; if (sr.Variables != null && sr.Variables.TryGetValue(parameter.Name, out varInfo)) { return sr.CmdTree.CreateVariableReferenceExpression(varInfo.Key, varInfo.Value); } if (null == sr.Parameters || !sr.Parameters.TryGetValue(parameter.Name, out paramType)) { throw EntityUtil.EntitySqlError(parameter.ErrCtx, System.Data.Entity.Strings.ParameterWasNotDefined(parameter.Name)); } sr.CmdTree.AddParameter(parameter.Name, TypeHelpers.GetReadOnlyType(paramType)); return sr.CmdTree.CreateParameterReferenceExpression(parameter.Name); } /// /// Validate a relationship-traversal - used for both Navigate expressions /// and for entity construction with related entity refs. /// /// For "related entity refs", "isTargetEnd" is true - for Navigate expressions, /// this parameter is "false". /// /// /// the relationshipExpr AST /// /// resolver context /// the source/target expression /// the relationship type /// from end of the relationship /// to-end of the relationship private static void ValidateRelationshipTraversal(RelshipNavigationExpr relshipExpr, bool isTargetEnd, SemanticResolver sr, out DbExpression refExpr, out RelationshipType relationshipType, out RelationshipEndMember refEnd, out RelationshipEndMember otherEnd) { relationshipType = null; refEnd = null; otherEnd = null; refExpr = null; // // resolve relationship type // relationshipType = sr.ResolveNameAsType(relshipExpr.RelationTypeNames, relshipExpr.RelationTypeNameIdentifier).EdmType as RelationshipType; if (null == relationshipType) { throw EntityUtil.EntitySqlError(relshipExpr.RelationTypeNameIdentifier.ErrCtx, System.Data.Entity.Strings.InvalidRelationshipTypeName(relshipExpr.RelationTypeFullName)); } // // convert relationship 'instance' expression // refExpr = Convert(relshipExpr.RelationshipSource, sr); // // if is entity, create entity ref out if it // if (!isTargetEnd && TypeSemantics.IsEntityType(refExpr.ResultType)) { refExpr = sr.CmdTree.CreateEntityRefExpression(refExpr); } // // make sure is ref type // if (!TypeSemantics.IsReferenceType(refExpr.ResultType)) { throw EntityUtil.EntitySqlError(relshipExpr.RelationshipSource.ErrCtx, System.Data.Entity.Strings.InvalidRelationshipSourceType); } // // ensure entity 'participates' in the given relationship type // if (!TypeSemantics.IsTypeValidForRelationship(TypeHelpers.GetElementTypeUsage(refExpr.ResultType), relationshipType)) { throw EntityUtil.EntitySqlError(relshipExpr.RelationTypeNameIdentifier.ErrCtx, System.Data.Entity.Strings.RelationshipTypeIsNotCompatibleWithEntity( TypeHelpers.GetFullName(TypeHelpers.GetElementTypeUsage(refExpr.ResultType)), TypeHelpers.GetFullName(relationshipType))); } // // ensure relationship ends are valid // metadata ensures that there will never happen to have two equal end names // TypeUsage fromEndType = null; int fromEndMatchCount = 0; TypeUsage elementType = TypeHelpers.GetElementTypeUsage(refExpr.ResultType); for (int i = 0; i < relationshipType.Members.Count; i++) { // // check 'to' end // if (relationshipType.Members[i].Name.Equals(relshipExpr.ToEndIdentifierName, StringComparison.OrdinalIgnoreCase)) { otherEnd = (RelationshipEndMember)relationshipType.Members[i]; continue; } // // check 'from' end // if ( (null != relshipExpr.FromEndIdentifier && relationshipType.Members[i].Name.Equals(relshipExpr.FromEndIdentifierName, StringComparison.OrdinalIgnoreCase)) || (null == relshipExpr.FromEndIdentifier && TypeSemantics.IsEquivalentOrPromotableTo(elementType, TypeHelpers.GetElementTypeUsage(relationshipType.Members[i].TypeUsage))) ) { fromEndMatchCount++; if (fromEndMatchCount > 1) { ErrorContext errCtx = (null == relshipExpr.FromEndIdentifier) ? relshipExpr.ErrCtx : relshipExpr.FromEndIdentifier.ErrCtx; throw EntityUtil.EntitySqlError(errCtx, System.Data.Entity.Strings.RelationshipFromEndIsAmbiguos); } refEnd = (RelationshipEndMember)relationshipType.Members[i]; fromEndType = relationshipType.Members[i].TypeUsage; } } // // ensure relationship 'To' end contains given property // if (null == otherEnd) { if (null != relshipExpr.ToEndIdentifier) { throw EntityUtil.EntitySqlError(relshipExpr.ToEndIdentifier.ErrCtx, System.Data.Entity.Strings.InvalidRelationshipMember(relshipExpr.ToEndIdentifierName, relshipExpr.RelationTypeFullName)); } if (2 != relationshipType.Members.Count) { throw EntityUtil.EntitySqlError(relshipExpr.ErrCtx, System.Data.Entity.Strings.InvalidImplicitRelationshipToEnd(relshipExpr.RelationTypeFullName)); } Debug.Assert(null != refEnd, "null!=fromEnd"); otherEnd = (RelationshipEndMember)(refEnd.Name.Equals(relationshipType.Members[0].Name, StringComparison.OrdinalIgnoreCase) ? relationshipType.Members[1] : relationshipType.Members[0]); } // // ensure relationship 'From' end contains given entity // if (null == refEnd || null == fromEndType) { ErrorContext errCtx = (null == relshipExpr.FromEndIdentifier) ? relshipExpr.ErrCtx : relshipExpr.FromEndIdentifier.ErrCtx; if (null == relshipExpr.FromEndIdentifier) { throw EntityUtil.EntitySqlError(errCtx, System.Data.Entity.Strings.InvalidImplicitRelationshipFromEnd(relshipExpr.RelationTypeFullName)); } else { throw EntityUtil.EntitySqlError(errCtx, System.Data.Entity.Strings.InvalidRelationshipMember(relshipExpr.FromEndIdentifierName, relshipExpr.RelationTypeFullName)); } } // // check if source is promotable to from end type // if (!TypeSemantics.IsValidPolymorphicCast(TypeHelpers.GetElementTypeUsage(refExpr.ResultType), TypeHelpers.GetElementTypeUsage(refEnd.TypeUsage))) { ErrorContext errCtx = (null == relshipExpr.FromEndIdentifier) ? relshipExpr.ErrCtx : relshipExpr.FromEndIdentifier.ErrCtx; throw EntityUtil.EntitySqlError(errCtx, System.Data.Entity.Strings.SourceTypeMustBePromotoableToFromEndRelationType(TypeHelpers.GetElementTypeUsage(refExpr.ResultType).EdmType.FullName, TypeHelpers.GetElementTypeUsage(fromEndType).EdmType.FullName)); } return; } ////// Build out a RelatedEntityRef /// /// the ast expression /// the Semantic Resolver context ///a DbRelatedEntityRef instance private static DbRelatedEntityRef ConvertRelatedEntityRef(RelshipNavigationExpr relshipExpr, SemanticResolver sr) { // // Validate the relationship traversal // DbExpression targetRef; RelationshipEndMember targetRefEnd; RelationshipEndMember otherEnd; RelationshipType relationshipType; ValidateRelationshipTraversal(relshipExpr, true /* targetEnd */ , sr, out targetRef, out relationshipType, out targetRefEnd, out otherEnd); // // ensure is *..{0|1} // if (RelationshipMultiplicity.One != targetRefEnd.RelationshipMultiplicity && RelationshipMultiplicity.ZeroOrOne != targetRefEnd.RelationshipMultiplicity) { throw EntityUtil.EntitySqlError(relshipExpr.ErrCtx, System.Data.Entity.Strings.InvalidWithRelationshipTargetEndMultiplicity(targetRefEnd.Identity, targetRefEnd.RelationshipMultiplicity.ToString())); } DbRelatedEntityRef relatedEntityRef = sr.CmdTree.CreateRelatedEntityRef(otherEnd, targetRefEnd, targetRef); return relatedEntityRef; } ////// converts Relationship Navigation operator /// /// /// SemanticResolver instance relative to a especif typespace/system ///private static DbExpression ConvertRelshipNavigationExpr( Expr astExpr, SemanticResolver sr ) { RelshipNavigationExpr relshipExpr = (RelshipNavigationExpr)astExpr; // // Validate the relationship traversal // DbExpression relationshipSource; RelationshipEndMember fromEnd; RelationshipEndMember toEnd; RelationshipType relationshipType; ValidateRelationshipTraversal(relshipExpr, false /* !targetEnd */, sr, out relationshipSource, out relationshipType, out fromEnd, out toEnd); // // create cqt expression // DbExpression converted = sr.CmdTree.CreateRelationshipNavigationExpression(fromEnd, toEnd, relationshipSource); Debug.Assert(null != converted,"null != converted"); return converted; } /// /// converts REF operator /// /// /// SemanticResolver instance relative to a especif typespace/system ///private static DbExpression ConvertRefExpr( Expr astExpr, SemanticResolver sr ) { RefExpr refExpr = (RefExpr)astExpr; DbExpression converted = Convert(refExpr.RefArgExpr, sr); // // check if is entity type // if (!TypeSemantics.IsEntityType(converted.ResultType)) { throw EntityUtil.EntitySqlError(refExpr.RefArgExpr.ErrCtx, System.Data.Entity.Strings.RefArgIsNotOfEntityType(converted.ResultType.EdmType.FullName)); } // // create ref expression // converted = sr.CmdTree.CreateEntityRefExpression(converted); Debug.Assert(null != converted,"null != converted"); return converted; } /// /// converts DEREF operator /// /// /// SemanticResolver instance relative to a especif typespace/system ///private static DbExpression ConvertDeRefExpr( Expr astExpr, SemanticResolver sr ) { DerefExpr deRefExpr = (DerefExpr)astExpr; DbExpression converted = null; converted = Convert(deRefExpr.RefExpr, sr); // // check if return type is RefType // if (!TypeSemantics.IsReferenceType(converted.ResultType)) { throw EntityUtil.EntitySqlError(deRefExpr.RefExpr.ErrCtx, System.Data.Entity.Strings.DeRefArgIsNotOfRefType(converted.ResultType.EdmType.FullName)); } // // create DeRef expression // converted = sr.CmdTree.CreateDerefExpression(converted); Debug.Assert(null != converted,"null != converted"); return converted; } /// /// converts CREATEREF operator /// /// /// SemanticResolver instance relative to a especif typespace/system ///private static DbExpression ConvertCreateRefExpr( Expr astExpr, SemanticResolver sr ) { CreateRefExpr createRefExpr = (CreateRefExpr)astExpr; DbExpression converted = null; // // Convert the entity set, also, ensure that we get back an extent expression // DbScanExpression entitySetExpr = Convert(createRefExpr.EntitySet, sr) as DbScanExpression; if (entitySetExpr == null) { throw EntityUtil.EntitySqlError(createRefExpr.EntitySet.ErrCtx, System.Data.Entity.Strings.ExprIsNotValidEntitySetForCreateRef); } // // Ensure that the extent is an entity set // EntitySet entitySet = entitySetExpr.Target as EntitySet; if (entitySet == null) { throw EntityUtil.EntitySqlError(createRefExpr.EntitySet.ErrCtx, System.Data.Entity.Strings.ExprIsNotValidEntitySetForCreateRef); } DbExpression keyRowExpression = Convert(createRefExpr.Keys, sr); SemanticResolver.EnsureIsNotUntypedNull(keyRowExpression, createRefExpr.Keys.ErrCtx); RowType inputKeyRowType = keyRowExpression.ResultType.EdmType as RowType; if (null == inputKeyRowType) { throw EntityUtil.EntitySqlError(createRefExpr.Keys.ErrCtx,System.Data.Entity.Strings.InvalidCreateRefKeyType); } RowType entityKeyRowType = TypeHelpers.CreateKeyRowType(entitySet.ElementType, sr.CmdTree.MetadataWorkspace); if (entityKeyRowType.Members.Count != inputKeyRowType.Members.Count) { throw EntityUtil.EntitySqlError(createRefExpr.Keys.ErrCtx, System.Data.Entity.Strings.ImcompatibleCreateRefKeyType); } if (!TypeSemantics.IsEquivalentOrPromotableTo(keyRowExpression.ResultType, TypeUsage.Create(entityKeyRowType))) { throw EntityUtil.EntitySqlError(createRefExpr.Keys.ErrCtx, System.Data.Entity.Strings.ImcompatibleCreateRefKeyElementType); } // // if CREATEREF specifies a type, resolve and validate the type // if (null != createRefExpr.TypeIdentifier) { TypeUsage targetTypeUsage = ConvertTypeIdentifier(createRefExpr.TypeIdentifier, sr); // // ensure type is entity // if (!TypeSemantics.IsEntityType(targetTypeUsage)) { throw EntityUtil.EntitySqlError(createRefExpr.TypeIdentifier.ErrCtx, System.Data.Entity.Strings.CreateRefTypeIdentifierMustSpecifyAnEntityType( targetTypeUsage.EdmType.Identity, targetTypeUsage.EdmType.BuiltInTypeKind.ToString())); } if (!TypeSemantics.IsValidPolymorphicCast(entitySet.ElementType, targetTypeUsage.EdmType)) { throw EntityUtil.EntitySqlError(createRefExpr.TypeIdentifier.ErrCtx, System.Data.Entity.Strings.CreateRefTypeIdentifierMustBeASubOrSuperType( entitySet.ElementType.Identity, targetTypeUsage.EdmType.FullName)); } converted = sr.CmdTree.CreateRefExpression(entitySet, keyRowExpression, (EntityType)targetTypeUsage.EdmType); } else { // // finally creates the expression // converted = sr.CmdTree.CreateRefExpression(entitySet, keyRowExpression); } Debug.Assert(null != converted,"null != converted"); return converted; } /// /// converts KEY operator /// /// /// SemanticResolver instance relative to a especif typespace/system ///private static DbExpression ConvertKeyExpr( Expr astExpr, SemanticResolver sr ) { KeyExpr keyExpr = (KeyExpr)astExpr; DbExpression converted = Convert(keyExpr.RefExpr, sr); SemanticResolver.EnsureIsNotUntypedNull(converted, keyExpr.RefExpr.ErrCtx); if (TypeSemantics.IsEntityType(converted.ResultType)) { converted = sr.CmdTree.CreateEntityRefExpression(converted); } else if (!TypeSemantics.IsReferenceType(converted.ResultType)) { throw EntityUtil.EntitySqlError(keyExpr.RefExpr.ErrCtx,System.Data.Entity.Strings.InvalidKeyArgument(TypeHelpers.GetFullName(converted.ResultType))); } converted = sr.CmdTree.CreateRefKeyExpression(converted); Debug.Assert(null != converted, "null != converted"); return converted; } /// /// Dispatches/Converts BuiltIn Expressions /// /// /// SemanticResolver instance relative to a especif typespace/system ///private static DbExpression ConvertBuiltIn( Expr astExpr, SemanticResolver sr ) { if (null == astExpr) { return null; } BuiltInExpr bltInExpr = (BuiltInExpr)astExpr; BuiltInExprConverter builtInConverter = _builtInExprConverter[bltInExpr.Kind]; if (null == builtInConverter) { throw EntityUtil.Argument(System.Data.Entity.Strings.UnknownBuiltInAstExpressionType); } DbExpression converted = builtInConverter(bltInExpr, sr); Debug.Assert(null != converted,"null != converted"); return converted; } /// /// Converts Arithmetic Expressions Args /// /// /// SemanticResolver instance relative to a especif typespace/system ///private static Pair ConvertArithmeticArgs( BuiltInExpr astBuiltInExpr, SemanticResolver sr ) { DbExpression leftExpr = Convert(astBuiltInExpr.Arg1, sr); if (!(TypeSemantics.IsNumericType(leftExpr.ResultType) || SemanticResolver.IsNullExpression(leftExpr))) { throw EntityUtil.EntitySqlError(astBuiltInExpr.Arg1.ErrCtx, System.Data.Entity.Strings.ExpressionMustBeNumericType); } DbExpression rightExpr = null; if (null != astBuiltInExpr.Arg2) { rightExpr = Convert(astBuiltInExpr.Arg2, sr); if (!(TypeSemantics.IsNumericType(rightExpr.ResultType) || SemanticResolver.IsNullExpression(rightExpr))) { throw EntityUtil.EntitySqlError(astBuiltInExpr.Arg2.ErrCtx, System.Data.Entity.Strings.ExpressionMustBeNumericType); } if (null == TypeHelpers.GetCommonTypeUsage(leftExpr.ResultType, rightExpr.ResultType)) { throw EntityUtil.EntitySqlError(astBuiltInExpr.ErrCtx, System.Data.Entity.Strings.ArgumentTypesAreIncompatible(leftExpr.ResultType.EdmType.FullName, rightExpr.ResultType.EdmType.FullName)); } } return sr.EnsureTypedNulls(leftExpr, rightExpr, astBuiltInExpr.ErrCtx, () => Strings.InvalidNullArithmetic); } /// /// Converts Plus Args - specific case since string type is an allowed type for '+' /// /// /// SemanticResolver instance relative to a especif typespace/system ///private static Pair ConvertPlusOperands( BuiltInExpr astBuiltInExpr, SemanticResolver sr ) { DbExpression leftExpr = Convert(astBuiltInExpr.Arg1, sr); if (!(TypeSemantics.IsNumericType(leftExpr.ResultType) || TypeSemantics.IsPrimitiveType(leftExpr.ResultType,PrimitiveTypeKind.String) || SemanticResolver.IsNullExpression(leftExpr))) { throw EntityUtil.EntitySqlError(astBuiltInExpr.Arg1.ErrCtx, System.Data.Entity.Strings.PlusLeftExpressionInvalidType); } DbExpression rightExpr = Convert(astBuiltInExpr.Arg2, sr); if (!(TypeSemantics.IsNumericType(rightExpr.ResultType) || TypeSemantics.IsPrimitiveType(rightExpr.ResultType, PrimitiveTypeKind.String) || SemanticResolver.IsNullExpression(rightExpr))) { throw EntityUtil.EntitySqlError(astBuiltInExpr.Arg2.ErrCtx, System.Data.Entity.Strings.PlusRightExpressionInvalidType); } if (null == TypeHelpers.GetCommonTypeUsage(leftExpr.ResultType, rightExpr.ResultType)) { throw EntityUtil.EntitySqlError(astBuiltInExpr.ErrCtx, System.Data.Entity.Strings.ArgumentTypesAreIncompatible(leftExpr.ResultType.EdmType.FullName, rightExpr.ResultType.EdmType.FullName)); } return sr.EnsureTypedNulls(leftExpr, rightExpr, astBuiltInExpr.ErrCtx, () => Strings.InvalidNullArithmetic); } /// /// Converts Logical Expression Args /// /// /// SemanticResolver instance relative to a especif typespace/system ///private static Pair ConvertLogicalArgs( BuiltInExpr astBuiltInExpr, SemanticResolver sr ) { DbExpression leftExpr = Convert(astBuiltInExpr.Arg1, sr); if (leftExpr is UntypedNullExpression) { leftExpr = sr.CmdTree.CreateNullExpression(sr.TypeResolver.BooleanType); } DbExpression rightExpr = Convert(astBuiltInExpr.Arg2, sr); if (rightExpr is UntypedNullExpression) { rightExpr = sr.CmdTree.CreateNullExpression(sr.TypeResolver.BooleanType); } // // ensure left expression type is boolean // if (!TypeResolver.IsBooleanType(leftExpr.ResultType)) { throw EntityUtil.EntitySqlError(astBuiltInExpr.Arg1.ErrCtx, System.Data.Entity.Strings.ExpressionTypeMustBeBoolean); } // // ensure right expression type is boolean // if (null != rightExpr && !TypeResolver.IsBooleanType(rightExpr.ResultType)) { throw EntityUtil.EntitySqlError(astBuiltInExpr.Arg2.ErrCtx, System.Data.Entity.Strings.ExpressionTypeMustBeBoolean); } return new Pair (leftExpr, rightExpr); } /// /// Converts Equal Comparison Expression Args /// /// /// SemanticResolver instance relative to a especif typespace/system ///private static Pair ConvertEqualCompArgs( BuiltInExpr astBuiltInExpr, SemanticResolver sr ) { // // convert left and right types and infer null types // Pair compArgs = sr.EnsureTypedNulls( Convert(astBuiltInExpr.Arg1, sr), Convert(astBuiltInExpr.Arg2, sr), astBuiltInExpr.ErrCtx, () => Strings.InvalidNullComparison); // // ensure both operand types are equal-comparable // if (!TypeSemantics.IsEqualComparableTo(compArgs.Left.ResultType, compArgs.Right.ResultType)) { throw EntityUtil.EntitySqlError(astBuiltInExpr.ErrCtx, System.Data.Entity.Strings.ArgumentTypesAreIncompatible(compArgs.Left.ResultType.EdmType.FullName, compArgs.Right.ResultType.EdmType.FullName)); } return compArgs; } /// /// Converts Order Comparison Expression Args /// /// /// SemanticResolver instance relative to a especif typespace/system ///private static Pair ConvertOrderCompArgs( BuiltInExpr astBuiltInExpr, SemanticResolver sr ) { Pair compArgs = sr.EnsureTypedNulls( Convert(astBuiltInExpr.Arg1, sr), Convert(astBuiltInExpr.Arg2, sr), astBuiltInExpr.ErrCtx, () => Strings.InvalidNullComparison); // // ensure both operand types are order-comparable // if (!TypeSemantics.IsOrderComparableTo(compArgs.Left.ResultType, compArgs.Right.ResultType)) { throw EntityUtil.EntitySqlError(astBuiltInExpr.ErrCtx, System.Data.Entity.Strings.ArgumentTypesAreIncompatible(compArgs.Left.ResultType.EdmType.FullName, compArgs.Right.ResultType.EdmType.FullName)); } return compArgs; } /// /// Converts Set Expression Args /// /// /// SemanticResolver instance relative to a especif typespace/system ///private static Pair ConvertSetArgs( BuiltInExpr astBuiltInExpr, SemanticResolver sr ) { // // convert left expression // DbExpression leftExpr = Convert(astBuiltInExpr.Arg1, sr); // // convert right expression if binary set op kind // DbExpression rightExpr = null; if (null != astBuiltInExpr.Arg2) { // // binary set op // // // make sure left expression type is of sequence type (ICollection or Extent) // if (!TypeSemantics.IsCollectionType(leftExpr.ResultType)) { throw EntityUtil.EntitySqlError(astBuiltInExpr.Arg1.ErrCtx, System.Data.Entity.Strings.LeftSetExpressionArgsMustBeCollection); } // // convert right expression // rightExpr = Convert(astBuiltInExpr.Arg2, sr); // // make sure right expression type is of sequence type (ICollection or Extent) // if (!TypeSemantics.IsCollectionType(rightExpr.ResultType)) { throw EntityUtil.EntitySqlError(astBuiltInExpr.Arg2.ErrCtx, System.Data.Entity.Strings.RightSetExpressionArgsMustBeCollection); } TypeUsage commonType; TypeUsage leftElemType = TypeHelpers.GetElementTypeUsage(leftExpr.ResultType); TypeUsage rightElemType = TypeHelpers.GetElementTypeUsage(rightExpr.ResultType); if (!TypeSemantics.TryGetCommonType(leftElemType, rightElemType, out commonType)) { CqlErrorHelper.ReportIncompatibleCommonType(astBuiltInExpr.ErrCtx, leftElemType, rightElemType); } if (astBuiltInExpr.Kind != BuiltInKind.UnionAll) { // // ensure left argument is set op comparable // if (!TypeHelpers.IsSetComparableOpType(TypeHelpers.GetElementTypeUsage(leftExpr.ResultType))) { throw EntityUtil.EntitySqlError(astBuiltInExpr.Arg1.ErrCtx, System.Data.Entity.Strings.PlaceholderSetArgTypeIsNotEqualComparable( astBuiltInExpr.Kind.ToString().ToUpperInvariant(), System.Data.Entity.Strings.LocalizedLeft, TypeHelpers.GetElementTypeUsage(leftExpr.ResultType).EdmType.FullName)); } // // ensure right argument is set op comparable // if (!TypeHelpers.IsSetComparableOpType(TypeHelpers.GetElementTypeUsage(rightExpr.ResultType))) { throw EntityUtil.EntitySqlError(astBuiltInExpr.Arg2.ErrCtx, System.Data.Entity.Strings.PlaceholderSetArgTypeIsNotEqualComparable( astBuiltInExpr.Kind.ToString().ToUpperInvariant(), System.Data.Entity.Strings.LocalizedRight, TypeHelpers.GetElementTypeUsage(rightExpr.ResultType).EdmType.FullName)); } } else { if (Helper.IsAssociationType(leftElemType.EdmType)) { throw EntityUtil.EntitySqlError(astBuiltInExpr.Arg1.ErrCtx, System.Data.Entity.Strings.InvalidAssociationTypeForUnion(leftElemType.Identity)); } if (Helper.IsAssociationType(rightElemType.EdmType)) { throw EntityUtil.EntitySqlError(astBuiltInExpr.Arg2.ErrCtx, System.Data.Entity.Strings.InvalidAssociationTypeForUnion(rightElemType.Identity)); } } } else { // // unary set op // // // make sure expression type is of sequence type (ICollection or Extent) // if (!TypeSemantics.IsCollectionType(leftExpr.ResultType)) { throw EntityUtil.EntitySqlError(astBuiltInExpr.Arg1.ErrCtx, System.Data.Entity.Strings.InvalidUnarySetOpArgument(astBuiltInExpr.Name)); } // // make sure that if is distinct unary operator, arg element type must be equal-comparable // if (astBuiltInExpr.Kind == BuiltInKind.Distinct && !TypeHelpers.IsValidDistinctOpType(TypeHelpers.GetElementTypeUsage(leftExpr.ResultType))) { throw EntityUtil.EntitySqlError(astBuiltInExpr.Arg1.ErrCtx, System.Data.Entity.Strings.ExpressionTypeMustBeEqualComparable); } } return new Pair (leftExpr, rightExpr); } /// /// Converts Set 'IN' expression args /// /// /// SemanticResolver instance relative to a especif typespace/system ///private static Pair ConvertInExprArgs( BuiltInExpr astBuiltInExpr, SemanticResolver sr ) { DbExpression leftExpr = Convert(astBuiltInExpr.Arg1, sr); if (TypeSemantics.IsCollectionType(leftExpr.ResultType)) { throw EntityUtil.EntitySqlError(astBuiltInExpr.Arg1.ErrCtx, System.Data.Entity.Strings.ExpressionTypeMustNotBeCollection); } DbExpression rightExpr = Convert(astBuiltInExpr.Arg2, sr); if (!TypeSemantics.IsCollectionType(rightExpr.ResultType)) { throw EntityUtil.EntitySqlError(astBuiltInExpr.Arg2.ErrCtx, System.Data.Entity.Strings.RightSetExpressionArgsMustBeCollection); } // // if left expression type is null, infer its type from the collection element type // if (SemanticResolver.IsNullExpression(leftExpr)) { TypeUsage elementType = TypeHelpers.GetElementTypeUsage(rightExpr.ResultType); SemanticResolver.EnsureValidTypeForNullExpression(elementType, astBuiltInExpr.Arg1.ErrCtx); leftExpr = sr.CmdTree.CreateNullExpression(elementType); } else { // // ensure that if left and right are typed expressions then their types must be comparable for IN op // TypeUsage commonElemType = TypeHelpers.GetCommonTypeUsage(leftExpr.ResultType, TypeHelpers.GetElementTypeUsage(rightExpr.ResultType)); if (null == commonElemType || !TypeHelpers.IsValidInOpType(commonElemType)) { throw EntityUtil.EntitySqlError(astBuiltInExpr.ErrCtx, System.Data.Entity.Strings.InvalidInExprArgs(leftExpr.ResultType.EdmType.FullName, rightExpr.ResultType.EdmType.FullName)); } } return new Pair (leftExpr, rightExpr); } /// /// Converts Type Expression Args /// /// /// SemanticResolver instance relative to a specific typespace/system ///private static Pair ConvertTypeExprArgs( BuiltInExpr astBuiltInExpr, SemanticResolver sr ) { return new Pair (Convert(astBuiltInExpr.Arg1, sr), ConvertTypeIdentifier(astBuiltInExpr.Arg2, sr)); } /// /// Converts TypeIdentifier /// TypeIdentifier can have the 'shape' of a simple identifier (product), a dotted identifier (namespace.bar) or a methodExpr ( edm.decimal(10,4) ) /// /// /// ///private static TypeUsage ConvertTypeIdentifier(Expr typeIdentifierExpr, SemanticResolver sr) { MethodExpr methodExpr = null; string[] typeNames; // // if it is dot id get full id name // DotExpr dotExpr = typeIdentifierExpr as DotExpr; if (null != dotExpr && dotExpr.IsDottedIdentifier) { typeNames = dotExpr.Names; } else { // // method expression, type with parameters // methodExpr = typeIdentifierExpr as MethodExpr; if (null != methodExpr) { typeNames = methodExpr.MethodPrefixExpr.Names; Debug.Assert(methodExpr.Args.Count == 1 || methodExpr.Args.Count == 2, "decimal type must have one or two arguments"); Debug.Assert(methodExpr.Args[0] is Literal, "type expression must have literal arg"); Debug.Assert((methodExpr.Args.Count == 2) ? methodExpr.Args[1] is Literal : true, "type expression must have literal arg"); } else { // // if it is single id, get it is name // Identifier id = typeIdentifierExpr as Identifier; if (null != id) { typeNames = new string[] { id.Name }; } else { throw EntityUtil.EntitySqlError(typeIdentifierExpr.ErrCtx, System.Data.Entity.Strings.InvalidTypeNameExpression); } } } // // Resolve type // TypeUsage typeUsage = sr.ResolveNameAsType(typeNames, typeIdentifierExpr); return typeUsage; } /// /// Converts Row type constructor expression /// /// /// SemanticResolver instance relative to a especif typespace/system ///private static DbExpression ConvertRowConstructor( Expr expr, SemanticResolver sr ) { RowConstructorExpr rowExpr = (RowConstructorExpr)expr; Dictionary rowColumns = new Dictionary (sr.ScopeStringComparer); List fieldExprs = new List (rowExpr.AliasExprList.Count); for (int i = 0 ; i < rowExpr.AliasExprList.Count ; i++) { AliasExpr aliasExpr = rowExpr.AliasExprList[i]; DbExpression colExpr = Convert(aliasExpr.Expr, sr); string aliasName = sr.InferAliasName(aliasExpr, colExpr); if (rowColumns.ContainsKey(aliasName)) { if (aliasExpr.HasAlias) { CqlErrorHelper.ReportAliasAlreadyUsedError(aliasName, aliasExpr.AliasIdentifier.ErrCtx, System.Data.Entity.Strings.InRowConstructor); } else { aliasName = sr.GenerateInternalName("autoRowCol"); } } if (SemanticResolver.IsNullExpression(colExpr)) { throw EntityUtil.EntitySqlError(aliasExpr.Expr.ErrCtx, System.Data.Entity.Strings.RowCtorElementCannotBeNull); } rowColumns.Add(aliasName, colExpr.ResultType); fieldExprs.Add(colExpr); } return sr.CmdTree.CreateNewInstanceExpression(TypeHelpers.CreateRowTypeUsage(rowColumns, true /* readOnly */), fieldExprs); } /// /// Converts Multiset type constructor expression /// /// /// SemanticResolver instance relative to a especif typespace/system ///private static DbExpression ConvertMultisetConstructor( Expr expr, SemanticResolver sr ) { MultisetConstructorExpr msetCtor = (MultisetConstructorExpr)expr; if (null == msetCtor.ExprList) { throw EntityUtil.EntitySqlError(expr.ErrCtx, System.Data.Entity.Strings.CannotCreateEmptyMultiset); } PairOfLists mSetExprs = ProcessExprList(msetCtor.ExprList, sr); TypeUsage commonType = TypeHelpers.GetCommonTypeUsage(mSetExprs.Left); // // ensure all elems have a common type // if (null == commonType) { throw EntityUtil.EntitySqlError(expr.ErrCtx, System.Data.Entity.Strings.MultisetElemsAreNotTypeCompatible); } // // ensure common type is not an untyped null // if (TypeSemantics.IsNullType(commonType)) { throw EntityUtil.EntitySqlError(expr.ErrCtx, System.Data.Entity.Strings.CannotCreateMultisetofNulls); } commonType = TypeHelpers.GetReadOnlyType(commonType); // // fixup untyped nulls // for (int i = 0 ; i < mSetExprs.Count ; i++) { if (SemanticResolver.IsNullExpression(mSetExprs.Right[i])) { SemanticResolver.EnsureValidTypeForNullExpression(commonType, msetCtor.ExprList[i].ErrCtx); mSetExprs.Right[i] = sr.CmdTree.CreateNullExpression(commonType); } } return sr.CmdTree.CreateNewInstanceExpression(TypeHelpers.CreateCollectionTypeUsage(commonType, true /* readOnly */), mSetExprs.Right); } /// /// converts case-when-then expression /// /// /// SemanticResolver instance relative to a especif typespace/system ///private static DbExpression ConvertCaseExpr( Expr expr, SemanticResolver sr ) { CaseExpr caseExpr = (CaseExpr)expr; List whenExprList = new List (caseExpr.WhenThenExprList.Count); PairOfLists thenExprList = new PairOfLists (); // // Resolve then expressions // for (int i = 0 ; i < caseExpr.WhenThenExprList.Count ; i++) { WhenThenExpr whenThenExpr = caseExpr.WhenThenExprList[i]; DbExpression whenExpression = Convert(whenThenExpr.WhenExpr, sr); if (!TypeResolver.IsBooleanType(whenExpression.ResultType)) { throw EntityUtil.EntitySqlError(whenThenExpr.WhenExpr.ErrCtx, System.Data.Entity.Strings.ExpressionTypeMustBeBoolean); } whenExprList.Add(whenExpression); DbExpression thenExpression = Convert(whenThenExpr.ThenExpr, sr); thenExprList.Add(thenExpression, thenExpression.ResultType); } TypeUsage resultType = TypeHelpers.GetCommonTypeUsage(thenExprList.Right); if (null == resultType) { throw EntityUtil.EntitySqlError(caseExpr.WhenThenExprList.Expressions[0].ThenExpr.ErrCtx, System.Data.Entity.Strings.InvalidCaseThenTypes); } if ((null == caseExpr.ElseExpr) && TypeSemantics.IsNullType(resultType)) { throw EntityUtil.EntitySqlError(caseExpr.WhenThenExprList.Expressions[0].ThenExpr.ErrCtx, System.Data.Entity.Strings.InvalidCaseThenNullType); } // // Converts else if present // DbExpression elseExpr = null; if (null != caseExpr.ElseExpr) { elseExpr = Convert(caseExpr.ElseExpr, sr); resultType = TypeHelpers.GetCommonTypeUsage(resultType, elseExpr.ResultType); if (null == resultType) { throw EntityUtil.EntitySqlError(caseExpr.ElseExpr.ErrCtx, System.Data.Entity.Strings.InvalidCaseElseType); } if (TypeSemantics.IsNullType(resultType)) { throw EntityUtil.EntitySqlError(caseExpr.ElseExpr.ErrCtx, System.Data.Entity.Strings.InvalidCaseWhenThenNullType); } if (SemanticResolver.IsNullExpression(elseExpr)) { SemanticResolver.EnsureValidTypeForNullExpression(resultType, caseExpr.ElseExpr.ErrCtx); elseExpr = sr.CmdTree.CreateNullExpression(resultType); } } else { if (TypeSemantics.IsCollectionType(resultType)) { elseExpr = sr.CmdTree.CreateNewEmptyCollectionExpression(resultType); } else { SemanticResolver.EnsureValidTypeForNullExpression(resultType, caseExpr.ErrCtx); elseExpr = sr.CmdTree.CreateNullExpression(resultType); } } // // fixup untyped nulls // for (int i = 0 ; i < thenExprList.Count ; i++) { if (SemanticResolver.IsNullExpression(thenExprList.Left[i])) { SemanticResolver.EnsureValidTypeForNullExpression(resultType, caseExpr.WhenThenExprList[i].ThenExpr.ErrCtx); thenExprList[i] = new Pair (sr.CmdTree.CreateNullExpression(resultType), resultType); } } return sr.CmdTree.CreateCaseExpression(whenExprList, thenExprList.Left, elseExpr); } /// /// Converts Query Expression /// /// /// SemanticResolver instance relative to a especif typespace/system ///private static DbExpression ConvertQuery( Expr expr, SemanticResolver sr ) { QueryExpr queryExpr = (QueryExpr)expr; DbExpression converted = null; bool isRestrictedViewGenerationMode = (ParserOptions.CompilationMode.RestrictedViewGenerationMode == sr.ParserOptions.ParserCompilationMode); // // Validate & Compensate Query // ValidateAndCompensateQuery(queryExpr); // // Create Source Scope Region // using (sr.EnterScopeRegion()) { // // Process From Clause // DbExpressionBinding sourceExpr = ProcessFromClause(queryExpr.FromClause, sr); // // Process Where Clause // sourceExpr = ProcessWhereClause(sourceExpr, queryExpr.WhereClause, sr); Debug.Assert(isRestrictedViewGenerationMode ? null == queryExpr.GroupByClause : true, "GROUP BY clause must be null in RestrictedViewGenerationMode"); Debug.Assert(isRestrictedViewGenerationMode ? null == queryExpr.HavingClause : true, "HAVING clause must be null in RestrictedViewGenerationMode"); Debug.Assert(isRestrictedViewGenerationMode ? null == queryExpr.OrderByClause : true, "ORDER BY clause must be null in RestrictedViewGenerationMode"); if ( !isRestrictedViewGenerationMode ) { // // Process GroupBy Clause // sourceExpr = ProcessGroupByClause(sourceExpr, queryExpr, sr); // // Process Having Clause // sourceExpr = ProcessHavingClause(sourceExpr, queryExpr.HavingClause, sr); // // Process OrderBy Clause // sourceExpr = ProcessOrderByClause(sourceExpr, queryExpr, sr); } // // Process Projection Clause // converted = ProcessSelectClause(sourceExpr, queryExpr, sr); } // end query scope region return converted; } /// /// Validates and Compensates query expression /// /// private static void ValidateAndCompensateQuery( QueryExpr queryExpr ) { if (null != queryExpr.HavingClause && null == queryExpr.GroupByClause) { throw EntityUtil.EntitySqlError(queryExpr.ErrCtx, System.Data.Entity.Strings.HavingRequiresGroupClause); } if (queryExpr.SelectClause.HasTopClause) { if ((null != queryExpr.OrderByClause) && queryExpr.OrderByClause.HasLimitSubClause) { throw EntityUtil.EntitySqlError(queryExpr.SelectClause.TopExpr.ErrCtx, System.Data.Entity.Strings.TopAndLimitCannotCoexist); } if ((null != queryExpr.OrderByClause) && queryExpr.OrderByClause.HasSkipSubClause) { throw EntityUtil.EntitySqlError(queryExpr.SelectClause.TopExpr.ErrCtx, System.Data.Entity.Strings.TopAndSkipCannotCoexist); } } } ////// Process Select Clause /// /// /// /// SemanticResolver instance relative to a especific typespace/system ///private static DbExpression ProcessSelectClause( DbExpressionBinding source, QueryExpr queryExpr, SemanticResolver sr ) { DbExpression projectExpression = null; SelectClause selectClause = queryExpr.SelectClause; HashSet projectionAliases = new HashSet (sr.ScopeStringComparer); List > projFields = new List >(selectClause.Items.Count); // // if source is sort/skip expression, then skip projection conversion since it was already // performed // if (queryExpr.OrderByClause != null && selectClause.DistinctKind == DistinctKind.Distinct) { projectExpression = source.Expression; } else { // // Converts projection list // #region Process projection list for (int i = 0; i < selectClause.Items.Count; i++) { AliasExpr selectExprItem = selectClause.Items[i]; DbExpression converted = Convert(selectExprItem.Expr, sr); // // ensure expression is typed // SemanticResolver.EnsureIsNotUntypedNull(converted, selectExprItem.Expr.ErrCtx); // // infer projection expression alias // string aliasName = sr.InferAliasName(selectExprItem, converted); // // ensure the alias was not used already // if (projectionAliases.Contains(aliasName)) { if (selectExprItem.HasAlias) { CqlErrorHelper.ReportAliasAlreadyUsedError(aliasName, selectExprItem.AliasIdentifier.ErrCtx, System.Data.Entity.Strings.InSelectProjectionList); } else { aliasName = sr.GenerateInternalName("autoProject"); } } projectionAliases.Add(aliasName); projFields.Add(new KeyValuePair (aliasName, converted)); } #endregion // // VALUE projection // #region handles VALUE modifier if (selectClause.SelectKind == SelectKind.SelectValue) { if (projFields.Count > 1) { throw EntityUtil.EntitySqlError(selectClause.ErrCtx, System.Data.Entity.Strings.InvalidSelectItem); } projectExpression = sr.CmdTree.CreateProjectExpression(source, projFields[0].Value); } else { projectExpression = sr.CmdTree.CreateProjectExpression(source, sr.CmdTree.CreateNewRowExpression(projFields)); } #endregion // // handle DISTINCT modifier // #region DISTINCT if (selectClause.DistinctKind == DistinctKind.Distinct) { // // ensure element type is equal-comparable // SemanticResolver.ValidateDistinctProjection(selectClause, projectExpression.ResultType); // // create distinct expression // projectExpression = sr.CmdTree.CreateDistinctExpression(projectExpression); } #endregion } // // TOP sub-clause // NOTE: WITH TIES is not supported in M3.2 // #region TOP/LIMIT sub-clause if (selectClause.HasTopClause || ((null != queryExpr.OrderByClause) && queryExpr.OrderByClause.HasLimitSubClause)) { ErrorContext errCtx = (selectClause.HasTopClause) ? selectClause.TopExpr.ErrCtx : queryExpr.OrderByClause.LimitSubClause.ErrCtx; // // convert top argument // DbExpression limitExpr = Convert((selectClause.HasTopClause) ? selectClause.TopExpr : queryExpr.OrderByClause.LimitSubClause, sr); // // ensure is not NULL expr // SemanticResolver.EnsureIsNotUntypedNull(limitExpr, errCtx); Debug.Assert(limitExpr is DbConstantExpression || limitExpr is DbParameterReferenceExpression, "TOP/LIMIT inner expression must be a parameter or numeric literal in this release"); // // ensure proper pre-conditions hold for TOP expression // sr.EnsureValidLimitExpression( errCtx, limitExpr, (selectClause.HasTopClause) ? "TOP" : "LIMIT"); // create expression - WITH TIES is not supported in M3.2 projectExpression = sr.CmdTree.CreateLimitExpression(projectExpression, limitExpr); } #endregion Debug.Assert(null != projectExpression,"null != projectExpr"); return projectExpression; } /// /// Process From Clause /// /// /// SemanticResolver instance relative to a especif typespace/system ///private static DbExpressionBinding ProcessFromClause( FromClause fromClause, SemanticResolver sr ) { DbExpressionBinding fromBinding = null; DbExpressionBinding fromBindingAux = null; // // Process Each From Clause Item // for (int i = 0 ; i < fromClause.FromClauseItems.Count ; i++ ) { // // Set Scope Source Var Kind // sr.SetCurrentScopeVarKind(fromClause.FromClauseItems[i].FromClauseItemKind); // // Convert From Clause // fromBindingAux = ProcessFromClauseItem(fromClause.FromClauseItems[i], sr); // // Reset All Vars to SourceVar Kind // sr.ResetCurrentScopeVarKind(); if (null == fromBinding) { fromBinding = fromBindingAux; } else { fromBinding = sr.CmdTree.CreateExpressionBinding( sr.CmdTree.CreateCrossApplyExpression(fromBinding, fromBindingAux), sr.GenerateInternalName("lcapply")); sr.FixupNamedSourceVarBindings(fromBinding.Variable); } } Debug.Assert(null != fromBinding,"null != fromBinding"); return fromBinding; } /// /// Process Generic From Clause Item /// /// /// SemanticResolver instance relative to a especif typespace/system ///private static DbExpressionBinding ProcessFromClauseItem( FromClauseItem fromClauseItem, SemanticResolver sr ) { DbExpressionBinding fromItemBinding = null; AliasExpr aliasExpr = fromClauseItem.FromExpr as AliasExpr; if (null != aliasExpr) { fromItemBinding = ProcessAliasedFromClauseItem(aliasExpr, sr); } else { JoinClauseItem joinClauseItem = fromClauseItem.FromExpr as JoinClauseItem; if (null != joinClauseItem) { fromItemBinding = ProcessJoinClauseItem(joinClauseItem, sr); } else { fromItemBinding = ProcessApplyClauseItem((ApplyClauseItem)fromClauseItem.FromExpr, sr); } } Debug.Assert(null != fromItemBinding,"null != fromItemBinding"); return fromItemBinding; } /// /// Process 'Simple' From Clause Item /// /// /// SemanticResolver instance relative to a especif typespace/system ///private static DbExpressionBinding ProcessAliasedFromClauseItem( AliasExpr aliasedExpr, SemanticResolver sr ) { DbExpressionBinding aliasedBinding = null; // // converts from item expression // DbExpression converted = Convert(aliasedExpr.Expr, sr); // // ensure expression is typed // SemanticResolver.EnsureIsNotUntypedNull(converted, aliasedExpr.Expr.ErrCtx); // // validate it is of sequence type (Extent || ICollection) // if (!TypeSemantics.IsCollectionType(converted.ResultType)) { throw EntityUtil.EntitySqlError(aliasedExpr.Expr.ErrCtx, System.Data.Entity.Strings.ExpressionMustBeCollection); } // // infer source var alias name // string aliasName = sr.InferAliasName(aliasedExpr, converted); // // validate the name was not used yet. // if (sr.IsInCurrentScope(aliasName)) { if (aliasedExpr.HasAlias) { CqlErrorHelper.ReportAliasAlreadyUsedError(aliasName, aliasedExpr.AliasIdentifier.ErrCtx, System.Data.Entity.Strings.InFromClause); } else { aliasName = sr.GenerateInternalName("autoFrom"); } } // // create cqt expression // aliasedBinding = sr.CmdTree.CreateExpressionBinding(converted, aliasName); // // add source var to scope // sr.AddSourceBinding(aliasedBinding); Debug.Assert(null != aliasedBinding,"null != aliasedBinding"); return aliasedBinding; } /// /// process join clause item /// /// /// SemanticResolver instance relative to a especif typespace/system ///private static DbExpressionBinding ProcessJoinClauseItem( JoinClauseItem joinClause, SemanticResolver sr ) { DbExpressionBinding joinBinding = null; // // make sure inner join have on predicate AND cross join has no ON predicate // if (null == joinClause.OnExpr) { if (JoinKind.Inner == joinClause.JoinKind) { throw EntityUtil.EntitySqlError(joinClause.ErrCtx, System.Data.Entity.Strings.InnerJoinMustHaveOnPredicate); } } else { if (JoinKind.Cross == joinClause.JoinKind) { throw EntityUtil.EntitySqlError(joinClause.OnExpr.ErrCtx, System.Data.Entity.Strings.InvalidPredicateForCrossJoin); } } // // Resolve Left Expression // sr.CurrentScopeRegionFlags.PathTagger.VisitLeftNode(); DbExpressionBinding leftBindingExpr = ProcessFromClauseItem(joinClause.LeftExpr, sr); sr.CurrentScopeRegionFlags.PathTagger.LeaveNode(); // // Resolve Right Expression // sr.CurrentScopeRegionFlags.IsInsideJoinOnPredicate = false; sr.CurrentScopeRegionFlags.PathTagger.VisitRightNode(); DbExpressionBinding rightBindingExpr = ProcessFromClauseItem(joinClause.RightExpr, sr); sr.CurrentScopeRegionFlags.PathTagger.LeaveNode(); // // convert right outer to left outer // if (joinClause.JoinKind == JoinKind.RightOuter) { joinClause.JoinKind = JoinKind.LeftOuter; DbExpressionBinding tmpExpr = leftBindingExpr; leftBindingExpr = rightBindingExpr; rightBindingExpr = tmpExpr; } // // Resolve JoinType // DbExpressionKind joinKind = SemanticResolver.MapJoinKind(joinClause.JoinKind); // // Resolve ON // sr.CurrentScopeRegionFlags.IsInsideJoinOnPredicate = true; DbExpression onExpr = null; if (null == joinClause.OnExpr) { if (DbExpressionKind.CrossJoin != joinKind) { onExpr = sr.CmdTree.CreateTrueExpression(); } } else { onExpr = Convert(joinClause.OnExpr, sr); // // ensure expression is typed // SemanticResolver.EnsureIsNotUntypedNull(onExpr, joinClause.OnExpr.ErrCtx); } sr.CurrentScopeRegionFlags.IsInsideJoinOnPredicate = false; // // Create New Join // joinBinding = sr.CmdTree.CreateExpressionBinding( sr.CmdTree.CreateJoinExpressionByKind(joinKind, onExpr, leftBindingExpr, rightBindingExpr), sr.GenerateInternalName("join")); // // Fixup Join Source Vars in Scope // sr.FixupNamedSourceVarBindings(joinBinding.Variable); Debug.Assert(null != joinBinding,"null != joinBinding"); return joinBinding; } /// /// Process apply clause item /// /// /// SemanticResolver instance relative to a especif typespace/system ///private static DbExpressionBinding ProcessApplyClauseItem( ApplyClauseItem applyClause, SemanticResolver sr ) { DbExpressionBinding applyBinding = null; // // Resolve Left Expression // sr.CurrentScopeRegionFlags.PathTagger.VisitLeftNode(); DbExpressionBinding leftBindingExpr = ProcessFromClauseItem(applyClause.LeftExpr, sr); sr.CurrentScopeRegionFlags.PathTagger.LeaveNode(); // // Resolve Right Expression // sr.CurrentScopeRegionFlags.PathTagger.VisitRightNode(); DbExpressionBinding rightBindingExpr = ProcessFromClauseItem(applyClause.RightExpr, sr); sr.CurrentScopeRegionFlags.PathTagger.LeaveNode(); // // Create Apply // applyBinding = sr.CmdTree.CreateExpressionBinding( sr.CmdTree.CreateApplyExpressionByKind(SemanticResolver.MapApplyKind(applyClause.ApplyKind), leftBindingExpr, rightBindingExpr), sr.GenerateInternalName("apply")); // // Fixup Apply Source Vars in Scope // sr.FixupNamedSourceVarBindings(applyBinding.Variable); Debug.Assert(null != applyBinding,"null != applyBinding"); return applyBinding; } /// /// Process Where Expression /// /// /// /// SemanticResolver instance relative to a especif typespace/system ///private static DbExpressionBinding ProcessWhereClause( DbExpressionBinding source, Expr whereClause, SemanticResolver sr ) { if (null == whereClause) { return source; } DbExpressionBinding whereBinding = null; // // Convert Where Condition // DbExpression filterConditionExpr = Convert(whereClause, sr); // // ensure expression is typed // SemanticResolver.EnsureIsNotUntypedNull(filterConditionExpr, whereClause.ErrCtx); // // ensure the predicate type is boolean // if (!TypeResolver.IsBooleanType(filterConditionExpr.ResultType)) { throw EntityUtil.EntitySqlError(whereClause.ErrCtx, System.Data.Entity.Strings.ExpressionTypeMustBeBoolean); } // // Create New Filter Binding // whereBinding = sr.CmdTree.CreateExpressionBinding( sr.CmdTree.CreateFilterExpression(source, filterConditionExpr), sr.GenerateInternalName("where")); // // Fixup Bindings // sr.FixupSourceVarBindings(whereBinding.Variable); Debug.Assert(null != whereBinding,"null != whereBinding"); return whereBinding; } /// /// Process Group By Clause /// /// /// /// SemanticResolver instance relative to a especif typespace/system ///private static DbExpressionBinding ProcessGroupByClause( DbExpressionBinding source, QueryExpr queryExpr, SemanticResolver sr ) { SemanticResolver.ScopeViewKind saveScopeView = sr.GetScopeView(); GroupByClause groupByClause = queryExpr.GroupByClause; Debug.Assert((sr.ParserOptions.ParserCompilationMode == ParserOptions.CompilationMode.RestrictedViewGenerationMode) ? null == groupByClause : true, "GROUP BY clause must be null in RestrictedViewGenerationMode"); // // if group expression is null, create a dummy and speculate that there are group aggregates in the remaining query expression // if no group aggregate if found after partial evaluation of Having, OrderBy and Select in the 1st pass, rollback what we did // and return source expression. // #region Define Implicit Group if needed if (null == queryExpr.GroupByClause) { if (!queryExpr.HasMethodCall) { return source; } // // if group expression is null create a dummy and speculate that there are group aggregates in the remaining query expression // if no group aggregate if found after partial evaluation of Having, OrderBy and Select in the 1st pass, rollback what we did // and return source expression. // sr.CurrentScopeRegionFlags.IsImplicitGroup = true; } else { sr.CurrentScopeRegionFlags.IsImplicitGroup = false; } #endregion DbExpressionBinding groupBinding = null; // // Create Group Binding // DbGroupExpressionBinding groupExprBinding = sr.CmdTree.CreateGroupExpressionBinding( source.Expression, sr.GenerateInternalName("geb"), sr.GenerateInternalName("group")); // // Update source scope vars // sr.FixupGroupSourceVarBindings(groupExprBinding.Variable, groupExprBinding.GroupVariable); // // convert group elements // #region Convert Group Key/Expressions int groupKeysCount = (null != groupByClause ) ? groupByClause.GroupItems.Count : 0; List > groupKeys = new List >(groupKeysCount); HashSet groupKeyNames = new HashSet (sr.ScopeStringComparer); List groupKeysForAggregates = new List (8); if (!sr.CurrentScopeRegionFlags.IsImplicitGroup) { Debug.Assert(null != groupByClause, "groupByClause must not be null at this point"); for (int i = 0 ; i < groupKeysCount ; i++) { AliasExpr aliasedExpr = groupByClause.GroupItems[i]; sr.ResetScopeRegionCorrelationFlag(); // // convert key expression (relative to DbGroupExpressionBinding.Var) // DbExpression converted = Convert(aliasedExpr.Expr, sr); // // ensure expression is typed // SemanticResolver.EnsureIsNotUntypedNull(converted, aliasedExpr.Expr.ErrCtx); // // ensure group key expression is correlated // if (!sr.CurrentScopeRegionFlags.WasResolutionCorrelated) { throw EntityUtil.EntitySqlError(aliasedExpr.Expr.ErrCtx, System.Data.Entity.Strings.KeyMustBeCorrelated("GROUP BY")); } // // convert key expression (relative to DbGroupExpressionBinding.GroupVar) // this is only needed because during the search for groupaggregates, group aggregates may // refer to group keys. // sr.CurrentScopeRegionFlags.IsInsideGroupAggregate = true; DbExpression groupKeyAggExpr = Convert(aliasedExpr.Expr, sr); groupKeysForAggregates.Add(groupKeyAggExpr); sr.CurrentScopeRegionFlags.IsInsideGroupAggregate = false; // // ensure keys are valid // if (!TypeHelpers.IsValidGroupKeyType(converted.ResultType)) { throw EntityUtil.EntitySqlError(aliasedExpr.Expr.ErrCtx, System.Data.Entity.Strings.GroupingKeysMustBeEqualComparable); } // // infer alias name // string groupKeyAlias = sr.InferAliasName(aliasedExpr, converted); // // check if alias was already used // if (groupKeyNames.Contains(groupKeyAlias)) { if (aliasedExpr.HasAlias) { CqlErrorHelper.ReportAliasAlreadyUsedError(groupKeyAlias, aliasedExpr.AliasIdentifier.ErrCtx, System.Data.Entity.Strings.InGroupClause); } else { groupKeyAlias = sr.GenerateInternalName("autoGroup"); } } // // add key name to alias dictionary // groupKeyNames.Add(groupKeyAlias); // // add key to keys collection // groupKeys.Add(new KeyValuePair (groupKeyAlias, converted)); // // group keys should visible by their 'original' key expression name. All forms should be allowed: // SELECT k FROM ... as p GROUP BY p.Price as k (explicit key alias) - handled above by InferAliasName() // SELECT Price FROM ... as p GROUP BY p.Price (implicit alias - leading name) - handled above by InferAliasName() // SELECT p.Price FROM ... as p GROUP BY p.Price (original key expression) - case handled in the code bellow // if (!aliasedExpr.HasAlias) { DotExpr dotExpr = aliasedExpr.Expr as DotExpr; if (null != dotExpr && dotExpr.IsDottedIdentifier) { groupKeyAlias = dotExpr.FullName; if (groupKeyNames.Contains(groupKeyAlias)) { CqlErrorHelper.ReportAliasAlreadyUsedError(groupKeyAlias, dotExpr.ErrCtx, System.Data.Entity.Strings.InGroupClause); } groupKeyNames.Add(groupKeyAlias); groupKeys.Add(new KeyValuePair (groupKeyAlias, converted)); groupKeysForAggregates.Add(groupKeyAggExpr); } } } } #endregion // // save scope status // SavePoint savePoint = sr.CreateSavePoint(); // // Push Group scope // sr.EnterScope(); // // Add converted group variables/expressions to group scope // #region Add Converted Group Variables to Scope // // add 'dummy' keys to scope. // this is needed since during the aggreagate search phase, keys may be referenced. // for (int i = 0 ; i < groupKeys.Count ; i++) { sr.AddDummyGroupKeyToScope(groupKeys[i].Key, groupKeys[i].Value, groupKeysForAggregates[i]); } // // flags that we are inside a group scope // sr.CurrentScopeRegionFlags.IsInGroupScope = true; #endregion // // Convert/Search Aggregates // since aggregates can be defined in Having, OrderBy and/or Select clauses must be resolved as part of the group expression. // The resolution of these clauses result in potential collection of resolved group aggregates and the actual resulting // expression is ignored. These clauses will be then resolved as usual on a second pass. // #region Search for group Aggregates // // search for aggregates in HAVING clause // if (null != queryExpr.HavingClause && queryExpr.HavingClause.HasMethodCall) { sr.CurrentScopeRegionFlags.ResetGroupAggregateNestingCount(); DbExpression converted = Convert(queryExpr.HavingClause.HavingPredicate, sr); // // ensure expression is typed // SemanticResolver.EnsureIsNotUntypedNull(converted, queryExpr.HavingClause.ErrCtx); } // // search for aggregates in SELECT clause // Dictionary sortExpr = null; if ( null != queryExpr.OrderByClause || queryExpr.SelectClause.HasMethodCall ) { sortExpr = new Dictionary (queryExpr.SelectClause.Items.Count, sr.ScopeStringComparer); for ( int i = 0 ; i < queryExpr.SelectClause.Items.Count ; i++ ) { AliasExpr aliasedExpr = queryExpr.SelectClause.Items[i]; // // Reset Group aggregate nesting count // sr.CurrentScopeRegionFlags.ResetGroupAggregateNestingCount(); // // convert projection item expression // DbExpression converted = Convert(aliasedExpr.Expr, sr); // // ensure expression is typed // SemanticResolver.EnsureIsNotUntypedNull(converted, aliasedExpr.Expr.ErrCtx); // // create Null Expression with actual type // converted = sr.CmdTree.CreateNullExpression(converted.ResultType); // // infer alias // string aliasName = sr.InferAliasName(aliasedExpr, converted); if ( sortExpr.ContainsKey(aliasName) ) { if ( aliasedExpr.HasAlias ) { CqlErrorHelper.ReportAliasAlreadyUsedError(aliasName, aliasedExpr.AliasIdentifier.ErrCtx, System.Data.Entity.Strings.InSelectProjectionList); } else { aliasName = sr.GenerateInternalName("autoProject"); } } sortExpr.Add(aliasName, converted); } } // // search for aggregates in ORDER BY clause // if (null != queryExpr.OrderByClause && queryExpr.OrderByClause.HasMethodCall) { // // push projection key scope // sr.EnterScope(); // // Add projection items to scope (it may be used in ORDER BY) // foreach ( KeyValuePair kvp in sortExpr ) { sr.AddToScope(kvp.Key, new ProjectionScopeEntry(kvp.Key, kvp.Value)); } // // search for aggregates in ORDER BY clause // for (int i = 0 ; i < queryExpr.OrderByClause.OrderByClauseItem.Count ; i++) { OrderByClauseItem orderItem = queryExpr.OrderByClause.OrderByClauseItem[i]; sr.CurrentScopeRegionFlags.ResetGroupAggregateNestingCount(); sr.ResetScopeRegionCorrelationFlag(); DbExpression converted = Convert(orderItem.OrderExpr, sr); // // ensure expression is typed // SemanticResolver.EnsureIsNotUntypedNull(converted, orderItem.OrderExpr.ErrCtx); // // ensure key expression is correlated // if (!sr.CurrentScopeRegionFlags.WasResolutionCorrelated) { throw EntityUtil.EntitySqlError(orderItem.ErrCtx, System.Data.Entity.Strings.KeyMustBeCorrelated("ORDER BY")); } } // // pop projection scope // sr.LeaveScope(); } #endregion // // if we introduced a fake group but did not 'found' any group aggregate // on the first pass, then there is no need for creating an implicit group. // rollback to the status before entering ProcessGroupByClause(). // if we did find group aggregates, make sure all non-group aggregate function // expressions refer to group scope variables only // #region Implicit Group Rollback if (sr.CurrentScopeRegionFlags.IsImplicitGroup) { if (0 == sr.CurrentScopeRegionFlags.GroupAggregatesInfo.Count) { // // rolls back scope status // sr.RollbackToSavepoint(savePoint); // // undo any group source fixups, re-applying the source var // sr.UndoFixupGroupSourceVarBindings(source.Variable); // // reset is inside group scope flag // sr.CurrentScopeRegionFlags.IsInGroupScope = false; //// //// reset implict group flag //// sr.CurrentScopeRegionFlags.IsImplicitGroup = false; // // restore scope view kind // sr.SetScopeView(saveScopeView); // // return the original source var binding // return source; } // // now that we know that there are group aggregates in other expression, reset implict group flag to false // since it is now considered a legitimate group // sr.CurrentScopeRegionFlags.IsImplicitGroup = false; } #endregion // // extract list of aggregates and names // List > aggregates = new List >(sr.CurrentScopeRegionFlags.GroupAggregatesInfo.Count); foreach(KeyValuePair kvp in sr.CurrentScopeRegionFlags.GroupAggregatesInfo) { aggregates.Add(new KeyValuePair (kvp.Value.AggregateName, kvp.Value.AggregateExpression)); kvp.Key.ResetDummyExpression(); } // // Create Group Expression // groupBinding = sr.CmdTree.CreateExpressionBinding( sr.CmdTree.CreateGroupByExpression( groupExprBinding, groupKeys, aggregates), sr.GenerateInternalName("group")); // // replace dummy keys with real keys // for (int i = 0 ; i < groupKeys.Count ; i++) { sr.ReplaceGroupVarInScope(groupKeys[i].Key, groupBinding.Variable); } // // add aggregates to scope // for (int i = 0 ; i < aggregates.Count ; i++ ) { sr.CurrentScopeRegionFlags.AddGroupAggregateToScopeFlags(aggregates[i].Key); sr.AddGroupAggregateToScope(aggregates[i].Key, groupBinding.Variable); } // // restrict group scope visibility // sr.SetScopeView(SemanticResolver.ScopeViewKind.GroupScope); // // fixup all source vars // sr.FixupNamedSourceVarBindings(groupBinding.Variable); // // Mark source vars as group input vars // sr.MarkGroupInputVars(); Debug.Assert(null != groupBinding,"null != groupBinding"); return groupBinding; } /// /// Process Having Clause /// /// /// /// SemanticResolver instance relative to a especif typespace/system ///private static DbExpressionBinding ProcessHavingClause( DbExpressionBinding source, HavingClause havingClause, SemanticResolver sr ) { Debug.Assert((sr.ParserOptions.ParserCompilationMode == ParserOptions.CompilationMode.RestrictedViewGenerationMode) ? null == havingClause : true, "HAVING clause must be null in RestrictedViewGenerationMode"); if (null == havingClause) { return source; } DbExpressionBinding havingBinding = null; // // Convert Having Expression // DbExpression filterConditionExpr = Convert(havingClause.HavingPredicate, sr); // // ensure expression is typed // SemanticResolver.EnsureIsNotUntypedNull(filterConditionExpr, havingClause.ErrCtx); // // ensure having predicate of boolean type // if (!TypeResolver.IsBooleanType(filterConditionExpr.ResultType)) { throw EntityUtil.EntitySqlError(havingClause.ErrCtx, System.Data.Entity.Strings.ExpressionTypeMustBeBoolean); } // // Create New Filter Binding // havingBinding = sr.CmdTree.CreateExpressionBinding( sr.CmdTree.CreateFilterExpression(source, filterConditionExpr), sr.GenerateInternalName("having")); // // Fixup Bindings // sr.FixupSourceVarBindings(havingBinding.Variable); Debug.Assert(null != havingBinding,"null != havingBinding"); return havingBinding; } /// /// Process Order By Clause /// /// /// /// SemanticResolver instance relative to a especif typespace/system ///private static DbExpressionBinding ProcessOrderByClause( DbExpressionBinding source, QueryExpr queryExpr, SemanticResolver sr ) { Debug.Assert((sr.ParserOptions.ParserCompilationMode == ParserOptions.CompilationMode.RestrictedViewGenerationMode) ? null == queryExpr.OrderByClause : true, "ORDER BY clause must be null in RestrictedViewGenerationMode"); if (null == queryExpr.OrderByClause) { return source; } DbExpressionBinding sortBinding = null; OrderByClause orderByClause = queryExpr.OrderByClause; SelectClause selectClause = queryExpr.SelectClause; // // Create a savepoint // SavePoint savePoint = sr.CreateSavePoint(); // // perform partial conversion of SELECT statements // Dictionary projectionExpressions = new Dictionary (selectClause.Items.Count, sr.ScopeStringComparer); for (int i = 0 ; i < selectClause.Items.Count ; i++) { AliasExpr aliasedExpr = selectClause.Items[i]; DbExpression converted = Convert(aliasedExpr.Expr, sr); // // ensure expression is typed // SemanticResolver.EnsureIsNotUntypedNull(converted, aliasedExpr.Expr.ErrCtx); // // infer projection alias // string aliasName = sr.InferAliasName(aliasedExpr, converted); if (projectionExpressions.ContainsKey(aliasName)) { if (aliasedExpr.HasAlias) { CqlErrorHelper.ReportAliasAlreadyUsedError(aliasName, aliasedExpr.AliasIdentifier.ErrCtx, System.Data.Entity.Strings.InSelectProjectionList); } else { aliasName = sr.GenerateInternalName("autoProject"); } } projectionExpressions.Add(aliasName, converted); } // // convert paging sub-clauses they if exists before adding projection list to scope // NOTE: TOP, LIMIT and SKIP have nearly the same constraints in M3.2. in the future this is likely to change by allowing // these sub-clauses to have generic expressions. // #region Handles SKIP sub-clause DbExpression skipExpr = null; if (orderByClause.HasSkipSubClause) { skipExpr = Convert(orderByClause.SkipSubClause, sr); // // ensure is not NULL expr // SemanticResolver.EnsureIsNotUntypedNull(skipExpr, orderByClause.SkipSubClause.ErrCtx); DbConstantExpression constantExpr = skipExpr as DbConstantExpression; Debug.Assert(constantExpr!=null || skipExpr is DbParameterReferenceExpression, "SKIP inner expression must be a parameter or numeric literal in this release"); // // ensure SKIP expression have the right type // if (!TypeSemantics.IsPromotableTo(skipExpr.ResultType, sr.TypeResolver.Int64Type)) { throw EntityUtil.EntitySqlError(orderByClause.SkipSubClause.ErrCtx, System.Data.Entity.Strings.PlaceholderExpressionMustBeCompatibleWithEdm64("SKIP", skipExpr.ResultType.EdmType.FullName)); } // // if it is a literal, make sure it has the correct value // if (null != constantExpr && System.Convert.ToInt64(constantExpr.Value, CultureInfo.InvariantCulture) < 0) { throw EntityUtil.EntitySqlError(orderByClause.SkipSubClause.ErrCtx, System.Data.Entity.Strings.PlaceholderExpressionMustBeGreaterThanOrEqualToZero("SKIP")); } } #endregion // // Push scope for projection items // sr.EnterScope(); // // Add projection items to scope // foreach (KeyValuePair kvp in projectionExpressions) { // // if the reference expression is a group aggregate, then there is no need to add to scope // if (!sr.CurrentScopeRegionFlags.ContainsGroupAggregate(kvp.Key)) { sr.AddToScope(kvp.Key, new ProjectionScopeEntry(kvp.Key, kvp.Value)); } } // // save scope view // SemanticResolver.ScopeViewKind saveScopeView = sr.GetScopeView(); // // If DISTICT was especified set visibility to current scope only // if DISTINCT modifier is present, push the projection and distinct expression down bellow // sort/skip expressions // if (selectClause.DistinctKind == DistinctKind.Distinct) { sr.SetScopeView(SemanticResolver.ScopeViewKind.CurrentScope); List > projectionExpressionList = new List >(projectionExpressions); // // Create projection // DbExpression projectExpression; if (selectClause.SelectKind == SelectKind.SelectRow) { projectExpression = sr.CmdTree.CreateNewRowExpression(projectionExpressionList); } else { Debug.Assert(selectClause.Items.Count == 1, "SELECT VALUE must have only one argument"); projectExpression = projectionExpressionList[0].Value; } projectExpression = sr.CmdTree.CreateProjectExpression(source, projectExpression); // // Ensure Projection is valid for DISTINCT modifier // SemanticResolver.ValidateDistinctProjection(selectClause, projectExpression.ResultType); // // create new source binding // source = sr.CmdTree.CreateExpressionBinding(sr.CmdTree.CreateDistinctExpression(projectExpression), sr.GenerateInternalName("distinct")); // // replace Projection scope with new expression bindings // for (int i = 0; i < projectionExpressionList.Count; i++) { if (!sr.CurrentScopeRegionFlags.ContainsGroupAggregate(projectionExpressionList[i].Key)) { // remove old scope var sr.RemoveFromScope(projectionExpressionList[i].Key); // create and add new source var to scope SourceScopeEntry sce = new SourceScopeEntry(ScopeEntryKind.SourceVar, projectionExpressionList[i].Key, source.Variable); if (selectClause.SelectKind == SelectKind.SelectRow) { sce.AddBindingPrefix(projectionExpressionList[i].Key); } sr.AddToScope(projectionExpressionList[i].Key, sce); } } } // // if is not DISTINCT, but is a group scope, then should be the group scope and the // projection list // else if (sr.CurrentScopeRegionFlags.IsInGroupScope) { sr.SetScopeView(SemanticResolver.ScopeViewKind.CurrentAndPreviousScope); } // // convert sort keys // List sortKeys = new List (orderByClause.OrderByClauseItem.Expressions.Count); for (int i = 0 ; i < orderByClause.OrderByClauseItem.Expressions.Count ; i++) { OrderByClauseItem orderClauseItem = orderByClause.OrderByClauseItem.Expressions[i]; sr.CurrentScopeRegionFlags.ResetGroupAggregateNestingCount(); sr.ResetScopeRegionCorrelationFlag(); // // convert order key expression // DbExpression keyExpr = Convert(orderClauseItem.OrderExpr, sr); // // ensure expression is typed // SemanticResolver.EnsureIsNotUntypedNull(keyExpr, orderClauseItem.OrderExpr.ErrCtx); // // ensure key expression is correlated. if group by is present, then the check was already performed // if (!sr.CurrentScopeRegionFlags.WasResolutionCorrelated) { throw EntityUtil.EntitySqlError(orderClauseItem.ErrCtx, System.Data.Entity.Strings.KeyMustBeCorrelated("ORDER BY")); } // // ensure key is order comparable // if (!TypeHelpers.IsValidSortOpKeyType(keyExpr.ResultType)) { throw EntityUtil.EntitySqlError(orderClauseItem.OrderExpr.ErrCtx, System.Data.Entity.Strings.OrderByKeyIsNotOrderComparable); } // // define order // bool ascSort = (orderClauseItem.OrderKind == OrderKind.None) || (orderClauseItem.OrderKind == OrderKind.Asc); // // define collation // string collation = null; if (orderClauseItem.IsCollated) { if (!TypeResolver.IsKeyValidForCollation(keyExpr.ResultType)) { throw EntityUtil.EntitySqlError(orderClauseItem.OrderExpr.ErrCtx, System.Data.Entity.Strings.InvalidKeyTypeForCollation(keyExpr.ResultType.EdmType.FullName)); } collation = orderClauseItem.CollateIdentifier.Name; } // // if orderby has no collation defined, check if a default was given through ParserOptions // else if (sr.ParserOptions.DefaultOrderByCollation.Length > 0 && TypeResolver.IsKeyValidForCollation(keyExpr.ResultType)) { collation = sr.ParserOptions.DefaultOrderByCollation; } // // add keys to key collection // if (string.IsNullOrEmpty(collation)) { sortKeys.Add(sr.CmdTree.CreateSortClause(keyExpr, ascSort)); } else { sortKeys.Add(sr.CmdTree.CreateSortClause(keyExpr, ascSort, collation)); } } DbExpression sortSourceExpr = null; if (orderByClause.HasSkipSubClause) { sortSourceExpr = sr.CmdTree.CreateSkipExpression(source, sortKeys, skipExpr); } else { sortSourceExpr = sr.CmdTree.CreateSortExpression(source, sortKeys); } // // Create Sort Binding // sortBinding = sr.CmdTree.CreateExpressionBinding( sortSourceExpr, sr.GenerateInternalName("sort")); // // Fixup Bindings // sr.FixupSourceVarBindings(sortBinding.Variable); // // pops projection keys from scope // sr.RollbackToSavepoint(savePoint); // // restore scope view // sr.SetScopeView(saveScopeView); Debug.Assert(null != sortBinding,"null != sortBinding"); return sortBinding; } /// /// Converts a list of ast expression nodes /// /// /// SemanticResolver instance relative to a especif typespace/system ///private static PairOfLists ProcessExprList( ExprList astExprList, SemanticResolver sr ) { List types = new List (astExprList.Count); List convertedExprs = new List (astExprList.Count); for (int i = 0 ; i < astExprList.Count ; i++) { DbExpression e = Convert(astExprList[i], sr); types.Add(e.ResultType); convertedExprs.Add(e); } return new PairOfLists (types, convertedExprs); } /// /// [....]: Temporary workaround for 2/3 milestone. /// Convert "x in multiset(y1, y2, ..., yn)" into /// x = y1 or x = y2 or x = y3 ... /// /// semantic resolver /// left-expression (the probe) /// right expression (the collection) ///Or chain of equality comparisons private static DbExpression ConvertSimpleInExpression( SemanticResolver sr, DbExpression left, DbExpression right ) { // Only handle cases when the right-side is a new instance expression Debug.Assert(right.ExpressionKind == DbExpressionKind.NewInstance,"right.ExpressionKind == DbExpressionKind.NewInstance"); DbNewInstanceExpression rightColl = (DbNewInstanceExpression)right; if (rightColl.Arguments.Count == 0) { return sr.CmdTree.CreateConstantExpression(false); } DbExpression orExpr = null; foreach (DbExpression e in rightColl.Arguments) { DbExpression leftClone = (DbExpression)left.Clone(); DbExpression eqExpr = sr.CmdTree.CreateEqualsExpression(leftClone, e); if (orExpr == null) { orExpr = eqExpr; } else { orExpr = sr.CmdTree.CreateOrExpression(orExpr, eqExpr); } } return orExpr; } #region Conversion Delegate Mappings private delegate DbExpression AstExprConverter( Expr astExpr, SemanticResolver sr ); private static readonly Dictionary_astExprConverters = CreateAstExprConverters(); private delegate DbExpression BuiltInExprConverter( BuiltInExpr astBltInExpr, SemanticResolver sr ); private static readonly Dictionary _builtInExprConverter = CreateBuiltInExprConverter(); #region Define converter delegates private static Dictionary CreateAstExprConverters() { const int NumberOfElements = 15; // number of elements initialized by the dictionary Dictionary astExprConverters = new Dictionary (NumberOfElements); astExprConverters.Add(typeof(Literal), new AstExprConverter(ConvertLiteral)); astExprConverters.Add(typeof(Parameter), new AstExprConverter(ConvertParameter)); astExprConverters.Add(typeof(Identifier), new AstExprConverter(ConvertIdentifier)); astExprConverters.Add(typeof(DotExpr), new AstExprConverter(ConvertDotExpr)); astExprConverters.Add(typeof(BuiltInExpr), new AstExprConverter(ConvertBuiltIn)); astExprConverters.Add(typeof(QueryExpr), new AstExprConverter(ConvertQuery)); astExprConverters.Add(typeof(RowConstructorExpr), new AstExprConverter(ConvertRowConstructor)); astExprConverters.Add(typeof(MultisetConstructorExpr), new AstExprConverter(ConvertMultisetConstructor)); astExprConverters.Add(typeof(CaseExpr), new AstExprConverter(ConvertCaseExpr)); astExprConverters.Add(typeof(RelshipNavigationExpr), new AstExprConverter(ConvertRelshipNavigationExpr)); astExprConverters.Add(typeof(RefExpr), new AstExprConverter(ConvertRefExpr)); astExprConverters.Add(typeof(DerefExpr), new AstExprConverter(ConvertDeRefExpr)); astExprConverters.Add(typeof(MethodExpr), new AstExprConverter(ConvertMethodExpr)); astExprConverters.Add(typeof(CreateRefExpr), new AstExprConverter(ConvertCreateRefExpr)); astExprConverters.Add(typeof(KeyExpr), new AstExprConverter(ConvertKeyExpr)); Debug.Assert(NumberOfElements == astExprConverters.Count, "The number of elements and initial capacity don't match"); return astExprConverters; } private static Dictionary CreateBuiltInExprConverter() { Dictionary builtInExprConverter = new Dictionary (sizeof(BuiltInKind)); //////////////////////////// // Arithmetic Expressions //////////////////////////// // // e1 + e2 // #region e1 + e2 builtInExprConverter.Add(BuiltInKind.Plus, delegate( BuiltInExpr bltInExpr, SemanticResolver sr ) { Pair args = ConvertPlusOperands(bltInExpr, sr); if (TypeSemantics.IsNumericType(args.Left.ResultType)) { return sr.CmdTree.CreatePlusExpression(args.Left, args.Right); } else { // // fold '+' operator into concat canonical function // IList functions; if (!sr.TypeResolver.TryGetFunctionFromMetadata("Concat","Edm", true /* ignoreCase */, out functions)) { throw EntityUtil.EntitySqlError(bltInExpr.ErrCtx, System.Data.Entity.Strings.ConcatBuiltinNotSupported); } List argTypes = new List (2); argTypes.Add(args.Left.ResultType); argTypes.Add(args.Right.ResultType); bool isAmbiguous = false; EdmFunction concatFunction = TypeResolver.ResolveFunctionOverloads(functions, argTypes, false /* isGroupAggregate */, out isAmbiguous); if (null == concatFunction || isAmbiguous) { throw EntityUtil.EntitySqlError(bltInExpr.ErrCtx, System.Data.Entity.Strings.ConcatBuiltinNotSupported); } return sr.CmdTree.CreateFunctionExpression(concatFunction, new DbExpression[] { args.Left, args.Right }); } }); #endregion // // e1 - e2 // #region e1 - e2 builtInExprConverter.Add(BuiltInKind.Minus, delegate( BuiltInExpr bltInExpr, SemanticResolver sr ) { Pair args = ConvertArithmeticArgs(bltInExpr, sr); return sr.CmdTree.CreateMinusExpression(args.Left, args.Right); }); #endregion // // e1 * e2 // #region e1 * e2 builtInExprConverter.Add(BuiltInKind.Multiply, delegate( BuiltInExpr bltInExpr, SemanticResolver sr ) { Pair args = ConvertArithmeticArgs(bltInExpr, sr); return sr.CmdTree.CreateMultiplyExpression(args.Left, args.Right); }); #endregion // // e1 / e2 // #region e1 / e2 builtInExprConverter.Add(BuiltInKind.Divide, delegate( BuiltInExpr bltInExpr, SemanticResolver sr ) { Pair args = ConvertArithmeticArgs(bltInExpr, sr); return sr.CmdTree.CreateDivideExpression(args.Left, args.Right); }); #endregion // // e1 % e2 // #region e1 % e2 builtInExprConverter.Add(BuiltInKind.Modulus, delegate( BuiltInExpr bltInExpr, SemanticResolver sr ) { Pair args = ConvertArithmeticArgs(bltInExpr, sr); return sr.CmdTree.CreateModuloExpression(args.Left, args.Right); }); #endregion // // - e // #region - e builtInExprConverter.Add(BuiltInKind.UnaryMinus, delegate( BuiltInExpr bltInExpr, SemanticResolver sr ) { DbExpression unaryExpr = sr.CmdTree.CreateUnaryMinusExpression(ConvertArithmeticArgs(bltInExpr, sr).Left); if (TypeSemantics.IsUnsignedNumericType(unaryExpr.ResultType)) { TypeUsage closestPromotableType = null; if (TypeHelpers.TryGetClosestPromotableType(unaryExpr.ResultType, out closestPromotableType)) { unaryExpr = sr.CmdTree.CreateCastExpression(unaryExpr, closestPromotableType); } else { throw EntityUtil.EntitySqlError(System.Data.Entity.Strings.InvalidUnsignedTypeForUnaryMinusOperation(unaryExpr.ResultType.EdmType.FullName)); } } return unaryExpr; }); #endregion // // + e // #region + e builtInExprConverter.Add(BuiltInKind.UnaryPlus, delegate( BuiltInExpr bltInExpr, SemanticResolver sr ) { return ConvertArithmeticArgs(bltInExpr, sr).Left; }); #endregion //////////////////////////// // Logical Expressions //////////////////////////// // // e1 AND e2 // e1 && e2 // #region e1 AND e2 builtInExprConverter.Add(BuiltInKind.And, delegate( BuiltInExpr bltInExpr, SemanticResolver sr ) { Pair args = SemanticAnalyzer.ConvertLogicalArgs(bltInExpr, sr); return sr.CmdTree.CreateAndExpression(args.Left, args.Right); }); #endregion // // e1 OR e2 // e1 || e2 // #region e1 OR e2 builtInExprConverter.Add(BuiltInKind.Or, delegate( BuiltInExpr bltInExpr, SemanticResolver sr ) { Pair args = SemanticAnalyzer.ConvertLogicalArgs(bltInExpr, sr); return sr.CmdTree.CreateOrExpression(args.Left, args.Right); }); #endregion // // NOT e // ! e // #region NOT e builtInExprConverter.Add(BuiltInKind.Not, delegate( BuiltInExpr bltInExpr, SemanticResolver sr ) { return sr.CmdTree.CreateNotExpression(ConvertLogicalArgs(bltInExpr, sr).Left); }); #endregion //////////////////////////// // Comparison Expressions //////////////////////////// // // e1 == e2 | e1 = e2 // #region e1 == e2 builtInExprConverter.Add(BuiltInKind.Equal, delegate( BuiltInExpr bltInExpr, SemanticResolver sr ) { Pair args = ConvertEqualCompArgs(bltInExpr, sr); return sr.CmdTree.CreateEqualsExpression(args.Left, args.Right); }); #endregion // // e1 != e2 | e1 <> e2 // #region e1 != e2 builtInExprConverter.Add(BuiltInKind.NotEqual, delegate( BuiltInExpr bltInExpr, SemanticResolver sr ) { Pair args = ConvertEqualCompArgs(bltInExpr, sr); return sr.CmdTree.CreateNotExpression( sr.CmdTree.CreateEqualsExpression(args.Left, args.Right)); }); #endregion // // e1 >= e2 // #region e1 >= e2 builtInExprConverter.Add(BuiltInKind.GreaterEqual, delegate( BuiltInExpr bltInExpr, SemanticResolver sr ) { Pair args = ConvertOrderCompArgs(bltInExpr, sr); return sr.CmdTree.CreateGreaterThanOrEqualsExpression(args.Left, args.Right); }); #endregion // // e1 > e2 // #region e1 > e2 builtInExprConverter.Add(BuiltInKind.GreaterThan, delegate( BuiltInExpr bltInExpr, SemanticResolver sr ) { Pair args = ConvertOrderCompArgs(bltInExpr, sr); return sr.CmdTree.CreateGreaterThanExpression(args.Left, args.Right); }); #endregion // // e1 <= e2 // #region e1 <= e2 builtInExprConverter.Add(BuiltInKind.LessEqual, delegate( BuiltInExpr bltInExpr, SemanticResolver sr ) { Pair args = ConvertOrderCompArgs(bltInExpr, sr); return sr.CmdTree.CreateLessThanOrEqualsExpression(args.Left, args.Right); }); #endregion // // e1 < e2 // #region e1 < e2 builtInExprConverter.Add(BuiltInKind.LessThan, delegate( BuiltInExpr bltInExpr, SemanticResolver sr ) { Pair args = ConvertOrderCompArgs(bltInExpr, sr); return sr.CmdTree.CreateLessThanExpression(args.Left, args.Right); }); #endregion //////////////////////////// // SET EXPRESSIONS //////////////////////////// // // e1 UNION e2 // #region e1 UNION e2 builtInExprConverter.Add(BuiltInKind.Union, delegate( BuiltInExpr bltInExpr, SemanticResolver sr ) { Pair args = ConvertSetArgs(bltInExpr, sr); return sr.CmdTree.CreateDistinctExpression(sr.CmdTree.CreateUnionAllExpression(args.Left, args.Right)); }); #endregion // // e1 UNION ALL e2 // #region e1 UNION ALL e2 builtInExprConverter.Add(BuiltInKind.UnionAll, delegate( BuiltInExpr bltInExpr, SemanticResolver sr ) { Pair args = ConvertSetArgs(bltInExpr, sr); return sr.CmdTree.CreateUnionAllExpression(args.Left, args.Right); }); #endregion // // e1 INTERSECT e2 // #region e1 INTERSECT e2 builtInExprConverter.Add(BuiltInKind.Intersect, delegate( BuiltInExpr bltInExpr, SemanticResolver sr ) { Pair args = ConvertSetArgs(bltInExpr, sr); return sr.CmdTree.CreateIntersectExpression(args.Left, args.Right); }); #endregion // // e1 OVERLAPS e2 // #region e1 OVERLAPS e1 builtInExprConverter.Add(BuiltInKind.Overlaps, delegate( BuiltInExpr bltInExpr, SemanticResolver sr ) { Pair args = ConvertSetArgs(bltInExpr, sr); return sr.CmdTree.CreateNotExpression( sr.CmdTree.CreateIsEmptyExpression( sr.CmdTree.CreateIntersectExpression(args.Left, args.Right))); }); #endregion // // ANYELEMENT( e ) // #region ANYELEMENT( e ) builtInExprConverter.Add(BuiltInKind.AnyElement, delegate( BuiltInExpr bltInExpr, SemanticResolver sr ) { return sr.CmdTree.CreateElementExpression(ConvertSetArgs(bltInExpr, sr).Left); }); #endregion // // ELEMENT( e ) // #region ELEMENT( e ) - NOT SUPPORTED IN ORCAS TIMEFRAME builtInExprConverter.Add(BuiltInKind.Element, delegate( BuiltInExpr bltInExpr, SemanticResolver sr ) { throw EntityUtil.NotSupported(System.Data.Entity.Strings.ElementOperatorIsNotSupported); }); #endregion // // e1 EXCEPT e2 // #region e1 EXCEPT e2 builtInExprConverter.Add(BuiltInKind.Except, delegate( BuiltInExpr bltInExpr, SemanticResolver sr ) { Pair args = ConvertSetArgs(bltInExpr, sr); return sr.CmdTree.CreateExceptExpression(args.Left, args.Right); }); #endregion // // EXISTS( e ) // #region EXISTS( e ) builtInExprConverter.Add(BuiltInKind.Exists, delegate( BuiltInExpr bltInExpr, SemanticResolver sr ) { return sr.CmdTree.CreateNotExpression( sr.CmdTree.CreateIsEmptyExpression(ConvertSetArgs(bltInExpr, sr).Left)); }); #endregion // // FLATTEN( e ) // #region FLATTEN( e ) builtInExprConverter.Add(BuiltInKind.Flatten, delegate( BuiltInExpr bltInExpr, SemanticResolver sr ) { DbExpression elemExpr = Convert(bltInExpr.Arg1, sr); if (!TypeSemantics.IsCollectionType(elemExpr.ResultType)) { throw EntityUtil.EntitySqlError(bltInExpr.Arg1.ErrCtx, System.Data.Entity.Strings.InvalidFlattenArgument); } if (!TypeSemantics.IsCollectionType(TypeHelpers.GetElementTypeUsage(elemExpr.ResultType))) { throw EntityUtil.EntitySqlError(bltInExpr.Arg1.ErrCtx, System.Data.Entity.Strings.InvalidFlattenArgument); } DbExpressionBinding leftExpr = sr.CmdTree.CreateExpressionBinding(elemExpr, sr.GenerateInternalName("l_flatten")); DbExpressionBinding rightExpr = sr.CmdTree.CreateExpressionBinding(leftExpr.Variable, sr.GenerateInternalName("r_flatten")); DbExpressionBinding applyBinding = sr.CmdTree.CreateExpressionBinding( sr.CmdTree.CreateCrossApplyExpression(leftExpr, rightExpr), sr.GenerateInternalName("flatten")); return sr.CmdTree.CreateProjectExpression(applyBinding, sr.CmdTree.CreatePropertyExpression(rightExpr.VariableName, applyBinding.Variable)); }); #endregion // // e1 IN e2 // #region e1 IN e2 builtInExprConverter.Add(BuiltInKind.In, delegate( BuiltInExpr bltInExpr, SemanticResolver sr ) { Pair args = ConvertInExprArgs(bltInExpr, sr); // [....]: Temporary workaround for 2/3 milestone. // Convert "x in multiset(y1, y2, ..., yn)" into // x = y1 or x = y2 or x = y3 ... // if (args.Right.ExpressionKind == DbExpressionKind.NewInstance) { return ConvertSimpleInExpression(sr, args.Left, args.Right); } else { DbExpressionBinding rSet = sr.CmdTree.CreateExpressionBinding(args.Right, sr.GenerateInternalName("in-filter")); DbExpression leftIn = args.Left; DbExpression rightSet = rSet.Variable; DbExpression exists = sr.CmdTree.CreateNotExpression( sr.CmdTree.CreateIsEmptyExpression( sr.CmdTree.CreateFilterExpression( rSet, sr.CmdTree.CreateEqualsExpression(leftIn, rightSet)))); List whenExpr = new List (1); whenExpr.Add(sr.CmdTree.CreateIsNullExpression(leftIn)); List thenExpr = new List (1); thenExpr.Add(sr.CmdTree.CreateNullExpression(sr.TypeResolver.BooleanType)); DbExpression left = sr.CmdTree.CreateCaseExpression( whenExpr, thenExpr, sr.CmdTree.CreateFalseExpression()); DbExpression converted = sr.CmdTree.CreateOrExpression(left, exists); return converted; } }); #endregion // // e1 NOT IN e1 // #region e1 NOT IN e1 builtInExprConverter.Add(BuiltInKind.NotIn, delegate( BuiltInExpr bltInExpr, SemanticResolver sr ) { Pair args = ConvertInExprArgs(bltInExpr, sr); if (args.Right.ExpressionKind == DbExpressionKind.NewInstance) { return sr.CmdTree.CreateNotExpression( ConvertSimpleInExpression(sr, args.Left, args.Right)); } else { DbExpressionBinding rSet = sr.CmdTree.CreateExpressionBinding(args.Right, sr.GenerateInternalName("in-filter")); DbExpression leftIn = args.Left; DbExpression rightSet = rSet.Variable; DbExpression exists = sr.CmdTree.CreateIsEmptyExpression( sr.CmdTree.CreateFilterExpression( rSet, sr.CmdTree.CreateEqualsExpression(leftIn, rightSet))); List whenExpr = new List (1); whenExpr.Add(sr.CmdTree.CreateIsNullExpression(leftIn)); List thenExpr = new List (1); thenExpr.Add(sr.CmdTree.CreateNullExpression(sr.TypeResolver.BooleanType)); DbExpression left = sr.CmdTree.CreateCaseExpression( whenExpr, thenExpr, sr.CmdTree.CreateTrueExpression()); DbExpression converted = sr.CmdTree.CreateAndExpression(left, exists); return converted; } }); #endregion // // SET( e ) - DISTINCT( e ) before // #region SET( e ) builtInExprConverter.Add(BuiltInKind.Distinct, delegate( BuiltInExpr bltInExpr, SemanticResolver sr ) { Pair args = ConvertSetArgs(bltInExpr, sr); return sr.CmdTree.CreateDistinctExpression(args.Left); }); #endregion //////////////////////////// // Nullabity Expressions //////////////////////////// // // e IS NULL // #region e IS NULL builtInExprConverter.Add(BuiltInKind.IsNull, delegate(BuiltInExpr bltInExpr, SemanticResolver sr) { DbExpression isNullExpr = Convert(bltInExpr.Arg1, sr); // // ensure expression type is valid for this operation // if (!TypeHelpers.IsValidIsNullOpType(isNullExpr.ResultType)) { throw EntityUtil.EntitySqlError(bltInExpr.Arg1.ErrCtx, System.Data.Entity.Strings.IsNullInvalidType); } return SemanticResolver.IsNullExpression(isNullExpr) ? sr.CmdTree.CreateTrueExpression() : (DbExpression)sr.CmdTree.CreateIsNullExpression(isNullExpr); }); #endregion // // e IS NOT NULL // #region e IS NOT NULL builtInExprConverter.Add(BuiltInKind.IsNotNull, delegate(BuiltInExpr bltInExpr, SemanticResolver sr) { DbExpression isNullExpr = Convert(bltInExpr.Arg1, sr); // // ensure expression type is valid for this operation // if (!TypeHelpers.IsValidIsNullOpType(isNullExpr.ResultType)) { throw EntityUtil.EntitySqlError(bltInExpr.Arg1.ErrCtx, System.Data.Entity.Strings.IsNullInvalidType); } isNullExpr = SemanticResolver.IsNullExpression(isNullExpr) ? sr.CmdTree.CreateTrueExpression() : (DbExpression)sr.CmdTree.CreateIsNullExpression(isNullExpr); return sr.CmdTree.CreateNotExpression(isNullExpr); }); #endregion //////////////////////////// // Type Expressions //////////////////////////// // // e IS OF ( [ONLY] T ) // #region e IS OF ( [ONLY] T ) builtInExprConverter.Add(BuiltInKind.IsOf, delegate(BuiltInExpr bltInExpr, SemanticResolver sr) { Pair args = ConvertTypeExprArgs(bltInExpr, sr); bool isOnly = (bool)((Literal)bltInExpr.ArgList[2]).Value; bool isNot = (bool)((Literal)bltInExpr.ArgList[3]).Value; bool isNominalTypeAllowed = sr.ParserOptions.ParserCompilationMode == ParserOptions.CompilationMode.RestrictedViewGenerationMode; if (TypeSemantics.IsNullType(args.Left.ResultType)) { throw EntityUtil.EntitySqlError(bltInExpr.Arg1.ErrCtx, System.Data.Entity.Strings.ExpressionCannotBeNull); } if (!isNominalTypeAllowed && !TypeSemantics.IsEntityType(args.Left.ResultType)) { throw EntityUtil.EntitySqlError(bltInExpr.Arg1.ErrCtx, System.Data.Entity.Strings.ExpressionTypeMustBeEntityType(System.Data.Entity.Strings.CtxIsOf, args.Left.ResultType.EdmType.BuiltInTypeKind.ToString(), args.Left.ResultType.EdmType.FullName)); } else if (isNominalTypeAllowed && !TypeSemantics.IsNominalType(args.Left.ResultType)) { throw EntityUtil.EntitySqlError(bltInExpr.Arg1.ErrCtx, System.Data.Entity.Strings.ExpressionTypeMustBeNominalType(System.Data.Entity.Strings.CtxIsOf, args.Left.ResultType.EdmType.BuiltInTypeKind.ToString(), args.Left.ResultType.EdmType.FullName)); } if (!isNominalTypeAllowed && !TypeSemantics.IsEntityType(args.Right)) { throw EntityUtil.EntitySqlError(bltInExpr.Arg2.ErrCtx, System.Data.Entity.Strings.TypeMustBeEntityType(System.Data.Entity.Strings.CtxIsOf, args.Right.EdmType.BuiltInTypeKind.ToString(), args.Right.EdmType.FullName)); } else if (isNominalTypeAllowed && !TypeSemantics.IsNominalType(args.Right)) { throw EntityUtil.EntitySqlError(bltInExpr.Arg2.ErrCtx, System.Data.Entity.Strings.TypeMustBeNominalType(System.Data.Entity.Strings.CtxIsOf, args.Right.EdmType.BuiltInTypeKind.ToString(), args.Right.EdmType.FullName)); } if (!TypeSemantics.IsPolymorphicType(args.Left.ResultType)) { throw EntityUtil.EntitySqlError(bltInExpr.Arg1.ErrCtx, System.Data.Entity.Strings.TypeMustBeInheritableType); } if (!TypeSemantics.IsPolymorphicType(args.Right)) { throw EntityUtil.EntitySqlError(bltInExpr.Arg2.ErrCtx, System.Data.Entity.Strings.TypeMustBeInheritableType); } if (!TypeResolver.IsSubOrSuperType(args.Left.ResultType, args.Right)) { throw EntityUtil.EntitySqlError(bltInExpr.ErrCtx, System.Data.Entity.Strings.NotASuperOrSubType(args.Left.ResultType.EdmType.FullName, args.Right.EdmType.FullName)); } args.Right = TypeHelpers.GetReadOnlyType(args.Right); DbExpression retExpr = null; if (isOnly) { retExpr = sr.CmdTree.CreateIsOfOnlyExpression(args.Left, args.Right); } else { retExpr = sr.CmdTree.CreateIsOfExpression(args.Left, args.Right); } if (isNot) { retExpr = sr.CmdTree.CreateNotExpression(retExpr); } return retExpr; }); #endregion // // TREAT( e as T ) // #region TREAT( e as T ) builtInExprConverter.Add(BuiltInKind.Treat, delegate( BuiltInExpr bltInExpr, SemanticResolver sr ) { Pair args = ConvertTypeExprArgs(bltInExpr, sr); bool isNominalTypeAllowed = sr.ParserOptions.ParserCompilationMode == ParserOptions.CompilationMode.RestrictedViewGenerationMode; if (!isNominalTypeAllowed && !TypeSemantics.IsEntityType(args.Right)) { throw EntityUtil.EntitySqlError(bltInExpr.Arg2.ErrCtx, System.Data.Entity.Strings.TypeMustBeEntityType(System.Data.Entity.Strings.CtxTreat, args.Right.EdmType.BuiltInTypeKind.ToString(), args.Right.EdmType.FullName)); } else if (isNominalTypeAllowed && !TypeSemantics.IsNominalType(args.Right)) { throw EntityUtil.EntitySqlError(bltInExpr.Arg2.ErrCtx, System.Data.Entity.Strings.TypeMustBeNominalType(System.Data.Entity.Strings.CtxTreat, args.Right.EdmType.BuiltInTypeKind.ToString(), args.Right.EdmType.FullName)); } if (TypeSemantics.IsNullType(args.Left.ResultType)) { args.Left = sr.CmdTree.CreateNullExpression(args.Right); } else if (!isNominalTypeAllowed && !TypeSemantics.IsEntityType(args.Left.ResultType)) { throw EntityUtil.EntitySqlError(bltInExpr.Arg1.ErrCtx, System.Data.Entity.Strings.ExpressionTypeMustBeEntityType(System.Data.Entity.Strings.CtxTreat, args.Left.ResultType.EdmType.BuiltInTypeKind.ToString(), args.Left.ResultType.EdmType.FullName)); } else if (isNominalTypeAllowed && !TypeSemantics.IsNominalType(args.Left.ResultType)) { throw EntityUtil.EntitySqlError(bltInExpr.Arg1.ErrCtx, System.Data.Entity.Strings.ExpressionTypeMustBeNominalType(System.Data.Entity.Strings.CtxTreat, args.Left.ResultType.EdmType.BuiltInTypeKind.ToString(), args.Left.ResultType.EdmType.FullName)); } if (!TypeSemantics.IsPolymorphicType(args.Left.ResultType)) { throw EntityUtil.EntitySqlError(bltInExpr.Arg1.ErrCtx, System.Data.Entity.Strings.TypeMustBeInheritableType); } if (!TypeSemantics.IsPolymorphicType(args.Right)) { throw EntityUtil.EntitySqlError(bltInExpr.Arg2.ErrCtx, System.Data.Entity.Strings.TypeMustBeInheritableType); } if (!TypeResolver.IsSubOrSuperType(args.Left.ResultType, args.Right)) { throw EntityUtil.EntitySqlError(bltInExpr.Arg1.ErrCtx, System.Data.Entity.Strings.NotASuperOrSubType(args.Left.ResultType.EdmType.FullName, args.Right.EdmType.FullName)); } return sr.CmdTree.CreateTreatExpression(args.Left, TypeHelpers.GetReadOnlyType(args.Right)); }); #endregion // // CAST( e AS T ) // #region CAST( e AS T ) builtInExprConverter.Add(BuiltInKind.Cast, delegate( BuiltInExpr bltInExpr, SemanticResolver sr ) { Pair args = ConvertTypeExprArgs(bltInExpr, sr); // // ensure CAST target type is Scalar // if (!TypeSemantics.IsPrimitiveType(args.Right)) { throw EntityUtil.EntitySqlError(bltInExpr.Arg2.ErrCtx, System.Data.Entity.Strings.InvalidCastType); } if (SemanticResolver.IsNullExpression(args.Left)) { return sr.CmdTree.CreateCastExpression( sr.CmdTree.CreateNullExpression(args.Right), args.Right); } if (args.Left.ResultType.BuiltInTypeKind != BuiltInTypeKind.EnumType) { if (!TypeSemantics.IsPrimitiveType(args.Left.ResultType)) { throw EntityUtil.EntitySqlError(bltInExpr.Arg1.ErrCtx, System.Data.Entity.Strings.InvalidCastExpressionType); } if (!TypeSemantics.IsCastAllowed(args.Left.ResultType, args.Right)) { throw EntityUtil.EntitySqlError(bltInExpr.Arg1.ErrCtx, System.Data.Entity.Strings.InvalidCast( args.Left.ResultType.EdmType, args.Right.EdmType.FullName)); } } return sr.CmdTree.CreateCastExpression(args.Left, TypeHelpers.GetReadOnlyType(args.Right)); }); #endregion // // OFTYPE( [ONLY] e, T ) // #region OFTYPE( [ONLY] e, T ) builtInExprConverter.Add(BuiltInKind.OfType, delegate(BuiltInExpr bltInExpr, SemanticResolver sr) { Pair args = ConvertTypeExprArgs(bltInExpr, sr); bool isOnly = (bool)((Literal)bltInExpr.ArgList[2]).Value; bool isNominalTypeAllowed = sr.ParserOptions.ParserCompilationMode == ParserOptions.CompilationMode.RestrictedViewGenerationMode; if (!TypeSemantics.IsCollectionType(args.Left.ResultType)) { throw EntityUtil.EntitySqlError(bltInExpr.Arg1.ErrCtx, System.Data.Entity.Strings.ExpressionMustBeCollection); } TypeUsage elementType = TypeHelpers.GetElementTypeUsage(args.Left.ResultType); if (!isNominalTypeAllowed && !TypeSemantics.IsEntityType(elementType)) { throw EntityUtil.EntitySqlError(bltInExpr.Arg1.ErrCtx, System.Data.Entity.Strings.OfTypeExpressionElementTypeMustBeEntityType(elementType.EdmType.BuiltInTypeKind.ToString(), elementType)); } else if (isNominalTypeAllowed && !TypeSemantics.IsNominalType(elementType)) { throw EntityUtil.EntitySqlError(bltInExpr.Arg1.ErrCtx, System.Data.Entity.Strings.OfTypeExpressionElementTypeMustBeNominalType(elementType.EdmType.BuiltInTypeKind.ToString(), elementType)); } if (!isNominalTypeAllowed && !TypeSemantics.IsEntityType(args.Right)) { throw EntityUtil.EntitySqlError(bltInExpr.Arg2.ErrCtx, System.Data.Entity.Strings.TypeMustBeEntityType(System.Data.Entity.Strings.CtxOfType, args.Right.EdmType.BuiltInTypeKind.ToString(), args.Right.EdmType.FullName)); } else if (isNominalTypeAllowed && !TypeSemantics.IsNominalType(args.Right)) { throw EntityUtil.EntitySqlError(bltInExpr.Arg2.ErrCtx, System.Data.Entity.Strings.TypeMustBeNominalType(System.Data.Entity.Strings.CtxOfType, args.Right.EdmType.BuiltInTypeKind.ToString(), args.Right.EdmType.FullName)); } if (isOnly && args.Right.EdmType.Abstract) { throw EntityUtil.EntitySqlError(bltInExpr.Arg2.ErrCtx, System.Data.Entity.Strings.OfTypeOnlyTypeArgumentCannotBeAbstract(args.Right.EdmType.FullName)); } if (!TypeResolver.IsSubOrSuperType(elementType, args.Right)) { throw EntityUtil.EntitySqlError(bltInExpr.Arg1.ErrCtx, System.Data.Entity.Strings.NotASuperOrSubType(elementType.EdmType.FullName, args.Right.EdmType.FullName)); } DbExpression ofTypeExpression = null; if (isOnly) { ofTypeExpression = sr.CmdTree.CreateOfTypeOnlyExpression(args.Left, TypeHelpers.GetReadOnlyType(args.Right)); } else { ofTypeExpression = sr.CmdTree.CreateOfTypeExpression(args.Left, TypeHelpers.GetReadOnlyType(args.Right)); } return ofTypeExpression; }); #endregion // // e LIKE pattern [ESCAPE escape] // #region e LIKE pattern [ESCAPE escape] builtInExprConverter.Add(BuiltInKind.Like, delegate( BuiltInExpr bltInExpr, SemanticResolver sr ) { DbExpression likeExpr = null; DbExpression matchExpr = Convert(bltInExpr.Arg1, sr); if (TypeSemantics.IsNullType(matchExpr.ResultType)) { matchExpr = sr.CmdTree.CreateNullExpression(sr.TypeResolver.StringType); } else if (!TypeResolver.IsStringType(matchExpr.ResultType)) { throw EntityUtil.EntitySqlError(bltInExpr.Arg1.ErrCtx, System.Data.Entity.Strings.LikeArgMustBeStringType); } DbExpression patternExpr = Convert(bltInExpr.Arg2, sr); if (patternExpr is UntypedNullExpression) { patternExpr = sr.CmdTree.CreateNullExpression(sr.TypeResolver.StringType); } else if (!TypeResolver.IsStringType(patternExpr.ResultType)) { throw EntityUtil.EntitySqlError(bltInExpr.Arg2.ErrCtx, System.Data.Entity.Strings.LikeArgMustBeStringType); } if (3 == bltInExpr.ArgCount) { DbExpression escapeExpr = Convert(bltInExpr.ArgList[2], sr); if (escapeExpr is UntypedNullExpression) { escapeExpr = sr.CmdTree.CreateNullExpression(sr.TypeResolver.StringType); } else if (!TypeResolver.IsStringType(escapeExpr.ResultType)) { throw EntityUtil.EntitySqlError(bltInExpr.ArgList[2].ErrCtx, System.Data.Entity.Strings.LikeArgMustBeStringType); } likeExpr = sr.CmdTree.CreateLikeExpression(matchExpr, patternExpr, escapeExpr); } else { likeExpr = sr.CmdTree.CreateLikeExpression(matchExpr, patternExpr); } return likeExpr; }); #endregion // // e BETWEEN e1 AND e2 // #region e BETWEEN e1 AND e2 builtInExprConverter.Add(BuiltInKind.Between, delegate( BuiltInExpr bltInExpr, SemanticResolver sr ) { Debug.Assert(bltInExpr.ArgCount == 3); // // convert lower and upper limits // Pair limitsExpr = sr.EnsureTypedNulls( Convert(bltInExpr.ArgList[1], sr), Convert(bltInExpr.ArgList[2], sr), bltInExpr.ArgList[0].ErrCtx, () => Strings.BetweenLimitsCannotBeUntypedNulls); // // Get and check common type for limits // TypeUsage rangeCommonType = TypeHelpers.GetCommonTypeUsage(limitsExpr.Left.ResultType, limitsExpr.Right.ResultType); if (null == rangeCommonType) { throw EntityUtil.EntitySqlError(bltInExpr.ArgList[0].ErrCtx, System.Data.Entity.Strings.BetweenLimitsTypesAreNotCompatible(limitsExpr.Left.ResultType.EdmType.FullName, limitsExpr.Right.ResultType.EdmType.FullName)); } // // check if limit types are order-comp // if (!TypeSemantics.IsOrderComparableTo(limitsExpr.Left.ResultType, limitsExpr.Right.ResultType)) { throw EntityUtil.EntitySqlError(bltInExpr.ArgList[0].ErrCtx, System.Data.Entity.Strings.BetweenLimitsTypesAreNotOrderComparable(limitsExpr.Left.ResultType.EdmType.FullName, limitsExpr.Right.ResultType.EdmType.FullName)); } // // convert value expression // DbExpression valueExpr = Convert(bltInExpr.ArgList[0], sr); // // Fixup value type if untyped // if (TypeSemantics.IsNullType(valueExpr.ResultType)) { valueExpr = sr.CmdTree.CreateNullExpression(rangeCommonType); } // // check if valueExpr is order-comparable to limits // if (!TypeSemantics.IsOrderComparableTo(valueExpr.ResultType, rangeCommonType)) { throw EntityUtil.EntitySqlError(bltInExpr.ArgList[0].ErrCtx, System.Data.Entity.Strings.BetweenValueIsNotOrderComparable(valueExpr.ResultType.EdmType.FullName, rangeCommonType.EdmType.FullName)); } return sr.CmdTree.CreateAndExpression( sr.CmdTree.CreateGreaterThanOrEqualsExpression(valueExpr, limitsExpr.Left), sr.CmdTree.CreateLessThanOrEqualsExpression(valueExpr, limitsExpr.Right)); }); #endregion // // e NOT BETWEEN e1 AND e2 // #region e NOT BETWEEN e1 AND e2 builtInExprConverter.Add(BuiltInKind.NotBetween, delegate( BuiltInExpr bltInExpr, SemanticResolver sr ) { bltInExpr.Kind = BuiltInKind.Between; DbExpression converted = sr.CmdTree.CreateNotExpression(ConvertBuiltIn(bltInExpr, sr)); bltInExpr.Kind = BuiltInKind.NotBetween; return converted; }); #endregion return builtInExprConverter; } #endregion #endregion } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007.
Link Menu
This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- UmAlQuraCalendar.cs
- DataGridViewButtonColumn.cs
- DataGridRow.cs
- TextMarkerSource.cs
- UserNameSecurityTokenProvider.cs
- ToolboxItemFilterAttribute.cs
- Accessible.cs
- DynamicILGenerator.cs
- ObservableDictionary.cs
- DBSqlParser.cs
- PerformanceCounterLib.cs
- CodeMemberMethod.cs
- ProfileEventArgs.cs
- MetadataPropertyCollection.cs
- CaretElement.cs
- CompatibleIComparer.cs
- HwndMouseInputProvider.cs
- XmlSchema.cs
- ToolStripMenuItemCodeDomSerializer.cs
- LayoutEvent.cs
- TheQuery.cs
- AssemblyInfo.cs
- SafeProcessHandle.cs
- StylusButtonEventArgs.cs
- _SslSessionsCache.cs
- FlowDocumentScrollViewerAutomationPeer.cs
- RSACryptoServiceProvider.cs
- Stroke.cs
- Menu.cs
- Reference.cs
- LocalizabilityAttribute.cs
- Vector.cs
- externdll.cs
- UniqueIdentifierService.cs
- Compress.cs
- WriteFileContext.cs
- UnaryExpression.cs
- HtmlInputHidden.cs
- HexParser.cs
- PlacementWorkspace.cs
- UIElementHelper.cs
- XmlAnyAttributeAttribute.cs
- StringInfo.cs
- IntMinMaxAggregationOperator.cs
- Token.cs
- LingerOption.cs
- StateWorkerRequest.cs
- ParallelTimeline.cs
- LoginUtil.cs
- HtmlPageAdapter.cs
- Compiler.cs
- ReadOnlyTernaryTree.cs
- PkcsUtils.cs
- XPathCompileException.cs
- GridViewColumnCollection.cs
- XmlSchemaAttributeGroup.cs
- XmlParser.cs
- ExitEventArgs.cs
- ReferenceSchema.cs
- StateWorkerRequest.cs
- AssociationTypeEmitter.cs
- EdmType.cs
- basecomparevalidator.cs
- MailAddress.cs
- AmbiguousMatchException.cs
- IndicShape.cs
- ApplicationBuildProvider.cs
- WpfPayload.cs
- BevelBitmapEffect.cs
- DataFormats.cs
- ObjectItemCollectionAssemblyCacheEntry.cs
- DecimalFormatter.cs
- FontStyles.cs
- Freezable.cs
- ConfigurationManagerHelperFactory.cs
- IisTraceListener.cs
- XmlSchemaInfo.cs
- CommonObjectSecurity.cs
- MatcherBuilder.cs
- RecognizerBase.cs
- ThreadAttributes.cs
- ResourceContainerWrapper.cs
- WindowsAuthenticationEventArgs.cs
- DataRelation.cs
- SqlMetaData.cs
- XamlStyleSerializer.cs
- PriorityQueue.cs
- ResourceDisplayNameAttribute.cs
- ProfileManager.cs
- BitmapSourceSafeMILHandle.cs
- FileUpload.cs
- FullTextLine.cs
- ImpersonateTokenRef.cs
- EntityContainer.cs
- ParallelQuery.cs
- DocumentSequence.cs
- ImpersonationContext.cs
- QueryableDataSourceView.cs
- ProxyRpc.cs
- PointHitTestResult.cs