OdbcParameter.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ Net / Net / 3.5.50727.3053 / DEVDIV / depot / DevDiv / releases / whidbey / netfxsp / ndp / fx / src / Data / System / Data / Odbc / OdbcParameter.cs / 1 / OdbcParameter.cs

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

using System; 
using System.ComponentModel;
using System.Data;
using System.Data.Common;
using System.Data.ProviderBase; 
using System.Data.SqlTypes;
using System.Diagnostics; 
using System.Globalization; 
using System.Runtime.InteropServices;
using System.Text; 
using System.Threading;

namespace System.Data.Odbc {
 
    [
    TypeConverterAttribute(typeof(System.Data.Odbc.OdbcParameter.OdbcParameterConverter)) 
    ] 
#if WINFSInternalOnly
    internal 
#else
    public
#endif
    sealed partial class OdbcParameter : DbParameter, ICloneable, IDbDataParameter { 

        private bool _hasChanged; 
        private bool _userSpecifiedType; 

        // _typemap     User explicit set type  or  default parameter type 
        // _infertpe    _typemap if the user explicitly sets type
        //              otherwise it is infered from the value
        // _bindtype    The actual type used for binding. E.g. string substitutes numeric
        // 
        // set_DbType:      _bindtype = _infertype = _typemap = TypeMap.FromDbType(value)
        // set_OdbcType:    _bindtype = _infertype = _typemap = TypeMap.FromOdbcType(value) 
        // 
        // GetParameterType:    If _typemap != _infertype AND value != 0
        //                      _bindtype = _infertype = TypeMap.FromSystemType(value.GetType()); 
        //                      otherwise
        //                      _bindtype = _infertype
        //
        // Bind:            Bind may change _bindtype if the type is not supported through the driver 
        //
 
        private TypeMap _typemap; 
        private TypeMap _bindtype;
 
        private string _parameterName;
        private byte _precision;
        private byte _scale;
        private bool _hasScale; 

 
        private ODBC32.SQL_C    _boundSqlCType; 
        private ODBC32.SQL_TYPE _boundParameterType;       // if we bound already that is the type we used
        private int             _boundSize; 
        private int             _boundScale;
        private IntPtr          _boundBuffer;
        private IntPtr          _boundIntbuffer;
        private TypeMap         _originalbindtype;         // the original type in case we had to change the bindtype 
                                                           // (e.g. decimal to string)
        private byte            _internalPrecision; 
        private bool            _internalShouldSerializeSize; 
        private int             _internalSize;
        private ParameterDirection _internalDirection; 
        private byte            _internalScale;
        private int             _internalOffset;
        internal bool           _internalUserSpecifiedType;
        private object          _internalValue; 

        private int             _preparedOffset; 
        private int             _preparedSize; 
        private int             _preparedBufferSize;
        private object          _preparedValue; 
        private int             _preparedIntOffset;
        private int             _preparedValueOffset;

        private ODBC32.SQL_C    _prepared_Sql_C_Type; 

        public OdbcParameter() : base() { 
            // uses System.Threading! 
        }
 
        public OdbcParameter(string name, object value) : this() {
            ParameterName  = name;
            Value          = value;
        } 

        public OdbcParameter(string name, OdbcType type) : this() { 
            ParameterName  = name; 
            OdbcType       = type;
        } 

        public OdbcParameter(string name, OdbcType type, int size) : this() {
            ParameterName  = name;
            OdbcType       = type; 
            Size           = size;
        } 
 
        public OdbcParameter(string name, OdbcType type, int size, string sourcecolumn) : this() {
            ParameterName  = name; 
            OdbcType       = type;
            Size           = size;
            SourceColumn   = sourcecolumn;
        } 

 
        [ EditorBrowsableAttribute(EditorBrowsableState.Advanced) ] // MDAC 69508 
        public OdbcParameter(string parameterName,
                             OdbcType odbcType, 
                             int size,
                             ParameterDirection parameterDirection,
                             Boolean isNullable,
                             Byte precision, 
                             Byte scale,
                             string srcColumn, 
                             DataRowVersion srcVersion, 
                             object value
                             ) : this() { // V1.0 everything 
            this.ParameterName = parameterName;
            this.OdbcType = odbcType;
            this.Size = size;
            this.Direction = parameterDirection; 
            this.IsNullable = isNullable;
            PrecisionInternal = precision; 
            ScaleInternal = scale; 
            this.SourceColumn = srcColumn;
            this.SourceVersion = srcVersion; 
            this.Value = value;
        }

        [ EditorBrowsableAttribute(EditorBrowsableState.Advanced) ] // MDAC 69508 
        public OdbcParameter(string parameterName,
                                 OdbcType odbcType, int size, 
                                 ParameterDirection parameterDirection, 
                                 Byte precision, Byte scale,
                                 string sourceColumn, DataRowVersion sourceVersion, bool sourceColumnNullMapping, 
                                 object value) : this() { // V2.0 everything - round trip all browsable properties + precision/scale
            this.ParameterName = parameterName;
            this.OdbcType = odbcType;
            this.Size = size; 
            this.Direction = parameterDirection;
            this.PrecisionInternal = precision; 
            this.ScaleInternal = scale; 
            this.SourceColumn = sourceColumn;
            this.SourceVersion = sourceVersion; 
            this.SourceColumnNullMapping = sourceColumnNullMapping;
            this.Value = value;
        }
 
        override public System.Data.DbType DbType {
            get { 
                if (_userSpecifiedType) { 
                    return _typemap._dbType;
                } 
                return TypeMap._NVarChar._dbType; // default type
            }
            set {
                if ((null == _typemap) || (_typemap._dbType != value)) { 
                    PropertyTypeChanging();
                    _typemap = TypeMap.FromDbType(value); 
                    _userSpecifiedType = true; 
                }
            } 
        }

        public override void ResetDbType() {
            ResetOdbcType(); 
        }
 
        [ 
        DefaultValue(OdbcType.NChar),
        RefreshProperties(RefreshProperties.All), 
        ResCategoryAttribute(Res.DataCategory_Data),
        ResDescriptionAttribute(Res.OdbcParameter_OdbcType),
        System.Data.Common.DbProviderSpecificTypePropertyAttribute(true),
        ] 
        public OdbcType OdbcType {
            get { 
                if (_userSpecifiedType) { 
                    return _typemap._odbcType;
                } 
                return TypeMap._NVarChar._odbcType; // default type
            }
            set {
                if ((null == _typemap) || (_typemap._odbcType != value)) { 
                    PropertyTypeChanging();
                    _typemap = TypeMap.FromOdbcType(value); 
                    _userSpecifiedType = true; 
                }
            } 
        }

        public void ResetOdbcType() {
            PropertyTypeChanging(); 
            _typemap = null;
            _userSpecifiedType = false; 
        } 

        internal bool HasChanged { 
            set {
                _hasChanged = value;
            }
        } 

        internal bool UserSpecifiedType { 
            get { 
                return _userSpecifiedType;
            } 
        }

        [
        ResCategoryAttribute(Res.DataCategory_Data), 
        ResDescriptionAttribute(Res.DbParameter_ParameterName),
        ] 
        override public string ParameterName { // V1.2.3300, XXXParameter V1.0.3300 
            get {
                string parameterName = _parameterName; 
                return ((null != parameterName) ? parameterName : ADP.StrEmpty);
            }
            set {
                if (_parameterName != value) { 
                    PropertyChanging();
                    _parameterName = value; 
                } 
            }
        } 

        [DefaultValue((Byte)0)] // MDAC 65862
        [ResCategoryAttribute(Res.DataCategory_Data)]
        [ResDescriptionAttribute(Res.DbDataParameter_Precision)] 
        public Byte Precision {
            get { 
                return PrecisionInternal; 
            }
            set { 
                PrecisionInternal = value;
            }
        }
        internal byte PrecisionInternal { 
            get {
                byte precision = _precision; 
                if (0 == precision) { 
                    precision = ValuePrecision(Value);
                } 
                return precision;
            }
            set {
                if (_precision != value) { 
                    PropertyChanging();
                    _precision = value; 
                } 
            }
        } 
        private bool ShouldSerializePrecision() {
            return (0 != _precision);
        }
 
        [DefaultValue((Byte)0)] // MDAC 65862
        [ResCategoryAttribute(Res.DataCategory_Data)] 
        [ResDescriptionAttribute(Res.DbDataParameter_Scale)] 
        public Byte Scale {
            get { 
                return ScaleInternal;
            }
            set {
                ScaleInternal = value; 
            }
        } 
        internal byte ScaleInternal { 
            get {
                byte scale = _scale; 
                if (!ShouldSerializeScale(scale)) { // WebData 94688
                    scale = ValueScale(Value);
                }
                return scale; 
            }
            set { 
                if (_scale != value || !_hasScale) { 
                    PropertyChanging();
                    _scale = value; 
                    _hasScale = true;
                }
            }
        } 
        private bool ShouldSerializeScale() {
            return ShouldSerializeScale(_scale); 
        } 
        private bool ShouldSerializeScale(byte scale) {
            return _hasScale && ((0 != scale) ||  ShouldSerializePrecision()); 
        }

