OracleParameterBinding.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 / DataOracleClient / System / Data / OracleClient / OracleParameterBinding.cs / 3 / OracleParameterBinding.cs

                            //------------------------------------------------------------------------------ 
// 
//      Copyright (c) Microsoft Corporation.  All rights reserved.
// 
// [....] 
//-----------------------------------------------------------------------------
 
namespace System.Data.OracleClient 
{
    using System; 
    using System.ComponentModel;
    using System.Data;
    using System.Data.Common;
    using System.Data.SqlTypes; 
    using System.Diagnostics;
    using System.IO; 
    using System.Runtime.InteropServices; 

    //--------------------------------------------------------------------- 
    // OracleParameterBinding
    //
    //  this class is meant to handle the parameter binding for an
    //  single command object (since parameters can be bound concurrently 
    //  to multiple command objects)
    // 
    sealed internal class OracleParameterBinding { 

        OracleCommand       _command;                   // the command that this binding is for 
        OracleParameter     _parameter;                 // the parameter that this binding is for
        object              _coercedValue;              // _parameter.CoercedValue;

        MetaType            _bindingMetaType;           // meta type of the binding, in case it needs adjustment (String bound as CLOB, etc...) 
        OciBindHandle       _bindHandle;                // the bind handle, once this has been bound
        int                 _bindSize;                  // number of bytes/characters to reserve on the server 
        int                 _bufferLength;              // number of bytes required to bind the value 
        int                 _indicatorOffset;           // offset from the start of the parameter buffer to the indicator binding (see OCI.INDICATOR)
        int                 _lengthOffset;              // offset from the start of the parameter buffer to the length binding 
        int                 _valueOffset;               // offset from the start of the parameter buffer to the value binding
        bool                _bindAsUCS2;                // true when we should bind this as UCS2
        bool                _freeTemporaryLob;          // true when we've allocated a temporary lob (in _coercedValue) that must be freed.
 
        OciStatementHandle  _descriptor;                // ref cursor handle for ref cursor types.
        OciLobLocator       _locator;                   // lob locator for BFile and Lob types. 
        OciDateTimeDescriptor _dateTimeDescriptor;      // OCI datetime descriptor to hold date time values 

        // Construct an "empty" parameter 
        internal OracleParameterBinding (OracleCommand command, OracleParameter parameter) {
            _command   = command;
            _parameter = parameter;
        } 

        internal OracleParameter Parameter { 
            get { 
                return _parameter;
            } 
        }

        internal void Bind (OciStatementHandle statementHandle, NativeBuffer parameterBuffer, OracleConnection connection, ref bool mustRelease, ref SafeHandle handleToBind) {
            //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 
            // NOTE: You must have called DangerousAddRef on the parameterBuffer
            //       before calling this method, or you run the risk of allowing 
            //       Handle Recycling to occur! 
            //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
 
            IntPtr          h;

            // Don't bother with parameters where the user asks for the default value.
            if ( !IsDirection(Parameter, ParameterDirection.Output) && null == Parameter.Value) { 
                return;
            } 
            string          parameterName  = Parameter.ParameterName; 
            OciErrorHandle      errorHandle    = connection.ErrorHandle;
            OciServiceContextHandle     serviceContextHandle =  connection.ServiceContextHandle; 

            int             valueLength = 0;    // number of BYTES written to the valueLocation for the INPUT value.
            int             bufferLength;       // number of BYTES we tell Oracle that we have provided space for in our buffer (may be shorter than actual buffer)
            OCI.INDICATOR   indicatorValue  = OCI.INDICATOR.OK; 

            OCI.DATATYPE    ociType = _bindingMetaType.OciType; 
 
            IntPtr          indicatorLocation   = parameterBuffer.DangerousGetDataPtr(_indicatorOffset);
            IntPtr          lengthLocation      = parameterBuffer.DangerousGetDataPtr(_lengthOffset); 
            IntPtr          valueLocation       = parameterBuffer.DangerousGetDataPtr(_valueOffset);

            OciHandle.SafeDispose(ref _dateTimeDescriptor);
 
            // First, write the value to the parameter buffer and get the number
            // of bytes written. 
 
            if (IsDirection(Parameter, ParameterDirection.Input)) {
                if (ADP.IsNull(_coercedValue)) { 
                    indicatorValue = OCI.INDICATOR.ISNULL;

                    // for TIMESTAMP types, we still have to provide the descriptor, even if the value is null
                    switch (ociType) 
                    {
                        case OCI.DATATYPE.INT_TIMESTAMP: 
                        case OCI.DATATYPE.INT_TIMESTAMP_TZ: 
                        case OCI.DATATYPE.INT_TIMESTAMP_LTZ:
                            _dateTimeDescriptor = OracleDateTime.CreateEmptyDescriptor(ociType, connection); 
                            handleToBind = _dateTimeDescriptor;
                            break;
                    }
                } 
                else {
                    valueLength = PutOracleValue( 
                                            _coercedValue, 
                                            parameterBuffer,
                                            _valueOffset, 
                                            _bindingMetaType,
                                            connection,
                                            ref handleToBind);
                } 
            }
            else { 
                Debug.Assert(IsDirection(Parameter, ParameterDirection.Output), "non-output output parameter?"); 

                if (_bindingMetaType.IsVariableLength) 
                    valueLength = 0;                // Output-only values never have an input length...
                else
                    valueLength = _bufferLength;    // ...except when they're fixed length, to avoid ORA-01459 errors
 
                OciLobLocator.SafeDispose(ref _locator);
                OciHandle.SafeDispose(ref _descriptor); 
 
                switch (ociType) {
                case OCI.DATATYPE.BFILE: 
                case OCI.DATATYPE.BLOB:
                case OCI.DATATYPE.CLOB:
                    _locator = new OciLobLocator(connection, _bindingMetaType.OracleType);
                    handleToBind = _locator.Descriptor; 
                    break;
 
                case OCI.DATATYPE.RSET: 
                    _descriptor = new OciStatementHandle(serviceContextHandle);
                    handleToBind = _descriptor; 
                    break;

                case OCI.DATATYPE.INT_TIMESTAMP:
                case OCI.DATATYPE.INT_TIMESTAMP_TZ: 
                case OCI.DATATYPE.INT_TIMESTAMP_LTZ:
                    _dateTimeDescriptor = OracleDateTime.CreateEmptyDescriptor(ociType, connection); 
                    handleToBind = _dateTimeDescriptor; 
                    break;
                } 
            }

            // We need to add-ref the handle so it can't be released somehow
            // by another thread while we're executing.  Only after we do that 
            // can we write it to the buffer for the Oracle to use during the
            // Execute.  The caller is required to provide storage for the 
            // handleToBind and ensure that the DangerousRelease is called 
            // in it's CER.
            if (null != handleToBind) { 
                handleToBind.DangerousAddRef(ref mustRelease);
                parameterBuffer.WriteIntPtr(_valueOffset, handleToBind.DangerousGetHandle());
            }
 
            // Second, write the indicatorValue (whether the parameter has a null
            // value or not) to the parameter buffer. 
 
            parameterBuffer.WriteInt16(_indicatorOffset, (Int16)indicatorValue);
 
            // Third, write the length of the input value to the parameter buffer.
            //
            // Don't bind a length value for LONGVARCHAR or LONGVARRAW data, or you'll end
            // up with ORA-01098: program Interface error during Long Insert\nORA-01458: invalid length inside variable character string 
            // errors.
 
            if (OCI.DATATYPE.LONGVARCHAR == ociType || OCI.DATATYPE.LONGVARRAW  == ociType) { 
                lengthLocation = IntPtr.Zero;
            } 
            else {
                // When we're binding this parameter as UCS2, the length we specify
                // must be in characters, not in bytes.
                if (_bindAsUCS2) 
                    parameterBuffer.WriteInt32(_lengthOffset,  (Int32)(valueLength/ADP.CharSize));
                else 
                    parameterBuffer.WriteInt32(_lengthOffset,  (Int32)valueLength); 
            }
 
            // Fourth, compute the number of bytes in the parameter buffer that we need
            // to report to Oracle, depending on whether it is an input-only or any type
            // of output parameter. For input-only parameters, we only need to report
            // the actual value's size, but for output parameters, we have to report the 
            // full buffer size to avoid truncation of data, should the output value
            // exceed the length of the input value. 
 
            if (IsDirection(Parameter, ParameterDirection.Output))
                bufferLength = _bufferLength; 
            else
                bufferLength = valueLength;

            // bind type is different for INT_TIMESTAMP* since we bind them as Oracle's public TIMESTAMP* ones and use descriptors 
            OCI.DATATYPE bindAsOciType = ociType;
            switch (ociType) { 
                case OCI.DATATYPE.INT_TIMESTAMP: 
                    bindAsOciType = OCI.DATATYPE.TIMESTAMP;
                    break; 
                case OCI.DATATYPE.INT_TIMESTAMP_TZ:
                    bindAsOciType = OCI.DATATYPE.TIMESTAMP_TZ;
                    break;
                case OCI.DATATYPE.INT_TIMESTAMP_LTZ: 
                    bindAsOciType = OCI.DATATYPE.TIMESTAMP_LTZ;
                    break; 
            } 

            // Finally, tell Oracle about our parameter. 

            int rc = TracedNativeMethods.OCIBindByName(
                                statementHandle,
                                out h, 
                                errorHandle,
                                parameterName, 
                                parameterName.Length, 
                                valueLocation,
                                bufferLength, 
                                bindAsOciType,
                                indicatorLocation,
                                lengthLocation,
                                OCI.MODE.OCI_DEFAULT 
                                );
 
            if (rc != 0) 
                _command.Connection.CheckError(errorHandle, rc);
 
            _bindHandle = new OciBindHandle(statementHandle, h);

#if TRACEPARAMETERVALUES
            if (null != _coercedValue) { 
                SafeNativeMethods.OutputDebugStringW("Value = '" + _coercedValue.ToString() + "'\n");
            } 
#endif //TRACEPARAMETERVALUES 

            // OK, character bindings have a few extra things we need to do to 
            // deal with character sizes and alternate character sets.

            if (_bindingMetaType.IsCharacterType) {
                // To avoid problems when our buffer is larger than the maximum number 
                // of characters, we use OCI_ATTR_MAXCHAR_SIZE to limit the number of
                // characters that will be used.  (Except on Oracle8i clients where it 
                // isn't available) 
                if (OCI.ClientVersionAtLeastOracle9i
                        && IsDirection(Parameter, ParameterDirection.Output)) 
                    _bindHandle.SetAttribute(OCI.ATTR.OCI_ATTR_MAXCHAR_SIZE, (int)_bindSize, errorHandle);

                if ((bufferLength > _bindingMetaType.MaxBindSize / ADP.CharSize)
                        || (!OCI.ClientVersionAtLeastOracle9i && _bindingMetaType.UsesNationalCharacterSet))    // need to specify MAXDATA_SIZE for OCI8 UCS2 bindings to work 
                    _bindHandle.SetAttribute(OCI.ATTR.OCI_ATTR_MAXDATA_SIZE, (int)_bindingMetaType.MaxBindSize, errorHandle);
 
                // NOTE:    the order is important here; setting charsetForm will 
                //          reset charsetId (I found this out the hard way...)
                if (_bindingMetaType.UsesNationalCharacterSet) 
                    _bindHandle.SetAttribute(OCI.ATTR.OCI_ATTR_CHARSET_FORM, (int)OCI.CHARSETFORM.SQLCS_NCHAR, errorHandle);

                // NOTE:    the order is important here; setting charsetForm will
                //          reset charsetId (I found this out the hard way...) 
                if (_bindAsUCS2)
                    _bindHandle.SetAttribute(OCI.ATTR.OCI_ATTR_CHARSET_ID, (int)OCI.CHARSETID.OCI_UTF16ID, errorHandle); 
            } 
            GC.KeepAlive(parameterBuffer);
        } 

