BinaryNode.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / fx / src / Data / System / Data / Filter / BinaryNode.cs / 1305376 / BinaryNode.cs

                            //------------------------------------------------------------------------------ 
// 
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// 
// [....] 
// [....]
// [....] 
//----------------------------------------------------------------------------- 

namespace System.Data { 
    using System;
    using System.Diagnostics;
    using System.Collections.Generic;
    using System.Globalization; 
    using System.ComponentModel;
    using System.Data.SqlTypes; 
    using System.Data.Common; 

    internal class BinaryNode : ExpressionNode { 
        internal int op;

        internal ExpressionNode left;
        internal ExpressionNode right; 

        internal BinaryNode(DataTable table, int op, ExpressionNode left, ExpressionNode right) : base(table) { 
            this.op = op; 
            this.left = left;
            this.right = right; 
        }

        internal override void Bind(DataTable table, List list) {
            BindTable(table); 
            left.Bind(table, list);
            right.Bind(table, list); 
        } 

        internal override object Eval() { 
            return Eval(null, DataRowVersion.Default);
        }

        internal override object Eval(DataRow row, DataRowVersion version) { 
            return EvalBinaryOp(op, left, right, row, version, null);
        } 
 
        internal override object Eval(int[] recordNos) {
            return EvalBinaryOp(op, left, right, null, DataRowVersion.Default, recordNos); 
        }

        internal override bool IsConstant() {
            // 
            return(left.IsConstant() && right.IsConstant());
        } 
 
        internal override bool IsTableConstant() {
            return(left.IsTableConstant() && right.IsTableConstant()); 
        }
        internal override bool HasLocalAggregate() {
            return(left.HasLocalAggregate() || right.HasLocalAggregate());
        } 

        internal override bool HasRemoteAggregate() { 
            return(left.HasRemoteAggregate() || right.HasRemoteAggregate()); 
        }
 
        internal override bool DependsOn(DataColumn column) {
            if (left.DependsOn(column))
                return true;
            return right.DependsOn(column); 
        }
 
        internal override ExpressionNode Optimize() { 
            left = left.Optimize();
 
            if (op == Operators.Is) {
                // only 'Is Null' or 'Is Not Null' are valid
                if (right is UnaryNode) {
                    UnaryNode un = (UnaryNode)right; 
                    if (un.op != Operators.Not) {
                        throw ExprException.InvalidIsSyntax(); 
                    } 
                    op = Operators.IsNot;
                    right = un.right; 
                }
                if (right is ZeroOpNode) {
                    if (((ZeroOpNode)right).op != Operators.Null) {
                        throw ExprException.InvalidIsSyntax(); 
                    }
                } 
                else { 
                    throw ExprException.InvalidIsSyntax();
                } 
            }
            else {
                right = right.Optimize();
            } 

 
            if (this.IsConstant()) { 

                object val = this.Eval(); 

                if (val == DBNull.Value) {
                    return new ZeroOpNode(Operators.Null);
                } 

                if (val is bool) { 
                    if ((bool)val) 
                        return new ZeroOpNode(Operators.True);
                    else 
                        return new ZeroOpNode(Operators.False);
                }
                return new ConstNode(table, ValueType.Object, val, false);
            } 
            else
                return this; 
        } 

        internal void SetTypeMismatchError(int op, Type left, Type right) { 
            throw ExprException.TypeMismatchInBinop(op, left, right);
        }

        private static object Eval(ExpressionNode expr, DataRow row, DataRowVersion version, int[] recordNos) { 
            if (recordNos == null) {
                return expr.Eval(row, version); 
            } 
            else {
                return expr.Eval(recordNos); 
            }
        }

        internal int BinaryCompare(object vLeft, object vRight, StorageType resultType, int op) { 
            int result = 0;
            try { 
                if (!DataStorage.IsSqlType(resultType)) { 
                    switch(resultType) {
                    case StorageType.SByte: 
                    case StorageType.Int16:
                    case StorageType.Int32:
                    case StorageType.Byte:
                    case StorageType.UInt16: 
                        return Convert.ToInt32(vLeft, FormatProvider).CompareTo(Convert.ToInt32(vRight, FormatProvider));
                    case StorageType.Int64: 
                    case StorageType.UInt32: 
                    case StorageType.UInt64:
                    case StorageType.Decimal: 
                        return Decimal.Compare(Convert.ToDecimal(vLeft, FormatProvider), Convert.ToDecimal(vRight, FormatProvider));
                    case StorageType.Char:
                        return Convert.ToInt32(vLeft, FormatProvider).CompareTo(Convert.ToInt32(vRight, FormatProvider));
                    case StorageType.Double: 
                        return Convert.ToDouble(vLeft, FormatProvider).CompareTo(Convert.ToDouble(vRight, FormatProvider));
                    case StorageType.Single: 
                        return Convert.ToSingle(vLeft, FormatProvider).CompareTo(Convert.ToSingle(vRight, FormatProvider)); 
                    case StorageType.DateTime:
                        return DateTime.Compare(Convert.ToDateTime(vLeft, FormatProvider), Convert.ToDateTime(vRight, FormatProvider)); 
                    case StorageType.DateTimeOffset:
                        // DTO can only be compared to DTO, other cases: cast Exception
                        return DateTimeOffset.Compare((DateTimeOffset)vLeft, (DateTimeOffset)vRight);
                    case StorageType.String: 
                        return table.Compare(Convert.ToString(vLeft, FormatProvider), Convert.ToString(vRight, FormatProvider));
                    case StorageType.Guid: 
                        return ((Guid)vLeft).CompareTo((Guid) vRight); 
                    case StorageType.Boolean:
                        if (op == Operators.EqualTo || op == Operators.NotEqual) { 
                            return Convert.ToInt32(DataExpression.ToBoolean(vLeft), FormatProvider) -
                                   Convert.ToInt32(DataExpression.ToBoolean(vRight), FormatProvider);
                        }
                        break; 
                    }
                } 
                else{ 
                    switch(resultType) {
                    case StorageType.SByte: 
                    case StorageType.Int16:
                    case StorageType.Int32:
                    case StorageType.Byte:
                    case StorageType.UInt16: 
                    case StorageType.SqlByte:
                    case StorageType.SqlInt16: 
                    case StorageType.SqlInt32: 
                        return SqlConvert.ConvertToSqlInt32(vLeft).CompareTo(SqlConvert.ConvertToSqlInt32(vRight));
                    case StorageType.Int64: 
                    case StorageType.UInt32:
                    case StorageType.SqlInt64:
                        return SqlConvert.ConvertToSqlInt64(vLeft).CompareTo(SqlConvert.ConvertToSqlInt64(vRight));
                    case StorageType.UInt64: 
                    case StorageType.SqlDecimal:
                        return SqlConvert.ConvertToSqlDecimal(vLeft).CompareTo(SqlConvert.ConvertToSqlDecimal(vRight)); 
                    case StorageType.SqlDouble: 
                        return SqlConvert.ConvertToSqlDouble(vLeft).CompareTo(SqlConvert.ConvertToSqlDouble(vRight));
                    case StorageType.SqlSingle: 
                        return SqlConvert.ConvertToSqlSingle(vLeft).CompareTo(SqlConvert.ConvertToSqlSingle(vRight));
                    case StorageType.SqlString:
                        return table.Compare(vLeft.ToString(), vRight.ToString());
                    case StorageType.SqlGuid: 
                        return ((SqlGuid)vLeft).CompareTo(vRight);
                    case StorageType.SqlBoolean: 
                        if (op == Operators.EqualTo || op == Operators.NotEqual) { 
                            result = 1;
                            if (((vLeft.GetType() == typeof(SqlBoolean)) && ((vRight.GetType() == typeof(SqlBoolean))|| (vRight.GetType() == typeof(Boolean))))|| 
                                ((vRight.GetType() == typeof(SqlBoolean)) && ((vLeft.GetType() == typeof(SqlBoolean))|| (vLeft.GetType() == typeof(Boolean))))){
                                return SqlConvert.ConvertToSqlBoolean(vLeft).CompareTo(SqlConvert.ConvertToSqlBoolean(vRight));
                            }
                        } 
                        break;
                    case StorageType.SqlBinary: 
                        return SqlConvert.ConvertToSqlBinary(vLeft).CompareTo(SqlConvert.ConvertToSqlBinary(vRight)); 
                    case StorageType.SqlDateTime:
                        return SqlConvert.ConvertToSqlDateTime(vLeft).CompareTo(SqlConvert.ConvertToSqlDateTime(vRight)); 
                    case StorageType.SqlMoney:
                        return SqlConvert.ConvertToSqlMoney(vLeft).CompareTo(SqlConvert.ConvertToSqlMoney(vRight));
                    }
                } 
            }
            catch (System.ArgumentException e) { 
                ExceptionBuilder.TraceExceptionWithoutRethrow(e); 
            }
            catch (System.FormatException e) { 
                ExceptionBuilder.TraceExceptionWithoutRethrow(e);
            }
            catch (System.InvalidCastException e) {
                ExceptionBuilder.TraceExceptionWithoutRethrow(e); 
            }
            catch (System.OverflowException e) { 
                ExceptionBuilder.TraceExceptionWithoutRethrow(e); 
            }
            catch (System.Data.EvaluateException e) { 
                ExceptionBuilder.TraceExceptionWithoutRethrow(e);
            }
            SetTypeMismatchError(op, vLeft.GetType(), vRight.GetType());
            return result; 
        }
 
        private object EvalBinaryOp(int op, ExpressionNode left, ExpressionNode right, DataRow row, DataRowVersion version, int[] recordNos) { 
            object vLeft;
            object vRight; 
            StorageType resultType;

            /*
            special case for OR and AND operators: we don't want to evaluate 
            both right and left operands, because we can shortcut :
                for OR  operator If one of the operands is true the result is true 
                for AND operator If one of rhe operands is flase the result is false 

*/ 

            if (op != Operators.Or && op != Operators.And && op != Operators.In && op != Operators.Is && op != Operators.IsNot) {
                vLeft  = BinaryNode.Eval(left, row, version, recordNos);
                vRight = BinaryNode.Eval(right, row, version, recordNos); 
                Type typeofLeft  = vLeft.GetType();
                Type typeofRight = vRight.GetType(); 
 
                StorageType leftStorage  = DataStorage.GetStorageType(typeofLeft);
                StorageType rightStorage = DataStorage.GetStorageType(typeofRight); 

                bool leftIsSqlType = DataStorage.IsSqlType(leftStorage);
                bool rightIsSqlType = DataStorage.IsSqlType(rightStorage);
 
                //    special case of handling NULLS, currently only OR operator can work with NULLS
                if (leftIsSqlType && DataStorage.IsObjectSqlNull(vLeft)) { 
                    return vLeft; 
                }
                else if (rightIsSqlType && DataStorage.IsObjectSqlNull(vRight)) { 
                    return vRight;
                }
                else if ((vLeft == DBNull.Value)||(vRight == DBNull.Value)) {
                    return DBNull.Value; 
                }
 
                if (leftIsSqlType || rightIsSqlType) { 
                     resultType = ResultSqlType(leftStorage, rightStorage, (left is ConstNode), (right is ConstNode), op);
                } 
                else {
                     resultType = ResultType(leftStorage, rightStorage, (left is ConstNode), (right is ConstNode), op);
                }
 
                if (StorageType.Empty == resultType) {
                    SetTypeMismatchError(op, typeofLeft, typeofRight); 
                } 

            } 
            else {
                vLeft = vRight = DBNull.Value;
                resultType = StorageType.Empty; // shouldnt we make it boolean?
            } 

            object value = DBNull.Value; 
            bool typeMismatch = false; 