        // returns the count of bytes for the data (ColumnSize argument to SqlBindParameter)
        private int GetColumnSize(object value, int offset, int ordinal) { 
            if ((ODBC32.SQL_C.NUMERIC == _bindtype._sql_c) && (0 != _internalPrecision)){
                return Math.Min((int)_internalPrecision,ADP.DecimalMaxPrecision); 
            } 
            int cch = _bindtype._columnSize;
            if (0 >= cch) { 
                if (ODBC32.SQL_C.NUMERIC == _typemap._sql_c) {
                    cch = 62;  // (DecimalMaxPrecision+sign+terminator)*BytesPerUnicodeCharater
                }
                else { 
                    cch = _internalSize;
                        if (!_internalShouldSerializeSize || 0x3fffffff<=cch || cch<0) { 
                        Debug.Assert((ODBC32.SQL_C.WCHAR == _bindtype._sql_c) || (ODBC32.SQL_C.BINARY == _bindtype._sql_c), "not wchar or binary"); 
                        if (!_internalShouldSerializeSize && (0 != (ParameterDirection.Output & _internalDirection))) {
                            throw ADP.UninitializedParameterSize(ordinal, _bindtype._type); 
                        }
                        if ((null == value) || Convert.IsDBNull(value)) {
                            cch = 0;
                        } 
                        else if (value is String) {
                            cch = ((String)value).Length - offset; 
 
                            if ((0 != (ParameterDirection.Output & _internalDirection)) && (0x3fffffff <= _internalSize)) {
                                // restrict output parameters when user set Size to Int32.MaxValue 
                                // to the greater of intput size or 8K
                                cch = Math.Max(cch, 4 * 1024); // MDAC 69224
                            }
 

                            // the following code causes failure against SQL 6.5 
                            // ERROR [HY104] [Microsoft][ODBC SQL Server Driver]Invalid precision value 
                            //
                            // the code causes failure if it is NOT there (remark added by [....]) 
                            // it causes failure with jet if it is there
                            //
                            // MDAC 76227: Code is required for japanese client/server tests.
                            // If this causes regressions with Jet please doc here including bug#. ([....]) 
                            //
                            if ((ODBC32.SQL_TYPE.CHAR == _bindtype._sql_type) 
                                || (ODBC32.SQL_TYPE.VARCHAR == _bindtype._sql_type) 
                                || (ODBC32.SQL_TYPE.LONGVARCHAR == _bindtype._sql_type)) {
                                cch = System.Text.Encoding.Default.GetMaxByteCount(cch); 
                            }

                        }
                        else if (value is char[]) { 
                            cch = ((char[])value).Length - offset;
                            if ((0 != (ParameterDirection.Output & _internalDirection)) && (0x3fffffff <= _internalSize)) { 
                                cch = Math.Max(cch, 4 * 1024); // MDAC 69224 
                            }
                            if ((ODBC32.SQL_TYPE.CHAR == _bindtype._sql_type) 
                                || (ODBC32.SQL_TYPE.VARCHAR == _bindtype._sql_type)
                                || (ODBC32.SQL_TYPE.LONGVARCHAR == _bindtype._sql_type)) {
                                cch = System.Text.Encoding.Default.GetMaxByteCount(cch);
                            } 
                        }
                        else if (value is byte[]) { 
                            cch = ((byte[])value).Length - offset; 

                            if ((0 != (ParameterDirection.Output & _internalDirection)) && (0x3fffffff <= _internalSize)) { 
                                // restrict output parameters when user set Size to Int32.MaxValue
                                // to the greater of intput size or 8K
                                cch = Math.Max(cch, 8 * 1024); // MDAC 69224
                            } 
                        }
#if DEBUG 
                        else { Debug.Assert(false, "not expecting this"); } 
#endif
                        // Note: ColumnSize should never be 0, 
                        // this represents the size of the column on the backend.
                        //
                        // without the following code causes failure
                        //ERROR [HY104] [Microsoft][ODBC Microsoft Access Driver]Invalid precision value 
                        cch = Math.Max(2, cch);
                       } 
                } 
            }
            Debug.Assert((0 <= cch) && (cch < 0x3fffffff), String.Format((IFormatProvider)null, "GetColumnSize: cch = {0} out of range, _internalShouldSerializeSize = {1}, _internalSize = {2}",cch, _internalShouldSerializeSize, _internalSize)); 
            return cch;
        }

 