        private OracleLob CreateTemporaryLobForValue(OracleConnection connection, OracleType oracleType, object value) {
            switch (oracleType) {
            case OracleType.BFile: 
                // Note that we can't really construct a temporary BFILE, so we
                // construct a BLOB instead. This is safe because Oracle won't 
                // let you write to a BFILE, so the caller is using it as an Input 
                // parameter.
                oracleType = OracleType.Blob; 
                break;
            case OracleType.Blob:
            case OracleType.Clob:
            case OracleType.NClob: 
                break;
 
            default: 
                throw ADP.InvalidLobType(oracleType);
            } 

            OracleLob tempLob = new OracleLob(connection, oracleType);

            byte[] byteArrayValue = value as byte[]; 
            if (null != byteArrayValue) {
                tempLob.Write(byteArrayValue,0,byteArrayValue.Length); 
            } 
            else {
                System.Text.Encoding UnicodeWithoutBOMs = new System.Text.UnicodeEncoding(false, false);    // Oracle won't put in BOMs, so neither should we... 
                tempLob.Seek(0,SeekOrigin.Begin);
                StreamWriter sw = new StreamWriter(tempLob, UnicodeWithoutBOMs);
                sw.Write(value);
                sw.Flush(); 
            }
            return tempLob; 
        } 

