SqlTypeSystemProvider.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ Dotnetfx_Win7_3.5.1 / Dotnetfx_Win7_3.5.1 / 3.5.1 / DEVDIV / depot / DevDiv / releases / Orcas / NetFXw7 / ndp / fx / src / DLinq / Dlinq / SqlClient / SqlTypeSystemProvider.cs / 1 / SqlTypeSystemProvider.cs

                            using System.Collections.Generic; 
using System.Data.Common;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Linq; 
using System.Reflection;
using System.Text; 
 
namespace System.Data.Linq.SqlClient {
 
    internal static class SqlTypeSystem {

        internal static TypeSystemProvider Create2000Provider() {
            return new Sql2000Provider(); 
        }
 
        internal static TypeSystemProvider Create2005Provider() { 
            return new Sql2005Provider();
        } 

        internal static TypeSystemProvider Create2008Provider() {
            return new Sql2008Provider();
        } 

        internal static TypeSystemProvider CreateCEProvider() { 
            return new SqlCEProvider(); 
        }
 
        // -1 is used to indicate a MAX size.  In ADO.NET, -1 is specified as the size
        // on a SqlParameter with SqlDbType = VarChar to indicate VarChar(MAX).
        internal const short LargeTypeSizeIndicator = -1;
 
        // class constructor will cause static initialization to be deferred
        [SuppressMessage("Microsoft.Performance", "CA1810:InitializeReferenceTypeStaticFieldsInline", Justification="Static constructors provide deferred execution, which is desired.")] 
        static SqlTypeSystem() { } 

        #region Factories 
        private static ProviderType Create(SqlDbType type, int size) {
            return new SqlType(type, size);
        }
 
        private static ProviderType Create(SqlDbType type, int precision, int scale) {
            if (type != SqlDbType.Decimal && precision == 0 && scale == 0) { 
                return Create(type); 
            }
            else if (type == SqlDbType.Decimal && precision == defaultDecimalPrecision && scale == defaultDecimalScale) { 
                return Create(type);
            }
            return new SqlType(type, precision, scale);
        } 