            try { 
                switch (op) {
                case Operators.Plus:
                    switch(resultType) {
                    case StorageType.Byte:{ 
                        value = Convert.ToByte((Convert.ToByte(vLeft, FormatProvider) + Convert.ToByte(vRight, FormatProvider)), FormatProvider);
                        break;} 
                    case StorageType.SByte:{ 
                        value = Convert.ToSByte((Convert.ToSByte(vLeft, FormatProvider) + Convert.ToSByte(vRight, FormatProvider)), FormatProvider);
                        break;} 
                    case StorageType.Int16:{
                        value = Convert.ToInt16((Convert.ToInt16(vLeft, FormatProvider) + Convert.ToInt16(vRight, FormatProvider)), FormatProvider);
                        break;}
                    case StorageType.UInt16:{ 
                        value = Convert.ToUInt16((Convert.ToUInt16(vLeft, FormatProvider) + Convert.ToUInt16(vRight, FormatProvider)), FormatProvider);
                        break;} 
                    case StorageType.Int32: { 
                        checked {value = Convert.ToInt32(vLeft, FormatProvider) + Convert.ToInt32(vRight, FormatProvider);}
                        break;} 
                    case StorageType.UInt32: {
                        checked {value = Convert.ToUInt32(vLeft, FormatProvider) + Convert.ToUInt32(vRight, FormatProvider);}
                        break;}
                    case StorageType.UInt64: { 
                        checked {value = Convert.ToUInt64(vLeft, FormatProvider) + Convert.ToUInt64(vRight, FormatProvider);}
                        break;} 
                    case StorageType.Int64:{ 
                        checked {value = Convert.ToInt64(vLeft, FormatProvider) + Convert.ToInt64(vRight, FormatProvider);}
                        break;} 
                    case StorageType.Decimal:{
                        checked {value = Convert.ToDecimal(vLeft, FormatProvider) + Convert.ToDecimal(vRight, FormatProvider);}
                        break;}
                    case StorageType.Single:{ 
                        checked {value = Convert.ToSingle(vLeft, FormatProvider) + Convert.ToSingle(vRight, FormatProvider);}
                        break;} 
                    case StorageType.Double:{ 
                        checked {value = Convert.ToDouble(vLeft, FormatProvider) + Convert.ToDouble(vRight, FormatProvider);}
                        break;} 
                    case StorageType.String:
                    case StorageType.Char:{
                        value = Convert.ToString(vLeft, FormatProvider) + Convert.ToString(vRight, FormatProvider);
                        break;} 
                    case StorageType.DateTime:{
                        // one of the operands should be a DateTime, and an other a TimeSpan 
 
                        if (vLeft is TimeSpan && vRight is DateTime) {
                            value = (DateTime)vRight + (TimeSpan)vLeft; 
                        }
                        else if (vLeft is DateTime && vRight is TimeSpan) {
                            value = (DateTime)vLeft + (TimeSpan)vRight;
                        } 
                        else {
                            typeMismatch = true; 
                        } 
                        break;}
                    case StorageType.TimeSpan:{ 
                        value = (TimeSpan)vLeft + (TimeSpan)vRight;
                        break;}
                    case StorageType.SqlInt16:{
                        value = (SqlConvert.ConvertToSqlInt16(vLeft) + SqlConvert.ConvertToSqlInt16(vRight)); 
                        break;}
                    case StorageType.SqlInt32:{ 
                        value = ( SqlConvert.ConvertToSqlInt32(vLeft) + SqlConvert.ConvertToSqlInt32(vRight)); 
                        break;}
                    case StorageType.SqlInt64:{ 
                        value = (SqlConvert.ConvertToSqlInt64(vLeft) + SqlConvert.ConvertToSqlInt64(vRight));
                        break;}
                    case StorageType.SqlDouble:{
                        value = (SqlConvert.ConvertToSqlDouble(vLeft) + SqlConvert.ConvertToSqlDouble(vRight)); 
                        break;}
                    case StorageType.SqlSingle:{ 
                        value = (SqlConvert.ConvertToSqlSingle(vLeft)+ SqlConvert.ConvertToSqlSingle(vRight)); 
                        break;}
                    case StorageType.SqlDecimal:{ 
                        value = (SqlConvert.ConvertToSqlDecimal(vLeft) + SqlConvert.ConvertToSqlDecimal(vRight));
                        break;}
                    case StorageType.SqlMoney:{
                        value = (SqlConvert.ConvertToSqlMoney(vLeft) + SqlConvert.ConvertToSqlMoney(vRight)); 
                        break;}
                    case StorageType.SqlByte:{ 
                        value = (SqlConvert.ConvertToSqlByte(vLeft) + SqlConvert.ConvertToSqlByte(vRight)); 
                        break;}
                    case StorageType.SqlString:{ 
                        value = (SqlConvert.ConvertToSqlString(vLeft) + SqlConvert.ConvertToSqlString(vRight));
                        break;}
                    case StorageType.SqlDateTime:{
                        if (vLeft is TimeSpan && vRight is SqlDateTime) { 
                          SqlDateTime rValue = (SqlDateTime)SqlConvert.ConvertToSqlDateTime(vRight);
                          value = (SqlDateTime)SqlConvert.ConvertToSqlDateTime((DateTime)rValue.Value + (TimeSpan)vLeft); 
                        } 
                        else if (vLeft is SqlDateTime && vRight is TimeSpan) {
                          SqlDateTime lValue = (SqlDateTime)SqlConvert.ConvertToSqlDateTime(vLeft); 
                          value = (SqlDateTime)SqlConvert.ConvertToSqlDateTime((DateTime)lValue.Value + (TimeSpan)vRight);
                        }
                        else {
                            typeMismatch = true; 
                        }
                        break;} 
                    default:{ 
                        typeMismatch = true;
                        break;} 
                    }
                    break; // Operators.Plus

                case Operators.Minus: 
                    switch(resultType) {
                    case StorageType.Byte: { 
                        value = Convert.ToByte((Convert.ToByte(vLeft, FormatProvider) - Convert.ToByte(vRight, FormatProvider)), FormatProvider); 
                    break; }
                    case StorageType.SqlByte: { 
                        value = (SqlConvert.ConvertToSqlByte(vLeft) - SqlConvert.ConvertToSqlByte(vRight));
                    break;}
                    case StorageType.SByte:{
                        value = Convert.ToSByte((Convert.ToSByte(vLeft, FormatProvider) - Convert.ToSByte(vRight, FormatProvider)), FormatProvider); 
                    break;}
                    case StorageType.Int16:{ 
                        value = Convert.ToInt16((Convert.ToInt16(vLeft, FormatProvider) - Convert.ToInt16(vRight, FormatProvider)), FormatProvider); 
                    break;}
                    case StorageType.SqlInt16:{ 
                        value = (SqlConvert.ConvertToSqlInt16(vLeft) - SqlConvert.ConvertToSqlInt16(vRight));
                    break;}
                    case StorageType.UInt16:{
                        value = Convert.ToUInt16((Convert.ToUInt16(vLeft, FormatProvider) - Convert.ToUInt16(vRight, FormatProvider)), FormatProvider); 
                    break;}
                    case StorageType.Int32:{ 
                        checked {value = Convert.ToInt32(vLeft, FormatProvider) - Convert.ToInt32(vRight, FormatProvider);} 
                    break;}
                    case StorageType.SqlInt32:{ 
                        value = (SqlConvert.ConvertToSqlInt32(vLeft) - SqlConvert.ConvertToSqlInt32(vRight));
                    break;}
                    case StorageType.UInt32:{
                        checked {value = Convert.ToUInt32(vLeft, FormatProvider) - Convert.ToUInt32(vRight, FormatProvider);} 
                    break;}
                    case StorageType.Int64:{ 
                        checked {value = Convert.ToInt64(vLeft, FormatProvider) - Convert.ToInt64(vRight, FormatProvider);} 
                    break;}
                    case StorageType.SqlInt64:{ 
                        value = (SqlConvert.ConvertToSqlInt64(vLeft) - SqlConvert.ConvertToSqlInt64(vRight));
                    break;}
                    case StorageType.UInt64:{
                        checked {value = Convert.ToUInt64(vLeft, FormatProvider) - Convert.ToUInt64(vRight, FormatProvider);} 
                        break;}
                    case StorageType.Decimal:{ 
                        checked {value = Convert.ToDecimal(vLeft, FormatProvider) - Convert.ToDecimal(vRight, FormatProvider);} 
                        break;}
                    case StorageType.SqlDecimal:{ 
                        value = (SqlConvert.ConvertToSqlDecimal(vLeft) - SqlConvert.ConvertToSqlDecimal(vRight));
                        break;}
                    case StorageType.Single:{
                        checked {value = Convert.ToSingle(vLeft, FormatProvider) - Convert.ToSingle(vRight, FormatProvider);} 
                        break;}
                    case StorageType.SqlSingle:{ 
                        value = (SqlConvert.ConvertToSqlSingle(vLeft) - SqlConvert.ConvertToSqlSingle(vRight)); 
                        break;}
                    case StorageType.Double:{ 
                        checked {value = Convert.ToDouble(vLeft, FormatProvider) - Convert.ToDouble(vRight, FormatProvider);}
                        break;}
                    case StorageType.SqlDouble:{
                        value = (SqlConvert.ConvertToSqlDouble(vLeft) - SqlConvert.ConvertToSqlDouble(vRight)); 
                        break;}
                    case StorageType.SqlMoney:{ 
                        value = (SqlConvert.ConvertToSqlMoney(vLeft) - SqlConvert.ConvertToSqlMoney(vRight)); 
                        break;}
                    case StorageType.DateTime:{ 
                        value = (DateTime)vLeft - (TimeSpan)vRight;
                        break;}
                    case StorageType.TimeSpan:{
                        if (vLeft is DateTime) { 
                            value = (DateTime)vLeft - (DateTime)vRight;
                        } 
                        else 
                            value = (TimeSpan)vLeft - (TimeSpan)vRight;
                        break;} 
                    case StorageType.SqlDateTime:{
                        if (vLeft is TimeSpan && vRight is SqlDateTime) {
                          SqlDateTime rValue = (SqlDateTime)SqlConvert.ConvertToSqlDateTime(vRight);
                          value = (SqlDateTime)SqlConvert.ConvertToSqlDateTime((DateTime)rValue.Value - (TimeSpan)vLeft); 
                        }
                        else if (vLeft is SqlDateTime && vRight is TimeSpan) { 
                          SqlDateTime lValue = (SqlDateTime)SqlConvert.ConvertToSqlDateTime(vLeft); 
                          value = (SqlDateTime)SqlConvert.ConvertToSqlDateTime((DateTime)lValue.Value - (TimeSpan)vRight);
                        } 
                        else {
                            typeMismatch = true;
                        }
                        break;} 
                    default:{
                        typeMismatch = true; 
                        break;} 
                    }
                    break; // Operators.Minus 

                case Operators.Multiply:
                    switch(resultType) {
                    case StorageType.Byte:{ 
                        value = Convert.ToByte((Convert.ToByte(vLeft, FormatProvider) * Convert.ToByte(vRight, FormatProvider)), FormatProvider);
                        break;} 
                    case StorageType.SqlByte:{ 
                        value = (SqlConvert.ConvertToSqlByte(vLeft) * SqlConvert.ConvertToSqlByte(vRight));
                        break;} 
                    case StorageType.SByte:{
                        value = Convert.ToSByte((Convert.ToSByte(vLeft, FormatProvider) * Convert.ToSByte(vRight, FormatProvider)), FormatProvider);
                        break;}
                    case StorageType.Int16:{ 
                        value = Convert.ToInt16((Convert.ToInt16(vLeft, FormatProvider) * Convert.ToInt16(vRight, FormatProvider)), FormatProvider);
                        break;} 
                    case StorageType.SqlInt16:{ 
                        value = (SqlConvert.ConvertToSqlInt16(vLeft) * SqlConvert.ConvertToSqlInt16(vRight));
                        break;} 
                    case StorageType.UInt16:{
                        value = Convert.ToUInt16((Convert.ToUInt16(vLeft, FormatProvider) * Convert.ToUInt16(vRight, FormatProvider)), FormatProvider);
                        break;}
                    case StorageType.Int32:{ 
                        checked {value = Convert.ToInt32(vLeft, FormatProvider) * Convert.ToInt32(vRight, FormatProvider);}
                        break;} 
                    case StorageType.SqlInt32:{ 
                        value = (SqlConvert.ConvertToSqlInt32(vLeft) * SqlConvert.ConvertToSqlInt32(vRight));
                        break;} 
                    case StorageType.UInt32:{
                        checked {value = Convert.ToUInt32(vLeft, FormatProvider) * Convert.ToUInt32(vRight, FormatProvider);}
                        break;}
                    case StorageType.Int64:{ 

                        checked {value = Convert.ToInt64(vLeft, FormatProvider) * Convert.ToInt64(vRight, FormatProvider);} 
                        break;} 
                    case StorageType.SqlInt64:{
                        value = (SqlConvert.ConvertToSqlInt64(vLeft) * SqlConvert.ConvertToSqlInt64(vRight)); 
                        break;}
                    case StorageType.UInt64:{
                        checked {value = Convert.ToUInt64(vLeft, FormatProvider) * Convert.ToUInt64(vRight, FormatProvider);}
                        break;} 
                    case StorageType.Decimal:{
                        checked {value = Convert.ToDecimal(vLeft, FormatProvider) * Convert.ToDecimal(vRight, FormatProvider);} 
                        break;} 
                    case StorageType.SqlDecimal:{
                        value = (SqlConvert.ConvertToSqlDecimal(vLeft) * SqlConvert.ConvertToSqlDecimal(vRight)); 
                        break;}
                    case StorageType.Single:{
                        checked {value = Convert.ToSingle(vLeft, FormatProvider) * Convert.ToSingle(vRight, FormatProvider);}
                        break;} 
                    case StorageType.SqlSingle:{
                        value = ( SqlConvert.ConvertToSqlSingle(vLeft) * SqlConvert.ConvertToSqlSingle(vRight)); 
                        break;} 
                    case StorageType.SqlMoney:{
                        value = (SqlConvert.ConvertToSqlMoney(vLeft) * SqlConvert.ConvertToSqlMoney(vRight)); 
                        break;}
                    case StorageType.Double:{
                        checked {value = Convert.ToDouble(vLeft, FormatProvider) * Convert.ToDouble(vRight, FormatProvider);}
                        break;} 
                    case StorageType.SqlDouble:{
                        value = (SqlConvert.ConvertToSqlDouble(vLeft) * SqlConvert.ConvertToSqlDouble(vRight)); 
                        break;} 
                    default:{
                        typeMismatch = true; 
                        break;}
                    }
                    break; // Operators.Multiply
 
                case Operators.Divide:
                    switch(resultType) { 
                    case StorageType.Byte:{ 
                        value = Convert.ToByte((Convert.ToByte(vLeft, FormatProvider) / Convert.ToByte(vRight, FormatProvider)), FormatProvider);
                        break;} 
                    case StorageType.SqlByte:{
                        value = (SqlConvert.ConvertToSqlByte(vLeft) / SqlConvert.ConvertToSqlByte(vRight));
                        break;}
                    case StorageType.SByte:{ 
                        value = Convert.ToSByte((Convert.ToSByte(vLeft, FormatProvider) / Convert.ToSByte(vRight, FormatProvider)), FormatProvider);
                        break;} 
                    case StorageType.Int16:{ 
                        value = Convert.ToInt16((Convert.ToInt16(vLeft, FormatProvider) / Convert.ToInt16(vRight, FormatProvider)), FormatProvider);
                        break;} 
                    case StorageType.SqlInt16:{
                        value = (SqlConvert.ConvertToSqlInt16(vLeft) / SqlConvert.ConvertToSqlInt16(vRight));
                        break;}
                    case StorageType.UInt16:{ 
                        value = Convert.ToUInt16((Convert.ToUInt16(vLeft, FormatProvider) / Convert.ToUInt16(vRight, FormatProvider)), FormatProvider);
                        break;} 
                    case StorageType.Int32:{ 
                        checked {value = Convert.ToInt32(vLeft, FormatProvider) / Convert.ToInt32(vRight, FormatProvider);}
                        break;} 
                    case StorageType.SqlInt32:{
                        value = (SqlConvert.ConvertToSqlInt32(vLeft) / SqlConvert.ConvertToSqlInt32(vRight));
                        break;}
                    case StorageType.UInt32:{ 
                        checked {value = Convert.ToUInt32(vLeft, FormatProvider) / Convert.ToUInt32(vRight, FormatProvider);}
                        break;} 
                    case StorageType.UInt64:{ 
                        checked {value = Convert.ToUInt64(vLeft, FormatProvider) / Convert.ToUInt64(vRight, FormatProvider);}
                        break;} 
                    case StorageType.Int64:{
                        checked {value = Convert.ToInt64(vLeft, FormatProvider) / Convert.ToInt64(vRight, FormatProvider);}
                        break;}
                    case StorageType.SqlInt64:{ 
                        value = (SqlConvert.ConvertToSqlInt64(vLeft) / SqlConvert.ConvertToSqlInt64(vRight));
                        break;} 
                    case StorageType.Decimal:{ 
                        checked {value = Convert.ToDecimal(vLeft, FormatProvider) / Convert.ToDecimal(vRight, FormatProvider);}
                        break;} 
                    case StorageType.SqlDecimal:{
                        value = (SqlConvert.ConvertToSqlDecimal(vLeft) / SqlConvert.ConvertToSqlDecimal(vRight));
                        break;}
                    case StorageType.Single:{ 
                        checked {value = Convert.ToSingle(vLeft, FormatProvider) / Convert.ToSingle(vRight, FormatProvider);}
                        break;} 
                    case StorageType.SqlSingle:{ 
                        value = ( SqlConvert.ConvertToSqlSingle(vLeft) / SqlConvert.ConvertToSqlSingle(vRight));
                        break;} 
                    case StorageType.SqlMoney:{
                        value = (SqlConvert.ConvertToSqlMoney(vLeft) / SqlConvert.ConvertToSqlMoney(vRight));
                        break;}
                    case StorageType.Double:{ 
                        Double b = Convert.ToDouble(vRight, FormatProvider);
                        checked {value = Convert.ToDouble(vLeft, FormatProvider) / b;} 
                        break;} 
                    case StorageType.SqlDouble:{
                        value = (SqlConvert.ConvertToSqlDouble(vLeft) / SqlConvert.ConvertToSqlDouble(vRight)); 
                        break;}
                    default:{
                        typeMismatch = true;
                        break;} 
                    }
                    break; // Operators.Divide 
 
                case Operators.EqualTo:
                    if ((vLeft == DBNull.Value)||(left.IsSqlColumn && DataStorage.IsObjectSqlNull(vLeft)) || 
                         (vRight == DBNull.Value)||(right.IsSqlColumn && DataStorage.IsObjectSqlNull(vRight)))
                        return DBNull.Value;
                    return(0 == BinaryCompare (vLeft, vRight, resultType, Operators.EqualTo));
 
                case Operators.GreaterThen:
                    if ((vLeft == DBNull.Value)||(left.IsSqlColumn && DataStorage.IsObjectSqlNull(vLeft)) || 
                         (vRight == DBNull.Value)||(right.IsSqlColumn && DataStorage.IsObjectSqlNull(vRight))) 
                        return DBNull.Value;
                    return(0 < BinaryCompare (vLeft, vRight, resultType,  op)); 

                case Operators.LessThen:
                    if ((vLeft == DBNull.Value)||(left.IsSqlColumn && DataStorage.IsObjectSqlNull(vLeft)) ||
                         (vRight == DBNull.Value)||(right.IsSqlColumn && DataStorage.IsObjectSqlNull(vRight))) 
                        return DBNull.Value;
                    return(0 > BinaryCompare (vLeft, vRight, resultType,  op)); 
 
                case Operators.GreaterOrEqual:
                    if ((vLeft == DBNull.Value)||(left.IsSqlColumn && DataStorage.IsObjectSqlNull(vLeft)) || 
                         (vRight == DBNull.Value)||(right.IsSqlColumn && DataStorage.IsObjectSqlNull(vRight)))
                        return DBNull.Value;
                    return(0 <= BinaryCompare (vLeft, vRight, resultType, op));
 
                case Operators.LessOrEqual:
                    if (((vLeft == DBNull.Value)||(left.IsSqlColumn && DataStorage.IsObjectSqlNull(vLeft))) || 
                         ((vRight == DBNull.Value)||(right.IsSqlColumn && DataStorage.IsObjectSqlNull(vRight)))) 
                        return DBNull.Value;
                    return(0 >= BinaryCompare (vLeft, vRight, resultType, op)); 

                case Operators.NotEqual:
                    if (((vLeft == DBNull.Value)||(left.IsSqlColumn && DataStorage.IsObjectSqlNull(vLeft))) ||
                         ((vRight == DBNull.Value)||(right.IsSqlColumn && DataStorage.IsObjectSqlNull(vRight)))) 
                        return DBNull.Value;
                    return(0 != BinaryCompare (vLeft, vRight, resultType, op)); 
 
                case Operators.Is:
                    vLeft  = BinaryNode.Eval(left, row, version, recordNos); 
                    if ((vLeft == DBNull.Value)||(left.IsSqlColumn && DataStorage.IsObjectSqlNull(vLeft))){
                        return true;
                    }
                    return false; 

                case Operators.IsNot: 
                    vLeft  = BinaryNode.Eval(left, row, version, recordNos); 
                    if ((vLeft == DBNull.Value)||(left.IsSqlColumn && DataStorage.IsObjectSqlNull(vLeft))){
                        return false; 
                    }
                    return true;

                case Operators.And: 
                    /*
                    special case evaluating of the AND operator: we don't want to evaluate 
                    both right and left operands, because we can shortcut : 
                        If one of the operands is flase the result is false
 
*/
                    vLeft  = BinaryNode.Eval(left, row, version, recordNos);
                    if ((vLeft == DBNull.Value)||(left.IsSqlColumn && DataStorage.IsObjectSqlNull(vLeft)))
                        return DBNull.Value; 

                    if ((!(vLeft is bool)) && (!(vLeft is SqlBoolean))){ 
                        vRight = BinaryNode.Eval(right, row, version, recordNos); 
                        typeMismatch = true;
                        break; 
                    }

                    if (vLeft is bool){
                        if ((bool)vLeft == false){ 
                           value = false;
                           break; 
                        } 
                    }
                    else{ 
                        if (((SqlBoolean) vLeft).IsFalse){
                            value = false;
                            break;
                        } 
                    }
                    vRight = BinaryNode.Eval(right, row, version, recordNos); 
                    if ((vRight  == DBNull.Value)||(right.IsSqlColumn && DataStorage.IsObjectSqlNull(vRight ))) 
                        return DBNull.Value;
 
                    if ((!(vRight is bool)) && (!(vRight is SqlBoolean))){
                        typeMismatch = true;
                        break;
                    } 

                    if (vRight is bool){ 
                        value = (bool)vRight; 
                        break;
                    } 
                    else{
                        value = ((SqlBoolean) vRight).IsTrue;
                    }
                    break; 
                case Operators.Or:
                    /* 
                    special case evaluating the OR operator: we don't want to evaluate 
                    both right and left operands, because we can shortcut :
                        If one of the operands is true the result is true 

*/

                    vLeft = BinaryNode.Eval(left, row, version, recordNos); 

                    if ((vLeft != DBNull.Value) && (!DataStorage.IsObjectSqlNull(vLeft))) { 
                        if ((!(vLeft is bool)) && (!(vLeft is SqlBoolean))) { 
                            vRight = BinaryNode.Eval(right, row, version, recordNos);
                            typeMismatch = true; 
                            break;
                        }

                        if ((bool)vLeft == true) { 
                            value = true;
                            break; 
                        } 
                    }
 
                    vRight = BinaryNode.Eval(right, row, version, recordNos);
                    if ((vRight == DBNull.Value)||(DataStorage.IsObjectSqlNull(vRight)))
                        return vLeft;
 
                    if ((vLeft == DBNull.Value)||(DataStorage.IsObjectSqlNull(vLeft)))
                        return vRight; 
 
                    if ((!(vRight is bool)) && (!(vRight is SqlBoolean))) {
                        typeMismatch = true; 
                        break;
                    }

                    value = (vRight is bool) ? ((bool)vRight) : (((SqlBoolean)vRight).IsTrue); 
                    break;
 
/*  for M3, use original code , in below,  and make sure to have two different code path; increases perf 

                    vLeft = BinaryNode.Eval(left, row, version, recordNos); 
                    if (vLeft != DBNull.Value) {
                        if (!(vLeft is bool)) {
                            vRight = BinaryNode.Eval(right, row, version, recordNos);
                            typeMismatch = true; 
                            break;
                        } 
 
                        if ((bool)vLeft == true) {
                            value = true; 
                            break;
                        }
                    }
 
                    vRight = BinaryNode.Eval(right, row, version, recordNos);
                    if (vRight == DBNull.Value) 
                        return vLeft; 

                    if (vLeft == DBNull.Value) 
                        return vRight;

                    if (!(vRight is bool)) {
                        typeMismatch = true; 
                        break;
                    } 
 
                    value = (bool)vRight;
                    break; 
*/

                case Operators.Modulo:
                    if (ExpressionNode.IsIntegerSql(resultType)) { 
                        if (resultType == StorageType.UInt64) {
                            value = Convert.ToUInt64(vLeft, FormatProvider) % Convert.ToUInt64(vRight, FormatProvider); 
                        } 
                        else if (DataStorage.IsSqlType(resultType)) {
                            SqlInt64 res = (SqlConvert.ConvertToSqlInt64(vLeft) % SqlConvert.ConvertToSqlInt64(vRight)); 

                            if (resultType == StorageType.SqlInt32){
                                value =  (SqlInt32) res.ToSqlInt32();
                            } 
                            else if (resultType == StorageType.SqlInt16){
                                value =  (SqlInt16) res.ToSqlInt16(); 
                            } 
                            else if (resultType == StorageType.SqlByte){
                                value =  (SqlByte) res.ToSqlByte(); 
                            }
                            else{
                                value =  (SqlInt64) res;
                            } 
                        }
                        else { 
                            value = Convert.ToInt64(vLeft, FormatProvider) % Convert.ToInt64(vRight, FormatProvider); 
                            value = Convert.ChangeType(value, DataStorage.GetTypeStorage(resultType), FormatProvider);
                        } 
                    }
                    else {
                        typeMismatch = true;
                    } 
                    break;
 
                case Operators.In: 
                    /*
                    special case evaluating of the IN operator: the right have to be IN function node 
                    */


                    if (!(right is FunctionNode)) { 
                        // this is more like an Assert: should never happens, so we do not care about "nice" Exseptions
                        throw ExprException.InWithoutParentheses(); 
                    } 

                    vLeft = BinaryNode.Eval(left, row, version, recordNos); 

                    if ((vLeft == DBNull.Value)||(left.IsSqlColumn && DataStorage.IsObjectSqlNull(vLeft)))
                        return DBNull.Value;
 
                    /* validate IN parameters : must all be constant expressions */
 
                    value = false; 

                    FunctionNode into = (FunctionNode)right; 

                    for (int i = 0; i < into.argumentCount; i++) {
                        vRight = into.arguments[i].Eval();
 

                    if ((vRight == DBNull.Value)||(right.IsSqlColumn && DataStorage.IsObjectSqlNull(vRight))) 
                            continue; 
                        Debug.Assert((!DataStorage.IsObjectNull(vLeft))&& (!DataStorage.IsObjectNull(vRight)), "Imposible..");
 
                        resultType = DataStorage.GetStorageType(vLeft.GetType());

                        if (0 == BinaryCompare(vLeft, vRight, resultType,  Operators.EqualTo)) {
                            value = true; 
                            break;
                        } 
                    } 
                    break;
 
                default:
                    throw ExprException.UnsupportedOperator(op);
                }
            } 
            catch (OverflowException) {
                throw ExprException.Overflow(DataStorage.GetTypeStorage(resultType)); 
            } 
            if (typeMismatch) {
                SetTypeMismatchError(op, vLeft.GetType(), vRight.GetType()); 
            }