        internal object GetOutputValue( 
                NativeBuffer        parameterBuffer,
                OracleConnection    connection,         // connection, so we can create LOB values
                bool                needCLSType
                ) { 

            object result; 
            //  Returns an object that contains the value of the column in the 
            //  specified row buffer.  This method returns Oracle-typed objects.
 
            if (parameterBuffer.ReadInt16(_indicatorOffset) == (Int16)OCI.INDICATOR.ISNULL)
                return DBNull.Value;

            switch (_bindingMetaType.OciType) { 
                case OCI.DATATYPE.FLOAT:
                case OCI.DATATYPE.INTEGER: 
                case OCI.DATATYPE.UNSIGNEDINT: 
                    result = parameterBuffer.PtrToStructure(_valueOffset, _bindingMetaType.BaseType);
                    return result; 

                case OCI.DATATYPE.BFILE:
                    result = new OracleBFile(_locator);
                    return result; 

                case OCI.DATATYPE.RAW: 
                case OCI.DATATYPE.LONGRAW: 
                case OCI.DATATYPE.LONGVARRAW:
                    result = new OracleBinary(parameterBuffer, _valueOffset, _lengthOffset, _bindingMetaType); 
                    if (needCLSType) {
                        object newresult = ((OracleBinary)result).Value;
                        result = newresult;
                    } 
                    return result;
 
                case OCI.DATATYPE.RSET: 
                    result = new OracleDataReader(connection, _descriptor);
                    return result; 

                case OCI.DATATYPE.DATE:
                    result = new OracleDateTime(parameterBuffer, _valueOffset, _lengthOffset, _bindingMetaType, connection);
                    if (needCLSType) { 
                        object newresult = ((OracleDateTime)result).Value;
                        result = newresult; 
                    } 
                    return result;
 
                case OCI.DATATYPE.INT_TIMESTAMP:
                case OCI.DATATYPE.INT_TIMESTAMP_TZ:
                case OCI.DATATYPE.INT_TIMESTAMP_LTZ:
                    result = new OracleDateTime(_dateTimeDescriptor, _bindingMetaType, connection); 
                    if (needCLSType) {
                        object newresult = ((OracleDateTime)result).Value; 
                        result = newresult; 
                    }
                    return result; 

                case OCI.DATATYPE.BLOB:
                case OCI.DATATYPE.CLOB:
                    result = new OracleLob(_locator); 
                    return result;
 
                case OCI.DATATYPE.INT_INTERVAL_YM: 
                    result = new OracleMonthSpan(parameterBuffer, _valueOffset);
                    if (needCLSType) { 
                        object newresult = ((OracleMonthSpan)result).Value;
                        result = newresult;
                    }
                    return result; 

                case OCI.DATATYPE.VARNUM: 
                    result = new OracleNumber(parameterBuffer, _valueOffset); 
                    if (needCLSType) {
                        object newresult = ((OracleNumber)result).Value; 
                        result = newresult;
                    }
                    return result;
 
                case OCI.DATATYPE.CHAR:
                case OCI.DATATYPE.VARCHAR2: 
                case OCI.DATATYPE.LONG: 
                case OCI.DATATYPE.LONGVARCHAR:
                    result = new OracleString(parameterBuffer, 
                                            _valueOffset,
                                            _lengthOffset,
                                            _bindingMetaType,
                                            connection, 
                                            _bindAsUCS2,
                                            true 
                                            ); 
                    int size = _parameter.Size;
                    if (0 != size && size < ((OracleString)result).Length) { 
                        string truncatedResult = ((OracleString)result).Value.Substring(0,size);
                        if (needCLSType)
                            result = truncatedResult;
                        else 
                            result = new OracleString(truncatedResult);
                    } 
                    else if (needCLSType) { 
                        object newresult = ((OracleString)result).Value;
                        result = newresult; 
                    }
                    return result;

                case OCI.DATATYPE.INT_INTERVAL_DS: 
                    result = new OracleTimeSpan(parameterBuffer, _valueOffset);
                    if (needCLSType) { 
                        object newresult = ((OracleTimeSpan)result).Value; 
                        result = newresult;
                    } 
                    return result;

            }
            throw ADP.TypeNotSupported(_bindingMetaType.OciType); 

        } 
 
        internal void Dispose() {
            OciHandle.SafeDispose(ref _bindHandle); 

            // Make sure we clean up any temporary lob we may have constructed
            // so they don't leak.
            if (_freeTemporaryLob) { 
                OracleLob temporaryLob = _coercedValue as OracleLob;
                if (null != temporaryLob) { 
                    temporaryLob.Free(); 
                }
            } 
        }

        static internal bool IsDirection(IDataParameter value, ParameterDirection condition) {
            return (condition == (condition & value.Direction)); 
        }
 
        private bool IsEmpty(object value) { 
            bool result = false;
 
            if (value is string) {
                result = (0 == ((string) value).Length);
            }
            if (value is OracleString) { 
                result = (0 == ((OracleString) value).Length);
            } 
            if (value is char[]) { 
                result = (0 == ((char[]) value).Length);
            } 

            if (value is byte[]) {
                result = (0 == ((byte[]) value).Length);
            } 
            if (value is OracleBinary) {
                result = (0 == ((OracleBinary) value).Length); 
            } 
            return result;
        } 

        internal void PostExecute (NativeBuffer parameterBuffer, OracleConnection connection) { // connection, so we can create LOB values
            OracleParameter parameter = Parameter;
            if (IsDirection(parameter, ParameterDirection.Output) 
             || IsDirection(parameter, ParameterDirection.ReturnValue)) {
                bool needCLSType = true; 
                if (IsDirection(parameter, ParameterDirection.Input)) { 
                    object inputValue = parameter.Value;
 
                    if (inputValue is INullable) {
                        needCLSType = false;
                    }
                } 
                parameter.Value = GetOutputValue(parameterBuffer, connection, needCLSType);
            } 
        } 

        internal void PrepareForBind (OracleConnection connection, ref int offset) { 
            OracleParameter parameter = Parameter;
            bool useLONGBinding = false;

            object value = parameter.Value; 

            // Don't bother with parameters where the user asks for the default value. 
            if ( !IsDirection(parameter, ParameterDirection.Output) && (null == value)) { 
                _bufferLength = 0;
                return; 
            }

            _bindingMetaType = parameter.GetMetaType(value);
 
            // We currently don't support binding a REF CURSOR as an input
            // parameter; that is for a future release. 
            if (OCI.DATATYPE.RSET == _bindingMetaType.OciType && ADP.IsDirection(parameter.Direction, ParameterDirection.Input)) 
                throw ADP.InputRefCursorNotSupported(parameter.ParameterName);
 
            // Make sure we have a coerced value, if we haven't already done
            // so, then save it.
            parameter.SetCoercedValueInternal(value, _bindingMetaType);
            _coercedValue = parameter.GetCoercedValueInternal(); 

            // WebData 103336 - When the customer requests that we use a LOB we 
            // need to use a LOB, so that it can be processed by PL/SQL, which 
            // can't handle values larger than 32000 bytes.  When they don't pass
            // us a LOB or a BFILE as the value, we silently construct a 
            // temporary LOB for them.  This is necessary for DataAdapter.Update.
            switch (_bindingMetaType.OciType) {
            case OCI.DATATYPE.BFILE:
            case OCI.DATATYPE.BLOB: 
            case OCI.DATATYPE.CLOB:
                if (!ADP.IsNull(_coercedValue) && !(_coercedValue is OracleLob || _coercedValue is OracleBFile)) { 
                    // WebData 104205 - Except I forgot that you have to be in a 
                    // transaction to write to a LOB. Since we don't want to break
                    // people that currently work outside of a transaction, we 
                    // need to limit when we use temporary LOBs to when we already
                    // have a transaction.  Other than that, they're out of luck.
                    if (connection.HasTransaction) {
                        _freeTemporaryLob = true; 
                        _coercedValue = CreateTemporaryLobForValue(connection, _bindingMetaType.OracleType, _coercedValue);
                    } 
                    else { 
                        _bindingMetaType = MetaType.GetMetaTypeForType(_bindingMetaType.DbType);
                        useLONGBinding = true; 
                    }
                }
                break;
            } 

            // For fixed-width types, we take the bind size from the meta type 
            // information; if it's zero, then the type must be variable width 
            // (or it's an output parameter) and we require that they specify a
            // size. 

            _bindSize = _bindingMetaType.BindSize;

            if ((IsDirection(parameter, ParameterDirection.Output) 
                                && _bindingMetaType.IsVariableLength)   // they must specify a size for variable-length output parameters...
                || (0 == _bindSize && !ADP.IsNull(_coercedValue))       // ...or if it's a non-null, variable-length input paramter... 
                || (_bindSize > short.MaxValue) ) {                     // ...or if the parameter type's maximum size is huge. 

                int size = parameter.BindSize; 

                if (0 != size)
                    _bindSize = size;
 
                if ((0 == _bindSize || MetaType.LongMax == _bindSize) && !IsEmpty(_coercedValue))
                    throw ADP.ParameterSizeIsMissing(parameter.ParameterName, _bindingMetaType.BaseType); 
            } 

            // Now determine the number of bytes we require in the buffer. For 
            // character types, we must adjust for the size of the characters that
            // we will bind.

            _bufferLength = _bindSize; 

            if (_bindingMetaType.IsCharacterType && connection.ServerVersionAtLeastOracle8) { 
                _bindAsUCS2 = true; 
                _bufferLength *= ADP.CharSize;
            } 

            // Anything with a length that exceeds what fits into a two-byte integer
            // requires special binding because the base types don't allow more than
            // 65535 bytes.  We change the binding under the covers to reflect the 
            // different type.
 
            if (!ADP.IsNull(_coercedValue) && (_bindSize > _bindingMetaType.MaxBindSize || useLONGBinding)) { 
                // DEVNOTE: it is perfectly fine to bind values less than 65535 bytes
                //          as long, so there's no problem with using the maximum number 
                //          of bytes for each Unicode character above.

                switch (_bindingMetaType.OciType) {
                    case OCI.DATATYPE.CHAR: 
                    case OCI.DATATYPE.LONG:
                    case OCI.DATATYPE.VARCHAR2: 
                        _bindingMetaType = (_bindingMetaType.UsesNationalCharacterSet ) 
                                                ? MetaType.oracleTypeMetaType_LONGNVARCHAR
                                                : MetaType.oracleTypeMetaType_LONGVARCHAR; 
                        break;

                    case OCI.DATATYPE.RAW:
                    case OCI.DATATYPE.LONGRAW: 
                        _bindingMetaType = MetaType.oracleTypeMetaType_LONGVARRAW;
                        break; 
 
                    default:
                        Debug.Assert(false, "invalid type for long binding!");  // this should never happen! 
                        break;
                }

                // Long data requires a LONGVARCHAR or LONGVARRAW binding instead, which 
                // mean we have to add another 4 bytes for the length.
                _bufferLength += 4; 
            } 

            if (0 > _bufferLength) 
                throw ADP.ParameterSizeIsTooLarge(parameter.ParameterName);

            _indicatorOffset    = offset;   offset += IntPtr.Size;
            _lengthOffset       = offset;   offset += IntPtr.Size; 
            _valueOffset        = offset;   offset += _bufferLength;
 
            offset = (offset + (IntPtr.Size-1)) & ~(IntPtr.Size-1);          // align buffer; 
        }
 
