5 // Copyright (c) 2007-2008 Jiri Moudry, Pascal Craponne
\r
7 // Permission is hereby granted, free of charge, to any person obtaining a copy
\r
8 // of this software and associated documentation files (the "Software"), to deal
\r
9 // in the Software without restriction, including without limitation the rights
\r
10 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
\r
11 // copies of the Software, and to permit persons to whom the Software is
\r
12 // furnished to do so, subject to the following conditions:
\r
14 // The above copyright notice and this permission notice shall be included in
\r
15 // all copies or substantial portions of the Software.
\r
17 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
\r
18 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
\r
19 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
\r
20 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
\r
21 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
\r
22 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
\r
29 using System.Linq.Expressions;
\r
32 using System.Data.Linq.Sugar;
\r
33 using System.Data.Linq.Sugar.ExpressionMutator;
\r
34 using System.Data.Linq.Sugar.Expressions;
\r
36 using DbLinq.Data.Linq.Sugar;
\r
37 using DbLinq.Data.Linq.Sugar.ExpressionMutator;
\r
38 using DbLinq.Data.Linq.Sugar.Expressions;
\r
42 namespace System.Data.Linq.Sugar.Implementation
\r
44 namespace DbLinq.Data.Linq.Sugar.Implementation
\r
48 /// Optimizes expressions (such as constant chains)
\r
50 internal class ExpressionOptimizer : IExpressionOptimizer
\r
52 public virtual Expression Optimize(Expression expression, BuilderContext builderContext)
\r
54 return expression.Recurse(e => Analyze(e, builderContext));
\r
57 protected Expression Analyze(Expression expression, BuilderContext builderContext)
\r
59 // small optimization
\r
60 if (expression is ConstantExpression)
\r
63 expression = AnalyzeNull(expression, builderContext);
\r
64 expression = AnalyzeNot(expression, builderContext);
\r
65 // constant optimization at last, because the previous optimizations may generate constant expressions
\r
66 expression = AnalyzeConstant(expression, builderContext);
\r
70 protected virtual Expression AnalyzeConstant(Expression expression, BuilderContext builderContext)
\r
72 // we try to find a non-constant operand, and if we do, we won't change this expression
\r
73 foreach (var operand in expression.GetOperands())
\r
75 if (!(operand is ConstantExpression))
\r
78 if (expression is ColumnExpression)
\r
80 if (expression is TableExpression)
\r
82 if (expression is ParameterExpression)
\r
84 // now, we just simply return a constant with new value
\r
87 var optimizedExpression = Expression.Constant(expression.Evaluate());
\r
88 // sometimes, optimizing an expression changes its type, and we just can't allow this.
\r
89 if (optimizedExpression.Type == expression.Type)
\r
90 return optimizedExpression;
\r
92 // if we fail to evaluate the expression, then just return it
\r
93 catch (ArgumentException) { }
\r
97 protected virtual Expression AnalyzeNot(Expression expression, BuilderContext builderContext)
\r
99 if (expression.NodeType == ExpressionType.Not)
\r
101 var notExpression = expression as UnaryExpression;
\r
102 var subExpression = notExpression.Operand;
\r
103 var subOperands = subExpression.GetOperands().ToList();
\r
104 switch (subExpression.NodeType)
\r
106 case ExpressionType.Equal:
\r
107 return Expression.NotEqual(subOperands[0], subOperands[1]);
\r
108 case ExpressionType.GreaterThan:
\r
109 return Expression.LessThanOrEqual(subOperands[0], subOperands[1]);
\r
110 case ExpressionType.GreaterThanOrEqual:
\r
111 return Expression.LessThan(subOperands[0], subOperands[1]);
\r
112 case ExpressionType.LessThan:
\r
113 return Expression.GreaterThanOrEqual(subOperands[0], subOperands[1]);
\r
114 case ExpressionType.LessThanOrEqual:
\r
115 return Expression.GreaterThan(subOperands[0], subOperands[1]);
\r
116 case ExpressionType.Not:
\r
117 return subOperands[0]; // not not x -> x :)
\r
118 case ExpressionType.NotEqual:
\r
119 return Expression.Equal(subOperands[0], subOperands[1]);
\r
120 case (ExpressionType)SpecialExpressionType.IsNotNull: // is this dirty work?
\r
121 return new SpecialExpression(SpecialExpressionType.IsNull, subOperands);
\r
122 case (ExpressionType)SpecialExpressionType.IsNull:
\r
123 return new SpecialExpression(SpecialExpressionType.IsNotNull, subOperands);
\r
129 protected virtual Expression AnalyzeNull(Expression expression, BuilderContext builderContext)
\r
131 // this first test only to speed up things a little
\r
132 if (expression.NodeType == ExpressionType.Equal || expression.NodeType == ExpressionType.NotEqual)
\r
134 var operands = expression.GetOperands().ToList();
\r
135 var nullComparison = GetNullComparison(expression.NodeType, operands[0], operands[1]);
\r
136 if (nullComparison == null)
\r
137 nullComparison = GetNullComparison(expression.NodeType, operands[1], operands[0]);
\r
138 if (nullComparison != null)
\r
139 return nullComparison;
\r
145 protected virtual Expression GetNullComparison(ExpressionType nodeType, Expression columnExpression, Expression nullExpression)
\r
147 if (columnExpression is ColumnExpression || columnExpression is InputParameterExpression)
\r
149 if (nullExpression is ConstantExpression && ((ConstantExpression)nullExpression).Value == null)
\r
153 case ExpressionType.Equal:
\r
154 return new SpecialExpression(SpecialExpressionType.IsNull, columnExpression);
\r
155 case ExpressionType.NotEqual:
\r
156 return new SpecialExpression(SpecialExpressionType.IsNotNull, columnExpression);
\r