OracleColumn.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ Dotnetfx_Win7_3.5.1 / Dotnetfx_Win7_3.5.1 / 3.5.1 / DEVDIV / depot / DevDiv / releases / whidbey / NetFXspW7 / ndp / fx / src / DataOracleClient / System / Data / OracleClient / OracleColumn.cs / 1 / OracleColumn.cs

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

    //--------------------------------------------------------------------- 
    // OracleColumn
    //
    //  Contains all the information about a single column in a result set,
    //  and implements the methods necessary to describe column to Oracle 
    //  and to extract the column data from the native buffer used to fetch
    //  it. 
    // 
    sealed internal class OracleColumn {
        private OciParameterDescriptor _describeHandle;     // the Describe handle 
        private int             _ordinal;               // the ordinal position in the rowset (0..n-1)
        private string          _columnName;            // the name of the column

        private MetaType        _metaType; 
        private byte            _precision;             // precision of the column (OracleNumber only)
        private byte            _scale;                 // scale of the column (OracleNumber only) 
        private int             _byteSize;              // how many bytes we need in the row buffer 
        private bool            _isNullable;            // whether the value is nullable or not.
 
        private int             _indicatorOffset;       // offset from the start of the row buffer to the indicator binding (see OCI.INDICATOR)
        private int             _lengthOffset;          // offset from the start of the row buffer to the length binding
        private int             _valueOffset;           // offset from the start of the row buffer to the value binding
 
        private NativeBuffer_RowBuffer _rowBuffer;      // the row buffer we're bound to (reused for all rows fetched)
        private NativeBuffer_LongColumnData _longBuffer;// the out-of-line buffer used for piecewise binding; must be reset for each new fetch. 
        private int             _longLength;            // the length of the data we actually fetched into _longBuffer 
        private OCI.Callback.OCICallbackDefine _callback;// the piecewise binding callback for this column
 
        private OciLobLocator   _lobLocator;            // the descriptor allocated for LOB columns

        private OracleConnection _connection;           // the connection the column is on (LOB columns only)
        private int             _connectionCloseCount;  // The close count of the connection; used to decide if we're zombied 

        private bool            _bindAsUTF16;            // true whenever we're binding character data as Unicode... 
 

        // Construct by getting the specified describe handle from the specified statement handle 
        internal OracleColumn(OciStatementHandle statementHandle, int ordinal, OciErrorHandle errorHandle, OracleConnection connection) {
            _ordinal                = ordinal;
            _describeHandle         = statementHandle.GetDescriptor(_ordinal, errorHandle);;
            _connection             = connection; 
            _connectionCloseCount   = connection.CloseCount;
        } 
 

        internal string     ColumnName      { get { return _columnName; } } 
        internal bool       IsNullable      { get { return _isNullable; } }
        internal bool       IsLob           { get { return _metaType.IsLob; } }
        internal bool       IsLong          { get { return _metaType.IsLong; } }
        internal OracleType OracleType      { get { return _metaType.OracleType; } } 
        internal int        Ordinal         { get { return _ordinal; } }
        internal byte       Precision       { get { return _precision; } } 
        internal byte       Scale           { get { return _scale; } } 

        // This is the value used for the SchemaTable, which must be Chars... 
        internal int        SchemaTableSize { get { return (_bindAsUTF16 && !_metaType.IsLong)?_byteSize/2:_byteSize; } }


        private int _callback_GetColumnPiecewise( 
                        IntPtr      octxp,
                        IntPtr      defnp, 
                        uint        iter, 
                        IntPtr      bufpp,  // dvoid**
                        IntPtr      alenp,  // ub4** 
                        IntPtr      piecep, // ub1*
                        IntPtr      indpp,  // dvoid**
                        IntPtr      rcodep  // ub2**
                        ) { 
            //  Callback routine for Dynamic Binding column values from Oracle: tell
            //  Oracle where to stuff the data. 
 
            if (Bid.AdvancedOn)
                Bid.Trace("" 
                    +" octxp=0x%-07Ix"
                    +" defnp=0x%-07Ix"
                    +" iter=%-2d"
                    +" bufpp=0x%-07Ix" 
                    +" alenp=0x%-07Ix"
                    +" piecep=0x%-07Ix" 
                    +" indpp=0x%-07Ix" 
                    +" rcodep=0x%-07Ix\n",
                    octxp, 
                    defnp,
                    unchecked((int)iter), // tracing -- I don't care about overflow.
                    bufpp,
                    alenp, 
                    piecep,
                    indpp, 
                    rcodep 
                );
            //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 
            // NOTE: THIS IS A CALLBACK FUNCTION FROM AN OCI PINVOKE!
            //       Namely, OCIStmtFetch.  We expect that you will have called
            //       DangerousAddRef on the _rowBuffer and the _longBuffer
            //       SafeHandles, to prevent any Handle Recycling from occurring. 
            //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
 
            // RFC50002189 - chunk length is saved as part of chunk's buffer 
            // later, when the LONG field value is requested, TotalLength is used
            // to sum the lengths and the result is writtent into buffer[_lengthOffset], as before the change 

            IntPtr lengthPtr;
            IntPtr indicatorPtr = (-1 != _indicatorOffset) ? _rowBuffer.DangerousGetDataPtr(_indicatorOffset) : IntPtr.Zero;
            IntPtr valuePtr     = _longBuffer.GetChunk(out lengthPtr); 

            Marshal.WriteIntPtr(bufpp, valuePtr);       // *bufpp 
            Marshal.WriteIntPtr(indpp, indicatorPtr);   // *indpp 
            Marshal.WriteIntPtr(alenp, lengthPtr);      // *alenp
 
            // provide the size of allocated buffer, in bytes, to Oracle driver
            // on output, we will receive from Oracle driver the length of filled buffer, in bytes
            Marshal.WriteInt32(lengthPtr, NativeBuffer_LongColumnData.MaxChunkSize);    // **alenp
 
            GC.KeepAlive(this);
            return (int)OCI.RETURNCODE.OCI_CONTINUE; 
        } 

        internal void Bind(OciStatementHandle statementHandle, NativeBuffer_RowBuffer buffer, OciErrorHandle errorHandle, int rowBufferLength) { 
            //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
            // NOTE: You must have called DangerousAddRef on the buffer before
            //       calling this method, or you run the risk of allowing Handle
            //       Recycling to occur! 
            //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
 
            //  Binds the buffer for the column to the statement handle specified. 

            OciDefineHandle     defineHandle = null; 
            IntPtr          h;
            OCI.MODE        mode = OCI.MODE.OCI_DEFAULT;
            int             bindByteSize;
            OCI.DATATYPE    ociType = _metaType.OciType; 

            _rowBuffer = buffer; 
 
            if (_metaType.IsLong) {
                mode     = OCI.MODE.OCI_DYNAMIC_FETCH; 
                bindByteSize = Int32.MaxValue;
            }
            else {
                bindByteSize = _byteSize; 
            }
 
            IntPtr indicatorLocation = IntPtr.Zero; 
            IntPtr lengthLocation    = IntPtr.Zero;
            IntPtr valueLocation     = _rowBuffer.DangerousGetDataPtr(_valueOffset); 

            if (-1 != _indicatorOffset) {
                indicatorLocation = _rowBuffer.DangerousGetDataPtr(_indicatorOffset);
            } 
            if (-1 != _lengthOffset && !_metaType.IsLong) {
                lengthLocation = _rowBuffer.DangerousGetDataPtr(_lengthOffset); 
            } 
             try {
                int rc = TracedNativeMethods.OCIDefineByPos( 
                                            statementHandle,            // hndlp
                                            out h,                      // defnpp
                                            errorHandle,                // errhp
                                            checked((uint)_ordinal+1),  // position 
                                            valueLocation,              // valuep
                                            bindByteSize,               // value_sz 
                                            ociType,                    // htype 
                                            indicatorLocation,          // indp,
                                            lengthLocation,             // rlenp, 
                                            IntPtr.Zero,                // rcodep,
                                            mode                        // mode
                                            );
                if (rc != 0) { 
                    _connection.CheckError(errorHandle, rc);
                } 
                defineHandle = new OciDefineHandle(statementHandle, h); 

                if (0 != rowBufferLength) { 
                    uint valOffset = checked((uint)rowBufferLength);
                    uint indOffset = (-1 != _indicatorOffset) ? valOffset : 0;
                    uint lenOffset = (-1 != _lengthOffset && !_metaType.IsLong) ? valOffset : 0;
 
                    rc = TracedNativeMethods.OCIDefineArrayOfStruct(
                                                defineHandle, 
                                                errorHandle, 
                                                valOffset,
                                                indOffset, 
                                                lenOffset,
                                                0    // never use rcodep above...
                                                );
                    if (rc != 0) { 
                        _connection.CheckError(errorHandle, rc);
                    } 
                } 

                if (_metaType.UsesNationalCharacterSet) { 
                    Debug.Assert(!_metaType.IsLong, "LONG data may never be bound as NCHAR");
                    // NOTE:    the order is important here; setting charsetForm will
                    //          reset charsetId (I found this out the hard way...)
                    defineHandle.SetAttribute(OCI.ATTR.OCI_ATTR_CHARSET_FORM, (int)OCI.CHARSETFORM.SQLCS_NCHAR, errorHandle); 
                }
                if (!_connection.UnicodeEnabled) { 
                    if (_bindAsUTF16) { 
                        // NOTE:    the order is important here; setting charsetForm will
                        //          reset charsetId (I found this out the hard way...) 
                        defineHandle.SetAttribute(OCI.ATTR.OCI_ATTR_CHARSET_ID, (short)OCI.CHARSETID.OCI_UTF16ID, errorHandle);
                    }
                }
                if (_metaType.IsLong) { 
                    // Initialize the longBuffer in the rowBuffer to null
                    _rowBuffer.WriteIntPtr(_valueOffset, IntPtr.Zero); 
 
                    _callback = new OCI.Callback.OCICallbackDefine(_callback_GetColumnPiecewise);
 
                    rc = TracedNativeMethods.OCIDefineDynamic(
                                                defineHandle,       // defnp
                                                errorHandle,        // errhp
                                                IntPtr.Zero,        // dvoid *octxp, 
                                                _callback           // OCICallbackDefine ocbfp
                                                ); 
                    if (rc != 0) { 
                        _connection.CheckError(errorHandle, rc);
                    } 
                }
            }
            finally {
                // We don't need these any longer, get rid of it. 
                NativeBuffer.SafeDispose(ref _longBuffer);
                OciHandle.SafeDispose(ref defineHandle); 
            } 
        }
 
        internal bool Describe(ref int offset, OracleConnection connection, OciErrorHandle errorHandle) {
            //  Gets all of the column description information from the describe
            //  handle.  In addition, we'll determine the position of the column
            //  in the rowbuffer, based upon the offset parameter, which is passed 
            //  by ref so we can adjust the end position accordingly.
 
            short           tempub2; 
            byte            tempub1;
            OCI.DATATYPE    ociType; 
            bool            needSize = false;
            bool            cannotPrefetch = false;

            _describeHandle.GetAttribute(OCI.ATTR.OCI_ATTR_NAME,        out _columnName,errorHandle, _connection); 
            _describeHandle.GetAttribute(OCI.ATTR.OCI_ATTR_DATA_TYPE,   out tempub2,    errorHandle);
            _describeHandle.GetAttribute(OCI.ATTR.OCI_ATTR_IS_NULL,     out tempub1,    errorHandle); 
 
            _isNullable = (0 != tempub1);
 
            ociType = (OCI.DATATYPE)tempub2;

            switch (ociType) {
                case OCI.DATATYPE.CHAR: 
                case OCI.DATATYPE.VARCHAR2:
                    _describeHandle.GetAttribute(OCI.ATTR.OCI_ATTR_DATA_SIZE,   out _byteSize,      errorHandle); 
                    _describeHandle.GetAttribute(OCI.ATTR.OCI_ATTR_CHARSET_FORM,out tempub1,    errorHandle); 
                    OCI.CHARSETFORM charsetForm = (OCI.CHARSETFORM)tempub1;
 
                    _bindAsUTF16 = connection.ServerVersionAtLeastOracle8;

                    // SQLBUVSTS 217686: the _byteSize we have is size, in bytes, of the string in its server representation. This size can be
                    // less than the buffer size we need to fetch the UTF16 chars for the same string which can result in 
                    // either silent data truncation or ORA-01406 exception of Oracle.
                    // To calculate the byte size for UTF16 characters, we query for the size in UTF16 characters using 
                    // OCI_ATTR_CHAR_SIZE and double it (1 UTF16 char == 2 bytes). 
                    int charSize;
 
                    // according to Oracle's documentation, OCI_ATTR_CHAR_SIZE is supported only if both client and server >= 9
                    if (connection.ServerVersionAtLeastOracle9i && OCI.ClientVersionAtLeastOracle9i) {
                        // we can query for the char size since both client and server versions are >= 9
                        _describeHandle.GetAttribute(OCI.ATTR.OCI_ATTR_CHAR_SIZE, out tempub2, errorHandle); 
                        charSize = tempub2;
                    } 
                    else { 
                        // if either client or server is 8 or less, we cannot use OCI_ATTR_CHAR_SIZE attribute
                        // in that case, we assume the worse scenario: max number of characters is same or less as number of bytes used to encode it 
                        // (which is true in all NLS languages and UTF* encodings).
                        // we could query for OCI_ATTR_CHARSET_ID and calculate the max size with better efficiency, but this would
                        // complicate the calcs thus making the fix risky and prone for regressions.
                        charSize = _byteSize; 
                    }
 
                    if (charsetForm == OCI.CHARSETFORM.SQLCS_NCHAR) { 
                        // National Character Set
                        _metaType = MetaType.GetMetaTypeForType((OCI.DATATYPE.CHAR == ociType) ? OracleType.NChar : OracleType.NVarChar); 
                    }
                    else {
                        // Database Character Set
                        _metaType = MetaType.GetMetaTypeForType((OCI.DATATYPE.CHAR == ociType) ? OracleType.Char  : OracleType.VarChar); 

                        if (_bindAsUTF16) { 
                            // we deal only with UTF16 so get the size required to store same number of UTF16 chars 
                            _byteSize *= ADP.CharSize;
                        } 
                    }

                    // To fetch the data, we have to specify size in bytes.
                    // To be on the safe side and avoid regressions, select the max between the size as it 
                    // is encoded on the server and the size we've calculated above.
                    _byteSize = Math.Max(_byteSize, charSize * ADP.CharSize); 
 
                    needSize    = true;
                    break; 

                case OCI.DATATYPE.DATE:
                    _metaType   = MetaType.GetMetaTypeForType(OracleType.DateTime);
                    _byteSize   = _metaType.BindSize; 
                    needSize    = true;
                    break; 
 
                case OCI.DATATYPE.TIMESTAMP:
                    _metaType   = MetaType.GetMetaTypeForType(OracleType.Timestamp); 
                    _byteSize   = _metaType.BindSize;
                    needSize    = true;
                    break;
 
                case OCI.DATATYPE.TIMESTAMP_LTZ:
                    _metaType   = MetaType.GetMetaTypeForType(OracleType.TimestampLocal); 
                    _byteSize   = _metaType.BindSize; 
                    needSize    = true;
                    break; 

                case OCI.DATATYPE.TIMESTAMP_TZ:
                    _metaType   = MetaType.GetMetaTypeForType(OracleType.TimestampWithTZ);
                    _byteSize   = _metaType.BindSize; 
                    needSize    = true;
                    break; 
 
                case OCI.DATATYPE.INTERVAL_YM:
                    _metaType   = MetaType.GetMetaTypeForType(OracleType.IntervalYearToMonth); 
                    _byteSize   = _metaType.BindSize;
                    break;

                case OCI.DATATYPE.INTERVAL_DS: 
                    _metaType   = MetaType.GetMetaTypeForType(OracleType.IntervalDayToSecond);
                    _byteSize   = _metaType.BindSize; 
                    break; 

                case OCI.DATATYPE.NUMBER: 
                    _metaType   = MetaType.GetMetaTypeForType(OracleType.Number);
                    _byteSize   = _metaType.BindSize;

                    _describeHandle.GetAttribute(OCI.ATTR.OCI_ATTR_PRECISION,   out _precision, errorHandle); 
                    _describeHandle.GetAttribute(OCI.ATTR.OCI_ATTR_SCALE,       out _scale,     errorHandle);
                    break; 
 
                case OCI.DATATYPE.RAW:
                    _metaType   = MetaType.GetMetaTypeForType(OracleType.Raw); 
                    _describeHandle.GetAttribute(OCI.ATTR.OCI_ATTR_DATA_SIZE,   out _byteSize,  errorHandle);
                    needSize    = true;
                    break;
 
                case OCI.DATATYPE.ROWID:
                case OCI.DATATYPE.ROWID_DESC: 
                case OCI.DATATYPE.UROWID: 
                    _metaType   = MetaType.GetMetaTypeForType(OracleType.RowId);
                    _byteSize   = _metaType.BindSize; 
                    if (connection.UnicodeEnabled) {
                        _bindAsUTF16 = true;
                        _byteSize *= ADP.CharSize; // Since Oracle reported the number of characters and UTF16 characters are two bytes each, have to adjust the buffer size
                    } 
                    needSize    = true;
                    break; 
 
                case OCI.DATATYPE.BFILE:
                    _metaType   = MetaType.GetMetaTypeForType(OracleType.BFile); 
                    _byteSize   = _metaType.BindSize;
                    cannotPrefetch = true;
                    break;
 
                case OCI.DATATYPE.BLOB:
                    _metaType   = MetaType.GetMetaTypeForType(OracleType.Blob); 
                    _byteSize   = _metaType.BindSize; 
                    cannotPrefetch = true;
                    break; 

                case OCI.DATATYPE.CLOB:
                    _describeHandle.GetAttribute(OCI.ATTR.OCI_ATTR_CHARSET_FORM,    out tempub1,    errorHandle);
                    _metaType   = MetaType.GetMetaTypeForType((OCI.CHARSETFORM.SQLCS_NCHAR == (OCI.CHARSETFORM)tempub1) ? OracleType.NClob : OracleType.Clob); 
                    _byteSize   = _metaType.BindSize;
                    cannotPrefetch = true; 
                    break; 

                case OCI.DATATYPE.LONG: 
                    _metaType   = MetaType.GetMetaTypeForType(OracleType.LongVarChar);
                    _byteSize   = _metaType.BindSize;
                    needSize    = true;
                    cannotPrefetch = true; 
                    _bindAsUTF16 = connection.ServerVersionAtLeastOracle8;       // MDAC #79471 - Oracle7 servers don't do Unicode
                    break; 
 
                case OCI.DATATYPE.LONGRAW:
                    _metaType   = MetaType.GetMetaTypeForType(OracleType.LongRaw); 
                    _byteSize   = _metaType.BindSize;
                    needSize    = true;
                    cannotPrefetch = true;
                    break; 

                default: 
                    throw ADP.TypeNotSupported(ociType); 
            }
 
            if (_isNullable) {
                _indicatorOffset= offset;   offset += IntPtr.Size;
            }
            else { 
                _indicatorOffset = -1;
            } 
            if (needSize) { 
                _lengthOffset   = offset;   offset += IntPtr.Size;
            } 
            else {
                _lengthOffset = -1;
            }
            _valueOffset    = offset; 

            if (OCI.DATATYPE.LONG == ociType || OCI.DATATYPE.LONGRAW == ociType) { 
                offset += IntPtr.Size; 
            }
            else { 
                offset += _byteSize;
            }

            offset = (offset + (IntPtr.Size-1)) & ~(IntPtr.Size-1);          // align buffer; 

            // We don't need this any longer, get rid of it. 
            OciHandle.SafeDispose(ref _describeHandle); 

            return cannotPrefetch; 
        }

        internal void Dispose() {
            NativeBuffer.SafeDispose(ref _longBuffer); 
            OciLobLocator.SafeDispose(ref _lobLocator);
            OciHandle.SafeDispose(ref _describeHandle); 
            _columnName     = null; 
            _metaType       = null;
            _callback       = null; 
            _connection     = null;
        }

        internal void FixupLongValueLength(NativeBuffer buffer) { 
            if (null != _longBuffer) {
                Debug.Assert(_metaType.IsLong, "dangling long buffer?"); 
 
                // Determine the actual length of the LONG/LONG RAW data read, if we
                // haven't done so already. 
                if (-1 == _longLength) {
                    // Our "piecewise" fetching of LONG/LONG RAW data will extend the
                    // buffer by a chunk, and ask Oracle to fill it.
 
                    // Oracle calls ours _callback_GetColumnPiecewise for each new buffer.
                    // We create different chunk for each callback call, each chunk has its own 
                    // length. 

                    // Before the fix of RFC50002189, we assumed that native Oracle driver will fill each 
                    // non-last chunk fully (with size = request one == ChunkSize),so we calculated the total
                    // length as fixed chunk size * (num of chunks - 1) + last chunk size!
                    // This assumption was wrong (RFC50002189) - Oracle driver can fill less data than the chunk size.
                    // The fix for RFC50002189 includes: 
                    //  * remember each chunk size separately, as part of the chunk
                    //  * calculate and fixup the total length here (as before) and update the buffer[_lengthOffset] 
 
                    _longLength = _longBuffer.TotalLengthInBytes;
 
                    // Of course, we have to convert for character data to number of
                    // Unicode Characters read, not number of bytes
                    if (_bindAsUTF16) {
                        Debug.Assert(0 == (_longLength & 0x1), "odd length unicode data?"); 
                        _longLength /= 2;
                    } 
 
                    Debug.Assert(_longLength >= 0, "invalid size for LONG data?");
 
                    // Finally, we write the length back to the row buffer so we don't
                    // have to have two code paths to construct the managed object.
                    buffer.WriteInt32(_lengthOffset, _longLength);
                } 
            }
        } 
 
        internal string GetDataTypeName() {
            //  Returns the name of the back-end data type. 
            return _metaType.DataTypeName;
        }

        internal Type GetFieldType() { 
            //  Returns the actual clr type that the column is.
            return _metaType.BaseType; 
        } 

        internal Type GetFieldOracleType() { 
            //  Returns the actual oracletype  that the column is.
            return _metaType.NoConvertType;
        }
 
        internal object GetValue(NativeBuffer_RowBuffer buffer) {
            //  Returns an object that contains the value of the column in the 
            //  specified row buffer.  This method returns CLS-typed objects. 

            if (IsDBNull(buffer)) { 
                return DBNull.Value;
            }
//Debug.WriteLine(String.Format("{0}: {1}", _columnName, buffer.ReadInt16(_indicatorOffset+2)));
 
            switch (_metaType.OciType) {
                case OCI.DATATYPE.BFILE: { 
                    object value; 
                    using (OracleBFile bfile = GetOracleBFile(buffer)) {
                        value = bfile.Value;    // reading the LOB is MUCH more expensive than constructing an object we'll throw away 
                    }
                    return value;
                }
 
                case OCI.DATATYPE.RAW:
                case OCI.DATATYPE.LONGRAW: { 
                    long    length = GetBytes(buffer, 0, null, 0, 0); 
                    byte[]  value  = new byte[length];
                    GetBytes( buffer, 0, value, 0, (int)length ); 
                    return value;
                }

                case OCI.DATATYPE.DATE: 
                case OCI.DATATYPE.INT_TIMESTAMP:
                case OCI.DATATYPE.INT_TIMESTAMP_TZ: 
                case OCI.DATATYPE.INT_TIMESTAMP_LTZ: 
                    return GetDateTime( buffer );
 
                case OCI.DATATYPE.BLOB:
                case OCI.DATATYPE.CLOB: {
                    object value;
                    using (OracleLob lob = GetOracleLob(buffer)) { 
                        value = lob.Value;  // reading the LOB is MUCH more expensive than constructing an object we'll throw away
                    } 
                    return value; 
                }
 
                case OCI.DATATYPE.INT_INTERVAL_YM:
                    return GetInt32( buffer );

                case OCI.DATATYPE.VARNUM: 
                    return GetDecimal( buffer );
 
                case OCI.DATATYPE.CHAR: 
                case OCI.DATATYPE.VARCHAR2:
                case OCI.DATATYPE.LONG: 
                    return GetString( buffer );

                case OCI.DATATYPE.INT_INTERVAL_DS:
                    return GetTimeSpan( buffer ); 
            }
            throw ADP.TypeNotSupported(_metaType.OciType); 
        } 

        internal object GetOracleValue(NativeBuffer_RowBuffer buffer) { 
            //  Returns an object that contains the value of the column in the
            //  specified row buffer.  This method returns Oracle-typed objects.

//Debug.WriteLine(String.Format("{0}: {1}", _columnName, buffer.ReadInt16(_indicatorOffset+2))); 

            switch (_metaType.OciType) { 
                case OCI.DATATYPE.BFILE: 
                    return GetOracleBFile( buffer );
 
                case OCI.DATATYPE.RAW:
                case OCI.DATATYPE.LONGRAW:
                    return GetOracleBinary( buffer );
 
                case OCI.DATATYPE.DATE:
                case OCI.DATATYPE.INT_TIMESTAMP: 
                case OCI.DATATYPE.INT_TIMESTAMP_TZ: 
                case OCI.DATATYPE.INT_TIMESTAMP_LTZ:
                    return GetOracleDateTime( buffer ); 

                case OCI.DATATYPE.BLOB:
                case OCI.DATATYPE.CLOB:
                    return GetOracleLob( buffer ); 

                case OCI.DATATYPE.INT_INTERVAL_YM: 
                    return GetOracleMonthSpan( buffer ); 

                case OCI.DATATYPE.VARNUM: 
                    return GetOracleNumber( buffer );

                case OCI.DATATYPE.CHAR:
                case OCI.DATATYPE.VARCHAR2: 
                case OCI.DATATYPE.LONG:
                    return GetOracleString( buffer ); 
 
                case OCI.DATATYPE.INT_INTERVAL_DS:
                    return GetOracleTimeSpan( buffer ); 
            }
            throw ADP.TypeNotSupported(_metaType.OciType);
        }
 

        //--------------------------------------------------------------------- 
        // Get 
        //
        //  Returns an the value of the column in the specified row buffer as 
        //  the appropriate type
        //
        internal long GetBytes( NativeBuffer_RowBuffer buffer, long fieldOffset, byte[] destinationBuffer, int destinationOffset, int length ) {
            if (length < 0) { // MDAC 71007 
                throw ADP.InvalidDataLength(length);
            } 
            if ((destinationOffset < 0) || (null != destinationBuffer && destinationOffset >= destinationBuffer.Length)) { // MDAC 71013 
                throw ADP.InvalidDestinationBufferIndex(destinationBuffer.Length, destinationOffset, "bufferoffset"); // NOTE: Name matches public object model OracleDataReader.GetBytes()
            } 
            if (0 > fieldOffset || UInt32.MaxValue < fieldOffset) {
                throw ADP.InvalidSourceOffset("fieldOffset", 0, UInt32.MaxValue);
            }
            int byteCount; 

            if (IsLob) { 
                OracleType  lobType = _metaType.OracleType; 

                if (OracleType.Blob != lobType && OracleType.BFile != lobType) { 
                    throw ADP.InvalidCast();
                }
                if (IsDBNull(buffer)) {
                    throw ADP.DataReaderNoData(); 
                }
                using (OracleLob lob = new OracleLob(_lobLocator)) { 
                    uint valueLength = (uint)lob.Length; 
                    uint sourceOffset = (uint) fieldOffset;
 
                    if (sourceOffset > valueLength) { // MDAC 72830
                        throw ADP.InvalidSourceBufferIndex((int)valueLength, (int)sourceOffset, "fieldOffset"); // NOTE: Name matches public object model OracleDataReader.GetBytes()
                    }
                    byteCount = (int)(valueLength - sourceOffset); 

                    if (null != destinationBuffer) { 
                        byteCount = Math.Min(byteCount, length); 

                        if (0 < byteCount) { 
                            lob.Seek(sourceOffset,SeekOrigin.Begin);
                            lob.Read(destinationBuffer, destinationOffset, byteCount);
                        }
                    } 
                }
            } 
            else { 
                if (OracleType.Raw != OracleType && OracleType.LongRaw != OracleType) {
                    throw ADP.InvalidCast(); 
                }
                if (IsDBNull(buffer)) {
                    throw ADP.DataReaderNoData();
                } 
                FixupLongValueLength(buffer);
 
                int valueLength = OracleBinary.GetLength(buffer, _lengthOffset, _metaType); 
                int sourceOffset = (int) fieldOffset;
 
                byteCount = valueLength - sourceOffset;

                if (null != destinationBuffer) {
                    byteCount = Math.Min(byteCount, length); 

                    if (0 < byteCount) { 
                        OracleBinary.GetBytes(buffer, 
                            _valueOffset,
                            _metaType, 
                            sourceOffset,
                            destinationBuffer,
                            destinationOffset,
                            byteCount); 
                    }
                } 
            } 
            return Math.Max(0,byteCount);
        } 

        internal long GetChars(NativeBuffer_RowBuffer buffer, long fieldOffset, char[] destinationBuffer, int destinationOffset, int length) {
            if (length < 0) { // MDAC 71007
                throw ADP.InvalidDataLength(length); 
            }
            if ((destinationOffset < 0) || (null != destinationBuffer && destinationOffset >= destinationBuffer.Length)) { // MDAC 71013 
                throw ADP.InvalidDestinationBufferIndex(destinationBuffer.Length, destinationOffset, "bufferoffset"); // NOTE: Name matches public object model OracleDataReader.GetChars() 
            }
            if (0 > fieldOffset || UInt32.MaxValue < fieldOffset) { 
                throw ADP.InvalidSourceOffset("fieldOffset", 0, UInt32.MaxValue);
            }
            int charCount;
 
            if (IsLob) {
                OracleType  lobType = _metaType.OracleType; 
 
                if (OracleType.Clob     != lobType
                 && OracleType.NClob    != lobType 
                 && OracleType.BFile    != lobType) {
                    throw ADP.InvalidCast();
                }
                if (IsDBNull(buffer)) { 
                    throw ADP.DataReaderNoData();
                } 
                using (OracleLob lob = new OracleLob(_lobLocator)) { 
                    string s = (string)lob.Value;
 
                    int valueLength = s.Length;
                    int sourceOffset = (int) fieldOffset;

                    if (sourceOffset < 0) { // MDAC 72830 
                        throw ADP.InvalidSourceBufferIndex(valueLength, sourceOffset, "fieldOffset"); // NOTE: Name matches public object model OracleDataReader.GetChars()
                    } 
                    charCount = (int)(valueLength - sourceOffset); 

                    if (null != destinationBuffer) { 
                        charCount = Math.Min(charCount, length);

                        if (0 < charCount) {
                            char[]  result = s.ToCharArray(sourceOffset, charCount); 
                            Buffer.BlockCopy(result, 0, destinationBuffer, destinationOffset, charCount);
                        } 
                    } 
                }
            } 
            else {
                if (OracleType.Char         != OracleType
                 && OracleType.VarChar      != OracleType
                 && OracleType.LongVarChar  != OracleType 
                 && OracleType.NChar        != OracleType
                 && OracleType.NVarChar     != OracleType) { 
                    throw ADP.InvalidCast(); 
                }
                if (IsDBNull(buffer)) { 
                    throw ADP.DataReaderNoData();
                }
                FixupLongValueLength(buffer);
 
                int valueLength = OracleString.GetLength(buffer, _lengthOffset, _metaType);
                int sourceOffset = (int) fieldOffset; 
 
                charCount = valueLength - sourceOffset;
 
                if (null != destinationBuffer) {
                    charCount = Math.Min(charCount, length);

                    if (0 < charCount) { 
                        OracleString.GetChars(buffer,
                                                _valueOffset, 
                                                _lengthOffset, 
                                                _metaType,
                                                _connection, 
                                                _bindAsUTF16,
                                                sourceOffset,
                                                destinationBuffer,
                                                destinationOffset, 
                                                charCount);
                    } 
                } 

            } 
            return Math.Max(0,charCount);
        }

        internal DateTime GetDateTime(NativeBuffer_RowBuffer buffer) { 
            if (IsDBNull(buffer)) {
                throw ADP.DataReaderNoData(); 
            } 
            if (typeof(DateTime) != _metaType.BaseType) {
                throw ADP.InvalidCast(); 
            }
            Debug.Assert(null == _longBuffer, "dangling long buffer?");

            DateTime result = OracleDateTime.MarshalToDateTime(buffer, _valueOffset, _lengthOffset, _metaType, _connection); 
            return result;
        } 
 
        internal decimal GetDecimal(NativeBuffer_RowBuffer buffer) {
            if (typeof(decimal) != _metaType.BaseType) { 
                throw ADP.InvalidCast();
            }
            if (IsDBNull(buffer)) {
                throw ADP.DataReaderNoData(); 
            }
            Debug.Assert(null == _longBuffer, "dangling long buffer?"); 
 
            decimal result = OracleNumber.MarshalToDecimal(buffer, _valueOffset, _connection);
            return result; 
        }

        internal double GetDouble(NativeBuffer_RowBuffer buffer) {
            if (typeof(decimal) != _metaType.BaseType) { 
                throw ADP.InvalidCast();
            } 
            if (IsDBNull(buffer)) { 
                throw ADP.DataReaderNoData();
            } 
            Debug.Assert(null == _longBuffer, "dangling long buffer?");

            decimal decimalValue = OracleNumber.MarshalToDecimal(buffer, _valueOffset, _connection);
            double result = (double)decimalValue; 
            return result;
        } 
 
        internal float GetFloat(NativeBuffer_RowBuffer buffer) {
            if (typeof(decimal) != _metaType.BaseType) { 
                throw ADP.InvalidCast();
            }
            if (IsDBNull(buffer)) {
                throw ADP.DataReaderNoData(); 
            }
            Debug.Assert(null == _longBuffer, "dangling long buffer?"); 
 
            decimal decimalValue = OracleNumber.MarshalToDecimal(buffer, _valueOffset, _connection);
            float result = (float)decimalValue; 
            return result;
        }

        internal int GetInt32(NativeBuffer_RowBuffer buffer) { 
            if (typeof(int) != _metaType.BaseType
             && typeof(decimal) != _metaType.BaseType) { 
                throw ADP.InvalidCast(); 
            }
            if (IsDBNull(buffer)) { 
                throw ADP.DataReaderNoData();
            }
            Debug.Assert(null == _longBuffer, "dangling long buffer?");
 
            int result;
 
            if (typeof(int) == _metaType.BaseType) { 
                result = OracleMonthSpan.MarshalToInt32(buffer, _valueOffset);
            } 
            else {
                result = OracleNumber.MarshalToInt32(buffer, _valueOffset, _connection);
            }
            return result; 
        }
 
        internal Int64 GetInt64(NativeBuffer_RowBuffer buffer) { 
            if (typeof(decimal) != _metaType.BaseType) {
                throw ADP.InvalidCast(); 
            }
            if (IsDBNull(buffer)) {
                throw ADP.DataReaderNoData();
            } 
            Debug.Assert(null == _longBuffer, "dangling long buffer?");
 
            Int64 result = OracleNumber.MarshalToInt64(buffer, _valueOffset, _connection); 

            return result; 
        }

        internal string GetString(NativeBuffer_RowBuffer buffer) {
            if (IsLob) { 
                OracleType  lobType = _metaType.OracleType;
 
                if (OracleType.Clob != lobType && OracleType.NClob != lobType && OracleType.BFile != lobType) { 
                    throw ADP.InvalidCast();
                } 
                if (IsDBNull(buffer)) {
                    throw ADP.DataReaderNoData();
                }
                string result; 

                using (OracleLob lob = new OracleLob(_lobLocator)) { 
                    result = (string)lob.Value; 
                }
                return result; 
            }
            else {
                if (typeof(string) != _metaType.BaseType) {
                    throw ADP.InvalidCast(); 
                }
                if (IsDBNull(buffer)) { 
                    throw ADP.DataReaderNoData(); 
                }
                FixupLongValueLength(buffer); 

                string result = OracleString.MarshalToString(buffer, _valueOffset, _lengthOffset, _metaType, _connection, _bindAsUTF16, false);
                return result;
            } 
        }
 
        internal TimeSpan GetTimeSpan(NativeBuffer_RowBuffer buffer) { 
            if (typeof(TimeSpan) != _metaType.BaseType) {
                throw ADP.InvalidCast(); 
            }
            if (IsDBNull(buffer)) {
                throw ADP.DataReaderNoData();
            } 
            Debug.Assert(null == _longBuffer, "dangling long buffer?");
 
            TimeSpan result = OracleTimeSpan.MarshalToTimeSpan(buffer, _valueOffset); 
            return result;
        } 

        internal OracleBFile GetOracleBFile(NativeBuffer_RowBuffer buffer) {
            Debug.Assert(null == _longBuffer, "dangling long buffer?");
 
            if (typeof(OracleBFile) != _metaType.NoConvertType) {
                throw ADP.InvalidCast(); 
            } 
            if (IsDBNull(buffer)) {
                return OracleBFile.Null; 
            }
            OracleBFile result = new OracleBFile(_lobLocator);
            return result;
        } 

        internal OracleBinary GetOracleBinary(NativeBuffer_RowBuffer buffer) { 
            if (typeof(OracleBinary) != _metaType.NoConvertType) { 
                throw ADP.InvalidCast();
            } 
            FixupLongValueLength(buffer);

            if (IsDBNull(buffer)) {
                return OracleBinary.Null; 
            }
            OracleBinary result = new OracleBinary(buffer, _valueOffset, _lengthOffset, _metaType); 
            return result; 
        }
 
        internal OracleDateTime GetOracleDateTime(NativeBuffer_RowBuffer buffer) {
            if (typeof(OracleDateTime) != _metaType.NoConvertType) {
                throw ADP.InvalidCast();
            } 
            if (IsDBNull(buffer)) {
                return OracleDateTime.Null; 
            } 
            Debug.Assert(null == _longBuffer, "dangling long buffer?");
 
            OracleDateTime result = new OracleDateTime(buffer, _valueOffset, _lengthOffset, _metaType, _connection);
            return result;
        }
 
        internal OracleLob GetOracleLob(NativeBuffer_RowBuffer buffer) {
            if (typeof(OracleLob) != _metaType.NoConvertType) { 
                throw ADP.InvalidCast(); 
            }
            if (IsDBNull(buffer)) { 
                return OracleLob.Null;
            }
            Debug.Assert(null == _longBuffer, "dangling long buffer?");
 
            OracleLob result = new OracleLob(_lobLocator);
            return result; 
        } 

        internal OracleMonthSpan GetOracleMonthSpan(NativeBuffer_RowBuffer buffer) { 
            if (typeof(OracleMonthSpan) != _metaType.NoConvertType) {
                throw ADP.InvalidCast();
            }
            if (IsDBNull(buffer)) { 
                return OracleMonthSpan.Null;
            } 
            Debug.Assert(null == _longBuffer, "dangling long buffer?"); 

            OracleMonthSpan result = new OracleMonthSpan(buffer, _valueOffset); 
            return result;
        }

        internal OracleNumber GetOracleNumber(NativeBuffer_RowBuffer buffer) { 
            if (typeof(OracleNumber) != _metaType.NoConvertType) {
                throw ADP.InvalidCast(); 
            } 
            if (IsDBNull(buffer)) {
                return OracleNumber.Null; 
            }
            Debug.Assert(null == _longBuffer, "dangling long buffer?");

            OracleNumber result = new OracleNumber(buffer, _valueOffset); 
            return result;
        } 
 
        internal OracleString GetOracleString(NativeBuffer_RowBuffer buffer) {
            if (typeof(OracleString) != _metaType.NoConvertType) { 
                throw ADP.InvalidCast();
            }
            if (IsDBNull(buffer)) {
                return OracleString.Null; 
            }
            FixupLongValueLength(buffer); 
 
            OracleString result = new OracleString(buffer, _valueOffset, _lengthOffset, _metaType, _connection, _bindAsUTF16, false);
            return result; 
        }

        internal OracleTimeSpan GetOracleTimeSpan(NativeBuffer_RowBuffer buffer) {
            if (typeof(OracleTimeSpan) != _metaType.NoConvertType) { 
                throw ADP.InvalidCast();
            } 
            if (IsDBNull(buffer)) { 
                return OracleTimeSpan.Null;
            } 
            Debug.Assert(null == _longBuffer, "dangling long buffer?");

            OracleTimeSpan result = new OracleTimeSpan(buffer, _valueOffset);
            return result; 
        }
 
        internal bool IsDBNull(NativeBuffer_RowBuffer buffer) { 
            //  Returns true if the column value in the buffer is null.
            return (_isNullable && buffer.ReadInt16(_indicatorOffset) == (Int16)OCI.INDICATOR.ISNULL); 
        }

        internal void Rebind(OracleConnection connection, ref bool mustRelease, 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! 
            //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
 
            //  Here's the hook that gets called whenever we're about to fetch
            //  a new row, allowing us to reset any information that we shouldn't
            //  carry forward.
 
            handleToBind = null;
 
            switch (_metaType.OciType) { 
            case OCI.DATATYPE.LONG:
            case OCI.DATATYPE.LONGRAW: 
                _rowBuffer.WriteInt32(_lengthOffset, 0);
                _longLength = -1;     // reset the length to unknown;
                if (null != _longBuffer) {
                    _longBuffer.Reset();  // free all the memory we allocated, except the initial one 
                }
                else { 
                    _longBuffer = new NativeBuffer_LongColumnData(); 
                }
                handleToBind = _longBuffer; 
                break;

            case OCI.DATATYPE.BLOB:
            case OCI.DATATYPE.CLOB: 
            case OCI.DATATYPE.BFILE:
                OciLobLocator.SafeDispose(ref _lobLocator); 
                _lobLocator = new OciLobLocator(connection, _metaType.OracleType); 
                handleToBind = _lobLocator.Descriptor;
                break; 
            }

            // We need to add-ref the handle so it can't be released somehow
            // by another thread while we're fetching.  Only after we do that 
            // can we write it to the buffer for the Oracle to use during the
            // Fetch.  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);
                _rowBuffer.WriteIntPtr(_valueOffset, handleToBind.DangerousGetHandle());
            }
        } 
    };
} 
 

// 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.Data;
    using System.Data.Common;
    using System.Diagnostics;
    using System.IO; 
    using System.Runtime.ConstrainedExecution;
    using System.Runtime.InteropServices; 
    using System.Text; 

    //--------------------------------------------------------------------- 
    // OracleColumn
    //
    //  Contains all the information about a single column in a result set,
    //  and implements the methods necessary to describe column to Oracle 
    //  and to extract the column data from the native buffer used to fetch
    //  it. 
    // 
    sealed internal class OracleColumn {
        private OciParameterDescriptor _describeHandle;     // the Describe handle 
        private int             _ordinal;               // the ordinal position in the rowset (0..n-1)
        private string          _columnName;            // the name of the column

        private MetaType        _metaType; 
        private byte            _precision;             // precision of the column (OracleNumber only)
        private byte            _scale;                 // scale of the column (OracleNumber only) 
        private int             _byteSize;              // how many bytes we need in the row buffer 
        private bool            _isNullable;            // whether the value is nullable or not.
 
        private int             _indicatorOffset;       // offset from the start of the row buffer to the indicator binding (see OCI.INDICATOR)
        private int             _lengthOffset;          // offset from the start of the row buffer to the length binding
        private int             _valueOffset;           // offset from the start of the row buffer to the value binding
 
        private NativeBuffer_RowBuffer _rowBuffer;      // the row buffer we're bound to (reused for all rows fetched)
        private NativeBuffer_LongColumnData _longBuffer;// the out-of-line buffer used for piecewise binding; must be reset for each new fetch. 
        private int             _longLength;            // the length of the data we actually fetched into _longBuffer 
        private OCI.Callback.OCICallbackDefine _callback;// the piecewise binding callback for this column
 
        private OciLobLocator   _lobLocator;            // the descriptor allocated for LOB columns

        private OracleConnection _connection;           // the connection the column is on (LOB columns only)
        private int             _connectionCloseCount;  // The close count of the connection; used to decide if we're zombied 

        private bool            _bindAsUTF16;            // true whenever we're binding character data as Unicode... 
 

        // Construct by getting the specified describe handle from the specified statement handle 
        internal OracleColumn(OciStatementHandle statementHandle, int ordinal, OciErrorHandle errorHandle, OracleConnection connection) {
            _ordinal                = ordinal;
            _describeHandle         = statementHandle.GetDescriptor(_ordinal, errorHandle);;
            _connection             = connection; 
            _connectionCloseCount   = connection.CloseCount;
        } 
 

        internal string     ColumnName      { get { return _columnName; } } 
        internal bool       IsNullable      { get { return _isNullable; } }
        internal bool       IsLob           { get { return _metaType.IsLob; } }
        internal bool       IsLong          { get { return _metaType.IsLong; } }
        internal OracleType OracleType      { get { return _metaType.OracleType; } } 
        internal int        Ordinal         { get { return _ordinal; } }
        internal byte       Precision       { get { return _precision; } } 
        internal byte       Scale           { get { return _scale; } } 

        // This is the value used for the SchemaTable, which must be Chars... 
        internal int        SchemaTableSize { get { return (_bindAsUTF16 && !_metaType.IsLong)?_byteSize/2:_byteSize; } }


        private int _callback_GetColumnPiecewise( 
                        IntPtr      octxp,
                        IntPtr      defnp, 
                        uint        iter, 
                        IntPtr      bufpp,  // dvoid**
                        IntPtr      alenp,  // ub4** 
                        IntPtr      piecep, // ub1*
                        IntPtr      indpp,  // dvoid**
                        IntPtr      rcodep  // ub2**
                        ) { 
            //  Callback routine for Dynamic Binding column values from Oracle: tell
            //  Oracle where to stuff the data. 
 
            if (Bid.AdvancedOn)
                Bid.Trace("" 
                    +" octxp=0x%-07Ix"
                    +" defnp=0x%-07Ix"
                    +" iter=%-2d"
                    +" bufpp=0x%-07Ix" 
                    +" alenp=0x%-07Ix"
                    +" piecep=0x%-07Ix" 
                    +" indpp=0x%-07Ix" 
                    +" rcodep=0x%-07Ix\n",
                    octxp, 
                    defnp,
                    unchecked((int)iter), // tracing -- I don't care about overflow.
                    bufpp,
                    alenp, 
                    piecep,
                    indpp, 
                    rcodep 
                );
            //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 
            // NOTE: THIS IS A CALLBACK FUNCTION FROM AN OCI PINVOKE!
            //       Namely, OCIStmtFetch.  We expect that you will have called
            //       DangerousAddRef on the _rowBuffer and the _longBuffer
            //       SafeHandles, to prevent any Handle Recycling from occurring. 
            //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
 
            // RFC50002189 - chunk length is saved as part of chunk's buffer 
            // later, when the LONG field value is requested, TotalLength is used
            // to sum the lengths and the result is writtent into buffer[_lengthOffset], as before the change 

            IntPtr lengthPtr;
            IntPtr indicatorPtr = (-1 != _indicatorOffset) ? _rowBuffer.DangerousGetDataPtr(_indicatorOffset) : IntPtr.Zero;
            IntPtr valuePtr     = _longBuffer.GetChunk(out lengthPtr); 

            Marshal.WriteIntPtr(bufpp, valuePtr);       // *bufpp 
            Marshal.WriteIntPtr(indpp, indicatorPtr);   // *indpp 
            Marshal.WriteIntPtr(alenp, lengthPtr);      // *alenp
 
            // provide the size of allocated buffer, in bytes, to Oracle driver
            // on output, we will receive from Oracle driver the length of filled buffer, in bytes
            Marshal.WriteInt32(lengthPtr, NativeBuffer_LongColumnData.MaxChunkSize);    // **alenp
 
            GC.KeepAlive(this);
            return (int)OCI.RETURNCODE.OCI_CONTINUE; 
        } 

        internal void Bind(OciStatementHandle statementHandle, NativeBuffer_RowBuffer buffer, OciErrorHandle errorHandle, int rowBufferLength) { 
            //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
            // NOTE: You must have called DangerousAddRef on the buffer before
            //       calling this method, or you run the risk of allowing Handle
            //       Recycling to occur! 
            //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
 
            //  Binds the buffer for the column to the statement handle specified. 

            OciDefineHandle     defineHandle = null; 
            IntPtr          h;
            OCI.MODE        mode = OCI.MODE.OCI_DEFAULT;
            int             bindByteSize;
            OCI.DATATYPE    ociType = _metaType.OciType; 

            _rowBuffer = buffer; 
 
            if (_metaType.IsLong) {
                mode     = OCI.MODE.OCI_DYNAMIC_FETCH; 
                bindByteSize = Int32.MaxValue;
            }
            else {
                bindByteSize = _byteSize; 
            }
 
            IntPtr indicatorLocation = IntPtr.Zero; 
            IntPtr lengthLocation    = IntPtr.Zero;
            IntPtr valueLocation     = _rowBuffer.DangerousGetDataPtr(_valueOffset); 

            if (-1 != _indicatorOffset) {
                indicatorLocation = _rowBuffer.DangerousGetDataPtr(_indicatorOffset);
            } 
            if (-1 != _lengthOffset && !_metaType.IsLong) {
                lengthLocation = _rowBuffer.DangerousGetDataPtr(_lengthOffset); 
            } 
             try {
                int rc = TracedNativeMethods.OCIDefineByPos( 
                                            statementHandle,            // hndlp
                                            out h,                      // defnpp
                                            errorHandle,                // errhp
                                            checked((uint)_ordinal+1),  // position 
                                            valueLocation,              // valuep
                                            bindByteSize,               // value_sz 
                                            ociType,                    // htype 
                                            indicatorLocation,          // indp,
                                            lengthLocation,             // rlenp, 
                                            IntPtr.Zero,                // rcodep,
                                            mode                        // mode
                                            );
                if (rc != 0) { 
                    _connection.CheckError(errorHandle, rc);
                } 
                defineHandle = new OciDefineHandle(statementHandle, h); 

                if (0 != rowBufferLength) { 
                    uint valOffset = checked((uint)rowBufferLength);
                    uint indOffset = (-1 != _indicatorOffset) ? valOffset : 0;
                    uint lenOffset = (-1 != _lengthOffset && !_metaType.IsLong) ? valOffset : 0;
 
                    rc = TracedNativeMethods.OCIDefineArrayOfStruct(
                                                defineHandle, 
                                                errorHandle, 
                                                valOffset,
                                                indOffset, 
                                                lenOffset,
                                                0    // never use rcodep above...
                                                );
                    if (rc != 0) { 
                        _connection.CheckError(errorHandle, rc);
                    } 
                } 

                if (_metaType.UsesNationalCharacterSet) { 
                    Debug.Assert(!_metaType.IsLong, "LONG data may never be bound as NCHAR");
                    // NOTE:    the order is important here; setting charsetForm will
                    //          reset charsetId (I found this out the hard way...)
                    defineHandle.SetAttribute(OCI.ATTR.OCI_ATTR_CHARSET_FORM, (int)OCI.CHARSETFORM.SQLCS_NCHAR, errorHandle); 
                }
                if (!_connection.UnicodeEnabled) { 
                    if (_bindAsUTF16) { 
                        // NOTE:    the order is important here; setting charsetForm will
                        //          reset charsetId (I found this out the hard way...) 
                        defineHandle.SetAttribute(OCI.ATTR.OCI_ATTR_CHARSET_ID, (short)OCI.CHARSETID.OCI_UTF16ID, errorHandle);
                    }
                }
                if (_metaType.IsLong) { 
                    // Initialize the longBuffer in the rowBuffer to null
                    _rowBuffer.WriteIntPtr(_valueOffset, IntPtr.Zero); 
 
                    _callback = new OCI.Callback.OCICallbackDefine(_callback_GetColumnPiecewise);
 
                    rc = TracedNativeMethods.OCIDefineDynamic(
                                                defineHandle,       // defnp
                                                errorHandle,        // errhp
                                                IntPtr.Zero,        // dvoid *octxp, 
                                                _callback           // OCICallbackDefine ocbfp
                                                ); 
                    if (rc != 0) { 
                        _connection.CheckError(errorHandle, rc);
                    } 
                }
            }
            finally {
                // We don't need these any longer, get rid of it. 
                NativeBuffer.SafeDispose(ref _longBuffer);
                OciHandle.SafeDispose(ref defineHandle); 
            } 
        }
 
        internal bool Describe(ref int offset, OracleConnection connection, OciErrorHandle errorHandle) {
            //  Gets all of the column description information from the describe
            //  handle.  In addition, we'll determine the position of the column
            //  in the rowbuffer, based upon the offset parameter, which is passed 
            //  by ref so we can adjust the end position accordingly.
 
            short           tempub2; 
            byte            tempub1;
            OCI.DATATYPE    ociType; 
            bool            needSize = false;
            bool            cannotPrefetch = false;

            _describeHandle.GetAttribute(OCI.ATTR.OCI_ATTR_NAME,        out _columnName,errorHandle, _connection); 
            _describeHandle.GetAttribute(OCI.ATTR.OCI_ATTR_DATA_TYPE,   out tempub2,    errorHandle);
            _describeHandle.GetAttribute(OCI.ATTR.OCI_ATTR_IS_NULL,     out tempub1,    errorHandle); 
 
            _isNullable = (0 != tempub1);
 
            ociType = (OCI.DATATYPE)tempub2;

            switch (ociType) {
                case OCI.DATATYPE.CHAR: 
                case OCI.DATATYPE.VARCHAR2:
                    _describeHandle.GetAttribute(OCI.ATTR.OCI_ATTR_DATA_SIZE,   out _byteSize,      errorHandle); 
                    _describeHandle.GetAttribute(OCI.ATTR.OCI_ATTR_CHARSET_FORM,out tempub1,    errorHandle); 
                    OCI.CHARSETFORM charsetForm = (OCI.CHARSETFORM)tempub1;
 
                    _bindAsUTF16 = connection.ServerVersionAtLeastOracle8;

                    // SQLBUVSTS 217686: the _byteSize we have is size, in bytes, of the string in its server representation. This size can be
                    // less than the buffer size we need to fetch the UTF16 chars for the same string which can result in 
                    // either silent data truncation or ORA-01406 exception of Oracle.
                    // To calculate the byte size for UTF16 characters, we query for the size in UTF16 characters using 
                    // OCI_ATTR_CHAR_SIZE and double it (1 UTF16 char == 2 bytes). 
                    int charSize;
 
                    // according to Oracle's documentation, OCI_ATTR_CHAR_SIZE is supported only if both client and server >= 9
                    if (connection.ServerVersionAtLeastOracle9i && OCI.ClientVersionAtLeastOracle9i) {
                        // we can query for the char size since both client and server versions are >= 9
                        _describeHandle.GetAttribute(OCI.ATTR.OCI_ATTR_CHAR_SIZE, out tempub2, errorHandle); 
                        charSize = tempub2;
                    } 
                    else { 
                        // if either client or server is 8 or less, we cannot use OCI_ATTR_CHAR_SIZE attribute
                        // in that case, we assume the worse scenario: max number of characters is same or less as number of bytes used to encode it 
                        // (which is true in all NLS languages and UTF* encodings).
                        // we could query for OCI_ATTR_CHARSET_ID and calculate the max size with better efficiency, but this would
                        // complicate the calcs thus making the fix risky and prone for regressions.
                        charSize = _byteSize; 
                    }
 
                    if (charsetForm == OCI.CHARSETFORM.SQLCS_NCHAR) { 
                        // National Character Set
                        _metaType = MetaType.GetMetaTypeForType((OCI.DATATYPE.CHAR == ociType) ? OracleType.NChar : OracleType.NVarChar); 
                    }
                    else {
                        // Database Character Set
                        _metaType = MetaType.GetMetaTypeForType((OCI.DATATYPE.CHAR == ociType) ? OracleType.Char  : OracleType.VarChar); 

                        if (_bindAsUTF16) { 
                            // we deal only with UTF16 so get the size required to store same number of UTF16 chars 
                            _byteSize *= ADP.CharSize;
                        } 
                    }

                    // To fetch the data, we have to specify size in bytes.
                    // To be on the safe side and avoid regressions, select the max between the size as it 
                    // is encoded on the server and the size we've calculated above.
                    _byteSize = Math.Max(_byteSize, charSize * ADP.CharSize); 
 
                    needSize    = true;
                    break; 

                case OCI.DATATYPE.DATE:
                    _metaType   = MetaType.GetMetaTypeForType(OracleType.DateTime);
                    _byteSize   = _metaType.BindSize; 
                    needSize    = true;
                    break; 
 
                case OCI.DATATYPE.TIMESTAMP:
                    _metaType   = MetaType.GetMetaTypeForType(OracleType.Timestamp); 
                    _byteSize   = _metaType.BindSize;
                    needSize    = true;
                    break;
 
                case OCI.DATATYPE.TIMESTAMP_LTZ:
                    _metaType   = MetaType.GetMetaTypeForType(OracleType.TimestampLocal); 
                    _byteSize   = _metaType.BindSize; 
                    needSize    = true;
                    break; 

                case OCI.DATATYPE.TIMESTAMP_TZ:
                    _metaType   = MetaType.GetMetaTypeForType(OracleType.TimestampWithTZ);
                    _byteSize   = _metaType.BindSize; 
                    needSize    = true;
                    break; 
 
                case OCI.DATATYPE.INTERVAL_YM:
                    _metaType   = MetaType.GetMetaTypeForType(OracleType.IntervalYearToMonth); 
                    _byteSize   = _metaType.BindSize;
                    break;

                case OCI.DATATYPE.INTERVAL_DS: 
                    _metaType   = MetaType.GetMetaTypeForType(OracleType.IntervalDayToSecond);
                    _byteSize   = _metaType.BindSize; 
                    break; 

                case OCI.DATATYPE.NUMBER: 
                    _metaType   = MetaType.GetMetaTypeForType(OracleType.Number);
                    _byteSize   = _metaType.BindSize;

                    _describeHandle.GetAttribute(OCI.ATTR.OCI_ATTR_PRECISION,   out _precision, errorHandle); 
                    _describeHandle.GetAttribute(OCI.ATTR.OCI_ATTR_SCALE,       out _scale,     errorHandle);
                    break; 
 
                case OCI.DATATYPE.RAW:
                    _metaType   = MetaType.GetMetaTypeForType(OracleType.Raw); 
                    _describeHandle.GetAttribute(OCI.ATTR.OCI_ATTR_DATA_SIZE,   out _byteSize,  errorHandle);
                    needSize    = true;
                    break;
 
                case OCI.DATATYPE.ROWID:
                case OCI.DATATYPE.ROWID_DESC: 
                case OCI.DATATYPE.UROWID: 
                    _metaType   = MetaType.GetMetaTypeForType(OracleType.RowId);
                    _byteSize   = _metaType.BindSize; 
                    if (connection.UnicodeEnabled) {
                        _bindAsUTF16 = true;
                        _byteSize *= ADP.CharSize; // Since Oracle reported the number of characters and UTF16 characters are two bytes each, have to adjust the buffer size
                    } 
                    needSize    = true;
                    break; 
 
                case OCI.DATATYPE.BFILE:
                    _metaType   = MetaType.GetMetaTypeForType(OracleType.BFile); 
                    _byteSize   = _metaType.BindSize;
                    cannotPrefetch = true;
                    break;
 
                case OCI.DATATYPE.BLOB:
                    _metaType   = MetaType.GetMetaTypeForType(OracleType.Blob); 
                    _byteSize   = _metaType.BindSize; 
                    cannotPrefetch = true;
                    break; 

                case OCI.DATATYPE.CLOB:
                    _describeHandle.GetAttribute(OCI.ATTR.OCI_ATTR_CHARSET_FORM,    out tempub1,    errorHandle);
                    _metaType   = MetaType.GetMetaTypeForType((OCI.CHARSETFORM.SQLCS_NCHAR == (OCI.CHARSETFORM)tempub1) ? OracleType.NClob : OracleType.Clob); 
                    _byteSize   = _metaType.BindSize;
                    cannotPrefetch = true; 
                    break; 

                case OCI.DATATYPE.LONG: 
                    _metaType   = MetaType.GetMetaTypeForType(OracleType.LongVarChar);
                    _byteSize   = _metaType.BindSize;
                    needSize    = true;
                    cannotPrefetch = true; 
                    _bindAsUTF16 = connection.ServerVersionAtLeastOracle8;       // MDAC #79471 - Oracle7 servers don't do Unicode
                    break; 
 
                case OCI.DATATYPE.LONGRAW:
                    _metaType   = MetaType.GetMetaTypeForType(OracleType.LongRaw); 
                    _byteSize   = _metaType.BindSize;
                    needSize    = true;
                    cannotPrefetch = true;
                    break; 

                default: 
                    throw ADP.TypeNotSupported(ociType); 
            }
 
            if (_isNullable) {
                _indicatorOffset= offset;   offset += IntPtr.Size;
            }
            else { 
                _indicatorOffset = -1;
            } 
            if (needSize) { 
                _lengthOffset   = offset;   offset += IntPtr.Size;
            } 
            else {
                _lengthOffset = -1;
            }
            _valueOffset    = offset; 

            if (OCI.DATATYPE.LONG == ociType || OCI.DATATYPE.LONGRAW == ociType) { 
                offset += IntPtr.Size; 
            }
            else { 
                offset += _byteSize;
            }

            offset = (offset + (IntPtr.Size-1)) & ~(IntPtr.Size-1);          // align buffer; 

            // We don't need this any longer, get rid of it. 
            OciHandle.SafeDispose(ref _describeHandle); 

            return cannotPrefetch; 
        }

        internal void Dispose() {
            NativeBuffer.SafeDispose(ref _longBuffer); 
            OciLobLocator.SafeDispose(ref _lobLocator);
            OciHandle.SafeDispose(ref _describeHandle); 
            _columnName     = null; 
            _metaType       = null;
            _callback       = null; 
            _connection     = null;
        }

        internal void FixupLongValueLength(NativeBuffer buffer) { 
            if (null != _longBuffer) {
                Debug.Assert(_metaType.IsLong, "dangling long buffer?"); 
 
                // Determine the actual length of the LONG/LONG RAW data read, if we
                // haven't done so already. 
                if (-1 == _longLength) {
                    // Our "piecewise" fetching of LONG/LONG RAW data will extend the
                    // buffer by a chunk, and ask Oracle to fill it.
 
                    // Oracle calls ours _callback_GetColumnPiecewise for each new buffer.
                    // We create different chunk for each callback call, each chunk has its own 
                    // length. 

                    // Before the fix of RFC50002189, we assumed that native Oracle driver will fill each 
                    // non-last chunk fully (with size = request one == ChunkSize),so we calculated the total
                    // length as fixed chunk size * (num of chunks - 1) + last chunk size!
                    // This assumption was wrong (RFC50002189) - Oracle driver can fill less data than the chunk size.
                    // The fix for RFC50002189 includes: 
                    //  * remember each chunk size separately, as part of the chunk
                    //  * calculate and fixup the total length here (as before) and update the buffer[_lengthOffset] 
 
                    _longLength = _longBuffer.TotalLengthInBytes;
 
                    // Of course, we have to convert for character data to number of
                    // Unicode Characters read, not number of bytes
                    if (_bindAsUTF16) {
                        Debug.Assert(0 == (_longLength & 0x1), "odd length unicode data?"); 
                        _longLength /= 2;
                    } 
 
                    Debug.Assert(_longLength >= 0, "invalid size for LONG data?");
 
                    // Finally, we write the length back to the row buffer so we don't
                    // have to have two code paths to construct the managed object.
                    buffer.WriteInt32(_lengthOffset, _longLength);
                } 
            }
        } 
 
        internal string GetDataTypeName() {
            //  Returns the name of the back-end data type. 
            return _metaType.DataTypeName;
        }

        internal Type GetFieldType() { 
            //  Returns the actual clr type that the column is.
            return _metaType.BaseType; 
        } 

        internal Type GetFieldOracleType() { 
            //  Returns the actual oracletype  that the column is.
            return _metaType.NoConvertType;
        }
 
        internal object GetValue(NativeBuffer_RowBuffer buffer) {
            //  Returns an object that contains the value of the column in the 
            //  specified row buffer.  This method returns CLS-typed objects. 

            if (IsDBNull(buffer)) { 
                return DBNull.Value;
            }
//Debug.WriteLine(String.Format("{0}: {1}", _columnName, buffer.ReadInt16(_indicatorOffset+2)));
 
            switch (_metaType.OciType) {
                case OCI.DATATYPE.BFILE: { 
                    object value; 
                    using (OracleBFile bfile = GetOracleBFile(buffer)) {
                        value = bfile.Value;    // reading the LOB is MUCH more expensive than constructing an object we'll throw away 
                    }
                    return value;
                }
 
                case OCI.DATATYPE.RAW:
                case OCI.DATATYPE.LONGRAW: { 
                    long    length = GetBytes(buffer, 0, null, 0, 0); 
                    byte[]  value  = new byte[length];
                    GetBytes( buffer, 0, value, 0, (int)length ); 
                    return value;
                }

                case OCI.DATATYPE.DATE: 
                case OCI.DATATYPE.INT_TIMESTAMP:
                case OCI.DATATYPE.INT_TIMESTAMP_TZ: 
                case OCI.DATATYPE.INT_TIMESTAMP_LTZ: 
                    return GetDateTime( buffer );
 
                case OCI.DATATYPE.BLOB:
                case OCI.DATATYPE.CLOB: {
                    object value;
                    using (OracleLob lob = GetOracleLob(buffer)) { 
                        value = lob.Value;  // reading the LOB is MUCH more expensive than constructing an object we'll throw away
                    } 
                    return value; 
                }
 
                case OCI.DATATYPE.INT_INTERVAL_YM:
                    return GetInt32( buffer );

                case OCI.DATATYPE.VARNUM: 
                    return GetDecimal( buffer );
 
                case OCI.DATATYPE.CHAR: 
                case OCI.DATATYPE.VARCHAR2:
                case OCI.DATATYPE.LONG: 
                    return GetString( buffer );

                case OCI.DATATYPE.INT_INTERVAL_DS:
                    return GetTimeSpan( buffer ); 
            }
            throw ADP.TypeNotSupported(_metaType.OciType); 
        } 

        internal object GetOracleValue(NativeBuffer_RowBuffer buffer) { 
            //  Returns an object that contains the value of the column in the
            //  specified row buffer.  This method returns Oracle-typed objects.

//Debug.WriteLine(String.Format("{0}: {1}", _columnName, buffer.ReadInt16(_indicatorOffset+2))); 

            switch (_metaType.OciType) { 
                case OCI.DATATYPE.BFILE: 
                    return GetOracleBFile( buffer );
 
                case OCI.DATATYPE.RAW:
                case OCI.DATATYPE.LONGRAW:
                    return GetOracleBinary( buffer );
 
                case OCI.DATATYPE.DATE:
                case OCI.DATATYPE.INT_TIMESTAMP: 
                case OCI.DATATYPE.INT_TIMESTAMP_TZ: 
                case OCI.DATATYPE.INT_TIMESTAMP_LTZ:
                    return GetOracleDateTime( buffer ); 

                case OCI.DATATYPE.BLOB:
                case OCI.DATATYPE.CLOB:
                    return GetOracleLob( buffer ); 

                case OCI.DATATYPE.INT_INTERVAL_YM: 
                    return GetOracleMonthSpan( buffer ); 

                case OCI.DATATYPE.VARNUM: 
                    return GetOracleNumber( buffer );

                case OCI.DATATYPE.CHAR:
                case OCI.DATATYPE.VARCHAR2: 
                case OCI.DATATYPE.LONG:
                    return GetOracleString( buffer ); 
 
                case OCI.DATATYPE.INT_INTERVAL_DS:
                    return GetOracleTimeSpan( buffer ); 
            }
            throw ADP.TypeNotSupported(_metaType.OciType);
        }
 

        //--------------------------------------------------------------------- 
        // Get 
        //
        //  Returns an the value of the column in the specified row buffer as 
        //  the appropriate type
        //
        internal long GetBytes( NativeBuffer_RowBuffer buffer, long fieldOffset, byte[] destinationBuffer, int destinationOffset, int length ) {
            if (length < 0) { // MDAC 71007 
                throw ADP.InvalidDataLength(length);
            } 
            if ((destinationOffset < 0) || (null != destinationBuffer && destinationOffset >= destinationBuffer.Length)) { // MDAC 71013 
                throw ADP.InvalidDestinationBufferIndex(destinationBuffer.Length, destinationOffset, "bufferoffset"); // NOTE: Name matches public object model OracleDataReader.GetBytes()
            } 
            if (0 > fieldOffset || UInt32.MaxValue < fieldOffset) {
                throw ADP.InvalidSourceOffset("fieldOffset", 0, UInt32.MaxValue);
            }
            int byteCount; 

            if (IsLob) { 
                OracleType  lobType = _metaType.OracleType; 

                if (OracleType.Blob != lobType && OracleType.BFile != lobType) { 
                    throw ADP.InvalidCast();
                }
                if (IsDBNull(buffer)) {
                    throw ADP.DataReaderNoData(); 
                }
                using (OracleLob lob = new OracleLob(_lobLocator)) { 
                    uint valueLength = (uint)lob.Length; 
                    uint sourceOffset = (uint) fieldOffset;
 
                    if (sourceOffset > valueLength) { // MDAC 72830
                        throw ADP.InvalidSourceBufferIndex((int)valueLength, (int)sourceOffset, "fieldOffset"); // NOTE: Name matches public object model OracleDataReader.GetBytes()
                    }
                    byteCount = (int)(valueLength - sourceOffset); 

                    if (null != destinationBuffer) { 
                        byteCount = Math.Min(byteCount, length); 

                        if (0 < byteCount) { 
                            lob.Seek(sourceOffset,SeekOrigin.Begin);
                            lob.Read(destinationBuffer, destinationOffset, byteCount);
                        }
                    } 
                }
            } 
            else { 
                if (OracleType.Raw != OracleType && OracleType.LongRaw != OracleType) {
                    throw ADP.InvalidCast(); 
                }
                if (IsDBNull(buffer)) {
                    throw ADP.DataReaderNoData();
                } 
                FixupLongValueLength(buffer);
 
                int valueLength = OracleBinary.GetLength(buffer, _lengthOffset, _metaType); 
                int sourceOffset = (int) fieldOffset;
 
                byteCount = valueLength - sourceOffset;

                if (null != destinationBuffer) {
                    byteCount = Math.Min(byteCount, length); 

                    if (0 < byteCount) { 
                        OracleBinary.GetBytes(buffer, 
                            _valueOffset,
                            _metaType, 
                            sourceOffset,
                            destinationBuffer,
                            destinationOffset,
                            byteCount); 
                    }
                } 
            } 
            return Math.Max(0,byteCount);
        } 

        internal long GetChars(NativeBuffer_RowBuffer buffer, long fieldOffset, char[] destinationBuffer, int destinationOffset, int length) {
            if (length < 0) { // MDAC 71007
                throw ADP.InvalidDataLength(length); 
            }
            if ((destinationOffset < 0) || (null != destinationBuffer && destinationOffset >= destinationBuffer.Length)) { // MDAC 71013 
                throw ADP.InvalidDestinationBufferIndex(destinationBuffer.Length, destinationOffset, "bufferoffset"); // NOTE: Name matches public object model OracleDataReader.GetChars() 
            }
            if (0 > fieldOffset || UInt32.MaxValue < fieldOffset) { 
                throw ADP.InvalidSourceOffset("fieldOffset", 0, UInt32.MaxValue);
            }
            int charCount;
 
            if (IsLob) {
                OracleType  lobType = _metaType.OracleType; 
 
                if (OracleType.Clob     != lobType
                 && OracleType.NClob    != lobType 
                 && OracleType.BFile    != lobType) {
                    throw ADP.InvalidCast();
                }
                if (IsDBNull(buffer)) { 
                    throw ADP.DataReaderNoData();
                } 
                using (OracleLob lob = new OracleLob(_lobLocator)) { 
                    string s = (string)lob.Value;
 
                    int valueLength = s.Length;
                    int sourceOffset = (int) fieldOffset;

                    if (sourceOffset < 0) { // MDAC 72830 
                        throw ADP.InvalidSourceBufferIndex(valueLength, sourceOffset, "fieldOffset"); // NOTE: Name matches public object model OracleDataReader.GetChars()
                    } 
                    charCount = (int)(valueLength - sourceOffset); 

                    if (null != destinationBuffer) { 
                        charCount = Math.Min(charCount, length);

                        if (0 < charCount) {
                            char[]  result = s.ToCharArray(sourceOffset, charCount); 
                            Buffer.BlockCopy(result, 0, destinationBuffer, destinationOffset, charCount);
                        } 
                    } 
                }
            } 
            else {
                if (OracleType.Char         != OracleType
                 && OracleType.VarChar      != OracleType
                 && OracleType.LongVarChar  != OracleType 
                 && OracleType.NChar        != OracleType
                 && OracleType.NVarChar     != OracleType) { 
                    throw ADP.InvalidCast(); 
                }
                if (IsDBNull(buffer)) { 
                    throw ADP.DataReaderNoData();
                }
                FixupLongValueLength(buffer);
 
                int valueLength = OracleString.GetLength(buffer, _lengthOffset, _metaType);
                int sourceOffset = (int) fieldOffset; 
 
                charCount = valueLength - sourceOffset;
 
                if (null != destinationBuffer) {
                    charCount = Math.Min(charCount, length);

                    if (0 < charCount) { 
                        OracleString.GetChars(buffer,
                                                _valueOffset, 
                                                _lengthOffset, 
                                                _metaType,
                                                _connection, 
                                                _bindAsUTF16,
                                                sourceOffset,
                                                destinationBuffer,
                                                destinationOffset, 
                                                charCount);
                    } 
                } 

            } 
            return Math.Max(0,charCount);
        }

        internal DateTime GetDateTime(NativeBuffer_RowBuffer buffer) { 
            if (IsDBNull(buffer)) {
                throw ADP.DataReaderNoData(); 
            } 
            if (typeof(DateTime) != _metaType.BaseType) {
                throw ADP.InvalidCast(); 
            }
            Debug.Assert(null == _longBuffer, "dangling long buffer?");

            DateTime result = OracleDateTime.MarshalToDateTime(buffer, _valueOffset, _lengthOffset, _metaType, _connection); 
            return result;
        } 
 
        internal decimal GetDecimal(NativeBuffer_RowBuffer buffer) {
            if (typeof(decimal) != _metaType.BaseType) { 
                throw ADP.InvalidCast();
            }
            if (IsDBNull(buffer)) {
                throw ADP.DataReaderNoData(); 
            }
            Debug.Assert(null == _longBuffer, "dangling long buffer?"); 
 
            decimal result = OracleNumber.MarshalToDecimal(buffer, _valueOffset, _connection);
            return result; 
        }

        internal double GetDouble(NativeBuffer_RowBuffer buffer) {
            if (typeof(decimal) != _metaType.BaseType) { 
                throw ADP.InvalidCast();
            } 
            if (IsDBNull(buffer)) { 
                throw ADP.DataReaderNoData();
            } 
            Debug.Assert(null == _longBuffer, "dangling long buffer?");

            decimal decimalValue = OracleNumber.MarshalToDecimal(buffer, _valueOffset, _connection);
            double result = (double)decimalValue; 
            return result;
        } 
 
        internal float GetFloat(NativeBuffer_RowBuffer buffer) {
            if (typeof(decimal) != _metaType.BaseType) { 
                throw ADP.InvalidCast();
            }
            if (IsDBNull(buffer)) {
                throw ADP.DataReaderNoData(); 
            }
            Debug.Assert(null == _longBuffer, "dangling long buffer?"); 
 
            decimal decimalValue = OracleNumber.MarshalToDecimal(buffer, _valueOffset, _connection);
            float result = (float)decimalValue; 
            return result;
        }

        internal int GetInt32(NativeBuffer_RowBuffer buffer) { 
            if (typeof(int) != _metaType.BaseType
             && typeof(decimal) != _metaType.BaseType) { 
                throw ADP.InvalidCast(); 
            }
            if (IsDBNull(buffer)) { 
                throw ADP.DataReaderNoData();
            }
            Debug.Assert(null == _longBuffer, "dangling long buffer?");
 
            int result;
 
            if (typeof(int) == _metaType.BaseType) { 
                result = OracleMonthSpan.MarshalToInt32(buffer, _valueOffset);
            } 
            else {
                result = OracleNumber.MarshalToInt32(buffer, _valueOffset, _connection);
            }
            return result; 
        }
 
        internal Int64 GetInt64(NativeBuffer_RowBuffer buffer) { 
            if (typeof(decimal) != _metaType.BaseType) {
                throw ADP.InvalidCast(); 
            }
            if (IsDBNull(buffer)) {
                throw ADP.DataReaderNoData();
            } 
            Debug.Assert(null == _longBuffer, "dangling long buffer?");
 
            Int64 result = OracleNumber.MarshalToInt64(buffer, _valueOffset, _connection); 

            return result; 
        }

        internal string GetString(NativeBuffer_RowBuffer buffer) {
            if (IsLob) { 
                OracleType  lobType = _metaType.OracleType;
 
                if (OracleType.Clob != lobType && OracleType.NClob != lobType && OracleType.BFile != lobType) { 
                    throw ADP.InvalidCast();
                } 
                if (IsDBNull(buffer)) {
                    throw ADP.DataReaderNoData();
                }
                string result; 

                using (OracleLob lob = new OracleLob(_lobLocator)) { 
                    result = (string)lob.Value; 
                }
                return result; 
            }
            else {
                if (typeof(string) != _metaType.BaseType) {
                    throw ADP.InvalidCast(); 
                }
                if (IsDBNull(buffer)) { 
                    throw ADP.DataReaderNoData(); 
                }
                FixupLongValueLength(buffer); 

                string result = OracleString.MarshalToString(buffer, _valueOffset, _lengthOffset, _metaType, _connection, _bindAsUTF16, false);
                return result;
            } 
        }
 
        internal TimeSpan GetTimeSpan(NativeBuffer_RowBuffer buffer) { 
            if (typeof(TimeSpan) != _metaType.BaseType) {
                throw ADP.InvalidCast(); 
            }
            if (IsDBNull(buffer)) {
                throw ADP.DataReaderNoData();
            } 
            Debug.Assert(null == _longBuffer, "dangling long buffer?");
 
            TimeSpan result = OracleTimeSpan.MarshalToTimeSpan(buffer, _valueOffset); 
            return result;
        } 

        internal OracleBFile GetOracleBFile(NativeBuffer_RowBuffer buffer) {
            Debug.Assert(null == _longBuffer, "dangling long buffer?");
 
            if (typeof(OracleBFile) != _metaType.NoConvertType) {
                throw ADP.InvalidCast(); 
            } 
            if (IsDBNull(buffer)) {
                return OracleBFile.Null; 
            }
            OracleBFile result = new OracleBFile(_lobLocator);
            return result;
        } 

        internal OracleBinary GetOracleBinary(NativeBuffer_RowBuffer buffer) { 
            if (typeof(OracleBinary) != _metaType.NoConvertType) { 
                throw ADP.InvalidCast();
            } 
            FixupLongValueLength(buffer);

            if (IsDBNull(buffer)) {
                return OracleBinary.Null; 
            }
            OracleBinary result = new OracleBinary(buffer, _valueOffset, _lengthOffset, _metaType); 
            return result; 
        }
 
        internal OracleDateTime GetOracleDateTime(NativeBuffer_RowBuffer buffer) {
            if (typeof(OracleDateTime) != _metaType.NoConvertType) {
                throw ADP.InvalidCast();
            } 
            if (IsDBNull(buffer)) {
                return OracleDateTime.Null; 
            } 
            Debug.Assert(null == _longBuffer, "dangling long buffer?");
 
            OracleDateTime result = new OracleDateTime(buffer, _valueOffset, _lengthOffset, _metaType, _connection);
            return result;
        }
 
        internal OracleLob GetOracleLob(NativeBuffer_RowBuffer buffer) {
            if (typeof(OracleLob) != _metaType.NoConvertType) { 
                throw ADP.InvalidCast(); 
            }
            if (IsDBNull(buffer)) { 
                return OracleLob.Null;
            }
            Debug.Assert(null == _longBuffer, "dangling long buffer?");
 
            OracleLob result = new OracleLob(_lobLocator);
            return result; 
        } 

        internal OracleMonthSpan GetOracleMonthSpan(NativeBuffer_RowBuffer buffer) { 
            if (typeof(OracleMonthSpan) != _metaType.NoConvertType) {
                throw ADP.InvalidCast();
            }
            if (IsDBNull(buffer)) { 
                return OracleMonthSpan.Null;
            } 
            Debug.Assert(null == _longBuffer, "dangling long buffer?"); 

            OracleMonthSpan result = new OracleMonthSpan(buffer, _valueOffset); 
            return result;
        }

        internal OracleNumber GetOracleNumber(NativeBuffer_RowBuffer buffer) { 
            if (typeof(OracleNumber) != _metaType.NoConvertType) {
                throw ADP.InvalidCast(); 
            } 
            if (IsDBNull(buffer)) {
                return OracleNumber.Null; 
            }
            Debug.Assert(null == _longBuffer, "dangling long buffer?");

            OracleNumber result = new OracleNumber(buffer, _valueOffset); 
            return result;
        } 
 
        internal OracleString GetOracleString(NativeBuffer_RowBuffer buffer) {
            if (typeof(OracleString) != _metaType.NoConvertType) { 
                throw ADP.InvalidCast();
            }
            if (IsDBNull(buffer)) {
                return OracleString.Null; 
            }
            FixupLongValueLength(buffer); 
 
            OracleString result = new OracleString(buffer, _valueOffset, _lengthOffset, _metaType, _connection, _bindAsUTF16, false);
            return result; 
        }

        internal OracleTimeSpan GetOracleTimeSpan(NativeBuffer_RowBuffer buffer) {
            if (typeof(OracleTimeSpan) != _metaType.NoConvertType) { 
                throw ADP.InvalidCast();
            } 
            if (IsDBNull(buffer)) { 
                return OracleTimeSpan.Null;
            } 
            Debug.Assert(null == _longBuffer, "dangling long buffer?");

            OracleTimeSpan result = new OracleTimeSpan(buffer, _valueOffset);
            return result; 
        }
 
        internal bool IsDBNull(NativeBuffer_RowBuffer buffer) { 
            //  Returns true if the column value in the buffer is null.
            return (_isNullable && buffer.ReadInt16(_indicatorOffset) == (Int16)OCI.INDICATOR.ISNULL); 
        }

        internal void Rebind(OracleConnection connection, ref bool mustRelease, 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! 
            //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
 
            //  Here's the hook that gets called whenever we're about to fetch
            //  a new row, allowing us to reset any information that we shouldn't
            //  carry forward.
 
            handleToBind = null;
 
            switch (_metaType.OciType) { 
            case OCI.DATATYPE.LONG:
            case OCI.DATATYPE.LONGRAW: 
                _rowBuffer.WriteInt32(_lengthOffset, 0);
                _longLength = -1;     // reset the length to unknown;
                if (null != _longBuffer) {
                    _longBuffer.Reset();  // free all the memory we allocated, except the initial one 
                }
                else { 
                    _longBuffer = new NativeBuffer_LongColumnData(); 
                }
                handleToBind = _longBuffer; 
                break;

            case OCI.DATATYPE.BLOB:
            case OCI.DATATYPE.CLOB: 
            case OCI.DATATYPE.BFILE:
                OciLobLocator.SafeDispose(ref _lobLocator); 
                _lobLocator = new OciLobLocator(connection, _metaType.OracleType); 
                handleToBind = _lobLocator.Descriptor;
                break; 
            }

            // We need to add-ref the handle so it can't be released somehow
            // by another thread while we're fetching.  Only after we do that 
            // can we write it to the buffer for the Oracle to use during the
            // Fetch.  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);
                _rowBuffer.WriteIntPtr(_valueOffset, handleToBind.DangerousGetHandle());
            }
        } 
    };
} 
 

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