private Tuple <int, bool> GetCompareMode(DbExpressionKind kind) { switch (kind) { case DbExpressionKind.Equals: return(Tuple.Create(0, true)); case DbExpressionKind.NotEquals: return(Tuple.Create(0, false)); case DbExpressionKind.GreaterThan: return(Tuple.Create(1, true)); case DbExpressionKind.GreaterThanOrEquals: return(Tuple.Create(-1, false)); case DbExpressionKind.LessThan: return(Tuple.Create(-1, true)); case DbExpressionKind.LessThanOrEquals: return(Tuple.Create(1, false)); } throw new InvalidOperationException( "The ExpressionKind cannot be " + kind.ToString()); }
internal DbUnaryExpression(DbExpressionKind kind, TypeUsage resultType, DbExpression argument) : base(kind, resultType) { DebugCheck.NotNull(argument); _argument = argument; }
// <summary> // Helper method for FlattenAssociativeExpression. // Creates a flat list of the associative arguments and appends to the given argument list. // For example, for ((A1 + (A2 - A3)) + A4) it will add A1, (A2 - A3), A4 to the list. // Only 'unfolds' the given expression if it is of the given expression kind. // </summary> private static void ExtractAssociativeArguments( DbExpressionKind expressionKind, List <DbExpression> argumentList, DbExpression expression) { if (expression.ExpressionKind != expressionKind) { argumentList.Add(expression); return; } //All associative expressions are binary, thus we must be dealing with a DbBinaryExpresson or // a DbArithmeticExpression with 2 arguments. var binaryExpression = expression as DbBinaryExpression; if (binaryExpression != null) { ExtractAssociativeArguments(expressionKind, argumentList, binaryExpression.Left); ExtractAssociativeArguments(expressionKind, argumentList, binaryExpression.Right); return; } var arithExpression = (DbArithmeticExpression)expression; ExtractAssociativeArguments(expressionKind, argumentList, arithExpression.Arguments[0]); ExtractAssociativeArguments(expressionKind, argumentList, arithExpression.Arguments[1]); }
// <summary> // Uses a stack to non-recursively traverse a given tree structure and retrieve the leaf nodes. // </summary> // <param name="root"> The node that represents the root of the tree. </param> // <param name="kind"> Expressions not of this kind are considered leaves. </param> // <param name="getChildNodes"> // A function that traverses the tree by retrieving the <b>immediate</b> descendants of a (non-leaf) node. // </param> // <returns> An enumerable containing the leaf nodes. </returns> public static IEnumerable <DbExpression> GetLeafNodes( this DbExpression root, DbExpressionKind kind, Func <DbExpression, IEnumerable <DbExpression> > getChildNodes) { DebugCheck.NotNull(getChildNodes); var nodes = new Stack <DbExpression>(); nodes.Push(root); while (nodes.Count > 0) { var current = nodes.Pop(); if (current.ExpressionKind != kind) { yield return(current); } else { foreach (var node in getChildNodes(current).Reverse()) { nodes.Push(node); } } } }
private static Mock<DbExpression> CreateMockExpression(DbExpressionKind kind) { var mockRoot = new Mock<DbExpression>(); mockRoot.Setup(m => m.ExpressionKind).Returns(kind); return mockRoot; }
public static string GetOperator(DbExpressionKind expressionKind) { switch (expressionKind) { case DbExpressionKind.Equals: return("="); case DbExpressionKind.LessThan: return("<"); case DbExpressionKind.GreaterThan: return(">"); case DbExpressionKind.LessThanOrEquals: return("<="); case DbExpressionKind.GreaterThanOrEquals: return(">="); case DbExpressionKind.NotEquals: return("!="); case DbExpressionKind.LeftOuterJoin: return("LEFT OUTER JOIN"); case DbExpressionKind.InnerJoin: return("INNER JOIN"); case DbExpressionKind.CrossJoin: return("CROSS JOIN"); case DbExpressionKind.FullOuterJoin: return("OUTER JOIN"); } throw new NotSupportedException("expression kind not supported"); }
private DbExpression TransformIntersectOrExcept( DbExpression left, DbExpression right, DbExpressionKind expressionKind) { return(this.TransformIntersectOrExcept(left, right, expressionKind, (IList <DbPropertyExpression>)null, (string)null)); }
internal DbArithmeticExpression(DbExpressionKind kind, TypeUsage numericResultType, DbExpressionList args) : base(kind, numericResultType) { Debug.Assert(TypeSemantics.IsNumericType(numericResultType), "DbArithmeticExpression result type must be numeric"); Debug.Assert( DbExpressionKind.Divide == kind || DbExpressionKind.Minus == kind || DbExpressionKind.Modulo == kind || DbExpressionKind.Multiply == kind || DbExpressionKind.Plus == kind || DbExpressionKind.UnaryMinus == kind, "Invalid DbExpressionKind used in DbArithmeticExpression: " + Enum.GetName(typeof(DbExpressionKind), kind) ); Debug.Assert(args != null, "DbArithmeticExpression arguments cannot be null"); Debug.Assert( (DbExpressionKind.UnaryMinus == kind && 1 == args.Count) || 2 == args.Count, "Incorrect number of arguments specified to DbArithmeticExpression" ); this._args = args; }
public JoinExpression(InputExpression left, DbExpressionKind joinType, InputExpression right, VisitedExpression condition) { _left = left; _joinType = joinType; _right = right; _condition = condition; }
public bool IsCompatible(DbExpressionKind expressionKind) { switch (expressionKind) { case DbExpressionKind.Filter: return(Where == null && Columns.Count == 0); case DbExpressionKind.Project: return(Columns.Count == 0); case DbExpressionKind.Limit: return(Limit == null); case DbExpressionKind.Skip: return(Skip == null); case DbExpressionKind.Sort: return(Columns.Count == 0 && GroupBy == null && OrderBy == null); case DbExpressionKind.GroupBy: return(Columns.Count == 0 && GroupBy == null && OrderBy == null && Limit == null); } throw new InvalidOperationException(); }
internal DbUnaryExpression(DbExpressionKind kind, TypeUsage resultType, DbExpression argument) : base(kind, resultType) { Debug.Assert(argument != null, "DbUnaryExpression.Argument cannot be null"); this._argument = argument; }
private Expression CreateComparison(Expression left, Expression right, DbExpressionKind kind) { if (left.Type == typeof(string) && right.Type == typeof(string)) { return CreateStringComparison(left, right, kind); } switch (kind) { case DbExpressionKind.Equals: return Expression.Equal(left, right); case DbExpressionKind.NotEquals: return Expression.NotEqual(left, right); case DbExpressionKind.GreaterThan: return Expression.GreaterThan(left, right); case DbExpressionKind.GreaterThanOrEquals: return Expression.GreaterThanOrEqual(left, right); case DbExpressionKind.LessThan: return Expression.LessThan(left, right); case DbExpressionKind.LessThanOrEquals: return Expression.LessThanOrEqual(left, right); default: throw new InvalidOperationException( "The ExpressionKind cannot be " + kind.ToString()); } }
internal DbUnaryExpression(DbExpressionKind kind, TypeUsage resultType, DbExpression argument) : base(kind, resultType) { Debug.Assert(argument != null, "DbUnaryExpression.Argument cannot be null"); _argument = argument; }
private SqlFragment HandleJoinExpression(DbExpressionBinding left, DbExpressionBinding right, DbExpressionKind joinType, DbExpression joinCondition) { JoinFragment join = new JoinFragment(); join.JoinType = Metadata.GetOperator(joinType); join.Left = VisitInputExpression(left.Expression, left.VariableName, left.VariableType); join.Left = WrapJoinInputIfNecessary(join.Left, false); join.Right = VisitInputExpression(right.Expression, right.VariableName, right.VariableType); join.Right = WrapJoinInputIfNecessary(join.Right, true); if (join.Right is SelectStatement) { SelectStatement select = join.Right as SelectStatement; if (select.IsWrapped) { select.Name = right.VariableName; } } // now handle the ON case if (joinCondition != null) { join.Condition = joinCondition.Accept(this); } return(join); }
// <summary> // Uses a stack to non-recursively traverse a given tree structure and retrieve the leaf nodes. // </summary> // <param name="root"> The node that represents the root of the tree. </param> // <param name="kind"> Expressions not of this kind are considered leaves. </param> // <param name="getChildNodes"> // A function that traverses the tree by retrieving the <b>immediate</b> descendants of a (non-leaf) node. // </param> // <returns> An enumerable containing the leaf nodes. </returns> public static IEnumerable<DbExpression> GetLeafNodes( this DbExpression root, DbExpressionKind kind, Func<DbExpression, IEnumerable<DbExpression>> getChildNodes) { DebugCheck.NotNull(getChildNodes); var nodes = new Stack<DbExpression>(); nodes.Push(root); while (nodes.Count > 0) { var current = nodes.Pop(); if (current.ExpressionKind != kind) { yield return current; } else { foreach (var node in getChildNodes(current).Reverse()) { nodes.Push(node); } } } }
private Expression CreateComparison(Expression left, Expression right, DbExpressionKind kind) { if (left.Type == typeof(string) && right.Type == typeof(string)) { return(CreateStringComparison(left, right, kind)); } switch (kind) { case DbExpressionKind.Equals: return(Expression.Equal(left, right)); case DbExpressionKind.NotEquals: return(Expression.NotEqual(left, right)); case DbExpressionKind.GreaterThan: return(Expression.GreaterThan(left, right)); case DbExpressionKind.GreaterThanOrEquals: return(Expression.GreaterThanOrEqual(left, right)); case DbExpressionKind.LessThan: return(Expression.LessThan(left, right)); case DbExpressionKind.LessThanOrEquals: return(Expression.LessThanOrEqual(left, right)); default: throw new InvalidOperationException( "The ExpressionKind cannot be " + kind.ToString()); } }
/// <summary> /// Determine if the owner expression can add its unique sql to the input's /// SqlSelectStatement /// </summary> /// <param name="result">The SqlSelectStatement of the input to the relational node.</param> /// <param name="expressionKind">The kind of the expression node(not the input's)</param> /// <returns></returns> private static bool IsCompatible(SqlSelectStatement result, DbExpressionKind expressionKind) { switch (expressionKind) { case DbExpressionKind.Distinct: return(result.Top.IsEmpty // The projection after distinct may not project all // columns used in the Order By // Improvement: Consider getting rid of the Order By instead && result.OrderBy.IsEmpty); case DbExpressionKind.Filter: return(result.Select.IsEmpty && result.Where.IsEmpty && result.GroupBy.IsEmpty && result.Top.IsEmpty); case DbExpressionKind.GroupBy: return(result.Select.IsEmpty && result.GroupBy.IsEmpty && result.OrderBy.IsEmpty && result.Top.IsEmpty); case DbExpressionKind.Limit: return(result.Top.TopCount == null); case DbExpressionKind.Element: return(result.Top.TopCount == null); case DbExpressionKind.Project: // Allow a Project to be compatible with an OrderBy // Otherwise we won't be able to sort an input, and project out only // a subset of the input columns return(result.Select.IsEmpty && result.GroupBy.IsEmpty // If distinct is specified, the projection may affect // the cardinality of the results, thus a new statement must be started. && !result.IsDistinct); case DbExpressionKind.Skip: return(result.Top.SkipCount == null); case DbExpressionKind.Sort: return(result.Select.IsEmpty && result.GroupBy.IsEmpty && result.OrderBy.IsEmpty // A Project may be on the top of the Sort, and if so, it would need // to be in the same statement as the Sort (see comment above for the Project case). // A Distinct in the same statement would prevent that, and therefore if Distinct is present, // we need to start a new statement. && !result.IsDistinct); //return result.OrderBy.IsEmpty; default: Debug.Assert(false); throw new InvalidOperationException(String.Empty); } }
private static Mock <DbExpression> CreateMockExpression(DbExpressionKind kind) { var mockRoot = new Mock <DbExpression>(); mockRoot.Setup(m => m.ExpressionKind).Returns(kind); return(mockRoot); }
internal static void CheckExpressionKind(DbExpressionKind kind) { if (kind < DbExpressionKind.All || DbExpressionKindHelper.Last < kind) { string name = typeof(DbExpressionKind).Name; throw new ArgumentOutOfRangeException(name, Strings.ADP_InvalidEnumerationValue((object)name, (object)((int)kind).ToString((IFormatProvider)CultureInfo.InvariantCulture))); } }
internal DbIsOfExpression(DbExpressionKind isOfKind, TypeUsage booleanResultType, DbExpression argument, TypeUsage isOfType) : base(isOfKind, booleanResultType, argument) { Debug.Assert(DbExpressionKind.IsOf == this.ExpressionKind || DbExpressionKind.IsOfOnly == this.ExpressionKind, string.Format(CultureInfo.InvariantCulture, "Invalid DbExpressionKind used in DbIsOfExpression: {0}", Enum.GetName(typeof(DbExpressionKind), this.ExpressionKind))); Debug.Assert(TypeSemantics.IsBooleanType(booleanResultType), "DbIsOfExpression requires a Boolean result type"); this._ofType = isOfType; }
internal DbComparisonExpression( DbExpressionKind kind, TypeUsage booleanResultType, DbExpression left, DbExpression right) : base(kind, booleanResultType, left, right) { }
internal DbArithmeticExpression( DbExpressionKind kind, TypeUsage numericResultType, DbExpressionList args) : base(kind, numericResultType, true) { this._args = args; }
internal DbBinaryExpression(DbExpressionKind kind, TypeUsage type, DbExpression left, DbExpression right) : base(kind, type) { DebugCheck.NotNull(left); DebugCheck.NotNull(right); _left = left; _right = right; }
public CombinedProjectionExpression(DbExpressionKind setOperator, List <VisitedExpression> list) { _setOperator = setOperator == DbExpressionKind.UnionAll ? "UNION ALL" : setOperator == DbExpressionKind.Except ? "EXCEPT" : "INTERSECT"; _list = list; }
internal static void CheckExpressionKind(DbExpressionKind kind) { // Add new valid DbExpressionKind values to this method as well as the enum itself. // DbExpressionKind is a contiguous enum from All = 0 through View if ((kind < DbExpressionKind.All) || (DbExpressionKind.Lambda < kind)) { throw EntityUtil.InvalidEnumerationValue(typeof(DbExpressionKind), (int)kind); } }
internal DbBinaryExpression(DbExpressionKind kind, TypeUsage type, DbExpression left, DbExpression right) : base(kind, type) { Debug.Assert(left != null, "DbBinaryExpression.Left cannot be null"); Debug.Assert(right != null, "DbBinaryExpression.Right cannot be null"); this._left = left; this._right = right; }
internal DbOfTypeExpression( DbExpressionKind ofTypeKind, TypeUsage collectionResultType, DbExpression argument, TypeUsage type) : base(ofTypeKind, collectionResultType, argument) { this._ofType = type; }
internal DbBinaryExpression(DbExpressionKind kind, TypeUsage type, DbExpression left, DbExpression right) : base(kind, type) { Debug.Assert(left != null, "DbBinaryExpression.Left cannot be null"); Debug.Assert(right != null, "DbBinaryExpression.Right cannot be null"); _left = left; _right = right; }
internal DbIsOfExpression( DbExpressionKind isOfKind, TypeUsage booleanResultType, DbExpression argument, TypeUsage isOfType) : base(isOfKind, booleanResultType, argument) { this._ofType = isOfType; }
internal DbQuantifierExpression( DbExpressionKind kind, TypeUsage booleanResultType, DbExpressionBinding input, DbExpression predicate) : base(kind, booleanResultType, true) { this._input = input; this._predicate = predicate; }
internal DbApplyExpression(DbExpressionKind applyKind, TypeUsage resultRowCollectionTypeUsage, DbExpressionBinding input, DbExpressionBinding apply) : base(applyKind, resultRowCollectionTypeUsage) { Debug.Assert(input != null, "DbApplyExpression input cannot be null"); Debug.Assert(input != null, "DbApplyExpression apply cannot be null"); Debug.Assert(DbExpressionKind.CrossApply == applyKind || DbExpressionKind.OuterApply == applyKind, "Invalid DbExpressionKind for DbApplyExpression"); _input = input; _apply = apply; }
internal DbBinaryExpression( DbExpressionKind kind, TypeUsage type, DbExpression left, DbExpression right) : base(kind, type, true) { this._left = left; this._right = right; }
internal DbApplyExpression( DbExpressionKind applyKind, TypeUsage resultRowCollectionTypeUsage, DbExpressionBinding input, DbExpressionBinding apply) : base(applyKind, resultRowCollectionTypeUsage, true) { this._input = input; this._apply = apply; }
internal DbQuantifierExpression(DbExpressionKind kind, TypeUsage booleanResultType, DbExpressionBinding input, DbExpression predicate) : base(kind, booleanResultType) { Debug.Assert(input != null, "DbQuantifierExpression input cannot be null"); Debug.Assert(predicate != null, "DbQuantifierExpression predicate cannot be null"); Debug.Assert(TypeSemantics.IsPrimitiveType(booleanResultType, PrimitiveTypeKind.Boolean), "DbQuantifierExpression must have a Boolean result type"); Debug.Assert(TypeSemantics.IsPrimitiveType(predicate.ResultType, PrimitiveTypeKind.Boolean), "DbQuantifierExpression predicate must have a Boolean result type"); this._input = input; this._predicate = predicate; }
internal DbJoinExpression( DbExpressionKind joinKind, TypeUsage collectionOfRowResultType, DbExpressionBinding left, DbExpressionBinding right, DbExpression condition) : base(joinKind, collectionOfRowResultType, true) { this._left = left; this._right = right; this._condition = condition; }
private Expression CreateStringComparison(Expression left, Expression right, DbExpressionKind kind) { var method = Expression.Call(null, StringFunctions.CompareTo, left, right); var mode = GetCompareMode(kind); Expression res = Expression.Equal(method, Expression.Constant(mode.Item1)); if (!mode.Item2) { res = Expression.Not(res); } return res; }
/// <summary> /// Creates a flat list of the associative arguments. /// For example, for ((A1 + (A2 - A3)) + A4) it will create A1, (A2 - A3), A4 /// Only 'unfolds' the given arguments that are of the given expression kind. /// </summary> /// <param name="expressionKind"></param> /// <param name="arguments"></param> /// <returns></returns> internal static IEnumerable<DbExpression> FlattenAssociativeExpression( DbExpressionKind expressionKind, params DbExpression[] arguments) { if (!_associativeExpressionKinds.Contains(expressionKind)) { return arguments; } var outputArguments = new List<DbExpression>(); foreach (var argument in arguments) { ExtractAssociativeArguments(expressionKind, outputArguments, argument); } return outputArguments; }
/// <summary> /// Helper method for FlattenAssociativeExpression. /// Creates a flat list of the associative arguments and appends to the given argument list. /// For example, for ((A1 + (A2 - A3)) + A4) it will add A1, (A2 - A3), A4 to the list. /// Only 'unfolds' the given expression if it is of the given expression kind. /// </summary> /// <param name="expressionKind"></param> /// <param name="argumentList"></param> /// <param name="expression"></param> private static void ExtractAssociativeArguments( DbExpressionKind expressionKind, List<DbExpression> argumentList, DbExpression expression) { if (expression.ExpressionKind != expressionKind) { argumentList.Add(expression); return; } //All associative expressions are binary, thus we must be dealing with a DbBinaryExpresson or // a DbArithmeticExpression with 2 arguments. var binaryExpression = expression as DbBinaryExpression; if (binaryExpression != null) { ExtractAssociativeArguments(expressionKind, argumentList, binaryExpression.Left); ExtractAssociativeArguments(expressionKind, argumentList, binaryExpression.Right); return; } var arithExpression = (DbArithmeticExpression)expression; ExtractAssociativeArguments(expressionKind, argumentList, arithExpression.Arguments[0]); ExtractAssociativeArguments(expressionKind, argumentList, arithExpression.Arguments[1]); }
/// <summary> /// Constructs a new pattern that will match an expression with the specified <see cref="DbExpressionKind"/>. /// </summary> internal static Func<DbExpression, bool> MatchKind(DbExpressionKind kindToMatch) { return (e => e.ExpressionKind == kindToMatch); }
private static Mock<DbIsNullExpression> CreatNullExpression( Mock<DbPropertyExpression> mockLeftArgumentExpression, DbExpressionKind kind) { var mockLeftExpression = new Mock<DbIsNullExpression>(); mockLeftExpression.Setup(m => m.ExpressionKind).Returns(kind); mockLeftExpression.Setup(m => m.Argument).Returns(mockLeftArgumentExpression.Object); return mockLeftExpression; }
public CombinedProjectionExpression(VisitedExpression first, DbExpressionKind setOperator, VisitedExpression second) { _first = first; _setOperator = setOperator == DbExpressionKind.UnionAll ? "UNION ALL" : setOperator == DbExpressionKind.Except ? "EXCEPT" : "INTERSECT"; _second = second; }
/// <summary> /// This method is invoked when tranforming <see cref="DbIntersectExpression"/> and <see cref="DbExceptExpression"/> by doing comparison over all input columns. /// <see cref="TransformIntersectOrExcept(DbExpression left, DbExpression right, DbExpressionKind expressionKind, IList<DbPropertyExpression> sortExpressionsOverLeft, string sortExpressionsBindingVariableName)"/> /// </summary> /// <param name="left"></param> /// <param name="right"></param> /// <param name="expressionKind"></param> /// <returns></returns> private DbExpression TransformIntersectOrExcept(DbExpression left, DbExpression right, DbExpressionKind expressionKind) { return TransformIntersectOrExcept(left, right, expressionKind, null, null); }
public NegatableBooleanExpression(DbExpressionKind booleanOperator, VisitedExpression left, VisitedExpression right) { _booleanOperator = booleanOperator; _left = left; _right = right; }
private static Mock<DbBinaryExpression> CreateMockBinaryExpression( Mock<DbPropertyExpression> mockLeftExpression, Mock<DbPropertyExpression> mockRightExpression, DbExpressionKind kind) { SetupMockArguments(mockLeftExpression, mockRightExpression); var mockBinaryExpression = new Mock<DbBinaryExpression>(); mockBinaryExpression.Setup(m => m.ExpressionKind).Returns(kind); mockBinaryExpression.Setup(m => m.Left).Returns(mockLeftExpression.Object); mockBinaryExpression.Setup(m => m.Right).Returns(mockRightExpression.Object); return mockBinaryExpression; }
private static Mock<DbExpression> CreateMockDbArgumentExpression( PrimitiveTypeKind typeKind, DbExpressionKind expressionKind, bool? isUnicode) { var mockEdmType = new Mock<PrimitiveType>(); mockEdmType.Setup(m => m.BuiltInTypeKind).Returns(BuiltInTypeKind.PrimitiveType); mockEdmType.Setup(m => m.PrimitiveTypeKind).Returns(typeKind); var mockTypeUsage = new Mock<TypeUsage>(); mockTypeUsage.Setup(m => m.EdmType).Returns(mockEdmType.Object); if (isUnicode.HasValue) { var mockFacet = new Mock<Facet>(); mockFacet.Setup(m => m.Value).Returns(isUnicode.Value); mockFacet.Setup(m => m.Identity).Returns(DbProviderManifest.UnicodeFacetName); mockTypeUsage.Setup(m => m.Facets).Returns( new ReadOnlyMetadataCollection<Facet>( new MetadataCollection<Facet> { mockFacet.Object })); } else { mockTypeUsage.Setup(m => m.Facets).Returns(new ReadOnlyMetadataCollection<Facet>(new MetadataCollection<Facet>())); } var mockExpression = new Mock<DbExpression>(); mockExpression.Setup(m => m.ResultType).Returns(mockTypeUsage.Object); mockExpression.Setup(m => m.ExpressionKind).Returns(expressionKind); return mockExpression; }
private SqlFragment HandleJoinExpression(DbExpressionBinding left, DbExpressionBinding right, DbExpressionKind joinType, DbExpression joinCondition) { JoinFragment join = new JoinFragment(); join.JoinType = Metadata.GetOperator(joinType); join.Left = VisitInputExpression(left.Expression, left.VariableName, left.VariableType); WrapJoinInputIfNecessary(join.Left, false); join.Right = VisitInputExpression(right.Expression, right.VariableName, right.VariableType); WrapJoinInputIfNecessary(join.Right, true); // now handle the ON case if (joinCondition != null) join.Condition = joinCondition.Accept(this); return join; }
/// <summary> /// This method is used for translating <see cref="DbIntersectExpression"/> and <see cref="DbExceptExpression"/>, /// and for translating the "Except" part of <see cref="DbSkipExpression"/>. /// into the follwoing expression: /// /// A INTERSECT B, A EXCEPT B /// /// (DISTINCT) /// | /// FILTER /// | /// | - Input: A /// | - Predicate:(NOT) /// | /// ANY /// | /// | - Input: B /// | - Predicate: (B.b1 = A.a1 or (B.b1 is null and A.a1 is null)) /// AND (B.b2 = A.a2 or (B.b2 is null and A.a2 is null)) /// AND ... /// AND (B.bn = A.an or (B.bn is null and A.an is null))) /// /// Here, A corresponds to right and B to left. /// (NOT) is present when transforming Except /// for the purpose of translating <see cref="DbExceptExpression"/> or <see cref="DbSkipExpression"/>. /// (DISTINCT) is present when transforming for the purpose of translating /// <see cref="DbExceptExpression"/> or <see cref="DbIntersectExpression"/>. /// /// For <see cref="DbSkipExpression"/>, the input to ANY is caped with project which projects out only /// the columns represented in the sortExpressionsOverLeft list and only these are used in the predicate. /// This is because we want to support skip over input with non-equal comarable columns and we have no way to recognize these. /// </summary> /// <param name="left"></param> /// <param name="right"></param> /// <param name="expressionKind"></param> /// <param name="sortExpressionsOverLeft">note that this list gets destroyed by this method</param> /// <param name="sortExpressionsBindingVariableName"></param> /// <returns></returns> private DbExpression TransformIntersectOrExcept( DbExpression left, DbExpression right, DbExpressionKind expressionKind, IList<DbPropertyExpression> sortExpressionsOverLeft, string sortExpressionsBindingVariableName) { var negate = (expressionKind == DbExpressionKind.Except) || (expressionKind == DbExpressionKind.Skip); var distinct = (expressionKind == DbExpressionKind.Except) || (expressionKind == DbExpressionKind.Intersect); var leftInputBinding = left.Bind(); var rightInputBinding = right.Bind(); IList<DbPropertyExpression> leftFlattenedProperties = new List<DbPropertyExpression>(); IList<DbPropertyExpression> rightFlattenedProperties = new List<DbPropertyExpression>(); FlattenProperties(leftInputBinding.Variable, leftFlattenedProperties); FlattenProperties(rightInputBinding.Variable, rightFlattenedProperties); //For Skip, we need to ignore any columns that are not in the original sort list. We can recognize these by comparing the left flattened properties and // the properties in the list sortExpressionsOverLeft // If any such columns exist, we need to add an additional project, to keep the rest of the columns from being projected, as if any among these // are non equal comparable, SQL Server 2000 throws. if (expressionKind == DbExpressionKind.Skip) { if (RemoveNonSortProperties( leftFlattenedProperties, rightFlattenedProperties, sortExpressionsOverLeft, leftInputBinding.VariableName, sortExpressionsBindingVariableName)) { rightInputBinding = CapWithProject(rightInputBinding, rightFlattenedProperties); } } Debug.Assert( leftFlattenedProperties.Count == rightFlattenedProperties.Count, "The left and the right input to INTERSECT or EXCEPT have a different number of properties"); Debug.Assert(leftFlattenedProperties.Count != 0, "The inputs to INTERSECT or EXCEPT have no properties"); //Build the predicate for the quantifier: // (B.b1 = A.a1 or (B.b1 is null and A.a1 is null)) // AND (B.b2 = A.a2 or (B.b2 is null and A.a2 is null)) // AND ... // AND (B.bn = A.an or (B.bn is null and A.an is null))) DbExpression existsPredicate = null; for (var i = 0; i < leftFlattenedProperties.Count; i++) { //A.ai == B.bi DbExpression equalsExpression = leftFlattenedProperties[i].Equal(rightFlattenedProperties[i]); //A.ai is null AND B.bi is null DbExpression leftIsNullExpression = leftFlattenedProperties[i].IsNull(); DbExpression rightIsNullExpression = rightFlattenedProperties[i].IsNull(); DbExpression bothNullExpression = leftIsNullExpression.And(rightIsNullExpression); DbExpression orExpression = equalsExpression.Or(bothNullExpression); if (i == 0) { existsPredicate = orExpression; } else { existsPredicate = existsPredicate.And(orExpression); } } //Build the quantifier DbExpression quantifierExpression = rightInputBinding.Any(existsPredicate); DbExpression filterPredicate; //Negate if needed if (negate) { filterPredicate = quantifierExpression.Not(); } else { filterPredicate = quantifierExpression; } //Build the filter DbExpression result = leftInputBinding.Filter(filterPredicate); //Apply distinct in needed if (distinct) { result = result.Distinct(); } return result; }
public SelectStatement WrapIfNotCompatible(SelectStatement select, DbExpressionKind expressionKind) { if (select.IsCompatible(expressionKind)) return select; SelectStatement newSelect = new SelectStatement(); select.Wrap(scope); newSelect.From = select; return newSelect; }
private void VisitExprKind(DbExpressionKind kind) { _key.Append('['); _key.Append(_exprKindNames[(int)kind]); _key.Append(']'); }
private Tuple<int, bool> GetCompareMode(DbExpressionKind kind) { switch (kind) { case DbExpressionKind.Equals: return Tuple.Create(0, true); case DbExpressionKind.NotEquals: return Tuple.Create(0, false); case DbExpressionKind.GreaterThan: return Tuple.Create(1, true); case DbExpressionKind.GreaterThanOrEquals: return Tuple.Create(-1, false); case DbExpressionKind.LessThan: return Tuple.Create(-1, true); case DbExpressionKind.LessThanOrEquals: return Tuple.Create(1, false); } throw new InvalidOperationException( "The ExpressionKind cannot be " + kind.ToString()); }
public bool IsCompatible(DbExpressionKind expressionKind) { switch (expressionKind) { case DbExpressionKind.Filter: return Where == null && Columns.Count == 0; case DbExpressionKind.Project: return Columns.Count == 0; case DbExpressionKind.Limit: return Limit == null; case DbExpressionKind.Skip: return Skip == null; case DbExpressionKind.Sort: return Columns.Count == 0 && GroupBy == null && OrderBy == null; case DbExpressionKind.GroupBy: return Columns.Count == 0 && GroupBy == null && OrderBy == null && Limit == null; } throw new InvalidOperationException(); }
private static Mock<DbPropertyExpression> CreateMockArgumentExpression(DbExpressionKind kind) { var mockLeftExpression = new Mock<DbPropertyExpression>(); mockLeftExpression.Setup(m => m.ExpressionKind).Returns(kind); return mockLeftExpression; }
public CombinedProjectionExpression(DbExpressionKind setOperator, List<VisitedExpression> list) { _setOperator = setOperator == DbExpressionKind.UnionAll ? "UNION ALL" : setOperator == DbExpressionKind.Except ? "EXCEPT" : "INTERSECT"; _list = list; }