        // Return the count of bytes for the data (size in bytes for the native buffer) 
        // 
        private int GetValueSize(object value, int offset) {
            if ((ODBC32.SQL_C.NUMERIC == _bindtype._sql_c) && (0 != _internalPrecision)){ 
                return Math.Min((int)_internalPrecision,ADP.DecimalMaxPrecision);
            }
            int cch = _bindtype._columnSize;
            if (0 >= cch) { 
                bool twobytesperunit = false;
                if (value is String) { 
                    cch = ((string)value).Length - offset; 
                    twobytesperunit = true;
                } 
                else if (value is char[]) {
                    cch = ((char[])value).Length - offset;
                    twobytesperunit = true;
                } 
                else if (value is byte[]) {
                    cch = ((byte[])value).Length - offset; 
                } 
                else {
                    cch = 0; 
                }
                if (_internalShouldSerializeSize && (_internalSize>=0) && (_internalSize= ccb) {
                if (ODBC32.SQL_C.NUMERIC == _typemap._sql_c) { 
                    ccb = 518; // _bindtype would be VarChar ([0-9]?{255} + '-' + '.') * 2
                }
                else {
                    ccb = _internalSize; 
                    if (!_internalShouldSerializeSize || (0x3fffffff <= ccb)||(ccb < 0)) {
                        Debug.Assert((ODBC32.SQL_C.WCHAR == _bindtype._sql_c) || (ODBC32.SQL_C.BINARY == _bindtype._sql_c), "not wchar or binary"); 
                        if ((ccb <= 0) && (0 != (ParameterDirection.Output & _internalDirection))) { 
                            throw ADP.UninitializedParameterSize(ordinal, _bindtype._type);
                        } 
                        if ((null == value) || Convert.IsDBNull(value)) {
                            if (_bindtype._sql_c == ODBC32.SQL_C.WCHAR) {
                                ccb = 2; // allow for null termination
                            } 
                            else {
                                ccb = 0; 
                            } 
                        }
                        else if (value is String) { 
                            ccb = (((String)value).Length - offset ) * 2 + 2;
                        }
                        else if (value is char[]) {
                            ccb = (((char[])value).Length - offset ) * 2 + 2; 
                        }
                        else if (value is byte[]) { 
                            ccb = ((byte[])value).Length - offset; 
                        }
#if DEBUG 
                        else { Debug.Assert(false, "not expecting this"); }
#endif
                        if ((0 != (ParameterDirection.Output & _internalDirection)) && (0x3fffffff <= _internalSize)) {
                            // restrict output parameters when user set Size to Int32.MaxValue 
                            // to the greater of intput size or 8K
                            ccb = Math.Max(ccb, 8 * 1024); // MDAC 69224 
                        } 
                    }
                    else if (ODBC32.SQL_C.WCHAR == _bindtype._sql_c) { 
                        if ((value is String) && (ccb < ((String)value).Length) && (_bindtype == _originalbindtype)) {
                            // silently truncate ... MDAC 84408 ... do not truncate upgraded values ... MDAC 84706
                            ccb = ((String)value).Length;
                        } 
                        ccb = (ccb * 2) + 2; // allow for null termination
                    } 
                    else if ((value is byte[]) && (ccb < ((byte[])value).Length) && (_bindtype == _originalbindtype)) { 
                        // silently truncate ... MDAC 84408 ... do not truncate upgraded values ... MDAC 84706
                        ccb = ((byte[])value).Length; 
                    }
                }
            }
            Debug.Assert((0 <= ccb) && (ccb < 0x3fffffff), "GetParameterSize: out of range " + ccb); 
            return ccb;
         } 
 
         private byte GetParameterPrecision(object value) {
            if (0 != _internalPrecision && value is decimal) { 
                // from qfe 762
                if (_internalPrecision<29) {
                    // from SqlClient ...
                    if (_internalPrecision != 0) { 
                        // devnote: If the userspecified precision (_internalPrecision) is less than the actual values precision
                        // we silently adjust the userspecified precision to the values precision. 
                        byte precision = ((SqlDecimal)(decimal)value).Precision; 
                        _internalPrecision = Math.Max(_internalPrecision, precision);   // silently adjust the precision
                    } 
                    return _internalPrecision;
                }
                return ADP.DecimalMaxPrecision;
            } 
            if ((null == value) || (value is Decimal) || Convert.IsDBNull(value)) { // MDAC 60882
                return ADP.DecimalMaxPrecision28; 
            } 
            return 0;
        } 


        private byte GetParameterScale(object value) {
 
            // For any value that is not decimal simply return the Scale
            // 
            if (!(value is decimal)) { 
                return _internalScale;
            } 

            // Determin the values scale
            // If the user specified a lower scale we return the user specified scale,
            // otherwise the values scale 
            //
            byte s = (byte)((Decimal.GetBits((Decimal)value)[3] & 0x00ff0000) >> 0x10); 
            if ((_internalScale > 0) && (_internalScale < s)){ 
                return _internalScale;
            } 
            return s;
        }

        //This is required for OdbcCommand.Clone to deep copy the parameters collection 
        object ICloneable.Clone() {
            return new OdbcParameter(this); 
        } 

        private void CopyParameterInternal () { 
            _internalValue = Value;
            // we should coerce the parameter value at this time.
            _internalPrecision = ShouldSerializePrecision() ? PrecisionInternal : ValuePrecision(_internalValue);
            _internalShouldSerializeSize = ShouldSerializeSize(); 
            _internalSize = _internalShouldSerializeSize ? Size : ValueSize(_internalValue);
            _internalDirection = Direction; 
            _internalScale = ShouldSerializeScale() ? ScaleInternal : ValueScale(_internalValue); 
            _internalOffset = Offset;
            _internalUserSpecifiedType = UserSpecifiedType; 
        }

        private void CloneHelper(OdbcParameter destination) {
            CloneHelperCore(destination); 
            destination._userSpecifiedType = _userSpecifiedType;
            destination._typemap = _typemap; 
            destination._parameterName = _parameterName; 
            destination._precision = _precision;
            destination._scale = _scale; 
            destination._hasScale = _hasScale;
        }

        internal void ClearBinding() { 
            if (!_userSpecifiedType) {
                _typemap = null; 
            } 
            _bindtype = null;
        } 

        internal void PrepareForBind(OdbcCommand command, short ordinal, ref int parameterBufferSize) {
            // make a snapshot of the current properties. Properties may change while we work on them
            // 
            CopyParameterInternal();
 
            object value  = ProcessAndGetParameterValue(); 
            int    offset = _internalOffset;
            int    size   = _internalSize; 
            ODBC32.SQL_C sql_c_type;


            // offset validation based on the values type 
            //
            if (offset > 0) { 
                if (value is string) { 
                    if (offset > ((string)value).Length) {
                        throw ADP.OffsetOutOfRangeException(); 
                    }
                }
                else if (value is char[]) {
                    if (offset > ((char[])value).Length) { 
                        throw ADP.OffsetOutOfRangeException();
                    } 
                } 
                else if (value is byte[]) {
                    if (offset > ((byte[])value).Length) { 
                        throw ADP.OffsetOutOfRangeException();
                    }
                }
                else { 
                    // for all other types offset has no meaning
                    // this is important since we might upgrade some types to strings 
                    offset = 0; 
                }
            } 

            // type support verification for certain data types
            //
            switch(_bindtype._sql_type) { 
                case ODBC32.SQL_TYPE.DECIMAL:
                case ODBC32.SQL_TYPE.NUMERIC: 
                    if ( 
                        !command.Connection.IsV3Driver                                      // for non V3 driver we always do the conversion
                        || !command.Connection.TestTypeSupport(ODBC32.SQL_TYPE.NUMERIC)     // otherwise we convert if the driver does not support numeric 
                        || command.Connection.TestRestrictedSqlBindType(_bindtype._sql_type)// or the type is not supported
                    ){
                        // No support for NUMERIC
                        // Change the type 
                        _bindtype = TypeMap._VarChar;
                        if ((null != value) && !Convert.IsDBNull(value)) { 
                            value = ((Decimal)value).ToString(CultureInfo.CurrentCulture); 
                            size = ((string)value).Length;
                            offset = 0; 
                        }
                    }
                    break;
                case ODBC32.SQL_TYPE.BIGINT: 
                    if (!command.Connection.IsV3Driver){
                        // No support for BIGINT 
                        // Change the type 
                        _bindtype = TypeMap._VarChar;
                        if ((null != value) && !Convert.IsDBNull(value)) { 
                            value = ((Int64)value).ToString(CultureInfo.CurrentCulture);
                            size = ((string)value).Length;
                            offset = 0;
                        } 
                    }
                    break; 
                case ODBC32.SQL_TYPE.WCHAR: // MDAC 68993 
                case ODBC32.SQL_TYPE.WVARCHAR:
                case ODBC32.SQL_TYPE.WLONGVARCHAR: 
                    if (value is Char) {
                        value = value.ToString();
                        size = ((string)value).Length;
                        offset = 0; 
                    }
                    if (!command.Connection.TestTypeSupport (_bindtype._sql_type)) { 
                        // No support for WCHAR, WVARCHAR or WLONGVARCHAR 
                        // Change the type
                        if (ODBC32.SQL_TYPE.WCHAR == _bindtype._sql_type) { _bindtype = TypeMap._Char; } 
                        else if (ODBC32.SQL_TYPE.WVARCHAR == _bindtype._sql_type) { _bindtype = TypeMap._VarChar; }
                        else if (ODBC32.SQL_TYPE.WLONGVARCHAR == _bindtype._sql_type) {
                            _bindtype = TypeMap._Text;
                        } 
                    }
                    break; 
            } // end switch 

            // Conversation from WCHAR to CHAR, VARCHAR or LONVARCHAR (AnsiString) is different for some providers 
            // we need to chonvert WCHAR to CHAR and bind as sql_c_type = CHAR
            //
            sql_c_type = _bindtype._sql_c;
 
            if (!command.Connection.IsV3Driver) {
                  if (sql_c_type == ODBC32.SQL_C.WCHAR) { 
                    sql_c_type = ODBC32.SQL_C.CHAR; 

                    if (null != value){ 
                        if (!Convert.IsDBNull(value) && value is string) {
                            int lcid = System.Globalization.CultureInfo.CurrentCulture.LCID;
                            CultureInfo culInfo = new CultureInfo(lcid);
                            Encoding cpe = System.Text.Encoding.GetEncoding(culInfo.TextInfo.ANSICodePage); 
                            value = cpe.GetBytes(value.ToString());
                            size = ((byte[])value).Length; 
                        } 
                    }
                } 
            };

            int cbParameterSize = GetParameterSize(value, offset, ordinal);      // count of bytes for the data, for SQLBindParameter
 
            // here we upgrade the datatypes if the given values size is bigger than the types columnsize
            // 
            switch(_bindtype._sql_type) { 
                case ODBC32.SQL_TYPE.VARBINARY: // MDAC 74372
                    // Note: per definition DbType.Binary does not support more than 8000 bytes so we change the type for binding 
                    if ((cbParameterSize > 8000))
                        { _bindtype = TypeMap._Image; } // will change to LONGVARBINARY
                    break;
                case ODBC32.SQL_TYPE.VARCHAR: // MDAC 74372 
                    // Note: per definition DbType.Binary does not support more than 8000 bytes so we change the type for binding
                    if ((cbParameterSize > 8000)) 
                        { _bindtype = TypeMap._Text; }  // will change to LONGVARCHAR 
                    break;
                case ODBC32.SQL_TYPE.WVARCHAR : // MDAC 75099 
                    // Note: per definition DbType.Binary does not support more than 8000 bytes so we change the type for binding
                    if ((cbParameterSize > 4000))
                        { _bindtype = TypeMap._NText; }  // will change to WLONGVARCHAR
                    break; 
            }
 
            _prepared_Sql_C_Type = sql_c_type; 
            _preparedOffset      = offset;
            _preparedSize        = size; 
            _preparedValue       = value;
            _preparedBufferSize  = cbParameterSize;
            _preparedIntOffset   = parameterBufferSize;
            _preparedValueOffset = _preparedIntOffset + IntPtr.Size; 
            parameterBufferSize += (cbParameterSize + IntPtr.Size);
        } 
 
        internal void Bind(OdbcStatementHandle hstmt, OdbcCommand command, short ordinal, CNativeBuffer parameterBuffer, bool allowReentrance) {
            ODBC32.RetCode  retcode; 
            ODBC32.SQL_C    sql_c_type = _prepared_Sql_C_Type;
            ODBC32.SQL_PARAM sqldirection = SqlDirectionFromParameterDirection();

            int offset      = _preparedOffset; 
            int size        = _preparedSize;
            object value    = _preparedValue; 
            int cbValueSize = GetValueSize(value, offset);             // count of bytes for the data 
            int cchSize     = GetColumnSize(value, offset, ordinal);   // count of bytes for the data, used to allocate the buffer length
            byte precision  = GetParameterPrecision(value); 
            byte scale      = GetParameterScale(value);
            int cbActual;

            HandleRef valueBuffer  = parameterBuffer.PtrOffset(_preparedValueOffset, _preparedBufferSize); 
            HandleRef intBuffer    = parameterBuffer.PtrOffset(_preparedIntOffset, IntPtr.Size);
 
            // for the numeric datatype we need to do some special case handling ... 
            //
            if (ODBC32.SQL_C.NUMERIC == sql_c_type) { 

                // for input/output parameters we need to adjust the scale of the input value since the convert function in
                // sqlsrv32 takes this scale for the output parameter (possible bug in sqlsrv32?)
                // 
                if ((ODBC32.SQL_PARAM.INPUT_OUTPUT == sqldirection) && (value is Decimal)) {
                    if (scale < _internalScale) { 
                        while (scale < _internalScale) { 
                            value = ((decimal)value ) * 10;
                            scale++; 
                        }
                    }
                }
                SetInputValue(value, sql_c_type, cbValueSize, precision, 0, parameterBuffer); 

                // for output parameters we need to write precision and scale to the buffer since the convert function in 
                // sqlsrv32 expects these values there (possible bug in sqlsrv32?) 
                //
                if (ODBC32.SQL_PARAM.INPUT != sqldirection) { 
                    parameterBuffer.WriteInt16(_preparedValueOffset, (short)(((ushort)scale << 8) | (ushort)precision));
                }
            }
            else { 
                SetInputValue(value, sql_c_type, cbValueSize, size, offset, parameterBuffer);
            } 
 

            // Try to reuse existing bindings if 
            //  the binding is valid (means we already went through binding all parameters)
            //  the parametercollection is bound already
            //  the bindtype ParameterType did not change (forced upgrade)
 
            if (!_hasChanged
                && (_boundSqlCType == sql_c_type) 
                && (_boundParameterType == _bindtype._sql_type) 
                && (_boundSize == cchSize)
                && (_boundScale == scale) 
                && (_boundBuffer == valueBuffer.Handle)
                && (_boundIntbuffer == intBuffer.Handle)
            ) {
                return; 
            }
 
            //SQLBindParameter 
            retcode = hstmt.BindParameter(
                                    ordinal,                    // Parameter Number 
                                    (short)sqldirection,        // InputOutputType
                                    sql_c_type,                 // ValueType
                                    _bindtype._sql_type,        // ParameterType
                                    (IntPtr)cchSize,            // ColumnSize 
                                    (IntPtr)scale,              // DecimalDigits
                                    valueBuffer,                // ParameterValuePtr 
                                    (IntPtr)_preparedBufferSize, 
                                    intBuffer);                 // StrLen_or_IndPtr
 
            if (ODBC32.RetCode.SUCCESS != retcode) {
                if ("07006" == command.GetDiagSqlState()) {
                    Bid.Trace(" Call to BindParameter returned errorcode [07006]\n");
                    command.Connection.FlagRestrictedSqlBindType(_bindtype._sql_type); 
                    if (allowReentrance) {
                        this.Bind(hstmt, command, ordinal, parameterBuffer, false); 
                        return; 
                    }
                } 
                command.Connection.HandleError(hstmt, retcode);
            }
            _hasChanged = false;
            _boundSqlCType = sql_c_type; 
            _boundParameterType = _bindtype._sql_type;
            _boundSize = cchSize; 
            _boundScale = scale; 
            _boundBuffer = valueBuffer.Handle;
            _boundIntbuffer = intBuffer.Handle; 

            if (ODBC32.SQL_C.NUMERIC == sql_c_type) {
                OdbcDescriptorHandle hdesc = command.GetDescriptorHandle(ODBC32.SQL_ATTR.APP_PARAM_DESC);
                // descriptor handle is cached on command wrapper, don't release it 

                // Set descriptor Type 
                // 
                //SQLSetDescField(hdesc, i+1, SQL_DESC_TYPE, (void *)SQL_C_NUMERIC, 0);
                retcode = hdesc.SetDescriptionField1(ordinal, ODBC32.SQL_DESC.TYPE, (IntPtr)ODBC32.SQL_C.NUMERIC); 

                if (ODBC32.RetCode.SUCCESS != retcode) {
                    command.Connection.HandleError(hstmt, retcode);
                } 

 
                // Set precision 
                //
                cbActual= (int)precision; 
                //SQLSetDescField(hdesc, i+1, SQL_DESC_PRECISION, (void *)precision, 0);
                retcode = hdesc.SetDescriptionField1(ordinal, ODBC32.SQL_DESC.PRECISION, (IntPtr)cbActual);

                if (ODBC32.RetCode.SUCCESS != retcode) { 
                    command.Connection.HandleError(hstmt, retcode);
                } 
 

                // Set scale 
                //
                // SQLSetDescField(hdesc, i+1, SQL_DESC_SCALE,  (void *)llen, 0);
                cbActual= (int)scale;
                retcode = hdesc.SetDescriptionField1(ordinal, ODBC32.SQL_DESC.SCALE, (IntPtr)cbActual); 

                if (ODBC32.RetCode.SUCCESS != retcode) { 
                    command.Connection.HandleError(hstmt, retcode); 
                }
 
                // Set data pointer
                //
                // SQLSetDescField(hdesc, i+1, SQL_DESC_DATA_PTR,  (void *)&numeric, 0);
                retcode = hdesc.SetDescriptionField2(ordinal, ODBC32.SQL_DESC.DATA_PTR, valueBuffer); 

                if (ODBC32.RetCode.SUCCESS != retcode) { 
                    command.Connection.HandleError(hstmt, retcode); 
                }
            } 
        }

        internal void GetOutputValue(CNativeBuffer parameterBuffer) { //Handle any output params
 
            // No value is available if the user fiddles with the parameters properties
            // 
            if (_hasChanged) return; 

            if ((null != _bindtype) && (_internalDirection != ParameterDirection.Input)) { 

               TypeMap typemap = _bindtype;
                _bindtype = null;
 
                int cbActual = (int)parameterBuffer.ReadIntPtr(_preparedIntOffset);
                if (ODBC32.SQL_NULL_DATA == cbActual) { 
                    Value = DBNull.Value; 
                }
                else if ((0 <= cbActual)  || (cbActual == ODBC32.SQL_NTS)){ // safeguard 
                    Value = parameterBuffer.MarshalToManaged(_preparedValueOffset, _boundSqlCType, cbActual);

                if (_boundSqlCType== ODBC32.SQL_C.CHAR) {
                    if ((null != Value) && !Convert.IsDBNull(Value)) { 
                        int lcid = System.Globalization.CultureInfo.CurrentCulture.LCID;
                        CultureInfo culInfo = new CultureInfo(lcid); 
                        Encoding cpe = System.Text.Encoding.GetEncoding(culInfo.TextInfo.ANSICodePage); 
                        Value = cpe.GetString((Byte[])Value);
                    } 
                }

                    if ((typemap != _typemap) && (null != Value) && !Convert.IsDBNull(Value) && (Value.GetType() != _typemap._type)) {
                        Debug.Assert(ODBC32.SQL_C.NUMERIC == _typemap._sql_c, "unexpected"); 
                        Value = Decimal.Parse((string)Value, System.Globalization.CultureInfo.CurrentCulture);
                    } 
                } 
            }
        } 

        private object ProcessAndGetParameterValue() {
            object value = _internalValue;
            if (_internalUserSpecifiedType) { 
                if ((null != value) && !Convert.IsDBNull(value)) {
                    Type valueType = value.GetType(); 
                    if (!valueType.IsArray) { 
                        if (valueType != _typemap._type) {
                            try { 
                                value = Convert.ChangeType (value, _typemap._type, (System.IFormatProvider)null);
                            }
                            catch(Exception e) {
                                // Don't know which exception to expect from ChangeType so we filter out the serious ones 
                                //
                                if (!ADP.IsCatchableExceptionType(e)) { 
                                    throw; 
                                }
                                throw ADP.ParameterConversionFailed(value, _typemap._type, e); // WebData 75433 
                            }
                        }
                    }
                    else if (valueType == typeof(char[])) { 
                        value = new String((char[])value);
                    } 
                } 
            }
            else if (null == _typemap) { 
                if ((null == value) || Convert.IsDBNull (value)) {
                    _typemap = TypeMap._NVarChar; // default type
                }
                else { 
                    Type type = value.GetType ();
 
                    _typemap = TypeMap.FromSystemType (type); 
                }
            } 
            Debug.Assert(null != _typemap, "GetParameterValue: null _typemap");
            _originalbindtype = _bindtype = _typemap;
            return value;
        } 

        private void PropertyChanging() { 
            _hasChanged = true; 
        }
 
        private void PropertyTypeChanging() {
            PropertyChanging();
            //CoercedValue = null;
        } 

        internal void SetInputValue(object value, ODBC32.SQL_C sql_c_type, int cbsize, int sizeorprecision, int offset, CNativeBuffer parameterBuffer) { //Handle any input params 
            if((ParameterDirection.Input == _internalDirection) || (ParameterDirection.InputOutput == _internalDirection)) { 
                //Note: (lang) "null" means to use the servers default (not DBNull).
                //We probably should just not have bound this parameter, period, but that 
                //would mess up the users question marks, etc...
                if((null == value)) {
                    parameterBuffer.WriteIntPtr(_preparedIntOffset, (IntPtr)ODBC32.SQL_DEFAULT_PARAM);
                } 
                else if(Convert.IsDBNull(value)) {
                    parameterBuffer.WriteIntPtr(_preparedIntOffset, (IntPtr)ODBC32.SQL_NULL_DATA); 
                } 
                else {
                    switch(sql_c_type) { 
                    case ODBC32.SQL_C.CHAR:
                    case ODBC32.SQL_C.WCHAR:
                    case ODBC32.SQL_C.BINARY:
                        //StrLen_or_IndPtr is ignored except for Character or Binary or data. 
                        parameterBuffer.WriteIntPtr(_preparedIntOffset, (IntPtr)cbsize);
                        break; 
                    default: 
                        parameterBuffer.WriteIntPtr(_preparedIntOffset, IntPtr.Zero);
                        break; 

                    }

                    //Place the input param value into the native buffer 
                    parameterBuffer.MarshalToNative(_preparedValueOffset, value, sql_c_type, sizeorprecision, offset);
                } 
            } 
            else {
                // always set ouput only and return value parameter values to null when executing 
                _internalValue = null;

                //Always initialize the intbuffer (for output params).  Since we need to know
                //if/when the parameters are available for output. (ie: when is the buffer valid...) 
                //if (_sqldirection != ODBC32.SQL_PARAM.INPUT)
                parameterBuffer.WriteIntPtr(_preparedIntOffset, (IntPtr)ODBC32.SQL_NULL_DATA); 
            } 
        }
 
        private ODBC32.SQL_PARAM SqlDirectionFromParameterDirection () {
            switch(_internalDirection) {
                case ParameterDirection.Input:
                    return ODBC32.SQL_PARAM.INPUT; 
                case ParameterDirection.Output:
                case ParameterDirection.ReturnValue: 
                    //ODBC doesn't seem to distinguish between output and return value 
                    //as SQL_PARAM_RETURN_VALUE fails with "Invalid parameter type"
                    return ODBC32.SQL_PARAM.OUTPUT; 
                case ParameterDirection.InputOutput:
                    return ODBC32.SQL_PARAM.INPUT_OUTPUT;
                default:
                    Debug.Assert (false, "Unexpected Direction Property on Parameter"); 
                    return ODBC32.SQL_PARAM.INPUT;
            } 
        } 

        [ 
        RefreshProperties(RefreshProperties.All),
        ResCategoryAttribute(Res.DataCategory_Data),
        ResDescriptionAttribute(Res.DbParameter_Value),
        TypeConverterAttribute(typeof(StringConverter)), 
        ]
        override public object Value { // V1.2.3300, XXXParameter V1.0.3300 
            get { 
                return _value;
            } 
            set {
                _coercedValue = null;
                _value = value;
            } 
        }
 
        private byte ValuePrecision(object value) { 
            return ValuePrecisionCore(value);
        } 

        private byte ValueScale(object value) {
            return ValueScaleCore(value);
        } 

        private int ValueSize(object value) { 
            return ValueSizeCore(value); 
        }
 
        // implemented as nested class to take advantage of the private/protected ShouldSerializeXXX methods
        sealed internal class OdbcParameterConverter : ExpandableObjectConverter {

            // converter classes should have public ctor 
            public OdbcParameterConverter() {
            } 
 
            public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType) {
                if (destinationType == typeof(System.ComponentModel.Design.Serialization.InstanceDescriptor)) { 
                    return true;
                }
                return base.CanConvertTo(context, destinationType);
            } 

            public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType) { 
                if (destinationType == null) { 
                    throw ADP.ArgumentNull("destinationType");
                } 

                if (destinationType == typeof(System.ComponentModel.Design.Serialization.InstanceDescriptor) && value is OdbcParameter) {
                    OdbcParameter p = (OdbcParameter)value;
 
                    // MDAC 67321 - reducing parameter generated code
                    int flags = 0; // if part of the collection - the parametername can't be empty 
 
                    if (OdbcType.NChar != p.OdbcType) {
                        flags |= 1; 
                    }
                    if (p.ShouldSerializeSize()) {
                        flags |= 2;
                    } 
                    if (!ADP.IsEmpty(p.SourceColumn)) {
                        flags |= 4; 
                    } 
                    if (null != p.Value) {
                        flags |= 8; 
                    }
                    if ((ParameterDirection.Input != p.Direction) || p.IsNullable
                        || p.ShouldSerializePrecision() || p.ShouldSerializeScale()
                        || (DataRowVersion.Current != p.SourceVersion)) { 
                        flags |= 16; // V1.0 everything
                    } 
                    if (p.SourceColumnNullMapping) { 
                        flags |= 32; // v2.0 everything
                    } 

                    Type[] ctorParams;
                    object[] ctorValues;
                    switch(flags) { 
                    case  0: // ParameterName
                    case  1: // SqlDbType 
                        ctorParams = new Type[] { typeof(string), typeof(OdbcType) }; 
                        ctorValues = new object[] { p.ParameterName, p.OdbcType };
                        break; 
                    case  2: // Size
                    case  3: // Size, SqlDbType
                        ctorParams = new Type[] { typeof(string), typeof(OdbcType), typeof(int) };
                        ctorValues = new object[] { p.ParameterName, p.OdbcType, p.Size }; 
                        break;
                    case  4: // SourceColumn 
                    case  5: // SourceColumn, SqlDbType 
                    case  6: // SourceColumn, Size
                    case  7: // SourceColumn, Size, SqlDbType 
                        ctorParams = new Type[] { typeof(string), typeof(OdbcType), typeof(int), typeof(string) };
                        ctorValues = new object[] { p.ParameterName, p.OdbcType, p.Size, p.SourceColumn };
                        break;
                    case  8: // Value 
                        ctorParams = new Type[] { typeof(string), typeof(object) };
                        ctorValues = new object[] { p.ParameterName, p.Value }; 
                        break; 
                    default:
                        if (0 == (32 & flags)) { // V1.0 everything 
                            ctorParams = new Type[] {
                                typeof(string), typeof(OdbcType), typeof(int), typeof(ParameterDirection),
                                typeof(bool), typeof(byte), typeof(byte), typeof(string),
                                typeof(DataRowVersion), typeof(object) }; 
                            ctorValues = new object[] {
                                p.ParameterName, p.OdbcType,  p.Size, p.Direction, 
                                p.IsNullable, p.PrecisionInternal, p.ScaleInternal, p.SourceColumn, 
                                p.SourceVersion, p.Value };
                        } 
                        else { // v2.0 everything - round trip all browsable properties + precision/scale
                            ctorParams = new Type[] {
                                typeof(string), typeof(OdbcType), typeof(int), typeof(ParameterDirection),
                                typeof(byte), typeof(byte), 
                                typeof(string), typeof(DataRowVersion), typeof(bool),
                                typeof(object) }; 
                            ctorValues = new object[] { 
                                p.ParameterName, p.OdbcType,  p.Size, p.Direction,
                                p.PrecisionInternal, p.ScaleInternal, 
                                p.SourceColumn, p.SourceVersion, p.SourceColumnNullMapping,
                                p.Value };
                        }
                        break; 
                    }
                    System.Reflection.ConstructorInfo ctor = typeof(OdbcParameter).GetConstructor(ctorParams); 
                    if (null != ctor) { 
                        return new System.ComponentModel.Design.Serialization.InstanceDescriptor(ctor, ctorValues);
                    } 
                }
                return base.ConvertTo(context, culture, value, destinationType);
            }
        } 
    }
} 

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