            return value;
        } 

        // Data type precedence rules specify which data type is converted to the other. 
        // The data type with the lower precedence is converted to the data type with the higher precedence. 
        // If the conversion is not a supported implicit conversion, an error is returned.
        // When both operand expressions have the same data type, the result of the operation has that data type. 
        // This is the precedence order for the DataSet numeric data types:

        private enum DataTypePrecedence {
           SqlDateTime = 25, 
           DateTimeOffset = 24,
           DateTime = 23, 
           TimeSpan = 20, 
           SqlDouble = 19,
           Double = 18, 
           SqlSingle = 17,
           Single = 16,
           SqlDecimal = 15,
           Decimal = 14, 
           SqlMoney = 13,
           UInt64 = 12, 
           SqlInt64 = 11, 
           Int64 = 10,
           UInt32 = 9, 
           SqlInt32 = 8,
           Int32 = 7,
           UInt16 = 6,
           SqlInt16 = 5, 
           Int16 = 4,
           Byte = 3, 
           SqlByte = 2, 
           SByte = 1,
           Error = 0, 
           SqlBoolean = -1,
           Boolean = -2,
           SqlGuid = -3,
           SqlString = -4, 
           String = -5,
           SqlXml = -6, 
           SqlChars = -7, 
           Char = -8,
           SqlBytes = -9, 
           SqlBinary = -10,
        }

        private DataTypePrecedence GetPrecedence(StorageType storageType) { 
            switch(storageType) {
            case StorageType.Boolean: return DataTypePrecedence.Boolean; 
            case StorageType.Char: return DataTypePrecedence.Char; 
            case StorageType.SByte: return DataTypePrecedence.SByte;
            case StorageType.Byte: return DataTypePrecedence.Byte; 
            case StorageType.Int16: return DataTypePrecedence.Int16;
            case StorageType.UInt16: return DataTypePrecedence.UInt16;
            case StorageType.Int32: return DataTypePrecedence.Int32;
            case StorageType.UInt32: return DataTypePrecedence.UInt32; 
            case StorageType.Int64: return DataTypePrecedence.Int64;
            case StorageType.UInt64: return DataTypePrecedence.UInt64; 
            case StorageType.Single: return DataTypePrecedence.Single; 
            case StorageType.Double: return DataTypePrecedence.Double;
            case StorageType.Decimal: return DataTypePrecedence.Decimal; 
            case StorageType.DateTime: return DataTypePrecedence.DateTime;
            case StorageType.DateTimeOffset: return DataTypePrecedence.DateTimeOffset;
            case StorageType.TimeSpan: return DataTypePrecedence.TimeSpan;
            case StorageType.String: return DataTypePrecedence.String; 
            case StorageType.SqlBinary: return DataTypePrecedence.SqlBinary;
            case StorageType.SqlBoolean: return DataTypePrecedence.SqlBoolean; 
            case StorageType.SqlByte: return DataTypePrecedence.SqlByte; 
            case StorageType.SqlBytes: return DataTypePrecedence.SqlBytes;
            case StorageType.SqlChars: return DataTypePrecedence.SqlChars; 
            case StorageType.SqlDateTime: return DataTypePrecedence.SqlDateTime;
            case StorageType.SqlDecimal: return DataTypePrecedence.SqlDecimal;
            case StorageType.SqlDouble: return DataTypePrecedence.SqlDouble;
            case StorageType.SqlGuid: return DataTypePrecedence.SqlGuid; 
            case StorageType.SqlInt16: return DataTypePrecedence.SqlInt16;
            case StorageType.SqlInt32: return DataTypePrecedence.SqlInt32; 
            case StorageType.SqlInt64: return DataTypePrecedence.SqlInt64; 
            case StorageType.SqlMoney: return DataTypePrecedence.SqlMoney;
            case StorageType.SqlSingle: return DataTypePrecedence.SqlSingle; 
            case StorageType.SqlString: return DataTypePrecedence.SqlString;
//            case StorageType.SqlXml: return DataTypePrecedence.SqlXml;
            case StorageType.Empty:
            case StorageType.Object: 
            case StorageType.DBNull:
            default: return DataTypePrecedence.Error; 
            } 
        }
 
