internal static void AssertEdmType(TypeUsage typeUsage) { EdmType edmType = typeUsage.EdmType; if (TypeSemantics.IsCollectionType(typeUsage)) { return; } if (TypeSemantics.IsStructuralType(typeUsage) && !Helper.IsComplexType(typeUsage.EdmType) && !Helper.IsEntityType(typeUsage.EdmType)) { foreach (EdmMember structuralMember in TypeHelpers.GetDeclaredStructuralMembers(typeUsage)) { ; } } else { if (!TypeSemantics.IsPrimitiveType(typeUsage)) { return; } PrimitiveType primitiveType = edmType as PrimitiveType; if (primitiveType != null && primitiveType.DataSpace != DataSpace.CSpace) { throw new NotSupportedException(string.Format((IFormatProvider)CultureInfo.InvariantCulture, "PrimitiveType must be CSpace '{0}'", (object)typeUsage)); } } }
private DbExpression GenerateScalarResultMappingView(DbExpression storeFunctionInvoke) { DbExpression queryExpression = storeFunctionInvoke; CollectionType functionImportReturnType; if (!MetadataHelper.TryGetFunctionImportReturnCollectionType(this.FunctionImport, 0, out functionImportReturnType)) { Debug.Fail("Failed to get the result type of the function import."); } Debug.Assert(TypeSemantics.IsCollectionType(queryExpression.ResultType), "Store function must be TVF (collection expected)."); var collectionType = (CollectionType)queryExpression.ResultType.EdmType; Debug.Assert(TypeSemantics.IsRowType(collectionType.TypeUsage), "Store function must be TVF (collection of rows expected)."); var rowType = (RowType)collectionType.TypeUsage.EdmType; var column = rowType.Properties[0]; Func <DbExpression, DbExpression> scalarView = (DbExpression row) => { var propertyAccess = row.Property(column); if (TypeSemantics.IsEqual(functionImportReturnType.TypeUsage, column.TypeUsage)) { return(propertyAccess); } else { return(propertyAccess.CastTo(functionImportReturnType.TypeUsage)); } }; queryExpression = queryExpression.Select(row => scalarView(row)); return(queryExpression); }
/// <summary> /// Resolve property <paramref name="name" /> off the <paramref name="valueExpr" />. /// </summary> internal ValueExpression ResolvePropertyAccess(DbExpression valueExpr, string name, ErrorContext errCtx) { DbExpression propertyExpr; if (TryResolveAsPropertyAccess(valueExpr, name, out propertyExpr)) { return(new ValueExpression(propertyExpr)); } if (TryResolveAsRefPropertyAccess(valueExpr, name, errCtx, out propertyExpr)) { return(new ValueExpression(propertyExpr)); } if (TypeSemantics.IsCollectionType(valueExpr.ResultType)) { var message = Strings.NotAMemberOfCollection(name, valueExpr.ResultType.EdmType.FullName); throw EntitySqlException.Create(errCtx, message, null); } else { var message = Strings.NotAMemberOfType(name, valueExpr.ResultType.EdmType.FullName); throw EntitySqlException.Create(errCtx, message, null); } }
internal static void AssertEdmType(TypeUsage typeUsage) { var type = typeUsage.EdmType; if (TypeSemantics.IsCollectionType(typeUsage)) { AssertEdmType(GetElementTypeUsage(typeUsage)); } else if (TypeSemantics.IsStructuralType(typeUsage) && !Helper.IsComplexType(typeUsage.EdmType) && !Helper.IsEntityType(typeUsage.EdmType)) { foreach (EdmMember m in GetDeclaredStructuralMembers(typeUsage)) { AssertEdmType(m.TypeUsage); } } else if (TypeSemantics.IsPrimitiveType(typeUsage)) { var pType = type as PrimitiveType; if (null != pType) { if (pType.DataSpace != DataSpace.CSpace) { throw new NotSupportedException( String.Format(CultureInfo.InvariantCulture, "PrimitiveType must be CSpace '{0}'", typeUsage)); } } } }
internal static void RequireCollectionArgument <TExpressionType>(DbExpression argument) { if (!TypeSemantics.IsCollectionType(argument.ResultType)) { throw new ArgumentException(Strings.Cqt_Unary_CollectionRequired((object)typeof(TExpressionType).Name), nameof(argument)); } }
internal static DbExpression FindNavigationExpression(DbExpression expression, AliasGenerator aliasGenerator, out NavigationInfo navInfo) { Debug.Assert(TypeSemantics.IsCollectionType(expression.ResultType), "Non-collection input to projection?"); navInfo = null; TypeUsage elementType = ((CollectionType)expression.ResultType.EdmType).TypeUsage; if (!TypeSemantics.IsEntityType(elementType) && !TypeSemantics.IsReferenceType(elementType)) { return(expression); } RelationshipNavigationVisitor visitor = new RelationshipNavigationVisitor(aliasGenerator); DbExpression rewrittenExpression = visitor.Find(expression); if (!object.ReferenceEquals(expression, rewrittenExpression)) { Debug.Assert(visitor._original != null && visitor._rewritten != null, "Expression was rewritten but no navigation was found?"); navInfo = new NavigationInfo(visitor._original, visitor._rewritten); return(rewrittenExpression); } else { return(expression); } }
internal static bool IsCollectionAggregateFunction(FunctionOp op, System.Data.Entity.Core.Query.InternalTrees.Node n) { if (n.Children.Count == 1 && TypeSemantics.IsCollectionType(n.Child0.Op.Type)) { return(TypeSemantics.IsAggregateFunction(op.Function)); } return(false); }
private Node VisitCollectionFunction(FunctionOp op, Node n) { System.Data.Entity.Core.Query.PlanCompiler.PlanCompiler.Assert(TypeSemantics.IsCollectionType(op.Type), "non-TVF function?"); Node node1 = this.BuildUnnest(n); Node node2 = this.m_command.CreateNode((Op)this.m_command.CreatePhysicalProjectOp((node1.Op as UnnestOp).Table.Columns[0]), node1); return(this.m_command.CreateNode((Op)this.m_command.CreateCollectOp(n.Op.Type), node2)); }
public override Node Visit(FunctionOp op, Node n) { this.VisitScalarOpDefault((ScalarOp)op, n); Node node = !TypeSemantics.IsCollectionType(op.Type) ? (!PlanCompilerUtil.IsCollectionAggregateFunction(op, n) ? n : this.VisitCollectionAggregateFunction(op, n)) : this.VisitCollectionFunction(op, n); System.Data.Entity.Core.Query.PlanCompiler.PlanCompiler.Assert(node != null, "failure to construct a functionOp?"); return(node); }
internal DbNewInstanceExpression(TypeUsage type, DbExpressionList args) : base(DbExpressionKind.NewInstance, type) { Debug.Assert(args != null, "DbNewInstanceExpression arguments cannot be null"); Debug.Assert(args.Count > 0 || TypeSemantics.IsCollectionType(type), "DbNewInstanceExpression requires at least one argument when not creating an empty collection"); this._elements = args; }
private static bool TryRankFunctionParameters <TFunctionParameterMetadata>( IList <TypeUsage> argumentList, IList <TypeUsage> flatArgumentList, IList <TFunctionParameterMetadata> overloadParamList, Func <TFunctionParameterMetadata, TypeUsage> getParameterTypeUsage, Func <TFunctionParameterMetadata, ParameterMode> getParameterMode, Func <TypeUsage, TypeUsage, IEnumerable <TypeUsage> > flattenParameterType, Func <TypeUsage, TypeUsage, bool> isPromotableTo, Func <TypeUsage, TypeUsage, bool> isStructurallyEqual, bool isGroupAggregateFunction, out int totalRank, out int[] parameterRanks) { totalRank = 0; parameterRanks = (int[])null; if (argumentList.Count != overloadParamList.Count) { return(false); } List <TypeUsage> typeUsageList = new List <TypeUsage>(flatArgumentList.Count); for (int index = 0; index < overloadParamList.Count; ++index) { TypeUsage typeUsage = argumentList[index]; TypeUsage type = getParameterTypeUsage(overloadParamList[index]); switch (getParameterMode(overloadParamList[index])) { case ParameterMode.In: case ParameterMode.InOut: if (isGroupAggregateFunction) { if (!TypeSemantics.IsCollectionType(type)) { throw new EntitySqlException(Strings.InvalidArgumentTypeForAggregateFunction); } type = TypeHelpers.GetElementTypeUsage(type); } if (!isPromotableTo(typeUsage, type)) { return(false); } typeUsageList.AddRange(flattenParameterType(type, typeUsage)); continue; default: return(false); } } parameterRanks = new int[typeUsageList.Count]; for (int index = 0; index < parameterRanks.Length; ++index) { int promotionRank = FunctionOverloadResolver.GetPromotionRank(flatArgumentList[index], typeUsageList[index], isPromotableTo, isStructurallyEqual); totalRank += promotionRank; parameterRanks[index] = promotionRank; } return(true); }
private Node BuildUnnest(Node collectionNode) { System.Data.Entity.Core.Query.PlanCompiler.PlanCompiler.Assert(collectionNode.Op.IsScalarOp, "non-scalar usage of Un-nest?"); System.Data.Entity.Core.Query.PlanCompiler.PlanCompiler.Assert(TypeSemantics.IsCollectionType(collectionNode.Op.Type), "non-collection usage for Un-nest?"); Var computedVar; Node varDefNode = this.m_command.CreateVarDefNode(collectionNode, out computedVar); return(this.m_command.CreateNode((Op)this.m_command.CreateUnnestOp(computedVar), varDefNode)); }
internal DbSortExpression(TypeUsage resultType, DbExpressionBinding input, System.Collections.ObjectModel.ReadOnlyCollection <DbSortClause> sortOrder) : base(DbExpressionKind.Sort, resultType) { Debug.Assert(input != null, "DbSortExpression input cannot be null"); Debug.Assert(sortOrder != null, "DbSortExpression sort order cannot be null"); Debug.Assert(TypeSemantics.IsCollectionType(resultType), "DbSkipExpression requires a collection result type"); this._input = input; this._keys = sortOrder; }
internal DbSortExpression(TypeUsage resultType, DbExpressionBinding input, ReadOnlyCollection <DbSortClause> sortOrder) : base(DbExpressionKind.Sort, resultType) { DebugCheck.NotNull(input); DebugCheck.NotNull(sortOrder); Debug.Assert(TypeSemantics.IsCollectionType(resultType), "DbSkipExpression requires a collection result type"); _input = input; _keys = sortOrder; }
/// <summary> /// Build up an unnest above a scalar op node /// X => unnest(X) /// </summary> /// <param name="collectionNode">the scalarop collection node</param> /// <returns>the unnest node</returns> private Node BuildUnnest(Node collectionNode) { PlanCompiler.Assert(collectionNode.Op.IsScalarOp, "non-scalar usage of Unnest?"); PlanCompiler.Assert(TypeSemantics.IsCollectionType(collectionNode.Op.Type), "non-collection usage for Unnest?"); Var newVar; Node varDefNode = m_command.CreateVarDefNode(collectionNode, out newVar); UnnestOp unnestOp = m_command.CreateUnnestOp(newVar); Node unnestNode = m_command.CreateNode(unnestOp, varDefNode); return(unnestNode); }
/// <summary> /// Returns row type if supplied function is a tvf returning Collection(RowType), otherwise null. /// </summary> internal static RowType GetTvfReturnType(EdmFunction tvf) { if (tvf.ReturnParameter != null && TypeSemantics.IsCollectionType(tvf.ReturnParameter.TypeUsage)) { var expectedElementTypeUsage = ((CollectionType)tvf.ReturnParameter.TypeUsage.EdmType).TypeUsage; if (TypeSemantics.IsRowType(expectedElementTypeUsage)) { return((RowType)expectedElementTypeUsage.EdmType); } } return(null); }
internal static TypeUsage ValidateNewEmptyCollection( TypeUsage collectionType, out DbExpressionList validElements) { ArgumentValidation.CheckType(collectionType, nameof(collectionType)); if (!TypeSemantics.IsCollectionType(collectionType)) { throw new ArgumentException(Strings.Cqt_NewInstance_CollectionTypeRequired, nameof(collectionType)); } validElements = new DbExpressionList((IList <DbExpression>) new DbExpression[0]); return(collectionType); }
internal static TypeUsage GetElementTypeUsage(TypeUsage type) { if (TypeSemantics.IsCollectionType(type)) { return(((CollectionType)type.EdmType).TypeUsage); } if (TypeSemantics.IsReferenceType(type)) { return(TypeUsage.Create((EdmType)((RefType)type.EdmType).ElementType)); } return((TypeUsage)null); }
/// <summary> /// Converts the reference to a TVF as following: Collect(PhysicalProject(Unnest(Func))) /// </summary> /// <param name="op">current function op</param> /// <param name="n">current function subtree</param> /// <returns>the new expression that corresponds to the TVF</returns> private Node VisitCollectionFunction(FunctionOp op, Node n) { PlanCompiler.Assert(TypeSemantics.IsCollectionType(op.Type), "non-TVF function?"); Node unnestNode = BuildUnnest(n); UnnestOp unnestOp = unnestNode.Op as UnnestOp; PhysicalProjectOp projectOp = m_command.CreatePhysicalProjectOp(unnestOp.Table.Columns[0]); Node projectNode = m_command.CreateNode(projectOp, unnestNode); CollectOp collectOp = m_command.CreateCollectOp(n.Op.Type); Node collectNode = m_command.CreateNode(collectOp, projectNode); return(collectNode); }
internal static TypeUsage RequireCollectionArguments <TExpressionType>( DbExpression left, DbExpression right) { if (!TypeSemantics.IsCollectionType(left.ResultType) || !TypeSemantics.IsCollectionType(right.ResultType)) { throw new ArgumentException(Strings.Cqt_Binary_CollectionsRequired((object)typeof(TExpressionType).Name)); } TypeUsage commonTypeUsage = TypeHelpers.GetCommonTypeUsage(left.ResultType, right.ResultType); if (commonTypeUsage == null) { throw new ArgumentException(Strings.Cqt_Binary_CollectionsRequired((object)typeof(TExpressionType).Name)); } return(commonTypeUsage); }
/// <summary> /// Recursively add any Row types to the list of types needing a sentinel. /// </summary> /// <param name="typesNeedingNullableSentinel"> </param> /// <param name="typeUsage"> </param> private static void AddTypeNeedingNullSentinel(HashSet <string> typesNeedingNullSentinel, TypeUsage typeUsage) { if (TypeSemantics.IsCollectionType(typeUsage)) { AddTypeNeedingNullSentinel(typesNeedingNullSentinel, TypeHelpers.GetElementTypeUsage(typeUsage)); } else { if (TypeSemantics.IsRowType(typeUsage) || TypeSemantics.IsComplexType(typeUsage)) { MarkAsNeedingNullSentinel(typesNeedingNullSentinel, typeUsage); } foreach (EdmMember m in TypeHelpers.GetAllStructuralMembers(typeUsage)) { AddTypeNeedingNullSentinel(typesNeedingNullSentinel, m.TypeUsage); } } }
private static void AddTypeNeedingNullSentinel( HashSet <string> typesNeedingNullSentinel, TypeUsage typeUsage) { if (TypeSemantics.IsCollectionType(typeUsage)) { StructuredTypeNullabilityAnalyzer.AddTypeNeedingNullSentinel(typesNeedingNullSentinel, TypeHelpers.GetElementTypeUsage(typeUsage)); } else { if (TypeSemantics.IsRowType(typeUsage) || TypeSemantics.IsComplexType(typeUsage)) { StructuredTypeNullabilityAnalyzer.MarkAsNeedingNullSentinel(typesNeedingNullSentinel, typeUsage); } foreach (EdmMember structuralMember in (IEnumerable)TypeHelpers.GetAllStructuralMembers(typeUsage)) { StructuredTypeNullabilityAnalyzer.AddTypeNeedingNullSentinel(typesNeedingNullSentinel, structuralMember.TypeUsage); } } }
/// <summary> /// Pre-processing for a function. Does the default scalar op processing. /// If the function returns a collection (TVF), the method converts this expression into /// Collect(PhysicalProject(Unnest(Func))). /// If the function is a collection aggregate, converts it into the corresponding group aggregate. /// </summary> /// <param name="op"></param> /// <param name="n"></param> /// <returns></returns> public override Node Visit(FunctionOp op, Node n) { VisitScalarOpDefault(op, n); Node newNode = null; // Is this a TVF? if (TypeSemantics.IsCollectionType(op.Type)) { newNode = VisitCollectionFunction(op, n); } // Is this a collection-aggregate function? else if (PlanCompilerUtil.IsCollectionAggregateFunction(op, n)) { newNode = VisitCollectionAggregateFunction(op, n); } else { newNode = n; } PlanCompiler.Assert(newNode != null, "failure to construct a functionOp?"); return(newNode); }
private DbExpression GenerateScalarResultMappingView(DbExpression storeFunctionInvoke) { var queryExpression = storeFunctionInvoke; CollectionType functionImportReturnType; if (!MetadataHelper.TryGetFunctionImportReturnCollectionType(FunctionImport, 0, out functionImportReturnType)) { Debug.Fail("Failed to get the result type of the function import."); } Debug.Assert(TypeSemantics.IsCollectionType(queryExpression.ResultType), "Store function must be TVF (collection expected)."); var collectionType = (CollectionType)queryExpression.ResultType.EdmType; Debug.Assert(TypeSemantics.IsRowType(collectionType.TypeUsage), "Store function must be TVF (collection of rows expected)."); var rowType = (RowType)collectionType.TypeUsage.EdmType; var column = rowType.Properties[0]; Func <DbExpression, DbExpression> scalarView = row => { var propertyAccess = row.Property(column); if (TypeSemantics.IsEqual( functionImportReturnType.TypeUsage, column.TypeUsage)) { return(propertyAccess); } else { return(propertyAccess.CastTo(functionImportReturnType.TypeUsage)); } }; // ReSharper disable ConvertClosureToMethodGroup // using Method Group breaks matching the expression in DbExpressionBuilder.ResolveToExpression return(queryExpression.Select(row => scalarView(row))); // ReSharper restore ConvertClosureToMethodGroup }
internal ValueExpression ResolvePropertyAccess( DbExpression valueExpr, string name, ErrorContext errCtx) { DbExpression propertyExpr; if (this.TryResolveAsPropertyAccess(valueExpr, name, out propertyExpr)) { return(new ValueExpression(propertyExpr)); } if (this.TryResolveAsRefPropertyAccess(valueExpr, name, errCtx, out propertyExpr)) { return(new ValueExpression(propertyExpr)); } if (TypeSemantics.IsCollectionType(valueExpr.ResultType)) { string errorMessage = Strings.NotAMemberOfCollection((object)name, (object)valueExpr.ResultType.EdmType.FullName); throw EntitySqlException.Create(errCtx, errorMessage, (Exception)null); } string errorMessage1 = Strings.NotAMemberOfType((object)name, (object)valueExpr.ResultType.EdmType.FullName); throw EntitySqlException.Create(errCtx, errorMessage1, (Exception)null); }
protected static void AssertCollectionType(TypeUsage type) { Assert(TypeSemantics.IsCollectionType(type), "Type Mismatch: Expected Collection type: Found {0}", TypeHelpers.GetFullName(type)); }
protected static void AssertCollectionType(TypeUsage type) { Assert( TypeSemantics.IsCollectionType(type), "Type Mismatch: Expected Collection type: Found {0}", type.ToString()); }
internal DbDistinctExpression(TypeUsage resultType, DbExpression argument) : base(DbExpressionKind.Distinct, resultType, argument) { Debug.Assert(TypeSemantics.IsCollectionType(argument.ResultType), "DbDistinctExpression argument must have a collection result type"); }
/// <summary> /// Is this function a collection aggregate function. It is, if /// - it has exactly one child /// - that child is a collection type /// - and the function has been marked with the aggregate attribute /// </summary> /// <param name="op"> the function op </param> /// <param name="n"> the current subtree </param> /// <returns> true, if this was a collection aggregate function </returns> internal static bool IsCollectionAggregateFunction(FunctionOp op, Node n) { return((n.Children.Count == 1) && TypeSemantics.IsCollectionType(n.Child0.Op.Type) && TypeSemantics.IsAggregateFunction(op.Function)); }
// <summary> // Check promotability, returns true if argument list is promotable to the overload and overload was successfully ranked, otherwise false. // Ranks the overload parameter types against the argument list. // </summary> // <param name="argumentList"> list of argument types </param> // <param name="flatArgumentList"> flattened list of argument types </param> // <param name="overloadParamList"> list of overload parameter types </param> // <param name="getParameterTypeUsage"> TypeUsage getter for the overload parameters </param> // <param name="getParameterMode"> ParameterMode getter for the overload parameters </param> // <param name="totalRank"> returns total promotion rank of the overload, 0 if no arguments </param> // <param name="parameterRanks"> returns individual promotion ranks of the overload parameters, empty array if no arguments </param> private static bool TryRankFunctionParameters <TFunctionParameterMetadata>( IList <TypeUsage> argumentList, IList <TypeUsage> flatArgumentList, IList <TFunctionParameterMetadata> overloadParamList, Func <TFunctionParameterMetadata, TypeUsage> getParameterTypeUsage, Func <TFunctionParameterMetadata, ParameterMode> getParameterMode, Func <TypeUsage, TypeUsage, IEnumerable <TypeUsage> > flattenParameterType, Func <TypeUsage, TypeUsage, bool> isPromotableTo, Func <TypeUsage, TypeUsage, bool> isStructurallyEqual, bool isGroupAggregateFunction, out int totalRank, out int[] parameterRanks) { totalRank = 0; parameterRanks = null; if (argumentList.Count != overloadParamList.Count) { return(false); } // // Check promotability and flatten the parameter types // var flatOverloadParamList = new List <TypeUsage>(flatArgumentList.Count); for (var i = 0; i < overloadParamList.Count; ++i) { var argumentType = argumentList[i]; var parameterType = getParameterTypeUsage(overloadParamList[i]); // // Parameter mode must match. // var parameterMode = getParameterMode(overloadParamList[i]); if (parameterMode != ParameterMode.In && parameterMode != ParameterMode.InOut) { return(false); } // // If function being ranked is a group aggregate, consider the element type. // if (isGroupAggregateFunction) { if (!TypeSemantics.IsCollectionType(parameterType)) { // // Even though it is the job of metadata to ensure that the provider manifest is consistent. // Ensure that if a function is marked as aggregate, then the argument type must be of collection{GivenType}. // var message = Strings.InvalidArgumentTypeForAggregateFunction; throw new EntitySqlException(message); } parameterType = TypeHelpers.GetElementTypeUsage(parameterType); } // // If argument is not promotable - reject the overload. // if (!isPromotableTo(argumentType, parameterType)) { return(false); } // // Flatten the parameter type. // flatOverloadParamList.AddRange(flattenParameterType(parameterType, argumentType)); } Debug.Assert(flatArgumentList.Count == flatOverloadParamList.Count, "flatArgumentList.Count == flatOverloadParamList.Count"); // // Rank argument promotions // parameterRanks = new int[flatOverloadParamList.Count]; for (var i = 0; i < parameterRanks.Length; ++i) { var rank = GetPromotionRank(flatArgumentList[i], flatOverloadParamList[i], isPromotableTo, isStructurallyEqual); totalRank += rank; parameterRanks[i] = rank; } return(true); }