using System; 
using System.ComponentModel;
using System.Data;
using System.Data.Common;
using System.Data.ProviderBase; 
using System.Data.SqlTypes;
using System.Diagnostics; 
using System.Globalization; 
using System.Runtime.InteropServices;
using System.Text; 
using System.Threading;

namespace System.Data.Odbc {
 
    [
    TypeConverterAttribute(typeof(System.Data.Odbc.OdbcParameter.OdbcParameterConverter)) 
    ] 
#if WINFSInternalOnly
    internal 
#else
    public
#endif
    sealed partial class OdbcParameter : DbParameter, ICloneable, IDbDataParameter { 

        private bool _hasChanged; 
        private bool _userSpecifiedType; 

        // _typemap     User explicit set type  or  default parameter type 
        // _infertpe    _typemap if the user explicitly sets type
        //              otherwise it is infered from the value
        // _bindtype    The actual type used for binding. E.g. string substitutes numeric
        // 
        // set_DbType:      _bindtype = _infertype = _typemap = TypeMap.FromDbType(value)
        // set_OdbcType:    _bindtype = _infertype = _typemap = TypeMap.FromOdbcType(value) 
        // 
        // GetParameterType:    If _typemap != _infertype AND value != 0
        //                      _bindtype = _infertype = TypeMap.FromSystemType(value.GetType()); 
        //                      otherwise
        //                      _bindtype = _infertype
        //
        // Bind:            Bind may change _bindtype if the type is not supported through the driver 
        //
 