        private static StorageType GetPrecedenceType(DataTypePrecedence code) {
            switch (code) {
            case DataTypePrecedence.Error:       return StorageType.Empty;
            case DataTypePrecedence.SByte:       return StorageType.SByte; 
            case DataTypePrecedence.Byte:        return StorageType.Byte;
            case DataTypePrecedence.Int16:       return StorageType.Int16; 
            case DataTypePrecedence.UInt16:      return StorageType.UInt16; 
            case DataTypePrecedence.Int32:       return StorageType.Int32;
            case DataTypePrecedence.UInt32:      return StorageType.UInt32; 
            case DataTypePrecedence.Int64:       return StorageType.Int64;
            case DataTypePrecedence.UInt64:      return StorageType.UInt64;
            case DataTypePrecedence.Decimal:     return StorageType.Decimal;
            case DataTypePrecedence.Single:      return StorageType.Single; 
            case DataTypePrecedence.Double:      return StorageType.Double;
 
            case DataTypePrecedence.Boolean:     return StorageType.Boolean; 
            case DataTypePrecedence.String:      return StorageType.String;
            case DataTypePrecedence.Char:        return StorageType.Char; 

            case DataTypePrecedence.DateTimeOffset:  return StorageType.DateTimeOffset;
            case DataTypePrecedence.DateTime:    return StorageType.DateTime;
            case DataTypePrecedence.TimeSpan:    return StorageType.TimeSpan; 

            case DataTypePrecedence.SqlDateTime: return StorageType.SqlDateTime; 
            case DataTypePrecedence.SqlDouble:   return StorageType.SqlDouble; 
            case DataTypePrecedence.SqlSingle:   return StorageType.SqlSingle;
            case DataTypePrecedence.SqlDecimal:  return StorageType.SqlDecimal; 
            case DataTypePrecedence.SqlInt64:    return StorageType.SqlInt64;
            case DataTypePrecedence.SqlInt32:    return StorageType.SqlInt32;
            case DataTypePrecedence.SqlInt16:    return StorageType.SqlInt16;
            case DataTypePrecedence.SqlByte:     return StorageType.SqlByte; 
            case DataTypePrecedence.SqlBoolean:  return StorageType.SqlBoolean;
            case DataTypePrecedence.SqlString:   return StorageType.SqlString; 
            case DataTypePrecedence.SqlGuid:     return StorageType.SqlGuid; 
            case DataTypePrecedence.SqlBinary:   return StorageType.SqlBinary;
            case DataTypePrecedence.SqlMoney:    return StorageType.SqlMoney; 
            default:
            Debug.Assert(false, "Invalid (unmapped) precedence " + code.ToString());
            goto case DataTypePrecedence.Error;
            } 
        }
 
        private bool IsMixed(StorageType left, StorageType right) { 
            return ((IsSigned(left) && IsUnsigned(right)) ||
                    (IsUnsigned(left) && IsSigned(right))); 
        }

        private bool IsMixedSql(StorageType left, StorageType right) {
            return ((IsSignedSql(left) && IsUnsignedSql(right)) || 
                    (IsUnsignedSql(left) && IsSignedSql(right)));
        } 
 
        internal StorageType ResultType(StorageType left, StorageType right, bool lc, bool rc, int op) {
            if ((left == StorageType.Guid) && (right == StorageType.Guid) && Operators.IsRelational(op)) 
                return left;
            if ((left == StorageType.String) && (right == StorageType.Guid) && Operators.IsRelational(op))
                return left;
            if ((left == StorageType.Guid) && (right == StorageType.String) && Operators.IsRelational(op)) 
                return right;
 
             int leftPrecedence = (int)GetPrecedence(left); 
             if (leftPrecedence == (int)DataTypePrecedence.Error) {
                return StorageType.Empty; 
             }

             int rightPrecedence = (int)GetPrecedence(right);
             if (rightPrecedence == (int)DataTypePrecedence.Error) { 
                return StorageType.Empty;
             } 
 
             if (Operators.IsLogical(op)){
                if (left == StorageType.Boolean && right == StorageType.Boolean) 
                    return StorageType.Boolean;
                else
                    return StorageType.Empty;
             } 
            if ((left == StorageType.DateTimeOffset) ||(right == StorageType.DateTimeOffset))
            { 
                // Rules to handle DateTimeOffset: 
                // we only allow Relational operations to operate only on DTO vs DTO
                // all other operations: "exception" 
                if (Operators.IsRelational(op) && left == StorageType.DateTimeOffset && right == StorageType.DateTimeOffset)
                    return StorageType.DateTimeOffset;
                return StorageType.Empty;
            } 

             if ((op == Operators.Plus) && ((left == StorageType.String) || (right == StorageType.String))) 
                return StorageType.String; 

             DataTypePrecedence higherPrec = (DataTypePrecedence)Math.Max(leftPrecedence, rightPrecedence); 

             StorageType result = GetPrecedenceType(higherPrec);

             if (Operators.IsArithmetical(op)) { 
                if (result != StorageType.String && result != StorageType.Char) {
                    if (!IsNumeric(left)) 
                        return StorageType.Empty; 
                    if (!IsNumeric(right))
                        return StorageType.Empty; 
                }
             }

             // if the operation is a division the result should be at least a double 

             if ((op == Operators.Divide) && IsInteger(result)) { 
                return StorageType.Double; 
             }
 
             if (IsMixed(left, right)) {
                // we are dealing with one signed and one unsigned type so
                // try to see if one of them is a ConstNode
                if (lc && (!rc)) { 
                    return right;
                } 
                else if ((!lc) && rc) { 
                    return left;
                } 

                if (IsUnsigned(result)) {
                    if (higherPrec < DataTypePrecedence.UInt64)
                        // left and right are mixed integers but with the same length 
                        // so promote to the next signed type
                        result = GetPrecedenceType(higherPrec+1); 
                    else 
                        throw ExprException.AmbiguousBinop(op, DataStorage.GetTypeStorage(left), DataStorage.GetTypeStorage(right));
                } 
             }

             return result;
        } 

        internal StorageType ResultSqlType(StorageType left, StorageType right, bool lc, bool rc, int op) { 
            int leftPrecedence = (int)GetPrecedence(left); 
            if (leftPrecedence == (int)DataTypePrecedence.Error) {
              return StorageType.Empty; 
            }

            int rightPrecedence = (int)GetPrecedence(right);
            if (rightPrecedence == (int)DataTypePrecedence.Error) { 
              return StorageType.Empty;
            } 
 
            if (Operators.IsLogical(op)){
                if ((left != StorageType.Boolean  && left != StorageType.SqlBoolean) || (right != StorageType.Boolean && right != StorageType.SqlBoolean)) 
                      return StorageType.Empty;
                if (left == StorageType.Boolean && right == StorageType.Boolean)
                      return StorageType.Boolean;
                return  StorageType.SqlBoolean; 
            }
 
            if (op == Operators.Plus){ 
                if((left == StorageType.SqlString) ||(right == StorageType.SqlString))
                      return StorageType.SqlString; 
                if ((left == StorageType.String) || (right == StorageType.String))
                      return StorageType.String;
            }
            //SqlBinary is operable just with SqlBinary 
            if ((left == StorageType.SqlBinary && right != StorageType.SqlBinary) ||(left != StorageType.SqlBinary && right == StorageType.SqlBinary))
                return StorageType.Empty; 
            //SqlGuid is operable just with SqlGuid 
            if((left == StorageType.SqlGuid && right != StorageType.SqlGuid) ||(left != StorageType.SqlGuid && right == StorageType.SqlGuid))
                return StorageType.Empty; 

            if ((leftPrecedence > (int)DataTypePrecedence.SqlDouble  && rightPrecedence <(int) DataTypePrecedence.TimeSpan)){
                return StorageType.Empty;
            } 

            if ((leftPrecedence < (int)DataTypePrecedence.TimeSpan  && rightPrecedence >(int) DataTypePrecedence.SqlDouble)){ 
                return StorageType.Empty; 
            }
 
            if (leftPrecedence > (int) DataTypePrecedence.SqlDouble){
                if (op == Operators.Plus || op == Operators.Minus){
                      if (left == StorageType.TimeSpan)
                            return right; 
                      if (right == StorageType.TimeSpan)
                        return left; 
                      return StorageType.Empty; // for plus or minus operations for  time types, one of them MUST be time span 
                }
 
                if (!Operators.IsRelational(op))
                      return StorageType.Empty; // we just have relational operations amoung time types
                return left;
            } 
            // time types finished
            // continue with numerical types, numbers 
 
            DataTypePrecedence higherPrec = (DataTypePrecedence)Math.Max(leftPrecedence, rightPrecedence);
 
            StorageType result = GetPrecedenceType(higherPrec);
            // if we have at least one Sql type, the intermediate result should be Sql type
            result = GetPrecedenceType((DataTypePrecedence)SqlResultType((int)higherPrec));
 
            if (Operators.IsArithmetical(op)) {
                if (result != StorageType.String && result != StorageType.Char && result != StorageType.SqlString) { 
                      if (!IsNumericSql(left)) 
                            return StorageType.Empty;
                      if (!IsNumericSql(right)) 
                            return StorageType.Empty;
               }
            }
 
            // if the operation is a division the result should be at least a double
            if ((op == Operators.Divide) && IsIntegerSql(result)) { 
                 return StorageType.SqlDouble; 
            }
 
            if (result == StorageType.SqlMoney){
                if ((left != StorageType.SqlMoney) && (right != StorageType.SqlMoney))
                      result =  StorageType.SqlDecimal;
            } 

            if (IsMixedSql(left, right)) { 
            // we are dealing with one signed and one unsigned type so 
            // try to see if one of them is a ConstNode
 
                if (IsUnsignedSql(result)) {
                      if (higherPrec < DataTypePrecedence.UInt64)
                        // left and right are mixed integers but with the same length
                        // so promote to the next signed type 
                            result = GetPrecedenceType(higherPrec+1);
                      else 
                        throw ExprException.AmbiguousBinop(op, DataStorage.GetTypeStorage(left), DataStorage.GetTypeStorage(right)); 
                }
            } 

            return result;
        }
 
        private int SqlResultType(int typeCode){
            switch (typeCode){ 
            case  23: return  24; 
            case  20: return  21;
            case  18: return  19; 
            case  16: return  17;
            case  14: return  15;
            case  12: return  13;
            case  9  : 
            case  10: return  11;
            case  6  : 
            case  7  : return  8; 
            case  3  :
            case  4  : return  5; 
            case  1  : return  2;
            case  -2: return -1;
            case  -5: return -4;
            case  -8: return -7; 
            default : return typeCode;
           } 
        } 
    }
 
    internal sealed class LikeNode : BinaryNode {
        // like kinds
        internal const int match_left = 1;      // *
        internal const int match_right = 2;     // * 
        internal const int match_middle = 3;    // **
        internal const int match_exact  = 4;    //  
        internal const int match_all  = 5;      // * 

        int kind; 
        string pattern = null;

        internal LikeNode(DataTable table, int op, ExpressionNode left, ExpressionNode right)
        : base (table, op, left, right) { 
        }
 
        internal override object Eval(DataRow row, DataRowVersion version) { 
            object vRight;
            // 
            object vLeft = left.Eval(row, version);
            string substring;

 
            if ((vLeft == DBNull.Value)||(left.IsSqlColumn && DataStorage.IsObjectSqlNull(vLeft)))
                return DBNull.Value; 
 
            if (pattern == null) {
                vRight = right.Eval(row, version); 

                if (!(vRight is string) && !(vRight is SqlString)) {
                    SetTypeMismatchError(op, vLeft.GetType(), vRight.GetType());
                } 

          if (vRight == DBNull.Value || DataStorage.IsObjectSqlNull(vRight)) 
              return DBNull.Value; 
          string rightStr = (string) SqlConvert.ChangeType2(vRight, StorageType.String, typeof(string), FormatProvider);
 

                // need to convert like pattern to a string

                // Parce the original pattern, and get the constant part of it.. 
                substring = AnalyzePattern(rightStr);
 
                if (right.IsConstant()) 
                    pattern = substring;
            } 
            else {
                substring = pattern;
            }
 
            if (!(vLeft is string) && !(vLeft is SqlString)) {
                SetTypeMismatchError(op, vLeft.GetType(), typeof(string)); 
            } 

            // 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. 
            char[] trimChars = new char[2] {(char)0x20, (char)0x3000};
            string tempStr;
            if (vLeft is SqlString)
                tempStr = ((SqlString)vLeft).Value; 
            else
                tempStr = (string)vLeft; 
 
            string s1 = (tempStr).TrimEnd(trimChars);
 
            switch (kind) {
                case match_all:
                    return true;
                case match_exact: 
                    return(0 == table.Compare(s1, substring));
                case match_middle: 
                    return(0 <= table.IndexOf(s1, substring)); 
                case match_left:
                    return(0 == table.IndexOf(s1, substring)); 
                case match_right:
                    string s2 = substring.TrimEnd(trimChars);
                    return table.IsSuffix(s1, s2);
                default: 
                    Debug.Assert(false, "Unexpected LIKE kind");
                    return DBNull.Value; 
            } 
        }
 
        internal string AnalyzePattern(string pat) {

            int length = pat.Length;
            char[] patchars = new char[length+1]; 
            pat.CopyTo(0, patchars, 0, length);
            patchars[length] = (char)0; 
            string substring = null; 

            char[] constchars = new char[length+1]; 
            int newLength = 0;

            int stars = 0;
 
            int i = 0;
 
            while (i < length) { 

                if (patchars[i] == '*' || patchars[i] == '%') { 

                    // replace conseq. * or % with one..
                    while ((patchars[i] == '*' || patchars[i] == '%') && i < length)
                        i++; 

                    // we allowing only *str* pattern 
                    if ((i < length && newLength > 0) || stars >= 2) { 
                        // we have a star inside string constant..
                        throw ExprException.InvalidPattern(pat); 
                    }
                    stars++;

                } 
                else if (patchars[i] == '[') {
                    i++; 
                    if (i >= length) { 
                        throw ExprException.InvalidPattern(pat);
                    } 
                    constchars[newLength++] = patchars[i++];

                    if (i >= length) {
                        throw ExprException.InvalidPattern(pat); 
                    }
 
                    if (patchars[i] != ']') { 
                        throw ExprException.InvalidPattern(pat);
                    } 
                    i++;
                }
                else {
                    constchars[newLength++] = patchars[i]; 
                    i++;
                } 
            } 

            substring = new string(constchars, 0, newLength); 

            if (stars == 0) {
                kind = match_exact;
            } 
            else {
                if (newLength > 0) { 
                    if (patchars[0] == '*' || patchars[0] == '%') { 

                        if (patchars[length-1] == '*' || patchars[length-1] == '%') { 
                            kind = match_middle;
                        }
                        else {
                            kind = match_right; 
                        }
                    } 
                    else { 
                        Debug.Assert(patchars[length-1] == '*' || patchars[length-1] == '%', "Invalid LIKE pattern formed.. ");
                        kind = match_left; 
                    }
                }
                else {
                    kind = match_all; 
                }
            } 
            return substring; 
        }
    } 
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
//------------------------------------------------------------------------------ 
// 
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// 
// [....] 
// [....]
// [....] 
//----------------------------------------------------------------------------- 

namespace System.Data { 
    using System;
    using System.Diagnostics;
    using System.Collections.Generic;
    using System.Globalization; 
    using System.ComponentModel;
    using System.Data.SqlTypes; 
    using System.Data.Common; 