        internal int PutOracleValue( object value, NativeBuffer buffer, int bufferOffset, MetaType metaType, OracleConnection connection, ref SafeHandle handleToBind) {
            //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
            // NOTE: You must have called DangerousAddRef on the buffer
            //       before calling this method, or you run the risk of allowing 
            //       Handle Recycling to occur!
            //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 
 
            //  writes the managed object into the buffer in the appropriate
            //  native Oracle format. 

            handleToBind = null;

            OCI.DATATYPE    ociType = metaType.OciType; 
            int             dataSize;
            OracleParameter parameter = Parameter; 
 
            switch (ociType) {
            case OCI.DATATYPE.FLOAT: 
            case OCI.DATATYPE.INTEGER:
            case OCI.DATATYPE.UNSIGNEDINT:
                buffer.StructureToPtr(bufferOffset, value);
                dataSize = metaType.BindSize; 
                break;
 
            case OCI.DATATYPE.RAW: 
            case OCI.DATATYPE.LONGRAW:
            case OCI.DATATYPE.LONGVARRAW: 
                {
                    byte[] from;

                    if (_coercedValue is OracleBinary) { 
                        OracleBinary temp = (OracleBinary)_coercedValue;
                        from = temp.Value; 
                    } 
                    else {
                        from = (byte[])_coercedValue; 
                    }
                    int ociBytes = from.Length - parameter.Offset;
                    int size = parameter.GetActualSize();
 
                    if (0 != size) {
                        ociBytes = Math.Min(ociBytes, size); 
                    } 
                    if ( OCI.DATATYPE.LONGVARRAW == ociType ) {
                        buffer.WriteInt32(bufferOffset, ociBytes); 
                        bufferOffset = checked((int)bufferOffset + 4) ;
                        dataSize = ociBytes + 4;
                     }
                    else { 
                        Debug.Assert (short.MaxValue >= ociBytes, "invalid size for non-LONG data?");
                        dataSize = ociBytes ; 
                    } 
                    buffer.WriteBytes(bufferOffset, from, parameter.Offset, ociBytes);
                } 
                break;

            case OCI.DATATYPE.DATE:
                dataSize = OracleDateTime.MarshalDateToNative(value, buffer, bufferOffset, ociType, connection); 
                break;
 
            // SQLBUVSTS 223628 New code doesn't handle TimestampWithTZ correctly for OracleDateTime. Reverting 
            //   to RTM behavior of throwing an exception for this combination.
            case OCI.DATATYPE.INT_TIMESTAMP_TZ: 
                if (value is OracleDateTime && !((OracleDateTime)value).HasTimeZoneInfo) {
                    // VSTS 223628: for 2.0 RTM compatibility, raise ArgumentOutOfRangeException if
                    // the input value size is less than the bound type size
                    throw ADP.UnsupportedOracleDateTimeBinding(OracleType.TimestampWithTZ); 
                }
                _dateTimeDescriptor = OracleDateTime.CreateDescriptor(ociType, connection, value); 
                handleToBind = _dateTimeDescriptor; 
                dataSize = IntPtr.Size;
                break; 

            case OCI.DATATYPE.INT_TIMESTAMP:
            case OCI.DATATYPE.INT_TIMESTAMP_LTZ:
                if (value is OracleDateTime && !((OracleDateTime)value).HasTimeInfo) { 
                    // VSTS 223628: for 2.0 RTM compatibility, raise ArgumentOutOfRangeException if
                    // the input value size is less than the bound type size 
                    throw ADP.UnsupportedOracleDateTimeBinding(metaType.OracleType); 
                }
                _dateTimeDescriptor = OracleDateTime.CreateDescriptor(ociType, connection, value); 
                handleToBind = _dateTimeDescriptor;
                dataSize = IntPtr.Size;
                break;
 
            case OCI.DATATYPE.BFILE:
                // We cannot construct lobs; if you want to bind a lob, you have to have 
                // a lob. 
                if ( !(value is OracleBFile) )
                    throw ADP.BadBindValueType(value.GetType(), metaType.OracleType); 

                handleToBind = ((OracleBFile) value).Descriptor;
                dataSize = IntPtr.Size;
                break; 

            case OCI.DATATYPE.BLOB: 
            case OCI.DATATYPE.CLOB: 
                // We cannot construct lobs; if you want to bind a lob, you have to have
                // a lob. 
                if ( !(value is OracleLob) )
                    throw ADP.BadBindValueType(value.GetType(), metaType.OracleType);

                handleToBind =  ((OracleLob) value).Descriptor; 
                dataSize = IntPtr.Size;
                break; 
 
            case OCI.DATATYPE.INT_INTERVAL_YM:
                dataSize = OracleMonthSpan.MarshalToNative(value, buffer, bufferOffset); 
                break;

            case OCI.DATATYPE.VARNUM:
                dataSize = OracleNumber.MarshalToNative(value, buffer, bufferOffset, connection); 
                break;
 
            case OCI.DATATYPE.CHAR: 
            case OCI.DATATYPE.VARCHAR2:
            case OCI.DATATYPE.LONG: 
            case OCI.DATATYPE.LONGVARCHAR:
                dataSize = OracleString.MarshalToNative(value, parameter.Offset, parameter.GetActualSize(), buffer, bufferOffset, ociType, _bindAsUCS2);
                break;
 
            case OCI.DATATYPE.INT_INTERVAL_DS:
                dataSize = OracleTimeSpan.MarshalToNative(value, buffer, bufferOffset); 
                break; 

            default: 
                throw ADP.TypeNotSupported(ociType);
            }
            Debug.Assert(dataSize <= _bufferLength, String.Format((IFormatProvider)null, "Internal Error: Exceeded Internal Buffer.  DataSize={0} BufferLength={1}",dataSize,_bufferLength));
            return dataSize; 
        }
 
    } 
};
 


// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
//------------------------------------------------------------------------------ 
// 
//      Copyright (c) Microsoft Corporation.  All rights reserved.
// 
// [....] 
//-----------------------------------------------------------------------------
 
namespace System.Data.OracleClient 
{
    using System; 
    using System.ComponentModel;
    using System.Data;
    using System.Data.Common;
    using System.Data.SqlTypes; 
    using System.Diagnostics;
    using System.IO; 
    using System.Runtime.InteropServices; 

    //--------------------------------------------------------------------- 
    // OracleParameterBinding
    //
    //  this class is meant to handle the parameter binding for an
    //  single command object (since parameters can be bound concurrently 
    //  to multiple command objects)
    // 
    sealed internal class OracleParameterBinding { 

        OracleCommand       _command;                   // the command that this binding is for 
        OracleParameter     _parameter;                 // the parameter that this binding is for
        object              _coercedValue;              // _parameter.CoercedValue;

        MetaType            _bindingMetaType;           // meta type of the binding, in case it needs adjustment (String bound as CLOB, etc...) 
        OciBindHandle       _bindHandle;                // the bind handle, once this has been bound
        int                 _bindSize;                  // number of bytes/characters to reserve on the server 
        int                 _bufferLength;              // number of bytes required to bind the value 
        int                 _indicatorOffset;           // offset from the start of the parameter buffer to the indicator binding (see OCI.INDICATOR)
        int                 _lengthOffset;              // offset from the start of the parameter buffer to the length binding 
        int                 _valueOffset;               // offset from the start of the parameter buffer to the value binding
        bool                _bindAsUCS2;                // true when we should bind this as UCS2
        bool                _freeTemporaryLob;          // true when we've allocated a temporary lob (in _coercedValue) that must be freed.
 
        OciStatementHandle  _descriptor;                // ref cursor handle for ref cursor types.
        OciLobLocator       _locator;                   // lob locator for BFile and Lob types. 
        OciDateTimeDescriptor _dateTimeDescriptor;      // OCI datetime descriptor to hold date time values 

        // Construct an "empty" parameter 
        internal OracleParameterBinding (OracleCommand command, OracleParameter parameter) {
            _command   = command;
            _parameter = parameter;
        } 

        internal OracleParameter Parameter { 
            get { 
                return _parameter;
            } 
        }

        internal void Bind (OciStatementHandle statementHandle, NativeBuffer parameterBuffer, OracleConnection connection, ref bool mustRelease, ref SafeHandle handleToBind) {
            //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 
            // NOTE: You must have called DangerousAddRef on the parameterBuffer
            //       before calling this method, or you run the risk of allowing 
            //       Handle Recycling to occur! 
            //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
 
            IntPtr          h;

            // Don't bother with parameters where the user asks for the default value.
            if ( !IsDirection(Parameter, ParameterDirection.Output) && null == Parameter.Value) { 
                return;
            } 
            string          parameterName  = Parameter.ParameterName; 
            OciErrorHandle      errorHandle    = connection.ErrorHandle;
            OciServiceContextHandle     serviceContextHandle =  connection.ServiceContextHandle; 

            int             valueLength = 0;    // number of BYTES written to the valueLocation for the INPUT value.
            int             bufferLength;       // number of BYTES we tell Oracle that we have provided space for in our buffer (may be shorter than actual buffer)
            OCI.INDICATOR   indicatorValue  = OCI.INDICATOR.OK; 

            OCI.DATATYPE    ociType = _bindingMetaType.OciType; 
 
            IntPtr          indicatorLocation   = parameterBuffer.DangerousGetDataPtr(_indicatorOffset);
            IntPtr          lengthLocation      = parameterBuffer.DangerousGetDataPtr(_lengthOffset); 
            IntPtr          valueLocation       = parameterBuffer.DangerousGetDataPtr(_valueOffset);

            OciHandle.SafeDispose(ref _dateTimeDescriptor);
 
            // First, write the value to the parameter buffer and get the number
            // of bytes written. 
 
            if (IsDirection(Parameter, ParameterDirection.Input)) {
                if (ADP.IsNull(_coercedValue)) { 
                    indicatorValue = OCI.INDICATOR.ISNULL;

                    // for TIMESTAMP types, we still have to provide the descriptor, even if the value is null
                    switch (ociType) 
                    {
                        case OCI.DATATYPE.INT_TIMESTAMP: 
                        case OCI.DATATYPE.INT_TIMESTAMP_TZ: 
                        case OCI.DATATYPE.INT_TIMESTAMP_LTZ:
                            _dateTimeDescriptor = OracleDateTime.CreateEmptyDescriptor(ociType, connection); 
                            handleToBind = _dateTimeDescriptor;
                            break;
                    }
                } 
                else {
                    valueLength = PutOracleValue( 
                                            _coercedValue, 
                                            parameterBuffer,
                                            _valueOffset, 
                                            _bindingMetaType,
                                            connection,
                                            ref handleToBind);
                } 
            }
            else { 
                Debug.Assert(IsDirection(Parameter, ParameterDirection.Output), "non-output output parameter?"); 

                if (_bindingMetaType.IsVariableLength) 
                    valueLength = 0;                // Output-only values never have an input length...
                else
                    valueLength = _bufferLength;    // ...except when they're fixed length, to avoid ORA-01459 errors
 
                OciLobLocator.SafeDispose(ref _locator);
                OciHandle.SafeDispose(ref _descriptor); 
 
                switch (ociType) {
                case OCI.DATATYPE.BFILE: 
                case OCI.DATATYPE.BLOB:
                case OCI.DATATYPE.CLOB:
                    _locator = new OciLobLocator(connection, _bindingMetaType.OracleType);
                    handleToBind = _locator.Descriptor; 
                    break;
 
                case OCI.DATATYPE.RSET: 
                    _descriptor = new OciStatementHandle(serviceContextHandle);
                    handleToBind = _descriptor; 
                    break;

                case OCI.DATATYPE.INT_TIMESTAMP:
                case OCI.DATATYPE.INT_TIMESTAMP_TZ: 
                case OCI.DATATYPE.INT_TIMESTAMP_LTZ:
                    _dateTimeDescriptor = OracleDateTime.CreateEmptyDescriptor(ociType, connection); 
                    handleToBind = _dateTimeDescriptor; 
                    break;
                } 
            }

            // We need to add-ref the handle so it can't be released somehow
            // by another thread while we're executing.  Only after we do that 
            // can we write it to the buffer for the Oracle to use during the
            // Execute.  The caller is required to provide storage for the 
            // handleToBind and ensure that the DangerousRelease is called 
            // in it's CER.
            if (null != handleToBind) { 
                handleToBind.DangerousAddRef(ref mustRelease);
                parameterBuffer.WriteIntPtr(_valueOffset, handleToBind.DangerousGetHandle());
            }
 
            // Second, write the indicatorValue (whether the parameter has a null
            // value or not) to the parameter buffer. 
 
            parameterBuffer.WriteInt16(_indicatorOffset, (Int16)indicatorValue);
 
            // Third, write the length of the input value to the parameter buffer.
            //
            // Don't bind a length value for LONGVARCHAR or LONGVARRAW data, or you'll end
            // up with ORA-01098: program Interface error during Long Insert\nORA-01458: invalid length inside variable character string 
            // errors.
 
            if (OCI.DATATYPE.LONGVARCHAR == ociType || OCI.DATATYPE.LONGVARRAW  == ociType) { 
                lengthLocation = IntPtr.Zero;
            } 
            else {
                // When we're binding this parameter as UCS2, the length we specify
                // must be in characters, not in bytes.
                if (_bindAsUCS2) 
                    parameterBuffer.WriteInt32(_lengthOffset,  (Int32)(valueLength/ADP.CharSize));
                else 
                    parameterBuffer.WriteInt32(_lengthOffset,  (Int32)valueLength); 
            }
 
            // Fourth, compute the number of bytes in the parameter buffer that we need
            // to report to Oracle, depending on whether it is an input-only or any type
            // of output parameter. For input-only parameters, we only need to report
            // the actual value's size, but for output parameters, we have to report the 
            // full buffer size to avoid truncation of data, should the output value
            // exceed the length of the input value. 
 
            if (IsDirection(Parameter, ParameterDirection.Output))
                bufferLength = _bufferLength; 
            else
                bufferLength = valueLength;

            // bind type is different for INT_TIMESTAMP* since we bind them as Oracle's public TIMESTAMP* ones and use descriptors 
            OCI.DATATYPE bindAsOciType = ociType;
            switch (ociType) { 
                case OCI.DATATYPE.INT_TIMESTAMP: 
                    bindAsOciType = OCI.DATATYPE.TIMESTAMP;
                    break; 
                case OCI.DATATYPE.INT_TIMESTAMP_TZ:
                    bindAsOciType = OCI.DATATYPE.TIMESTAMP_TZ;
                    break;
                case OCI.DATATYPE.INT_TIMESTAMP_LTZ: 
                    bindAsOciType = OCI.DATATYPE.TIMESTAMP_LTZ;
                    break; 
            } 

            // Finally, tell Oracle about our parameter. 

            int rc = TracedNativeMethods.OCIBindByName(
                                statementHandle,
                                out h, 
                                errorHandle,
                                parameterName, 
                                parameterName.Length, 
                                valueLocation,
                                bufferLength, 
                                bindAsOciType,
                                indicatorLocation,
                                lengthLocation,
                                OCI.MODE.OCI_DEFAULT 
                                );
 
            if (rc != 0) 
                _command.Connection.CheckError(errorHandle, rc);
 
            _bindHandle = new OciBindHandle(statementHandle, h);

#if TRACEPARAMETERVALUES
            if (null != _coercedValue) { 
                SafeNativeMethods.OutputDebugStringW("Value = '" + _coercedValue.ToString() + "'\n");
            } 
#endif //TRACEPARAMETERVALUES 

            // OK, character bindings have a few extra things we need to do to 
            // deal with character sizes and alternate character sets.

            if (_bindingMetaType.IsCharacterType) {
                // To avoid problems when our buffer is larger than the maximum number 
                // of characters, we use OCI_ATTR_MAXCHAR_SIZE to limit the number of
                // characters that will be used.  (Except on Oracle8i clients where it 
                // isn't available) 
                if (OCI.ClientVersionAtLeastOracle9i
                        && IsDirection(Parameter, ParameterDirection.Output)) 
                    _bindHandle.SetAttribute(OCI.ATTR.OCI_ATTR_MAXCHAR_SIZE, (int)_bindSize, errorHandle);

                if ((bufferLength > _bindingMetaType.MaxBindSize / ADP.CharSize)
                        || (!OCI.ClientVersionAtLeastOracle9i && _bindingMetaType.UsesNationalCharacterSet))    // need to specify MAXDATA_SIZE for OCI8 UCS2 bindings to work 
                    _bindHandle.SetAttribute(OCI.ATTR.OCI_ATTR_MAXDATA_SIZE, (int)_bindingMetaType.MaxBindSize, errorHandle);
 
                // NOTE:    the order is important here; setting charsetForm will 
                //          reset charsetId (I found this out the hard way...)
                if (_bindingMetaType.UsesNationalCharacterSet) 
                    _bindHandle.SetAttribute(OCI.ATTR.OCI_ATTR_CHARSET_FORM, (int)OCI.CHARSETFORM.SQLCS_NCHAR, errorHandle);

                // NOTE:    the order is important here; setting charsetForm will
                //          reset charsetId (I found this out the hard way...) 
                if (_bindAsUCS2)
                    _bindHandle.SetAttribute(OCI.ATTR.OCI_ATTR_CHARSET_ID, (int)OCI.CHARSETID.OCI_UTF16ID, errorHandle); 
            } 
            GC.KeepAlive(parameterBuffer);
        } 