        private TypeMap _typemap; 
        private TypeMap _bindtype;
 
        private string _parameterName;
        private byte _precision;
        private byte _scale;
        private bool _hasScale; 

 
        private ODBC32.SQL_C    _boundSqlCType; 
        private ODBC32.SQL_TYPE _boundParameterType;       // if we bound already that is the type we used
        private int             _boundSize; 
        private int             _boundScale;
        private IntPtr          _boundBuffer;
        private IntPtr          _boundIntbuffer;
        private TypeMap         _originalbindtype;         // the original type in case we had to change the bindtype 
                                                           // (e.g. decimal to string)
        private byte            _internalPrecision; 
        private bool            _internalShouldSerializeSize; 
        private int             _internalSize;
        private ParameterDirection _internalDirection; 
        private byte            _internalScale;
        private int             _internalOffset;
        internal bool           _internalUserSpecifiedType;
        private object          _internalValue; 

        private int             _preparedOffset; 
        private int             _preparedSize; 
        private int             _preparedBufferSize;
        private object          _preparedValue; 
        private int             _preparedIntOffset;
        private int             _preparedValueOffset;

        private ODBC32.SQL_C    _prepared_Sql_C_Type; 

        public OdbcParameter() : base() { 
            // uses System.Threading! 
        }
 
        public OdbcParameter(string name, object value) : this() {
            ParameterName  = name;
            Value          = value;
        } 

        public OdbcParameter(string name, OdbcType type) : this() { 
            ParameterName  = name; 
            OdbcType       = type;
        } 

        public OdbcParameter(string name, OdbcType type, int size) : this() {
            ParameterName  = name;
            OdbcType       = type; 
            Size           = size;
        } 
 
        public OdbcParameter(string name, OdbcType type, int size, string sourcecolumn) : this() {
            ParameterName  = name; 
            OdbcType       = type;
            Size           = size;
            SourceColumn   = sourcecolumn;
        } 

 
        [ EditorBrowsableAttribute(EditorBrowsableState.Advanced) ] // MDAC 69508 
        public OdbcParameter(string parameterName,
                             OdbcType odbcType, 
                             int size,
                             ParameterDirection parameterDirection,
                             Boolean isNullable,
                             Byte precision, 
                             Byte scale,
                             string srcColumn, 
                             DataRowVersion srcVersion, 
                             object value
                             ) : this() { // V1.0 everything 
            this.ParameterName = parameterName;
            this.OdbcType = odbcType;
            this.Size = size;
            this.Direction = parameterDirection; 
            this.IsNullable = isNullable;
            PrecisionInternal = precision; 
            ScaleInternal = scale; 
            this.SourceColumn = srcColumn;
            this.SourceVersion = srcVersion; 
            this.Value = value;
        }

        [ EditorBrowsableAttribute(EditorBrowsableState.Advanced) ] // MDAC 69508 
        public OdbcParameter(string parameterName,
                                 OdbcType odbcType, int size, 
                                 ParameterDirection parameterDirection, 
                                 Byte precision, Byte scale,
                                 string sourceColumn, DataRowVersion sourceVersion, bool sourceColumnNullMapping, 
                                 object value) : this() { // V2.0 everything - round trip all browsable properties + precision/scale
            this.ParameterName = parameterName;
            this.OdbcType = odbcType;
            this.Size = size; 
            this.Direction = parameterDirection;
            this.PrecisionInternal = precision; 
            this.ScaleInternal = scale; 
            this.SourceColumn = sourceColumn;
            this.SourceVersion = sourceVersion; 
            this.SourceColumnNullMapping = sourceColumnNullMapping;
            this.Value = value;
        }
 
        override public System.Data.DbType DbType {
            get { 
                if (_userSpecifiedType) { 
                    return _typemap._dbType;
                } 
                return TypeMap._NVarChar._dbType; // default type
            }
            set {
                if ((null == _typemap) || (_typemap._dbType != value)) { 
                    PropertyTypeChanging();
                    _typemap = TypeMap.FromDbType(value); 
                    _userSpecifiedType = true; 
                }
            } 
        }

        public override void ResetDbType() {
            ResetOdbcType(); 
        }
 
        [ 
        DefaultValue(OdbcType.NChar),
        RefreshProperties(RefreshProperties.All), 
        ResCategoryAttribute(Res.DataCategory_Data),
        ResDescriptionAttribute(Res.OdbcParameter_OdbcType),
        System.Data.Common.DbProviderSpecificTypePropertyAttribute(true),
        ] 
        public OdbcType OdbcType {
            get { 
                if (_userSpecifiedType) { 
                    return _typemap._odbcType;
                } 
                return TypeMap._NVarChar._odbcType; // default type
            }
            set {
                if ((null == _typemap) || (_typemap._odbcType != value)) { 
                    PropertyTypeChanging();
                    _typemap = TypeMap.FromOdbcType(value); 
                    _userSpecifiedType = true; 
                }
            } 
        }

        public void ResetOdbcType() {
            PropertyTypeChanging(); 
            _typemap = null;
            _userSpecifiedType = false; 
        } 

        internal bool HasChanged { 
            set {
                _hasChanged = value;
            }
        } 

        internal bool UserSpecifiedType { 
            get { 
                return _userSpecifiedType;
            } 
        }

        [
        ResCategoryAttribute(Res.DataCategory_Data), 
        ResDescriptionAttribute(Res.DbParameter_ParameterName),
        ] 
        override public string ParameterName { // V1.2.3300, XXXParameter V1.0.3300 
            get {
                string parameterName = _parameterName; 
                return ((null != parameterName) ? parameterName : ADP.StrEmpty);
            }
            set {
                if (_parameterName != value) { 
                    PropertyChanging();
                    _parameterName = value; 
                } 
            }
        } 

        [DefaultValue((Byte)0)] // MDAC 65862
        [ResCategoryAttribute(Res.DataCategory_Data)]
        [ResDescriptionAttribute(Res.DbDataParameter_Precision)] 
        public Byte Precision {
            get { 
                return PrecisionInternal; 
            }
            set { 
                PrecisionInternal = value;
            }
        }
        internal byte PrecisionInternal { 
            get {
                byte precision = _precision; 
                if (0 == precision) { 
                    precision = ValuePrecision(Value);
                } 
                return precision;
            }
            set {
                if (_precision != value) { 
                    PropertyChanging();
                    _precision = value; 
                } 
            }
        } 
        private bool ShouldSerializePrecision() {
            return (0 != _precision);
        }
 
        [DefaultValue((Byte)0)] // MDAC 65862
        [ResCategoryAttribute(Res.DataCategory_Data)] 
        [ResDescriptionAttribute(Res.DbDataParameter_Scale)] 
        public Byte Scale {
            get { 
                return ScaleInternal;
            }
            set {
                ScaleInternal = value; 
            }
        } 
        internal byte ScaleInternal { 
            get {
                byte scale = _scale; 
                if (!ShouldSerializeScale(scale)) { // WebData 94688
                    scale = ValueScale(Value);
                }
                return scale; 
            }
            set { 
                if (_scale != value || !_hasScale) { 
                    PropertyChanging();
                    _scale = value; 
                    _hasScale = true;
                }
            }
        } 
        private bool ShouldSerializeScale() {
            return ShouldSerializeScale(_scale); 
        } 
        private bool ShouldSerializeScale(byte scale) {
            return _hasScale && ((0 != scale) ||  ShouldSerializePrecision()); 
        }