    internal class BinaryNode : ExpressionNode { 
        internal int op;

        internal ExpressionNode left;
        internal ExpressionNode right; 

        internal BinaryNode(DataTable table, int op, ExpressionNode left, ExpressionNode right) : base(table) { 
            this.op = op; 
            this.left = left;
            this.right = right; 
        }

        internal override void Bind(DataTable table, List list) {
            BindTable(table); 
            left.Bind(table, list);
            right.Bind(table, list); 
        } 

        internal override object Eval() { 
            return Eval(null, DataRowVersion.Default);
        }

        internal override object Eval(DataRow row, DataRowVersion version) { 
            return EvalBinaryOp(op, left, right, row, version, null);
        } 
 
        internal override object Eval(int[] recordNos) {
            return EvalBinaryOp(op, left, right, null, DataRowVersion.Default, recordNos); 
        }

        internal override bool IsConstant() {
            // 
            return(left.IsConstant() && right.IsConstant());
        } 
 
        internal override bool IsTableConstant() {
            return(left.IsTableConstant() && right.IsTableConstant()); 
        }
        internal override bool HasLocalAggregate() {
            return(left.HasLocalAggregate() || right.HasLocalAggregate());
        } 

        internal override bool HasRemoteAggregate() { 
            return(left.HasRemoteAggregate() || right.HasRemoteAggregate()); 
        }
 
        internal override bool DependsOn(DataColumn column) {
            if (left.DependsOn(column))
                return true;
            return right.DependsOn(column); 
        }
 
        internal override ExpressionNode Optimize() { 
            left = left.Optimize();
 
            if (op == Operators.Is) {
                // only 'Is Null' or 'Is Not Null' are valid
                if (right is UnaryNode) {
                    UnaryNode un = (UnaryNode)right; 
                    if (un.op != Operators.Not) {
                        throw ExprException.InvalidIsSyntax(); 
                    } 
                    op = Operators.IsNot;
                    right = un.right; 
                }
                if (right is ZeroOpNode) {
                    if (((ZeroOpNode)right).op != Operators.Null) {
                        throw ExprException.InvalidIsSyntax(); 
                    }
                } 
                else { 
                    throw ExprException.InvalidIsSyntax();
                } 
            }
            else {
                right = right.Optimize();
            } 

 
            if (this.IsConstant()) { 

                object val = this.Eval(); 

                if (val == DBNull.Value) {
                    return new ZeroOpNode(Operators.Null);
                } 

                if (val is bool) { 
                    if ((bool)val) 
                        return new ZeroOpNode(Operators.True);
                    else 
                        return new ZeroOpNode(Operators.False);
                }
                return new ConstNode(table, ValueType.Object, val, false);
            } 
            else
                return this; 
        } 

        internal void SetTypeMismatchError(int op, Type left, Type right) { 
            throw ExprException.TypeMismatchInBinop(op, left, right);
        }

        private static object Eval(ExpressionNode expr, DataRow row, DataRowVersion version, int[] recordNos) { 
            if (recordNos == null) {
                return expr.Eval(row, version); 
            } 
            else {
                return expr.Eval(recordNos); 
            }
        }

        internal int BinaryCompare(object vLeft, object vRight, StorageType resultType, int op) { 
            int result = 0;
            try { 
                if (!DataStorage.IsSqlType(resultType)) { 
                    switch(resultType) {
                    case StorageType.SByte: 
                    case StorageType.Int16:
                    case StorageType.Int32:
                    case StorageType.Byte:
                    case StorageType.UInt16: 
                        return Convert.ToInt32(vLeft, FormatProvider).CompareTo(Convert.ToInt32(vRight, FormatProvider));
                    case StorageType.Int64: 
                    case StorageType.UInt32: 
                    case StorageType.UInt64:
                    case StorageType.Decimal: 
                        return Decimal.Compare(Convert.ToDecimal(vLeft, FormatProvider), Convert.ToDecimal(vRight, FormatProvider));
                    case StorageType.Char:
                        return Convert.ToInt32(vLeft, FormatProvider).CompareTo(Convert.ToInt32(vRight, FormatProvider));
                    case StorageType.Double: 
                        return Convert.ToDouble(vLeft, FormatProvider).CompareTo(Convert.ToDouble(vRight, FormatProvider));
                    case StorageType.Single: 
                        return Convert.ToSingle(vLeft, FormatProvider).CompareTo(Convert.ToSingle(vRight, FormatProvider)); 
                    case StorageType.DateTime:
                        return DateTime.Compare(Convert.ToDateTime(vLeft, FormatProvider), Convert.ToDateTime(vRight, FormatProvider)); 
                    case StorageType.DateTimeOffset:
                        // DTO can only be compared to DTO, other cases: cast Exception
                        return DateTimeOffset.Compare((DateTimeOffset)vLeft, (DateTimeOffset)vRight);
                    case StorageType.String: 
                        return table.Compare(Convert.ToString(vLeft, FormatProvider), Convert.ToString(vRight, FormatProvider));
                    case StorageType.Guid: 
                        return ((Guid)vLeft).CompareTo((Guid) vRight); 
                    case StorageType.Boolean:
                        if (op == Operators.EqualTo || op == Operators.NotEqual) { 
                            return Convert.ToInt32(DataExpression.ToBoolean(vLeft), FormatProvider) -
                                   Convert.ToInt32(DataExpression.ToBoolean(vRight), FormatProvider);
                        }
                        break; 
                    }
                } 
                else{ 
                    switch(resultType) {
                    case StorageType.SByte: 
                    case StorageType.Int16:
                    case StorageType.Int32:
                    case StorageType.Byte:
                    case StorageType.UInt16: 
                    case StorageType.SqlByte:
                    case StorageType.SqlInt16: 
                    case StorageType.SqlInt32: 
                        return SqlConvert.ConvertToSqlInt32(vLeft).CompareTo(SqlConvert.ConvertToSqlInt32(vRight));
                    case StorageType.Int64: 
                    case StorageType.UInt32:
                    case StorageType.SqlInt64:
                        return SqlConvert.ConvertToSqlInt64(vLeft).CompareTo(SqlConvert.ConvertToSqlInt64(vRight));
                    case StorageType.UInt64: 
                    case StorageType.SqlDecimal:
                        return SqlConvert.ConvertToSqlDecimal(vLeft).CompareTo(SqlConvert.ConvertToSqlDecimal(vRight)); 
                    case StorageType.SqlDouble: 
                        return SqlConvert.ConvertToSqlDouble(vLeft).CompareTo(SqlConvert.ConvertToSqlDouble(vRight));
                    case StorageType.SqlSingle: 
                        return SqlConvert.ConvertToSqlSingle(vLeft).CompareTo(SqlConvert.ConvertToSqlSingle(vRight));
                    case StorageType.SqlString:
                        return table.Compare(vLeft.ToString(), vRight.ToString());
                    case StorageType.SqlGuid: 
                        return ((SqlGuid)vLeft).CompareTo(vRight);
                    case StorageType.SqlBoolean: 
                        if (op == Operators.EqualTo || op == Operators.NotEqual) { 
                            result = 1;
                            if (((vLeft.GetType() == typeof(SqlBoolean)) && ((vRight.GetType() == typeof(SqlBoolean))|| (vRight.GetType() == typeof(Boolean))))|| 
                                ((vRight.GetType() == typeof(SqlBoolean)) && ((vLeft.GetType() == typeof(SqlBoolean))|| (vLeft.GetType() == typeof(Boolean))))){
                                return SqlConvert.ConvertToSqlBoolean(vLeft).CompareTo(SqlConvert.ConvertToSqlBoolean(vRight));
                            }
                        } 
                        break;
                    case StorageType.SqlBinary: 
                        return SqlConvert.ConvertToSqlBinary(vLeft).CompareTo(SqlConvert.ConvertToSqlBinary(vRight)); 
                    case StorageType.SqlDateTime:
                        return SqlConvert.ConvertToSqlDateTime(vLeft).CompareTo(SqlConvert.ConvertToSqlDateTime(vRight)); 
                    case StorageType.SqlMoney:
                        return SqlConvert.ConvertToSqlMoney(vLeft).CompareTo(SqlConvert.ConvertToSqlMoney(vRight));
                    }
                } 
            }
            catch (System.ArgumentException e) { 
                ExceptionBuilder.TraceExceptionWithoutRethrow(e); 
            }
            catch (System.FormatException e) { 
                ExceptionBuilder.TraceExceptionWithoutRethrow(e);
            }
            catch (System.InvalidCastException e) {
                ExceptionBuilder.TraceExceptionWithoutRethrow(e); 
            }
            catch (System.OverflowException e) { 
                ExceptionBuilder.TraceExceptionWithoutRethrow(e); 
            }
            catch (System.Data.EvaluateException e) { 
                ExceptionBuilder.TraceExceptionWithoutRethrow(e);
            }
            SetTypeMismatchError(op, vLeft.GetType(), vRight.GetType());
            return result; 
        }
 
        private object EvalBinaryOp(int op, ExpressionNode left, ExpressionNode right, DataRow row, DataRowVersion version, int[] recordNos) { 
            object vLeft;
            object vRight; 
            StorageType resultType;

            /*
            special case for OR and AND operators: we don't want to evaluate 
            both right and left operands, because we can shortcut :
                for OR  operator If one of the operands is true the result is true 
                for AND operator If one of rhe operands is flase the result is false 

*/ 

            if (op != Operators.Or && op != Operators.And && op != Operators.In && op != Operators.Is && op != Operators.IsNot) {
                vLeft  = BinaryNode.Eval(left, row, version, recordNos);
                vRight = BinaryNode.Eval(right, row, version, recordNos); 
                Type typeofLeft  = vLeft.GetType();
                Type typeofRight = vRight.GetType(); 
 
                StorageType leftStorage  = DataStorage.GetStorageType(typeofLeft);
                StorageType rightStorage = DataStorage.GetStorageType(typeofRight); 

                bool leftIsSqlType = DataStorage.IsSqlType(leftStorage);
                bool rightIsSqlType = DataStorage.IsSqlType(rightStorage);
 
                //    special case of handling NULLS, currently only OR operator can work with NULLS
                if (leftIsSqlType && DataStorage.IsObjectSqlNull(vLeft)) { 
                    return vLeft; 
                }
                else if (rightIsSqlType && DataStorage.IsObjectSqlNull(vRight)) { 
                    return vRight;
                }
                else if ((vLeft == DBNull.Value)||(vRight == DBNull.Value)) {
                    return DBNull.Value; 
                }
 
                if (leftIsSqlType || rightIsSqlType) { 
                     resultType = ResultSqlType(leftStorage, rightStorage, (left is ConstNode), (right is ConstNode), op);
                } 
                else {
                     resultType = ResultType(leftStorage, rightStorage, (left is ConstNode), (right is ConstNode), op);
                }
 
                if (StorageType.Empty == resultType) {
                    SetTypeMismatchError(op, typeofLeft, typeofRight); 
                } 

            } 
            else {
                vLeft = vRight = DBNull.Value;
                resultType = StorageType.Empty; // shouldnt we make it boolean?
            } 

            object value = DBNull.Value; 
            bool typeMismatch = false; 

