2009-06-12 Bill Holmes <billholmes54@gmail.com>
[mono.git] / mcs / class / System.Data.Linq / src / DbLinq / Data / Linq / Sugar / Implementation / ExpressionQualifier.cs
1 #region MIT license\r
2 // \r
3 // MIT license\r
4 //\r
5 // Copyright (c) 2007-2008 Jiri Moudry, Pascal Craponne\r
6 // \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
13 // \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
16 // \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
23 // THE SOFTWARE.\r
24 // \r
25 #endregion\r
26 \r
27 using System.Linq.Expressions;\r
28 #if MONO_STRICT\r
29 using System.Data.Linq.Sugar;\r
30 using System.Data.Linq.Sugar.Expressions;\r
31 #else\r
32 using DbLinq.Data.Linq.Sugar;\r
33 using DbLinq.Data.Linq.Sugar.Expressions;\r
34 #endif\r
35 \r
36 #if MONO_STRICT\r
37 namespace System.Data.Linq.Sugar.Implementation\r
38 #else\r
39 namespace DbLinq.Data.Linq.Sugar.Implementation\r
40 #endif\r
41 {\r
42     internal class ExpressionQualifier : IExpressionQualifier\r
43     {\r
44         /// <summary>\r
45         /// Returns Expression precedence. Higher value means lower precedence.\r
46         /// http://en.csharp-online.net/ECMA-334:_14.2.1_Operator_precedence_and_associativity\r
47         /// We added the Clase precedence, which is the lowest\r
48         /// </summary>\r
49         /// <param name="expression"></param>\r
50         /// <returns></returns>\r
51         public ExpressionPrecedence GetPrecedence(Expression expression)\r
52         {\r
53             if (expression is SpecialExpression)\r
54             {\r
55                 var specialNodeType = ((SpecialExpression)expression).SpecialNodeType;\r
56                 switch (specialNodeType) // SETuse\r
57                 {\r
58                 case SpecialExpressionType.IsNull:\r
59                 case SpecialExpressionType.IsNotNull:\r
60                     return ExpressionPrecedence.Equality;\r
61                 case SpecialExpressionType.Concat:\r
62                     return ExpressionPrecedence.Additive;\r
63                 case SpecialExpressionType.Like:\r
64                     return ExpressionPrecedence.Equality;\r
65                 // the following are methods\r
66                 case SpecialExpressionType.Min:\r
67                 case SpecialExpressionType.Max:\r
68                 case SpecialExpressionType.Sum:\r
69                 case SpecialExpressionType.Average:\r
70                 case SpecialExpressionType.Count:\r
71                 case SpecialExpressionType.StringLength:\r
72                 case SpecialExpressionType.ToUpper:\r
73                 case SpecialExpressionType.ToLower:\r
74                 case SpecialExpressionType.Substring:\r
75                 case SpecialExpressionType.Trim:\r
76                 case SpecialExpressionType.LTrim:\r
77                 case SpecialExpressionType.RTrim:\r
78                 case SpecialExpressionType.StringInsert:\r
79                 case SpecialExpressionType.Replace:\r
80                 case SpecialExpressionType.Remove:\r
81                 case SpecialExpressionType.IndexOf:\r
82                 case SpecialExpressionType.Year:\r
83                 case SpecialExpressionType.Month:\r
84                 case SpecialExpressionType.Day:\r
85                 case SpecialExpressionType.Hour:\r
86                 case SpecialExpressionType.Minute:\r
87                 case SpecialExpressionType.Second:\r
88                 case SpecialExpressionType.Millisecond:\r
89                 case SpecialExpressionType.Now:\r
90                 case SpecialExpressionType.DateDiffInMilliseconds:\r
91                 case SpecialExpressionType.Abs:\r
92                 case SpecialExpressionType.Exp:\r
93                 case SpecialExpressionType.Floor:\r
94                 case SpecialExpressionType.Ln:\r
95                 case SpecialExpressionType.Log:\r
96                 case SpecialExpressionType.Pow:\r
97                 case SpecialExpressionType.Round:\r
98                 case SpecialExpressionType.Sign:\r
99                 case SpecialExpressionType.Sqrt:\r
100                     return ExpressionPrecedence.Primary;\r
101                 case SpecialExpressionType.In:\r
102                     return ExpressionPrecedence.Equality; // not sure for this one\r
103                 default:\r
104                     throw Error.BadArgument("S0050: Unhandled SpecialExpressionType {0}", specialNodeType);\r
105                 }\r
106             }\r
107             if (expression is SelectExpression)\r
108                 return ExpressionPrecedence.Clause;\r
109             switch (expression.NodeType)\r
110             {\r
111             case ExpressionType.Add:\r
112             case ExpressionType.AddChecked:\r
113                 return ExpressionPrecedence.Additive;\r
114             case ExpressionType.And:\r
115             case ExpressionType.AndAlso:\r
116                 return ExpressionPrecedence.ConditionalAnd;\r
117             case ExpressionType.ArrayLength:\r
118             case ExpressionType.ArrayIndex:\r
119             case ExpressionType.Call:\r
120                 return ExpressionPrecedence.Primary;\r
121             case ExpressionType.Coalesce:\r
122                 return ExpressionPrecedence.NullCoalescing;\r
123             case ExpressionType.Conditional:\r
124                 return ExpressionPrecedence.Conditional;\r
125             case ExpressionType.Constant:\r
126                 return ExpressionPrecedence.Primary;\r
127             case ExpressionType.Convert:\r
128             case ExpressionType.ConvertChecked:\r
129                 return ExpressionPrecedence.Primary;\r
130             case ExpressionType.Divide:\r
131                 return ExpressionPrecedence.Multiplicative;\r
132             case ExpressionType.Equal:\r
133                 return ExpressionPrecedence.Equality;\r
134             case ExpressionType.ExclusiveOr:\r
135                 return ExpressionPrecedence.LogicalXor;\r
136             case ExpressionType.GreaterThan:\r
137             case ExpressionType.GreaterThanOrEqual:\r
138                 return ExpressionPrecedence.RelationalAndTypeTest;\r
139             case ExpressionType.Invoke:\r
140                 return ExpressionPrecedence.Primary;\r
141             case ExpressionType.Lambda:\r
142                 return ExpressionPrecedence.Primary;\r
143             case ExpressionType.LeftShift:\r
144                 return ExpressionPrecedence.Shift;\r
145             case ExpressionType.LessThan:\r
146             case ExpressionType.LessThanOrEqual:\r
147                 return ExpressionPrecedence.RelationalAndTypeTest;\r
148             case ExpressionType.ListInit:\r
149             case ExpressionType.MemberAccess:\r
150             case ExpressionType.MemberInit:\r
151                 return ExpressionPrecedence.Primary;\r
152             case ExpressionType.Modulo:\r
153             case ExpressionType.Multiply:\r
154             case ExpressionType.MultiplyChecked:\r
155                 return ExpressionPrecedence.Multiplicative;\r
156             case ExpressionType.Negate:\r
157             case ExpressionType.UnaryPlus:\r
158             case ExpressionType.NegateChecked:\r
159                 return ExpressionPrecedence.Unary;\r
160             case ExpressionType.New:\r
161             case ExpressionType.NewArrayInit:\r
162             case ExpressionType.NewArrayBounds:\r
163                 return ExpressionPrecedence.Primary;\r
164             case ExpressionType.Not:\r
165                 return ExpressionPrecedence.Unary;\r
166             case ExpressionType.NotEqual:\r
167                 return ExpressionPrecedence.Equality;\r
168             case ExpressionType.Or:\r
169             case ExpressionType.OrElse:\r
170                 return ExpressionPrecedence.ConditionalOr;\r
171             case ExpressionType.Parameter:\r
172                 return ExpressionPrecedence.Primary;\r
173             case ExpressionType.Power:\r
174                 return ExpressionPrecedence.Primary;\r
175             case ExpressionType.Quote:\r
176                 return ExpressionPrecedence.Primary;\r
177             case ExpressionType.RightShift:\r
178                 return ExpressionPrecedence.Shift;\r
179             case ExpressionType.Subtract:\r
180             case ExpressionType.SubtractChecked:\r
181                 return ExpressionPrecedence.Additive;\r
182             case ExpressionType.TypeAs:\r
183             case ExpressionType.TypeIs:\r
184                 return ExpressionPrecedence.RelationalAndTypeTest;\r
185             }\r
186             return ExpressionPrecedence.Primary;\r
187         }\r
188 \r
189         /// <summary>\r
190         /// Determines wether an expression can run in Clr or Sql\r
191         /// A request is valid is it starts with Clr only, followed by Any and ends (at bottom) with Sql.\r
192         /// With this, we can:\r
193         /// - Find the first point cut from Clr to Any\r
194         /// - Find the second point cut from Any to Sql\r
195         /// Select a strategy to load more or less the Clr or Sql engine\r
196         /// This is used only for SELECT clause\r
197         /// </summary>\r
198         /// <param name="expression"></param>\r
199         /// <returns></returns>\r
200         public ExpressionTier GetTier(Expression expression)\r
201         {\r
202             if (expression is GroupExpression)\r
203                 return ExpressionTier.Clr;\r
204             if (expression is SelectExpression)\r
205                 return ExpressionTier.Sql;\r
206             if (expression is ColumnExpression)\r
207                 return ExpressionTier.Sql;\r
208             if (expression is TableExpression)\r
209                 return ExpressionTier.Sql;\r
210             if (expression is EntitySetExpression)\r
211                 return ExpressionTier.Sql;\r
212             if (expression is InputParameterExpression)\r
213                 return ExpressionTier.Sql;\r
214             if (expression is SpecialExpression)\r
215             {\r
216                 var specialExpressionType = ((SpecialExpression)expression).SpecialNodeType;\r
217                 switch (specialExpressionType) // SETuse\r
218                 {\r
219                 case SpecialExpressionType.IsNull:\r
220                 case SpecialExpressionType.IsNotNull:\r
221                 case SpecialExpressionType.Concat:\r
222                 case SpecialExpressionType.StringLength:\r
223                 case SpecialExpressionType.ToUpper:\r
224                 case SpecialExpressionType.ToLower:\r
225                 case SpecialExpressionType.Substring:\r
226                 case SpecialExpressionType.Trim:\r
227                 case SpecialExpressionType.LTrim:\r
228                 case SpecialExpressionType.RTrim:\r
229                 case SpecialExpressionType.StringInsert:\r
230                 case SpecialExpressionType.Replace:\r
231                 case SpecialExpressionType.Remove:\r
232                 case SpecialExpressionType.IndexOf:\r
233                 case SpecialExpressionType.Year:\r
234                 case SpecialExpressionType.Month:\r
235                 case SpecialExpressionType.Day:\r
236                 case SpecialExpressionType.Hour:\r
237                 case SpecialExpressionType.Minute:\r
238                 case SpecialExpressionType.Second:\r
239                 case SpecialExpressionType.Millisecond:\r
240                 case SpecialExpressionType.Now:\r
241                 case SpecialExpressionType.DateDiffInMilliseconds:\r
242                 case SpecialExpressionType.Abs:\r
243                 case SpecialExpressionType.Exp:\r
244                 case SpecialExpressionType.Floor:\r
245                 case SpecialExpressionType.Ln:\r
246                 case SpecialExpressionType.Log:\r
247                 case SpecialExpressionType.Pow:\r
248                 case SpecialExpressionType.Round:\r
249                 case SpecialExpressionType.Sign:\r
250                 case SpecialExpressionType.Sqrt:\r
251                     return ExpressionTier.Any;\r
252 \r
253                 case SpecialExpressionType.Like:\r
254                 case SpecialExpressionType.Min:\r
255                 case SpecialExpressionType.Max:\r
256                 case SpecialExpressionType.Sum:\r
257                 case SpecialExpressionType.Average:\r
258                 case SpecialExpressionType.Count:\r
259                 case SpecialExpressionType.In:\r
260                     return ExpressionTier.Sql; // don't tell anyone, but we can do it on both tiers, anyway this is significantly faster/efficient in SQL anyway\r
261                 default:\r
262                     throw Error.BadArgument("S0157: Unhandled node type {0}", specialExpressionType);\r
263                 }\r
264             }\r
265             switch (expression.NodeType)\r
266             {\r
267             case ExpressionType.ArrayLength:\r
268             case ExpressionType.ArrayIndex:\r
269             case ExpressionType.Call:\r
270             case ExpressionType.Convert:\r
271             case ExpressionType.ConvertChecked:\r
272             case ExpressionType.Invoke:\r
273             case ExpressionType.Lambda:\r
274             case ExpressionType.ListInit:\r
275             case ExpressionType.MemberAccess:\r
276             case ExpressionType.MemberInit:\r
277             case ExpressionType.New:\r
278             case ExpressionType.NewArrayInit:\r
279             case ExpressionType.NewArrayBounds:\r
280             case ExpressionType.Parameter:\r
281             case ExpressionType.SubtractChecked:\r
282             case ExpressionType.TypeAs:\r
283             case ExpressionType.TypeIs:\r
284                 return ExpressionTier.Clr;\r
285             default:\r
286                 return ExpressionTier.Any;\r
287             }\r
288         }\r
289     }\r
290 }