        private OracleLob CreateTemporaryLobForValue(OracleConnection connection, OracleType oracleType, object value) {
            switch (oracleType) {
            case OracleType.BFile: 
                // Note that we can't really construct a temporary BFILE, so we
                // construct a BLOB instead. This is safe because Oracle won't 
                // let you write to a BFILE, so the caller is using it as an Input 
                // parameter.
                oracleType = OracleType.Blob; 
                break;
            case OracleType.Blob:
            case OracleType.Clob:
            case OracleType.NClob: 
                break;
 
            default: 
                throw ADP.InvalidLobType(oracleType);
            } 

            OracleLob tempLob = new OracleLob(connection, oracleType);

            byte[] byteArrayValue = value as byte[]; 
            if (null != byteArrayValue) {
                tempLob.Write(byteArrayValue,0,byteArrayValue.Length); 
            } 
            else {
                System.Text.Encoding UnicodeWithoutBOMs = new System.Text.UnicodeEncoding(false, false);    // Oracle won't put in BOMs, so neither should we... 
                tempLob.Seek(0,SeekOrigin.Begin);
                StreamWriter sw = new StreamWriter(tempLob, UnicodeWithoutBOMs);
                sw.Write(value);
                sw.Flush(); 
            }
            return tempLob; 
        } 

