protected override Expression VisitExtension(Expression node) { Filter filter = node as Filter; MergeByName mergeByName = node as MergeByName; if (filter != null) { return(VisitFilter(filter)); } else if (mergeByName != null) { return(VisitMergeByName(mergeByName)); } else { return(base.VisitExtension(node)); } }
/// <summary> /// Tries to combine nested filters; /// move 'MergeByName' nodes out of filter, if possible /// </summary> QueryNode ReorderFilter(Filter filter) { if (filter.Target is Filter) { // x.Filter(y).Filter(z) -> x.Filter(y && z) Filter innerFilter = (Filter)filter.Target; return ReorderFilter(new Filter(innerFilter.Target, innerFilter.Conditions.Concat(filter.Conditions).ToArray())); } else if (filter.Target is MergeByName) { // x.MergeByName().Filter(<criteria>) -> x.Filter(x, <criteria>).MergeByName() for some safe criterias QueryNode innerTarget = filter.Target.Target; var conditionsToMoveIntoFilter = filter.Conditions.Where(c => IsConditionSafeVisitor.Test(c, SafeMembersForMoveIntoMergeByName)).ToArray(); if (conditionsToMoveIntoFilter.Length != 0) { MergeByName newTarget = new MergeByName(ReorderFilter(new Filter(innerTarget, conditionsToMoveIntoFilter))); var conditionsKeptOutsideFilter = filter.Conditions.Except(conditionsToMoveIntoFilter).ToArray(); if (conditionsKeptOutsideFilter.Length == 0) return newTarget; else return new Filter(newTarget, conditionsKeptOutsideFilter); } else { return filter; } } else { return filter; } }
/// <summary> /// Tries to combine nested filters; /// move 'MergeByName' nodes out of filter, if possible /// </summary> QueryNode ReorderFilter(Filter filter) { if (filter.Target is Filter) { // x.Filter(y).Filter(z) -> x.Filter(y && z) Filter innerFilter = (Filter)filter.Target; return(ReorderFilter(new Filter(innerFilter.Target, innerFilter.Conditions.Concat(filter.Conditions).ToArray()))); } else if (filter.Target is MergeByName) { // x.MergeByName().Filter(<criteria>) -> x.Filter(x, <criteria>).MergeByName() for some safe criterias QueryNode innerTarget = filter.Target.Target; var conditionsToMoveIntoFilter = filter.Conditions.Where(c => IsConditionSafeVisitor.Test(c, SafeMembersForMoveIntoMergeByName)).ToArray(); if (conditionsToMoveIntoFilter.Length != 0) { MergeByName newTarget = new MergeByName(ReorderFilter(new Filter(innerTarget, conditionsToMoveIntoFilter))); var conditionsKeptOutsideFilter = filter.Conditions.Except(conditionsToMoveIntoFilter).ToArray(); if (conditionsKeptOutsideFilter.Length == 0) { return(newTarget); } else { return(new Filter(newTarget, conditionsKeptOutsideFilter)); } } else { return(filter); } } else { return(filter); } }
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); }
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)); }