            try { 
                switch (op) {
                case Operators.Plus:
                    switch(resultType) {
                    case StorageType.Byte:{ 
                        value = Convert.ToByte((Convert.ToByte(vLeft, FormatProvider) + Convert.ToByte(vRight, FormatProvider)), FormatProvider);
                        break;} 
                    case StorageType.SByte:{ 
                        value = Convert.ToSByte((Convert.ToSByte(vLeft, FormatProvider) + Convert.ToSByte(vRight, FormatProvider)), FormatProvider);
                        break;} 
                    case StorageType.Int16:{
                        value = Convert.ToInt16((Convert.ToInt16(vLeft, FormatProvider) + Convert.ToInt16(vRight, FormatProvider)), FormatProvider);
                        break;}
                    case StorageType.UInt16:{ 
                        value = Convert.ToUInt16((Convert.ToUInt16(vLeft, FormatProvider) + Convert.ToUInt16(vRight, FormatProvider)), FormatProvider);
                        break;} 
                    case StorageType.Int32: { 
                        checked {value = Convert.ToInt32(vLeft, FormatProvider) + Convert.ToInt32(vRight, FormatProvider);}
                        break;} 
                    case StorageType.UInt32: {
                        checked {value = Convert.ToUInt32(vLeft, FormatProvider) + Convert.ToUInt32(vRight, FormatProvider);}
                        break;}
                    case StorageType.UInt64: { 
                        checked {value = Convert.ToUInt64(vLeft, FormatProvider) + Convert.ToUInt64(vRight, FormatProvider);}
                        break;} 
                    case StorageType.Int64:{ 
                        checked {value = Convert.ToInt64(vLeft, FormatProvider) + Convert.ToInt64(vRight, FormatProvider);}
                        break;} 
                    case StorageType.Decimal:{
                        checked {value = Convert.ToDecimal(vLeft, FormatProvider) + Convert.ToDecimal(vRight, FormatProvider);}
                        break;}
                    case StorageType.Single:{ 
                        checked {value = Convert.ToSingle(vLeft, FormatProvider) + Convert.ToSingle(vRight, FormatProvider);}
                        break;} 
                    case StorageType.Double:{ 
                        checked {value = Convert.ToDouble(vLeft, FormatProvider) + Convert.ToDouble(vRight, FormatProvider);}
                        break;} 
                    case StorageType.String:
                    case StorageType.Char:{
                        value = Convert.ToString(vLeft, FormatProvider) + Convert.ToString(vRight, FormatProvider);
                        break;} 
                    case StorageType.DateTime:{
                        // one of the operands should be a DateTime, and an other a TimeSpan 
 
                        if (vLeft is TimeSpan && vRight is DateTime) {
                            value = (DateTime)vRight + (TimeSpan)vLeft; 
                        }
                        else if (vLeft is DateTime && vRight is TimeSpan) {
                            value = (DateTime)vLeft + (TimeSpan)vRight;
                        } 
                        else {
                            typeMismatch = true; 
                        } 
                        break;}
                    case StorageType.TimeSpan:{ 
                        value = (TimeSpan)vLeft + (TimeSpan)vRight;
                        break;}
                    case StorageType.SqlInt16:{
                        value = (SqlConvert.ConvertToSqlInt16(vLeft) + SqlConvert.ConvertToSqlInt16(vRight)); 
                        break;}
                    case StorageType.SqlInt32:{ 
                        value = ( SqlConvert.ConvertToSqlInt32(vLeft) + SqlConvert.ConvertToSqlInt32(vRight)); 
                        break;}
                    case StorageType.SqlInt64:{ 
                        value = (SqlConvert.ConvertToSqlInt64(vLeft) + SqlConvert.ConvertToSqlInt64(vRight));
                        break;}
                    case StorageType.SqlDouble:{
                        value = (SqlConvert.ConvertToSqlDouble(vLeft) + SqlConvert.ConvertToSqlDouble(vRight)); 
                        break;}
                    case StorageType.SqlSingle:{ 
                        value = (SqlConvert.ConvertToSqlSingle(vLeft)+ SqlConvert.ConvertToSqlSingle(vRight)); 
                        break;}
                    case StorageType.SqlDecimal:{ 
                        value = (SqlConvert.ConvertToSqlDecimal(vLeft) + SqlConvert.ConvertToSqlDecimal(vRight));
                        break;}
                    case StorageType.SqlMoney:{
                        value = (SqlConvert.ConvertToSqlMoney(vLeft) + SqlConvert.ConvertToSqlMoney(vRight)); 
                        break;}
                    case StorageType.SqlByte:{ 
                        value = (SqlConvert.ConvertToSqlByte(vLeft) + SqlConvert.ConvertToSqlByte(vRight)); 
                        break;}
                    case StorageType.SqlString:{ 
                        value = (SqlConvert.ConvertToSqlString(vLeft) + SqlConvert.ConvertToSqlString(vRight));
                        break;}
                    case StorageType.SqlDateTime:{
                        if (vLeft is TimeSpan && vRight is SqlDateTime) { 
                          SqlDateTime rValue = (SqlDateTime)SqlConvert.ConvertToSqlDateTime(vRight);
                          value = (SqlDateTime)SqlConvert.ConvertToSqlDateTime((DateTime)rValue.Value + (TimeSpan)vLeft); 
                        } 
                        else if (vLeft is SqlDateTime && vRight is TimeSpan) {
                          SqlDateTime lValue = (SqlDateTime)SqlConvert.ConvertToSqlDateTime(vLeft); 
                          value = (SqlDateTime)SqlConvert.ConvertToSqlDateTime((DateTime)lValue.Value + (TimeSpan)vRight);
                        }
                        else {
                            typeMismatch = true; 
                        }
                        break;} 
                    default:{ 
                        typeMismatch = true;
                        break;} 
                    }
                    break; // Operators.Plus

                case Operators.Minus: 
                    switch(resultType) {
                    case StorageType.Byte: { 
                        value = Convert.ToByte((Convert.ToByte(vLeft, FormatProvider) - Convert.ToByte(vRight, FormatProvider)), FormatProvider); 
                    break; }
                    case StorageType.SqlByte: { 
                        value = (SqlConvert.ConvertToSqlByte(vLeft) - SqlConvert.ConvertToSqlByte(vRight));
                    break;}
                    case StorageType.SByte:{
                        value = Convert.ToSByte((Convert.ToSByte(vLeft, FormatProvider) - Convert.ToSByte(vRight, FormatProvider)), FormatProvider); 
                    break;}
                    case StorageType.Int16:{ 
                        value = Convert.ToInt16((Convert.ToInt16(vLeft, FormatProvider) - Convert.ToInt16(vRight, FormatProvider)), FormatProvider); 
                    break;}
                    case StorageType.SqlInt16:{ 
                        value = (SqlConvert.ConvertToSqlInt16(vLeft) - SqlConvert.ConvertToSqlInt16(vRight));
                    break;}
                    case StorageType.UInt16:{
                        value = Convert.ToUInt16((Convert.ToUInt16(vLeft, FormatProvider) - Convert.ToUInt16(vRight, FormatProvider)), FormatProvider); 
                    break;}
                    case StorageType.Int32:{ 
                        checked {value = Convert.ToInt32(vLeft, FormatProvider) - Convert.ToInt32(vRight, FormatProvider);} 
                    break;}
                    case StorageType.SqlInt32:{ 
                        value = (SqlConvert.ConvertToSqlInt32(vLeft) - SqlConvert.ConvertToSqlInt32(vRight));
                    break;}
                    case StorageType.UInt32:{
                        checked {value = Convert.ToUInt32(vLeft, FormatProvider) - Convert.ToUInt32(vRight, FormatProvider);} 
                    break;}
                    case StorageType.Int64:{ 
                        checked {value = Convert.ToInt64(vLeft, FormatProvider) - Convert.ToInt64(vRight, FormatProvider);} 
                    break;}
                    case StorageType.SqlInt64:{ 
                        value = (SqlConvert.ConvertToSqlInt64(vLeft) - SqlConvert.ConvertToSqlInt64(vRight));
                    break;}
                    case StorageType.UInt64:{
                        checked {value = Convert.ToUInt64(vLeft, FormatProvider) - Convert.ToUInt64(vRight, FormatProvider);} 
                        break;}
                    case StorageType.Decimal:{ 
                        checked {value = Convert.ToDecimal(vLeft, FormatProvider) - Convert.ToDecimal(vRight, FormatProvider);} 
                        break;}
                    case StorageType.SqlDecimal:{ 
                        value = (SqlConvert.ConvertToSqlDecimal(vLeft) - SqlConvert.ConvertToSqlDecimal(vRight));
                        break;}
                    case StorageType.Single:{
                        checked {value = Convert.ToSingle(vLeft, FormatProvider) - Convert.ToSingle(vRight, FormatProvider);} 
                        break;}
                    case StorageType.SqlSingle:{ 
                        value = (SqlConvert.ConvertToSqlSingle(vLeft) - SqlConvert.ConvertToSqlSingle(vRight)); 
                        break;}
                    case StorageType.Double:{ 
                        checked {value = Convert.ToDouble(vLeft, FormatProvider) - Convert.ToDouble(vRight, FormatProvider);}
                        break;}
                    case StorageType.SqlDouble:{
                        value = (SqlConvert.ConvertToSqlDouble(vLeft) - SqlConvert.ConvertToSqlDouble(vRight)); 
                        break;}
                    case StorageType.SqlMoney:{ 
                        value = (SqlConvert.ConvertToSqlMoney(vLeft) - SqlConvert.ConvertToSqlMoney(vRight)); 
                        break;}
                    case StorageType.DateTime:{ 
                        value = (DateTime)vLeft - (TimeSpan)vRight;
                        break;}
                    case StorageType.TimeSpan:{
                        if (vLeft is DateTime) { 
                            value = (DateTime)vLeft - (DateTime)vRight;
                        } 
                        else 
                            value = (TimeSpan)vLeft - (TimeSpan)vRight;
                        break;} 
                    case StorageType.SqlDateTime:{
                        if (vLeft is TimeSpan && vRight is SqlDateTime) {
                          SqlDateTime rValue = (SqlDateTime)SqlConvert.ConvertToSqlDateTime(vRight);
                          value = (SqlDateTime)SqlConvert.ConvertToSqlDateTime((DateTime)rValue.Value - (TimeSpan)vLeft); 
                        }
                        else if (vLeft is SqlDateTime && vRight is TimeSpan) { 
                          SqlDateTime lValue = (SqlDateTime)SqlConvert.ConvertToSqlDateTime(vLeft); 
                          value = (SqlDateTime)SqlConvert.ConvertToSqlDateTime((DateTime)lValue.Value - (TimeSpan)vRight);
                        } 
                        else {
                            typeMismatch = true;
                        }
                        break;} 
                    default:{
                        typeMismatch = true; 
                        break;} 
                    }
                    break; // Operators.Minus 

                case Operators.Multiply:
                    switch(resultType) {
                    case StorageType.Byte:{ 
                        value = Convert.ToByte((Convert.ToByte(vLeft, FormatProvider) * Convert.ToByte(vRight, FormatProvider)), FormatProvider);
                        break;} 
                    case StorageType.SqlByte:{ 
                        value = (SqlConvert.ConvertToSqlByte(vLeft) * SqlConvert.ConvertToSqlByte(vRight));
                        break;} 
                    case StorageType.SByte:{
                        value = Convert.ToSByte((Convert.ToSByte(vLeft, FormatProvider) * Convert.ToSByte(vRight, FormatProvider)), FormatProvider);
                        break;}
                    case StorageType.Int16:{ 
                        value = Convert.ToInt16((Convert.ToInt16(vLeft, FormatProvider) * Convert.ToInt16(vRight, FormatProvider)), FormatProvider);
                        break;} 
                    case StorageType.SqlInt16:{ 
                        value = (SqlConvert.ConvertToSqlInt16(vLeft) * SqlConvert.ConvertToSqlInt16(vRight));
                        break;} 
                    case StorageType.UInt16:{
                        value = Convert.ToUInt16((Convert.ToUInt16(vLeft, FormatProvider) * Convert.ToUInt16(vRight, FormatProvider)), FormatProvider);
                        break;}
                    case StorageType.Int32:{ 
                        checked {value = Convert.ToInt32(vLeft, FormatProvider) * Convert.ToInt32(vRight, FormatProvider);}
                        break;} 
                    case StorageType.SqlInt32:{ 
                        value = (SqlConvert.ConvertToSqlInt32(vLeft) * SqlConvert.ConvertToSqlInt32(vRight));
                        break;} 
                    case StorageType.UInt32:{
                        checked {value = Convert.ToUInt32(vLeft, FormatProvider) * Convert.ToUInt32(vRight, FormatProvider);}
                        break;}
                    case StorageType.Int64:{ 

                        checked {value = Convert.ToInt64(vLeft, FormatProvider) * Convert.ToInt64(vRight, FormatProvider);} 
                        break;} 
                    case StorageType.SqlInt64:{
                        value = (SqlConvert.ConvertToSqlInt64(vLeft) * SqlConvert.ConvertToSqlInt64(vRight)); 
                        break;}
                    case StorageType.UInt64:{
                        checked {value = Convert.ToUInt64(vLeft, FormatProvider) * Convert.ToUInt64(vRight, FormatProvider);}
                        break;} 
                    case StorageType.Decimal:{
                        checked {value = Convert.ToDecimal(vLeft, FormatProvider) * Convert.ToDecimal(vRight, FormatProvider);} 
                        break;} 
                    case StorageType.SqlDecimal:{
                        value = (SqlConvert.ConvertToSqlDecimal(vLeft) * SqlConvert.ConvertToSqlDecimal(vRight)); 
                        break;}
                    case StorageType.Single:{
                        checked {value = Convert.ToSingle(vLeft, FormatProvider) * Convert.ToSingle(vRight, FormatProvider);}
                        break;} 
                    case StorageType.SqlSingle:{
                        value = ( SqlConvert.ConvertToSqlSingle(vLeft) * SqlConvert.ConvertToSqlSingle(vRight)); 
                        break;} 
                    case StorageType.SqlMoney:{
                        value = (SqlConvert.ConvertToSqlMoney(vLeft) * SqlConvert.ConvertToSqlMoney(vRight)); 
                        break;}
                    case StorageType.Double:{
                        checked {value = Convert.ToDouble(vLeft, FormatProvider) * Convert.ToDouble(vRight, FormatProvider);}
                        break;} 
                    case StorageType.SqlDouble:{
                        value = (SqlConvert.ConvertToSqlDouble(vLeft) * SqlConvert.ConvertToSqlDouble(vRight)); 
                        break;} 
                    default:{
                        typeMismatch = true; 
                        break;}
                    }
                    break; // Operators.Multiply
 
                case Operators.Divide:
                    switch(resultType) { 
                    case StorageType.Byte:{ 
                        value = Convert.ToByte((Convert.ToByte(vLeft, FormatProvider) / Convert.ToByte(vRight, FormatProvider)), FormatProvider);
                        break;} 
                    case StorageType.SqlByte:{
                        value = (SqlConvert.ConvertToSqlByte(vLeft) / SqlConvert.ConvertToSqlByte(vRight));
                        break;}
                    case StorageType.SByte:{ 
                        value = Convert.ToSByte((Convert.ToSByte(vLeft, FormatProvider) / Convert.ToSByte(vRight, FormatProvider)), FormatProvider);
                        break;} 
                    case StorageType.Int16:{ 
                        value = Convert.ToInt16((Convert.ToInt16(vLeft, FormatProvider) / Convert.ToInt16(vRight, FormatProvider)), FormatProvider);
                        break;} 
                    case StorageType.SqlInt16:{
                        value = (SqlConvert.ConvertToSqlInt16(vLeft) / SqlConvert.ConvertToSqlInt16(vRight));
                        break;}
                    case StorageType.UInt16:{ 
                        value = Convert.ToUInt16((Convert.ToUInt16(vLeft, FormatProvider) / Convert.ToUInt16(vRight, FormatProvider)), FormatProvider);
                        break;} 
                    case StorageType.Int32:{ 
                        checked {value = Convert.ToInt32(vLeft, FormatProvider) / Convert.ToInt32(vRight, FormatProvider);}
                        break;} 
                    case StorageType.SqlInt32:{
                        value = (SqlConvert.ConvertToSqlInt32(vLeft) / SqlConvert.ConvertToSqlInt32(vRight));
                        break;}
                    case StorageType.UInt32:{ 
                        checked {value = Convert.ToUInt32(vLeft, FormatProvider) / Convert.ToUInt32(vRight, FormatProvider);}
                        break;} 
                    case StorageType.UInt64:{ 
                        checked {value = Convert.ToUInt64(vLeft, FormatProvider) / Convert.ToUInt64(vRight, FormatProvider);}
                        break;} 
                    case StorageType.Int64:{
                        checked {value = Convert.ToInt64(vLeft, FormatProvider) / Convert.ToInt64(vRight, FormatProvider);}
                        break;}
                    case StorageType.SqlInt64:{ 
                        value = (SqlConvert.ConvertToSqlInt64(vLeft) / SqlConvert.ConvertToSqlInt64(vRight));
                        break;} 
                    case StorageType.Decimal:{ 
                        checked {value = Convert.ToDecimal(vLeft, FormatProvider) / Convert.ToDecimal(vRight, FormatProvider);}
                        break;} 
                    case StorageType.SqlDecimal:{
                        value = (SqlConvert.ConvertToSqlDecimal(vLeft) / SqlConvert.ConvertToSqlDecimal(vRight));
                        break;}
                    case StorageType.Single:{ 
                        checked {value = Convert.ToSingle(vLeft, FormatProvider) / Convert.ToSingle(vRight, FormatProvider);}
                        break;} 
                    case StorageType.SqlSingle:{ 
                        value = ( SqlConvert.ConvertToSqlSingle(vLeft) / SqlConvert.ConvertToSqlSingle(vRight));
                        break;} 
                    case StorageType.SqlMoney:{
                        value = (SqlConvert.ConvertToSqlMoney(vLeft) / SqlConvert.ConvertToSqlMoney(vRight));
                        break;}
                    case StorageType.Double:{ 
                        Double b = Convert.ToDouble(vRight, FormatProvider);
                        checked {value = Convert.ToDouble(vLeft, FormatProvider) / b;} 
                        break;} 
                    case StorageType.SqlDouble:{
                        value = (SqlConvert.ConvertToSqlDouble(vLeft) / SqlConvert.ConvertToSqlDouble(vRight)); 
                        break;}
                    default:{
                        typeMismatch = true;
                        break;} 
                    }
                    break; // Operators.Divide 
 
                case Operators.EqualTo:
                    if ((vLeft == DBNull.Value)||(left.IsSqlColumn && DataStorage.IsObjectSqlNull(vLeft)) || 
                         (vRight == DBNull.Value)||(right.IsSqlColumn && DataStorage.IsObjectSqlNull(vRight)))
                        return DBNull.Value;
                    return(0 == BinaryCompare (vLeft, vRight, resultType, Operators.EqualTo));
 
                case Operators.GreaterThen:
                    if ((vLeft == DBNull.Value)||(left.IsSqlColumn && DataStorage.IsObjectSqlNull(vLeft)) || 
                         (vRight == DBNull.Value)||(right.IsSqlColumn && DataStorage.IsObjectSqlNull(vRight))) 
                        return DBNull.Value;
                    return(0 < BinaryCompare (vLeft, vRight, resultType,  op)); 

                case Operators.LessThen:
                    if ((vLeft == DBNull.Value)||(left.IsSqlColumn && DataStorage.IsObjectSqlNull(vLeft)) ||
                         (vRight == DBNull.Value)||(right.IsSqlColumn && DataStorage.IsObjectSqlNull(vRight))) 
                        return DBNull.Value;
                    return(0 > BinaryCompare (vLeft, vRight, resultType,  op)); 
 
                case Operators.GreaterOrEqual:
                    if ((vLeft == DBNull.Value)||(left.IsSqlColumn && DataStorage.IsObjectSqlNull(vLeft)) || 
                         (vRight == DBNull.Value)||(right.IsSqlColumn && DataStorage.IsObjectSqlNull(vRight)))
                        return DBNull.Value;
                    return(0 <= BinaryCompare (vLeft, vRight, resultType, op));
 
                case Operators.LessOrEqual:
                    if (((vLeft == DBNull.Value)||(left.IsSqlColumn && DataStorage.IsObjectSqlNull(vLeft))) || 
                         ((vRight == DBNull.Value)||(right.IsSqlColumn && DataStorage.IsObjectSqlNull(vRight)))) 
                        return DBNull.Value;
                    return(0 >= BinaryCompare (vLeft, vRight, resultType, op)); 

                case Operators.NotEqual:
                    if (((vLeft == DBNull.Value)||(left.IsSqlColumn && DataStorage.IsObjectSqlNull(vLeft))) ||
                         ((vRight == DBNull.Value)||(right.IsSqlColumn && DataStorage.IsObjectSqlNull(vRight)))) 
                        return DBNull.Value;
                    return(0 != BinaryCompare (vLeft, vRight, resultType, op)); 
 
                case Operators.Is:
                    vLeft  = BinaryNode.Eval(left, row, version, recordNos); 
                    if ((vLeft == DBNull.Value)||(left.IsSqlColumn && DataStorage.IsObjectSqlNull(vLeft))){
                        return true;
                    }
                    return false; 

                case Operators.IsNot: 
                    vLeft  = BinaryNode.Eval(left, row, version, recordNos); 
                    if ((vLeft == DBNull.Value)||(left.IsSqlColumn && DataStorage.IsObjectSqlNull(vLeft))){
                        return false; 
                    }
                    return true;

                case Operators.And: 
                    /*
                    special case evaluating of the AND operator: we don't want to evaluate 
                    both right and left operands, because we can shortcut : 
                        If one of the operands is flase the result is false
 
*/
                    vLeft  = BinaryNode.Eval(left, row, version, recordNos);
                    if ((vLeft == DBNull.Value)||(left.IsSqlColumn && DataStorage.IsObjectSqlNull(vLeft)))
                        return DBNull.Value; 

                    if ((!(vLeft is bool)) && (!(vLeft is SqlBoolean))){ 
                        vRight = BinaryNode.Eval(right, row, version, recordNos); 
                        typeMismatch = true;
                        break; 
                    }

                    if (vLeft is bool){
                        if ((bool)vLeft == false){ 
                           value = false;
                           break; 
                        } 
                    }
                    else{ 
                        if (((SqlBoolean) vLeft).IsFalse){
                            value = false;
                            break;
                        } 
                    }
                    vRight = BinaryNode.Eval(right, row, version, recordNos); 
                    if ((vRight  == DBNull.Value)||(right.IsSqlColumn && DataStorage.IsObjectSqlNull(vRight ))) 
                        return DBNull.Value;
 
                    if ((!(vRight is bool)) && (!(vRight is SqlBoolean))){
                        typeMismatch = true;
                        break;
                    } 

                    if (vRight is bool){ 
                        value = (bool)vRight; 
                        break;
                    } 
                    else{
                        value = ((SqlBoolean) vRight).IsTrue;
                    }
                    break; 
                case Operators.Or:
                    /* 
                    special case evaluating the OR operator: we don't want to evaluate 
                    both right and left operands, because we can shortcut :
                        If one of the operands is true the result is true 

*/

                    vLeft = BinaryNode.Eval(left, row, version, recordNos); 

                    if ((vLeft != DBNull.Value) && (!DataStorage.IsObjectSqlNull(vLeft))) { 
                        if ((!(vLeft is bool)) && (!(vLeft is SqlBoolean))) { 
                            vRight = BinaryNode.Eval(right, row, version, recordNos);
                            typeMismatch = true; 
                            break;
                        }

                        if ((bool)vLeft == true) { 
                            value = true;
                            break; 
                        } 
                    }
 
                    vRight = BinaryNode.Eval(right, row, version, recordNos);
                    if ((vRight == DBNull.Value)||(DataStorage.IsObjectSqlNull(vRight)))
                        return vLeft;
 
                    if ((vLeft == DBNull.Value)||(DataStorage.IsObjectSqlNull(vLeft)))
                        return vRight; 
 
                    if ((!(vRight is bool)) && (!(vRight is SqlBoolean))) {
                        typeMismatch = true; 
                        break;
                    }

                    value = (vRight is bool) ? ((bool)vRight) : (((SqlBoolean)vRight).IsTrue); 
                    break;
 
/*  for M3, use original code , in below,  and make sure to have two different code path; increases perf 

                    vLeft = BinaryNode.Eval(left, row, version, recordNos); 
                    if (vLeft != DBNull.Value) {
                        if (!(vLeft is bool)) {
                            vRight = BinaryNode.Eval(right, row, version, recordNos);
                            typeMismatch = true; 
                            break;
                        } 
 
                        if ((bool)vLeft == true) {
                            value = true; 
                            break;
                        }
                    }
 
                    vRight = BinaryNode.Eval(right, row, version, recordNos);
                    if (vRight == DBNull.Value) 
                        return vLeft; 

                    if (vLeft == DBNull.Value) 
                        return vRight;

                    if (!(vRight is bool)) {
                        typeMismatch = true; 
                        break;
                    } 
 
                    value = (bool)vRight;
                    break; 
*/

                case Operators.Modulo:
                    if (ExpressionNode.IsIntegerSql(resultType)) { 
                        if (resultType == StorageType.UInt64) {
                            value = Convert.ToUInt64(vLeft, FormatProvider) % Convert.ToUInt64(vRight, FormatProvider); 
                        } 
                        else if (DataStorage.IsSqlType(resultType)) {
                            SqlInt64 res = (SqlConvert.ConvertToSqlInt64(vLeft) % SqlConvert.ConvertToSqlInt64(vRight)); 

                            if (resultType == StorageType.SqlInt32){
                                value =  (SqlInt32) res.ToSqlInt32();
                            } 
                            else if (resultType == StorageType.SqlInt16){
                                value =  (SqlInt16) res.ToSqlInt16(); 
                            } 
                            else if (resultType == StorageType.SqlByte){
                                value =  (SqlByte) res.ToSqlByte(); 
                            }
                            else{
                                value =  (SqlInt64) res;
                            } 
                        }
                        else { 
                            value = Convert.ToInt64(vLeft, FormatProvider) % Convert.ToInt64(vRight, FormatProvider); 
                            value = Convert.ChangeType(value, DataStorage.GetTypeStorage(resultType), FormatProvider);
                        } 
                    }
                    else {
                        typeMismatch = true;
                    } 
                    break;
 
                case Operators.In: 
                    /*
                    special case evaluating of the IN operator: the right have to be IN function node 
                    */


                    if (!(right is FunctionNode)) { 
                        // this is more like an Assert: should never happens, so we do not care about "nice" Exseptions
                        throw ExprException.InWithoutParentheses(); 
                    } 

                    vLeft = BinaryNode.Eval(left, row, version, recordNos); 

                    if ((vLeft == DBNull.Value)||(left.IsSqlColumn && DataStorage.IsObjectSqlNull(vLeft)))
                        return DBNull.Value;
 
                    /* validate IN parameters : must all be constant expressions */
 
                    value = false; 

                    FunctionNode into = (FunctionNode)right; 

                    for (int i = 0; i < into.argumentCount; i++) {
                        vRight = into.arguments[i].Eval();
 

                    if ((vRight == DBNull.Value)||(right.IsSqlColumn && DataStorage.IsObjectSqlNull(vRight))) 
                            continue; 
                        Debug.Assert((!DataStorage.IsObjectNull(vLeft))&& (!DataStorage.IsObjectNull(vRight)), "Imposible..");
 
                        resultType = DataStorage.GetStorageType(vLeft.GetType());

                        if (0 == BinaryCompare(vLeft, vRight, resultType,  Operators.EqualTo)) {
                            value = true; 
                            break;
                        } 
                    } 
                    break;
 
                default:
                    throw ExprException.UnsupportedOperator(op);
                }
            } 
            catch (OverflowException) {
                throw ExprException.Overflow(DataStorage.GetTypeStorage(resultType)); 
            } 
            if (typeMismatch) {
                SetTypeMismatchError(op, vLeft.GetType(), vRight.GetType()); 
            }

