Пример #1
0
		public Filter(QueryNode target, params LambdaExpression[] conditions)
			: base(target)
		{
			Debug.Assert(target != null);
			foreach (LambdaExpression l in conditions) {
				Debug.Assert(l.Parameters.Count == 1);
			}
			this.Conditions = Array.AsReadOnly(conditions);
		}
Пример #2
0
		public Sort(QueryNode target, IList<SortArgument> args)
			: base(target)
		{
			this.arguments = new ReadOnlyCollection<SortArgument>(args);
		}
Пример #3
0
		protected QueryNode(QueryNode target)
		{
			this.Target = target;
		}
Пример #4
0
		public MergeByName(QueryNode target)
			: base(target)
		{
			Debug.Assert(target != null);
		}
            protected override Expression VisitMethodCall(MethodCallExpression node)
            {
                if (node.Method == KnownMembers.QueryableOfCallTreeNode_Select && node.Arguments[1].NodeType == ExpressionType.Quote)
                {
                    // CallTreeNode[].Select:
                    // selects are not supported by query evaluator, but we will detect and remove
                    // degenerate selects (.Select(x => x)).
                    UnaryExpression quote = (UnaryExpression)node.Arguments[1];
                    if (quote.Operand.NodeType == ExpressionType.Lambda)
                    {
                        LambdaExpression lambda = (LambdaExpression)quote.Operand;
                        if (lambda.Parameters.Count == 1 && lambda.Body == lambda.Parameters[0])
                        {
                            return(Visit(node.Arguments[0]));
                        }
                    }
                }
                else if (node.Method == KnownMembers.QueryableOfCallTreeNode_Where && node.Arguments[1].NodeType == ExpressionType.Quote)
                {
                    // CallTreeNode[].Where:
                    // if the target is a QueryNode and the condition can be safely imported, convert the Where call to Filter
                    UnaryExpression quote = (UnaryExpression)node.Arguments[1];
                    if (quote.Operand.NodeType == ExpressionType.Lambda)
                    {
                        LambdaExpression lambda = (LambdaExpression)quote.Operand;
                        if (lambda.Parameters.Count == 1)
                        {
                            QueryNode target = Visit(node.Arguments[0]) as QueryNode;
                            if (target != null)
                            {
                                SafeExpressionImporter  importer   = new SafeExpressionImporter(lambda.Parameters[0]);
                                List <LambdaExpression> conditions = new List <LambdaExpression>();
                                if (importer.AddConditionsToFilterList(lambda.Body, conditions))
                                {
                                    return(new Filter(target, conditions.ToArray()));
                                }
                            }
                        }
                    }
                }
                else if (node.Method == KnownMembers.Queryable_WithQueryLog && node.Arguments[1].NodeType == ExpressionType.Constant)
                {
                    options.AddLogger((TextWriter)(((ConstantExpression)node.Arguments[1]).Value));
                    return(Visit(node.Arguments[0]));
                }
                else if (node.Method == KnownMembers.Queryable_MergeByName)
                {
                    QueryNode target = Visit(node.Arguments[0]) as QueryNode;
                    if (target != null)
                    {
                        return(new MergeByName(target));
                    }
                }
                else if (node.Method == KnownMembers.QueryableOfCallTreeNode_Take && node.Arguments[1].NodeType == ExpressionType.Constant)
                {
                    ConstantExpression ce = (ConstantExpression)node.Arguments[1];
                    if (ce.Type == typeof(int))
                    {
                        QueryNode target = Visit(node.Arguments[0]) as QueryNode;
                        if (target != null)
                        {
                            return(new Limit(target, 0, (int)ce.Value));
                        }
                    }
                }
                else if (IsGenericMethodInfoOfCallTreeNode(node, KnownMembers.Queryable_OrderBy) ||
                         IsGenericMethodInfoOfCallTreeNode(node, KnownMembers.Queryable_OrderByDesc))
                {
                    SortArgument sortArgument = GetSortArgumentFromSortCall(node);
                    if (sortArgument != null)
                    {
                        QueryNode target = Visit(node.Arguments[0]) as QueryNode;
                        if (target != null)
                        {
                            return(new Sort(target, new [] { sortArgument }));
                        }
                    }
                }
                else if (IsThenByCall(node))
                {
                    // 'ThenBy' is dangerous: we must not translate an OrderBy inside a ThenBy that we do not support
                    List <MethodCallExpression> thenByCalls = new List <MethodCallExpression>();
                    Expression tmp = node;
                    while (IsThenByCall(tmp))
                    {
                        thenByCalls.Add((MethodCallExpression)tmp);
                        tmp = ((MethodCallExpression)tmp).Arguments[0];
                    }
                    MethodCallExpression mc = tmp as MethodCallExpression;
                    if (mc != null &&
                        (IsGenericMethodInfoOfCallTreeNode(mc, KnownMembers.Queryable_OrderBy) ||
                         IsGenericMethodInfoOfCallTreeNode(mc, KnownMembers.Queryable_OrderByDesc)))
                    {
                        // TODO: add support for safe expressions in ThenBy

                        // this is an unsupported OrderBy/ThenBy sequence
                        // skip visiting the sequence and go directly into the base object
                        tmp = Visit(mc.Arguments[0]);
                        // now reconstruct the OrderBy/ThenBy sequence
                        tmp = Expression.Call(mc.Method, new[] { tmp }.Concat(mc.Arguments.Skip(1)));                         // reconstruct OrderBy
                        for (int i = thenByCalls.Count - 1; i >= 0; i--)
                        {
                            // reconstruct ThenBy
                            tmp = Expression.Call(thenByCalls[i].Method, new[] { tmp }.Concat(thenByCalls[i].Arguments.Skip(1)));
                        }
                        return(tmp);
                    }
                    // else: we couldn't detect the OrderBy belonging to this ThenBy; so it's probably not one
                    // of the OrderBy overloads that we support. Go down recursively
                }
                return(base.VisitMethodCall(node));
            }
