Updates referencesource to .NET 4.7
[mono.git] / mcs / class / referencesource / System.Data / System / Data / Filter / BinaryNode.cs
1 //------------------------------------------------------------------------------
2 // <copyright file="BinaryNode.cs" company="Microsoft">
3 //     Copyright (c) Microsoft Corporation.  All rights reserved.
4 // </copyright>
5 // <owner current="true" primary="true">Microsoft</owner>
6 // <owner current="true" primary="false">Microsoft</owner>
7 // <owner current="false" primary="false">Microsoft</owner>
8 //------------------------------------------------------------------------------
9
10 namespace System.Data {
11     using System;
12     using System.Diagnostics;
13     using System.Collections.Generic;
14     using System.Globalization;
15     using System.ComponentModel;
16     using System.Data.SqlTypes;
17     using System.Data.Common;
18
19     internal class BinaryNode : ExpressionNode {
20         internal int op;
21
22         internal ExpressionNode left;
23         internal ExpressionNode right;
24
25         internal BinaryNode(DataTable table, int op, ExpressionNode left, ExpressionNode right) : base(table) {
26             this.op = op;
27             this.left = left;
28             this.right = right;
29         }
30
31         internal override void Bind(DataTable table, List<DataColumn> list) {
32             BindTable(table);
33             left.Bind(table, list);
34             right.Bind(table, list);
35         }
36
37         internal override object Eval() {
38             return Eval(null, DataRowVersion.Default);
39         }
40
41         internal override object Eval(DataRow row, DataRowVersion version) {
42             return EvalBinaryOp(op, left, right, row, version, null);
43         }
44
45         internal override object Eval(int[] recordNos) {
46             return EvalBinaryOp(op, left, right, null, DataRowVersion.Default, recordNos);
47         }
48
49         internal override bool IsConstant() {
50             // 
51             return(left.IsConstant() && right.IsConstant());
52         }
53
54         internal override bool IsTableConstant() {
55             return(left.IsTableConstant() && right.IsTableConstant());
56         }
57         internal override bool HasLocalAggregate() {
58             return(left.HasLocalAggregate() || right.HasLocalAggregate());
59         }
60         
61         internal override bool HasRemoteAggregate() {
62             return(left.HasRemoteAggregate() || right.HasRemoteAggregate());
63         }
64
65         internal override bool DependsOn(DataColumn column) {
66             if (left.DependsOn(column))
67                 return true;
68             return right.DependsOn(column);
69         }
70
71         internal override ExpressionNode Optimize() {
72             left = left.Optimize();
73
74             if (op == Operators.Is) {
75                 // only 'Is Null' or 'Is Not Null' are valid
76                 if (right is UnaryNode) {
77                     UnaryNode un = (UnaryNode)right;
78                     if (un.op != Operators.Not) {
79                         throw ExprException.InvalidIsSyntax();
80                     }
81                     op = Operators.IsNot;
82                     right = un.right;
83                 }
84                 if (right is ZeroOpNode) {
85                     if (((ZeroOpNode)right).op != Operators.Null) {
86                         throw ExprException.InvalidIsSyntax();
87                     }
88                 }
89                 else {
90                     throw ExprException.InvalidIsSyntax();
91                 }
92             }
93             else {
94                 right = right.Optimize();
95             }
96
97
98             if (this.IsConstant()) {
99
100                 object val = this.Eval();
101
102                 if (val == DBNull.Value) {
103                     return new ZeroOpNode(Operators.Null);
104                 }
105
106                 if (val is bool) {
107                     if ((bool)val)
108                         return new ZeroOpNode(Operators.True);
109                     else
110                         return new ZeroOpNode(Operators.False);
111                 }
112                 return new ConstNode(table, ValueType.Object, val, false);
113             }
114             else
115                 return this;
116         }
117
118         internal void SetTypeMismatchError(int op, Type left, Type right) {
119             throw ExprException.TypeMismatchInBinop(op, left, right);
120         }
121
122         private static object Eval(ExpressionNode expr, DataRow row, DataRowVersion version, int[] recordNos) {
123             if (recordNos == null) {
124                 return expr.Eval(row, version);
125             }
126             else {
127                 return expr.Eval(recordNos);
128             }
129         }
130
131         internal int BinaryCompare(object vLeft, object vRight, StorageType resultType, int op) {
132             return BinaryCompare(vLeft, vRight, resultType, op, null);
133         }
134
135         internal int BinaryCompare(object vLeft, object vRight, StorageType resultType, int op, CompareInfo comparer) {
136             int result = 0;
137             try {
138                 if (!DataStorage.IsSqlType(resultType)) {
139                     switch(resultType) {
140                     case StorageType.SByte:
141                     case StorageType.Int16:
142                     case StorageType.Int32:
143                     case StorageType.Byte:
144                     case StorageType.UInt16:
145                         return Convert.ToInt32(vLeft, FormatProvider).CompareTo(Convert.ToInt32(vRight, FormatProvider));
146                     case StorageType.Int64:
147                     case StorageType.UInt32:
148                     case StorageType.UInt64:
149                     case StorageType.Decimal:
150                         return Decimal.Compare(Convert.ToDecimal(vLeft, FormatProvider), Convert.ToDecimal(vRight, FormatProvider));
151                     case StorageType.Char:
152                         return Convert.ToInt32(vLeft, FormatProvider).CompareTo(Convert.ToInt32(vRight, FormatProvider));
153                     case StorageType.Double:
154                         return Convert.ToDouble(vLeft, FormatProvider).CompareTo(Convert.ToDouble(vRight, FormatProvider));
155                     case StorageType.Single:
156                         return Convert.ToSingle(vLeft, FormatProvider).CompareTo(Convert.ToSingle(vRight, FormatProvider));
157                     case StorageType.DateTime:
158                         return DateTime.Compare(Convert.ToDateTime(vLeft, FormatProvider), Convert.ToDateTime(vRight, FormatProvider));
159                     case StorageType.DateTimeOffset:
160                         // DTO can only be compared to DTO, other cases: cast Exception
161                         return DateTimeOffset.Compare((DateTimeOffset)vLeft, (DateTimeOffset)vRight);
162                     case StorageType.String:
163                         return table.Compare(Convert.ToString(vLeft, FormatProvider), Convert.ToString(vRight, FormatProvider), comparer);
164                     case StorageType.Guid:
165                         return ((Guid)vLeft).CompareTo((Guid) vRight);
166                     case StorageType.Boolean:
167                         if (op == Operators.EqualTo || op == Operators.NotEqual) {
168                             return Convert.ToInt32(DataExpression.ToBoolean(vLeft), FormatProvider) -
169                                    Convert.ToInt32(DataExpression.ToBoolean(vRight), FormatProvider);
170                         }
171                         break;
172                     }
173                 }
174                 else{
175                     switch(resultType) {
176                     case StorageType.SByte:
177                     case StorageType.Int16:
178                     case StorageType.Int32:
179                     case StorageType.Byte:
180                     case StorageType.UInt16:
181                     case StorageType.SqlByte:
182                     case StorageType.SqlInt16:
183                     case StorageType.SqlInt32:
184                         return SqlConvert.ConvertToSqlInt32(vLeft).CompareTo(SqlConvert.ConvertToSqlInt32(vRight));
185                     case StorageType.Int64:
186                     case StorageType.UInt32:
187                     case StorageType.SqlInt64:
188                         return SqlConvert.ConvertToSqlInt64(vLeft).CompareTo(SqlConvert.ConvertToSqlInt64(vRight));
189                     case StorageType.UInt64:
190                     case StorageType.SqlDecimal:
191                         return SqlConvert.ConvertToSqlDecimal(vLeft).CompareTo(SqlConvert.ConvertToSqlDecimal(vRight));
192                     case StorageType.SqlDouble:
193                         return SqlConvert.ConvertToSqlDouble(vLeft).CompareTo(SqlConvert.ConvertToSqlDouble(vRight));
194                     case StorageType.SqlSingle:
195                         return SqlConvert.ConvertToSqlSingle(vLeft).CompareTo(SqlConvert.ConvertToSqlSingle(vRight));
196                     case StorageType.SqlString:
197                         return table.Compare(vLeft.ToString(), vRight.ToString());
198                     case StorageType.SqlGuid:
199                         return ((SqlGuid)vLeft).CompareTo(vRight);
200                     case StorageType.SqlBoolean:
201                         if (op == Operators.EqualTo || op == Operators.NotEqual) {
202                             result = 1;
203                             if (((vLeft.GetType() == typeof(SqlBoolean)) && ((vRight.GetType() == typeof(SqlBoolean))|| (vRight.GetType() == typeof(Boolean))))||
204                                 ((vRight.GetType() == typeof(SqlBoolean)) && ((vLeft.GetType() == typeof(SqlBoolean))|| (vLeft.GetType() == typeof(Boolean))))){
205                                 return SqlConvert.ConvertToSqlBoolean(vLeft).CompareTo(SqlConvert.ConvertToSqlBoolean(vRight));
206                             }
207                         }
208                         break;
209                     case StorageType.SqlBinary:
210                         return SqlConvert.ConvertToSqlBinary(vLeft).CompareTo(SqlConvert.ConvertToSqlBinary(vRight));
211                     case StorageType.SqlDateTime:
212                         return SqlConvert.ConvertToSqlDateTime(vLeft).CompareTo(SqlConvert.ConvertToSqlDateTime(vRight));
213                     case StorageType.SqlMoney:
214                         return SqlConvert.ConvertToSqlMoney(vLeft).CompareTo(SqlConvert.ConvertToSqlMoney(vRight));
215                     }
216                 }
217             }
218             catch (System.ArgumentException e) {
219                 ExceptionBuilder.TraceExceptionWithoutRethrow(e);
220             }
221             catch (System.FormatException e) {
222                 ExceptionBuilder.TraceExceptionWithoutRethrow(e);
223             }
224             catch (System.InvalidCastException e) {
225                 ExceptionBuilder.TraceExceptionWithoutRethrow(e);
226             }
227             catch (System.OverflowException e) {
228                 ExceptionBuilder.TraceExceptionWithoutRethrow(e);
229             }
230             catch (System.Data.EvaluateException e) {
231                 ExceptionBuilder.TraceExceptionWithoutRethrow(e);
232             }
233             SetTypeMismatchError(op, vLeft.GetType(), vRight.GetType());
234             return result;
235         }
236
237         private object EvalBinaryOp(int op, ExpressionNode left, ExpressionNode right, DataRow row, DataRowVersion version, int[] recordNos) {
238             object vLeft;
239             object vRight;
240             StorageType resultType;
241
242             /*
243             special case for OR and AND operators: we don't want to evaluate
244             both right and left operands, because we can shortcut :
245                 for OR  operator If one of the operands is true the result is true
246                 for AND operator If one of rhe operands is flase the result is false
247             
248 */
249
250             if (op != Operators.Or && op != Operators.And && op != Operators.In && op != Operators.Is && op != Operators.IsNot) {
251                 vLeft  = BinaryNode.Eval(left, row, version, recordNos);
252                 vRight = BinaryNode.Eval(right, row, version, recordNos);               
253                 Type typeofLeft  = vLeft.GetType();
254                 Type typeofRight = vRight.GetType();
255
256                 StorageType leftStorage  = DataStorage.GetStorageType(typeofLeft);
257                 StorageType rightStorage = DataStorage.GetStorageType(typeofRight);
258                  
259                 bool leftIsSqlType = DataStorage.IsSqlType(leftStorage);
260                 bool rightIsSqlType = DataStorage.IsSqlType(rightStorage);
261
262                 //    special case of handling NULLS, currently only OR operator can work with NULLS
263                 if (leftIsSqlType && DataStorage.IsObjectSqlNull(vLeft)) {
264                     return vLeft;
265                 }
266                 else if (rightIsSqlType && DataStorage.IsObjectSqlNull(vRight)) {
267                     return vRight;
268                 }
269                 else if ((vLeft == DBNull.Value)||(vRight == DBNull.Value)) {
270                     return DBNull.Value;
271                 }
272
273                 if (leftIsSqlType || rightIsSqlType) {
274                      resultType = ResultSqlType(leftStorage, rightStorage, (left is ConstNode), (right is ConstNode), op);
275                 }
276                 else {
277                      resultType = ResultType(leftStorage, rightStorage, (left is ConstNode), (right is ConstNode), op);
278                 }
279
280                 if (StorageType.Empty == resultType) {
281                     SetTypeMismatchError(op, typeofLeft, typeofRight);
282                 }
283
284             }
285             else {
286                 vLeft = vRight = DBNull.Value;
287                 resultType = StorageType.Empty; // shouldnt we make it boolean?
288             }
289
290             object value = DBNull.Value;
291             bool typeMismatch = false;
292
293             try {
294                 switch (op) {
295                 case Operators.Plus:
296                     switch(resultType) {
297                     case StorageType.Byte:{
298                         value = Convert.ToByte((Convert.ToByte(vLeft, FormatProvider) + Convert.ToByte(vRight, FormatProvider)), FormatProvider);
299                         break;}
300                     case StorageType.SByte:{
301                         value = Convert.ToSByte((Convert.ToSByte(vLeft, FormatProvider) + Convert.ToSByte(vRight, FormatProvider)), FormatProvider);
302                         break;}
303                     case StorageType.Int16:{
304                         value = Convert.ToInt16((Convert.ToInt16(vLeft, FormatProvider) + Convert.ToInt16(vRight, FormatProvider)), FormatProvider);
305                         break;}
306                     case StorageType.UInt16:{
307                         value = Convert.ToUInt16((Convert.ToUInt16(vLeft, FormatProvider) + Convert.ToUInt16(vRight, FormatProvider)), FormatProvider);
308                         break;}
309                     case StorageType.Int32: {
310                         checked {value = Convert.ToInt32(vLeft, FormatProvider) + Convert.ToInt32(vRight, FormatProvider);}
311                         break;}
312                     case StorageType.UInt32: {
313                         checked {value = Convert.ToUInt32(vLeft, FormatProvider) + Convert.ToUInt32(vRight, FormatProvider);}
314                         break;}
315                     case StorageType.UInt64: {
316                         checked {value = Convert.ToUInt64(vLeft, FormatProvider) + Convert.ToUInt64(vRight, FormatProvider);}
317                         break;}
318                     case StorageType.Int64:{
319                         checked {value = Convert.ToInt64(vLeft, FormatProvider) + Convert.ToInt64(vRight, FormatProvider);}
320                         break;}
321                     case StorageType.Decimal:{
322                         checked {value = Convert.ToDecimal(vLeft, FormatProvider) + Convert.ToDecimal(vRight, FormatProvider);}
323                         break;}
324                     case StorageType.Single:{
325                         checked {value = Convert.ToSingle(vLeft, FormatProvider) + Convert.ToSingle(vRight, FormatProvider);}
326                         break;}
327                     case StorageType.Double:{
328                         checked {value = Convert.ToDouble(vLeft, FormatProvider) + Convert.ToDouble(vRight, FormatProvider);}
329                         break;}
330                     case StorageType.String:
331                     case StorageType.Char:{
332                         value = Convert.ToString(vLeft, FormatProvider) + Convert.ToString(vRight, FormatProvider);
333                         break;}
334                     case StorageType.DateTime:{
335                         // one of the operands should be a DateTime, and an other a TimeSpan
336
337                         if (vLeft is TimeSpan && vRight is DateTime) {
338                             value = (DateTime)vRight + (TimeSpan)vLeft;
339                         }
340                         else if (vLeft is DateTime && vRight is TimeSpan) {
341                             value = (DateTime)vLeft + (TimeSpan)vRight;
342                         }
343                         else {
344                             typeMismatch = true;
345                         }
346                         break;}
347                     case StorageType.TimeSpan:{
348                         value = (TimeSpan)vLeft + (TimeSpan)vRight;
349                         break;}
350                     case StorageType.SqlInt16:{
351                         value = (SqlConvert.ConvertToSqlInt16(vLeft) + SqlConvert.ConvertToSqlInt16(vRight));
352                         break;}
353                     case StorageType.SqlInt32:{
354                         value = ( SqlConvert.ConvertToSqlInt32(vLeft) + SqlConvert.ConvertToSqlInt32(vRight));
355                         break;}
356                     case StorageType.SqlInt64:{
357                         value = (SqlConvert.ConvertToSqlInt64(vLeft) + SqlConvert.ConvertToSqlInt64(vRight));
358                         break;}
359                     case StorageType.SqlDouble:{
360                         value = (SqlConvert.ConvertToSqlDouble(vLeft) + SqlConvert.ConvertToSqlDouble(vRight));
361                         break;}
362                     case StorageType.SqlSingle:{
363                         value = (SqlConvert.ConvertToSqlSingle(vLeft)+ SqlConvert.ConvertToSqlSingle(vRight));
364                         break;}
365                     case StorageType.SqlDecimal:{
366                         value = (SqlConvert.ConvertToSqlDecimal(vLeft) + SqlConvert.ConvertToSqlDecimal(vRight));
367                         break;}
368                     case StorageType.SqlMoney:{
369                         value = (SqlConvert.ConvertToSqlMoney(vLeft) + SqlConvert.ConvertToSqlMoney(vRight));
370                         break;}
371                     case StorageType.SqlByte:{
372                         value = (SqlConvert.ConvertToSqlByte(vLeft) + SqlConvert.ConvertToSqlByte(vRight));
373                         break;}
374                     case StorageType.SqlString:{
375                         value = (SqlConvert.ConvertToSqlString(vLeft) + SqlConvert.ConvertToSqlString(vRight));
376                         break;}
377                     case StorageType.SqlDateTime:{
378                         if (vLeft is TimeSpan && vRight is SqlDateTime) {
379                           SqlDateTime rValue = (SqlDateTime)SqlConvert.ConvertToSqlDateTime(vRight);
380                           value = (SqlDateTime)SqlConvert.ConvertToSqlDateTime((DateTime)rValue.Value + (TimeSpan)vLeft);
381                         }
382                         else if (vLeft is SqlDateTime && vRight is TimeSpan) {
383                           SqlDateTime lValue = (SqlDateTime)SqlConvert.ConvertToSqlDateTime(vLeft);
384                           value = (SqlDateTime)SqlConvert.ConvertToSqlDateTime((DateTime)lValue.Value + (TimeSpan)vRight);
385                         }
386                         else {
387                             typeMismatch = true;
388                         }
389                         break;}
390                     default:{
391                         typeMismatch = true;
392                         break;}
393                     }
394                     break; // Operators.Plus
395
396                 case Operators.Minus:
397                     switch(resultType) {
398                     case StorageType.Byte: {
399                         value = Convert.ToByte((Convert.ToByte(vLeft, FormatProvider) - Convert.ToByte(vRight, FormatProvider)), FormatProvider);
400                     break; }
401                     case StorageType.SqlByte: {
402                         value = (SqlConvert.ConvertToSqlByte(vLeft) - SqlConvert.ConvertToSqlByte(vRight));
403                     break;}
404                     case StorageType.SByte:{
405                         value = Convert.ToSByte((Convert.ToSByte(vLeft, FormatProvider) - Convert.ToSByte(vRight, FormatProvider)), FormatProvider);
406                     break;}
407                     case StorageType.Int16:{
408                         value = Convert.ToInt16((Convert.ToInt16(vLeft, FormatProvider) - Convert.ToInt16(vRight, FormatProvider)), FormatProvider);
409                     break;}
410                     case StorageType.SqlInt16:{
411                         value = (SqlConvert.ConvertToSqlInt16(vLeft) - SqlConvert.ConvertToSqlInt16(vRight));
412                     break;}
413                     case StorageType.UInt16:{
414                         value = Convert.ToUInt16((Convert.ToUInt16(vLeft, FormatProvider) - Convert.ToUInt16(vRight, FormatProvider)), FormatProvider);
415                     break;}
416                     case StorageType.Int32:{
417                         checked {value = Convert.ToInt32(vLeft, FormatProvider) - Convert.ToInt32(vRight, FormatProvider);}
418                     break;}
419                     case StorageType.SqlInt32:{
420                         value = (SqlConvert.ConvertToSqlInt32(vLeft) - SqlConvert.ConvertToSqlInt32(vRight));
421                     break;}
422                     case StorageType.UInt32:{
423                         checked {value = Convert.ToUInt32(vLeft, FormatProvider) - Convert.ToUInt32(vRight, FormatProvider);}
424                     break;}
425                     case StorageType.Int64:{
426                         checked {value = Convert.ToInt64(vLeft, FormatProvider) - Convert.ToInt64(vRight, FormatProvider);}
427                     break;}
428                     case StorageType.SqlInt64:{
429                         value = (SqlConvert.ConvertToSqlInt64(vLeft) - SqlConvert.ConvertToSqlInt64(vRight));
430                     break;}
431                     case StorageType.UInt64:{
432                         checked {value = Convert.ToUInt64(vLeft, FormatProvider) - Convert.ToUInt64(vRight, FormatProvider);}
433                         break;}
434                     case StorageType.Decimal:{
435                         checked {value = Convert.ToDecimal(vLeft, FormatProvider) - Convert.ToDecimal(vRight, FormatProvider);}
436                         break;}
437                     case StorageType.SqlDecimal:{
438                         value = (SqlConvert.ConvertToSqlDecimal(vLeft) - SqlConvert.ConvertToSqlDecimal(vRight));
439                         break;}
440                     case StorageType.Single:{
441                         checked {value = Convert.ToSingle(vLeft, FormatProvider) - Convert.ToSingle(vRight, FormatProvider);}
442                         break;}
443                     case StorageType.SqlSingle:{
444                         value = (SqlConvert.ConvertToSqlSingle(vLeft) - SqlConvert.ConvertToSqlSingle(vRight));
445                         break;}
446                     case StorageType.Double:{
447                         checked {value = Convert.ToDouble(vLeft, FormatProvider) - Convert.ToDouble(vRight, FormatProvider);}
448                         break;}
449                     case StorageType.SqlDouble:{
450                         value = (SqlConvert.ConvertToSqlDouble(vLeft) - SqlConvert.ConvertToSqlDouble(vRight));
451                         break;}
452                     case StorageType.SqlMoney:{
453                         value = (SqlConvert.ConvertToSqlMoney(vLeft) - SqlConvert.ConvertToSqlMoney(vRight));
454                         break;}
455                     case StorageType.DateTime:{
456                         value = (DateTime)vLeft - (TimeSpan)vRight;
457                         break;}
458                     case StorageType.TimeSpan:{
459                         if (vLeft is DateTime) {
460                             value = (DateTime)vLeft - (DateTime)vRight;
461                         }
462                         else
463                             value = (TimeSpan)vLeft - (TimeSpan)vRight;
464                         break;}
465                     case StorageType.SqlDateTime:{
466                         if (vLeft is TimeSpan && vRight is SqlDateTime) {
467                           SqlDateTime rValue = (SqlDateTime)SqlConvert.ConvertToSqlDateTime(vRight);
468                           value = (SqlDateTime)SqlConvert.ConvertToSqlDateTime((DateTime)rValue.Value - (TimeSpan)vLeft);
469                         }
470                         else if (vLeft is SqlDateTime && vRight is TimeSpan) {
471                           SqlDateTime lValue = (SqlDateTime)SqlConvert.ConvertToSqlDateTime(vLeft);
472                           value = (SqlDateTime)SqlConvert.ConvertToSqlDateTime((DateTime)lValue.Value - (TimeSpan)vRight);
473                         }
474                         else {
475                             typeMismatch = true;
476                         }
477                         break;}
478                     default:{
479                         typeMismatch = true;
480                         break;}
481                     }
482                     break; // Operators.Minus
483
484                 case Operators.Multiply:
485                     switch(resultType) {
486                     case StorageType.Byte:{
487                         value = Convert.ToByte((Convert.ToByte(vLeft, FormatProvider) * Convert.ToByte(vRight, FormatProvider)), FormatProvider);
488                         break;}
489                     case StorageType.SqlByte:{
490                         value = (SqlConvert.ConvertToSqlByte(vLeft) * SqlConvert.ConvertToSqlByte(vRight));
491                         break;}
492                     case StorageType.SByte:{
493                         value = Convert.ToSByte((Convert.ToSByte(vLeft, FormatProvider) * Convert.ToSByte(vRight, FormatProvider)), FormatProvider);
494                         break;}
495                     case StorageType.Int16:{
496                         value = Convert.ToInt16((Convert.ToInt16(vLeft, FormatProvider) * Convert.ToInt16(vRight, FormatProvider)), FormatProvider);
497                         break;}
498                     case StorageType.SqlInt16:{
499                         value = (SqlConvert.ConvertToSqlInt16(vLeft) * SqlConvert.ConvertToSqlInt16(vRight));
500                         break;}
501                     case StorageType.UInt16:{
502                         value = Convert.ToUInt16((Convert.ToUInt16(vLeft, FormatProvider) * Convert.ToUInt16(vRight, FormatProvider)), FormatProvider);
503                         break;}
504                     case StorageType.Int32:{
505                         checked {value = Convert.ToInt32(vLeft, FormatProvider) * Convert.ToInt32(vRight, FormatProvider);}
506                         break;}
507                     case StorageType.SqlInt32:{
508                         value = (SqlConvert.ConvertToSqlInt32(vLeft) * SqlConvert.ConvertToSqlInt32(vRight));
509                         break;}
510                     case StorageType.UInt32:{
511                         checked {value = Convert.ToUInt32(vLeft, FormatProvider) * Convert.ToUInt32(vRight, FormatProvider);}
512                         break;}
513                     case StorageType.Int64:{
514
515                         checked {value = Convert.ToInt64(vLeft, FormatProvider) * Convert.ToInt64(vRight, FormatProvider);}
516                         break;}
517                     case StorageType.SqlInt64:{
518                         value = (SqlConvert.ConvertToSqlInt64(vLeft) * SqlConvert.ConvertToSqlInt64(vRight));
519                         break;}
520                     case StorageType.UInt64:{
521                         checked {value = Convert.ToUInt64(vLeft, FormatProvider) * Convert.ToUInt64(vRight, FormatProvider);}
522                         break;}
523                     case StorageType.Decimal:{
524                         checked {value = Convert.ToDecimal(vLeft, FormatProvider) * Convert.ToDecimal(vRight, FormatProvider);}
525                         break;}
526                     case StorageType.SqlDecimal:{
527                         value = (SqlConvert.ConvertToSqlDecimal(vLeft) * SqlConvert.ConvertToSqlDecimal(vRight));
528                         break;}
529                     case StorageType.Single:{
530                         checked {value = Convert.ToSingle(vLeft, FormatProvider) * Convert.ToSingle(vRight, FormatProvider);}
531                         break;}
532                     case StorageType.SqlSingle:{
533                         value = ( SqlConvert.ConvertToSqlSingle(vLeft) * SqlConvert.ConvertToSqlSingle(vRight));
534                         break;}
535                     case StorageType.SqlMoney:{
536                         value = (SqlConvert.ConvertToSqlMoney(vLeft) * SqlConvert.ConvertToSqlMoney(vRight));
537                         break;}
538                     case StorageType.Double:{
539                         checked {value = Convert.ToDouble(vLeft, FormatProvider) * Convert.ToDouble(vRight, FormatProvider);}
540                         break;}
541                     case StorageType.SqlDouble:{
542                         value = (SqlConvert.ConvertToSqlDouble(vLeft) * SqlConvert.ConvertToSqlDouble(vRight));
543                         break;}
544                     default:{
545                         typeMismatch = true;
546                         break;}
547                     }
548                     break; // Operators.Multiply
549
550                 case Operators.Divide:
551                     switch(resultType) {
552                     case StorageType.Byte:{
553                         value = Convert.ToByte((Convert.ToByte(vLeft, FormatProvider) / Convert.ToByte(vRight, FormatProvider)), FormatProvider);
554                         break;}
555                     case StorageType.SqlByte:{
556                         value = (SqlConvert.ConvertToSqlByte(vLeft) / SqlConvert.ConvertToSqlByte(vRight));
557                         break;}
558                     case StorageType.SByte:{
559                         value = Convert.ToSByte((Convert.ToSByte(vLeft, FormatProvider) / Convert.ToSByte(vRight, FormatProvider)), FormatProvider);
560                         break;}
561                     case StorageType.Int16:{
562                         value = Convert.ToInt16((Convert.ToInt16(vLeft, FormatProvider) / Convert.ToInt16(vRight, FormatProvider)), FormatProvider);
563                         break;}
564                     case StorageType.SqlInt16:{
565                         value = (SqlConvert.ConvertToSqlInt16(vLeft) / SqlConvert.ConvertToSqlInt16(vRight));
566                         break;}
567                     case StorageType.UInt16:{
568                         value = Convert.ToUInt16((Convert.ToUInt16(vLeft, FormatProvider) / Convert.ToUInt16(vRight, FormatProvider)), FormatProvider);
569                         break;}
570                     case StorageType.Int32:{
571                         checked {value = Convert.ToInt32(vLeft, FormatProvider) / Convert.ToInt32(vRight, FormatProvider);}
572                         break;}
573                     case StorageType.SqlInt32:{
574                         value = (SqlConvert.ConvertToSqlInt32(vLeft) / SqlConvert.ConvertToSqlInt32(vRight));
575                         break;}
576                     case StorageType.UInt32:{
577                         checked {value = Convert.ToUInt32(vLeft, FormatProvider) / Convert.ToUInt32(vRight, FormatProvider);}
578                         break;}
579                     case StorageType.UInt64:{
580                         checked {value = Convert.ToUInt64(vLeft, FormatProvider) / Convert.ToUInt64(vRight, FormatProvider);}
581                         break;}
582                     case StorageType.Int64:{
583                         checked {value = Convert.ToInt64(vLeft, FormatProvider) / Convert.ToInt64(vRight, FormatProvider);}
584                         break;}
585                     case StorageType.SqlInt64:{
586                         value = (SqlConvert.ConvertToSqlInt64(vLeft) / SqlConvert.ConvertToSqlInt64(vRight));
587                         break;}
588                     case StorageType.Decimal:{
589                         checked {value = Convert.ToDecimal(vLeft, FormatProvider) / Convert.ToDecimal(vRight, FormatProvider);}
590                         break;}
591                     case StorageType.SqlDecimal:{
592                         value = (SqlConvert.ConvertToSqlDecimal(vLeft) / SqlConvert.ConvertToSqlDecimal(vRight));
593                         break;}
594                     case StorageType.Single:{
595                         checked {value = Convert.ToSingle(vLeft, FormatProvider) / Convert.ToSingle(vRight, FormatProvider);}
596                         break;}
597                     case StorageType.SqlSingle:{
598                         value = ( SqlConvert.ConvertToSqlSingle(vLeft) / SqlConvert.ConvertToSqlSingle(vRight));
599                         break;}
600                     case StorageType.SqlMoney:{
601                         value = (SqlConvert.ConvertToSqlMoney(vLeft) / SqlConvert.ConvertToSqlMoney(vRight));
602                         break;}
603                     case StorageType.Double:{
604                         Double b = Convert.ToDouble(vRight, FormatProvider);
605                         checked {value = Convert.ToDouble(vLeft, FormatProvider) / b;}
606                         break;}
607                     case StorageType.SqlDouble:{
608                         value = (SqlConvert.ConvertToSqlDouble(vLeft) / SqlConvert.ConvertToSqlDouble(vRight));
609                         break;}
610                     default:{
611                         typeMismatch = true;
612                         break;}
613                     }
614                     break; // Operators.Divide
615
616                 case Operators.EqualTo:
617                     if ((vLeft == DBNull.Value)||(left.IsSqlColumn && DataStorage.IsObjectSqlNull(vLeft)) ||
618                          (vRight == DBNull.Value)||(right.IsSqlColumn && DataStorage.IsObjectSqlNull(vRight)))
619                         return DBNull.Value;
620                     return(0 == BinaryCompare (vLeft, vRight, resultType, Operators.EqualTo));
621
622                 case Operators.GreaterThen:
623                     if ((vLeft == DBNull.Value)||(left.IsSqlColumn && DataStorage.IsObjectSqlNull(vLeft)) ||
624                          (vRight == DBNull.Value)||(right.IsSqlColumn && DataStorage.IsObjectSqlNull(vRight)))
625                         return DBNull.Value;
626                     return(0 < BinaryCompare (vLeft, vRight, resultType,  op));
627
628                 case Operators.LessThen:
629                     if ((vLeft == DBNull.Value)||(left.IsSqlColumn && DataStorage.IsObjectSqlNull(vLeft)) ||
630                          (vRight == DBNull.Value)||(right.IsSqlColumn && DataStorage.IsObjectSqlNull(vRight)))
631                         return DBNull.Value;
632                     return(0 > BinaryCompare (vLeft, vRight, resultType,  op));
633
634                 case Operators.GreaterOrEqual:
635                     if ((vLeft == DBNull.Value)||(left.IsSqlColumn && DataStorage.IsObjectSqlNull(vLeft)) ||
636                          (vRight == DBNull.Value)||(right.IsSqlColumn && DataStorage.IsObjectSqlNull(vRight)))
637                         return DBNull.Value;
638                     return(0 <= BinaryCompare (vLeft, vRight, resultType, op));
639
640                 case Operators.LessOrEqual:
641                     if (((vLeft == DBNull.Value)||(left.IsSqlColumn && DataStorage.IsObjectSqlNull(vLeft))) ||
642                          ((vRight == DBNull.Value)||(right.IsSqlColumn && DataStorage.IsObjectSqlNull(vRight))))
643                         return DBNull.Value;
644                     return(0 >= BinaryCompare (vLeft, vRight, resultType, op));
645
646                 case Operators.NotEqual:
647                     if (((vLeft == DBNull.Value)||(left.IsSqlColumn && DataStorage.IsObjectSqlNull(vLeft))) ||
648                          ((vRight == DBNull.Value)||(right.IsSqlColumn && DataStorage.IsObjectSqlNull(vRight))))
649                         return DBNull.Value;
650                     return(0 != BinaryCompare (vLeft, vRight, resultType, op));
651
652                 case Operators.Is:
653                     vLeft  = BinaryNode.Eval(left, row, version, recordNos);
654                     if ((vLeft == DBNull.Value)||(left.IsSqlColumn && DataStorage.IsObjectSqlNull(vLeft))){
655                         return true;
656                     }
657                     return false;
658
659                 case Operators.IsNot:
660                     vLeft  = BinaryNode.Eval(left, row, version, recordNos);
661                     if ((vLeft == DBNull.Value)||(left.IsSqlColumn && DataStorage.IsObjectSqlNull(vLeft))){
662                         return false;
663                     }
664                     return true;
665
666                 case Operators.And:
667                     /*
668                     special case evaluating of the AND operator: we don't want to evaluate
669                     both right and left operands, because we can shortcut :
670                         If one of the operands is flase the result is false
671                     
672 */
673                     vLeft  = BinaryNode.Eval(left, row, version, recordNos);
674                     if ((vLeft == DBNull.Value)||(left.IsSqlColumn && DataStorage.IsObjectSqlNull(vLeft)))
675                         return DBNull.Value;
676
677                     if ((!(vLeft is bool)) && (!(vLeft is SqlBoolean))){
678                         vRight = BinaryNode.Eval(right, row, version, recordNos);
679                         typeMismatch = true;
680                         break;
681                     }
682
683                     if (vLeft is bool){
684                         if ((bool)vLeft == false){
685                            value = false;
686                            break;
687                         }
688                     }
689                     else{
690                         if (((SqlBoolean) vLeft).IsFalse){
691                             value = false;
692                             break;
693                         }
694                     }
695                     vRight = BinaryNode.Eval(right, row, version, recordNos);
696                     if ((vRight  == DBNull.Value)||(right.IsSqlColumn && DataStorage.IsObjectSqlNull(vRight )))
697                         return DBNull.Value;
698
699                     if ((!(vRight is bool)) && (!(vRight is SqlBoolean))){
700                         typeMismatch = true;
701                         break;
702                     }
703
704                     if (vRight is bool){
705                         value = (bool)vRight;
706                         break;
707                     }
708                     else{
709                         value = ((SqlBoolean) vRight).IsTrue;
710                     }
711                     break;
712                 case Operators.Or:
713                     /*
714                     special case evaluating the OR operator: we don't want to evaluate
715                     both right and left operands, because we can shortcut :
716                         If one of the operands is true the result is true
717                     
718 */
719
720                     vLeft = BinaryNode.Eval(left, row, version, recordNos);
721
722                     if ((vLeft != DBNull.Value) && (!DataStorage.IsObjectSqlNull(vLeft))) {
723                         if ((!(vLeft is bool)) && (!(vLeft is SqlBoolean))) {
724                             vRight = BinaryNode.Eval(right, row, version, recordNos);
725                             typeMismatch = true;
726                             break;
727                         }
728
729                         if ((bool)vLeft == true) {
730                             value = true;
731                             break;
732                         }
733                     }
734
735                     vRight = BinaryNode.Eval(right, row, version, recordNos);
736                     if ((vRight == DBNull.Value)||(DataStorage.IsObjectSqlNull(vRight)))
737                         return vLeft;
738
739                     if ((vLeft == DBNull.Value)||(DataStorage.IsObjectSqlNull(vLeft)))
740                         return vRight;
741
742                     if ((!(vRight is bool)) && (!(vRight is SqlBoolean))) {
743                         typeMismatch = true;
744                         break;
745                     }
746
747                     value = (vRight is bool) ? ((bool)vRight) : (((SqlBoolean)vRight).IsTrue);
748                     break;
749
750 /*  for M3, use original code , in below,  and make sure to have two different code path; increases perf
751
752                     vLeft = BinaryNode.Eval(left, row, version, recordNos);
753                     if (vLeft != DBNull.Value) {
754                         if (!(vLeft is bool)) {
755                             vRight = BinaryNode.Eval(right, row, version, recordNos);
756                             typeMismatch = true;
757                             break;
758                         }
759
760                         if ((bool)vLeft == true) {
761                             value = true;
762                             break;
763                         }
764                     }
765
766                     vRight = BinaryNode.Eval(right, row, version, recordNos);
767                     if (vRight == DBNull.Value)
768                         return vLeft;
769
770                     if (vLeft == DBNull.Value)
771                         return vRight;
772
773                     if (!(vRight is bool)) {
774                         typeMismatch = true;
775                         break;
776                     }
777
778                     value = (bool)vRight;
779                     break;
780 */
781
782                 case Operators.Modulo:
783                     if (ExpressionNode.IsIntegerSql(resultType)) {
784                         if (resultType == StorageType.UInt64) {
785                             value = Convert.ToUInt64(vLeft, FormatProvider) % Convert.ToUInt64(vRight, FormatProvider);
786                         }
787                         else if (DataStorage.IsSqlType(resultType)) {
788                             SqlInt64 res = (SqlConvert.ConvertToSqlInt64(vLeft) % SqlConvert.ConvertToSqlInt64(vRight));
789
790                             if (resultType == StorageType.SqlInt32){
791                                 value =  (SqlInt32) res.ToSqlInt32();
792                             }
793                             else if (resultType == StorageType.SqlInt16){
794                                 value =  (SqlInt16) res.ToSqlInt16();
795                             }
796                             else if (resultType == StorageType.SqlByte){
797                                 value =  (SqlByte) res.ToSqlByte();
798                             }
799                             else{
800                                 value =  (SqlInt64) res;
801                             }
802                         }
803                         else {
804                             value = Convert.ToInt64(vLeft, FormatProvider) % Convert.ToInt64(vRight, FormatProvider);
805                             value = Convert.ChangeType(value, DataStorage.GetTypeStorage(resultType), FormatProvider);
806                         }
807                     }
808                     else {
809                         typeMismatch = true;
810                     }
811                     break;
812
813                 case Operators.In:
814                     /*
815                     special case evaluating of the IN operator: the right have to be IN function node
816                     */
817
818
819                     if (!(right is FunctionNode)) {
820                         // this is more like an Assert: should never happens, so we do not care about "nice" Exseptions
821                         throw ExprException.InWithoutParentheses();
822                     }
823
824                     vLeft = BinaryNode.Eval(left, row, version, recordNos);
825
826                     if ((vLeft == DBNull.Value)||(left.IsSqlColumn && DataStorage.IsObjectSqlNull(vLeft)))
827                         return DBNull.Value;
828
829                     /* validate IN parameters : must all be constant expressions */
830
831                     value = false;
832
833                     FunctionNode into = (FunctionNode)right;
834
835                     for (int i = 0; i < into.argumentCount; i++) {
836                         vRight = into.arguments[i].Eval();
837
838
839                     if ((vRight == DBNull.Value)||(right.IsSqlColumn && DataStorage.IsObjectSqlNull(vRight)))
840                             continue;
841                         Debug.Assert((!DataStorage.IsObjectNull(vLeft))&& (!DataStorage.IsObjectNull(vRight)), "Imposible..");
842
843                         resultType = DataStorage.GetStorageType(vLeft.GetType());
844
845                         if (0 == BinaryCompare(vLeft, vRight, resultType,  Operators.EqualTo)) {
846                             value = true;
847                             break;
848                         }
849                     }
850                     break;
851
852                 default:
853                     throw ExprException.UnsupportedOperator(op);
854                 }
855             }
856             catch (OverflowException) {
857                 throw ExprException.Overflow(DataStorage.GetTypeStorage(resultType));
858             }
859             if (typeMismatch) {
860                 SetTypeMismatchError(op, vLeft.GetType(), vRight.GetType());
861             }
862
863             return value;
864         }
865
866         // Data type precedence rules specify which data type is converted to the other.
867         // The data type with the lower precedence is converted to the data type with the higher precedence.
868         // If the conversion is not a supported implicit conversion, an error is returned.
869         // When both operand expressions have the same data type, the result of the operation has that data type.
870         // This is the precedence order for the DataSet numeric data types:
871
872         private enum DataTypePrecedence {
873            SqlDateTime = 25,
874            DateTimeOffset = 24,
875            DateTime = 23,
876            TimeSpan = 20,
877            SqlDouble = 19,
878            Double = 18,
879            SqlSingle = 17,
880            Single = 16,
881            SqlDecimal = 15,
882            Decimal = 14,
883            SqlMoney = 13,
884            UInt64 = 12,
885            SqlInt64 = 11,
886            Int64 = 10,
887            UInt32 = 9,
888            SqlInt32 = 8,
889            Int32 = 7,
890            UInt16 = 6,
891            SqlInt16 = 5,
892            Int16 = 4,
893            Byte = 3,
894            SqlByte = 2,
895            SByte = 1,
896            Error = 0,
897            SqlBoolean = -1,
898            Boolean = -2,
899            SqlGuid = -3,
900            SqlString = -4,
901            String = -5,
902            SqlXml = -6,
903            SqlChars = -7,
904            Char = -8,
905            SqlBytes = -9,
906            SqlBinary = -10,
907         }
908
909         private DataTypePrecedence GetPrecedence(StorageType storageType) {
910             switch(storageType) {
911             case StorageType.Boolean: return DataTypePrecedence.Boolean;
912             case StorageType.Char: return DataTypePrecedence.Char;
913             case StorageType.SByte: return DataTypePrecedence.SByte;
914             case StorageType.Byte: return DataTypePrecedence.Byte;
915             case StorageType.Int16: return DataTypePrecedence.Int16;
916             case StorageType.UInt16: return DataTypePrecedence.UInt16;
917             case StorageType.Int32: return DataTypePrecedence.Int32;
918             case StorageType.UInt32: return DataTypePrecedence.UInt32;
919             case StorageType.Int64: return DataTypePrecedence.Int64;
920             case StorageType.UInt64: return DataTypePrecedence.UInt64;
921             case StorageType.Single: return DataTypePrecedence.Single;
922             case StorageType.Double: return DataTypePrecedence.Double;
923             case StorageType.Decimal: return DataTypePrecedence.Decimal;
924             case StorageType.DateTime: return DataTypePrecedence.DateTime;
925             case StorageType.DateTimeOffset: return DataTypePrecedence.DateTimeOffset;
926             case StorageType.TimeSpan: return DataTypePrecedence.TimeSpan;
927             case StorageType.String: return DataTypePrecedence.String;
928             case StorageType.SqlBinary: return DataTypePrecedence.SqlBinary;
929             case StorageType.SqlBoolean: return DataTypePrecedence.SqlBoolean;
930             case StorageType.SqlByte: return DataTypePrecedence.SqlByte;
931             case StorageType.SqlBytes: return DataTypePrecedence.SqlBytes;
932             case StorageType.SqlChars: return DataTypePrecedence.SqlChars;
933             case StorageType.SqlDateTime: return DataTypePrecedence.SqlDateTime;
934             case StorageType.SqlDecimal: return DataTypePrecedence.SqlDecimal;
935             case StorageType.SqlDouble: return DataTypePrecedence.SqlDouble;
936             case StorageType.SqlGuid: return DataTypePrecedence.SqlGuid;
937             case StorageType.SqlInt16: return DataTypePrecedence.SqlInt16;
938             case StorageType.SqlInt32: return DataTypePrecedence.SqlInt32;
939             case StorageType.SqlInt64: return DataTypePrecedence.SqlInt64;
940             case StorageType.SqlMoney: return DataTypePrecedence.SqlMoney;
941             case StorageType.SqlSingle: return DataTypePrecedence.SqlSingle;
942             case StorageType.SqlString: return DataTypePrecedence.SqlString;
943 //            case StorageType.SqlXml: return DataTypePrecedence.SqlXml;
944             case StorageType.Empty:
945             case StorageType.Object:
946             case StorageType.DBNull:
947             default: return DataTypePrecedence.Error;
948             }
949         }
950
951         private static StorageType GetPrecedenceType(DataTypePrecedence code) {
952             switch (code) {
953             case DataTypePrecedence.Error:       return StorageType.Empty;
954             case DataTypePrecedence.SByte:       return StorageType.SByte;
955             case DataTypePrecedence.Byte:        return StorageType.Byte;
956             case DataTypePrecedence.Int16:       return StorageType.Int16;
957             case DataTypePrecedence.UInt16:      return StorageType.UInt16;
958             case DataTypePrecedence.Int32:       return StorageType.Int32;
959             case DataTypePrecedence.UInt32:      return StorageType.UInt32;
960             case DataTypePrecedence.Int64:       return StorageType.Int64;
961             case DataTypePrecedence.UInt64:      return StorageType.UInt64;
962             case DataTypePrecedence.Decimal:     return StorageType.Decimal;
963             case DataTypePrecedence.Single:      return StorageType.Single;
964             case DataTypePrecedence.Double:      return StorageType.Double;
965
966             case DataTypePrecedence.Boolean:     return StorageType.Boolean;
967             case DataTypePrecedence.String:      return StorageType.String;
968             case DataTypePrecedence.Char:        return StorageType.Char;
969
970             case DataTypePrecedence.DateTimeOffset:  return StorageType.DateTimeOffset;
971             case DataTypePrecedence.DateTime:    return StorageType.DateTime;
972             case DataTypePrecedence.TimeSpan:    return StorageType.TimeSpan;
973
974             case DataTypePrecedence.SqlDateTime: return StorageType.SqlDateTime;
975             case DataTypePrecedence.SqlDouble:   return StorageType.SqlDouble;
976             case DataTypePrecedence.SqlSingle:   return StorageType.SqlSingle;
977             case DataTypePrecedence.SqlDecimal:  return StorageType.SqlDecimal;
978             case DataTypePrecedence.SqlInt64:    return StorageType.SqlInt64;
979             case DataTypePrecedence.SqlInt32:    return StorageType.SqlInt32;
980             case DataTypePrecedence.SqlInt16:    return StorageType.SqlInt16;
981             case DataTypePrecedence.SqlByte:     return StorageType.SqlByte;
982             case DataTypePrecedence.SqlBoolean:  return StorageType.SqlBoolean;
983             case DataTypePrecedence.SqlString:   return StorageType.SqlString;
984             case DataTypePrecedence.SqlGuid:     return StorageType.SqlGuid;
985             case DataTypePrecedence.SqlBinary:   return StorageType.SqlBinary;
986             case DataTypePrecedence.SqlMoney:    return StorageType.SqlMoney;
987             default:
988             Debug.Assert(false, "Invalid (unmapped) precedence " + code.ToString());
989             goto case DataTypePrecedence.Error;
990             }
991         }
992
993         private bool IsMixed(StorageType left, StorageType right) {
994             return ((IsSigned(left) && IsUnsigned(right)) ||
995                     (IsUnsigned(left) && IsSigned(right)));
996         }
997
998         private bool IsMixedSql(StorageType left, StorageType right) {
999             return ((IsSignedSql(left) && IsUnsignedSql(right)) ||
1000                     (IsUnsignedSql(left) && IsSignedSql(right)));
1001         }
1002
1003         internal StorageType ResultType(StorageType left, StorageType right, bool lc, bool rc, int op) {
1004             if ((left == StorageType.Guid) && (right == StorageType.Guid) && Operators.IsRelational(op))
1005                 return left;
1006             if ((left == StorageType.String) && (right == StorageType.Guid) && Operators.IsRelational(op))
1007                 return left;
1008             if ((left == StorageType.Guid) && (right == StorageType.String) && Operators.IsRelational(op))
1009                 return right;
1010
1011              int leftPrecedence = (int)GetPrecedence(left);
1012              if (leftPrecedence == (int)DataTypePrecedence.Error) {
1013                 return StorageType.Empty;
1014              }
1015
1016              int rightPrecedence = (int)GetPrecedence(right);
1017              if (rightPrecedence == (int)DataTypePrecedence.Error) {
1018                 return StorageType.Empty;
1019              }
1020
1021              if (Operators.IsLogical(op)){
1022                 if (left == StorageType.Boolean && right == StorageType.Boolean)
1023                     return StorageType.Boolean;
1024                 else
1025                     return StorageType.Empty;
1026              }
1027             if ((left == StorageType.DateTimeOffset) ||(right == StorageType.DateTimeOffset))
1028             {
1029                 // Rules to handle DateTimeOffset:
1030                 // we only allow Relational operations to operate only on DTO vs DTO
1031                 // all other operations: "exception"
1032                 if (Operators.IsRelational(op) && left == StorageType.DateTimeOffset && right == StorageType.DateTimeOffset)
1033                     return StorageType.DateTimeOffset;
1034                 return StorageType.Empty;
1035             }
1036
1037              if ((op == Operators.Plus) && ((left == StorageType.String) || (right == StorageType.String)))
1038                 return StorageType.String;
1039
1040              DataTypePrecedence higherPrec = (DataTypePrecedence)Math.Max(leftPrecedence, rightPrecedence);
1041
1042              StorageType result = GetPrecedenceType(higherPrec);
1043
1044              if (Operators.IsArithmetical(op)) {
1045                 if (result != StorageType.String && result != StorageType.Char) {
1046                     if (!IsNumeric(left))
1047                         return StorageType.Empty;
1048                     if (!IsNumeric(right))
1049                         return StorageType.Empty;
1050                 }
1051              }
1052
1053              // if the operation is a division the result should be at least a double
1054
1055              if ((op == Operators.Divide) && IsInteger(result)) {
1056                 return StorageType.Double;
1057              }
1058
1059              if (IsMixed(left, right)) {
1060                 // we are dealing with one signed and one unsigned type so
1061                 // try to see if one of them is a ConstNode
1062                 if (lc && (!rc)) {
1063                     return right;
1064                 }
1065                 else if ((!lc) && rc) {
1066                     return left;
1067                 }
1068
1069                 if (IsUnsigned(result)) {
1070                     if (higherPrec < DataTypePrecedence.UInt64)
1071                         // left and right are mixed integers but with the same length
1072                         // so promote to the next signed type
1073                         result = GetPrecedenceType(higherPrec+1);
1074                     else
1075                         throw ExprException.AmbiguousBinop(op, DataStorage.GetTypeStorage(left), DataStorage.GetTypeStorage(right));
1076                 }
1077              }
1078
1079              return result;
1080         }
1081
1082         internal StorageType ResultSqlType(StorageType left, StorageType right, bool lc, bool rc, int op) {
1083             int leftPrecedence = (int)GetPrecedence(left);
1084             if (leftPrecedence == (int)DataTypePrecedence.Error) {
1085               return StorageType.Empty;
1086             }
1087
1088             int rightPrecedence = (int)GetPrecedence(right);
1089             if (rightPrecedence == (int)DataTypePrecedence.Error) {
1090               return StorageType.Empty;
1091             }
1092
1093             if (Operators.IsLogical(op)){
1094                 if ((left != StorageType.Boolean  && left != StorageType.SqlBoolean) || (right != StorageType.Boolean && right != StorageType.SqlBoolean))
1095                       return StorageType.Empty;
1096                 if (left == StorageType.Boolean && right == StorageType.Boolean)
1097                       return StorageType.Boolean;
1098                 return  StorageType.SqlBoolean;
1099             }
1100
1101             if (op == Operators.Plus){
1102                 if((left == StorageType.SqlString) ||(right == StorageType.SqlString))
1103                       return StorageType.SqlString;
1104                 if ((left == StorageType.String) || (right == StorageType.String))
1105                       return StorageType.String;
1106             }
1107             //SqlBinary is operable just with SqlBinary
1108             if ((left == StorageType.SqlBinary && right != StorageType.SqlBinary) ||(left != StorageType.SqlBinary && right == StorageType.SqlBinary))
1109                 return StorageType.Empty;
1110             //SqlGuid is operable just with SqlGuid
1111             if((left == StorageType.SqlGuid && right != StorageType.SqlGuid) ||(left != StorageType.SqlGuid && right == StorageType.SqlGuid))
1112                 return StorageType.Empty;
1113
1114             if ((leftPrecedence > (int)DataTypePrecedence.SqlDouble  && rightPrecedence <(int) DataTypePrecedence.TimeSpan)){
1115                 return StorageType.Empty;
1116             }
1117
1118             if ((leftPrecedence < (int)DataTypePrecedence.TimeSpan  && rightPrecedence >(int) DataTypePrecedence.SqlDouble)){
1119                 return StorageType.Empty;
1120             }
1121
1122             if (leftPrecedence > (int) DataTypePrecedence.SqlDouble){
1123                 if (op == Operators.Plus || op == Operators.Minus){
1124                       if (left == StorageType.TimeSpan)
1125                             return right;
1126                       if (right == StorageType.TimeSpan)
1127                         return left;
1128                       return StorageType.Empty; // for plus or minus operations for  time types, one of them MUST be time span
1129                 }
1130
1131                 if (!Operators.IsRelational(op))
1132                       return StorageType.Empty; // we just have relational operations amoung time types
1133                 return left;
1134             }
1135             // time types finished
1136             // continue with numerical types, numbers
1137
1138             DataTypePrecedence higherPrec = (DataTypePrecedence)Math.Max(leftPrecedence, rightPrecedence);
1139
1140             StorageType result = GetPrecedenceType(higherPrec);
1141             // if we have at least one Sql type, the intermediate result should be Sql type
1142             result = GetPrecedenceType((DataTypePrecedence)SqlResultType((int)higherPrec));
1143
1144             if (Operators.IsArithmetical(op)) {
1145                 if (result != StorageType.String && result != StorageType.Char && result != StorageType.SqlString) {
1146                       if (!IsNumericSql(left))
1147                             return StorageType.Empty;
1148                       if (!IsNumericSql(right))
1149                             return StorageType.Empty;
1150                }
1151             }
1152
1153             // if the operation is a division the result should be at least a double
1154             if ((op == Operators.Divide) && IsIntegerSql(result)) {
1155                  return StorageType.SqlDouble;
1156             }
1157
1158             if (result == StorageType.SqlMoney){
1159                 if ((left != StorageType.SqlMoney) && (right != StorageType.SqlMoney))
1160                       result =  StorageType.SqlDecimal;
1161             }
1162
1163             if (IsMixedSql(left, right)) {
1164             // we are dealing with one signed and one unsigned type so
1165             // try to see if one of them is a ConstNode
1166
1167                 if (IsUnsignedSql(result)) {
1168                       if (higherPrec < DataTypePrecedence.UInt64)
1169                         // left and right are mixed integers but with the same length
1170                         // so promote to the next signed type
1171                             result = GetPrecedenceType(higherPrec+1);
1172                       else
1173                         throw ExprException.AmbiguousBinop(op, DataStorage.GetTypeStorage(left), DataStorage.GetTypeStorage(right));
1174                 }
1175             }
1176
1177             return result;
1178         }
1179
1180         private int SqlResultType(int typeCode){
1181             switch (typeCode){
1182             case  23: return  24;
1183             case  20: return  21;
1184             case  18: return  19;
1185             case  16: return  17;
1186             case  14: return  15;
1187             case  12: return  13;
1188             case  9  :
1189             case  10: return  11;
1190             case  6  :
1191             case  7  : return  8;
1192             case  3  :
1193             case  4  : return  5;
1194             case  1  : return  2;
1195             case  -2: return -1;
1196             case  -5: return -4;
1197             case  -8: return -7;
1198             default : return typeCode;
1199            }
1200         }
1201     }
1202
1203     internal sealed class LikeNode : BinaryNode {
1204         // like kinds
1205         internal const int match_left = 1;      // <STR>*
1206         internal const int match_right = 2;     // *<STR>
1207         internal const int match_middle = 3;    // *<STR>*
1208         internal const int match_exact  = 4;    // <STR>
1209         internal const int match_all  = 5;      // *
1210
1211         int kind;
1212         string pattern = null;
1213
1214         internal LikeNode(DataTable table, int op, ExpressionNode left, ExpressionNode right)
1215         : base (table, op, left, right) {
1216         }
1217
1218         internal override object Eval(DataRow row, DataRowVersion version) {
1219             object vRight;
1220             // 
1221             object vLeft = left.Eval(row, version);
1222             string substring;
1223
1224
1225             if ((vLeft == DBNull.Value)||(left.IsSqlColumn && DataStorage.IsObjectSqlNull(vLeft)))
1226                 return DBNull.Value;
1227
1228             if (pattern == null) {
1229                 vRight = right.Eval(row, version);
1230
1231                 if (!(vRight is string) && !(vRight is SqlString)) {
1232                     SetTypeMismatchError(op, vLeft.GetType(), vRight.GetType());
1233                 }
1234
1235           if (vRight == DBNull.Value || DataStorage.IsObjectSqlNull(vRight))
1236               return DBNull.Value;
1237           string rightStr = (string) SqlConvert.ChangeType2(vRight, StorageType.String, typeof(string), FormatProvider);
1238
1239
1240                 // need to convert like pattern to a string
1241
1242                 // Parce the original pattern, and get the constant part of it..
1243                 substring = AnalyzePattern(rightStr);
1244
1245                 if (right.IsConstant())
1246                     pattern = substring;
1247             }
1248             else {
1249                 substring = pattern;
1250             }
1251
1252             if (!(vLeft is string) && !(vLeft is SqlString)) {
1253                 SetTypeMismatchError(op, vLeft.GetType(), typeof(string));
1254             }
1255
1256             // WhiteSpace Chars Include : 0x9, 0xA, 0xB, 0xC, 0xD, 0x20, 0xA0, 0x2000, 0x2001, 0x2002, 0x2003, 0x2004, 0x2005, 0x2006, 0x2007, 0x2008, 0x2009, 0x200A, 0x200B, 0x3000, and 0xFEFF.
1257             char[] trimChars = new char[2] {(char)0x20, (char)0x3000};
1258             string tempStr;
1259             if (vLeft is SqlString)
1260                 tempStr = ((SqlString)vLeft).Value;
1261             else
1262                 tempStr = (string)vLeft;
1263
1264             string s1 = (tempStr).TrimEnd(trimChars);
1265
1266             switch (kind) {
1267                 case match_all:
1268                     return true;
1269                 case match_exact:
1270                     return(0 == table.Compare(s1, substring));
1271                 case match_middle:
1272                     return(0 <= table.IndexOf(s1, substring));
1273                 case match_left:
1274                     return(0 == table.IndexOf(s1, substring));
1275                 case match_right:
1276                     string s2 = substring.TrimEnd(trimChars);
1277                     return table.IsSuffix(s1, s2);
1278                 default:
1279                     Debug.Assert(false, "Unexpected LIKE kind");
1280                     return DBNull.Value;
1281             }
1282         }
1283
1284         internal string AnalyzePattern(string pat) {
1285
1286             int length = pat.Length;
1287             char[] patchars = new char[length+1];
1288             pat.CopyTo(0, patchars, 0, length);
1289             patchars[length] = (char)0;
1290             string substring = null;
1291
1292             char[] constchars = new char[length+1];
1293             int newLength = 0;
1294
1295             int stars = 0;
1296
1297             int i = 0;
1298
1299             while (i < length) {
1300
1301                 if (patchars[i] == '*' || patchars[i] == '%') {
1302
1303                     // replace conseq. * or % with one..
1304                     while ((patchars[i] == '*' || patchars[i] == '%') && i < length)
1305                         i++;
1306
1307                     // we allowing only *str* pattern
1308                     if ((i < length && newLength > 0) || stars >= 2) {
1309                         // we have a star inside string constant..
1310                         throw ExprException.InvalidPattern(pat);
1311                     }
1312                     stars++;
1313
1314                 }
1315                 else if (patchars[i] == '[') {
1316                     i++;
1317                     if (i >= length) {
1318                         throw ExprException.InvalidPattern(pat);
1319                     }
1320                     constchars[newLength++] = patchars[i++];
1321
1322                     if (i >= length) {
1323                         throw ExprException.InvalidPattern(pat);
1324                     }
1325
1326                     if (patchars[i] != ']') {
1327                         throw ExprException.InvalidPattern(pat);
1328                     }
1329                     i++;
1330                 }
1331                 else {
1332                     constchars[newLength++] = patchars[i];
1333                     i++;
1334                 }
1335             }
1336
1337             substring = new string(constchars, 0, newLength);
1338
1339             if (stars == 0) {
1340                 kind = match_exact;
1341             }
1342             else {
1343                 if (newLength > 0) {
1344                     if (patchars[0] == '*' || patchars[0] == '%') {
1345
1346                         if (patchars[length-1] == '*' || patchars[length-1] == '%') {
1347                             kind = match_middle;
1348                         }
1349                         else {
1350                             kind = match_right;
1351                         }
1352                     }
1353                     else {
1354                         Debug.Assert(patchars[length-1] == '*' || patchars[length-1] == '%', "Invalid LIKE pattern formed.. ");
1355                         kind = match_left;
1356                     }
1357                 }
1358                 else {
1359                     kind = match_all;
1360                 }
1361             }
1362             return substring;
1363         }
1364     }
1365 }