            return value;
        } 

        // Data type precedence rules specify which data type is converted to the other. 
        // The data type with the lower precedence is converted to the data type with the higher precedence. 
        // If the conversion is not a supported implicit conversion, an error is returned.
        // When both operand expressions have the same data type, the result of the operation has that data type. 
        // This is the precedence order for the DataSet numeric data types:

        private enum DataTypePrecedence {
           SqlDateTime = 25, 
           DateTimeOffset = 24,
           DateTime = 23, 
           TimeSpan = 20, 
           SqlDouble = 19,
           Double = 18, 
           SqlSingle = 17,
           Single = 16,
           SqlDecimal = 15,
           Decimal = 14, 
           SqlMoney = 13,
           UInt64 = 12, 
           SqlInt64 = 11, 
           Int64 = 10,
           UInt32 = 9, 
           SqlInt32 = 8,
           Int32 = 7,
           UInt16 = 6,
           SqlInt16 = 5, 
           Int16 = 4,
           Byte = 3, 
           SqlByte = 2, 
           SByte = 1,
           Error = 0, 
           SqlBoolean = -1,
           Boolean = -2,
           SqlGuid = -3,
           SqlString = -4, 
           String = -5,
           SqlXml = -6, 
           SqlChars = -7, 
           Char = -8,
           SqlBytes = -9, 
           SqlBinary = -10,
        }

        private DataTypePrecedence GetPrecedence(StorageType storageType) { 
            switch(storageType) {
            case StorageType.Boolean: return DataTypePrecedence.Boolean; 
            case StorageType.Char: return DataTypePrecedence.Char; 
            case StorageType.SByte: return DataTypePrecedence.SByte;
            case StorageType.Byte: return DataTypePrecedence.Byte; 
            case StorageType.Int16: return DataTypePrecedence.Int16;
            case StorageType.UInt16: return DataTypePrecedence.UInt16;
            case StorageType.Int32: return DataTypePrecedence.Int32;
            case StorageType.UInt32: return DataTypePrecedence.UInt32; 
            case StorageType.Int64: return DataTypePrecedence.Int64;
            case StorageType.UInt64: return DataTypePrecedence.UInt64; 
            case StorageType.Single: return DataTypePrecedence.Single; 
            case StorageType.Double: return DataTypePrecedence.Double;
            case StorageType.Decimal: return DataTypePrecedence.Decimal; 
            case StorageType.DateTime: return DataTypePrecedence.DateTime;
            case StorageType.DateTimeOffset: return DataTypePrecedence.DateTimeOffset;
            case StorageType.TimeSpan: return DataTypePrecedence.TimeSpan;
            case StorageType.String: return DataTypePrecedence.String; 
            case StorageType.SqlBinary: return DataTypePrecedence.SqlBinary;
            case StorageType.SqlBoolean: return DataTypePrecedence.SqlBoolean; 
            case StorageType.SqlByte: return DataTypePrecedence.SqlByte; 
            case StorageType.SqlBytes: return DataTypePrecedence.SqlBytes;
            case StorageType.SqlChars: return DataTypePrecedence.SqlChars; 
            case StorageType.SqlDateTime: return DataTypePrecedence.SqlDateTime;
            case StorageType.SqlDecimal: return DataTypePrecedence.SqlDecimal;
            case StorageType.SqlDouble: return DataTypePrecedence.SqlDouble;
            case StorageType.SqlGuid: return DataTypePrecedence.SqlGuid; 
            case StorageType.SqlInt16: return DataTypePrecedence.SqlInt16;
            case StorageType.SqlInt32: return DataTypePrecedence.SqlInt32; 
            case StorageType.SqlInt64: return DataTypePrecedence.SqlInt64; 
            case StorageType.SqlMoney: return DataTypePrecedence.SqlMoney;
            case StorageType.SqlSingle: return DataTypePrecedence.SqlSingle; 
            case StorageType.SqlString: return DataTypePrecedence.SqlString;
//            case StorageType.SqlXml: return DataTypePrecedence.SqlXml;
            case StorageType.Empty:
            case StorageType.Object: 
            case StorageType.DBNull:
            default: return DataTypePrecedence.Error; 
            } 
        }
 