        // returns the count of bytes for the data (ColumnSize argument to SqlBindParameter)
        private int GetColumnSize(object value, int offset, int ordinal) { 
            if ((ODBC32.SQL_C.NUMERIC == _bindtype._sql_c) && (0 != _internalPrecision)){
                return Math.Min((int)_internalPrecision,ADP.DecimalMaxPrecision); 
            } 
            int cch = _bindtype._columnSize;
            if (0 >= cch) { 
                if (ODBC32.SQL_C.NUMERIC == _typemap._sql_c) {
                    cch = 62;  // (DecimalMaxPrecision+sign+terminator)*BytesPerUnicodeCharater
                }
                else { 
                    cch = _internalSize;
                        if (!_internalShouldSerializeSize || 0x3fffffff<=cch || cch<0) { 
                        Debug.Assert((ODBC32.SQL_C.WCHAR == _bindtype._sql_c) || (ODBC32.SQL_C.BINARY == _bindtype._sql_c), "not wchar or binary"); 
                        if (!_internalShouldSerializeSize && (0 != (ParameterDirection.Output & _internalDirection))) {
                            throw ADP.UninitializedParameterSize(ordinal, _bindtype._type); 
                        }
                        if ((null == value) || Convert.IsDBNull(value)) {
                            cch = 0;
                        } 
                        else if (value is String) {
                            cch = ((String)value).Length - offset; 
 
                            if ((0 != (ParameterDirection.Output & _internalDirection)) && (0x3fffffff <= _internalSize)) {
                                // restrict output parameters when user set Size to Int32.MaxValue 
                                // to the greater of intput size or 8K
                                cch = Math.Max(cch, 4 * 1024); // MDAC 69224
                            }
 

                            // the following code causes failure against SQL 6.5 
                            // ERROR [HY104] [Microsoft][ODBC SQL Server Driver]Invalid precision value 
                            //
                            // the code causes failure if it is NOT there (remark added by [....]) 
                            // it causes failure with jet if it is there
                            //
                            // MDAC 76227: Code is required for japanese client/server tests.
                            // If this causes regressions with Jet please doc here including bug#. ([....]) 
                            //
                            if ((ODBC32.SQL_TYPE.CHAR == _bindtype._sql_type) 
                                || (ODBC32.SQL_TYPE.VARCHAR == _bindtype._sql_type) 
                                || (ODBC32.SQL_TYPE.LONGVARCHAR == _bindtype._sql_type)) {
                                cch = System.Text.Encoding.Default.GetMaxByteCount(cch); 
                            }

                        }
                        else if (value is char[]) { 
                            cch = ((char[])value).Length - offset;
                            if ((0 != (ParameterDirection.Output & _internalDirection)) && (0x3fffffff <= _internalSize)) { 
                                cch = Math.Max(cch, 4 * 1024); // MDAC 69224 
                            }
                            if ((ODBC32.SQL_TYPE.CHAR == _bindtype._sql_type) 
                                || (ODBC32.SQL_TYPE.VARCHAR == _bindtype._sql_type)
                                || (ODBC32.SQL_TYPE.LONGVARCHAR == _bindtype._sql_type)) {
                                cch = System.Text.Encoding.Default.GetMaxByteCount(cch);
                            } 
                        }
                        else if (value is byte[]) { 
                            cch = ((byte[])value).Length - offset; 

                            if ((0 != (ParameterDirection.Output & _internalDirection)) && (0x3fffffff <= _internalSize)) { 
                                // restrict output parameters when user set Size to Int32.MaxValue
                                // to the greater of intput size or 8K
                                cch = Math.Max(cch, 8 * 1024); // MDAC 69224
                            } 
                        }
#if DEBUG 
                        else { Debug.Assert(false, "not expecting this"); } 
#endif
                        // Note: ColumnSize should never be 0, 
                        // this represents the size of the column on the backend.
                        //
                        // without the following code causes failure
                        //ERROR [HY104] [Microsoft][ODBC Microsoft Access Driver]Invalid precision value 
                        cch = Math.Max(2, cch);
                       } 
                } 
            }
            Debug.Assert((0 <= cch) && (cch < 0x3fffffff), String.Format((IFormatProvider)null, "GetColumnSize: cch = {0} out of range, _internalShouldSerializeSize = {1}, _internalSize = {2}",cch, _internalShouldSerializeSize, _internalSize)); 
            return cch;
        }

 

        // Return the count of bytes for the data (size in bytes for the native buffer) 
        // 
        private int GetValueSize(object value, int offset) {
            if ((ODBC32.SQL_C.NUMERIC == _bindtype._sql_c) && (0 != _internalPrecision)){ 
                return Math.Min((int)_internalPrecision,ADP.DecimalMaxPrecision);
            }
            int cch = _bindtype._columnSize;
            if (0 >= cch) { 
                bool twobytesperunit = false;
                if (value is String) { 
                    cch = ((string)value).Length - offset; 
                    twobytesperunit = true;
                } 
                else if (value is char[]) {
                    cch = ((char[])value).Length - offset;
                    twobytesperunit = true;
                } 
                else if (value is byte[]) {
                    cch = ((byte[])value).Length - offset; 
                } 
                else {
                    cch = 0; 
                }
                if (_internalShouldSerializeSize && (_internalSize>=0) && (_internalSize= ccb) {
                if (ODBC32.SQL_C.NUMERIC == _typemap._sql_c) { 
                    ccb = 518; // _bindtype would be VarChar ([0-9]?{255} + '-' + '.') * 2
                }
                else {
                    ccb = _internalSize; 
                    if (!_internalShouldSerializeSize || (0x3fffffff <= ccb)||(ccb < 0)) {
                        Debug.Assert((ODBC32.SQL_C.WCHAR == _bindtype._sql_c) || (ODBC32.SQL_C.BINARY == _bindtype._sql_c), "not wchar or binary"); 
                        if ((ccb <= 0) && (0 != (ParameterDirection.Output & _internalDirection))) { 
                            throw ADP.UninitializedParameterSize(ordinal, _bindtype._type);
                        } 
                        if ((null == value) || Convert.IsDBNull(value)) {
                            if (_bindtype._sql_c == ODBC32.SQL_C.WCHAR) {
                                ccb = 2; // allow for null termination
                            } 
                            else {
                                ccb = 0; 
                            } 
                        }
                        else if (value is String) { 
                            ccb = (((String)value).Length - offset ) * 2 + 2;
                        }
                        else if (value is char[]) {
                            ccb = (((char[])value).Length - offset ) * 2 + 2; 
                        }
                        else if (value is byte[]) { 
                            ccb = ((byte[])value).Length - offset; 
                        }
#if DEBUG 
                        else { Debug.Assert(false, "not expecting this"); }
#endif
                        if ((0 != (ParameterDirection.Output & _internalDirection)) && (0x3fffffff <= _internalSize)) {
                            // restrict output parameters when user set Size to Int32.MaxValue 
                            // to the greater of intput size or 8K
                            ccb = Math.Max(ccb, 8 * 1024); // MDAC 69224 
                        } 
                    }
                    else if (ODBC32.SQL_C.WCHAR == _bindtype._sql_c) { 
                        if ((value is String) && (ccb < ((String)value).Length) && (_bindtype == _originalbindtype)) {
                            // silently truncate ... MDAC 84408 ... do not truncate upgraded values ... MDAC 84706
                            ccb = ((String)value).Length;
                        } 
                        ccb = (ccb * 2) + 2; // allow for null termination
                    } 
                    else if ((value is byte[]) && (ccb < ((byte[])value).Length) && (_bindtype == _originalbindtype)) { 
                        // silently truncate ... MDAC 84408 ... do not truncate upgraded values ... MDAC 84706
                        ccb = ((byte[])value).Length; 
                    }
                }
            }
            Debug.Assert((0 <= ccb) && (ccb < 0x3fffffff), "GetParameterSize: out of range " + ccb); 
            return ccb;
         } 
 
         private byte GetParameterPrecision(object value) {
            if (0 != _internalPrecision && value is decimal) { 
                // from qfe 762
                if (_internalPrecision<29) {
                    // from SqlClient ...
                    if (_internalPrecision != 0) { 
                        // devnote: If the userspecified precision (_internalPrecision) is less than the actual values precision
                        // we silently adjust the userspecified precision to the values precision. 
                        byte precision = ((SqlDecimal)(decimal)value).Precision; 
                        _internalPrecision = Math.Max(_internalPrecision, precision);   // silently adjust the precision
                    } 
                    return _internalPrecision;
                }
                return ADP.DecimalMaxPrecision;
            } 
            if ((null == value) || (value is Decimal) || Convert.IsDBNull(value)) { // MDAC 60882
                return ADP.DecimalMaxPrecision28; 
            } 
            return 0;
        } 


        private byte GetParameterScale(object value) {
 
            // For any value that is not decimal simply return the Scale
            // 
            if (!(value is decimal)) { 
                return _internalScale;
            } 

            // Determin the values scale
            // If the user specified a lower scale we return the user specified scale,
            // otherwise the values scale 
            //
            byte s = (byte)((Decimal.GetBits((Decimal)value)[3] & 0x00ff0000) >> 0x10); 
            if ((_internalScale > 0) && (_internalScale < s)){ 
                return _internalScale;
            } 
            return s;
        }

        //This is required for OdbcCommand.Clone to deep copy the parameters collection 
        object ICloneable.Clone() {
            return new OdbcParameter(this); 
        } 

        private void CopyParameterInternal () { 
            _internalValue = Value;
            // we should coerce the parameter value at this time.
            _internalPrecision = ShouldSerializePrecision() ? PrecisionInternal : ValuePrecision(_internalValue);
            _internalShouldSerializeSize = ShouldSerializeSize(); 
            _internalSize = _internalShouldSerializeSize ? Size : ValueSize(_internalValue);
            _internalDirection = Direction; 
            _internalScale = ShouldSerializeScale() ? ScaleInternal : ValueScale(_internalValue); 
            _internalOffset = Offset;
            _internalUserSpecifiedType = UserSpecifiedType; 
        }

        private void CloneHelper(OdbcParameter destination) {
            CloneHelperCore(destination); 
            destination._userSpecifiedType = _userSpecifiedType;
            destination._typemap = _typemap; 
            destination._parameterName = _parameterName; 
            destination._precision = _precision;
            destination._scale = _scale; 
            destination._hasScale = _hasScale;
        }

        internal void ClearBinding() { 
            if (!_userSpecifiedType) {
                _typemap = null; 
            } 
            _bindtype = null;
        } 

        internal void PrepareForBind(OdbcCommand command, short ordinal, ref int parameterBufferSize) {
            // make a snapshot of the current properties. Properties may change while we work on them
            // 
            CopyParameterInternal();
 
            object value  = ProcessAndGetParameterValue(); 
            int    offset = _internalOffset;
            int    size   = _internalSize; 
            ODBC32.SQL_C sql_c_type;


            // offset validation based on the values type 
            //
            if (offset > 0) { 
                if (value is string) { 
                    if (offset > ((string)value).Length) {
                        throw ADP.OffsetOutOfRangeException(); 
                    }
                }
                else if (value is char[]) {
                    if (offset > ((char[])value).Length) { 
                        throw ADP.OffsetOutOfRangeException();
                    } 
                } 
                else if (value is byte[]) {
                    if (offset > ((byte[])value).Length) { 
                        throw ADP.OffsetOutOfRangeException();
                    }
                }
                else { 
                    // for all other types offset has no meaning
                    // this is important since we might upgrade some types to strings 
                    offset = 0; 
                }
            } 

            // type support verification for certain data types
            //
            switch(_bindtype._sql_type) { 
                case ODBC32.SQL_TYPE.DECIMAL:
                case ODBC32.SQL_TYPE.NUMERIC: 
                    if ( 
                        !command.Connection.IsV3Driver                                      // for non V3 driver we always do the conversion
                        || !command.Connection.TestTypeSupport(ODBC32.SQL_TYPE.NUMERIC)     // otherwise we convert if the driver does not support numeric 
                        || command.Connection.TestRestrictedSqlBindType(_bindtype._sql_type)// or the type is not supported
                    ){
                        // No support for NUMERIC
                        // Change the type 
                        _bindtype = TypeMap._VarChar;
                        if ((null != value) && !Convert.IsDBNull(value)) { 
                            value = ((Decimal)value).ToString(CultureInfo.CurrentCulture); 
                            size = ((string)value).Length;
                            offset = 0; 
                        }
                    }
                    break;
                case ODBC32.SQL_TYPE.BIGINT: 
                    if (!command.Connection.IsV3Driver){
                        // No support for BIGINT 
                        // Change the type 
                        _bindtype = TypeMap._VarChar;
                        if ((null != value) && !Convert.IsDBNull(value)) { 
                            value = ((Int64)value).ToString(CultureInfo.CurrentCulture);
                            size = ((string)value).Length;
                            offset = 0;
                        } 
                    }
                    break; 
                case ODBC32.SQL_TYPE.WCHAR: // MDAC 68993 
                case ODBC32.SQL_TYPE.WVARCHAR:
                case ODBC32.SQL_TYPE.WLONGVARCHAR: 
                    if (value is Char) {
                        value = value.ToString();
                        size = ((string)value).Length;
                        offset = 0; 
                    }
                    if (!command.Connection.TestTypeSupport (_bindtype._sql_type)) { 
                        // No support for WCHAR, WVARCHAR or WLONGVARCHAR 
                        // Change the type
                        if (ODBC32.SQL_TYPE.WCHAR == _bindtype._sql_type) { _bindtype = TypeMap._Char; } 
                        else if (ODBC32.SQL_TYPE.WVARCHAR == _bindtype._sql_type) { _bindtype = TypeMap._VarChar; }
                        else if (ODBC32.SQL_TYPE.WLONGVARCHAR == _bindtype._sql_type) {
                            _bindtype = TypeMap._Text;
                        } 
                    }
                    break; 
            } // end switch 

            // Conversation from WCHAR to CHAR, VARCHAR or LONVARCHAR (AnsiString) is different for some providers 
            // we need to chonvert WCHAR to CHAR and bind as sql_c_type = CHAR
            //
            sql_c_type = _bindtype._sql_c;
 
            if (!command.Connection.IsV3Driver) {
                  if (sql_c_type == ODBC32.SQL_C.WCHAR) { 
                    sql_c_type = ODBC32.SQL_C.CHAR; 

                    if (null != value){ 
                        if (!Convert.IsDBNull(value) && value is string) {
                            int lcid = System.Globalization.CultureInfo.CurrentCulture.LCID;
                            CultureInfo culInfo = new CultureInfo(lcid);
                            Encoding cpe = System.Text.Encoding.GetEncoding(culInfo.TextInfo.ANSICodePage); 
                            value = cpe.GetBytes(value.ToString());
                            size = ((byte[])value).Length; 
                        } 
                    }
                } 
            };

            int cbParameterSize = GetParameterSize(value, offset, ordinal);      // count of bytes for the data, for SQLBindParameter
 
            // here we upgrade the datatypes if the given values size is bigger than the types columnsize
            // 
            switch(_bindtype._sql_type) { 
                case ODBC32.SQL_TYPE.VARBINARY: // MDAC 74372
                    // Note: per definition DbType.Binary does not support more than 8000 bytes so we change the type for binding 
                    if ((cbParameterSize > 8000))
                        { _bindtype = TypeMap._Image; } // will change to LONGVARBINARY
                    break;
                case ODBC32.SQL_TYPE.VARCHAR: // MDAC 74372 
                    // Note: per definition DbType.Binary does not support more than 8000 bytes so we change the type for binding
                    if ((cbParameterSize > 8000)) 
                        { _bindtype = TypeMap._Text; }  // will change to LONGVARCHAR 
                    break;
                case ODBC32.SQL_TYPE.WVARCHAR : // MDAC 75099 
                    // Note: per definition DbType.Binary does not support more than 8000 bytes so we change the type for binding
                    if ((cbParameterSize > 4000))
                        { _bindtype = TypeMap._NText; }  // will change to WLONGVARCHAR
                    break; 
            }
 
            _prepared_Sql_C_Type = sql_c_type; 
            _preparedOffset      = offset;
            _preparedSize        = size; 
            _preparedValue       = value;
            _preparedBufferSize  = cbParameterSize;
            _preparedIntOffset   = parameterBufferSize;
            _preparedValueOffset = _preparedIntOffset + IntPtr.Size; 
            parameterBufferSize += (cbParameterSize + IntPtr.Size);
        } 
 
        internal void Bind(OdbcStatementHandle hstmt, OdbcCommand command, short ordinal, CNativeBuffer parameterBuffer, bool allowReentrance) {
            ODBC32.RetCode  retcode; 
            ODBC32.SQL_C    sql_c_type = _prepared_Sql_C_Type;
            ODBC32.SQL_PARAM sqldirection = SqlDirectionFromParameterDirection();

            int offset      = _preparedOffset; 
            int size        = _preparedSize;
            object value    = _preparedValue; 
            int cbValueSize = GetValueSize(value, offset);             // count of bytes for the data 
            int cchSize     = GetColumnSize(value, offset, ordinal);   // count of bytes for the data, used to allocate the buffer length
            byte precision  = GetParameterPrecision(value); 
            byte scale      = GetParameterScale(value);
            int cbActual;

            HandleRef valueBuffer  = parameterBuffer.PtrOffset(_preparedValueOffset, _preparedBufferSize); 
            HandleRef intBuffer    = parameterBuffer.PtrOffset(_preparedIntOffset, IntPtr.Size);
 
            // for the numeric datatype we need to do some special case handling ... 
            //
            if (ODBC32.SQL_C.NUMERIC == sql_c_type) { 

                // for input/output parameters we need to adjust the scale of the input value since the convert function in
                // sqlsrv32 takes this scale for the output parameter (possible bug in sqlsrv32?)
                // 
                if ((ODBC32.SQL_PARAM.INPUT_OUTPUT == sqldirection) && (value is Decimal)) {
                    if (scale < _internalScale) { 
                        while (scale < _internalScale) { 
                            value = ((decimal)value ) * 10;
                            scale++; 
                        }
                    }
                }
                SetInputValue(value, sql_c_type, cbValueSize, precision, 0, parameterBuffer); 

                // for output parameters we need to write precision and scale to the buffer since the convert function in 
                // sqlsrv32 expects these values there (possible bug in sqlsrv32?) 
                //
                if (ODBC32.SQL_PARAM.INPUT != sqldirection) { 
                    parameterBuffer.WriteInt16(_preparedValueOffset, (short)(((ushort)scale << 8) | (ushort)precision));
                }
            }
            else { 
                SetInputValue(value, sql_c_type, cbValueSize, size, offset, parameterBuffer);
            } 
 

            // Try to reuse existing bindings if 
            //  the binding is valid (means we already went through binding all parameters)
            //  the parametercollection is bound already
            //  the bindtype ParameterType did not change (forced upgrade)
 
            if (!_hasChanged
                && (_boundSqlCType == sql_c_type) 
                && (_boundParameterType == _bindtype._sql_type) 
                && (_boundSize == cchSize)
                && (_boundScale == scale) 
                && (_boundBuffer == valueBuffer.Handle)
                && (_boundIntbuffer == intBuffer.Handle)
            ) {
                return; 
            }
 
            //SQLBindParameter 
            retcode = hstmt.BindParameter(
                                    ordinal,                    // Parameter Number 
                                    (short)sqldirection,        // InputOutputType
                                    sql_c_type,                 // ValueType
                                    _bindtype._sql_type,        // ParameterType
                                    (IntPtr)cchSize,            // ColumnSize 
                                    (IntPtr)scale,              // DecimalDigits
                                    valueBuffer,                // ParameterValuePtr 
                                    (IntPtr)_preparedBufferSize, 
                                    intBuffer);                 // StrLen_or_IndPtr
 
            if (ODBC32.RetCode.SUCCESS != retcode) {
                if ("07006" == command.GetDiagSqlState()) {
                    Bid.Trace(" Call to BindParameter returned errorcode [07006]\n");
                    command.Connection.FlagRestrictedSqlBindType(_bindtype._sql_type); 
                    if (allowReentrance) {
                        this.Bind(hstmt, command, ordinal, parameterBuffer, false); 
                        return; 
                    }
                } 
                command.Connection.HandleError(hstmt, retcode);
            }
            _hasChanged = false;
            _boundSqlCType = sql_c_type; 
            _boundParameterType = _bindtype._sql_type;
            _boundSize = cchSize; 
            _boundScale = scale; 
            _boundBuffer = valueBuffer.Handle;
            _boundIntbuffer = intBuffer.Handle; 

            if (ODBC32.SQL_C.NUMERIC == sql_c_type) {
                OdbcDescriptorHandle hdesc = command.GetDescriptorHandle(ODBC32.SQL_ATTR.APP_PARAM_DESC);
                // descriptor handle is cached on command wrapper, don't release it 

                // Set descriptor Type 
                // 
                //SQLSetDescField(hdesc, i+1, SQL_DESC_TYPE, (void *)SQL_C_NUMERIC, 0);
                retcode = hdesc.SetDescriptionField1(ordinal, ODBC32.SQL_DESC.TYPE, (IntPtr)ODBC32.SQL_C.NUMERIC); 

                if (ODBC32.RetCode.SUCCESS != retcode) {
                    command.Connection.HandleError(hstmt, retcode);
                } 

 
                // Set precision 
                //
                cbActual= (int)precision; 
                //SQLSetDescField(hdesc, i+1, SQL_DESC_PRECISION, (void *)precision, 0);
                retcode = hdesc.SetDescriptionField1(ordinal, ODBC32.SQL_DESC.PRECISION, (IntPtr)cbActual);

                if (ODBC32.RetCode.SUCCESS != retcode) { 
                    command.Connection.HandleError(hstmt, retcode);
                } 
 

                // Set scale 
                //
                // SQLSetDescField(hdesc, i+1, SQL_DESC_SCALE,  (void *)llen, 0);
                cbActual= (int)scale;
                retcode = hdesc.SetDescriptionField1(ordinal, ODBC32.SQL_DESC.SCALE, (IntPtr)cbActual); 

                if (ODBC32.RetCode.SUCCESS != retcode) { 
                    command.Connection.HandleError(hstmt, retcode); 
                }
 
                // Set data pointer
                //
                // SQLSetDescField(hdesc, i+1, SQL_DESC_DATA_PTR,  (void *)&numeric, 0);
                retcode = hdesc.SetDescriptionField2(ordinal, ODBC32.SQL_DESC.DATA_PTR, valueBuffer); 

                if (ODBC32.RetCode.SUCCESS != retcode) { 
                    command.Connection.HandleError(hstmt, retcode); 
                }
            } 
        }

        internal void GetOutputValue(CNativeBuffer parameterBuffer) { //Handle any output params
 
            // No value is available if the user fiddles with the parameters properties
            // 
            if (_hasChanged) return; 

            if ((null != _bindtype) && (_internalDirection != ParameterDirection.Input)) { 

               TypeMap typemap = _bindtype;
                _bindtype = null;
 
                int cbActual = (int)parameterBuffer.ReadIntPtr(_preparedIntOffset);
                if (ODBC32.SQL_NULL_DATA == cbActual) { 
                    Value = DBNull.Value; 
                }
                else if ((0 <= cbActual)  || (cbActual == ODBC32.SQL_NTS)){ // safeguard 
                    Value = parameterBuffer.MarshalToManaged(_preparedValueOffset, _boundSqlCType, cbActual);

                if (_boundSqlCType== ODBC32.SQL_C.CHAR) {
                    if ((null != Value) && !Convert.IsDBNull(Value)) { 
                        int lcid = System.Globalization.CultureInfo.CurrentCulture.LCID;
                        CultureInfo culInfo = new CultureInfo(lcid); 
                        Encoding cpe = System.Text.Encoding.GetEncoding(culInfo.TextInfo.ANSICodePage); 
                        Value = cpe.GetString((Byte[])Value);
                    } 
                }

                    if ((typemap != _typemap) && (null != Value) && !Convert.IsDBNull(Value) && (Value.GetType() != _typemap._type)) {
                        Debug.Assert(ODBC32.SQL_C.NUMERIC == _typemap._sql_c, "unexpected"); 
                        Value = Decimal.Parse((string)Value, System.Globalization.CultureInfo.CurrentCulture);
                    } 
                } 
            }
        } 

        private object ProcessAndGetParameterValue() {
            object value = _internalValue;
            if (_internalUserSpecifiedType) { 
                if ((null != value) && !Convert.IsDBNull(value)) {
                    Type valueType = value.GetType(); 
                    if (!valueType.IsArray) { 
                        if (valueType != _typemap._type) {
                            try { 
                                value = Convert.ChangeType (value, _typemap._type, (System.IFormatProvider)null);
                            }
                            catch(Exception e) {
                                // Don't know which exception to expect from ChangeType so we filter out the serious ones 
                                //
                                if (!ADP.IsCatchableExceptionType(e)) { 
                                    throw; 
                                }
                                throw ADP.ParameterConversionFailed(value, _typemap._type, e); // WebData 75433 
                            }
                        }
                    }
                    else if (valueType == typeof(char[])) { 
                        value = new String((char[])value);
                    } 
                } 
            }
            else if (null == _typemap) { 
                if ((null == value) || Convert.IsDBNull (value)) {
                    _typemap = TypeMap._NVarChar; // default type
                }
                else { 
                    Type type = value.GetType ();
 
                    _typemap = TypeMap.FromSystemType (type); 
                }
            } 
            Debug.Assert(null != _typemap, "GetParameterValue: null _typemap");
            _originalbindtype = _bindtype = _typemap;
            return value;
        } 

        private void PropertyChanging() { 
            _hasChanged = true; 
        }
 
        private void PropertyTypeChanging() {
            PropertyChanging();
            //CoercedValue = null;
        } 

        internal void SetInputValue(object value, ODBC32.SQL_C sql_c_type, int cbsize, int sizeorprecision, int offset, CNativeBuffer parameterBuffer) { //Handle any input params 
            if((ParameterDirection.Input == _internalDirection) || (ParameterDirection.InputOutput == _internalDirection)) { 
                //Note: (lang) "null" means to use the servers default (not DBNull).
                //We probably should just not have bound this parameter, period, but that 
                //would mess up the users question marks, etc...
                if((null == value)) {
                    parameterBuffer.WriteIntPtr(_preparedIntOffset, (IntPtr)ODBC32.SQL_DEFAULT_PARAM);
                } 
                else if(Convert.IsDBNull(value)) {
                    parameterBuffer.WriteIntPtr(_preparedIntOffset, (IntPtr)ODBC32.SQL_NULL_DATA); 
                } 
                else {
                    switch(sql_c_type) { 
                    case ODBC32.SQL_C.CHAR:
                    case ODBC32.SQL_C.WCHAR:
                    case ODBC32.SQL_C.BINARY:
                        //StrLen_or_IndPtr is ignored except for Character or Binary or data. 
                        parameterBuffer.WriteIntPtr(_preparedIntOffset, (IntPtr)cbsize);
                        break; 
                    default: 
                        parameterBuffer.WriteIntPtr(_preparedIntOffset, IntPtr.Zero);
                        break; 

                    }

                    //Place the input param value into the native buffer 
                    parameterBuffer.MarshalToNative(_preparedValueOffset, value, sql_c_type, sizeorprecision, offset);
                } 
            } 
            else {
                // always set ouput only and return value parameter values to null when executing 
                _internalValue = null;

                //Always initialize the intbuffer (for output params).  Since we need to know
                //if/when the parameters are available for output. (ie: when is the buffer valid...) 
                //if (_sqldirection != ODBC32.SQL_PARAM.INPUT)
                parameterBuffer.WriteIntPtr(_preparedIntOffset, (IntPtr)ODBC32.SQL_NULL_DATA); 
            } 
        }
 
        private ODBC32.SQL_PARAM SqlDirectionFromParameterDirection () {
            switch(_internalDirection) {
                case ParameterDirection.Input:
                    return ODBC32.SQL_PARAM.INPUT; 
                case ParameterDirection.Output:
                case ParameterDirection.ReturnValue: 
                    //ODBC doesn't seem to distinguish between output and return value 
                    //as SQL_PARAM_RETURN_VALUE fails with "Invalid parameter type"
                    return ODBC32.SQL_PARAM.OUTPUT; 
                case ParameterDirection.InputOutput:
                    return ODBC32.SQL_PARAM.INPUT_OUTPUT;
                default:
                    Debug.Assert (false, "Unexpected Direction Property on Parameter"); 
                    return ODBC32.SQL_PARAM.INPUT;
            } 
        } 

        [ 
        RefreshProperties(RefreshProperties.All),
        ResCategoryAttribute(Res.DataCategory_Data),
        ResDescriptionAttribute(Res.DbParameter_Value),
        TypeConverterAttribute(typeof(StringConverter)), 
        ]
        override public object Value { // V1.2.3300, XXXParameter V1.0.3300 
            get { 
                return _value;
            } 
            set {
                _coercedValue = null;
                _value = value;
            } 
        }
 
        private byte ValuePrecision(object value) { 
            return ValuePrecisionCore(value);
        } 

        private byte ValueScale(object value) {
            return ValueScaleCore(value);
        } 

        private int ValueSize(object value) { 
            return ValueSizeCore(value); 
        }
 
        // implemented as nested class to take advantage of the private/protected ShouldSerializeXXX methods
        sealed internal class OdbcParameterConverter : ExpandableObjectConverter {

            // converter classes should have public ctor 
            public OdbcParameterConverter() {
            } 
 
            public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType) {
                if (destinationType == typeof(System.ComponentModel.Design.Serialization.InstanceDescriptor)) { 
                    return true;
                }
                return base.CanConvertTo(context, destinationType);
            } 

            public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType) { 
                if (destinationType == null) { 
                    throw ADP.ArgumentNull("destinationType");
                } 

                if (destinationType == typeof(System.ComponentModel.Design.Serialization.InstanceDescriptor) && value is OdbcParameter) {
                    OdbcParameter p = (OdbcParameter)value;
 
                    // MDAC 67321 - reducing parameter generated code
                    int flags = 0; // if part of the collection - the parametername can't be empty 
 
                    if (OdbcType.NChar != p.OdbcType) {
                        flags |= 1; 
                    }
                    if (p.ShouldSerializeSize()) {
                        flags |= 2;
                    } 
                    if (!ADP.IsEmpty(p.SourceColumn)) {
                        flags |= 4; 
                    } 
                    if (null != p.Value) {
                        flags |= 8; 
                    }
                    if ((ParameterDirection.Input != p.Direction) || p.IsNullable
                        || p.ShouldSerializePrecision() || p.ShouldSerializeScale()
                        || (DataRowVersion.Current != p.SourceVersion)) { 
                        flags |= 16; // V1.0 everything
                    } 
                    if (p.SourceColumnNullMapping) { 
                        flags |= 32; // v2.0 everything
                    } 

                    Type[] ctorParams;
                    object[] ctorValues;
                    switch(flags) { 
                    case  0: // ParameterName
                    case  1: // SqlDbType 
                        ctorParams = new Type[] { typeof(string), typeof(OdbcType) }; 
                        ctorValues = new object[] { p.ParameterName, p.OdbcType };
                        break; 
                    case  2: // Size
                    case  3: // Size, SqlDbType
                        ctorParams = new Type[] { typeof(string), typeof(OdbcType), typeof(int) };
                        ctorValues = new object[] { p.ParameterName, p.OdbcType, p.Size }; 
                        break;
                    case  4: // SourceColumn 
                    case  5: // SourceColumn, SqlDbType 
                    case  6: // SourceColumn, Size
                    case  7: // SourceColumn, Size, SqlDbType 
                        ctorParams = new Type[] { typeof(string), typeof(OdbcType), typeof(int), typeof(string) };
                        ctorValues = new object[] { p.ParameterName, p.OdbcType, p.Size, p.SourceColumn };
                        break;
                    case  8: // Value 
                        ctorParams = new Type[] { typeof(string), typeof(object) };
                        ctorValues = new object[] { p.ParameterName, p.Value }; 
                        break; 
                    default:
                        if (0 == (32 & flags)) { // V1.0 everything 
                            ctorParams = new Type[] {
                                typeof(string), typeof(OdbcType), typeof(int), typeof(ParameterDirection),
                                typeof(bool), typeof(byte), typeof(byte), typeof(string),
                                typeof(DataRowVersion), typeof(object) }; 
                            ctorValues = new object[] {
                                p.ParameterName, p.OdbcType,  p.Size, p.Direction, 
                                p.IsNullable, p.PrecisionInternal, p.ScaleInternal, p.SourceColumn, 
                                p.SourceVersion, p.Value };
                        } 
                        else { // v2.0 everything - round trip all browsable properties + precision/scale
                            ctorParams = new Type[] {
                                typeof(string), typeof(OdbcType), typeof(int), typeof(ParameterDirection),
                                typeof(byte), typeof(byte), 
                                typeof(string), typeof(DataRowVersion), typeof(bool),
                                typeof(object) }; 
                            ctorValues = new object[] { 
                                p.ParameterName, p.OdbcType,  p.Size, p.Direction,
                                p.PrecisionInternal, p.ScaleInternal, 
                                p.SourceColumn, p.SourceVersion, p.SourceColumnNullMapping,
                                p.Value };
                        }
                        break; 
                    }
                    System.Reflection.ConstructorInfo ctor = typeof(OdbcParameter).GetConstructor(ctorParams); 
                    if (null != ctor) { 
                        return new System.ComponentModel.Design.Serialization.InstanceDescriptor(ctor, ctorValues);
                    } 
                }
                return base.ConvertTo(context, culture, value, destinationType);
            }
        } 
    }
} 

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

Link Menu

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