Пример #6
0
		public Limit(QueryNode target, int start, int length)
			: base(target)
		{
			this.Start = start;
			this.Length = length;
		}
Пример #7
0
 public Sort(QueryNode target, IList <SortArgument> args)
     : base(target)
 {
     this.arguments = new ReadOnlyCollection <SortArgument>(args);
 }
 public IQueryable <CallTreeNode> CreateQuery(QueryNode query)
 {
     return(new Query <CallTreeNode>(this, query));
 }
Пример #9
0
 protected QueryNode(QueryNode target)
 {
     this.Target = target;
 }
		QueryNode Visit(QueryNode queryNode)
		{
			return (QueryNode)base.Visit(queryNode);
		}
Пример #11
0
		public IQueryable<CallTreeNode> CreateQuery(QueryNode query)
		{
			return new Query<CallTreeNode>(this, query);
		}
Пример #12
0
 public MergeByName(QueryNode target)
     : base(target)
 {
     Debug.Assert(target != null);
 }
Пример #13
0
 public Limit(QueryNode target, int start, int length)
     : base(target)
 {
     this.Start  = start;
     this.Length = length;
 }
 QueryNode Visit(QueryNode queryNode)
 {
     return((QueryNode)base.Visit(queryNode));
 }
        QueryNode VisitMergeByName(MergeByName merge)
        {
            // First optimize the Target expression
            QueryNode target = Visit(merge.Target);

            if (target is MergeByName)
            {
                // x.MergeByName().MergeByName() -> x.MergeByName()
                return(target);
            }
            if (target == AllCalls.Instance)
            {
                // AllCalls.MergeByName() -> AllFunctions
                return(new AllFunctions());
            }
            if (target is Filter && target.Target == AllCalls.Instance)
            {
                // AllCalls.Filter(criteria).MergeByName() -> AllFunctions.Filter(criteria)
                // If criteria accesses no CallTreeNode properties except for NameMapping.
                // Criteria of the form 'start <= c.DataSetID && c.DataSetID <= end' will be converted into AllFunctions(start,end)
                List <LambdaExpression> newConditions = new List <LambdaExpression>();
                bool allIsSafe      = true;
                int  startDataSetID = -1;
                int  endDataSetID   = -1;
                foreach (LambdaExpression condition in ((Filter)target).Conditions)
                {
                    if (IsConditionSafeVisitor.Test(condition, SafeMembersForMoveIntoMergeByName))
                    {
                        newConditions.Add(condition);
                    }
                    else if (condition.Body.NodeType == ExpressionType.AndAlso && startDataSetID < 0)
                    {
                        // try match 'constant <= c.DataSetID && c.DataSetID <= constant', but only if we
                        // haven't found it already (startDataSetID is still -1)
                        BinaryExpression bin = (BinaryExpression)condition.Body;
                        if (bin.Left.NodeType == ExpressionType.LessThanOrEqual && bin.Right.NodeType == ExpressionType.LessThanOrEqual)
                        {
                            BinaryExpression left  = (BinaryExpression)bin.Left;
                            BinaryExpression right = (BinaryExpression)bin.Right;
                            if (left.Left.NodeType == ExpressionType.Constant && left.Right.NodeType == ExpressionType.MemberAccess &&
                                right.Left.NodeType == ExpressionType.MemberAccess && right.Right.NodeType == ExpressionType.Constant &&
                                ((MemberExpression)left.Right).Member == SingleCall.DataSetIdField &&
                                ((MemberExpression)right.Left).Member == SingleCall.DataSetIdField)
                            {
                                startDataSetID = (int)GetConstantValue(left.Left);
                                endDataSetID   = (int)GetConstantValue(right.Right);
                            }
                            else
                            {
                                allIsSafe = false;
                            }
                        }
                        else
                        {
                            allIsSafe = false;
                        }
                    }
                    else
                    {
                        allIsSafe = false;
                    }
                }
                if (allIsSafe)
                {
                    if (newConditions.Count > 0)
                    {
                        return(new Filter(new AllFunctions(startDataSetID, endDataSetID), newConditions.ToArray()));
                    }
                    else
                    {
                        return(new AllFunctions(startDataSetID, endDataSetID));
                    }
                }
            }
            return(new MergeByName(target));
        }