        [SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity", Justification="These issues are related to our use of if-then and case statements for node types, which adds to the complexity count however when reviewed they are easy to navigate and understand.")] 
        private static ProviderType Create(SqlDbType type) { 
            switch (type) {
                case SqlDbType.BigInt: return theBigInt; 
                case SqlDbType.Bit: return theBit;
                case SqlDbType.Char: return theChar;
                case SqlDbType.DateTime: return theDateTime;
                case SqlDbType.Date: return theDate; 
                case SqlDbType.Time: return theTime;
                case SqlDbType.DateTime2: return theDateTime2; 
                case SqlDbType.DateTimeOffset: return theDateTimeOffset; 
                case SqlDbType.Decimal: return theDefaultDecimal;
                case SqlDbType.Float: return theFloat; 
                case SqlDbType.Int: return theInt;
                case SqlDbType.Money: return theMoney;
                case SqlDbType.Real: return theReal;
                case SqlDbType.UniqueIdentifier: return theUniqueIdentifier; 
                case SqlDbType.SmallDateTime: return theSmallDateTime;
                case SqlDbType.SmallInt: return theSmallInt; 
                case SqlDbType.SmallMoney: return theSmallMoney; 
                case SqlDbType.Timestamp: return theTimestamp;
                case SqlDbType.TinyInt: return theTinyInt; 
                case SqlDbType.Xml: return theXml;
                case SqlDbType.Text: return theText;
                case SqlDbType.NText: return theNText;
                case SqlDbType.Image: return theImage; 
                default:
                    return new SqlType(type); 
            } 
        }
 
        [SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity", Justification="These issues are related to our use of if-then and case statements for node types, which adds to the complexity count however when reviewed they are easy to navigate and understand.")]
        private static Type GetClosestRuntimeType(SqlDbType sqlDbType) {
            switch (sqlDbType) {
                case SqlDbType.Int: 
                    return typeof(int);
                case SqlDbType.BigInt: 
                    return typeof(long); 
                case SqlDbType.Bit:
                    return typeof(bool); 
                case SqlDbType.Date:
                case SqlDbType.SmallDateTime:
                case SqlDbType.DateTime:
                case SqlDbType.DateTime2: 
                    return typeof(DateTime);
                case SqlDbType.DateTimeOffset: 
                    return typeof(DateTimeOffset); 
                case SqlDbType.Time:
                    return typeof(TimeSpan); 
                case SqlDbType.Float:
                    return typeof(double);
                case SqlDbType.Real:
                    return typeof(float); 
                case SqlDbType.Binary:
                case SqlDbType.Image: 
                case SqlDbType.Timestamp: 
                case SqlDbType.VarBinary:
                    return typeof(byte[]); 
                case SqlDbType.Decimal:
                case SqlDbType.Money:
                case SqlDbType.SmallMoney:
                    return typeof(decimal); 
                case SqlDbType.Char:
                case SqlDbType.NChar: 
                case SqlDbType.NText: 
                case SqlDbType.NVarChar:
                case SqlDbType.Xml: 
                case SqlDbType.VarChar:
                case SqlDbType.Text:
                    return typeof(string);
                case SqlDbType.UniqueIdentifier: 
                    return typeof(Guid);
                case SqlDbType.SmallInt: 
                    return typeof(short); 
                case SqlDbType.TinyInt:
                    return typeof(byte); 
                case SqlDbType.Udt:
                    // Udt type is not handled.
                    throw Error.UnexpectedTypeCode(SqlDbType.Udt);
                case SqlDbType.Variant: 
                default:
                    return typeof(object); 
            } 
        }
        #endregion 

        #region Singleton SqlTypes
        /*
         * For simple types with no size, precision or scale, reuse a static set of SqlDataTypes. 
         * This has two advantages: Fewer allocations of SqlType and faster comparison of
         * one type to another. 
         */ 
        static private readonly SqlType theBigInt = new SqlType(SqlDbType.BigInt);
        static private readonly SqlType theBit = new SqlType(SqlDbType.Bit); 
        static private readonly SqlType theChar = new SqlType(SqlDbType.Char);
        static private readonly SqlType theDateTime = new SqlType(SqlDbType.DateTime);
        static private readonly SqlType theDate = new SqlType(SqlDbType.Date);
        static private readonly SqlType theTime = new SqlType(SqlDbType.Time); 
        static private readonly SqlType theDateTime2 = new SqlType(SqlDbType.DateTime2);
        static private readonly SqlType theDateTimeOffset = new SqlType(SqlDbType.DateTimeOffset); 
        const int defaultDecimalPrecision = 29; 
        const int defaultDecimalScale = 4;
        static private readonly SqlType theDefaultDecimal = new SqlType(SqlDbType.Decimal, defaultDecimalPrecision, defaultDecimalScale); 
        static private readonly SqlType theFloat = new SqlType(SqlDbType.Float);
        static private readonly SqlType theInt = new SqlType(SqlDbType.Int);
        static private readonly SqlType theMoney = new SqlType(SqlDbType.Money, 19, 4);
        static private readonly SqlType theReal = new SqlType(SqlDbType.Real); 
        static private readonly SqlType theUniqueIdentifier = new SqlType(SqlDbType.UniqueIdentifier);
        static private readonly SqlType theSmallDateTime = new SqlType(SqlDbType.SmallDateTime); 
        static private readonly SqlType theSmallInt = new SqlType(SqlDbType.SmallInt); 
        static private readonly SqlType theSmallMoney = new SqlType(SqlDbType.SmallMoney, 10, 4);
        static private readonly SqlType theTimestamp = new SqlType(SqlDbType.Timestamp); 
        static private readonly SqlType theTinyInt = new SqlType(SqlDbType.TinyInt);
        static private readonly SqlType theXml = new SqlType(SqlDbType.Xml, LargeTypeSizeIndicator);
        static private readonly SqlType theText = new SqlType(SqlDbType.Text, LargeTypeSizeIndicator);
        static private readonly SqlType theNText = new SqlType(SqlDbType.NText, LargeTypeSizeIndicator); 
        static private readonly SqlType theImage = new SqlType(SqlDbType.Image, LargeTypeSizeIndicator);
        #endregion 
 
        public class SqlType : ProviderType {
            ///  
            /// Helper method for building ToString functions.
            /// 
            protected static string KeyValue(string key, T value) {
                if (value != null) { 
                    return key + "=" + value.ToString() + " ";
                } 
                return String.Empty; 
            }
 
            /// 
            /// Helper method for building ToString functions.
           /// 
            protected static string SingleValue(T value) { 
                if (value != null) {
                    return value.ToString() + " "; 
                } 
                return string.Empty;
            } 
            public override string ToString() {
                return SingleValue(GetClosestRuntimeType())
                        + SingleValue(ToQueryString())
                        + KeyValue("IsApplicationType", IsApplicationType) 
                        + KeyValue("IsUnicodeType", IsUnicodeType)
                        + KeyValue("IsRuntimeOnlyType", IsRuntimeOnlyType) 
                        + KeyValue("SupportsComparison", SupportsComparison) 
                        + KeyValue("SupportsLength", SupportsLength)
                        + KeyValue("IsLargeType", IsLargeType) 
                        + KeyValue("IsFixedSize", IsFixedSize)
                        + KeyValue("IsOrderable", IsOrderable)
                        + KeyValue("IsGroupable", IsGroupable)
                        + KeyValue("IsNumeric", IsNumeric) 
                        + KeyValue("IsChar", IsChar)
                        + KeyValue("IsString", IsString); 
            } 
            protected SqlDbType sqlDbType;
            protected int? size; 
            protected int precision;
            protected int scale;
            Type runtimeOnlyType;
            private int? applicationTypeIndex = null; 

            #region Constructors 
            internal SqlType(SqlDbType type) { 
                this.sqlDbType = type;
            } 

            internal SqlType(SqlDbType type, int? size) {
                this.sqlDbType = type;
                this.size = size; 
            }
 
            internal SqlType(SqlDbType type, int precision, int scale) { 
                System.Diagnostics.Debug.Assert(scale <= precision);
                this.sqlDbType = type; 
                this.precision = precision;
                this.scale = scale;
            }
 
            internal SqlType(Type type) {
                this.runtimeOnlyType = type; 
            } 

            internal SqlType(int applicationTypeIndex) { 
                this.applicationTypeIndex = applicationTypeIndex;
            }
            #endregion
 
            #region ProviderType Implementation
            internal override bool IsUnicodeType { 
                get { 
                    switch (this.SqlDbType) {
                        case SqlDbType.NChar: 
                        case SqlDbType.NText:
                        case SqlDbType.NVarChar:
                            return true;
                        default: 
                            return false;
                    } 
                } 
            }
            internal override ProviderType GetNonUnicodeEquivalent() { 
                if (IsUnicodeType) {
                    switch (this.SqlDbType) {
                        case SqlDbType.NChar:
                            return new SqlType(SqlDbType.Char, this.Size); 
                        case SqlDbType.NText:
                            return new SqlType(SqlDbType.Text); 
                        case SqlDbType.NVarChar: 
                            return new SqlType(SqlDbType.VarChar, this.Size);
                        default: 
                            // can't happen
                            return this;
                    }
                } 
                return this;
            } 
            internal override bool IsRuntimeOnlyType { 
                get { return runtimeOnlyType != null; }
            } 

            internal override bool IsApplicationType {
                get { return applicationTypeIndex != null; }
            } 

            internal override bool IsApplicationTypeOf(int index) { 
                if (IsApplicationType) { 
                    return applicationTypeIndex == index;
                } 
                return false;
            }

            ///  
            /// Determines if it is safe to suppress size specifications for
            /// the operand of a cast/convert.  For example, when casting to string, 
            /// all these types have length less than the default sized used by SqlServer, 
            /// so the length specification can be omitted without fear of truncation.
            ///  
            internal override bool CanSuppressSizeForConversionToString{
                get {
                    int defaultSize = 30;
 
                    if (this.IsLargeType) {
                        return false; 
                    } 
                    else if (!this.IsChar && !this.IsString && this.IsFixedSize && this.Size > 0 /*&& this.Size != LargeTypeSizeIndicator*/) { // commented out because LargeTypeSizeIndicator == -1
                        return (this.Size < defaultSize); 
                    }
                    else {

                        switch (this.SqlDbType) { 
                            case SqlDbType.BigInt: // -2^63 (-9,223,372,036,854,775,808) to 2^63-1 (9,223,372,036,854,775,807)
                            case SqlDbType.Bit: // 0 or 1 
                            case SqlDbType.Int: // -2^31 (-2,147,483,648) to 2^31-1 (2,147,483,647) 
                            case SqlDbType.SmallInt: // -2^15 (-32,768) to 2^15-1 (32,767)
                            case SqlDbType.TinyInt: // 0 to 255 
                            case SqlDbType.Money: // -922,337,203,685,477.5808 to 922,337,203,685,477.5807
                            case SqlDbType.SmallMoney: // -214,748.3648 to 214,748.3647
                            case SqlDbType.Float: // -1.79E+308 to -2.23E-308, 0 and 2.23E-308 to 1.79E+308
                            case SqlDbType.Real: // -3.40E+38 to -1.18E-38, 0 and 1.18E-38 to 3.40E+38 
                                return true;
                            default: 
                                return false; 
                        };
                    } 

                }
            }
 
            internal override int ComparePrecedenceTo(ProviderType type) {
                SqlType sqlProviderType = (SqlType)type; 
                // Highest precedence is given to server-known types. Converting to a client-only type is 
                // impossible when the conversion is present in a SQL query.
                int p0 = IsTypeKnownByProvider ? GetTypeCoercionPrecedence(this.SqlDbType) : Int32.MinValue; 
                int p1 = sqlProviderType.IsTypeKnownByProvider ? GetTypeCoercionPrecedence(sqlProviderType.SqlDbType) : Int32.MinValue;
                return p0.CompareTo(p1);
            }
 
            /// 
            /// Whether this is a legitimate server side type like NVARCHAR. 
            ///  
            private bool IsTypeKnownByProvider {
                get { return !IsApplicationType && !IsRuntimeOnlyType; } 
            }

            internal override bool IsSameTypeFamily(ProviderType type) {
                SqlType sqlType = (SqlType)type; 
                if (IsApplicationType) {
                    return false; 
                } 
                if (sqlType.IsApplicationType) {
                    return false; 
                }
                return this.Category == sqlType.Category;
            }
 
            internal override bool SupportsComparison {
                get { 
                    switch (this.sqlDbType) { 
                        case SqlDbType.NText:
                        case SqlDbType.Image: 
                        case SqlDbType.Xml:
                        case SqlDbType.Text:
                            return false;
                        default: 
                            return true;
                    } 
                } 
            }
 
            internal override bool SupportsLength {
                get {
                    switch (this.sqlDbType) {
                        case SqlDbType.NText: 
                        case SqlDbType.Image:
                        case SqlDbType.Xml: 
                        case SqlDbType.Text: 
                            return false;
                        default: 
                            return true;
                    }
                }
            } 

            ///  
            /// Returns true if the given values will be equal to eachother on the server for this type. 
            /// 
            internal override bool AreValuesEqual(object o1, object o2) { 
                if (o1 == null || o2 == null) {
                    return false;
                }
                switch (this.sqlDbType) { 
                    case SqlDbType.Char:
                    case SqlDbType.NChar: 
                    case SqlDbType.NVarChar: 
                    case SqlDbType.VarChar:
                    case SqlDbType.Text: 
                        string s1 = o1 as string;
                        if (s1 != null) {
                            string s2 = o2 as string;
                            if (s2 != null) { 
                                return s1.TrimEnd(' ').Equals(s2.TrimEnd(' '), StringComparison.Ordinal);
                            } 
                        } 
                        break;
                } 
                return o1.Equals(o2);
            }

            internal override bool IsLargeType { 
                get {
                    switch (this.sqlDbType) { 
                        case SqlDbType.NText: 
                        case SqlDbType.Image:
                        case SqlDbType.Xml: 
                        case SqlDbType.Text:
                            return true;
                        case SqlDbType.NVarChar:
                        case SqlDbType.VarChar: 
                        case SqlDbType.VarBinary:
                            return (this.size == LargeTypeSizeIndicator); 
                        default: 
                            return false;
                    } 
                }
            }

            internal override bool HasPrecisionAndScale { 
                get {
                    switch (SqlDbType) { 
                        case SqlDbType.Decimal: 
                        case SqlDbType.Float:
                        case SqlDbType.Real: 
                        case SqlDbType.Money:      // precision and scale are fixed at 19,4
                        case SqlDbType.SmallMoney: // precision and scale are fixed at 10,4
                        case SqlDbType.DateTime2:
                        case SqlDbType.DateTimeOffset: 
                        case SqlDbType.Time:
                            return true; 
                        default: 
                            return false;
                    } 
                }
            }

            internal override Type GetClosestRuntimeType() { 
                if (runtimeOnlyType != null) {
                    return runtimeOnlyType; 
                } 
                else {
                    return SqlTypeSystem.GetClosestRuntimeType(this.sqlDbType); 
                }
            }

            internal override string ToQueryString() { 
                return ToQueryString(QueryFormatOptions.None);
            } 
 
            [SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity", Justification="These issues are related to our use of if-then and case statements for node types, which adds to the complexity count however when reviewed they are easy to navigate and understand.")]
            internal override string ToQueryString(QueryFormatOptions formatFlags) { 
                if (runtimeOnlyType != null) {
                    return runtimeOnlyType.ToString();
                }
                StringBuilder sb = new StringBuilder(); 

                switch (sqlDbType) { 
                    case SqlDbType.BigInt: 
                    case SqlDbType.Bit:
                    case SqlDbType.Date: 
                    case SqlDbType.Time:
                    case SqlDbType.DateTime:
                    case SqlDbType.DateTime2:
                    case SqlDbType.DateTimeOffset: 
                    case SqlDbType.Int:
                    case SqlDbType.Money: 
                    case SqlDbType.SmallDateTime: 
                    case SqlDbType.SmallInt:
                    case SqlDbType.SmallMoney: 
                    case SqlDbType.Timestamp:
                    case SqlDbType.TinyInt:
                    case SqlDbType.UniqueIdentifier:
                    case SqlDbType.Xml: 
                    case SqlDbType.Image:
                    case SqlDbType.NText: 
                    case SqlDbType.Text: 
                    case SqlDbType.Udt:
                        sb.Append(sqlDbType.ToString()); 
                        break;
                    case SqlDbType.Variant:
                        sb.Append("sql_variant");
                        break; 
                    case SqlDbType.Binary:
                    case SqlDbType.Char: 
                    case SqlDbType.NChar: 
                        sb.Append(sqlDbType);
                        if ((formatFlags & QueryFormatOptions.SuppressSize) == 0) { 
                            sb.Append("(");
                            sb.Append(size);
                            sb.Append(")");
                        } 
                        break;
                    case SqlDbType.NVarChar: 
                    case SqlDbType.VarBinary: 
                    case SqlDbType.VarChar:
                        sb.Append(sqlDbType); 
                        if ((size.HasValue && size != 0) && (formatFlags & QueryFormatOptions.SuppressSize) == 0) {
                            sb.Append("(");
                            if (size == LargeTypeSizeIndicator) {
                                sb.Append("MAX"); 
                            }
                            else { 
                                sb.Append(size); 
                            }
                            sb.Append(")"); 
                        }
                        break;
                    case SqlDbType.Decimal:
                    case SqlDbType.Float: 
                    case SqlDbType.Real:
                        sb.Append(sqlDbType); 
                        if (precision != 0) { 
                            sb.Append("(");
                            sb.Append(precision); 
                            if (scale != 0) {
                                sb.Append(",");
                                sb.Append(scale);
                            } 
                            sb.Append(")");
                        } 
                        break; 
                }
                return sb.ToString(); 
            }

            internal override bool HasSizeOrIsLarge {
                get { 
                    return this.size.HasValue || this.IsLargeType;
                } 
            } 

            internal override int? Size { 
                get {
                    return this.size;
                }
            } 

            internal int Precision { 
                get { return this.precision; } 
            }
 
            internal int Scale {
                get { return this.scale; }
            }
 
            internal override bool IsFixedSize {
                get { 
                    switch (this.sqlDbType) { 
                        case SqlDbType.NText:
                        case SqlDbType.Text: 
                        case SqlDbType.NVarChar:
                        case SqlDbType.VarChar:
                        case SqlDbType.Image:
                        case SqlDbType.VarBinary: 
                        case SqlDbType.Xml:
                            return false; 
                        default: 
                            return true;
                    } 
                }
            }

            internal SqlDbType SqlDbType { 
                get { return sqlDbType; }
            } 
 
            internal override bool IsOrderable {
                get { 
                    if (this.IsRuntimeOnlyType) return false; // must be a SQL type

                    switch (this.sqlDbType) {
                        case SqlDbType.Image: 
                        case SqlDbType.Text:
                        case SqlDbType.NText: 
                        case SqlDbType.Xml: 
                            return false;
                        default: 
                            return true;
                    }
                }
            } 

            internal override bool IsGroupable { 
                get { 
                    if (this.IsRuntimeOnlyType) return false; // must be a SQL type
 
                    switch (this.sqlDbType) {
                        case SqlDbType.Image:
                        case SqlDbType.Text:
                        case SqlDbType.NText: 
                        case SqlDbType.Xml:
                            return false; 
                        default: 
                            return true;
                    } 
                }
            }

            internal override bool CanBeColumn { 
                get { return !this.IsApplicationType && !this.IsRuntimeOnlyType; }
            } 
 
            internal override bool CanBeParameter {
                get { return !this.IsApplicationType && !this.IsRuntimeOnlyType; } 
            }

            internal override bool IsNumeric {
                get { 
                    if (IsApplicationType || IsRuntimeOnlyType) {
                        return false; 
                    } 
                    switch (SqlDbType) {
                        case SqlDbType.Bit: 
                        case SqlDbType.TinyInt:
                        case SqlDbType.SmallInt:
                        case SqlDbType.Int:
                        case SqlDbType.BigInt: 
                        case SqlDbType.Decimal:
                        case SqlDbType.Float: 
                        case SqlDbType.Real: 
                        case SqlDbType.Money:
                        case SqlDbType.SmallMoney: 
                            return true;
                        default:
                            return false;
                    }; 
                }
            } 
 
            internal override bool IsChar {
                get { 
                    if (IsApplicationType || IsRuntimeOnlyType)
                        return false;
                    switch (SqlDbType) {
                        case SqlDbType.Char: 
                        case SqlDbType.NChar:
                        case SqlDbType.NVarChar: 
                        case SqlDbType.VarChar: 
                            return Size == 1;
                        default: 
                            return false;
                    }
                }
            } 

            internal override bool IsString { 
                get { 
                    if (IsApplicationType || IsRuntimeOnlyType)
                        return false; 
                    switch (SqlDbType) {
                        case SqlDbType.Char:
                        case SqlDbType.NChar:
                        case SqlDbType.NVarChar: 
                        case SqlDbType.VarChar:
                            // -1 is used for large types to represent MAX 
                            return Size == 0 || Size > 1 || Size == LargeTypeSizeIndicator; 
                        case SqlDbType.Text:
                        case SqlDbType.NText: 
                            return true;
                        default:
                            return false;
                    } 
                }
            } 
            #endregion 

            #region Equals + GetHashCode 

            public override bool Equals(object obj) {
                if ((object)this == obj)
                    return true; 

                SqlType that = obj as SqlType; 
                if (that == null) 
                    return false;
 
                return
                    this.runtimeOnlyType == that.runtimeOnlyType &&
                    this.applicationTypeIndex == that.applicationTypeIndex &&
                    this.sqlDbType == that.sqlDbType && 
                    this.Size == that.Size &&
                    this.precision == that.precision && 
                    this.scale == that.scale; 
            }
 
            public override int GetHashCode() {
                // Make up a hash function that will atleast not treat precision and scale
                // as interchangeable. This may need a smarter replacement if certain hash
                // buckets get too full. 
                int hash = 0;
                if (this.runtimeOnlyType != null) { 
                    hash = this.runtimeOnlyType.GetHashCode(); 
                }
                else if (this.applicationTypeIndex != null) { 
                    hash = this.applicationTypeIndex.Value;
                }
                return hash ^ this.sqlDbType.GetHashCode() ^ (this.size ?? 0) ^ (this.precision) ^ (this.scale << 8);
            } 
            #endregion
 
            #region Type Classification 
            [SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity", Justification="These issues are related to our use of if-then and case statements for node types, which adds to the complexity count however when reviewed they are easy to navigate and understand.")]
            private static int GetTypeCoercionPrecedence(SqlDbType type) { 
                switch (type) {
                    case SqlDbType.Binary: return 0;
                    case SqlDbType.VarBinary: return 1;
                    case SqlDbType.VarChar: return 2; 
                    case SqlDbType.Char: return 3;
                    case SqlDbType.NChar: return 4; 
                    case SqlDbType.NVarChar: return 5; 
                    case SqlDbType.UniqueIdentifier: return 6;
                    case SqlDbType.Timestamp: return 7; 
                    case SqlDbType.Image: return 8;
                    case SqlDbType.Text: return 9;
                    case SqlDbType.NText: return 10;
                    case SqlDbType.Bit: return 11; 
                    case SqlDbType.TinyInt: return 12;
                    case SqlDbType.SmallInt: return 13; 
                    case SqlDbType.Int: return 14; 
                    case SqlDbType.BigInt: return 15;
                    case SqlDbType.SmallMoney: return 16; 
                    case SqlDbType.Money: return 17;
                    case SqlDbType.Decimal: return 18;
                    case SqlDbType.Real: return 19;
                    case SqlDbType.Float: return 20; 
                    case SqlDbType.Date: return 21;
                    case SqlDbType.Time: return 22; 
                    case SqlDbType.SmallDateTime: return 23; 
                    case SqlDbType.DateTime: return 24;
                    case SqlDbType.DateTime2: return 25; 
                    case SqlDbType.DateTimeOffset: return 26;
                    case SqlDbType.Xml: return 27;
                    case SqlDbType.Variant: return 28;
                    case SqlDbType.Udt: return 29; 
                    default:
                        throw Error.UnexpectedTypeCode(type); 
                } 
            }
 
            internal enum TypeCategory {
                Numeric,
                Char,
                Text, 
                Binary,
                Image, 
                Xml, 
                DateTime,
                UniqueIdentifier, 
                Variant,
                Udt
            }
 
            [SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity", Justification="These issues are related to our use of if-then and case statements for node types, which adds to the complexity count however when reviewed they are easy to navigate and understand.")]
            internal TypeCategory Category { 
                get { 
                    switch (this.SqlDbType) {
                        case SqlDbType.Bit: 
                        case SqlDbType.TinyInt:
                        case SqlDbType.SmallInt:
                        case SqlDbType.Int:
                        case SqlDbType.BigInt: 
                        case SqlDbType.Decimal:
                        case SqlDbType.Float: 
                        case SqlDbType.Real: 
                        case SqlDbType.Money:
                        case SqlDbType.SmallMoney: 
                            return TypeCategory.Numeric;
                        case SqlDbType.Char:
                        case SqlDbType.NChar:
                        case SqlDbType.VarChar: 
                        case SqlDbType.NVarChar:
                            return TypeCategory.Char; 
                        case SqlDbType.Text: 
                        case SqlDbType.NText:
                            return TypeCategory.Text; 
                        case SqlDbType.Binary:
                        case SqlDbType.VarBinary:
                        case SqlDbType.Timestamp:
                            return TypeCategory.Binary; 
                        case SqlDbType.Image:
                            return TypeCategory.Image; 
                        case SqlDbType.Xml: 
                            return TypeCategory.Xml;
                        case SqlDbType.Date: 
                        case SqlDbType.Time:
                        case SqlDbType.DateTime:
                        case SqlDbType.DateTime2:
                        case SqlDbType.DateTimeOffset: 
                        case SqlDbType.SmallDateTime:
                            return TypeCategory.DateTime; 
                        case SqlDbType.UniqueIdentifier: 
                            return TypeCategory.UniqueIdentifier;
                        case SqlDbType.Variant: 
                            return TypeCategory.Variant;
                        case SqlDbType.Udt:
                            return TypeCategory.Udt;
                        default: 
                            throw Error.UnexpectedTypeCode(this);
                    } 
                } 
            }
            #endregion 
        }

        abstract class ProviderBase : TypeSystemProvider {
            protected Dictionary applicationTypes = new Dictionary(); 

            #region Factories 
            internal override ProviderType GetApplicationType(int index) { 
                if (index < 0)
                    throw Error.ArgumentOutOfRange("index"); 
                SqlType result = null;
                if (!applicationTypes.TryGetValue(index, out result)) {
                    result = new SqlType(index);
                    applicationTypes.Add(index, result); 
                }
                return result; 
            } 

            [SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity", Justification="These issues are related to our use of if-then and case statements for node types, which adds to the complexity count however when reviewed they are easy to navigate and understand.")] 
            internal override ProviderType Parse(string stype) {
                // parse type...
                string typeName = null;
                string param1 = null; 
                string param2 = null;
                int paren = stype.IndexOf('('); 
                int space = stype.IndexOf(' '); 
                int end = (paren != -1 && space != -1) ? Math.Min(space, paren)
                        : (paren != -1) ? paren 
                        : (space != -1) ? space
                        : -1;
                if (end == -1) {
                    typeName = stype; 
                    end = stype.Length;
                } 
                else { 
                    typeName = stype.Substring(0, end);
                } 
                int start = end;
                if (start < stype.Length && stype[start] == '(') {
                    start++;
                    end = stype.IndexOf(',', start); 
                    if (end > 0) {
                        param1 = stype.Substring(start, end - start); 
                        start = end + 1; 
                        end = stype.IndexOf(')', start);
                        param2 = stype.Substring(start, end - start); 
                    }
                    else {
                        end = stype.IndexOf(')', start);
                        param1 = stype.Substring(start, end - start); 
                    }
                    start = end++; 
                } 

                #region Special case type mappings 
                if (String.Compare(typeName, "rowversion", StringComparison.OrdinalIgnoreCase) == 0) {
                    typeName = "Timestamp";
                }
 
                if (String.Compare(typeName, "numeric", StringComparison.OrdinalIgnoreCase) == 0) {
                    typeName = "Decimal"; 
                } 

                if (String.Compare(typeName, "sql_variant", StringComparison.OrdinalIgnoreCase) == 0) { 
                    typeName = "Variant";
                }

                if (String.Compare(typeName, "filestream", StringComparison.OrdinalIgnoreCase) == 0) { 
                    typeName = "Binary";
                } 
                #endregion 

                // since we're going to parse the enum value below, we verify 
                // here that it is defined.  For example, types like table, cursor
                // are not valid.
                if (!Enum.GetNames(typeof(SqlDbType)).Select(n => n.ToUpperInvariant()).Contains(typeName.ToUpperInvariant()))
                { 
                    throw Error.InvalidProviderType(typeName);
                } 
 
                int p1 = 0;
                int p2 = 0; 
                SqlDbType dbType = (SqlDbType)Enum.Parse(typeof(SqlDbType), typeName, true);
                if (param1 != null) {
                    if (String.Compare(param1.Trim(), "max", StringComparison.OrdinalIgnoreCase) == 0) {
                        p1 = LargeTypeSizeIndicator; 
                    }
                    else { 
                        p1 = Int32.Parse(param1, Globalization.CultureInfo.InvariantCulture); 
                        if (p1 == int.MaxValue)
                            p1 = LargeTypeSizeIndicator; 
                    }
                }

                if (param2 != null) { 
                    if (String.Compare(param2.Trim(), "max", StringComparison.OrdinalIgnoreCase) == 0) {
                        p2 = LargeTypeSizeIndicator; 
                    } 
                    else {
                        p2 = Int32.Parse(param2, Globalization.CultureInfo.InvariantCulture); 
                        if (p2 == int.MaxValue)
                            p2 = LargeTypeSizeIndicator;

                    } 
                }
 
                switch (dbType) { 
                    case SqlDbType.Binary:
                    case SqlDbType.Char: 
                    case SqlDbType.NChar:
                    case SqlDbType.NVarChar:
                    case SqlDbType.VarBinary:
                    case SqlDbType.VarChar: 
                        return Create(dbType, p1);
                    case SqlDbType.Decimal: 
                    case SqlDbType.Real: 
                    case SqlDbType.Float:
                        return Create(dbType, p1, p2); 
                    case SqlDbType.Timestamp:
                    default:
                        return Create(dbType);
                } 
            }
            #endregion 
 
            #region Implementation
            // Returns true if the type provider supports MAX types (e.g NVarChar(MAX)) 
            protected abstract bool SupportsMaxSize { get; }

            /// 
            /// For types with size, determine the closest matching type for the information 
            /// specified, promoting to the appropriate large type as needed.  If no size is
            /// specified, we use the max. 
            ///  
            protected ProviderType GetBestType(SqlDbType targetType, int? size)
            { 
                // determine max size for the specified db type
                int maxSize = 0;
                switch (targetType)
                { 
                    case SqlDbType.NChar:
                    case SqlDbType.NVarChar: 
                        maxSize = 4000; 
                        break;
                    case SqlDbType.Char: 
                    case SqlDbType.VarChar:
                    case SqlDbType.Binary:
                    case SqlDbType.VarBinary:
                        maxSize = 8000; 
                        break;
                }; 
 
                if (size.HasValue)
                { 
                    if (size.Value <= maxSize)
                    {
                        return Create(targetType, size.Value);
                    } 
                    else
                    { 
                        return GetBestLargeType(Create(targetType)); 
                    }
                } 

                // if the type provider supports MAX types, return one, otherwise use
                // the maximum size determined above
                return Create(targetType, SupportsMaxSize ? SqlTypeSystem.LargeTypeSizeIndicator : maxSize); 
            }
 
            internal override void InitializeParameter(ProviderType type, DbParameter parameter, object value) { 
                SqlType sqlType = (SqlType)type;
                if (sqlType.IsRuntimeOnlyType) { 
                    throw Error.BadParameterType(sqlType.GetClosestRuntimeType());
                }
                System.Data.SqlClient.SqlParameter sParameter = parameter as System.Data.SqlClient.SqlParameter;
                if (sParameter != null) { 
                    sParameter.SqlDbType = sqlType.SqlDbType;
                    if (sqlType.HasPrecisionAndScale) { 
                        sParameter.Precision = (byte)sqlType.Precision; 
                        sParameter.Scale = (byte)sqlType.Scale;
                    } 
                }
                else {
                    PropertyInfo piSqlDbType = parameter.GetType().GetProperty("SqlDbType");
                    if (piSqlDbType != null) { 
                        piSqlDbType.SetValue(parameter, sqlType.SqlDbType, null);
                    } 
                    if (sqlType.HasPrecisionAndScale) { 
                        PropertyInfo piPrecision = parameter.GetType().GetProperty("Precision");
                        if (piPrecision != null) { 
                            piPrecision.SetValue(parameter, Convert.ChangeType(sqlType.Precision, piPrecision.PropertyType, CultureInfo.InvariantCulture), null);
                        }
                        PropertyInfo piScale = parameter.GetType().GetProperty("Scale");
                        if (piScale != null) { 
                            piScale.SetValue(parameter, Convert.ChangeType(sqlType.Scale, piScale.PropertyType, CultureInfo.InvariantCulture), null);
                        } 
                    } 
                }
                parameter.Value = GetParameterValue(sqlType, value); 
                // We want to allow the size of input parameters to be computed
                // implicitly (by setting the Value above). However, for fixed
                // length types and out/inout parameters, we want to set the size
                // explicitly (in the case of in/inout parameters only if the 
                // computed size is less than the fixed length, to avoid truncating
                // data). 
                bool isFixedSizeInputParameter = (parameter.Direction == ParameterDirection.Input) && sqlType.IsFixedSize; 
                if (isFixedSizeInputParameter || parameter.Direction != ParameterDirection.Input) {
                    if ((sqlType.Size.HasValue && parameter.Size < sqlType.Size) || sqlType.IsLargeType) { 
                        parameter.Size = sqlType.Size.Value;
                    }
                }
            } 

            [SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic", Justification="Unknown reason.")] 
            protected object GetParameterValue(SqlType type, object value) { 
                if (value == null) {
                    return DBNull.Value; 
                }
                else {
                    Type vType = value.GetType();
                    Type pType = type.GetClosestRuntimeType(); 
                    if (pType == vType) {
                        return value; 
                    } 
                    else {
                        return DBConvert.ChangeType(value, pType); 
                    }
                }
            }
 
            [SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity", Justification="These issues are related to our use of if-then and case statements for node types, which adds to the complexity count however when reviewed they are easy to navigate and understand.")]
            internal override ProviderType PredictTypeForUnary(SqlNodeType unaryOp, ProviderType operandType) { 
                switch (unaryOp) { 
                    case SqlNodeType.Not:
                    case SqlNodeType.Not2V: 
                    case SqlNodeType.IsNull:
                    case SqlNodeType.IsNotNull:
                        return theBit;
                    case SqlNodeType.Negate: 
                    case SqlNodeType.BitNot:
                    case SqlNodeType.ValueOf: 
                    case SqlNodeType.Treat: 
                    case SqlNodeType.OuterJoinedValue:
                        return operandType; 
                    case SqlNodeType.Count:
                        return this.From(typeof(int));
                    case SqlNodeType.LongCount:
                        return this.From(typeof(long)); 
                    case SqlNodeType.Min:
                    case SqlNodeType.Max: 
                        return operandType; 
                    case SqlNodeType.Sum:
                    case SqlNodeType.Avg: 
                    case SqlNodeType.Stddev:
                    case SqlNodeType.Covar:
                        return this.MostPreciseTypeInFamily(operandType);
                    case SqlNodeType.ClrLength: 
                        if (operandType.IsLargeType) {
                            return this.From(typeof(long)); // SqlDbType.BigInt 
                        } 
                        else {
                            return this.From(typeof(int)); // SqlDbType.Int 
                        }
                    default:
                        throw Error.UnexpectedNode(unaryOp);
                } 
            }
 
            [SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity", Justification="These issues are related to our use of if-then and case statements for node types, which adds to the complexity count however when reviewed they are easy to navigate and understand.")] 
            internal override ProviderType PredictTypeForBinary(SqlNodeType binaryOp, ProviderType leftType, ProviderType rightType) {
                SqlType highest; 

                if (leftType.IsSameTypeFamily(this.From(typeof(string))) && rightType.IsSameTypeFamily(this.From(typeof(string)))) {
                    highest = (SqlType)this.GetBestType(leftType, rightType);
                } else { 
                    int coercionPrecedence = leftType.ComparePrecedenceTo(rightType);
                    highest = (SqlType)(coercionPrecedence > 0 ? leftType : rightType); 
                } 

                switch (binaryOp) { 
                    case SqlNodeType.Add:
                    case SqlNodeType.Sub:
                    case SqlNodeType.Mul:
                    case SqlNodeType.Div: 
                    case SqlNodeType.BitAnd:
                    case SqlNodeType.BitOr: 
                    case SqlNodeType.BitXor: 
                    case SqlNodeType.Mod:
                    case SqlNodeType.Coalesce: 
                        return highest;
                    case SqlNodeType.Concat:
                        // When concatenating two types with size, the result type after
                        // concatenation must have a size equal to the sum of the two sizes. 
                        if (highest.HasSizeOrIsLarge)
                        { 
                            // get the best type, specifying null for size so we get 
                            // the maximum allowable size
                            ProviderType concatType = this.GetBestType(highest.SqlDbType, null); 

                            if ((!leftType.IsLargeType && leftType.Size.HasValue) &&
                                (!rightType.IsLargeType && rightType.Size.HasValue))
                            { 
                                // If both types are not large types and have size, and the
                                // size is less than the default size, return the shortened type. 
                                int concatSize = leftType.Size.Value + rightType.Size.Value; 
                                if ((concatSize < concatType.Size) || concatType.IsLargeType)
                                { 
                                    return GetBestType(highest.SqlDbType, concatSize);
                                }
                            }
 
                            return concatType;
                        } 
                        return highest; 
                    case SqlNodeType.And:
                    case SqlNodeType.Or: 
                    case SqlNodeType.LT:
                    case SqlNodeType.LE:
                    case SqlNodeType.GT:
                    case SqlNodeType.GE: 
                    case SqlNodeType.EQ:
                    case SqlNodeType.NE: 
                    case SqlNodeType.EQ2V: 
                    case SqlNodeType.NE2V:
                        return theInt; 
                    default:
                        throw Error.UnexpectedNode(binaryOp);
                }
            } 

            internal override ProviderType MostPreciseTypeInFamily(ProviderType type) { 
                SqlType sqlType = (SqlType)type; 
                switch (sqlType.SqlDbType) {
                    case SqlDbType.TinyInt: 
                    case SqlDbType.SmallInt:
                    case SqlDbType.Int:
                        return From(typeof(int));
                    case SqlDbType.SmallMoney: 
                    case SqlDbType.Money:
                        return Create(SqlDbType.Money); 
                    case SqlDbType.Real: 
                    case SqlDbType.Float:
                        return From(typeof(double)); 
                    case SqlDbType.Date:
                    case SqlDbType.Time:
                    case SqlDbType.SmallDateTime:
                    case SqlDbType.DateTime: 
                    case SqlDbType.DateTime2:
                        return From(typeof(DateTime)); 
                    case SqlDbType.DateTimeOffset: 
                        return From(typeof(DateTimeOffset));
                    default: 
                        return type;
                }
            }
 
            [SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic", Justification="Unknown reason.")]
            private ProviderType[] GetArgumentTypes(SqlFunctionCall fc) { 
                ProviderType[] array = new ProviderType[fc.Arguments.Count]; 
                for (int i = 0, n = array.Length; i < n; i++) {
                    array[i] = fc.Arguments[i].SqlType; 
                }
                return array;
            }
 
            /// 
            /// Gives the return type of a SQL function which has as first argument something of this SqlType. 
            /// For some functions (e.g. trigonometric functions) the return type is independent of the argument type; 
            /// in those cases this method returns null and the type was already set correctly in the MethodCallConverter.
            ///  
            /// The SqlFunctionCall node.
            /// null: Don't change type, otherwise: Set return type to this ProviderType
            [SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity", Justification="These issues are related to our use of if-then and case statements for node types, which adds to the complexity count however when reviewed they are easy to navigate and understand.")]
            internal override ProviderType ReturnTypeOfFunction(SqlFunctionCall functionCall) { 
                var argumentTypes = this.GetArgumentTypes(functionCall);
 
                SqlType arg0 = (SqlType)argumentTypes[0]; 
                SqlType arg1 = argumentTypes.Length > 1 ? (SqlType)argumentTypes[1] : (SqlType)null;
 
                switch (functionCall.Name) {
                    case "LEN":
                    case "DATALENGTH":
                        switch (arg0.SqlDbType) { 
                            case SqlDbType.NVarChar:
                            case SqlDbType.VarChar: 
                            case SqlDbType.VarBinary: 
                                if (arg0.IsLargeType) {
                                    return Create(SqlDbType.BigInt); 
                                }
                                else {
                                    return Create(SqlDbType.Int);
                                } 
                            default:
                                return Create(SqlDbType.Int); 
                        } 
                    case "ABS":
                    case "SIGN": 
                    case "ROUND":
                    case "CEILING":
                    case "FLOOR":
                    case "POWER": 
                        switch (arg0.SqlDbType) {
                            case SqlDbType.TinyInt: 
                            case SqlDbType.Int: 
                            case SqlDbType.SmallInt:
                                return Create(SqlDbType.Int); 
                            case SqlDbType.Float:
                            case SqlDbType.Real:
                                return Create(SqlDbType.Float);
                            default: 
                                return arg0;
                        } 
                    case "PATINDEX": 
                    case "CHARINDEX":
                        if (arg1.IsLargeType) 
                            return Create(SqlDbType.BigInt);
                        return Create(SqlDbType.Int);
                    case "SUBSTRING":
                        if (functionCall.Arguments[2].NodeType == SqlNodeType.Value) { 
                            SqlValue val = (SqlValue)functionCall.Arguments[2];
 
                            if (val.Value is int) { 
                                switch (arg0.SqlDbType) {
                                    case SqlDbType.NVarChar: 
                                    case SqlDbType.NChar:
                                    case SqlDbType.VarChar:
                                    case SqlDbType.Char:
                                        return Create(arg0.SqlDbType, (int)val.Value); 
                                    default:
                                        return null; 
                                } 
                            }
                        } 
                        switch (arg0.SqlDbType) {
                            case SqlDbType.NVarChar:
                            case SqlDbType.NChar:
                                return Create(SqlDbType.NVarChar); 
                            case SqlDbType.VarChar:
                            case SqlDbType.Char: 
                                return Create(SqlDbType.VarChar); 
                            default:
                                return null; 
                        }
                    case "STUFF":
                        // if the stuff call is an insertion  and is strictly additive
                        // (no deletion of characters) the return type is the same as 
                        // a concatenation
                        if (functionCall.Arguments.Count == 4) 
                        { 
                            SqlValue delLength = functionCall.Arguments[2] as SqlValue;
                            if (delLength != null && (int)delLength.Value == 0) 
                            {
                                return PredictTypeForBinary(SqlNodeType.Concat,
                                    functionCall.Arguments[0].SqlType, functionCall.Arguments[3].SqlType);
                            } 
                        }
                        return null; 
                    case "LOWER": 
                    case "UPPER":
                    case "RTRIM": 
                    case "LTRIM":
                    case "INSERT":
                    case "REPLACE":
                    case "LEFT": 
                    case "RIGHT":
                    case "REVERSE": 
                        return arg0; 
                    default:
                        return null; 
                }
            }

            internal override ProviderType ChangeTypeFamilyTo(ProviderType type, ProviderType toType) { 
                // if this is already the same family, do nothing
                if (type.IsSameTypeFamily(toType)) 
                    return type; 

                // otherwise as a default return toType 
                // but look for special cases we have to convert carefully
                if (type.IsApplicationType || toType.IsApplicationType)
                    return toType;
                SqlType sqlToType = (SqlType)toType; 
                SqlType sqlThisType = (SqlType)type;
 
                if (sqlToType.Category == SqlType.TypeCategory.Numeric && sqlThisType.Category == SqlType.TypeCategory.Char) { 
                    switch (sqlThisType.SqlDbType) {
                        case SqlDbType.NChar: 
                            return Create(SqlDbType.Int);
                        case SqlDbType.Char:
                            return Create(SqlDbType.SmallInt);
                        default: 
                            return toType;
                    } 
                } 
                else {
                    return toType; 
                }
            }

            [SuppressMessage("Microsoft.Performance", "CA1800:DoNotCastUnnecessarily", Justification = "[....]: Cast is dependent on node type and casts do not happen unecessarily in a single code path.")] 
            internal override ProviderType GetBestType(ProviderType typeA, ProviderType typeB) {
                // first determine the type precedence 
                SqlType bestType = (SqlType)(typeA.ComparePrecedenceTo(typeB) > 0 ? typeA : typeB); 

                // if one of the types is a not a server type, return 
                // that type
                if (typeA.IsApplicationType || typeA.IsRuntimeOnlyType) {
                    return typeA;
                } 
                if (typeB.IsApplicationType || typeB.IsRuntimeOnlyType) {
                    return typeB; 
                } 

                SqlType sqlTypeA = (SqlType)typeA; 
                SqlType sqlTypeB = (SqlType)typeB;
                if (sqlTypeA.HasPrecisionAndScale && sqlTypeB.HasPrecisionAndScale && bestType.SqlDbType == SqlDbType.Decimal) {
                    int p0 = sqlTypeA.Precision;
                    int s0 = sqlTypeA.Scale; 
                    int p1 = sqlTypeB.Precision;
                    int s1 = sqlTypeB.Scale; 
                    // precision and scale may be zero if this is an unsized type. 
                    if (p0 == 0 && s0 == 0 && p1 == 0 && s1 == 0) {
                        return Create(bestType.SqlDbType); 
                    } else if (p0 == 0 && s0 == 0) {
                        return Create(bestType.SqlDbType, p1, s1);
                    } else if (p1 == 0 && s1 == 0) {
                        return Create(bestType.SqlDbType, p0, s0); 
                    }
                    // determine best scale/precision 
                    int bestLeft = Math.Max(p0 - s0, p1 - s1); 
                    int bestRight = Math.Max(s0, s1);
                    int precision = Math.Min(bestLeft + bestRight, 38); 
                    return Create(bestType.SqlDbType, precision, /*scale*/bestRight);
                }
                else {
                    // determine the best size 
                    int? bestSize = null;
 
                    if (sqlTypeA.Size.HasValue && sqlTypeB.Size.HasValue) { 
                        bestSize = (sqlTypeB.Size > sqlTypeA.Size) ? sqlTypeB.Size : sqlTypeA.Size;
                    } 

                    if (sqlTypeB.Size.HasValue && sqlTypeB.Size.Value == LargeTypeSizeIndicator
                        || sqlTypeA.Size.HasValue && sqlTypeA.Size.Value == LargeTypeSizeIndicator) {
                        // the large type size trumps all 
                        bestSize = LargeTypeSizeIndicator;
                    } 
 
                    bestType = new SqlType(bestType.SqlDbType, bestSize);
                } 

                return bestType;
            }
 
            internal override ProviderType From(object o) {
                Type clrType = (o != null) ? o.GetType() : typeof(object); 
                if (clrType == typeof(string)) { 
                    string str = (string)o;
                    return From(clrType, str.Length); 
                }
                else if (clrType == typeof(bool)) {
                    return From(typeof(int));
                } 
                else if (clrType.IsArray) {
                    Array arr = (Array)o; 
                    return From(clrType, arr.Length); 
                }
                else if (clrType == typeof(decimal)) { 
                    decimal d = (decimal)o;
                    // The CLR stores the scale of a decimal value in bits
                    // 16 to 23 (i.e., mask 0x00FF0000) of the fourth int.
                    int scale = (Decimal.GetBits(d)[3] & 0x00FF0000) >> 16; 
                    return From(clrType, scale);
                } 
                else { 
                    return From(clrType);
                } 
            }

            internal override ProviderType From(Type type)
            { 
                return From(type, null);
            } 
 
            internal override ProviderType From(Type type, int? size) {
                return From(type, size); 
            }

            #endregion
        } 

        class Sql2005Provider : ProviderBase { 
            [SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity", Justification="These issues are related to our use of if-then and case statements for node types, which adds to the complexity count however when reviewed they are easy to navigate and understand.")] 
            internal override ProviderType From(Type type, int? size) {
                if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>)) 
                    type = type.GetGenericArguments()[0];
                TypeCode tc = System.Type.GetTypeCode(type);
                switch (tc) {
                    case TypeCode.Boolean: 
                        return Create(SqlDbType.Bit);
                    case TypeCode.Byte: 
                        return Create(SqlDbType.TinyInt); 
                    case TypeCode.SByte:
                    case TypeCode.Int16: 
                        return Create(SqlDbType.SmallInt);
                    case TypeCode.Int32:
                    case TypeCode.UInt16:
                        return Create(SqlDbType.Int); 
                    case TypeCode.Int64:
                    case TypeCode.UInt32: 
                        return Create(SqlDbType.BigInt); 
                    case TypeCode.UInt64:
                        return Create(SqlDbType.Decimal, 20, 0); 
                    case TypeCode.Decimal:
                        return Create(SqlDbType.Decimal, 29, size ?? 4);
                    case TypeCode.Double:
                        return Create(SqlDbType.Float); 
                    case TypeCode.Single:
                        return Create(SqlDbType.Real); 
                    case TypeCode.Char: 
                        return Create(SqlDbType.NChar, 1);
                    case TypeCode.String: 
                        return GetBestType(SqlDbType.NVarChar, size);
                    case TypeCode.DateTime:
                        return Create(SqlDbType.DateTime);
                    case TypeCode.Object: { 
                            if (type == typeof(Guid))
                                return Create(SqlDbType.UniqueIdentifier); 
                            if (type == typeof(byte[]) || type == typeof(Binary)) 
                                return GetBestType(SqlDbType.VarBinary, size);
                            if (type == typeof(char[])) 
                                return GetBestType(SqlDbType.NVarChar, size);
                            if (type == typeof(TimeSpan))
                                return Create(SqlDbType.BigInt);
                            if (type == typeof(System.Xml.Linq.XDocument) || 
                                type == typeof(System.Xml.Linq.XElement))
                                return theXml; 
                            // else UDT? 
                            return new SqlType(type);
                        } 
                    default:
                        throw Error.UnexpectedTypeCode(tc);
                }
            } 

            internal override ProviderType GetBestLargeType(ProviderType type) { 
                SqlType sqlType = (SqlType)type; 
                switch (sqlType.SqlDbType) {
                    case SqlDbType.NText: 
                    case SqlDbType.NChar:
                    case SqlDbType.NVarChar:
                        return Create(SqlDbType.NVarChar, LargeTypeSizeIndicator);
                    case SqlDbType.Text: 
                    case SqlDbType.Char:
                    case SqlDbType.VarChar: 
                        return Create(SqlDbType.VarChar, LargeTypeSizeIndicator); 
                    case SqlDbType.Image:
                    case SqlDbType.Binary: 
                    case SqlDbType.VarBinary:
                        return Create(SqlDbType.VarBinary, LargeTypeSizeIndicator);
                }
                return type; 
            }
 
            protected override bool SupportsMaxSize 
            {
                get { return true; } 
            }

        }
 
        class Sql2008Provider : Sql2005Provider
        { 
            [SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity", Justification = "These issues are related to our use of if-then and case statements for node types, which adds to the complexity count however when reviewed they are easy to navigate and understand.")] 
            internal override ProviderType From(Type type, int? size)
            { 
                if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>))
                    type = type.GetGenericArguments()[0];

                // Retain mappings for DateTime and TimeSpan; add one for the new DateTimeOffset type. 
                //
                if (System.Type.GetTypeCode(type) == TypeCode.Object && 
                    type == typeof(DateTimeOffset)) 
                {
                    return Create(SqlDbType.DateTimeOffset); 
                }

                return base.From(type, size);
            } 
        }
 
        class Sql2000Provider : ProviderBase { 
            [SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity", Justification="These issues are related to our use of if-then and case statements for node types, which adds to the complexity count however when reviewed they are easy to navigate and understand.")]
            internal override ProviderType From(Type type, int? size) { 
                if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>))
                    type = type.GetGenericArguments()[0];
                TypeCode tc = System.Type.GetTypeCode(type);
                switch (tc) { 
                    case TypeCode.Boolean:
                        return Create(SqlDbType.Bit); 
                    case TypeCode.Byte: 
                        return Create(SqlDbType.TinyInt);
                    case TypeCode.SByte: 
                    case TypeCode.Int16:
                        return Create(SqlDbType.SmallInt);
                    case TypeCode.Int32:
                    case TypeCode.UInt16: 
                        return Create(SqlDbType.Int);
                    case TypeCode.Int64: 
                    case TypeCode.UInt32: 
                        return Create(SqlDbType.BigInt);
                    case TypeCode.UInt64: 
                        return Create(SqlDbType.Decimal, 20, 0);
                    case TypeCode.Decimal:
                        return Create(SqlDbType.Decimal, 29, size ?? 4);
                    case TypeCode.Double: 
                        return Create(SqlDbType.Float);
                    case TypeCode.Single: 
                        return Create(SqlDbType.Real); 
                    case TypeCode.Char:
                        return Create(SqlDbType.NChar, 1); 
                    case TypeCode.String:
                        return GetBestType(SqlDbType.NVarChar, size);
                    case TypeCode.DateTime:
                        return Create(SqlDbType.DateTime); 
                    case TypeCode.Object: {
                            if (type == typeof(Guid)) 
                                return Create(SqlDbType.UniqueIdentifier); 
                            if (type == typeof(byte[]) || type == typeof(Binary))
                                return GetBestType(SqlDbType.VarBinary, size); 
                            if (type == typeof(char[]))
                                return GetBestType(SqlDbType.NVarChar, size);
                            if (type == typeof(TimeSpan))
                                return Create(SqlDbType.BigInt); 
                            if (type == typeof(System.Xml.Linq.XDocument) ||
                                type == typeof(System.Xml.Linq.XElement)) 
                                return theNText; 
                            // else UDT?
                            return new SqlType(type); 
                        }
                    default:
                        throw Error.UnexpectedTypeCode(tc);
                } 
            }
 
            internal override ProviderType GetBestLargeType(ProviderType type) { 
                SqlType sqlType = (SqlType)type;
                switch (sqlType.SqlDbType) { 
                    case SqlDbType.NChar:
                    case SqlDbType.NVarChar:
                        return Create(SqlDbType.NText);
                    case SqlDbType.Char: 
                    case SqlDbType.VarChar:
                        return Create(SqlDbType.Text); 
                    case SqlDbType.Binary: 
                    case SqlDbType.VarBinary:
                        return Create(SqlDbType.Image); 
                }
                return type;
            }
 
            protected override bool SupportsMaxSize
            { 
                get { return false; } 
            }
 
        }

        class SqlCEProvider : Sql2000Provider {
            internal override void InitializeParameter(ProviderType type, DbParameter parameter, object value) { 
                SqlType sqlType = (SqlType)type;
                PropertyInfo piSqlDbType = parameter.GetType().GetProperty("SqlDbType"); 
                piSqlDbType.SetValue(parameter, sqlType.SqlDbType, null); 
                if (sqlType.HasPrecisionAndScale) {
                    PropertyInfo piPrecision = parameter.GetType().GetProperty("Precision"); 
                    if (piPrecision != null) {
                        piPrecision.SetValue(parameter, Convert.ChangeType(sqlType.Precision, piPrecision.PropertyType, CultureInfo.InvariantCulture), null);
                    }
                    PropertyInfo piScale = parameter.GetType().GetProperty("Scale"); 
                    if (piScale != null) {
                        piScale.SetValue(parameter, Convert.ChangeType(sqlType.Scale, piScale.PropertyType, CultureInfo.InvariantCulture), null); 
                    } 
                }
                parameter.Value = GetParameterValue(sqlType, value); 
                // We want to allow the size of input parameters to be computed
                // implicitly (by setting the Value above). However, for fixed
                // length types and out/inout parameters, we want to set the size
                // explicitly (in the case of in/inout parameters only if the 
                // computed size is less than the fixed length, to avoid truncating
                // data). 
                bool isFixedSizeInputParameter = (parameter.Direction == ParameterDirection.Input) && sqlType.IsFixedSize; 
                if (isFixedSizeInputParameter || parameter.Direction != ParameterDirection.Input) {
                    if ((parameter.Size < sqlType.Size) || sqlType.IsLargeType) { 
                        parameter.Size = sqlType.Size ?? 0;
                    }
                }
            } 
        }
    } 
} 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
using System.Collections.Generic; 
using System.Data.Common;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Linq; 
using System.Reflection;
using System.Text; 
 
namespace System.Data.Linq.SqlClient {
 
    internal static class SqlTypeSystem {

        internal static TypeSystemProvider Create2000Provider() {
            return new Sql2000Provider(); 
        }
 
        internal static TypeSystemProvider Create2005Provider() { 
            return new Sql2005Provider();
        } 

        internal static TypeSystemProvider Create2008Provider() {
            return new Sql2008Provider();
        } 

        internal static TypeSystemProvider CreateCEProvider() { 
            return new SqlCEProvider(); 
        }
 
        // -1 is used to indicate a MAX size.  In ADO.NET, -1 is specified as the size
        // on a SqlParameter with SqlDbType = VarChar to indicate VarChar(MAX).
        internal const short LargeTypeSizeIndicator = -1;
 
        // class constructor will cause static initialization to be deferred
        [SuppressMessage("Microsoft.Performance", "CA1810:InitializeReferenceTypeStaticFieldsInline", Justification="Static constructors provide deferred execution, which is desired.")] 
        static SqlTypeSystem() { } 

        #region Factories 
        private static ProviderType Create(SqlDbType type, int size) {
            return new SqlType(type, size);
        }
 
        private static ProviderType Create(SqlDbType type, int precision, int scale) {
            if (type != SqlDbType.Decimal && precision == 0 && scale == 0) { 
                return Create(type); 
            }
            else if (type == SqlDbType.Decimal && precision == defaultDecimalPrecision && scale == defaultDecimalScale) { 
                return Create(type);
            }
            return new SqlType(type, precision, scale);
        } 

        [SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity", Justification="These issues are related to our use of if-then and case statements for node types, which adds to the complexity count however when reviewed they are easy to navigate and understand.")] 
        private static ProviderType Create(SqlDbType type) { 
            switch (type) {
                case SqlDbType.BigInt: return theBigInt; 
                case SqlDbType.Bit: return theBit;
                case SqlDbType.Char: return theChar;
                case SqlDbType.DateTime: return theDateTime;
                case SqlDbType.Date: return theDate; 
                case SqlDbType.Time: return theTime;
                case SqlDbType.DateTime2: return theDateTime2; 
                case SqlDbType.DateTimeOffset: return theDateTimeOffset; 
                case SqlDbType.Decimal: return theDefaultDecimal;
                case SqlDbType.Float: return theFloat; 
                case SqlDbType.Int: return theInt;
                case SqlDbType.Money: return theMoney;
                case SqlDbType.Real: return theReal;
                case SqlDbType.UniqueIdentifier: return theUniqueIdentifier; 
                case SqlDbType.SmallDateTime: return theSmallDateTime;
                case SqlDbType.SmallInt: return theSmallInt; 
                case SqlDbType.SmallMoney: return theSmallMoney; 
                case SqlDbType.Timestamp: return theTimestamp;
                case SqlDbType.TinyInt: return theTinyInt; 
                case SqlDbType.Xml: return theXml;
                case SqlDbType.Text: return theText;
                case SqlDbType.NText: return theNText;
                case SqlDbType.Image: return theImage; 
                default:
                    return new SqlType(type); 
            } 
        }
 
        [SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity", Justification="These issues are related to our use of if-then and case statements for node types, which adds to the complexity count however when reviewed they are easy to navigate and understand.")]
        private static Type GetClosestRuntimeType(SqlDbType sqlDbType) {
            switch (sqlDbType) {
                case SqlDbType.Int: 
                    return typeof(int);
                case SqlDbType.BigInt: 
                    return typeof(long); 
                case SqlDbType.Bit:
                    return typeof(bool); 
                case SqlDbType.Date:
                case SqlDbType.SmallDateTime:
                case SqlDbType.DateTime:
                case SqlDbType.DateTime2: 
                    return typeof(DateTime);
                case SqlDbType.DateTimeOffset: 
                    return typeof(DateTimeOffset); 
                case SqlDbType.Time:
                    return typeof(TimeSpan); 
                case SqlDbType.Float:
                    return typeof(double);
                case SqlDbType.Real:
                    return typeof(float); 
                case SqlDbType.Binary:
                case SqlDbType.Image: 
                case SqlDbType.Timestamp: 
                case SqlDbType.VarBinary:
                    return typeof(byte[]); 
                case SqlDbType.Decimal:
                case SqlDbType.Money:
                case SqlDbType.SmallMoney:
                    return typeof(decimal); 
                case SqlDbType.Char:
                case SqlDbType.NChar: 
                case SqlDbType.NText: 
                case SqlDbType.NVarChar:
                case SqlDbType.Xml: 
                case SqlDbType.VarChar:
                case SqlDbType.Text:
                    return typeof(string);
                case SqlDbType.UniqueIdentifier: 
                    return typeof(Guid);
                case SqlDbType.SmallInt: 
                    return typeof(short); 
                case SqlDbType.TinyInt:
                    return typeof(byte); 
                case SqlDbType.Udt:
                    // Udt type is not handled.
                    throw Error.UnexpectedTypeCode(SqlDbType.Udt);
                case SqlDbType.Variant: 
                default:
                    return typeof(object); 
            } 
        }
        #endregion 

        #region Singleton SqlTypes
        /*
         * For simple types with no size, precision or scale, reuse a static set of SqlDataTypes. 
         * This has two advantages: Fewer allocations of SqlType and faster comparison of
         * one type to another. 
         */ 
        static private readonly SqlType theBigInt = new SqlType(SqlDbType.BigInt);
        static private readonly SqlType theBit = new SqlType(SqlDbType.Bit); 
        static private readonly SqlType theChar = new SqlType(SqlDbType.Char);
        static private readonly SqlType theDateTime = new SqlType(SqlDbType.DateTime);
        static private readonly SqlType theDate = new SqlType(SqlDbType.Date);
        static private readonly SqlType theTime = new SqlType(SqlDbType.Time); 
        static private readonly SqlType theDateTime2 = new SqlType(SqlDbType.DateTime2);
        static private readonly SqlType theDateTimeOffset = new SqlType(SqlDbType.DateTimeOffset); 
        const int defaultDecimalPrecision = 29; 
        const int defaultDecimalScale = 4;
        static private readonly SqlType theDefaultDecimal = new SqlType(SqlDbType.Decimal, defaultDecimalPrecision, defaultDecimalScale); 
        static private readonly SqlType theFloat = new SqlType(SqlDbType.Float);
        static private readonly SqlType theInt = new SqlType(SqlDbType.Int);
        static private readonly SqlType theMoney = new SqlType(SqlDbType.Money, 19, 4);
        static private readonly SqlType theReal = new SqlType(SqlDbType.Real); 
        static private readonly SqlType theUniqueIdentifier = new SqlType(SqlDbType.UniqueIdentifier);
        static private readonly SqlType theSmallDateTime = new SqlType(SqlDbType.SmallDateTime); 
        static private readonly SqlType theSmallInt = new SqlType(SqlDbType.SmallInt); 
        static private readonly SqlType theSmallMoney = new SqlType(SqlDbType.SmallMoney, 10, 4);
        static private readonly SqlType theTimestamp = new SqlType(SqlDbType.Timestamp); 
        static private readonly SqlType theTinyInt = new SqlType(SqlDbType.TinyInt);
        static private readonly SqlType theXml = new SqlType(SqlDbType.Xml, LargeTypeSizeIndicator);
        static private readonly SqlType theText = new SqlType(SqlDbType.Text, LargeTypeSizeIndicator);
        static private readonly SqlType theNText = new SqlType(SqlDbType.NText, LargeTypeSizeIndicator); 
        static private readonly SqlType theImage = new SqlType(SqlDbType.Image, LargeTypeSizeIndicator);
        #endregion 
 
        public class SqlType : ProviderType {
            ///  
            /// Helper method for building ToString functions.
            /// 
            protected static string KeyValue(string key, T value) {
                if (value != null) { 
                    return key + "=" + value.ToString() + " ";
                } 
                return String.Empty; 
            }
 
            /// 
            /// Helper method for building ToString functions.
           /// 
            protected static string SingleValue(T value) { 
                if (value != null) {
                    return value.ToString() + " "; 
                } 
                return string.Empty;
            } 
            public override string ToString() {
                return SingleValue(GetClosestRuntimeType())
                        + SingleValue(ToQueryString())
                        + KeyValue("IsApplicationType", IsApplicationType) 
                        + KeyValue("IsUnicodeType", IsUnicodeType)
                        + KeyValue("IsRuntimeOnlyType", IsRuntimeOnlyType) 
                        + KeyValue("SupportsComparison", SupportsComparison) 
                        + KeyValue("SupportsLength", SupportsLength)
                        + KeyValue("IsLargeType", IsLargeType) 
                        + KeyValue("IsFixedSize", IsFixedSize)
                        + KeyValue("IsOrderable", IsOrderable)
                        + KeyValue("IsGroupable", IsGroupable)
                        + KeyValue("IsNumeric", IsNumeric) 
                        + KeyValue("IsChar", IsChar)
                        + KeyValue("IsString", IsString); 
            } 
            protected SqlDbType sqlDbType;
            protected int? size; 
            protected int precision;
            protected int scale;
            Type runtimeOnlyType;
            private int? applicationTypeIndex = null; 

            #region Constructors 
            internal SqlType(SqlDbType type) { 
                this.sqlDbType = type;
            } 

            internal SqlType(SqlDbType type, int? size) {
                this.sqlDbType = type;
                this.size = size; 
            }
 
            internal SqlType(SqlDbType type, int precision, int scale) { 
                System.Diagnostics.Debug.Assert(scale <= precision);
                this.sqlDbType = type; 
                this.precision = precision;
                this.scale = scale;
            }
 
            internal SqlType(Type type) {
                this.runtimeOnlyType = type; 
            } 

            internal SqlType(int applicationTypeIndex) { 
                this.applicationTypeIndex = applicationTypeIndex;
            }
            #endregion
 
            #region ProviderType Implementation
            internal override bool IsUnicodeType { 
                get { 
                    switch (this.SqlDbType) {
                        case SqlDbType.NChar: 
                        case SqlDbType.NText:
                        case SqlDbType.NVarChar:
                            return true;
                        default: 
                            return false;
                    } 
                } 
            }
            internal override ProviderType GetNonUnicodeEquivalent() { 
                if (IsUnicodeType) {
                    switch (this.SqlDbType) {
                        case SqlDbType.NChar:
                            return new SqlType(SqlDbType.Char, this.Size); 
                        case SqlDbType.NText:
                            return new SqlType(SqlDbType.Text); 
                        case SqlDbType.NVarChar: 
                            return new SqlType(SqlDbType.VarChar, this.Size);
                        default: 
                            // can't happen
                            return this;
                    }
                } 
                return this;
            } 
            internal override bool IsRuntimeOnlyType { 
                get { return runtimeOnlyType != null; }
            } 

            internal override bool IsApplicationType {
                get { return applicationTypeIndex != null; }
            } 

            internal override bool IsApplicationTypeOf(int index) { 
                if (IsApplicationType) { 
                    return applicationTypeIndex == index;
                } 
                return false;
            }

            ///  
            /// Determines if it is safe to suppress size specifications for
            /// the operand of a cast/convert.  For example, when casting to string, 
            /// all these types have length less than the default sized used by SqlServer, 
            /// so the length specification can be omitted without fear of truncation.
            ///  
            internal override bool CanSuppressSizeForConversionToString{
                get {
                    int defaultSize = 30;
 
                    if (this.IsLargeType) {
                        return false; 
                    } 
                    else if (!this.IsChar && !this.IsString && this.IsFixedSize && this.Size > 0 /*&& this.Size != LargeTypeSizeIndicator*/) { // commented out because LargeTypeSizeIndicator == -1
                        return (this.Size < defaultSize); 
                    }
                    else {

                        switch (this.SqlDbType) { 
                            case SqlDbType.BigInt: // -2^63 (-9,223,372,036,854,775,808) to 2^63-1 (9,223,372,036,854,775,807)
                            case SqlDbType.Bit: // 0 or 1 
                            case SqlDbType.Int: // -2^31 (-2,147,483,648) to 2^31-1 (2,147,483,647) 
                            case SqlDbType.SmallInt: // -2^15 (-32,768) to 2^15-1 (32,767)
                            case SqlDbType.TinyInt: // 0 to 255 
                            case SqlDbType.Money: // -922,337,203,685,477.5808 to 922,337,203,685,477.5807
                            case SqlDbType.SmallMoney: // -214,748.3648 to 214,748.3647
                            case SqlDbType.Float: // -1.79E+308 to -2.23E-308, 0 and 2.23E-308 to 1.79E+308
                            case SqlDbType.Real: // -3.40E+38 to -1.18E-38, 0 and 1.18E-38 to 3.40E+38 
                                return true;
                            default: 
                                return false; 
                        };
                    } 

                }
            }
 
            internal override int ComparePrecedenceTo(ProviderType type) {
                SqlType sqlProviderType = (SqlType)type; 
                // Highest precedence is given to server-known types. Converting to a client-only type is 
                // impossible when the conversion is present in a SQL query.
                int p0 = IsTypeKnownByProvider ? GetTypeCoercionPrecedence(this.SqlDbType) : Int32.MinValue; 
                int p1 = sqlProviderType.IsTypeKnownByProvider ? GetTypeCoercionPrecedence(sqlProviderType.SqlDbType) : Int32.MinValue;
                return p0.CompareTo(p1);
            }
 
            /// 
            /// Whether this is a legitimate server side type like NVARCHAR. 
            ///  
            private bool IsTypeKnownByProvider {
                get { return !IsApplicationType && !IsRuntimeOnlyType; } 
            }

            internal override bool IsSameTypeFamily(ProviderType type) {
                SqlType sqlType = (SqlType)type; 
                if (IsApplicationType) {
                    return false; 
                } 
                if (sqlType.IsApplicationType) {
                    return false; 
                }
                return this.Category == sqlType.Category;
            }
 
            internal override bool SupportsComparison {
                get { 
                    switch (this.sqlDbType) { 
                        case SqlDbType.NText:
                        case SqlDbType.Image: 
                        case SqlDbType.Xml:
                        case SqlDbType.Text:
                            return false;
                        default: 
                            return true;
                    } 
                } 
            }
 
            internal override bool SupportsLength {
                get {
                    switch (this.sqlDbType) {
                        case SqlDbType.NText: 
                        case SqlDbType.Image:
                        case SqlDbType.Xml: 
                        case SqlDbType.Text: 
                            return false;
                        default: 
                            return true;
                    }
                }
            } 

            ///  
            /// Returns true if the given values will be equal to eachother on the server for this type. 
            /// 
            internal override bool AreValuesEqual(object o1, object o2) { 
                if (o1 == null || o2 == null) {
                    return false;
                }
                switch (this.sqlDbType) { 
                    case SqlDbType.Char:
                    case SqlDbType.NChar: 
                    case SqlDbType.NVarChar: 
                    case SqlDbType.VarChar:
                    case SqlDbType.Text: 
                        string s1 = o1 as string;
                        if (s1 != null) {
                            string s2 = o2 as string;
                            if (s2 != null) { 
                                return s1.TrimEnd(' ').Equals(s2.TrimEnd(' '), StringComparison.Ordinal);
                            } 
                        } 
                        break;
                } 
                return o1.Equals(o2);
            }

            internal override bool IsLargeType { 
                get {
                    switch (this.sqlDbType) { 
                        case SqlDbType.NText: 
                        case SqlDbType.Image:
                        case SqlDbType.Xml: 
                        case SqlDbType.Text:
                            return true;
                        case SqlDbType.NVarChar:
                        case SqlDbType.VarChar: 
                        case SqlDbType.VarBinary:
                            return (this.size == LargeTypeSizeIndicator); 
                        default: 
                            return false;
                    } 
                }
            }

            internal override bool HasPrecisionAndScale { 
                get {
                    switch (SqlDbType) { 
                        case SqlDbType.Decimal: 
                        case SqlDbType.Float:
                        case SqlDbType.Real: 
                        case SqlDbType.Money:      // precision and scale are fixed at 19,4
                        case SqlDbType.SmallMoney: // precision and scale are fixed at 10,4
                        case SqlDbType.DateTime2:
                        case SqlDbType.DateTimeOffset: 
                        case SqlDbType.Time:
                            return true; 
                        default: 
                            return false;
                    } 
                }
            }

            internal override Type GetClosestRuntimeType() { 
                if (runtimeOnlyType != null) {
                    return runtimeOnlyType; 
                } 
                else {
                    return SqlTypeSystem.GetClosestRuntimeType(this.sqlDbType); 
                }
            }

            internal override string ToQueryString() { 
                return ToQueryString(QueryFormatOptions.None);
            } 
 
            [SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity", Justification="These issues are related to our use of if-then and case statements for node types, which adds to the complexity count however when reviewed they are easy to navigate and understand.")]
            internal override string ToQueryString(QueryFormatOptions formatFlags) { 
                if (runtimeOnlyType != null) {
                    return runtimeOnlyType.ToString();
                }
                StringBuilder sb = new StringBuilder(); 

                switch (sqlDbType) { 
                    case SqlDbType.BigInt: 
                    case SqlDbType.Bit:
                    case SqlDbType.Date: 
                    case SqlDbType.Time:
                    case SqlDbType.DateTime:
                    case SqlDbType.DateTime2:
                    case SqlDbType.DateTimeOffset: 
                    case SqlDbType.Int:
                    case SqlDbType.Money: 
                    case SqlDbType.SmallDateTime: 
                    case SqlDbType.SmallInt:
                    case SqlDbType.SmallMoney: 
                    case SqlDbType.Timestamp:
                    case SqlDbType.TinyInt:
                    case SqlDbType.UniqueIdentifier:
                    case SqlDbType.Xml: 
                    case SqlDbType.Image:
                    case SqlDbType.NText: 
                    case SqlDbType.Text: 
                    case SqlDbType.Udt:
                        sb.Append(sqlDbType.ToString()); 
                        break;
                    case SqlDbType.Variant:
                        sb.Append("sql_variant");
                        break; 
                    case SqlDbType.Binary:
                    case SqlDbType.Char: 
                    case SqlDbType.NChar: 
                        sb.Append(sqlDbType);
                        if ((formatFlags & QueryFormatOptions.SuppressSize) == 0) { 
                            sb.Append("(");
                            sb.Append(size);
                            sb.Append(")");
                        } 
                        break;
                    case SqlDbType.NVarChar: 
                    case SqlDbType.VarBinary: 
                    case SqlDbType.VarChar:
                        sb.Append(sqlDbType); 
                        if ((size.HasValue && size != 0) && (formatFlags & QueryFormatOptions.SuppressSize) == 0) {
                            sb.Append("(");
                            if (size == LargeTypeSizeIndicator) {
                                sb.Append("MAX"); 
                            }
                            else { 
                                sb.Append(size); 
                            }
                            sb.Append(")"); 
                        }
                        break;
                    case SqlDbType.Decimal:
                    case SqlDbType.Float: 
                    case SqlDbType.Real:
                        sb.Append(sqlDbType); 
                        if (precision != 0) { 
                            sb.Append("(");
                            sb.Append(precision); 
                            if (scale != 0) {
                                sb.Append(",");
                                sb.Append(scale);
                            } 
                            sb.Append(")");
                        } 
                        break; 
                }
                return sb.ToString(); 
            }

            internal override bool HasSizeOrIsLarge {
                get { 
                    return this.size.HasValue || this.IsLargeType;
                } 
            } 

            internal override int? Size { 
                get {
                    return this.size;
                }
            } 

            internal int Precision { 
                get { return this.precision; } 
            }
 
            internal int Scale {
                get { return this.scale; }
            }
 
            internal override bool IsFixedSize {
                get { 
                    switch (this.sqlDbType) { 
                        case SqlDbType.NText:
                        case SqlDbType.Text: 
                        case SqlDbType.NVarChar:
                        case SqlDbType.VarChar:
                        case SqlDbType.Image:
                        case SqlDbType.VarBinary: 
                        case SqlDbType.Xml:
                            return false; 
                        default: 
                            return true;
                    } 
                }
            }

            internal SqlDbType SqlDbType { 
                get { return sqlDbType; }
            } 
 
            internal override bool IsOrderable {
                get { 
                    if (this.IsRuntimeOnlyType) return false; // must be a SQL type

                    switch (this.sqlDbType) {
                        case SqlDbType.Image: 
                        case SqlDbType.Text:
                        case SqlDbType.NText: 
                        case SqlDbType.Xml: 
                            return false;
                        default: 
                            return true;
                    }
                }
            } 

            internal override bool IsGroupable { 
                get { 
                    if (this.IsRuntimeOnlyType) return false; // must be a SQL type
 
                    switch (this.sqlDbType) {
                        case SqlDbType.Image:
                        case SqlDbType.Text:
                        case SqlDbType.NText: 
                        case SqlDbType.Xml:
                            return false; 
                        default: 
                            return true;
                    } 
                }
            }

            internal override bool CanBeColumn { 
                get { return !this.IsApplicationType && !this.IsRuntimeOnlyType; }
            } 
 
            internal override bool CanBeParameter {
                get { return !this.IsApplicationType && !this.IsRuntimeOnlyType; } 
            }

            internal override bool IsNumeric {
                get { 
                    if (IsApplicationType || IsRuntimeOnlyType) {
                        return false; 
                    } 
                    switch (SqlDbType) {
                        case SqlDbType.Bit: 
                        case SqlDbType.TinyInt:
                        case SqlDbType.SmallInt:
                        case SqlDbType.Int:
                        case SqlDbType.BigInt: 
                        case SqlDbType.Decimal:
                        case SqlDbType.Float: 
                        case SqlDbType.Real: 
                        case SqlDbType.Money:
                        case SqlDbType.SmallMoney: 
                            return true;
                        default:
                            return false;
                    }; 
                }
            } 
 
            internal override bool IsChar {
                get { 
                    if (IsApplicationType || IsRuntimeOnlyType)
                        return false;
                    switch (SqlDbType) {
                        case SqlDbType.Char: 
                        case SqlDbType.NChar:
                        case SqlDbType.NVarChar: 
                        case SqlDbType.VarChar: 
                            return Size == 1;
                        default: 
                            return false;
                    }
                }
            } 

            internal override bool IsString { 
                get { 
                    if (IsApplicationType || IsRuntimeOnlyType)
                        return false; 
                    switch (SqlDbType) {
                        case SqlDbType.Char:
                        case SqlDbType.NChar:
                        case SqlDbType.NVarChar: 
                        case SqlDbType.VarChar:
                            // -1 is used for large types to represent MAX 
                            return Size == 0 || Size > 1 || Size == LargeTypeSizeIndicator; 
                        case SqlDbType.Text:
                        case SqlDbType.NText: 
                            return true;
                        default:
                            return false;
                    } 
                }
            } 
            #endregion 

            #region Equals + GetHashCode 

            public override bool Equals(object obj) {
                if ((object)this == obj)
                    return true; 

                SqlType that = obj as SqlType; 
                if (that == null) 
                    return false;
 
                return
                    this.runtimeOnlyType == that.runtimeOnlyType &&
                    this.applicationTypeIndex == that.applicationTypeIndex &&
                    this.sqlDbType == that.sqlDbType && 
                    this.Size == that.Size &&
                    this.precision == that.precision && 
                    this.scale == that.scale; 
            }
 
            public override int GetHashCode() {
                // Make up a hash function that will atleast not treat precision and scale
                // as interchangeable. This may need a smarter replacement if certain hash
                // buckets get too full. 
                int hash = 0;
                if (this.runtimeOnlyType != null) { 
                    hash = this.runtimeOnlyType.GetHashCode(); 
                }
                else if (this.applicationTypeIndex != null) { 
                    hash = this.applicationTypeIndex.Value;
                }
                return hash ^ this.sqlDbType.GetHashCode() ^ (this.size ?? 0) ^ (this.precision) ^ (this.scale << 8);
            } 
            #endregion
 
            #region Type Classification 
            [SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity", Justification="These issues are related to our use of if-then and case statements for node types, which adds to the complexity count however when reviewed they are easy to navigate and understand.")]
            private static int GetTypeCoercionPrecedence(SqlDbType type) { 
                switch (type) {
                    case SqlDbType.Binary: return 0;
                    case SqlDbType.VarBinary: return 1;
                    case SqlDbType.VarChar: return 2; 
                    case SqlDbType.Char: return 3;
                    case SqlDbType.NChar: return 4; 
                    case SqlDbType.NVarChar: return 5; 
                    case SqlDbType.UniqueIdentifier: return 6;
                    case SqlDbType.Timestamp: return 7; 
                    case SqlDbType.Image: return 8;
                    case SqlDbType.Text: return 9;
                    case SqlDbType.NText: return 10;
                    case SqlDbType.Bit: return 11; 
                    case SqlDbType.TinyInt: return 12;
                    case SqlDbType.SmallInt: return 13; 
                    case SqlDbType.Int: return 14; 
                    case SqlDbType.BigInt: return 15;
                    case SqlDbType.SmallMoney: return 16; 
                    case SqlDbType.Money: return 17;
                    case SqlDbType.Decimal: return 18;
                    case SqlDbType.Real: return 19;
                    case SqlDbType.Float: return 20; 
                    case SqlDbType.Date: return 21;
                    case SqlDbType.Time: return 22; 
                    case SqlDbType.SmallDateTime: return 23; 
                    case SqlDbType.DateTime: return 24;
                    case SqlDbType.DateTime2: return 25; 
                    case SqlDbType.DateTimeOffset: return 26;
                    case SqlDbType.Xml: return 27;
                    case SqlDbType.Variant: return 28;
                    case SqlDbType.Udt: return 29; 
                    default:
                        throw Error.UnexpectedTypeCode(type); 
                } 
            }
 
            internal enum TypeCategory {
                Numeric,
                Char,
                Text, 
                Binary,
                Image, 
                Xml, 
                DateTime,
                UniqueIdentifier, 
                Variant,
                Udt
            }
 
            [SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity", Justification="These issues are related to our use of if-then and case statements for node types, which adds to the complexity count however when reviewed they are easy to navigate and understand.")]
            internal TypeCategory Category { 
                get { 
                    switch (this.SqlDbType) {
                        case SqlDbType.Bit: 
                        case SqlDbType.TinyInt:
                        case SqlDbType.SmallInt:
                        case SqlDbType.Int:
                        case SqlDbType.BigInt: 
                        case SqlDbType.Decimal:
                        case SqlDbType.Float: 
                        case SqlDbType.Real: 
                        case SqlDbType.Money:
                        case SqlDbType.SmallMoney: 
                            return TypeCategory.Numeric;
                        case SqlDbType.Char:
                        case SqlDbType.NChar:
                        case SqlDbType.VarChar: 
                        case SqlDbType.NVarChar:
                            return TypeCategory.Char; 
                        case SqlDbType.Text: 
                        case SqlDbType.NText:
                            return TypeCategory.Text; 
                        case SqlDbType.Binary:
                        case SqlDbType.VarBinary:
                        case SqlDbType.Timestamp:
                            return TypeCategory.Binary; 
                        case SqlDbType.Image:
                            return TypeCategory.Image; 
                        case SqlDbType.Xml: 
                            return TypeCategory.Xml;
                        case SqlDbType.Date: 
                        case SqlDbType.Time:
                        case SqlDbType.DateTime:
                        case SqlDbType.DateTime2:
                        case SqlDbType.DateTimeOffset: 
                        case SqlDbType.SmallDateTime:
                            return TypeCategory.DateTime; 
                        case SqlDbType.UniqueIdentifier: 
                            return TypeCategory.UniqueIdentifier;
                        case SqlDbType.Variant: 
                            return TypeCategory.Variant;
                        case SqlDbType.Udt:
                            return TypeCategory.Udt;
                        default: 
                            throw Error.UnexpectedTypeCode(this);
                    } 
                } 
            }
            #endregion 
        }

        abstract class ProviderBase : TypeSystemProvider {
            protected Dictionary applicationTypes = new Dictionary(); 

            #region Factories 
            internal override ProviderType GetApplicationType(int index) { 
                if (index < 0)
                    throw Error.ArgumentOutOfRange("index"); 
                SqlType result = null;
                if (!applicationTypes.TryGetValue(index, out result)) {
                    result = new SqlType(index);
                    applicationTypes.Add(index, result); 
                }
                return result; 
            } 

            [SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity", Justification="These issues are related to our use of if-then and case statements for node types, which adds to the complexity count however when reviewed they are easy to navigate and understand.")] 
            internal override ProviderType Parse(string stype) {
                // parse type...
                string typeName = null;
                string param1 = null; 
                string param2 = null;
                int paren = stype.IndexOf('('); 
                int space = stype.IndexOf(' '); 
                int end = (paren != -1 && space != -1) ? Math.Min(space, paren)
                        : (paren != -1) ? paren 
                        : (space != -1) ? space
                        : -1;
                if (end == -1) {
                    typeName = stype; 
                    end = stype.Length;
                } 
                else { 
                    typeName = stype.Substring(0, end);
                } 
                int start = end;
                if (start < stype.Length && stype[start] == '(') {
                    start++;
                    end = stype.IndexOf(',', start); 
                    if (end > 0) {
                        param1 = stype.Substring(start, end - start); 
                        start = end + 1; 
                        end = stype.IndexOf(')', start);
                        param2 = stype.Substring(start, end - start); 
                    }
                    else {
                        end = stype.IndexOf(')', start);
                        param1 = stype.Substring(start, end - start); 
                    }
                    start = end++; 
                } 

                #region Special case type mappings 
                if (String.Compare(typeName, "rowversion", StringComparison.OrdinalIgnoreCase) == 0) {
                    typeName = "Timestamp";
                }
 
                if (String.Compare(typeName, "numeric", StringComparison.OrdinalIgnoreCase) == 0) {
                    typeName = "Decimal"; 
                } 

                if (String.Compare(typeName, "sql_variant", StringComparison.OrdinalIgnoreCase) == 0) { 
                    typeName = "Variant";
                }

                if (String.Compare(typeName, "filestream", StringComparison.OrdinalIgnoreCase) == 0) { 
                    typeName = "Binary";
                } 
                #endregion 

                // since we're going to parse the enum value below, we verify 
                // here that it is defined.  For example, types like table, cursor
                // are not valid.
                if (!Enum.GetNames(typeof(SqlDbType)).Select(n => n.ToUpperInvariant()).Contains(typeName.ToUpperInvariant()))
                { 
                    throw Error.InvalidProviderType(typeName);
                } 
 
                int p1 = 0;
                int p2 = 0; 
                SqlDbType dbType = (SqlDbType)Enum.Parse(typeof(SqlDbType), typeName, true);
                if (param1 != null) {
                    if (String.Compare(param1.Trim(), "max", StringComparison.OrdinalIgnoreCase) == 0) {
                        p1 = LargeTypeSizeIndicator; 
                    }
                    else { 
                        p1 = Int32.Parse(param1, Globalization.CultureInfo.InvariantCulture); 
                        if (p1 == int.MaxValue)
                            p1 = LargeTypeSizeIndicator; 
                    }
                }

                if (param2 != null) { 
                    if (String.Compare(param2.Trim(), "max", StringComparison.OrdinalIgnoreCase) == 0) {
                        p2 = LargeTypeSizeIndicator; 
                    } 
                    else {
                        p2 = Int32.Parse(param2, Globalization.CultureInfo.InvariantCulture); 
                        if (p2 == int.MaxValue)
                            p2 = LargeTypeSizeIndicator;

                    } 
                }
 
                switch (dbType) { 
                    case SqlDbType.Binary:
                    case SqlDbType.Char: 
                    case SqlDbType.NChar:
                    case SqlDbType.NVarChar:
                    case SqlDbType.VarBinary:
                    case SqlDbType.VarChar: 
                        return Create(dbType, p1);
                    case SqlDbType.Decimal: 
                    case SqlDbType.Real: 
                    case SqlDbType.Float:
                        return Create(dbType, p1, p2); 
                    case SqlDbType.Timestamp:
                    default:
                        return Create(dbType);
                } 
            }
            #endregion 
 
            #region Implementation
            // Returns true if the type provider supports MAX types (e.g NVarChar(MAX)) 
            protected abstract bool SupportsMaxSize { get; }

            /// 
            /// For types with size, determine the closest matching type for the information 
            /// specified, promoting to the appropriate large type as needed.  If no size is
            /// specified, we use the max. 
            ///  
            protected ProviderType GetBestType(SqlDbType targetType, int? size)
            { 
                // determine max size for the specified db type
                int maxSize = 0;
                switch (targetType)
                { 
                    case SqlDbType.NChar:
                    case SqlDbType.NVarChar: 
                        maxSize = 4000; 
                        break;
                    case SqlDbType.Char: 
                    case SqlDbType.VarChar:
                    case SqlDbType.Binary:
                    case SqlDbType.VarBinary:
                        maxSize = 8000; 
                        break;
                }; 
 
                if (size.HasValue)
                { 
                    if (size.Value <= maxSize)
                    {
                        return Create(targetType, size.Value);
                    } 
                    else
                    { 
                        return GetBestLargeType(Create(targetType)); 
                    }
                } 

                // if the type provider supports MAX types, return one, otherwise use
                // the maximum size determined above
                return Create(targetType, SupportsMaxSize ? SqlTypeSystem.LargeTypeSizeIndicator : maxSize); 
            }
 
            internal override void InitializeParameter(ProviderType type, DbParameter parameter, object value) { 
                SqlType sqlType = (SqlType)type;
                if (sqlType.IsRuntimeOnlyType) { 
                    throw Error.BadParameterType(sqlType.GetClosestRuntimeType());
                }
                System.Data.SqlClient.SqlParameter sParameter = parameter as System.Data.SqlClient.SqlParameter;
                if (sParameter != null) { 
                    sParameter.SqlDbType = sqlType.SqlDbType;
                    if (sqlType.HasPrecisionAndScale) { 
                        sParameter.Precision = (byte)sqlType.Precision; 
                        sParameter.Scale = (byte)sqlType.Scale;
                    } 
                }
                else {
                    PropertyInfo piSqlDbType = parameter.GetType().GetProperty("SqlDbType");
                    if (piSqlDbType != null) { 
                        piSqlDbType.SetValue(parameter, sqlType.SqlDbType, null);
                    } 
                    if (sqlType.HasPrecisionAndScale) { 
                        PropertyInfo piPrecision = parameter.GetType().GetProperty("Precision");
                        if (piPrecision != null) { 
                            piPrecision.SetValue(parameter, Convert.ChangeType(sqlType.Precision, piPrecision.PropertyType, CultureInfo.InvariantCulture), null);
                        }
                        PropertyInfo piScale = parameter.GetType().GetProperty("Scale");
                        if (piScale != null) { 
                            piScale.SetValue(parameter, Convert.ChangeType(sqlType.Scale, piScale.PropertyType, CultureInfo.InvariantCulture), null);
                        } 
                    } 
                }
                parameter.Value = GetParameterValue(sqlType, value); 
                // We want to allow the size of input parameters to be computed
                // implicitly (by setting the Value above). However, for fixed
                // length types and out/inout parameters, we want to set the size
                // explicitly (in the case of in/inout parameters only if the 
                // computed size is less than the fixed length, to avoid truncating
                // data). 
                bool isFixedSizeInputParameter = (parameter.Direction == ParameterDirection.Input) && sqlType.IsFixedSize; 
                if (isFixedSizeInputParameter || parameter.Direction != ParameterDirection.Input) {
                    if ((sqlType.Size.HasValue && parameter.Size < sqlType.Size) || sqlType.IsLargeType) { 
                        parameter.Size = sqlType.Size.Value;
                    }
                }
            } 

            [SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic", Justification="Unknown reason.")] 
            protected object GetParameterValue(SqlType type, object value) { 
                if (value == null) {
                    return DBNull.Value; 
                }
                else {
                    Type vType = value.GetType();
                    Type pType = type.GetClosestRuntimeType(); 
                    if (pType == vType) {
                        return value; 
                    } 
                    else {
                        return DBConvert.ChangeType(value, pType); 
                    }
                }
            }
 
            [SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity", Justification="These issues are related to our use of if-then and case statements for node types, which adds to the complexity count however when reviewed they are easy to navigate and understand.")]
            internal override ProviderType PredictTypeForUnary(SqlNodeType unaryOp, ProviderType operandType) { 
                switch (unaryOp) { 
                    case SqlNodeType.Not:
                    case SqlNodeType.Not2V: 
                    case SqlNodeType.IsNull:
                    case SqlNodeType.IsNotNull:
                        return theBit;
                    case SqlNodeType.Negate: 
                    case SqlNodeType.BitNot:
                    case SqlNodeType.ValueOf: 
                    case SqlNodeType.Treat: 
                    case SqlNodeType.OuterJoinedValue:
                        return operandType; 
                    case SqlNodeType.Count:
                        return this.From(typeof(int));
                    case SqlNodeType.LongCount:
                        return this.From(typeof(long)); 
                    case SqlNodeType.Min:
                    case SqlNodeType.Max: 
                        return operandType; 
                    case SqlNodeType.Sum:
                    case SqlNodeType.Avg: 
                    case SqlNodeType.Stddev:
                    case SqlNodeType.Covar:
                        return this.MostPreciseTypeInFamily(operandType);
                    case SqlNodeType.ClrLength: 
                        if (operandType.IsLargeType) {
                            return this.From(typeof(long)); // SqlDbType.BigInt 
                        } 
                        else {
                            return this.From(typeof(int)); // SqlDbType.Int 
                        }
                    default:
                        throw Error.UnexpectedNode(unaryOp);
                } 
            }
 
            [SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity", Justification="These issues are related to our use of if-then and case statements for node types, which adds to the complexity count however when reviewed they are easy to navigate and understand.")] 
            internal override ProviderType PredictTypeForBinary(SqlNodeType binaryOp, ProviderType leftType, ProviderType rightType) {
                SqlType highest; 

                if (leftType.IsSameTypeFamily(this.From(typeof(string))) && rightType.IsSameTypeFamily(this.From(typeof(string)))) {
                    highest = (SqlType)this.GetBestType(leftType, rightType);
                } else { 
                    int coercionPrecedence = leftType.ComparePrecedenceTo(rightType);
                    highest = (SqlType)(coercionPrecedence > 0 ? leftType : rightType); 
                } 

                switch (binaryOp) { 
                    case SqlNodeType.Add:
                    case SqlNodeType.Sub:
                    case SqlNodeType.Mul:
                    case SqlNodeType.Div: 
                    case SqlNodeType.BitAnd:
                    case SqlNodeType.BitOr: 
                    case SqlNodeType.BitXor: 
                    case SqlNodeType.Mod:
                    case SqlNodeType.Coalesce: 
                        return highest;
                    case SqlNodeType.Concat:
                        // When concatenating two types with size, the result type after
                        // concatenation must have a size equal to the sum of the two sizes. 
                        if (highest.HasSizeOrIsLarge)
                        { 
                            // get the best type, specifying null for size so we get 
                            // the maximum allowable size
                            ProviderType concatType = this.GetBestType(highest.SqlDbType, null); 

                            if ((!leftType.IsLargeType && leftType.Size.HasValue) &&
                                (!rightType.IsLargeType && rightType.Size.HasValue))
                            { 
                                // If both types are not large types and have size, and the
                                // size is less than the default size, return the shortened type. 
                                int concatSize = leftType.Size.Value + rightType.Size.Value; 
                                if ((concatSize < concatType.Size) || concatType.IsLargeType)
                                { 
                                    return GetBestType(highest.SqlDbType, concatSize);
                                }
                            }
 
                            return concatType;
                        } 
                        return highest; 
                    case SqlNodeType.And:
                    case SqlNodeType.Or: 
                    case SqlNodeType.LT:
                    case SqlNodeType.LE:
                    case SqlNodeType.GT:
                    case SqlNodeType.GE: 
                    case SqlNodeType.EQ:
                    case SqlNodeType.NE: 
                    case SqlNodeType.EQ2V: 
                    case SqlNodeType.NE2V:
                        return theInt; 
                    default:
                        throw Error.UnexpectedNode(binaryOp);
                }
            } 

            internal override ProviderType MostPreciseTypeInFamily(ProviderType type) { 
                SqlType sqlType = (SqlType)type; 
                switch (sqlType.SqlDbType) {
                    case SqlDbType.TinyInt: 
                    case SqlDbType.SmallInt:
                    case SqlDbType.Int:
                        return From(typeof(int));
                    case SqlDbType.SmallMoney: 
                    case SqlDbType.Money:
                        return Create(SqlDbType.Money); 
                    case SqlDbType.Real: 
                    case SqlDbType.Float:
                        return From(typeof(double)); 
                    case SqlDbType.Date:
                    case SqlDbType.Time:
                    case SqlDbType.SmallDateTime:
                    case SqlDbType.DateTime: 
                    case SqlDbType.DateTime2:
                        return From(typeof(DateTime)); 
                    case SqlDbType.DateTimeOffset: 
                        return From(typeof(DateTimeOffset));
                    default: 
                        return type;
                }
            }
 
            [SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic", Justification="Unknown reason.")]
            private ProviderType[] GetArgumentTypes(SqlFunctionCall fc) { 
                ProviderType[] array = new ProviderType[fc.Arguments.Count]; 
                for (int i = 0, n = array.Length; i < n; i++) {
                    array[i] = fc.Arguments[i].SqlType; 
                }
                return array;
            }
 
            /// 
            /// Gives the return type of a SQL function which has as first argument something of this SqlType. 
            /// For some functions (e.g. trigonometric functions) the return type is independent of the argument type; 
            /// in those cases this method returns null and the type was already set correctly in the MethodCallConverter.
            ///  
            /// The SqlFunctionCall node.
            /// null: Don't change type, otherwise: Set return type to this ProviderType
            [SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity", Justification="These issues are related to our use of if-then and case statements for node types, which adds to the complexity count however when reviewed they are easy to navigate and understand.")]
            internal override ProviderType ReturnTypeOfFunction(SqlFunctionCall functionCall) { 
                var argumentTypes = this.GetArgumentTypes(functionCall);
 
                SqlType arg0 = (SqlType)argumentTypes[0]; 
                SqlType arg1 = argumentTypes.Length > 1 ? (SqlType)argumentTypes[1] : (SqlType)null;
 
                switch (functionCall.Name) {
                    case "LEN":
                    case "DATALENGTH":
                        switch (arg0.SqlDbType) { 
                            case SqlDbType.NVarChar:
                            case SqlDbType.VarChar: 
                            case SqlDbType.VarBinary: 
                                if (arg0.IsLargeType) {
                                    return Create(SqlDbType.BigInt); 
                                }
                                else {
                                    return Create(SqlDbType.Int);
                                } 
                            default:
                                return Create(SqlDbType.Int); 
                        } 
                    case "ABS":
                    case "SIGN": 
                    case "ROUND":
                    case "CEILING":
                    case "FLOOR":
                    case "POWER": 
                        switch (arg0.SqlDbType) {
                            case SqlDbType.TinyInt: 
                            case SqlDbType.Int: 
                            case SqlDbType.SmallInt:
                                return Create(SqlDbType.Int); 
                            case SqlDbType.Float:
                            case SqlDbType.Real:
                                return Create(SqlDbType.Float);
                            default: 
                                return arg0;
                        } 
                    case "PATINDEX": 
                    case "CHARINDEX":
                        if (arg1.IsLargeType) 
                            return Create(SqlDbType.BigInt);
                        return Create(SqlDbType.Int);
                    case "SUBSTRING":
                        if (functionCall.Arguments[2].NodeType == SqlNodeType.Value) { 
                            SqlValue val = (SqlValue)functionCall.Arguments[2];
 
                            if (val.Value is int) { 
                                switch (arg0.SqlDbType) {
                                    case SqlDbType.NVarChar: 
                                    case SqlDbType.NChar:
                                    case SqlDbType.VarChar:
                                    case SqlDbType.Char:
                                        return Create(arg0.SqlDbType, (int)val.Value); 
                                    default:
                                        return null; 
                                } 
                            }
                        } 
                        switch (arg0.SqlDbType) {
                            case SqlDbType.NVarChar:
                            case SqlDbType.NChar:
                                return Create(SqlDbType.NVarChar); 
                            case SqlDbType.VarChar:
                            case SqlDbType.Char: 
                                return Create(SqlDbType.VarChar); 
                            default:
                                return null; 
                        }
                    case "STUFF":
                        // if the stuff call is an insertion  and is strictly additive
                        // (no deletion of characters) the return type is the same as 
                        // a concatenation
                        if (functionCall.Arguments.Count == 4) 
                        { 
                            SqlValue delLength = functionCall.Arguments[2] as SqlValue;
                            if (delLength != null && (int)delLength.Value == 0) 
                            {
                                return PredictTypeForBinary(SqlNodeType.Concat,
                                    functionCall.Arguments[0].SqlType, functionCall.Arguments[3].SqlType);
                            } 
                        }
                        return null; 
                    case "LOWER": 
                    case "UPPER":
                    case "RTRIM": 
                    case "LTRIM":
                    case "INSERT":
                    case "REPLACE":
                    case "LEFT": 
                    case "RIGHT":
                    case "REVERSE": 
                        return arg0; 
                    default:
                        return null; 
                }
            }

            internal override ProviderType ChangeTypeFamilyTo(ProviderType type, ProviderType toType) { 
                // if this is already the same family, do nothing
                if (type.IsSameTypeFamily(toType)) 
                    return type; 

                // otherwise as a default return toType 
                // but look for special cases we have to convert carefully
                if (type.IsApplicationType || toType.IsApplicationType)
                    return toType;
                SqlType sqlToType = (SqlType)toType; 
                SqlType sqlThisType = (SqlType)type;
 
                if (sqlToType.Category == SqlType.TypeCategory.Numeric && sqlThisType.Category == SqlType.TypeCategory.Char) { 
                    switch (sqlThisType.SqlDbType) {
                        case SqlDbType.NChar: 
                            return Create(SqlDbType.Int);
                        case SqlDbType.Char:
                            return Create(SqlDbType.SmallInt);
                        default: 
                            return toType;
                    } 
                } 
                else {
                    return toType; 
                }
            }

            [SuppressMessage("Microsoft.Performance", "CA1800:DoNotCastUnnecessarily", Justification = "[....]: Cast is dependent on node type and casts do not happen unecessarily in a single code path.")] 
            internal override ProviderType GetBestType(ProviderType typeA, ProviderType typeB) {
                // first determine the type precedence 
                SqlType bestType = (SqlType)(typeA.ComparePrecedenceTo(typeB) > 0 ? typeA : typeB); 

                // if one of the types is a not a server type, return 
                // that type
                if (typeA.IsApplicationType || typeA.IsRuntimeOnlyType) {
                    return typeA;
                } 
                if (typeB.IsApplicationType || typeB.IsRuntimeOnlyType) {
                    return typeB; 
                } 

                SqlType sqlTypeA = (SqlType)typeA; 
                SqlType sqlTypeB = (SqlType)typeB;
                if (sqlTypeA.HasPrecisionAndScale && sqlTypeB.HasPrecisionAndScale && bestType.SqlDbType == SqlDbType.Decimal) {
                    int p0 = sqlTypeA.Precision;
                    int s0 = sqlTypeA.Scale; 
                    int p1 = sqlTypeB.Precision;
                    int s1 = sqlTypeB.Scale; 
                    // precision and scale may be zero if this is an unsized type. 
                    if (p0 == 0 && s0 == 0 && p1 == 0 && s1 == 0) {
                        return Create(bestType.SqlDbType); 
                    } else if (p0 == 0 && s0 == 0) {
                        return Create(bestType.SqlDbType, p1, s1);
                    } else if (p1 == 0 && s1 == 0) {
                        return Create(bestType.SqlDbType, p0, s0); 
                    }
                    // determine best scale/precision 
                    int bestLeft = Math.Max(p0 - s0, p1 - s1); 
                    int bestRight = Math.Max(s0, s1);
                    int precision = Math.Min(bestLeft + bestRight, 38); 
                    return Create(bestType.SqlDbType, precision, /*scale*/bestRight);
                }
                else {
                    // determine the best size 
                    int? bestSize = null;
 
                    if (sqlTypeA.Size.HasValue && sqlTypeB.Size.HasValue) { 
                        bestSize = (sqlTypeB.Size > sqlTypeA.Size) ? sqlTypeB.Size : sqlTypeA.Size;
                    } 

                    if (sqlTypeB.Size.HasValue && sqlTypeB.Size.Value == LargeTypeSizeIndicator
                        || sqlTypeA.Size.HasValue && sqlTypeA.Size.Value == LargeTypeSizeIndicator) {
                        // the large type size trumps all 
                        bestSize = LargeTypeSizeIndicator;
                    } 
 
                    bestType = new SqlType(bestType.SqlDbType, bestSize);
                } 

                return bestType;
            }
 
            internal override ProviderType From(object o) {
                Type clrType = (o != null) ? o.GetType() : typeof(object); 
                if (clrType == typeof(string)) { 
                    string str = (string)o;
                    return From(clrType, str.Length); 
                }
                else if (clrType == typeof(bool)) {
                    return From(typeof(int));
                } 
                else if (clrType.IsArray) {
                    Array arr = (Array)o; 
                    return From(clrType, arr.Length); 
                }
                else if (clrType == typeof(decimal)) { 
                    decimal d = (decimal)o;
                    // The CLR stores the scale of a decimal value in bits
                    // 16 to 23 (i.e., mask 0x00FF0000) of the fourth int.
                    int scale = (Decimal.GetBits(d)[3] & 0x00FF0000) >> 16; 
                    return From(clrType, scale);
                } 
                else { 
                    return From(clrType);
                } 
            }

            internal override ProviderType From(Type type)
            { 
                return From(type, null);
            } 
 
            internal override ProviderType From(Type type, int? size) {
                return From(type, size); 
            }

            #endregion
        } 

        class Sql2005Provider : ProviderBase { 
            [SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity", Justification="These issues are related to our use of if-then and case statements for node types, which adds to the complexity count however when reviewed they are easy to navigate and understand.")] 
            internal override ProviderType From(Type type, int? size) {
                if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>)) 
                    type = type.GetGenericArguments()[0];
                TypeCode tc = System.Type.GetTypeCode(type);
                switch (tc) {
                    case TypeCode.Boolean: 
                        return Create(SqlDbType.Bit);
                    case TypeCode.Byte: 
                        return Create(SqlDbType.TinyInt); 
                    case TypeCode.SByte:
                    case TypeCode.Int16: 
                        return Create(SqlDbType.SmallInt);
                    case TypeCode.Int32:
                    case TypeCode.UInt16:
                        return Create(SqlDbType.Int); 
                    case TypeCode.Int64:
                    case TypeCode.UInt32: 
                        return Create(SqlDbType.BigInt); 
                    case TypeCode.UInt64:
                        return Create(SqlDbType.Decimal, 20, 0); 
                    case TypeCode.Decimal:
                        return Create(SqlDbType.Decimal, 29, size ?? 4);
                    case TypeCode.Double:
                        return Create(SqlDbType.Float); 
                    case TypeCode.Single:
                        return Create(SqlDbType.Real); 
                    case TypeCode.Char: 
                        return Create(SqlDbType.NChar, 1);
                    case TypeCode.String: 
                        return GetBestType(SqlDbType.NVarChar, size);
                    case TypeCode.DateTime:
                        return Create(SqlDbType.DateTime);
                    case TypeCode.Object: { 
                            if (type == typeof(Guid))
                                return Create(SqlDbType.UniqueIdentifier); 
                            if (type == typeof(byte[]) || type == typeof(Binary)) 
                                return GetBestType(SqlDbType.VarBinary, size);
                            if (type == typeof(char[])) 
                                return GetBestType(SqlDbType.NVarChar, size);
                            if (type == typeof(TimeSpan))
                                return Create(SqlDbType.BigInt);
                            if (type == typeof(System.Xml.Linq.XDocument) || 
                                type == typeof(System.Xml.Linq.XElement))
                                return theXml; 
                            // else UDT? 
                            return new SqlType(type);
                        } 
                    default:
                        throw Error.UnexpectedTypeCode(tc);
                }
            } 

            internal override ProviderType GetBestLargeType(ProviderType type) { 
                SqlType sqlType = (SqlType)type; 
                switch (sqlType.SqlDbType) {
                    case SqlDbType.NText: 
                    case SqlDbType.NChar:
                    case SqlDbType.NVarChar:
                        return Create(SqlDbType.NVarChar, LargeTypeSizeIndicator);
                    case SqlDbType.Text: 
                    case SqlDbType.Char:
                    case SqlDbType.VarChar: 
                        return Create(SqlDbType.VarChar, LargeTypeSizeIndicator); 
                    case SqlDbType.Image:
                    case SqlDbType.Binary: 
                    case SqlDbType.VarBinary:
                        return Create(SqlDbType.VarBinary, LargeTypeSizeIndicator);
                }
                return type; 
            }
 
            protected override bool SupportsMaxSize 
            {
                get { return true; } 
            }

        }
 
        class Sql2008Provider : Sql2005Provider
        { 
            [SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity", Justification = "These issues are related to our use of if-then and case statements for node types, which adds to the complexity count however when reviewed they are easy to navigate and understand.")] 
            internal override ProviderType From(Type type, int? size)
            { 
                if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>))
                    type = type.GetGenericArguments()[0];

                // Retain mappings for DateTime and TimeSpan; add one for the new DateTimeOffset type. 
                //
                if (System.Type.GetTypeCode(type) == TypeCode.Object && 
                    type == typeof(DateTimeOffset)) 
                {
                    return Create(SqlDbType.DateTimeOffset); 
                }

                return base.From(type, size);
            } 
        }
 
        class Sql2000Provider : ProviderBase { 
            [SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity", Justification="These issues are related to our use of if-then and case statements for node types, which adds to the complexity count however when reviewed they are easy to navigate and understand.")]
            internal override ProviderType From(Type type, int? size) { 
                if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>))
                    type = type.GetGenericArguments()[0];
                TypeCode tc = System.Type.GetTypeCode(type);
                switch (tc) { 
                    case TypeCode.Boolean:
                        return Create(SqlDbType.Bit); 
                    case TypeCode.Byte: 
                        return Create(SqlDbType.TinyInt);
                    case TypeCode.SByte: 
                    case TypeCode.Int16:
                        return Create(SqlDbType.SmallInt);
                    case TypeCode.Int32:
                    case TypeCode.UInt16: 
                        return Create(SqlDbType.Int);
                    case TypeCode.Int64: 
                    case TypeCode.UInt32: 
                        return Create(SqlDbType.BigInt);
                    case TypeCode.UInt64: 
                        return Create(SqlDbType.Decimal, 20, 0);
                    case TypeCode.Decimal:
                        return Create(SqlDbType.Decimal, 29, size ?? 4);
                    case TypeCode.Double: 
                        return Create(SqlDbType.Float);
                    case TypeCode.Single: 
                        return Create(SqlDbType.Real); 
                    case TypeCode.Char:
                        return Create(SqlDbType.NChar, 1); 
                    case TypeCode.String:
                        return GetBestType(SqlDbType.NVarChar, size);
                    case TypeCode.DateTime:
                        return Create(SqlDbType.DateTime); 
                    case TypeCode.Object: {
                            if (type == typeof(Guid)) 
                                return Create(SqlDbType.UniqueIdentifier); 
                            if (type == typeof(byte[]) || type == typeof(Binary))
                                return GetBestType(SqlDbType.VarBinary, size); 
                            if (type == typeof(char[]))
                                return GetBestType(SqlDbType.NVarChar, size);
                            if (type == typeof(TimeSpan))
                                return Create(SqlDbType.BigInt); 
                            if (type == typeof(System.Xml.Linq.XDocument) ||
                                type == typeof(System.Xml.Linq.XElement)) 
                                return theNText; 
                            // else UDT?
                            return new SqlType(type); 
                        }
                    default:
                        throw Error.UnexpectedTypeCode(tc);
                } 
            }
 
            internal override ProviderType GetBestLargeType(ProviderType type) { 
                SqlType sqlType = (SqlType)type;
                switch (sqlType.SqlDbType) { 
                    case SqlDbType.NChar:
                    case SqlDbType.NVarChar:
                        return Create(SqlDbType.NText);
                    case SqlDbType.Char: 
                    case SqlDbType.VarChar:
                        return Create(SqlDbType.Text); 
                    case SqlDbType.Binary: 
                    case SqlDbType.VarBinary:
                        return Create(SqlDbType.Image); 
                }
                return type;
            }
 
            protected override bool SupportsMaxSize
            { 
                get { return false; } 
            }
 
        }

        class SqlCEProvider : Sql2000Provider {
            internal override void InitializeParameter(ProviderType type, DbParameter parameter, object value) { 
                SqlType sqlType = (SqlType)type;
                PropertyInfo piSqlDbType = parameter.GetType().GetProperty("SqlDbType"); 
                piSqlDbType.SetValue(parameter, sqlType.SqlDbType, null); 
                if (sqlType.HasPrecisionAndScale) {
                    PropertyInfo piPrecision = parameter.GetType().GetProperty("Precision"); 
                    if (piPrecision != null) {
                        piPrecision.SetValue(parameter, Convert.ChangeType(sqlType.Precision, piPrecision.PropertyType, CultureInfo.InvariantCulture), null);
                    }
                    PropertyInfo piScale = parameter.GetType().GetProperty("Scale"); 
                    if (piScale != null) {
                        piScale.SetValue(parameter, Convert.ChangeType(sqlType.Scale, piScale.PropertyType, CultureInfo.InvariantCulture), null); 
                    } 
                }
                parameter.Value = GetParameterValue(sqlType, value); 
                // We want to allow the size of input parameters to be computed
                // implicitly (by setting the Value above). However, for fixed
                // length types and out/inout parameters, we want to set the size
                // explicitly (in the case of in/inout parameters only if the 
                // computed size is less than the fixed length, to avoid truncating
                // data). 
                bool isFixedSizeInputParameter = (parameter.Direction == ParameterDirection.Input) && sqlType.IsFixedSize; 
                if (isFixedSizeInputParameter || parameter.Direction != ParameterDirection.Input) {
                    if ((parameter.Size < sqlType.Size) || sqlType.IsLargeType) { 
                        parameter.Size = sqlType.Size ?? 0;
                    }
                }
            } 
        }
    } 
} 

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

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