        internal object GetOutputValue( 
                NativeBuffer        parameterBuffer,
                OracleConnection    connection,         // connection, so we can create LOB values
                bool                needCLSType
                ) { 

            object result; 
            //  Returns an object that contains the value of the column in the 
            //  specified row buffer.  This method returns Oracle-typed objects.
 
            if (parameterBuffer.ReadInt16(_indicatorOffset) == (Int16)OCI.INDICATOR.ISNULL)
                return DBNull.Value;

            switch (_bindingMetaType.OciType) { 
                case OCI.DATATYPE.FLOAT:
                case OCI.DATATYPE.INTEGER: 
                case OCI.DATATYPE.UNSIGNEDINT: 
                    result = parameterBuffer.PtrToStructure(_valueOffset, _bindingMetaType.BaseType);
                    return result; 

                case OCI.DATATYPE.BFILE:
                    result = new OracleBFile(_locator);
                    return result; 

                case OCI.DATATYPE.RAW: 
                case OCI.DATATYPE.LONGRAW: 
                case OCI.DATATYPE.LONGVARRAW:
                    result = new OracleBinary(parameterBuffer, _valueOffset, _lengthOffset, _bindingMetaType); 
                    if (needCLSType) {
                        object newresult = ((OracleBinary)result).Value;
                        result = newresult;
                    } 
                    return result;
 
                case OCI.DATATYPE.RSET: 
                    result = new OracleDataReader(connection, _descriptor);
                    return result; 

                case OCI.DATATYPE.DATE:
                    result = new OracleDateTime(parameterBuffer, _valueOffset, _lengthOffset, _bindingMetaType, connection);
                    if (needCLSType) { 
                        object newresult = ((OracleDateTime)result).Value;
                        result = newresult; 
                    } 
                    return result;
 
                case OCI.DATATYPE.INT_TIMESTAMP:
                case OCI.DATATYPE.INT_TIMESTAMP_TZ:
                case OCI.DATATYPE.INT_TIMESTAMP_LTZ:
                    result = new OracleDateTime(_dateTimeDescriptor, _bindingMetaType, connection); 
                    if (needCLSType) {
                        object newresult = ((OracleDateTime)result).Value; 
                        result = newresult; 
                    }
                    return result; 

                case OCI.DATATYPE.BLOB:
                case OCI.DATATYPE.CLOB:
                    result = new OracleLob(_locator); 
                    return result;
 
                case OCI.DATATYPE.INT_INTERVAL_YM: 
                    result = new OracleMonthSpan(parameterBuffer, _valueOffset);
                    if (needCLSType) { 
                        object newresult = ((OracleMonthSpan)result).Value;
                        result = newresult;
                    }
                    return result; 

                case OCI.DATATYPE.VARNUM: 
                    result = new OracleNumber(parameterBuffer, _valueOffset); 
                    if (needCLSType) {
                        object newresult = ((OracleNumber)result).Value; 
                        result = newresult;
                    }
                    return result;
 
                case OCI.DATATYPE.CHAR:
                case OCI.DATATYPE.VARCHAR2: 
                case OCI.DATATYPE.LONG: 
                case OCI.DATATYPE.LONGVARCHAR:
                    result = new OracleString(parameterBuffer, 
                                            _valueOffset,
                                            _lengthOffset,
                                            _bindingMetaType,
                                            connection, 
                                            _bindAsUCS2,
                                            true 
                                            ); 
                    int size = _parameter.Size;
                    if (0 != size && size < ((OracleString)result).Length) { 
                        string truncatedResult = ((OracleString)result).Value.Substring(0,size);
                        if (needCLSType)
                            result = truncatedResult;
                        else 
                            result = new OracleString(truncatedResult);
                    } 
                    else if (needCLSType) { 
                        object newresult = ((OracleString)result).Value;
                        result = newresult; 
                    }
                    return result;

                case OCI.DATATYPE.INT_INTERVAL_DS: 
                    result = new OracleTimeSpan(parameterBuffer, _valueOffset);
                    if (needCLSType) { 
                        object newresult = ((OracleTimeSpan)result).Value; 
                        result = newresult;
                    } 
                    return result;

            }
            throw ADP.TypeNotSupported(_bindingMetaType.OciType); 

        } 
 
        internal void Dispose() {
            OciHandle.SafeDispose(ref _bindHandle); 

            // Make sure we clean up any temporary lob we may have constructed
            // so they don't leak.
            if (_freeTemporaryLob) { 
                OracleLob temporaryLob = _coercedValue as OracleLob;
                if (null != temporaryLob) { 
                    temporaryLob.Free(); 
                }
            } 
        }

        static internal bool IsDirection(IDataParameter value, ParameterDirection condition) {
            return (condition == (condition & value.Direction)); 
        }
 
        private bool IsEmpty(object value) { 
            bool result = false;
 
            if (value is string) {
                result = (0 == ((string) value).Length);
            }
            if (value is OracleString) { 
                result = (0 == ((OracleString) value).Length);
            } 
            if (value is char[]) { 
                result = (0 == ((char[]) value).Length);
            } 

            if (value is byte[]) {
                result = (0 == ((byte[]) value).Length);
            } 
            if (value is OracleBinary) {
                result = (0 == ((OracleBinary) value).Length); 
            } 
            return result;
        } 

        internal void PostExecute (NativeBuffer parameterBuffer, OracleConnection connection) { // connection, so we can create LOB values
            OracleParameter parameter = Parameter;
            if (IsDirection(parameter, ParameterDirection.Output) 
             || IsDirection(parameter, ParameterDirection.ReturnValue)) {
                bool needCLSType = true; 
                if (IsDirection(parameter, ParameterDirection.Input)) { 
                    object inputValue = parameter.Value;
 
                    if (inputValue is INullable) {
                        needCLSType = false;
                    }
                } 
                parameter.Value = GetOutputValue(parameterBuffer, connection, needCLSType);
            } 
        } 

        internal void PrepareForBind (OracleConnection connection, ref int offset) { 
            OracleParameter parameter = Parameter;
            bool useLONGBinding = false;

            object value = parameter.Value; 

            // Don't bother with parameters where the user asks for the default value. 
            if ( !IsDirection(parameter, ParameterDirection.Output) && (null == value)) { 
                _bufferLength = 0;
                return; 
            }

            _bindingMetaType = parameter.GetMetaType(value);
 
            // We currently don't support binding a REF CURSOR as an input
            // parameter; that is for a future release. 
            if (OCI.DATATYPE.RSET == _bindingMetaType.OciType && ADP.IsDirection(parameter.Direction, ParameterDirection.Input)) 
                throw ADP.InputRefCursorNotSupported(parameter.ParameterName);
 
            // Make sure we have a coerced value, if we haven't already done
            // so, then save it.
            parameter.SetCoercedValueInternal(value, _bindingMetaType);
            _coercedValue = parameter.GetCoercedValueInternal(); 

            // WebData 103336 - When the customer requests that we use a LOB we 
            // need to use a LOB, so that it can be processed by PL/SQL, which 
            // can't handle values larger than 32000 bytes.  When they don't pass
            // us a LOB or a BFILE as the value, we silently construct a 
            // temporary LOB for them.  This is necessary for DataAdapter.Update.
            switch (_bindingMetaType.OciType) {
            case OCI.DATATYPE.BFILE:
            case OCI.DATATYPE.BLOB: 
            case OCI.DATATYPE.CLOB:
                if (!ADP.IsNull(_coercedValue) && !(_coercedValue is OracleLob || _coercedValue is OracleBFile)) { 
                    // WebData 104205 - Except I forgot that you have to be in a 
                    // transaction to write to a LOB. Since we don't want to break
                    // people that currently work outside of a transaction, we 
                    // need to limit when we use temporary LOBs to when we already
                    // have a transaction.  Other than that, they're out of luck.
                    if (connection.HasTransaction) {
                        _freeTemporaryLob = true; 
                        _coercedValue = CreateTemporaryLobForValue(connection, _bindingMetaType.OracleType, _coercedValue);
                    } 
                    else { 
                        _bindingMetaType = MetaType.GetMetaTypeForType(_bindingMetaType.DbType);
                        useLONGBinding = true; 
                    }
                }
                break;
            } 

            // For fixed-width types, we take the bind size from the meta type 
            // information; if it's zero, then the type must be variable width 
            // (or it's an output parameter) and we require that they specify a
            // size. 

            _bindSize = _bindingMetaType.BindSize;

            if ((IsDirection(parameter, ParameterDirection.Output) 
                                && _bindingMetaType.IsVariableLength)   // they must specify a size for variable-length output parameters...
                || (0 == _bindSize && !ADP.IsNull(_coercedValue))       // ...or if it's a non-null, variable-length input paramter... 
                || (_bindSize > short.MaxValue) ) {                     // ...or if the parameter type's maximum size is huge. 

                int size = parameter.BindSize; 

                if (0 != size)
                    _bindSize = size;
 
                if ((0 == _bindSize || MetaType.LongMax == _bindSize) && !IsEmpty(_coercedValue))
                    throw ADP.ParameterSizeIsMissing(parameter.ParameterName, _bindingMetaType.BaseType); 
            } 

            // Now determine the number of bytes we require in the buffer. For 
            // character types, we must adjust for the size of the characters that
            // we will bind.

            _bufferLength = _bindSize; 

            if (_bindingMetaType.IsCharacterType && connection.ServerVersionAtLeastOracle8) { 
                _bindAsUCS2 = true; 
                _bufferLength *= ADP.CharSize;
            } 

            // Anything with a length that exceeds what fits into a two-byte integer
            // requires special binding because the base types don't allow more than
            // 65535 bytes.  We change the binding under the covers to reflect the 
            // different type.
 
            if (!ADP.IsNull(_coercedValue) && (_bindSize > _bindingMetaType.MaxBindSize || useLONGBinding)) { 
                // DEVNOTE: it is perfectly fine to bind values less than 65535 bytes
                //          as long, so there's no problem with using the maximum number 
                //          of bytes for each Unicode character above.

                switch (_bindingMetaType.OciType) {
                    case OCI.DATATYPE.CHAR: 
                    case OCI.DATATYPE.LONG:
                    case OCI.DATATYPE.VARCHAR2: 
                        _bindingMetaType = (_bindingMetaType.UsesNationalCharacterSet ) 
                                                ? MetaType.oracleTypeMetaType_LONGNVARCHAR
                                                : MetaType.oracleTypeMetaType_LONGVARCHAR; 
                        break;

                    case OCI.DATATYPE.RAW:
                    case OCI.DATATYPE.LONGRAW: 
                        _bindingMetaType = MetaType.oracleTypeMetaType_LONGVARRAW;
                        break; 
 
                    default:
                        Debug.Assert(false, "invalid type for long binding!");  // this should never happen! 
                        break;
                }

                // Long data requires a LONGVARCHAR or LONGVARRAW binding instead, which 
                // mean we have to add another 4 bytes for the length.
                _bufferLength += 4; 
            } 

            if (0 > _bufferLength) 
                throw ADP.ParameterSizeIsTooLarge(parameter.ParameterName);

            _indicatorOffset    = offset;   offset += IntPtr.Size;
            _lengthOffset       = offset;   offset += IntPtr.Size; 
            _valueOffset        = offset;   offset += _bufferLength;
 
            offset = (offset + (IntPtr.Size-1)) & ~(IntPtr.Size-1);          // align buffer; 
        }
 
        internal int PutOracleValue( object value, NativeBuffer buffer, int bufferOffset, MetaType metaType, OracleConnection connection, ref SafeHandle handleToBind) {
            //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
            // NOTE: You must have called DangerousAddRef on the buffer
            //       before calling this method, or you run the risk of allowing 
            //       Handle Recycling to occur!
            //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 
 
            //  writes the managed object into the buffer in the appropriate
            //  native Oracle format. 

            handleToBind = null;

            OCI.DATATYPE    ociType = metaType.OciType; 
            int             dataSize;
            OracleParameter parameter = Parameter; 
 
            switch (ociType) {
            case OCI.DATATYPE.FLOAT: 
            case OCI.DATATYPE.INTEGER:
            case OCI.DATATYPE.UNSIGNEDINT:
                buffer.StructureToPtr(bufferOffset, value);
                dataSize = metaType.BindSize; 
                break;
 
            case OCI.DATATYPE.RAW: 
            case OCI.DATATYPE.LONGRAW:
            case OCI.DATATYPE.LONGVARRAW: 
                {
                    byte[] from;

                    if (_coercedValue is OracleBinary) { 
                        OracleBinary temp = (OracleBinary)_coercedValue;
                        from = temp.Value; 
                    } 
                    else {
                        from = (byte[])_coercedValue; 
                    }
                    int ociBytes = from.Length - parameter.Offset;
                    int size = parameter.GetActualSize();
 
                    if (0 != size) {
                        ociBytes = Math.Min(ociBytes, size); 
                    } 
                    if ( OCI.DATATYPE.LONGVARRAW == ociType ) {
                        buffer.WriteInt32(bufferOffset, ociBytes); 
                        bufferOffset = checked((int)bufferOffset + 4) ;
                        dataSize = ociBytes + 4;
                     }
                    else { 
                        Debug.Assert (short.MaxValue >= ociBytes, "invalid size for non-LONG data?");
                        dataSize = ociBytes ; 
                    } 
                    buffer.WriteBytes(bufferOffset, from, parameter.Offset, ociBytes);
                } 
                break;

            case OCI.DATATYPE.DATE:
                dataSize = OracleDateTime.MarshalDateToNative(value, buffer, bufferOffset, ociType, connection); 
                break;
 
            // SQLBUVSTS 223628 New code doesn't handle TimestampWithTZ correctly for OracleDateTime. Reverting 
            //   to RTM behavior of throwing an exception for this combination.
            case OCI.DATATYPE.INT_TIMESTAMP_TZ: 
                if (value is OracleDateTime && !((OracleDateTime)value).HasTimeZoneInfo) {
                    // VSTS 223628: for 2.0 RTM compatibility, raise ArgumentOutOfRangeException if
                    // the input value size is less than the bound type size
                    throw ADP.UnsupportedOracleDateTimeBinding(OracleType.TimestampWithTZ); 
                }
                _dateTimeDescriptor = OracleDateTime.CreateDescriptor(ociType, connection, value); 
                handleToBind = _dateTimeDescriptor; 
                dataSize = IntPtr.Size;
                break; 

            case OCI.DATATYPE.INT_TIMESTAMP:
            case OCI.DATATYPE.INT_TIMESTAMP_LTZ:
                if (value is OracleDateTime && !((OracleDateTime)value).HasTimeInfo) { 
                    // VSTS 223628: for 2.0 RTM compatibility, raise ArgumentOutOfRangeException if
                    // the input value size is less than the bound type size 
                    throw ADP.UnsupportedOracleDateTimeBinding(metaType.OracleType); 
                }
                _dateTimeDescriptor = OracleDateTime.CreateDescriptor(ociType, connection, value); 
                handleToBind = _dateTimeDescriptor;
                dataSize = IntPtr.Size;
                break;
 
            case OCI.DATATYPE.BFILE:
                // We cannot construct lobs; if you want to bind a lob, you have to have 
                // a lob. 
                if ( !(value is OracleBFile) )
                    throw ADP.BadBindValueType(value.GetType(), metaType.OracleType); 

                handleToBind = ((OracleBFile) value).Descriptor;
                dataSize = IntPtr.Size;
                break; 

            case OCI.DATATYPE.BLOB: 
            case OCI.DATATYPE.CLOB: 
                // We cannot construct lobs; if you want to bind a lob, you have to have
                // a lob. 
                if ( !(value is OracleLob) )
                    throw ADP.BadBindValueType(value.GetType(), metaType.OracleType);

                handleToBind =  ((OracleLob) value).Descriptor; 
                dataSize = IntPtr.Size;
                break; 
 
            case OCI.DATATYPE.INT_INTERVAL_YM:
                dataSize = OracleMonthSpan.MarshalToNative(value, buffer, bufferOffset); 
                break;

            case OCI.DATATYPE.VARNUM:
                dataSize = OracleNumber.MarshalToNative(value, buffer, bufferOffset, connection); 
                break;
 
            case OCI.DATATYPE.CHAR: 
            case OCI.DATATYPE.VARCHAR2:
            case OCI.DATATYPE.LONG: 
            case OCI.DATATYPE.LONGVARCHAR:
                dataSize = OracleString.MarshalToNative(value, parameter.Offset, parameter.GetActualSize(), buffer, bufferOffset, ociType, _bindAsUCS2);
                break;
 
            case OCI.DATATYPE.INT_INTERVAL_DS:
                dataSize = OracleTimeSpan.MarshalToNative(value, buffer, bufferOffset); 
                break; 

            default: 
                throw ADP.TypeNotSupported(ociType);
            }
            Debug.Assert(dataSize <= _bufferLength, String.Format((IFormatProvider)null, "Internal Error: Exceeded Internal Buffer.  DataSize={0} BufferLength={1}",dataSize,_bufferLength));
            return dataSize; 
        }
 
    } 
};
 


// 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