        private static StorageType GetPrecedenceType(DataTypePrecedence code) {
            switch (code) {
            case DataTypePrecedence.Error:       return StorageType.Empty;
            case DataTypePrecedence.SByte:       return StorageType.SByte; 
            case DataTypePrecedence.Byte:        return StorageType.Byte;
            case DataTypePrecedence.Int16:       return StorageType.Int16; 
            case DataTypePrecedence.UInt16:      return StorageType.UInt16; 
            case DataTypePrecedence.Int32:       return StorageType.Int32;
            case DataTypePrecedence.UInt32:      return StorageType.UInt32; 
            case DataTypePrecedence.Int64:       return StorageType.Int64;
            case DataTypePrecedence.UInt64:      return StorageType.UInt64;
            case DataTypePrecedence.Decimal:     return StorageType.Decimal;
            case DataTypePrecedence.Single:      return StorageType.Single; 
            case DataTypePrecedence.Double:      return StorageType.Double;
 
            case DataTypePrecedence.Boolean:     return StorageType.Boolean; 
            case DataTypePrecedence.String:      return StorageType.String;
            case DataTypePrecedence.Char:        return StorageType.Char; 

            case DataTypePrecedence.DateTimeOffset:  return StorageType.DateTimeOffset;
            case DataTypePrecedence.DateTime:    return StorageType.DateTime;
            case DataTypePrecedence.TimeSpan:    return StorageType.TimeSpan; 

            case DataTypePrecedence.SqlDateTime: return StorageType.SqlDateTime; 
            case DataTypePrecedence.SqlDouble:   return StorageType.SqlDouble; 
            case DataTypePrecedence.SqlSingle:   return StorageType.SqlSingle;
            case DataTypePrecedence.SqlDecimal:  return StorageType.SqlDecimal; 
            case DataTypePrecedence.SqlInt64:    return StorageType.SqlInt64;
            case DataTypePrecedence.SqlInt32:    return StorageType.SqlInt32;
            case DataTypePrecedence.SqlInt16:    return StorageType.SqlInt16;
            case DataTypePrecedence.SqlByte:     return StorageType.SqlByte; 
            case DataTypePrecedence.SqlBoolean:  return StorageType.SqlBoolean;
            case DataTypePrecedence.SqlString:   return StorageType.SqlString; 
            case DataTypePrecedence.SqlGuid:     return StorageType.SqlGuid; 
            case DataTypePrecedence.SqlBinary:   return StorageType.SqlBinary;
            case DataTypePrecedence.SqlMoney:    return StorageType.SqlMoney; 
            default:
            Debug.Assert(false, "Invalid (unmapped) precedence " + code.ToString());
            goto case DataTypePrecedence.Error;
            } 
        }
 
        private bool IsMixed(StorageType left, StorageType right) { 
            return ((IsSigned(left) && IsUnsigned(right)) ||
                    (IsUnsigned(left) && IsSigned(right))); 
        }

        private bool IsMixedSql(StorageType left, StorageType right) {
            return ((IsSignedSql(left) && IsUnsignedSql(right)) || 
                    (IsUnsignedSql(left) && IsSignedSql(right)));
        } 
 
        internal StorageType ResultType(StorageType left, StorageType right, bool lc, bool rc, int op) {
            if ((left == StorageType.Guid) && (right == StorageType.Guid) && Operators.IsRelational(op)) 
                return left;
            if ((left == StorageType.String) && (right == StorageType.Guid) && Operators.IsRelational(op))
                return left;
            if ((left == StorageType.Guid) && (right == StorageType.String) && Operators.IsRelational(op)) 
                return right;
 
             int leftPrecedence = (int)GetPrecedence(left); 
             if (leftPrecedence == (int)DataTypePrecedence.Error) {
                return StorageType.Empty; 
             }

             int rightPrecedence = (int)GetPrecedence(right);
             if (rightPrecedence == (int)DataTypePrecedence.Error) { 
                return StorageType.Empty;
             } 
 
             if (Operators.IsLogical(op)){
                if (left == StorageType.Boolean && right == StorageType.Boolean) 
                    return StorageType.Boolean;
                else
                    return StorageType.Empty;
             } 
            if ((left == StorageType.DateTimeOffset) ||(right == StorageType.DateTimeOffset))
            { 
                // Rules to handle DateTimeOffset: 
                // we only allow Relational operations to operate only on DTO vs DTO
                // all other operations: "exception" 
                if (Operators.IsRelational(op) && left == StorageType.DateTimeOffset && right == StorageType.DateTimeOffset)
                    return StorageType.DateTimeOffset;
                return StorageType.Empty;
            } 

             if ((op == Operators.Plus) && ((left == StorageType.String) || (right == StorageType.String))) 
                return StorageType.String; 

             DataTypePrecedence higherPrec = (DataTypePrecedence)Math.Max(leftPrecedence, rightPrecedence); 

             StorageType result = GetPrecedenceType(higherPrec);

             if (Operators.IsArithmetical(op)) { 
                if (result != StorageType.String && result != StorageType.Char) {
                    if (!IsNumeric(left)) 
                        return StorageType.Empty; 
                    if (!IsNumeric(right))
                        return StorageType.Empty; 
                }
             }

             // if the operation is a division the result should be at least a double 

             if ((op == Operators.Divide) && IsInteger(result)) { 
                return StorageType.Double; 
             }
 
             if (IsMixed(left, right)) {
                // we are dealing with one signed and one unsigned type so
                // try to see if one of them is a ConstNode
                if (lc && (!rc)) { 
                    return right;
                } 
                else if ((!lc) && rc) { 
                    return left;
                } 

                if (IsUnsigned(result)) {
                    if (higherPrec < DataTypePrecedence.UInt64)
                        // left and right are mixed integers but with the same length 
                        // so promote to the next signed type
                        result = GetPrecedenceType(higherPrec+1); 
                    else 
                        throw ExprException.AmbiguousBinop(op, DataStorage.GetTypeStorage(left), DataStorage.GetTypeStorage(right));
                } 
             }

             return result;
        } 

        internal StorageType ResultSqlType(StorageType left, StorageType right, bool lc, bool rc, int op) { 
            int leftPrecedence = (int)GetPrecedence(left); 
            if (leftPrecedence == (int)DataTypePrecedence.Error) {
              return StorageType.Empty; 
            }

            int rightPrecedence = (int)GetPrecedence(right);
            if (rightPrecedence == (int)DataTypePrecedence.Error) { 
              return StorageType.Empty;
            } 
 
            if (Operators.IsLogical(op)){
                if ((left != StorageType.Boolean  && left != StorageType.SqlBoolean) || (right != StorageType.Boolean && right != StorageType.SqlBoolean)) 
                      return StorageType.Empty;
                if (left == StorageType.Boolean && right == StorageType.Boolean)
                      return StorageType.Boolean;
                return  StorageType.SqlBoolean; 
            }
 
            if (op == Operators.Plus){ 
                if((left == StorageType.SqlString) ||(right == StorageType.SqlString))
                      return StorageType.SqlString; 
                if ((left == StorageType.String) || (right == StorageType.String))
                      return StorageType.String;
            }
            //SqlBinary is operable just with SqlBinary 
            if ((left == StorageType.SqlBinary && right != StorageType.SqlBinary) ||(left != StorageType.SqlBinary && right == StorageType.SqlBinary))
                return StorageType.Empty; 
            //SqlGuid is operable just with SqlGuid 
            if((left == StorageType.SqlGuid && right != StorageType.SqlGuid) ||(left != StorageType.SqlGuid && right == StorageType.SqlGuid))
                return StorageType.Empty; 

            if ((leftPrecedence > (int)DataTypePrecedence.SqlDouble  && rightPrecedence <(int) DataTypePrecedence.TimeSpan)){
                return StorageType.Empty;
            } 

            if ((leftPrecedence < (int)DataTypePrecedence.TimeSpan  && rightPrecedence >(int) DataTypePrecedence.SqlDouble)){ 
                return StorageType.Empty; 
            }
 
            if (leftPrecedence > (int) DataTypePrecedence.SqlDouble){
                if (op == Operators.Plus || op == Operators.Minus){
                      if (left == StorageType.TimeSpan)
                            return right; 
                      if (right == StorageType.TimeSpan)
                        return left; 
                      return StorageType.Empty; // for plus or minus operations for  time types, one of them MUST be time span 
                }
 
                if (!Operators.IsRelational(op))
                      return StorageType.Empty; // we just have relational operations amoung time types
                return left;
            } 
            // time types finished
            // continue with numerical types, numbers 
 
            DataTypePrecedence higherPrec = (DataTypePrecedence)Math.Max(leftPrecedence, rightPrecedence);
 
            StorageType result = GetPrecedenceType(higherPrec);
            // if we have at least one Sql type, the intermediate result should be Sql type
            result = GetPrecedenceType((DataTypePrecedence)SqlResultType((int)higherPrec));
 
            if (Operators.IsArithmetical(op)) {
                if (result != StorageType.String && result != StorageType.Char && result != StorageType.SqlString) { 
                      if (!IsNumericSql(left)) 
                            return StorageType.Empty;
                      if (!IsNumericSql(right)) 
                            return StorageType.Empty;
               }
            }
 
            // if the operation is a division the result should be at least a double
            if ((op == Operators.Divide) && IsIntegerSql(result)) { 
                 return StorageType.SqlDouble; 
            }
 
            if (result == StorageType.SqlMoney){
                if ((left != StorageType.SqlMoney) && (right != StorageType.SqlMoney))
                      result =  StorageType.SqlDecimal;
            } 

            if (IsMixedSql(left, right)) { 
            // we are dealing with one signed and one unsigned type so 
            // try to see if one of them is a ConstNode
 
                if (IsUnsignedSql(result)) {
                      if (higherPrec < DataTypePrecedence.UInt64)
                        // left and right are mixed integers but with the same length
                        // so promote to the next signed type 
                            result = GetPrecedenceType(higherPrec+1);
                      else 
                        throw ExprException.AmbiguousBinop(op, DataStorage.GetTypeStorage(left), DataStorage.GetTypeStorage(right)); 
                }
            } 

            return result;
        }
 
        private int SqlResultType(int typeCode){
            switch (typeCode){ 
            case  23: return  24; 
            case  20: return  21;
            case  18: return  19; 
            case  16: return  17;
            case  14: return  15;
            case  12: return  13;
            case  9  : 
            case  10: return  11;
            case  6  : 
            case  7  : return  8; 
            case  3  :
            case  4  : return  5; 
            case  1  : return  2;
            case  -2: return -1;
            case  -5: return -4;
            case  -8: return -7; 
            default : return typeCode;
           } 
        } 
    }
 
    internal sealed class LikeNode : BinaryNode {
        // like kinds
        internal const int match_left = 1;      // *
        internal const int match_right = 2;     // * 
        internal const int match_middle = 3;    // **
        internal const int match_exact  = 4;    //  
        internal const int match_all  = 5;      // * 

        int kind; 
        string pattern = null;

        internal LikeNode(DataTable table, int op, ExpressionNode left, ExpressionNode right)
        : base (table, op, left, right) { 
        }
 
        internal override object Eval(DataRow row, DataRowVersion version) { 
            object vRight;
            // 
            object vLeft = left.Eval(row, version);
            string substring;

 
            if ((vLeft == DBNull.Value)||(left.IsSqlColumn && DataStorage.IsObjectSqlNull(vLeft)))
                return DBNull.Value; 
 
            if (pattern == null) {
                vRight = right.Eval(row, version); 

                if (!(vRight is string) && !(vRight is SqlString)) {
                    SetTypeMismatchError(op, vLeft.GetType(), vRight.GetType());
                } 

          if (vRight == DBNull.Value || DataStorage.IsObjectSqlNull(vRight)) 
              return DBNull.Value; 
          string rightStr = (string) SqlConvert.ChangeType2(vRight, StorageType.String, typeof(string), FormatProvider);
 

                // need to convert like pattern to a string

                // Parce the original pattern, and get the constant part of it.. 
                substring = AnalyzePattern(rightStr);
 
                if (right.IsConstant()) 
                    pattern = substring;
            } 
            else {
                substring = pattern;
            }
 
            if (!(vLeft is string) && !(vLeft is SqlString)) {
                SetTypeMismatchError(op, vLeft.GetType(), typeof(string)); 
            } 

            // 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. 
            char[] trimChars = new char[2] {(char)0x20, (char)0x3000};
            string tempStr;
            if (vLeft is SqlString)
                tempStr = ((SqlString)vLeft).Value; 
            else
                tempStr = (string)vLeft; 
 
            string s1 = (tempStr).TrimEnd(trimChars);
 
            switch (kind) {
                case match_all:
                    return true;
                case match_exact: 
                    return(0 == table.Compare(s1, substring));
                case match_middle: 
                    return(0 <= table.IndexOf(s1, substring)); 
                case match_left:
                    return(0 == table.IndexOf(s1, substring)); 
                case match_right:
                    string s2 = substring.TrimEnd(trimChars);
                    return table.IsSuffix(s1, s2);
                default: 
                    Debug.Assert(false, "Unexpected LIKE kind");
                    return DBNull.Value; 
            } 
        }
 
        internal string AnalyzePattern(string pat) {

            int length = pat.Length;
            char[] patchars = new char[length+1]; 
            pat.CopyTo(0, patchars, 0, length);
            patchars[length] = (char)0; 
            string substring = null; 

            char[] constchars = new char[length+1]; 
            int newLength = 0;

            int stars = 0;
 
            int i = 0;
 
            while (i < length) { 

                if (patchars[i] == '*' || patchars[i] == '%') { 

                    // replace conseq. * or % with one..
                    while ((patchars[i] == '*' || patchars[i] == '%') && i < length)
                        i++; 

                    // we allowing only *str* pattern 
                    if ((i < length && newLength > 0) || stars >= 2) { 
                        // we have a star inside string constant..
                        throw ExprException.InvalidPattern(pat); 
                    }
                    stars++;

                } 
                else if (patchars[i] == '[') {
                    i++; 
                    if (i >= length) { 
                        throw ExprException.InvalidPattern(pat);
                    } 
                    constchars[newLength++] = patchars[i++];

                    if (i >= length) {
                        throw ExprException.InvalidPattern(pat); 
                    }
 
                    if (patchars[i] != ']') { 
                        throw ExprException.InvalidPattern(pat);
                    } 
                    i++;
                }
                else {
                    constchars[newLength++] = patchars[i]; 
                    i++;
                } 
            } 

            substring = new string(constchars, 0, newLength); 

            if (stars == 0) {
                kind = match_exact;
            } 
            else {
                if (newLength > 0) { 
                    if (patchars[0] == '*' || patchars[0] == '%') { 

                        if (patchars[length-1] == '*' || patchars[length-1] == '%') { 
                            kind = match_middle;
                        }
                        else {
                            kind = match_right; 
                        }
                    } 
                    else { 
                        Debug.Assert(patchars[length-1] == '*' || patchars[length-1] == '%', "Invalid LIKE pattern formed.. ");
                        kind = match_left; 
                    }
                }
                else {
                    kind = match_all; 
                }
            } 
            return substring; 
        }
    } 
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.

                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK