OleDbDataReader.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / fx / src / Data / System / Data / OleDb / OleDbDataReader.cs / 1305376 / OleDbDataReader.cs

                            //------------------------------------------------------------------------------ 
// 
//      Copyright (c) Microsoft Corporation.  All rights reserved.
// 
// [....] 
// [....]
//----------------------------------------------------------------------------- 
 
namespace System.Data.OleDb {
 
    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.ComponentModel; 
    using System.Data;
    using System.Data.Common; 
    using System.Data.ProviderBase; 
    using System.Diagnostics;
    using System.Globalization; 
    using System.IO;
    using System.Runtime.CompilerServices;
    using System.Runtime.InteropServices;
    using System.Text; 

    public sealed class OleDbDataReader : DbDataReader { 
 
        private CommandBehavior     _commandBehavior;
 
        private static int          _objectTypeCount; // Bid counter
        internal readonly int       ObjectID = System.Threading.Interlocked.Increment(ref _objectTypeCount);

        // object model interaction 
        private OleDbConnection _connection;
        private OleDbCommand _command; 
 
        // DataReader owns the parameter bindings until CloseDataReader
        // this allows OleDbCommand.Dispose to not require OleDbDataReader.Dispose 
        private Bindings _parameterBindings;

        // OLEDB interfaces
        private UnsafeNativeMethods.IMultipleResults _imultipleResults; 
        private UnsafeNativeMethods.IRowset _irowset;
        private UnsafeNativeMethods.IRow _irow; 
 
        private ChapterHandle _chapterHandle = ChapterHandle.DB_NULL_HCHAPTER;
 
        private int _depth;
        private bool _isClosed, _isRead, _hasRows, _hasRowsReadCheck;

        long _sequentialBytesRead; 
        int _sequentialOrdinal;
 
        private Bindings[] _bindings; // _metdata contains the ColumnBinding 

        // do we need to jump to the next accessor 
        private int _nextAccessorForRetrieval;

        // must increment the counter before retrieving value so that
        // if an exception is thrown, user can continue without erroring again 
        private int _nextValueForRetrieval;
 
        // record affected for the current dataset 
        private IntPtr _recordsAffected = ADP.RecordsUnaffected;
        private bool _useIColumnsRowset; 
        private bool _sequentialAccess;
        private bool _singleRow;

        // cached information for Reading (rowhandles/status) 
        private IntPtr _rowHandleFetchCount; // MDAC 60111 (>1 fails against jet)
        private RowHandleBuffer _rowHandleNativeBuffer; 
 
        private IntPtr _rowFetchedCount;
        private int _currentRow; 

        private DataTable _dbSchemaTable;

        private int _visibleFieldCount; 
        private MetaData[] _metadata;
        private FieldNameLookup _fieldNameLookup; 
 
        // ctor for an ICommandText, IMultipleResults, IRowset, IRow
        // ctor for an ADODB.Recordset, ADODB.Record or Hierarchial resultset 
        internal OleDbDataReader(OleDbConnection connection, OleDbCommand command, int depth, CommandBehavior commandBehavior) {
            OleDbConnection.VerifyExecutePermission();

            _connection = connection; 
            _command = command;
            _commandBehavior = commandBehavior; 
 
            if ((null != command) && (0 == _depth)) {
                _parameterBindings = command.TakeBindingOwnerShip(); 
            }
            _depth = depth;
        }
 
        private void Initialize() {
            CommandBehavior behavior = _commandBehavior; 
            _useIColumnsRowset = (0 != (CommandBehavior.KeyInfo & behavior)); 
            _sequentialAccess  = (0 != (CommandBehavior.SequentialAccess & behavior)); // MDAC 60296
            if (0 == _depth) { // MDAC 70886 
                _singleRow     = (0 != (CommandBehavior.SingleRow & behavior));
            }
        }
 
        internal void InitializeIMultipleResults(object result) {
            Initialize(); 
            _imultipleResults = (UnsafeNativeMethods.IMultipleResults) result; // maybe null if no results 
        }
        internal void InitializeIRowset(object result, ChapterHandle chapterHandle, IntPtr recordsAffected) { 
            // if from ADODB, connection will be null
            if ((null == _connection) || (ChapterHandle.DB_NULL_HCHAPTER != chapterHandle)) { // MDAC 59629
                _rowHandleFetchCount = new IntPtr(1);
            } 

            Initialize(); 
            _recordsAffected = recordsAffected; 
            _irowset = (UnsafeNativeMethods.IRowset) result; // maybe null if no results
            _chapterHandle = chapterHandle; 
        }

        internal void InitializeIRow(object result, IntPtr recordsAffected) {
            Initialize(); 
            Debug.Assert(_singleRow, "SingleRow not already set");
            _singleRow = true; 
            _recordsAffected = recordsAffected; 
            _irow = (UnsafeNativeMethods.IRow) result; // maybe null if no results
            _hasRows = (null != _irow); 
        }

        internal OleDbCommand Command {
            get { 
                return _command;
            } 
        } 

        override public int Depth { 
            get {
                Bid.Trace(" %d#\n", ObjectID);
                if (IsClosed) { // MDAC 63669
                    throw ADP.DataReaderClosed("Depth"); 
                }
                return _depth; 
            } 
        }
 
        override public Int32 FieldCount {
            get {
                Bid.Trace(" %d#\n", ObjectID);
                if (IsClosed) { // MDAC 63669 
                    throw ADP.DataReaderClosed("FieldCount");
                } 
                MetaData[] metadata = MetaData; 
                return ((null != metadata) ? metadata.Length : 0);
            } 
        }

        override public bool HasRows { // MDAC 78405
            get { 
                Bid.Trace(" %d#\n", ObjectID);
                if (IsClosed) { // MDAC 63669 
                    throw ADP.DataReaderClosed("HasRows"); 
                }
                return _hasRows; 
            }
        }

        override public Boolean IsClosed { 
            get { // if we have a rowset or multipleresults, we may have more to read
                Bid.Trace(" %d#\n", ObjectID); 
                Debug.Assert((_singleRow && !_isClosed && !_isRead && (null == _irow) && (null == _irowset)) || 
                             _isClosed == ((null == _irow) && (null == _irowset) && (null == _imultipleResults)
                                           && (null == _dbSchemaTable) && (null == _connection) && (null == _command)), // MDAC 59536 
                                           "IsClosed mismatch");
                return _isClosed;
            }
        } 

        private MetaData[] MetaData { 
            get { return _metadata; } 
        }
 
        override public int RecordsAffected {
            get {
                Bid.Trace(" %d#\n", ObjectID);
                return ADP.IntPtrToInt32(_recordsAffected); 
            }
        } 
 
        /*
        internal long RecordsAffectedLong { 
            get {
                return (long)_recordsAffected;
            }
        }*/ 

        override public object this[Int32 index] { 
            get { 
                return GetValue(index);
            } 
        }

        override public object this[String name] {
            get { 
                int ordinal = GetOrdinal(name);
                return GetValue(ordinal); 
            } 
        }
 
        // grouping the native OLE DB casts togther by required interfaces and optional interfaces
        // want these to be methods, not properties otherwise they appear in VS7 managed debugger which attempts to evaluate them

        // required interface, safe cast 
        private UnsafeNativeMethods.IAccessor IAccessor() {
            Bid.Trace(" %d#, IAccessor\n", ObjectID); 
            return (UnsafeNativeMethods.IAccessor) IRowset(); 
        }
 
        // required interface, safe cast
        private UnsafeNativeMethods.IRowsetInfo IRowsetInfo() {
            Bid.Trace(" %d#, IRowsetInfo\n", ObjectID);
            return (UnsafeNativeMethods.IRowsetInfo) IRowset(); 
        }
 
        private UnsafeNativeMethods.IRowset IRowset() { 
            UnsafeNativeMethods.IRowset irowset = _irowset;
            if (null == irowset) { 
                Debug.Assert(false, "object is disposed");
                throw new ObjectDisposedException(GetType().Name);
            }
            return irowset; 
        }
 
        private UnsafeNativeMethods.IRow IRow() { 
            UnsafeNativeMethods.IRow irow = _irow;
            if (null == irow) { 
                Debug.Assert(false, "object is disposed");
                throw new ObjectDisposedException(GetType().Name);
            }
            return irow; 
        }
 
#if INDEXINFO 
        public DataTable GetIndexTable() {
            // if we can't get index info, it's not catastrophic 
            return null;
        }
#endif
 
        override public DataTable GetSchemaTable() {
            IntPtr hscp; 
            Bid.ScopeEnter(out hscp, " %d#\n", ObjectID); 
            try {
                DataTable schemaTable = _dbSchemaTable; 
                if (null == schemaTable) {
                    MetaData[] metadata = MetaData;
                    if ((null != metadata) && (0 < metadata.Length)) {
                        if ((0 < metadata.Length) && _useIColumnsRowset && (null != _connection)) { 
                            AppendSchemaInfo();
                        } 
                        schemaTable = BuildSchemaTable(metadata); 
                    }
                    else if (IsClosed) { // MDAC 68331 
                        throw ADP.DataReaderClosed("GetSchemaTable");
                    }
                    //GetSchemaTable() is defined to return null after NextResult returns false
                    //throw ADP.DataReaderNoData(); 
                }
                return schemaTable; 
            } 
            finally {
                Bid.ScopeLeave(ref hscp); 
            }
        }

        internal void BuildMetaInfo() { 
            Debug.Assert(null == _metadata, "BuildMetaInfo: already built, by _metadata");
 
            if (null != _irowset) { 
                if (_useIColumnsRowset) {
                    BuildSchemaTableRowset(_irowset); 
                }
                else {
                    BuildSchemaTableInfo(_irowset, false, false);
                } 
                if (null != _metadata && 0 < _metadata.Length) {
                    // @devnote: because we want to use the DBACCESSOR_OPTIMIZED bit, 
                    // we are required to create the accessor before fetching any rows 
                    CreateAccessors(true);
                    Debug.Assert(null != _bindings, "unexpected dbBindings"); 
                }
            }
            else if (null != _irow) {
                BuildSchemaTableInfo(_irow, false, false); 
                if (null != _metadata && 0 < _metadata.Length) {
                    CreateBindingsFromMetaData(true); 
                } 
            }
            if (null == _metadata) { 
                _hasRows = false;
                _visibleFieldCount = 0;
                _metadata = new MetaData[0];
            } 
        }
 
        private DataTable BuildSchemaTable(MetaData[] metadata) { 
            Debug.Assert(null == _dbSchemaTable, "BuildSchemaTable: schema table already exists");
            Debug.Assert(null != metadata, "BuildSchemaTable: no _metadata"); 

            DataTable schemaTable = new DataTable("SchemaTable");
            schemaTable.Locale = CultureInfo.InvariantCulture;
            schemaTable.MinimumCapacity = metadata.Length; 

            DataColumn name       = new DataColumn("ColumnName",       typeof(System.String)); 
            DataColumn ordinal    = new DataColumn("ColumnOrdinal",    typeof(System.Int32)); 
            DataColumn size       = new DataColumn("ColumnSize",       typeof(System.Int32));
            DataColumn precision  = new DataColumn("NumericPrecision", typeof(System.Int16)); 
            DataColumn scale      = new DataColumn("NumericScale",     typeof(System.Int16));

            DataColumn dataType   = new DataColumn("DataType",         typeof(System.Type));
            DataColumn providerType = new DataColumn("ProviderType",   typeof(System.Int32)); 

            DataColumn isLong        = new DataColumn("IsLong",           typeof(System.Boolean)); 
            DataColumn allowDBNull   = new DataColumn("AllowDBNull",      typeof(System.Boolean)); 
            DataColumn isReadOnly    = new DataColumn("IsReadOnly",       typeof(System.Boolean));
            DataColumn isRowVersion  = new DataColumn("IsRowVersion",     typeof(System.Boolean)); 

            DataColumn isUnique        = new DataColumn("IsUnique",        typeof(System.Boolean));
            DataColumn isKey           = new DataColumn("IsKey",           typeof(System.Boolean));
            DataColumn isAutoIncrement = new DataColumn("IsAutoIncrement", typeof(System.Boolean)); 
            DataColumn isHidden        = new DataColumn("IsHidden",        typeof(System.Boolean));
 
            DataColumn baseSchemaName  = new DataColumn("BaseSchemaName",  typeof(System.String)); 
            DataColumn baseCatalogName = new DataColumn("BaseCatalogName", typeof(System.String));
            DataColumn baseTableName   = new DataColumn("BaseTableName",   typeof(System.String)); 
            DataColumn baseColumnName  = new DataColumn("BaseColumnName",  typeof(System.String));

            ordinal.DefaultValue = 0;
            isLong.DefaultValue = false; 

            DataColumnCollection columns = schemaTable.Columns; 
 
            columns.Add(name);
            columns.Add(ordinal); 
            columns.Add(size);
            columns.Add(precision);
            columns.Add(scale);
 
            columns.Add(dataType);
            columns.Add(providerType); 
 
            columns.Add(isLong);
            columns.Add(allowDBNull); 
            columns.Add(isReadOnly);
            columns.Add(isRowVersion);

            columns.Add(isUnique); 
            columns.Add(isKey);
            columns.Add(isAutoIncrement); 
            if (_visibleFieldCount < metadata.Length) { 
                columns.Add(isHidden);
            } 

            columns.Add(baseSchemaName);
            columns.Add(baseCatalogName);
            columns.Add(baseTableName); 
            columns.Add(baseColumnName);
 
            for (int i = 0; i < metadata.Length; ++i) { 
                MetaData info = metadata[i];
 
                DataRow newRow = schemaTable.NewRow();
                newRow[name] = info.columnName;
                newRow[ordinal] = i; // MDAC 68319
                // @devnote: size is count of characters for WSTR or STR, bytes otherwise 
                // @devnote: see OLEDB spec under IColumnsInfo::GetColumnInfo
                newRow[size] = ((info.type.enumOleDbType != OleDbType.BSTR) ? info.size : -1); // MDAC 72653 
                newRow[precision] = info.precision; // MDAC 72800 
                newRow[scale] = info.scale;
 
                newRow[dataType] = info.type.dataType;
                newRow[providerType] = info.type.enumOleDbType;
                newRow[isLong] = OleDbDataReader.IsLong(info.flags);
                if (info.isKeyColumn) { 
                    newRow[allowDBNull] = OleDbDataReader.AllowDBNull(info.flags);
                } 
                else { 
                    newRow[allowDBNull] = OleDbDataReader.AllowDBNullMaybeNull(info.flags);
                } 
                newRow[isReadOnly] = OleDbDataReader.IsReadOnly(info.flags);
                newRow[isRowVersion] = OleDbDataReader.IsRowVersion(info.flags);

                newRow[isUnique] = info.isUnique; 
                newRow[isKey] = info.isKeyColumn;
                newRow[isAutoIncrement] = info.isAutoIncrement; 
                if (_visibleFieldCount < metadata.Length) { 
                    newRow[isHidden] = info.isHidden;
                } 

                if (null != info.baseSchemaName) {
                    newRow[baseSchemaName] = info.baseSchemaName;
                } 
                if (null != info.baseCatalogName) {
                    newRow[baseCatalogName] = info.baseCatalogName; 
                } 
                if (null != info.baseTableName) {
                    newRow[baseTableName] = info.baseTableName; 
                }
                if (null != info.baseColumnName) {
                    newRow[baseColumnName] = info.baseColumnName;
                } 

                schemaTable.Rows.Add(newRow); 
                newRow.AcceptChanges(); 
            }
 
            // mark all columns as readonly
            int count = columns.Count;
            for (int i=0; i < count; i++) {
                columns[i].ReadOnly = true; // MDAC 70943 
            }
 
            _dbSchemaTable = schemaTable; 
            return schemaTable;
        } 

        private void BuildSchemaTableInfo(object handle, bool filterITypeInfo, bool filterChapters) {
            Debug.Assert(null == _dbSchemaTable, "non-null SchemaTable");
            Debug.Assert(null == _metadata, "non-null metadata"); 
            Debug.Assert(null != handle, "unexpected null rowset");
 
            Bid.Trace(" %d#, IColumnsInfo\n", ObjectID); 
            UnsafeNativeMethods.IColumnsInfo icolumnsInfo = (handle as UnsafeNativeMethods.IColumnsInfo);
            if (null == icolumnsInfo) { 
                 Bid.Trace(" %08X{HRESULT}\n", OleDbHResult.E_NOINTERFACE);
                _dbSchemaTable = null;
#if DEBUG
                if (handle is UnsafeNativeMethods.IRow) { 
                    Debug.Assert(false, "bad IRow - IColumnsInfo not available");
                } 
                else { 
                    Debug.Assert(handle is UnsafeNativeMethods.IRowset, "bad IRowset - IColumnsInfo not available");
                } 
#endif
                return;
            }
 
            OleDbHResult hr;
            IntPtr columnCount = ADP.PtrZero; // column count 
            IntPtr columnInfos = ADP.PtrZero; // ptr to byvalue tagDBCOLUMNINFO[] 

            using(DualCoTaskMem safehandle = new DualCoTaskMem(icolumnsInfo, out columnCount, out columnInfos, out hr)) { 
                if (hr < 0) {
                    ProcessResults(hr);
                }
                if (0 < (int)columnCount) { 
                    BuildSchemaTableInfoTable(columnCount.ToInt32(), columnInfos, filterITypeInfo, filterChapters);
                } 
            } 
        }
 
        // create DataColumns
        // add DataColumns to DataTable
        // add schema information to DataTable
        // generate unique column names 
        private void BuildSchemaTableInfoTable(int columnCount, IntPtr columnInfos, bool filterITypeInfo, bool filterChapters) {
            Debug.Assert(0 < columnCount, "BuildSchemaTableInfoTable - no column"); 
 
            int rowCount = 0;
            MetaData[] metainfo = new MetaData[columnCount]; 

            // for every column, build an equivalent to tagDBCOLUMNINFO
            tagDBCOLUMNINFO dbColumnInfo = new tagDBCOLUMNINFO();
            for (int i = 0, offset = 0; i < columnCount; ++i, offset += ODB.SizeOf_tagDBCOLUMNINFO) { 
                Marshal.PtrToStructure(ADP.IntPtrOffset(columnInfos, offset), dbColumnInfo);
#if WIN32 
                if (0 >= (int) dbColumnInfo.iOrdinal) { 
#else
                if (0 >= (long) dbColumnInfo.iOrdinal) { 
#endif
                    continue;
                }
                if (OleDbDataReader.DoColumnDropFilter(dbColumnInfo.dwFlags)) { 
                    continue;
                } 
 
                if (null == dbColumnInfo.pwszName) {
                    dbColumnInfo.pwszName = ""; 
                }
                if (filterITypeInfo && (ODB.DBCOLUMN_TYPEINFO == dbColumnInfo.pwszName)) { // MDAC 65306
                    continue;
                } 
                if (filterChapters && (NativeDBType.HCHAPTER == dbColumnInfo.wType)) {
                    continue;  // filter chapters in IRowset from IDBSchemaRowset for DumpToTable 
                } 

                bool islong  = OleDbDataReader.IsLong(dbColumnInfo.dwFlags); 
                bool isfixed = OleDbDataReader.IsFixed(dbColumnInfo.dwFlags);
                NativeDBType dbType = NativeDBType.FromDBType(dbColumnInfo.wType, islong, isfixed);

                MetaData info = new MetaData(); 
                info.columnName = dbColumnInfo.pwszName;
                info.type = dbType; 
                info.ordinal = dbColumnInfo.iOrdinal; 
#if WIN32
                    info.size = (int)dbColumnInfo.ulColumnSize; 
#else
                    long maxsize = (long) dbColumnInfo.ulColumnSize;
                    info.size = (((maxsize < 0) || (Int32.MaxValue < maxsize)) ? Int32.MaxValue : (int)maxsize);
#endif 
                info.flags = dbColumnInfo.dwFlags;
                info.precision = dbColumnInfo.bPrecision; 
                info.scale = dbColumnInfo.bScale; 

                info.kind = dbColumnInfo.columnid.eKind; 
                switch(dbColumnInfo.columnid.eKind) {
                    case ODB.DBKIND_GUID_NAME:
                    case ODB.DBKIND_GUID_PROPID:
                    case ODB.DBKIND_GUID: 
                        info.guid = dbColumnInfo.columnid.uGuid;
                        break; 
                    default: 
                        Debug.Assert(ODB.DBKIND_PGUID_NAME != dbColumnInfo.columnid.eKind, "OLE DB providers never return pGuid-style bindings.");
                        Debug.Assert(ODB.DBKIND_PGUID_PROPID != dbColumnInfo.columnid.eKind, "OLE DB providers never return pGuid-style bindings."); 
                        info.guid = Guid.Empty;
                        break;
                }
                switch(dbColumnInfo.columnid.eKind) { 
                    case ODB.DBKIND_GUID_PROPID:
                    case ODB.DBKIND_PROPID: 
                        info.propid = dbColumnInfo.columnid.ulPropid; 
                        break;
                    case ODB.DBKIND_GUID_NAME: 
                    case ODB.DBKIND_NAME:
                        if (ADP.PtrZero != dbColumnInfo.columnid.ulPropid) {
                            info.idname = Marshal.PtrToStringUni(dbColumnInfo.columnid.ulPropid);
                        } 
                        else {
                            info.idname = null; 
                        } 
                        break;
                    default: 
                        info.propid = ADP.PtrZero;
                        break;
                }
                metainfo[rowCount] = info; 

#if DEBUG 
                if (AdapterSwitches.DataSchema.TraceVerbose) { 
                    Debug.WriteLine("OleDbDataReader[" + info.ordinal.ToInt64().ToString(CultureInfo.InvariantCulture) + ", " + dbColumnInfo.pwszName + "]=" + dbType.enumOleDbType.ToString() + "," + dbType.dataSourceType + ", " + dbType.wType);
                } 
#endif
                rowCount++;
            }
            if (rowCount < columnCount) { // shorten names array appropriately 
                MetaData[] tmpinfo = new MetaData[rowCount];
                for (int i = 0; i < rowCount; ++i) { 
                    tmpinfo[i] = metainfo[i]; 
                }
                metainfo = tmpinfo; 
            }
            _visibleFieldCount = rowCount;
            _metadata = metainfo;
        } 

        private void BuildSchemaTableRowset(object handle) { 
            Debug.Assert(null == _dbSchemaTable, "BuildSchemaTableRowset - non-null SchemaTable"); 
            Debug.Assert(null != handle, "BuildSchemaTableRowset(object) - unexpected null handle");
 
            Bid.Trace(" %d, IColumnsRowset\n", ObjectID);
            UnsafeNativeMethods.IColumnsRowset icolumnsRowset = (handle as UnsafeNativeMethods.IColumnsRowset);

            if (null != icolumnsRowset) { 
                UnsafeNativeMethods.IRowset rowset = null;
                IntPtr cOptColumns; 
                OleDbHResult hr; 

                using(DualCoTaskMem prgOptColumns = new DualCoTaskMem(icolumnsRowset, out cOptColumns, out hr)) { 
                    Debug.Assert((0 == hr) || prgOptColumns.IsInvalid, "GetAvailableCOlumns: unexpected return");

                    Bid.Trace(" %d#, IID_IRowset\n", ObjectID);
                    hr = icolumnsRowset.GetColumnsRowset(ADP.PtrZero, cOptColumns, prgOptColumns, ref ODB.IID_IRowset, 0, ADP.PtrZero, out rowset); 
                    Bid.Trace(" %08X{HRESULT}\n", hr);
                } 
 
                Debug.Assert((0 <= hr) || (null == rowset), "if GetColumnsRowset failed, rowset should be null");
                if (hr < 0) { 
                    ProcessResults(hr);
                }
                DumpToSchemaTable(rowset);
 
                // VSTFDEVDIV 479576: release the rowset to avoid race condition between the GC and the user code causing
                // "Connection is busy with results for another command" exception 
                if (null != rowset) { 
                    Marshal.ReleaseComObject(rowset);
                } 
            }
            else {
                Bid.Trace(" %08X{HRESULT}\n", OleDbHResult.E_NOINTERFACE);
                _useIColumnsRowset = false; // MDAC 72653 
                BuildSchemaTableInfo(handle, false, false);
            } 
        } 

        override public void Close() { 
            IntPtr hscp;
            Bid.ScopeEnter(out hscp, " %d#\n", ObjectID);
            try {
                OleDbConnection con = _connection; 
                OleDbCommand cmd = _command;
                Bindings bindings = _parameterBindings; 
                _connection = null; 
                _command = null;
                _parameterBindings = null; 

                _isClosed = true;

                DisposeOpenResults(); 
                _hasRows = false;
 
                if ((null != cmd) && cmd.canceling) { // MDAC 68964 
                    DisposeNativeMultipleResults();
 
                    if (null != bindings) {
                        bindings.CloseFromConnection();
                        bindings = null;
                    } 
                }
                else { 
                    UnsafeNativeMethods.IMultipleResults multipleResults = _imultipleResults; 
                    _imultipleResults = null;
 
                    if (null != multipleResults) {
                        // if we don't have a cmd, same as a cancel (don't call NextResults) which is ADODB behavior

                        try { 
                            // tricky code path is an exception is thrown
                            // causing connection to do a ResetState and connection.Close 
                            // resulting in OleDbCommand.CloseFromConnection 
                            if ((null != cmd) && !cmd.canceling) { // MDAC 71435
                                IntPtr affected = IntPtr.Zero; 
                                OleDbException nextResultsFailure = NextResults(multipleResults, null, cmd, out affected);
                                _recordsAffected = AddRecordsAffected(_recordsAffected, affected);
                                if (null != nextResultsFailure) {
                                    throw nextResultsFailure; 
                                }
                            } 
                        } 
                        finally {
                            if (null != multipleResults) { 
                                Marshal.ReleaseComObject(multipleResults);
                            }
                        }
                    } 
                }
 
                if ((null != cmd) && (0 == _depth)) { 
                    // return bindings back to the cmd after closure of root DataReader
                    cmd.CloseFromDataReader(bindings); // MDAC 52283 
                }

                if (null != con) {
                    con.RemoveWeakReference(this); 

                    // if the DataReader is Finalized it will not close the connection 
                    if (IsCommandBehavior(CommandBehavior.CloseConnection)) { 
                        con.Close();
                    } 
                }

                // release unmanaged objects
                RowHandleBuffer rowHandleNativeBuffer = _rowHandleNativeBuffer; 
                _rowHandleNativeBuffer = null;
                if (null != rowHandleNativeBuffer) { 
                    rowHandleNativeBuffer.Dispose(); 
                }
            } 
            finally {
                Bid.ScopeLeave(ref hscp);
            }
        } 

        internal void CloseReaderFromConnection(bool canceling) { 
            // being called from the connection, we will have a command. that command 
            // may be Disposed, but it doesn't matter since another command can't execute
            // until all DataReader are closed 
            if (null != _command) { //
                _command.canceling = canceling;
            }
 
            // called from the connection which will remove this from its ReferenceCollection
            // we want the NextResult behavior, but no errors 
            _connection = null; 

            Close(); 
        }

        private void DisposeManagedRowset() {
            //not cleared after last rowset 
            //_hasRows = false;
 
            _isRead = false; 
            _hasRowsReadCheck = false;
 
            _nextAccessorForRetrieval = 0;
            _nextValueForRetrieval = 0;

            Bindings[] bindings = _bindings; 
            _bindings = null;
 
            if (null != bindings) { 
                for (int i = 0; i < bindings.Length; ++i) {
                    if (null != bindings[i]) { // MDAC 77007 
                        bindings[i].Dispose();
                    }
                }
            } 

            _currentRow = 0; 
            _rowFetchedCount = IntPtr.Zero; 

            _dbSchemaTable = null; 
            _visibleFieldCount = 0;
            _metadata = null;
            _fieldNameLookup = null;
        } 

        private void DisposeNativeMultipleResults() { 
            UnsafeNativeMethods.IMultipleResults imultipleResults = _imultipleResults; 
            _imultipleResults = null;
 
            if (null != imultipleResults) {
                Marshal.ReleaseComObject(imultipleResults);
            }
        } 

        private void DisposeNativeRowset() { 
            UnsafeNativeMethods.IRowset irowset = _irowset; 
            _irowset = null;
 
            ChapterHandle chapter = _chapterHandle;
            _chapterHandle = ChapterHandle.DB_NULL_HCHAPTER;

            if (ChapterHandle.DB_NULL_HCHAPTER != chapter) { // MDAC 81441 
                chapter.Dispose();
            } 
 
            if (null != irowset) {
                Marshal.ReleaseComObject(irowset); 
            }
        }

        private void DisposeNativeRow() { 
            UnsafeNativeMethods.IRow irow = _irow;
            _irow = null; 
 
            if (null != irow) {
                Marshal.ReleaseComObject(irow); 
            }
        }

        private void DisposeOpenResults() { 
            DisposeManagedRowset();
 
            DisposeNativeRow(); 
            DisposeNativeRowset();
        } 

        override public Boolean GetBoolean(int ordinal) {
            ColumnBinding binding = GetColumnBinding(ordinal);
            return binding.ValueBoolean(); 
        }
 
        override public Byte GetByte(int ordinal) { 
            ColumnBinding binding = GetColumnBinding(ordinal);
            return binding.ValueByte(); 
        }

        private ColumnBinding DoSequentialCheck(int ordinal, Int64 dataIndex, string method) {
            ColumnBinding binding = GetColumnBinding(ordinal); 

            if (dataIndex > Int32.MaxValue) { 
                throw ADP.InvalidSourceBufferIndex(0, dataIndex, "dataIndex"); 
            }
            if (_sequentialOrdinal != ordinal) { 
                _sequentialOrdinal = ordinal;
                _sequentialBytesRead = 0;
            }
            else if (_sequentialAccess && (_sequentialBytesRead < dataIndex)) { 
                throw ADP.NonSeqByteAccess(dataIndex, _sequentialBytesRead, method);
            } 
            // getting the value doesn't really belong, but it's common to both 
            // callers GetBytes and GetChars so we might as well have the code here
            return binding; 
        }

        override public Int64 GetBytes(int ordinal, Int64 dataIndex, byte[] buffer, Int32 bufferIndex, Int32 length) {
            ColumnBinding binding = DoSequentialCheck(ordinal, dataIndex, ADP.GetBytes); 
            byte[] value = binding.ValueByteArray();
 
            if (null == buffer) { 
                return value.Length;
            } 
            int srcIndex = (int) dataIndex;
            int byteCount = Math.Min(value.Length - srcIndex, length);
            if (srcIndex < 0) { // MDAC 72830
                throw ADP.InvalidSourceBufferIndex(value.Length, srcIndex, "dataIndex"); 
            }
            else if ((bufferIndex < 0) || (bufferIndex >= buffer.Length)) { // MDAC 71013 
                throw ADP.InvalidDestinationBufferIndex(buffer.Length, bufferIndex, "bufferIndex"); 
            }
            if (0 < byteCount) { 
                // @usernote: user may encounter ArgumentException from Buffer.BlockCopy
                Buffer.BlockCopy(value, srcIndex, buffer, bufferIndex, byteCount);
                _sequentialBytesRead = srcIndex + byteCount; // MDAC 71013
            } 
            else if (length < 0) { // MDAC 71007
                throw ADP.InvalidDataLength(length); 
            } 
            else {
                byteCount = 0; 
            }
            return byteCount;
        }
 
        override public Int64 GetChars(int ordinal, Int64 dataIndex, char[] buffer, Int32 bufferIndex, Int32 length) {
            ColumnBinding binding = DoSequentialCheck(ordinal, dataIndex, ADP.GetChars); 
            string value =  binding.ValueString(); 

            if (null == buffer) { 
                return value.Length;
            }

            int srcIndex = (int) dataIndex; 
            int charCount = Math.Min(value.Length - srcIndex, length);
            if (srcIndex < 0) { // MDAC 72830 
                throw ADP.InvalidSourceBufferIndex(value.Length, srcIndex, "dataIndex"); 
            }
            else if ((bufferIndex < 0) || (bufferIndex >= buffer.Length)) { // MDAC 71013 
                throw ADP.InvalidDestinationBufferIndex(buffer.Length, bufferIndex, "bufferIndex");
            }
            if (0 < charCount) {
                // @usernote: user may encounter ArgumentException from String.CopyTo 
                value.CopyTo(srcIndex, buffer, bufferIndex, charCount);
                _sequentialBytesRead = srcIndex + charCount; // MDAC 71013 
            } 
            else if (length < 0) { // MDAC 71007
                throw ADP.InvalidDataLength(length); 
            }
            else {
                charCount = 0;
            } 
            return charCount;
        } 
 
        [ EditorBrowsableAttribute(EditorBrowsableState.Never) ] // MDAC 69508
        override public Char GetChar(int ordinal) { 
            throw ADP.NotSupported();
        }

        [ EditorBrowsableAttribute(EditorBrowsableState.Advanced) ] 
        new public OleDbDataReader GetData(int ordinal) {
            ColumnBinding binding = GetColumnBinding(ordinal); 
            return binding.ValueChapter(); 
        }
 
        override protected DbDataReader GetDbDataReader(int ordinal) {
            return GetData(ordinal);
        }
 
        internal OleDbDataReader ResetChapter(int bindingIndex, int index, RowBinding rowbinding, int valueOffset) {
            return GetDataForReader(_metadata[bindingIndex + index].ordinal, rowbinding, valueOffset); 
        } 

        private OleDbDataReader GetDataForReader(IntPtr ordinal, RowBinding rowbinding, int valueOffset) { 
            UnsafeNativeMethods.IRowsetInfo rowsetInfo = IRowsetInfo();
            UnsafeNativeMethods.IRowset result;
            OleDbHResult hr;
 
            Bid.Trace(" %d#, ColumnOrdinal=%Id\n", ObjectID, ordinal);
            hr = rowsetInfo.GetReferencedRowset((IntPtr)ordinal, ref ODB.IID_IRowset, out result); 
            Bid.Trace(" %08X{HRESULT}\n", hr); 

            ProcessResults(hr); 

            OleDbDataReader reader = null;
            if (null != result) {
                // only when the first datareader is closed will the connection close 
                ChapterHandle chapterHandle = ChapterHandle.CreateChapterHandle(result, rowbinding, valueOffset);
                reader = new OleDbDataReader(_connection, _command, 1+Depth, _commandBehavior & ~CommandBehavior.CloseConnection); 
                reader.InitializeIRowset(result, chapterHandle, ADP.RecordsUnaffected); 
                reader.BuildMetaInfo();
                reader.HasRowsRead(); 

                if (null != _connection) {
                    // connection tracks all readers to prevent cmd from executing
                    // until all readers (including nested) are closed 
                    _connection.AddWeakReference(reader, OleDbReferenceCollection.DataReaderTag);
                } 
            } 
            return reader;
        } 

        override public String GetDataTypeName(int index) {
            if (null != _metadata) {
                return _metadata[index].type.dataSourceType; 
            }
            throw ADP.DataReaderNoData(); 
        } 

        override public DateTime GetDateTime(int ordinal) { 
            ColumnBinding binding = GetColumnBinding(ordinal);
            return binding.ValueDateTime();
        }
 
        override public Decimal GetDecimal(int ordinal) {
            ColumnBinding binding = GetColumnBinding(ordinal); 
            return binding.ValueDecimal(); 
        }
 
        override public Double GetDouble(int ordinal) {
            ColumnBinding binding = GetColumnBinding(ordinal);
            return binding.ValueDouble();
        } 

        override public IEnumerator GetEnumerator() { 
            return new DbEnumerator((IDataReader)this, IsCommandBehavior(CommandBehavior.CloseConnection)); 
        }
 
        override public Type GetFieldType(int index) {
            if (null != _metadata) {
                return _metadata[index].type.dataType;
            } 
            throw ADP.DataReaderNoData();
        } 
 
        override public Single GetFloat(int ordinal) {
            ColumnBinding binding = GetColumnBinding(ordinal); 
            return binding.ValueSingle();
        }

        override public Guid GetGuid(int ordinal) { 
            ColumnBinding binding = GetColumnBinding(ordinal);
            return binding.ValueGuid(); 
        } 

        override public Int16 GetInt16(int ordinal) { 
            ColumnBinding binding = GetColumnBinding(ordinal);
            return binding.ValueInt16();
        }
 
        override public Int32 GetInt32(int ordinal) {
            ColumnBinding binding = GetColumnBinding(ordinal); 
            return binding.ValueInt32(); 
        }
 
        override public Int64 GetInt64(int ordinal) {
            ColumnBinding binding = GetColumnBinding(ordinal);
            return binding.ValueInt64();
        } 

        override public String GetName(int index) { 
            if (null != _metadata) { 
                Debug.Assert(null != _metadata[index].columnName, "MDAC 66681");
                return _metadata[index].columnName; 
            }
            throw ADP.DataReaderNoData();
        }
 
        override public Int32 GetOrdinal(String name) {
            if (null == _fieldNameLookup) { 
                if (null == _metadata) { 
                    throw ADP.DataReaderNoData();
                } 
                _fieldNameLookup = new FieldNameLookup(this, -1);
            }
            return _fieldNameLookup.GetOrdinal(name); // MDAC 71470
        } 

        override public String GetString(int ordinal) { 
            ColumnBinding binding = GetColumnBinding(ordinal); 
            return binding.ValueString();
        } 

        public TimeSpan GetTimeSpan(int ordinal) {
            return (TimeSpan) GetValue(ordinal);
        } 

        private MetaData DoValueCheck(int ordinal) { 
            if (!_isRead) { 
                // Read hasn't been called yet or no more data
                throw ADP.DataReaderNoData(); 
            }
            else if (_sequentialAccess && (ordinal < _nextValueForRetrieval)) {
                throw ADP.NonSequentialColumnAccess(ordinal, _nextValueForRetrieval);
            } 
            // @usernote: user may encounter the IndexOutOfRangeException
            MetaData info = _metadata[ordinal]; 
            return info; 
        }
 
        private ColumnBinding GetColumnBinding(int ordinal) {
            MetaData info = DoValueCheck(ordinal);
            return GetValueBinding(info);
        } 

        private ColumnBinding GetValueBinding(MetaData info) { 
            ColumnBinding binding = info.columnBinding; 
            Debug.Assert(null != binding, "null binding");
 
            // do we need to jump to the next accessor
            for (int i = _nextAccessorForRetrieval; i <= binding.IndexForAccessor; ++i) {
                Debug.Assert(_nextAccessorForRetrieval <= binding.IndexForAccessor, "backwards index for accessor");
                Debug.Assert(_nextAccessorForRetrieval == i, "failed to increment"); 

                if (_sequentialAccess) { 
                    if (_nextValueForRetrieval != binding.Index) { // release old value 
                        _metadata[_nextValueForRetrieval].columnBinding.ResetValue();
                    } 
                    _nextAccessorForRetrieval = binding.IndexForAccessor;
                }

                if (null != _irowset) { 
                    GetRowDataFromHandle(); // will increment _nextAccessorForRetrieval
                } 
                else if (null != _irow) { 
                    GetRowValue(); // will increment _nextAccessorForRetrieval
                } 
                else {
                    throw ADP.DataReaderNoData();
                }
            } 

            // to enforce sequential access 
            _nextValueForRetrieval = binding.Index; 
            return binding;
        } 

        override public object GetValue(int ordinal) {
            ColumnBinding binding = GetColumnBinding(ordinal);
            object value = binding.Value(); 
            return value;
        } 
 
        override public Int32 GetValues(object[] values) {
            if (null == values) { 
                throw ADP.ArgumentNull("values");
            }
            MetaData info = DoValueCheck(0);
            int count = Math.Min(values.Length, _visibleFieldCount); 
            for (int i = 0; (i < _metadata.Length) && (i < count); ++i) {
                ColumnBinding binding = GetValueBinding(_metadata[i]); 
                values[i] = binding.Value(); 
            }
            return count; 
        }

        private bool IsCommandBehavior(CommandBehavior condition) {
            return (condition == (condition & _commandBehavior)); 
        }
 
        override public Boolean IsDBNull(int ordinal) { 
            ColumnBinding binding = GetColumnBinding(ordinal);
            return binding.IsValueNull(); 
        }

        private void ProcessResults(OleDbHResult hr) {
            Exception e; 
            if (null != _command) {
                e = OleDbConnection.ProcessResults(hr, _connection, _command); 
            } 
            else {
                e = OleDbConnection.ProcessResults(hr, _connection, _connection); 
            }
            if (null != e) { throw e; }
        }
 

        static private IntPtr AddRecordsAffected(IntPtr recordsAffected, IntPtr affected) { // MDAC 65374 
#if WIN32 
            if (0 <= (int)affected) {
                if (0 <= (int)recordsAffected) { 
                    return (IntPtr)((int)recordsAffected + (int)affected);
#else
            if (0 <= (long)affected) {
                if (0 <= (long)recordsAffected) { 
                    return (IntPtr)((long)recordsAffected + (long)affected);
#endif 
                } 
                return affected;
            } 
            return recordsAffected;
        }

        override public int VisibleFieldCount { 
            get {
                Bid.Trace(" %d#\n", ObjectID); 
                if (IsClosed) { 
                    throw ADP.DataReaderClosed("VisibleFieldCount");
                } 
                return _visibleFieldCount;
            }
        }
 
        internal void HasRowsRead() { // MDAC 78405
            Debug.Assert(!_hasRowsReadCheck, "_hasRowsReadCheck not reset"); 
            bool flag = Read(); 
            _hasRows = flag;
            _hasRowsReadCheck = true; 
            _isRead = false;
        }

        static internal OleDbException NextResults(UnsafeNativeMethods.IMultipleResults imultipleResults, OleDbConnection connection, OleDbCommand command, out IntPtr recordsAffected) { 
            recordsAffected = ADP.RecordsUnaffected;
            List exceptions = null; // WebData 104564 
            if (null != imultipleResults) { 
                object result;
                IntPtr affected; 
                OleDbHResult hr;


                // MSOLAP provider doesn't move onto the next result when calling GetResult with IID_NULL, but does return S_OK with 0 affected records. 
                // we want to break out of that infinite loop for ExecuteNonQuery and the multiple result Close scenarios
                for (int loop = 0;; ++loop) { 
                    if ((null != command) && command.canceling) { // MDAC 68964 
                        break;
                    } 

                    Bid.Trace(" DBRESULTFLAG_DEFAULT, IID_NULL\n");
                    hr = imultipleResults.GetResult(ADP.PtrZero, ODB.DBRESULTFLAG_DEFAULT, ref ODB.IID_NULL, out affected, out result);
                    Bid.Trace(" %08X{HRESULT}, RecordAffected=%Id\n", hr, affected); 

                    // If a provider doesn't support IID_NULL and returns E_NOINTERFACE we want to break out 
                    // of the loop without throwing an exception.  Our behavior will match ADODB in that scenario 
                    // where Recordset.Close just releases the interfaces without proccessing remaining results
                    if ((OleDbHResult.DB_S_NORESULT == hr) || (OleDbHResult.E_NOINTERFACE == hr)) { // MDAC 70874 
                        break;
                    }
                    if (null != connection) {
                        Exception e = OleDbConnection.ProcessResults(hr, connection, command); 
                        if (null != e) {
                            OleDbException excep = (e as OleDbException); 
                            if (null != excep) { 
                                if (null == exceptions) {
                                    exceptions = new List(); 
                                }
                                exceptions.Add(excep);
                            }
                            else { 
                                Debug.Assert(OleDbHResult.DB_E_OBJECTOPEN == hr, "unexpected");
                                throw e; // we don't expect to be here, but it could happen 
                            } 
                        }
                    } 
                    else if (hr < 0) {
                        SafeNativeMethods.Wrapper.ClearErrorInfo();
                        break; // MDAC 72694
                    } 
                    recordsAffected = AddRecordsAffected(recordsAffected, affected);
 
                    if (0 != (int)affected) { 
                        loop = 0;
                    } 
                    else if (2000 <= loop) { // MDAC 72126 (reason for more than 1000 iterations)
                        NextResultsInfinite(); // MDAC 72738
                        break;
                    } 
                }
            } 
            if (null != exceptions) { 
                return OleDbException.CombineExceptions(exceptions);
            } 
            return null;
        }

        static private void NextResultsInfinite() { // MDAC 72738 
            Bid.Trace(" System.Data.OleDb.OleDbDataReader: 2000 IMultipleResult.GetResult(NULL, DBRESULTFLAG_DEFAULT, IID_NULL, NULL, NULL) iterations with 0 records affected. Stopping suspect infinite loop. To work-around try using ExecuteReader() and iterating through results with NextResult().\n");
 
            // [....]'s suggestion is that we debug assert so that users will learn of MSOLAP's misbehavior and not call ExecuteNonQuery 
            Debug.Assert(false, " System.Data.OleDb.OleDbDataReader: 2000 IMultipleResult.GetResult(NULL, DBRESULTFLAG_DEFAULT, IID_NULL, NULL, NULL) iterations with 0 records affected. Stopping suspect infinite loop. To work-around try using ExecuteReader() and iterating through results with NextResult().\n");
        } 

        override public bool NextResult() {
            IntPtr hscp;
            Bid.ScopeEnter(out hscp, " %d#\n", ObjectID); 
            try {
                bool retflag = false; 
                if (IsClosed) { 
                    throw ADP.DataReaderClosed("NextResult");
                } 
                _fieldNameLookup = null;

                OleDbCommand command = _command;
                UnsafeNativeMethods.IMultipleResults imultipleResults = _imultipleResults; 
                if (null != imultipleResults) {
                    DisposeOpenResults(); 
                    _hasRows = false; 

                    for (;;) { 
                        Debug.Assert(null == _irow, "NextResult: row loop check");
                        Debug.Assert(null == _irowset, "NextResult: rowset loop check");

                        object result = null; 
                        OleDbHResult hr;
                        IntPtr affected; 
 
                        if ((null != command) && command.canceling) { // MDAC 69986
                            Close(); 
                            break;
                        }

                        Bid.Trace(" %d#, IID_IRowset\n", ObjectID); 
                        hr = imultipleResults.GetResult(ADP.PtrZero, ODB.DBRESULTFLAG_DEFAULT, ref ODB.IID_IRowset, out affected, out result);
                        Bid.Trace(" %08X{HRESULT}, RecordAffected=%Id\n", hr, affected); 
 
                        if ((0 <= hr) && (null != result)) {
                            Bid.Trace(" %d#, IRowset\n", ObjectID); 
                            _irowset = (UnsafeNativeMethods.IRowset) result;
                        }
                        _recordsAffected = AddRecordsAffected(_recordsAffected, affected);
 
                        if (OleDbHResult.DB_S_NORESULT == hr) {
                            DisposeNativeMultipleResults(); 
                            break; 
                        }
                        // @devnote: infomessage events may be fired from here 
                        ProcessResults(hr);

                        if (null != _irowset) {
                            BuildMetaInfo(); 
                            HasRowsRead();
                            retflag = true; 
                            break; 
                        }
                    } 
                }
                else {
                    DisposeOpenResults(); // MDAC 70934
                    _hasRows = false; // MDAC 85850 
                }
                return retflag; 
            } 
            finally {
                Bid.ScopeLeave(ref hscp); 
            }
        }

        override public bool Read() { 
            IntPtr hscp;
            Bid.ScopeEnter(out hscp, " %d#\n", ObjectID); 
            try { 
                bool retflag = false;
                OleDbCommand command = _command; 
                if ((null != command) && command.canceling) { // MDAC 69986
                    DisposeOpenResults();
                }
                else if (null != _irowset) { 
                    if (_hasRowsReadCheck) {
                        _isRead = retflag = _hasRows; 
                        _hasRowsReadCheck = false; 
                    }
                    else if (_singleRow && _isRead) { 
                        DisposeOpenResults(); // MDAC 66109
                    }
                    else {
                        retflag = ReadRowset(); 
                    }
                } 
                else if (null != _irow) { 
                    retflag = ReadRow();
                } 
                else if (IsClosed) {
                    throw ADP.DataReaderClosed("Read");
                }
                return retflag; 
            }
            finally { 
                Bid.ScopeLeave(ref hscp); 
            }
        } 

        private bool ReadRow() {
            if (_isRead) {
                _isRead = false; // for DoValueCheck 

                DisposeNativeRow(); 
 
                _sequentialOrdinal = -1; // sequentialBytesRead will reset when used
            } 
            else {
                _isRead = true;
                return (0 < _metadata.Length);
            } 
            return false;
        } 
 
        private bool ReadRowset() {
            Debug.Assert(null != _irowset, "ReadRow: null IRowset"); 
            Debug.Assert(0 <= _metadata.Length, "incorrect state for fieldCount");

            // releases bindings as necessary
            // bumps current row, else resets it back to initial state 
            ReleaseCurrentRow();
 
            _sequentialOrdinal = -1; // sequentialBytesRead will reset when used 

            // making the check if (null != irowset) unnecessary 
            // if necessary, get next group of row handles
            if (IntPtr.Zero == _rowFetchedCount) { // starts at (-1 <= 0)
                Debug.Assert(0 == _currentRow, "incorrect state for _currentRow");
                Debug.Assert(0 <= _metadata.Length, "incorrect state for fieldCount"); 
                Debug.Assert(0 == _nextAccessorForRetrieval, "incorrect state for nextAccessorForRetrieval");
                Debug.Assert(0 == _nextValueForRetrieval, "incorrect state for nextValueForRetrieval"); 
 
                // @devnote: releasing row handles occurs next time user calls read, skip, or close
                GetRowHandles(/*skipCount*/); 
            }
            return ((_currentRow <= (int)_rowFetchedCount) && _isRead);
        }
 
        private void ReleaseCurrentRow() {
            Debug.Assert(null != _irowset, "ReleaseCurrentRow: no rowset"); 
 
            if (0 < (int)_rowFetchedCount) {
 
                // release the data in the current row
                Bindings[] bindings = _bindings;
                Debug.Assert(null != bindings, "ReleaseCurrentRow: null dbBindings");
                for (int i = 0; (i < bindings.Length) && (i < _nextAccessorForRetrieval); ++i) { 
                    bindings[i].CleanupBindings();
                } 
                _nextAccessorForRetrieval = 0; 
                _nextValueForRetrieval = 0;
 
                _currentRow++;
                if (_currentRow == (int)_rowFetchedCount) {
                    ReleaseRowHandles();
                } 
            }
        } 
 
        private void CreateAccessors(bool allowMultipleAccessor) {
            Debug.Assert(null == _bindings, "CreateAccessor: dbBindings already exists"); 
            Debug.Assert(null != _irowset, "CreateAccessor: no IRowset available");
            Debug.Assert(null != _metadata && 0 < _metadata.Length, "no columns");

            Bindings[] dbBindings = CreateBindingsFromMetaData(allowMultipleAccessor); 

            UnsafeNativeMethods.IAccessor iaccessor = IAccessor(); 
            for (int i = 0; i < dbBindings.Length; ++i) { 
                OleDbHResult hr = dbBindings[i].CreateAccessor(iaccessor, ODB.DBACCESSOR_ROWDATA);
                if (hr < 0) { 
                    ProcessResults(hr);
                }
            }
 
            if (IntPtr.Zero == _rowHandleFetchCount) {
                _rowHandleFetchCount = new IntPtr(1); 
 
                object maxRows = GetPropertyValue(ODB.DBPROP_MAXROWS);
                if (maxRows is Int32) { 
                    _rowHandleFetchCount = new IntPtr((int) maxRows);
                    if ((ADP.PtrZero == _rowHandleFetchCount) || (20 <= (int)_rowHandleFetchCount)) {
                        _rowHandleFetchCount = new IntPtr(20);
                    } 
                }
                else if (maxRows is Int64) { 
                    _rowHandleFetchCount = new IntPtr((long) maxRows); 
                    if ((ADP.PtrZero == _rowHandleFetchCount) || (20 <= (long)_rowHandleFetchCount)) {
                        _rowHandleFetchCount = new IntPtr(20); 
                    }
                }
            }
            if (null == _rowHandleNativeBuffer) { 
                _rowHandleNativeBuffer = new RowHandleBuffer(_rowHandleFetchCount);
            } 
        } 

        private Bindings[] CreateBindingsFromMetaData(bool allowMultipleAccessor) { 
            int bindingCount = 0;
            int currentBindingIndex = 0;

            MetaData[] metadata = _metadata; 

            int[] indexToBinding = new int[metadata.Length]; 
            int[] indexWithinBinding = new int[metadata.Length]; 

            // walk through the schemaRows to determine the number of binding groups 
            if (allowMultipleAccessor) {
                if (null != _irowset) {
                    for (int i = 0; i < indexToBinding.Length; ++i) {
                        indexToBinding[i] = bindingCount; 
                        indexWithinBinding[i] = currentBindingIndex;
#if false 
                        // @denote: single/multiple Accessors 
                        if ((bindingCount < 2) && IsLong(metadata[i].flags)) {
                            bindingCount++; 
                            currentBindingIndex = 0;
                        }
                        else {
                            currentBindingIndex++; 
                        }
#elif false 
                        // @devnote: one accessor per column option 
                        bindingCount++;
                        currentBindingIndex = 0; 
#else
                        // @devnote: one accessor only for IRowset
                        currentBindingIndex++;
#endif 
                    }
                    if (0 < currentBindingIndex) { // when blob is not the last column 
                        bindingCount++; 
                    }
                } 
                else if (null != _irow) {
                    for (int i = 0; i < indexToBinding.Length; ++i) {
                        indexToBinding[i] = i;
                        indexWithinBinding[i] = 0; 
                    }
                    bindingCount = metadata.Length; 
                } 
            }
            else { 
                for (int i = 0; i < indexToBinding.Length; ++i) {
                    indexToBinding[i] = 0;
                    indexWithinBinding[i] = i;
                } 
                bindingCount = 1;
            } 
 
            Bindings bindings;
            Bindings[] dbbindings = new Bindings[bindingCount]; 
            bindingCount = 0;

            // for every column, build tagDBBinding info
            for (int index = 0; index < metadata.Length; ++index) { 
                Debug.Assert(indexToBinding[index] < dbbindings.Length, "bad indexToAccessor");
                bindings = dbbindings[indexToBinding[index]]; 
                if (null == bindings) { 
                    bindingCount = 0;
                    for (int i = index; (i < metadata.Length) && (bindingCount == indexWithinBinding[i]); ++i) { 
                        bindingCount++;
                    }
                    dbbindings[indexToBinding[index]] = bindings = new Bindings((OleDbDataReader)this, (null != _irowset), bindingCount);
 
                    // runningTotal is buffered to start values on 16-byte boundary
                    // the first columnCount * 8 bytes are for the length and status fields 
                    //bindings.DataBufferSize = (bindingCount + (bindingCount % 2)) * sizeof_int64; 
                }
                MetaData info = metadata[index]; 

                int maxLen = info.type.fixlen;
                short getType = info.type.wType;
 
                Debug.Assert(NativeDBType.STR != getType, "Should have bound as WSTR");
                Debug.Assert(!NativeDBType.HasHighBit(getType), "CreateAccessor - unexpected high bits on datatype"); 
 
                if (-1 != info.size) {
                    if (info.type.islong) { 
                        maxLen = ADP.PtrSize;
                        getType = (short)((ushort) getType | (ushort) NativeDBType.BYREF);
                    }
                    else if (-1 == maxLen) { 
                        // @devnote: not using provider owned memory for PDC, no one really supports it anyway.
                        /*if (((null != connection) && connection.PropertyGetProviderOwnedMemory()) 
                            || ((null != command) && command.Connection.PropertyGetProviderOwnedMemory())) { 
                            bindings.MemOwner = DBMemOwner.ProviderOwned;
 
                            bindings.MaxLen = ADP.PtrSize;
                            bindings.DbType = (short) (getType | DbType.BYREF);
                        }
                        else*/ 

                        if (ODB.LargeDataSize < info.size) { 
                            maxLen = ADP.PtrSize; 
                            getType = (short)((ushort) getType | (ushort)NativeDBType.BYREF);
                        } 
                        else if ((NativeDBType.WSTR == getType) && (-1 != info.size)) { // WebData 99298
                            maxLen = info.size * 2 + 2;
                        }
                        else { 
                            maxLen = info.size;
                        } 
                    } 
                }
                else if (maxLen < 0) { 
                    // if variable length and no defined size we require this to be byref at this time
                    /*if (((null != connection) && connection.PropertyGetProviderOwnedMemory())
                        || ((null != command) && command.Connection.PropertyGetProviderOwnedMemory())) {
                        bindings.MemOwner = DBMemOwner.ProviderOwned; 
                    }*/
                    maxLen = ADP.PtrSize; 
                    getType = (short)((ushort) getType | (ushort)NativeDBType.BYREF); 
                }
 
                currentBindingIndex = indexWithinBinding[index];
                bindings.CurrentIndex = currentBindingIndex;

                bindings.Ordinal      = info.ordinal; 
                bindings.Part         = info.type.dbPart;
                bindings.Precision    = (byte) info.precision; 
                bindings.Scale        = (byte) info.scale; 
                bindings.DbType       = (short) getType;
                bindings.MaxLen       = maxLen; // also increments databuffer size (uses DbType) 

              //bindings.ValueOffset  = // set via MaxLen
              //bindings.LengthOffset = // set via MaxLen
              //bindings.StatusOffset = // set via MaxLen 
              //bindings.TypeInfoPtr  = 0;
              //bindings.ObjectPtr    = 0; 
              //bindings.BindExtPtr   = 0; 
              //bindings.MemOwner     = /*DBMEMOWNER_CLIENTOWNED*/0;
              //bindings.ParamIO      = ODB.DBPARAMIO_NOTPARAM; 
              //bindings.Flags        = 0;

                if (Bid.AdvancedOn) {
                    Bid.Trace(" index=%d, columnName='%ls'\n", index, info.columnName);//, bindings.bindings[index]); 
                }
            } 
 
            int count = 0, indexStart = 0;
            for (int i = 0; i < dbbindings.Length; ++i) { 
                indexStart = dbbindings[i].AllocateForAccessor(this, indexStart, i);

                ColumnBinding[] columnBindings = dbbindings[i].ColumnBindings();
                for (int k = 0; k < columnBindings.Length; ++k) { 
                    Debug.Assert(count == columnBindings[k].Index, "column binding mismatch");
                    metadata[count].columnBinding = columnBindings[k]; 
                    metadata[count].bindings = dbbindings[i]; 
                    count++;
                } 
            }

            _bindings = dbbindings;
            return dbbindings; 
        }
 
        private void GetRowHandles(/*int skipCount*/) { 
            Debug.Assert(0 < (int)_rowHandleFetchCount, "GetRowHandles: bad _rowHandleFetchCount");
            Debug.Assert(!_isRead, "GetRowHandles: _isRead"); 

            OleDbHResult hr = 0;

            RowHandleBuffer rowHandleBuffer = _rowHandleNativeBuffer; 
            bool mustRelease = false;
 
            RuntimeHelpers.PrepareConstrainedRegions(); 
            try {
                rowHandleBuffer.DangerousAddRef(ref mustRelease); 

                IntPtr rowHandlesPtr = rowHandleBuffer.DangerousGetHandle();
                UnsafeNativeMethods.IRowset irowset = IRowset();
                try { 
                    Bid.Trace(" %d#, Chapter=%Id, RowsRequested=%Id\n", ObjectID, _chapterHandle.HChapter, _rowHandleFetchCount);
                    hr = irowset.GetNextRows(_chapterHandle.HChapter, /*skipCount*/IntPtr.Zero, _rowHandleFetchCount, out _rowFetchedCount, ref rowHandlesPtr); 
                    Bid.Trace(" %08X{HRESULT}, RowsObtained=%Id\n", hr, _rowFetchedCount); 
                    Debug.Assert(rowHandleBuffer.DangerousGetHandle() == rowHandlesPtr, "rowhandlebuffer changed");
                } 
                catch(System.InvalidCastException e) { // MDAC 64320
                    throw ODB.ThreadApartmentState(e);
                }
            } 
            finally {
                if (mustRelease) { 
                    rowHandleBuffer.DangerousRelease(); 
                }
            } 

            //if (/*DB_S_ROWLIMITEXCEEDED*/0x00040EC0 == hr) {
            //    _rowHandleFetchCount = 1;
            //    _isRead = true; 
            //} else
            if (hr < 0) { 
                // filter out the BadStartPosition due to the skipCount which 
                // maybe greater than the number of rows in the return rowset
                //const int /*OLEDB_Error.*/DB_E_BADSTARTPOSITION = unchecked((int)0x80040E1E); 
                //if (DB_E_BADSTARTPOSITION != hr)
                ProcessResults(hr);
            }
            _isRead = ((OleDbHResult.DB_S_ENDOFROWSET != hr) || (0 < (int)_rowFetchedCount)); // MDAC 59264 
            _rowFetchedCount = (IntPtr)Math.Max((int)_rowFetchedCount, 0);
        } 
 
        private void GetRowDataFromHandle() {
            Debug.Assert(null != _bindings, "GetRowDataFromHandle: null dbBindings"); 
            Debug.Assert(null != _rowHandleNativeBuffer, "GetRowDataFromHandle: null dbBindings");

            OleDbHResult hr = 0;
            UnsafeNativeMethods.IRowset irowset = IRowset(); 

            IntPtr rowHandle = _rowHandleNativeBuffer.GetRowHandle(_currentRow); 
 
            RowBinding rowBinding = _bindings[_nextAccessorForRetrieval].RowBinding();
            IntPtr accessorHandle = rowBinding.DangerousGetAccessorHandle(); 

            bool mustRelease = false;
            RuntimeHelpers.PrepareConstrainedRegions();
            try { 
                rowBinding.DangerousAddRef(ref mustRelease);
                rowBinding.StartDataBlock(); 
 
                IntPtr dataPtr = rowBinding.DangerousGetDataPtr();
 
                Bid.Trace(" %d#, RowHandle=%Id, AccessorHandle=%Id\n", ObjectID, rowHandle, accessorHandle);
                hr = irowset.GetData(rowHandle, accessorHandle, dataPtr);
                Bid.Trace(" %08X{HRESULT}\n", hr);
            } 
            finally {
                if (mustRelease) { 
                    rowBinding.DangerousRelease(); 
                }
            } 

            //if (AdapterSwitches.DataError.TraceWarning) {
            //    DBBindings binding = _dbBindings[i];
            //    for (int k = 0; k < binding.Count; ++k) { 
            //        binding.CurrentIndex = k;
            //        Debug.WriteLine("Status[" + k.ToString(CultureInfo.InvariantCulture) + "] = " + binding.StatusValue.ToString("G", CultureInfo.InvariantCulture)); 
            //    } 
            //}
 
            _nextAccessorForRetrieval++;
            if (hr < 0) {
                ProcessResults(hr);
            } 
        }
 
        private void ReleaseRowHandles() { 
            Debug.Assert(0 < (int)_rowFetchedCount, "invalid _rowFetchedCount");
 
            OleDbHResult hr;
            UnsafeNativeMethods.IRowset irowset = IRowset();

            Bid.Trace(" %d#, Request=%Id\n", ObjectID, _rowFetchedCount); 
            hr = irowset.ReleaseRows(_rowFetchedCount, _rowHandleNativeBuffer, ADP.PtrZero, ADP.PtrZero, ADP.PtrZero);
            Bid.Trace(" %08X{HRESULT}\n", hr); 
 
            if (hr < 0) {
                //ProcessFailure(hr); 
                //ProcessFailure(hr);
                SafeNativeMethods.Wrapper.ClearErrorInfo();
            }
            _rowFetchedCount = IntPtr.Zero; 
            _currentRow = 0;
            _isRead = false; // MDAC 59264 
        } 

        private object GetPropertyValue(int propertyId) { // MDAC 72106 
            if (null != _irowset) {
                return GetPropertyOnRowset(OleDbPropertySetGuid.Rowset, propertyId);
            }
            else if (null != _command) { 
                return _command.GetPropertyValue(OleDbPropertySetGuid.Rowset, propertyId);
            } 
            return OleDbPropertyStatus.NotSupported; 
        }
 
        private object GetPropertyOnRowset(Guid propertySet, int propertyID) {
            OleDbHResult hr;
            tagDBPROP[] dbprops;
            UnsafeNativeMethods.IRowsetInfo irowsetinfo = IRowsetInfo(); 

            using(PropertyIDSet propidset = new PropertyIDSet(propertySet, propertyID)) { 
 
                using(DBPropSet propset = new DBPropSet(irowsetinfo, propidset, out hr)) {
                    if (hr < 0) { 
                        // VSDD 621427: OLEDB Data Reader masks provider specific errors by raising "Internal .Net Framework Data Provider error 30."
                        // DBPropSet c-tor will register the exception and it will be raised at GetPropertySet call in case of failure
                        SafeNativeMethods.Wrapper.ClearErrorInfo();
                    } 
                    dbprops = propset.GetPropertySet(0, out propertySet);
                } 
            } 
            if (OleDbPropertyStatus.Ok == dbprops[0].dwStatus) {
                return dbprops[0].vValue; 
            }
            return dbprops[0].dwStatus;
        }
 
        private void GetRowValue() {
            Debug.Assert(null != _irow, "GetRowValue: null IRow"); 
            Debug.Assert(null != _metadata, "GetRowValue: null MetaData"); 

            Bindings bindings = _bindings[_nextAccessorForRetrieval]; 
            ColumnBinding[] columnBindings = bindings.ColumnBindings();
            RowBinding rowBinding = bindings.RowBinding();
            Debug.Assert(_nextValueForRetrieval <= columnBindings[0].Index, "backwards retrieval");
 
            bool mustReleaseBinding = false;
            bool[] mustRelease = new bool[columnBindings.Length]; 
            StringMemHandle[] sptr = new StringMemHandle[columnBindings.Length]; 

            RuntimeHelpers.PrepareConstrainedRegions(); 
            try {
                for (int i = 0; i < columnBindings.Length; ++i) {
                    bindings.CurrentIndex = i;
 
                    sptr[i] = null;
                    MetaData info = _metadata[columnBindings[i].Index]; 
                    if ((ODB.DBKIND_GUID_NAME == info.kind) || (ODB.DBKIND_NAME == info.kind)) { 
                        sptr[i] = new StringMemHandle(info.idname);
                        columnBindings[i]._sptr = sptr[i]; 
                    }

                    sptr[i].DangerousAddRef(ref mustRelease[i]);
 
                    IntPtr ulPropid = ((null != sptr[i]) ? sptr[i].DangerousGetHandle() : info.propid);
                    bindings.GuidKindName(info.guid, info.kind, ulPropid); 
                } 

                OleDbHResult hr; 
                tagDBCOLUMNACCESS[] access = bindings.DBColumnAccess;

                rowBinding.DangerousAddRef(ref mustReleaseBinding);
                rowBinding.StartDataBlock(); 

                UnsafeNativeMethods.IRow irow = IRow(); 
 
                Bid.Trace(" %d#\n", ObjectID);
                hr = irow.GetColumns((IntPtr)access.Length, access); 
                Bid.Trace(" %08X{HRESULT}\n", hr);
            }
            finally {
                if (mustReleaseBinding) { 
                    rowBinding.DangerousRelease();
                } 
                for (int i = 0; i < mustRelease.Length; i++) { 
                    if (mustRelease[i]) {
                        sptr[i].DangerousRelease(); 
                    }
                }
            }
            _nextAccessorForRetrieval++; 
        }
 
        private Int32 IndexOf(Hashtable hash, string name) { // MDAC 67385 
            // via case sensitive search, first match with lowest ordinal matches
            object index = hash[name]; 
            if (null != index) {
                return (int) index; // match via case-insensitive or by chance lowercase
            }
 
            // via case insensitive search, first match with lowest ordinal matches
            string tmp = name.ToLower(CultureInfo.InvariantCulture); 
            index = hash[tmp]; // match via lowercase 
            return ((null != index) ? (int) index : -1);
        } 

        private void AppendSchemaInfo() {
            Debug.Assert(null != _connection, "null connection");
            Debug.Assert(null != _metadata, "no _metadata"); 

            if (_metadata.Length <= 0) { 
                return; 
            }
 
            int keyCount = 0;
            for (int i = 0; i < _metadata.Length; ++i) {
                if (_metadata[i].isKeyColumn && !_metadata[i].isHidden) { // MDAC 90411
                    keyCount++; 
                }
            } 
            if (0 != keyCount) /*|| _connection.IsServer_msdaora || _connection.IsServer_Microsoft_SQL)*/ { // MDAC 60109 
                return;
            } 

            string schemaName, catalogName; // enforce single table
            string baseSchemaName = null, baseCatalogName = null, baseTableName = null;
            for (int i = 0; i < _metadata.Length; ++i) { 
                MetaData info = _metadata[i];
                if ((null != info.baseTableName) && (0 < info.baseTableName.Length)) { 
                    catalogName = ((null != info.baseCatalogName) ? info.baseCatalogName : ""); // MDAC 67249 
                    schemaName = ((null != info.baseSchemaName) ? info.baseSchemaName : "");
                    if (null == baseTableName) { 
                        baseSchemaName = schemaName;
                        baseCatalogName = catalogName;
                        baseTableName = info.baseTableName;
                    } 
                    else if ((0 != ADP.SrcCompare(baseTableName, info.baseTableName))
                            || (0 != ADP.SrcCompare(baseCatalogName, catalogName)) 
                            || (0 != ADP.SrcCompare(baseSchemaName, schemaName))) { // MDAC 71808 
#if DEBUG
                        if (AdapterSwitches.DataSchema.TraceVerbose) { 
                            Debug.WriteLine("Multiple BaseTableName detected:"
                                +" <"+baseCatalogName+"."+baseCatalogName+"."+baseTableName+">"
                                +" <"+info.baseCatalogName+"."+info.baseCatalogName+"."+info.baseTableName+">");
                        } 
#endif
                        baseTableName = null; 
                        break; 
                    }
                } 
            }
            if (null == baseTableName) {
                return;
            } 
            baseCatalogName = ADP.IsEmpty(baseCatalogName) ? null : baseCatalogName;
            baseSchemaName = ADP.IsEmpty(baseSchemaName) ? null : baseSchemaName; 
 
            if (null != _connection) { // MDAC 67394
                if (ODB.DBPROPVAL_IC_SENSITIVE == _connection.QuotedIdentifierCase()) { 
                    string p = null, s = null;
                    _connection.GetLiteralQuotes(ADP.GetSchemaTable, out s, out p);
                    if (null == s) {
                        s = ""; 
                    }
                    if (null == p) { 
                        p = ""; 
                    }
                    baseTableName = s + baseTableName + p; 
                }
            }

            Hashtable baseColumnNames = new Hashtable(_metadata.Length * 2); // MDAC 67385 

            for (int i = _metadata.Length-1; 0 <= i; --i) { 
                string basecolumname = _metadata[i].baseColumnName; 
                if (!ADP.IsEmpty(basecolumname)) {
                    baseColumnNames[basecolumname] = i; 
                }
            }
            for (int i = 0; i < _metadata.Length; ++i) {
                string basecolumname = _metadata[i].baseColumnName; 
                if (!ADP.IsEmpty(basecolumname)) {
                    basecolumname = basecolumname.ToLower(CultureInfo.InvariantCulture); 
                    if (!baseColumnNames.Contains(basecolumname)) { 
                        baseColumnNames[basecolumname] = i;
                    } 
                }
            }

            // look for primary keys in the table 
            if (_connection.SupportSchemaRowset(OleDbSchemaGuid.Primary_Keys)) {
                Object[] restrictions = new Object[] { baseCatalogName, baseSchemaName, baseTableName }; 
                keyCount = AppendSchemaPrimaryKey(baseColumnNames, restrictions); 
            }
            if (0 != keyCount) { 
                return;
            }

            // look for a single unique contraint that can be upgraded 
            if (_connection.SupportSchemaRowset(OleDbSchemaGuid.Indexes)) {
                Object[] restrictions = new Object[] { baseCatalogName, baseSchemaName, null, null, baseTableName }; 
                AppendSchemaUniqueIndexAsKey(baseColumnNames, restrictions); 
            }
        } 

        private int AppendSchemaPrimaryKey(Hashtable baseColumnNames, object[] restrictions) {
            int keyCount = 0;
            bool partialPrimaryKey = false; 
            DataTable table = null;
            try { 
                table = _connection.GetSchemaRowset(OleDbSchemaGuid.Primary_Keys, restrictions); 
            }
            catch(Exception e) { 
                //
                if (!ADP.IsCatchableExceptionType(e)) {
                    throw;
                } 

                ADP.TraceExceptionWithoutRethrow(e); 
            } 
            if (null != table) {
                DataColumnCollection dataColumns = table.Columns; 
                int nameColumnIndex = dataColumns.IndexOf(ODB.COLUMN_NAME);

                if (-1 != nameColumnIndex) {
                    DataColumn nameColumn = dataColumns[nameColumnIndex]; 
                    foreach(DataRow dataRow in table.Rows) {
                        string name = (string) dataRow[nameColumn, DataRowVersion.Default]; 
 
                        int metaindex = IndexOf(baseColumnNames, name); // MDAC 67385
                        if (0 <= metaindex) { 
                            MetaData info = _metadata[metaindex];
                            info.isKeyColumn = true;
                            info.flags &= ~ODB.DBCOLUMNFLAGS_ISNULLABLE;
                            keyCount++; 
                        }
                        else { 
#if DEBUG 
                            if (AdapterSwitches.DataSchema.TraceVerbose) {
                                Debug.WriteLine("PartialKeyColumn detected: <" + name + "> metaindex=" + metaindex); 
                            }
#endif
                            partialPrimaryKey = true;
                            break; 
                        }
                    } 
                } 
            }
            if (partialPrimaryKey) { // partial primary key detected 
                for (int i = 0; i < _metadata.Length; ++i) {
                    _metadata[i].isKeyColumn = false;
                }
                return -1; 
            }
            return keyCount; 
        } 

        private void AppendSchemaUniqueIndexAsKey(Hashtable baseColumnNames, object[] restrictions) { 
            bool partialPrimaryKey = false;
            DataTable table = null;
            try { // MDAC 66209
                table = _connection.GetSchemaRowset(OleDbSchemaGuid.Indexes, restrictions); 
            }
            catch(Exception e) { 
                // 
                if (!ADP.IsCatchableExceptionType(e)) {
                    throw; 
                }

                ADP.TraceExceptionWithoutRethrow(e);
            } 
            if (null != table) {
                DataColumnCollection dataColumns = table.Columns; 
 
                int indxIndex = dataColumns.IndexOf(ODB.INDEX_NAME);
                int pkeyIndex = dataColumns.IndexOf(ODB.PRIMARY_KEY); 
                int uniqIndex = dataColumns.IndexOf(ODB.UNIQUE);
                int nameIndex = dataColumns.IndexOf(ODB.COLUMN_NAME);
                int nullIndex = dataColumns.IndexOf(ODB.NULLS);
 
                if ((-1 != indxIndex) && (-1 != pkeyIndex) && (-1 != uniqIndex) && (-1 != nameIndex)) {
 
                    DataColumn indxColumn = dataColumns[indxIndex]; 
                    DataColumn pkeyColumn = dataColumns[pkeyIndex];
                    DataColumn uniqCOlumn = dataColumns[uniqIndex]; 
                    DataColumn nameColumn = dataColumns[nameIndex];
                    DataColumn nulls = ((-1 != nullIndex) ? dataColumns[nullIndex] : null);

                    bool[] keys = new bool[_metadata.Length]; 
                    bool[] uniq = new bool[_metadata.Length];
                    string uniqueIndexName = null; 
 
                    // match pkey name BaseColumnName
                    foreach(DataRow dataRow in table.Rows) { 

                        bool isPKey = (!dataRow.IsNull(pkeyColumn, DataRowVersion.Default) && (bool)dataRow[pkeyColumn, DataRowVersion.Default]);
                        bool isUniq = (!dataRow.IsNull(uniqCOlumn, DataRowVersion.Default) && (bool)dataRow[uniqCOlumn, DataRowVersion.Default]);
                        bool nullsVal = (null != nulls) && (dataRow.IsNull(nulls, DataRowVersion.Default) || (ODB.DBPROPVAL_IN_ALLOWNULL == Convert.ToInt32(dataRow[nulls, DataRowVersion.Default], CultureInfo.InvariantCulture))); 

                        if (isPKey || isUniq) { 
                            string name = (string) dataRow[nameColumn, DataRowVersion.Default]; 

                            int metaindex = IndexOf(baseColumnNames, name); // MDAC 67385 
                            if (0 <= metaindex) {
                                if (isPKey) {
                                    keys[metaindex] = true;
                                } 
                                if (isUniq && (null != uniq)) {
                                    uniq[metaindex] = true; 
 
                                    string indexname = (string) dataRow[indxColumn, DataRowVersion.Default];
                                    if (null == uniqueIndexName) { 
                                        uniqueIndexName = indexname;
                                    }
                                    else if (indexname != uniqueIndexName) {
#if DEBUG 
                                        if (AdapterSwitches.DataSchema.TraceVerbose) {
                                            Debug.WriteLine("MultipleUniqueIndexes detected: <" + uniqueIndexName + "> <" + indexname + ">"); 
                                        } 
#endif
                                        uniq = null; 
                                    }
                                }
                            }
                            else if (isPKey) { 
#if DEBUG
                                if (AdapterSwitches.DataSchema.TraceVerbose) { 
                                    Debug.WriteLine("PartialKeyColumn detected: " + name); 
                                }
#endif 
                                partialPrimaryKey = true;
                                break;
                            }
                            else if (null != uniqueIndexName) { 
                                string indexname = (string) dataRow[indxColumn, DataRowVersion.Default];
 
                                if (indexname != uniqueIndexName) { 
#if DEBUG
                                    if (AdapterSwitches.DataSchema.TraceVerbose) { 
                                        Debug.WriteLine("PartialUniqueIndexes detected: <" + uniqueIndexName + "> <" + indexname + ">");
                                    }
#endif
                                    uniq = null; 
                                }
                            } 
                        } 
                    }
                    if (partialPrimaryKey) { 
                        for (int i = 0; i < _metadata.Length; ++i) {
                            _metadata[i].isKeyColumn = false;
                        }
                        return; 
                    }
                    else if (null != uniq) { 
#if DEBUG 
                        if (AdapterSwitches.DataSchema.TraceVerbose) {
                            Debug.WriteLine("upgrade single unique index to be a key: <" + uniqueIndexName + ">"); 
                        }
#endif
                        // upgrade single unique index to be a key
                        for (int i = 0; i < _metadata.Length; ++i) { 
                            _metadata[i].isKeyColumn = uniq[i];
                        } 
                    } 
                }
            } 
        }

        private MetaData FindMetaData(string name) {
            int index = _fieldNameLookup.IndexOfName(name); 
            return ((-1 != index) ? _metadata[index] : null);
        } 
 
        internal void DumpToSchemaTable(UnsafeNativeMethods.IRowset rowset) {
            List metainfo = new List(); 

            object hiddenColumns = null;
            using (OleDbDataReader dataReader = new OleDbDataReader(_connection, _command, Int32.MinValue, 0)) {
                dataReader.InitializeIRowset(rowset, ChapterHandle.DB_NULL_HCHAPTER, IntPtr.Zero); 
                dataReader.BuildSchemaTableInfo(rowset, true, false);
 
                hiddenColumns = GetPropertyValue(ODB.DBPROP_HIDDENCOLUMNS); // MDAC 55611, 72106 
                if (0 == dataReader.FieldCount) {
                    return; 
                }

                Debug.Assert(null == dataReader._fieldNameLookup, "lookup already exists");
                FieldNameLookup lookup = new FieldNameLookup(dataReader, -1); 
                dataReader._fieldNameLookup = lookup;
 
                // This column, together with the DBCOLUMN_GUID and DBCOLUMN_PROPID 
                // columns, forms the ID of the column. One or more (but not all) of these columns
                // will be NULL, depending on which elements of the DBID structure the provider uses. 
                MetaData columnidname = dataReader.FindMetaData(ODB.DBCOLUMN_IDNAME);
                MetaData columnguid = dataReader.FindMetaData(ODB.DBCOLUMN_GUID);
                MetaData columnpropid = dataReader.FindMetaData(ODB.DBCOLUMN_PROPID);
 
                MetaData columnname = dataReader.FindMetaData(ODB.DBCOLUMN_NAME);
                MetaData columnordinal = dataReader.FindMetaData(ODB.DBCOLUMN_NUMBER); 
                MetaData dbtype = dataReader.FindMetaData(ODB.DBCOLUMN_TYPE); 
                MetaData columnsize = dataReader.FindMetaData(ODB.DBCOLUMN_COLUMNSIZE);
                MetaData numericprecision = dataReader.FindMetaData(ODB.DBCOLUMN_PRECISION); 
                MetaData numericscale = dataReader.FindMetaData(ODB.DBCOLUMN_SCALE);
                MetaData columnflags = dataReader.FindMetaData(ODB.DBCOLUMN_FLAGS);
                MetaData baseschemaname = dataReader.FindMetaData(ODB.DBCOLUMN_BASESCHEMANAME);
                MetaData basecatalogname = dataReader.FindMetaData(ODB.DBCOLUMN_BASECATALOGNAME); 
                MetaData basetablename = dataReader.FindMetaData(ODB.DBCOLUMN_BASETABLENAME);
                MetaData basecolumnname = dataReader.FindMetaData(ODB.DBCOLUMN_BASECOLUMNNAME); 
                MetaData isautoincrement = dataReader.FindMetaData(ODB.DBCOLUMN_ISAUTOINCREMENT); 
                MetaData isunique = dataReader.FindMetaData(ODB.DBCOLUMN_ISUNIQUE);
                MetaData iskeycolumn = dataReader.FindMetaData(ODB.DBCOLUMN_KEYCOLUMN); 

                // @devnote: because we want to use the DBACCESSOR_OPTIMIZED bit,
                // we are required to create the accessor before fetching any rows
                dataReader.CreateAccessors(false); 

                ColumnBinding binding; 
                while (dataReader.ReadRowset()) { 
                    dataReader.GetRowDataFromHandle();
 
                    MetaData info = new MetaData();

                    binding = columnidname.columnBinding; // MDAC 72627
                    if (!binding.IsValueNull()) { 
                        info.idname = (string)binding.Value();
                        info.kind = ODB.DBKIND_NAME; 
                    } 

                    binding = columnguid.columnBinding; 
                    if (!binding.IsValueNull()) {
                        info.guid = binding.Value_GUID();
                        info.kind = ((ODB.DBKIND_NAME == info.kind) ? ODB.DBKIND_GUID_NAME : ODB.DBKIND_GUID);
                    } 

                    binding = columnpropid.columnBinding; 
                    if (!binding.IsValueNull()) { 
                        info.propid = new IntPtr(binding.Value_UI4());
                        info.kind = ((ODB.DBKIND_GUID == info.kind) ? ODB.DBKIND_GUID_PROPID : ODB.DBKIND_PROPID); 
                    }

                    binding = columnname.columnBinding;
                    if (!binding.IsValueNull()) { 
                        info.columnName = (string)binding.Value();
                    } 
                    else { 
                        info.columnName = "";
                    } 

                    if (4 == ADP.PtrSize) {
                        info.ordinal = (IntPtr)columnordinal.columnBinding.Value_UI4();
                    } 
                    else {
                        info.ordinal = (IntPtr)columnordinal.columnBinding.Value_UI8(); 
                    } 
                    short wType = unchecked((short) dbtype.columnBinding.Value_UI2());
 
                    if (4 == ADP.PtrSize) {
                        info.size = unchecked((int) columnsize.columnBinding.Value_UI4()); // WebData 99298
                    }
                    else { 
                        info.size = ADP.IntPtrToInt32((IntPtr)unchecked((long)columnsize.columnBinding.Value_UI8()));
                    } 
 
                    binding = numericprecision.columnBinding;
                    if (!binding.IsValueNull()) { 
                        info.precision = (byte)binding.Value_UI2();
                    }

                    binding = numericscale.columnBinding; 
                    if (!binding.IsValueNull()) {
                        info.scale = (byte)binding.Value_I2(); 
                    } 

                    info.flags = unchecked((int) columnflags.columnBinding.Value_UI4()); 

                    bool islong = OleDbDataReader.IsLong(info.flags);
                    bool isfixed = OleDbDataReader.IsFixed(info.flags);
                    NativeDBType dbType = NativeDBType.FromDBType(wType, islong, isfixed); 

                    info.type = dbType; 
 
                    if (null != isautoincrement) {
                        binding = isautoincrement.columnBinding; 
                        if (!binding.IsValueNull()) {
                            info.isAutoIncrement = binding.Value_BOOL();
                        }
                    } 
                    if (null != isunique) {
                        binding = isunique.columnBinding; 
                        if (!binding.IsValueNull()) { 
                            info.isUnique = binding.Value_BOOL();
                        } 
                    }
                    if (null != iskeycolumn) {
                        binding = iskeycolumn.columnBinding;
                        if (!binding.IsValueNull()) { 
                            info.isKeyColumn = binding.Value_BOOL();
                        } 
                    } 
                    if (null != baseschemaname) {
                        binding = baseschemaname.columnBinding; 
                        if (!binding.IsValueNull()) {
                            info.baseSchemaName = binding.ValueString();
                        }
                    } 
                    if (null != basecatalogname) {
                        binding = basecatalogname.columnBinding; 
                        if (!binding.IsValueNull()) { 
                            info.baseCatalogName = binding.ValueString();
                        } 
                    }
                    if (null != basetablename) {
                        binding = basetablename.columnBinding;
                        if (!binding.IsValueNull()) { 
                            info.baseTableName = binding.ValueString();
                        } 
                    } 
                    if (null != basecolumnname) {
                        binding = basecolumnname.columnBinding; 
                        if (!binding.IsValueNull()) {
                            info.baseColumnName = binding.ValueString();
                        }
                    } 
                    metainfo.Add(info);
                } 
            } 

            int visibleCount = metainfo.Count; 
            if (hiddenColumns is Int32) {
                visibleCount -= (int)hiddenColumns;
            }
 
            // VSTFDevDiv 479578:
            //  if one key column is invalidated, they all need to be invalidated. The SET is the key, 
            //  and subsets likely are not accurate keys. Note the assumption that the two loops below 
            //  will traverse the entire set of columns.
            bool disallowKeyColumns = false; 

            for (int index = metainfo.Count - 1; visibleCount <= index; --index) {
                MetaData info = metainfo[index];
 
                info.isHidden = true;
 
                if (disallowKeyColumns) { 
                    info.isKeyColumn = false;
                } 
                else if (info.guid.Equals(ODB.DBCOL_SPECIALCOL)) { // MDAC 90827
                    info.isKeyColumn = false;

                    // This is the first key column to be invalidated, scan back through the 
                    //  columns we already processed to make sure none of those are marked as keys.
                    disallowKeyColumns = true; 
                    for (int index2 = metainfo.Count-1; index < index2; --index2) { 
                        metainfo[index2].isKeyColumn = false;
                    } 
                }
            }

            for (int index = visibleCount - 1; 0 <= index; --index) { 
                MetaData info = metainfo[index];
 
                if (disallowKeyColumns) { 
                    info.isKeyColumn = false;
                } 

                if (info.guid.Equals(ODB.DBCOL_SPECIALCOL)) { // MDAC 72390
#if DEBUG
                    if (AdapterSwitches.DataSchema.TraceVerbose) { 
                        Debug.WriteLine("Filtered Column: DBCOLUMN_GUID=DBCOL_SPECIALCOL DBCOLUMN_NAME=" + info.columnName + " DBCOLUMN_KEYCOLUMN=" + info.isKeyColumn);
                    } 
#endif 
                    info.isHidden = true;
                    visibleCount--; 
                }
#if WIN32
                else if (0 >= (int)info.ordinal) {
#else 
                else if (0 >= (long)info.ordinal) {
#endif 
#if DEBUG 
                    if (AdapterSwitches.DataSchema.TraceVerbose) {
                        Debug.WriteLine("Filtered Column: DBCOLUMN_NUMBER=" + info.ordinal.ToInt64().ToString(CultureInfo.InvariantCulture) + " DBCOLUMN_NAME=" + info.columnName); 
                    }
#endif
                    info.isHidden = true;
                    visibleCount--; 
                }
                else if (OleDbDataReader.DoColumnDropFilter(info.flags)) { 
#if DEBUG 
                    if (AdapterSwitches.DataSchema.TraceVerbose) {
                        Debug.WriteLine("Filtered Column: DBCOLUMN_FLAGS=" + info.flags.ToString("X8", (System.IFormatProvider)null) + " DBCOLUMN_NAME=" + info.columnName); 
                    }
#endif
                    info.isHidden = true;
                    visibleCount--; 
                }
            } 
 
            //
            metainfo.Sort(); // MDAC 68319 
            _visibleFieldCount = visibleCount;
            _metadata = metainfo.ToArray();
        }
 
        static internal void GenerateSchemaTable(OleDbDataReader dataReader, object handle, CommandBehavior behavior) {
            if (0 != (CommandBehavior.KeyInfo & behavior)) { 
                dataReader.BuildSchemaTableRowset(handle); // tries IColumnsRowset first then IColumnsInfo 
                dataReader.AppendSchemaInfo();
            } 
            else {
                dataReader.BuildSchemaTableInfo(handle, false, false); // only tries IColumnsInfo
            }
            MetaData[] metadata = dataReader.MetaData; 
            if ((null != metadata) && (0 < metadata.Length)) {
                dataReader.BuildSchemaTable(metadata); 
            } 
        }
 
        static private bool DoColumnDropFilter(int flags) {
            return (0 != (ODB.DBCOLUMNFLAGS_ISBOOKMARK & flags));
        }
        static private bool IsLong(int flags) { 
            return (0 != (ODB.DBCOLUMNFLAGS_ISLONG & flags));
        } 
        static private bool IsFixed(int flags) { 
            return (0 != (ODB.DBCOLUMNFLAGS_ISFIXEDLENGTH & flags));
        } 
        static private bool IsRowVersion(int flags) {
            return (0 != (ODB.DBCOLUMNFLAGS_ISROWID_DBCOLUMNFLAGS_ISROWVER & flags));
        }
        static private bool AllowDBNull(int flags) { 
            return (0 != (ODB.DBCOLUMNFLAGS_ISNULLABLE & flags));
        } 
        static private bool AllowDBNullMaybeNull(int flags) { 
            return (0 != (ODB.DBCOLUMNFLAGS_ISNULLABLE_DBCOLUMNFLAGS_MAYBENULL & flags));
        } 
        static private bool IsReadOnly(int flags) {
            return (0 == (ODB.DBCOLUMNFLAGS_WRITE_DBCOLUMNFLAGS_WRITEUNKNOWN & flags));
        }
    } 

    sealed internal class MetaData : IComparable { 
 
        internal Bindings bindings;
        internal ColumnBinding columnBinding; 

        internal string columnName;

        internal Guid guid; // MDAC 72627 
        internal int kind;
        internal IntPtr propid; 
        internal string idname; 

        internal NativeDBType type; 

        internal IntPtr ordinal;
        internal int size;
 
        internal int flags;
 
        internal byte precision; 
        internal byte scale;
 
        internal bool isAutoIncrement;
        internal bool isUnique;
        internal bool isKeyColumn;
        internal bool isHidden; 

        internal string baseSchemaName; 
        internal string baseCatalogName; 
        internal string baseTableName;
        internal string baseColumnName; 

        int IComparable.CompareTo(object obj) { // MDAC 68319
            if (isHidden == (obj as MetaData).isHidden) {
#if WIN32 
                return ((int)ordinal - (int)(obj as MetaData).ordinal);
#else 
                long v = ((long)ordinal - (long)(obj as MetaData).ordinal); 
                return ((0 < v) ? 1 : ((v < 0) ? -1 : 0));
#endif 

            }
            return (isHidden) ? 1 : -1; // ensure that all hidden columns come after non-hidden columns
        } 

        internal MetaData() { 
        } 
    }
} 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
//------------------------------------------------------------------------------ 
// 
//      Copyright (c) Microsoft Corporation.  All rights reserved.
// 
// [....] 
// [....]
//----------------------------------------------------------------------------- 
 
namespace System.Data.OleDb {
 
    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.ComponentModel; 
    using System.Data;
    using System.Data.Common; 
    using System.Data.ProviderBase; 
    using System.Diagnostics;
    using System.Globalization; 
    using System.IO;
    using System.Runtime.CompilerServices;
    using System.Runtime.InteropServices;
    using System.Text; 

    public sealed class OleDbDataReader : DbDataReader { 
 
        private CommandBehavior     _commandBehavior;
 
        private static int          _objectTypeCount; // Bid counter
        internal readonly int       ObjectID = System.Threading.Interlocked.Increment(ref _objectTypeCount);

        // object model interaction 
        private OleDbConnection _connection;
        private OleDbCommand _command; 
 
        // DataReader owns the parameter bindings until CloseDataReader
        // this allows OleDbCommand.Dispose to not require OleDbDataReader.Dispose 
        private Bindings _parameterBindings;

        // OLEDB interfaces
        private UnsafeNativeMethods.IMultipleResults _imultipleResults; 
        private UnsafeNativeMethods.IRowset _irowset;
        private UnsafeNativeMethods.IRow _irow; 
 
        private ChapterHandle _chapterHandle = ChapterHandle.DB_NULL_HCHAPTER;
 
        private int _depth;
        private bool _isClosed, _isRead, _hasRows, _hasRowsReadCheck;

        long _sequentialBytesRead; 
        int _sequentialOrdinal;
 
        private Bindings[] _bindings; // _metdata contains the ColumnBinding 

        // do we need to jump to the next accessor 
        private int _nextAccessorForRetrieval;

        // must increment the counter before retrieving value so that
        // if an exception is thrown, user can continue without erroring again 
        private int _nextValueForRetrieval;
 
        // record affected for the current dataset 
        private IntPtr _recordsAffected = ADP.RecordsUnaffected;
        private bool _useIColumnsRowset; 
        private bool _sequentialAccess;
        private bool _singleRow;

        // cached information for Reading (rowhandles/status) 
        private IntPtr _rowHandleFetchCount; // MDAC 60111 (>1 fails against jet)
        private RowHandleBuffer _rowHandleNativeBuffer; 
 
        private IntPtr _rowFetchedCount;
        private int _currentRow; 

        private DataTable _dbSchemaTable;

        private int _visibleFieldCount; 
        private MetaData[] _metadata;
        private FieldNameLookup _fieldNameLookup; 
 
        // ctor for an ICommandText, IMultipleResults, IRowset, IRow
        // ctor for an ADODB.Recordset, ADODB.Record or Hierarchial resultset 
        internal OleDbDataReader(OleDbConnection connection, OleDbCommand command, int depth, CommandBehavior commandBehavior) {
            OleDbConnection.VerifyExecutePermission();

            _connection = connection; 
            _command = command;
            _commandBehavior = commandBehavior; 
 
            if ((null != command) && (0 == _depth)) {
                _parameterBindings = command.TakeBindingOwnerShip(); 
            }
            _depth = depth;
        }
 
        private void Initialize() {
            CommandBehavior behavior = _commandBehavior; 
            _useIColumnsRowset = (0 != (CommandBehavior.KeyInfo & behavior)); 
            _sequentialAccess  = (0 != (CommandBehavior.SequentialAccess & behavior)); // MDAC 60296
            if (0 == _depth) { // MDAC 70886 
                _singleRow     = (0 != (CommandBehavior.SingleRow & behavior));
            }
        }
 
        internal void InitializeIMultipleResults(object result) {
            Initialize(); 
            _imultipleResults = (UnsafeNativeMethods.IMultipleResults) result; // maybe null if no results 
        }
        internal void InitializeIRowset(object result, ChapterHandle chapterHandle, IntPtr recordsAffected) { 
            // if from ADODB, connection will be null
            if ((null == _connection) || (ChapterHandle.DB_NULL_HCHAPTER != chapterHandle)) { // MDAC 59629
                _rowHandleFetchCount = new IntPtr(1);
            } 

            Initialize(); 
            _recordsAffected = recordsAffected; 
            _irowset = (UnsafeNativeMethods.IRowset) result; // maybe null if no results
            _chapterHandle = chapterHandle; 
        }

        internal void InitializeIRow(object result, IntPtr recordsAffected) {
            Initialize(); 
            Debug.Assert(_singleRow, "SingleRow not already set");
            _singleRow = true; 
            _recordsAffected = recordsAffected; 
            _irow = (UnsafeNativeMethods.IRow) result; // maybe null if no results
            _hasRows = (null != _irow); 
        }

        internal OleDbCommand Command {
            get { 
                return _command;
            } 
        } 

        override public int Depth { 
            get {
                Bid.Trace(" %d#\n", ObjectID);
                if (IsClosed) { // MDAC 63669
                    throw ADP.DataReaderClosed("Depth"); 
                }
                return _depth; 
            } 
        }
 
        override public Int32 FieldCount {
            get {
                Bid.Trace(" %d#\n", ObjectID);
                if (IsClosed) { // MDAC 63669 
                    throw ADP.DataReaderClosed("FieldCount");
                } 
                MetaData[] metadata = MetaData; 
                return ((null != metadata) ? metadata.Length : 0);
            } 
        }

        override public bool HasRows { // MDAC 78405
            get { 
                Bid.Trace(" %d#\n", ObjectID);
                if (IsClosed) { // MDAC 63669 
                    throw ADP.DataReaderClosed("HasRows"); 
                }
                return _hasRows; 
            }
        }

        override public Boolean IsClosed { 
            get { // if we have a rowset or multipleresults, we may have more to read
                Bid.Trace(" %d#\n", ObjectID); 
                Debug.Assert((_singleRow && !_isClosed && !_isRead && (null == _irow) && (null == _irowset)) || 
                             _isClosed == ((null == _irow) && (null == _irowset) && (null == _imultipleResults)
                                           && (null == _dbSchemaTable) && (null == _connection) && (null == _command)), // MDAC 59536 
                                           "IsClosed mismatch");
                return _isClosed;
            }
        } 

        private MetaData[] MetaData { 
            get { return _metadata; } 
        }
 
        override public int RecordsAffected {
            get {
                Bid.Trace(" %d#\n", ObjectID);
                return ADP.IntPtrToInt32(_recordsAffected); 
            }
        } 
 
        /*
        internal long RecordsAffectedLong { 
            get {
                return (long)_recordsAffected;
            }
        }*/ 

        override public object this[Int32 index] { 
            get { 
                return GetValue(index);
            } 
        }

        override public object this[String name] {
            get { 
                int ordinal = GetOrdinal(name);
                return GetValue(ordinal); 
            } 
        }
 
        // grouping the native OLE DB casts togther by required interfaces and optional interfaces
        // want these to be methods, not properties otherwise they appear in VS7 managed debugger which attempts to evaluate them

        // required interface, safe cast 
        private UnsafeNativeMethods.IAccessor IAccessor() {
            Bid.Trace(" %d#, IAccessor\n", ObjectID); 
            return (UnsafeNativeMethods.IAccessor) IRowset(); 
        }
 
        // required interface, safe cast
        private UnsafeNativeMethods.IRowsetInfo IRowsetInfo() {
            Bid.Trace(" %d#, IRowsetInfo\n", ObjectID);
            return (UnsafeNativeMethods.IRowsetInfo) IRowset(); 
        }
 
        private UnsafeNativeMethods.IRowset IRowset() { 
            UnsafeNativeMethods.IRowset irowset = _irowset;
            if (null == irowset) { 
                Debug.Assert(false, "object is disposed");
                throw new ObjectDisposedException(GetType().Name);
            }
            return irowset; 
        }
 
        private UnsafeNativeMethods.IRow IRow() { 
            UnsafeNativeMethods.IRow irow = _irow;
            if (null == irow) { 
                Debug.Assert(false, "object is disposed");
                throw new ObjectDisposedException(GetType().Name);
            }
            return irow; 
        }
 
#if INDEXINFO 
        public DataTable GetIndexTable() {
            // if we can't get index info, it's not catastrophic 
            return null;
        }
#endif
 
        override public DataTable GetSchemaTable() {
            IntPtr hscp; 
            Bid.ScopeEnter(out hscp, " %d#\n", ObjectID); 
            try {
                DataTable schemaTable = _dbSchemaTable; 
                if (null == schemaTable) {
                    MetaData[] metadata = MetaData;
                    if ((null != metadata) && (0 < metadata.Length)) {
                        if ((0 < metadata.Length) && _useIColumnsRowset && (null != _connection)) { 
                            AppendSchemaInfo();
                        } 
                        schemaTable = BuildSchemaTable(metadata); 
                    }
                    else if (IsClosed) { // MDAC 68331 
                        throw ADP.DataReaderClosed("GetSchemaTable");
                    }
                    //GetSchemaTable() is defined to return null after NextResult returns false
                    //throw ADP.DataReaderNoData(); 
                }
                return schemaTable; 
            } 
            finally {
                Bid.ScopeLeave(ref hscp); 
            }
        }

        internal void BuildMetaInfo() { 
            Debug.Assert(null == _metadata, "BuildMetaInfo: already built, by _metadata");
 
            if (null != _irowset) { 
                if (_useIColumnsRowset) {
                    BuildSchemaTableRowset(_irowset); 
                }
                else {
                    BuildSchemaTableInfo(_irowset, false, false);
                } 
                if (null != _metadata && 0 < _metadata.Length) {
                    // @devnote: because we want to use the DBACCESSOR_OPTIMIZED bit, 
                    // we are required to create the accessor before fetching any rows 
                    CreateAccessors(true);
                    Debug.Assert(null != _bindings, "unexpected dbBindings"); 
                }
            }
            else if (null != _irow) {
                BuildSchemaTableInfo(_irow, false, false); 
                if (null != _metadata && 0 < _metadata.Length) {
                    CreateBindingsFromMetaData(true); 
                } 
            }
            if (null == _metadata) { 
                _hasRows = false;
                _visibleFieldCount = 0;
                _metadata = new MetaData[0];
            } 
        }
 
        private DataTable BuildSchemaTable(MetaData[] metadata) { 
            Debug.Assert(null == _dbSchemaTable, "BuildSchemaTable: schema table already exists");
            Debug.Assert(null != metadata, "BuildSchemaTable: no _metadata"); 

            DataTable schemaTable = new DataTable("SchemaTable");
            schemaTable.Locale = CultureInfo.InvariantCulture;
            schemaTable.MinimumCapacity = metadata.Length; 

            DataColumn name       = new DataColumn("ColumnName",       typeof(System.String)); 
            DataColumn ordinal    = new DataColumn("ColumnOrdinal",    typeof(System.Int32)); 
            DataColumn size       = new DataColumn("ColumnSize",       typeof(System.Int32));
            DataColumn precision  = new DataColumn("NumericPrecision", typeof(System.Int16)); 
            DataColumn scale      = new DataColumn("NumericScale",     typeof(System.Int16));

            DataColumn dataType   = new DataColumn("DataType",         typeof(System.Type));
            DataColumn providerType = new DataColumn("ProviderType",   typeof(System.Int32)); 

            DataColumn isLong        = new DataColumn("IsLong",           typeof(System.Boolean)); 
            DataColumn allowDBNull   = new DataColumn("AllowDBNull",      typeof(System.Boolean)); 
            DataColumn isReadOnly    = new DataColumn("IsReadOnly",       typeof(System.Boolean));
            DataColumn isRowVersion  = new DataColumn("IsRowVersion",     typeof(System.Boolean)); 

            DataColumn isUnique        = new DataColumn("IsUnique",        typeof(System.Boolean));
            DataColumn isKey           = new DataColumn("IsKey",           typeof(System.Boolean));
            DataColumn isAutoIncrement = new DataColumn("IsAutoIncrement", typeof(System.Boolean)); 
            DataColumn isHidden        = new DataColumn("IsHidden",        typeof(System.Boolean));
 
            DataColumn baseSchemaName  = new DataColumn("BaseSchemaName",  typeof(System.String)); 
            DataColumn baseCatalogName = new DataColumn("BaseCatalogName", typeof(System.String));
            DataColumn baseTableName   = new DataColumn("BaseTableName",   typeof(System.String)); 
            DataColumn baseColumnName  = new DataColumn("BaseColumnName",  typeof(System.String));

            ordinal.DefaultValue = 0;
            isLong.DefaultValue = false; 

            DataColumnCollection columns = schemaTable.Columns; 
 
            columns.Add(name);
            columns.Add(ordinal); 
            columns.Add(size);
            columns.Add(precision);
            columns.Add(scale);
 
            columns.Add(dataType);
            columns.Add(providerType); 
 
            columns.Add(isLong);
            columns.Add(allowDBNull); 
            columns.Add(isReadOnly);
            columns.Add(isRowVersion);

            columns.Add(isUnique); 
            columns.Add(isKey);
            columns.Add(isAutoIncrement); 
            if (_visibleFieldCount < metadata.Length) { 
                columns.Add(isHidden);
            } 

            columns.Add(baseSchemaName);
            columns.Add(baseCatalogName);
            columns.Add(baseTableName); 
            columns.Add(baseColumnName);
 
            for (int i = 0; i < metadata.Length; ++i) { 
                MetaData info = metadata[i];
 
                DataRow newRow = schemaTable.NewRow();
                newRow[name] = info.columnName;
                newRow[ordinal] = i; // MDAC 68319
                // @devnote: size is count of characters for WSTR or STR, bytes otherwise 
                // @devnote: see OLEDB spec under IColumnsInfo::GetColumnInfo
                newRow[size] = ((info.type.enumOleDbType != OleDbType.BSTR) ? info.size : -1); // MDAC 72653 
                newRow[precision] = info.precision; // MDAC 72800 
                newRow[scale] = info.scale;
 
                newRow[dataType] = info.type.dataType;
                newRow[providerType] = info.type.enumOleDbType;
                newRow[isLong] = OleDbDataReader.IsLong(info.flags);
                if (info.isKeyColumn) { 
                    newRow[allowDBNull] = OleDbDataReader.AllowDBNull(info.flags);
                } 
                else { 
                    newRow[allowDBNull] = OleDbDataReader.AllowDBNullMaybeNull(info.flags);
                } 
                newRow[isReadOnly] = OleDbDataReader.IsReadOnly(info.flags);
                newRow[isRowVersion] = OleDbDataReader.IsRowVersion(info.flags);

                newRow[isUnique] = info.isUnique; 
                newRow[isKey] = info.isKeyColumn;
                newRow[isAutoIncrement] = info.isAutoIncrement; 
                if (_visibleFieldCount < metadata.Length) { 
                    newRow[isHidden] = info.isHidden;
                } 

                if (null != info.baseSchemaName) {
                    newRow[baseSchemaName] = info.baseSchemaName;
                } 
                if (null != info.baseCatalogName) {
                    newRow[baseCatalogName] = info.baseCatalogName; 
                } 
                if (null != info.baseTableName) {
                    newRow[baseTableName] = info.baseTableName; 
                }
                if (null != info.baseColumnName) {
                    newRow[baseColumnName] = info.baseColumnName;
                } 

                schemaTable.Rows.Add(newRow); 
                newRow.AcceptChanges(); 
            }
 
            // mark all columns as readonly
            int count = columns.Count;
            for (int i=0; i < count; i++) {
                columns[i].ReadOnly = true; // MDAC 70943 
            }
 
            _dbSchemaTable = schemaTable; 
            return schemaTable;
        } 

        private void BuildSchemaTableInfo(object handle, bool filterITypeInfo, bool filterChapters) {
            Debug.Assert(null == _dbSchemaTable, "non-null SchemaTable");
            Debug.Assert(null == _metadata, "non-null metadata"); 
            Debug.Assert(null != handle, "unexpected null rowset");
 
            Bid.Trace(" %d#, IColumnsInfo\n", ObjectID); 
            UnsafeNativeMethods.IColumnsInfo icolumnsInfo = (handle as UnsafeNativeMethods.IColumnsInfo);
            if (null == icolumnsInfo) { 
                 Bid.Trace(" %08X{HRESULT}\n", OleDbHResult.E_NOINTERFACE);
                _dbSchemaTable = null;
#if DEBUG
                if (handle is UnsafeNativeMethods.IRow) { 
                    Debug.Assert(false, "bad IRow - IColumnsInfo not available");
                } 
                else { 
                    Debug.Assert(handle is UnsafeNativeMethods.IRowset, "bad IRowset - IColumnsInfo not available");
                } 
#endif
                return;
            }
 
            OleDbHResult hr;
            IntPtr columnCount = ADP.PtrZero; // column count 
            IntPtr columnInfos = ADP.PtrZero; // ptr to byvalue tagDBCOLUMNINFO[] 

            using(DualCoTaskMem safehandle = new DualCoTaskMem(icolumnsInfo, out columnCount, out columnInfos, out hr)) { 
                if (hr < 0) {
                    ProcessResults(hr);
                }
                if (0 < (int)columnCount) { 
                    BuildSchemaTableInfoTable(columnCount.ToInt32(), columnInfos, filterITypeInfo, filterChapters);
                } 
            } 
        }
 
        // create DataColumns
        // add DataColumns to DataTable
        // add schema information to DataTable
        // generate unique column names 
        private void BuildSchemaTableInfoTable(int columnCount, IntPtr columnInfos, bool filterITypeInfo, bool filterChapters) {
            Debug.Assert(0 < columnCount, "BuildSchemaTableInfoTable - no column"); 
 
            int rowCount = 0;
            MetaData[] metainfo = new MetaData[columnCount]; 

            // for every column, build an equivalent to tagDBCOLUMNINFO
            tagDBCOLUMNINFO dbColumnInfo = new tagDBCOLUMNINFO();
            for (int i = 0, offset = 0; i < columnCount; ++i, offset += ODB.SizeOf_tagDBCOLUMNINFO) { 
                Marshal.PtrToStructure(ADP.IntPtrOffset(columnInfos, offset), dbColumnInfo);
#if WIN32 
                if (0 >= (int) dbColumnInfo.iOrdinal) { 
#else
                if (0 >= (long) dbColumnInfo.iOrdinal) { 
#endif
                    continue;
                }
                if (OleDbDataReader.DoColumnDropFilter(dbColumnInfo.dwFlags)) { 
                    continue;
                } 
 
                if (null == dbColumnInfo.pwszName) {
                    dbColumnInfo.pwszName = ""; 
                }
                if (filterITypeInfo && (ODB.DBCOLUMN_TYPEINFO == dbColumnInfo.pwszName)) { // MDAC 65306
                    continue;
                } 
                if (filterChapters && (NativeDBType.HCHAPTER == dbColumnInfo.wType)) {
                    continue;  // filter chapters in IRowset from IDBSchemaRowset for DumpToTable 
                } 

                bool islong  = OleDbDataReader.IsLong(dbColumnInfo.dwFlags); 
                bool isfixed = OleDbDataReader.IsFixed(dbColumnInfo.dwFlags);
                NativeDBType dbType = NativeDBType.FromDBType(dbColumnInfo.wType, islong, isfixed);

                MetaData info = new MetaData(); 
                info.columnName = dbColumnInfo.pwszName;
                info.type = dbType; 
                info.ordinal = dbColumnInfo.iOrdinal; 
#if WIN32
                    info.size = (int)dbColumnInfo.ulColumnSize; 
#else
                    long maxsize = (long) dbColumnInfo.ulColumnSize;
                    info.size = (((maxsize < 0) || (Int32.MaxValue < maxsize)) ? Int32.MaxValue : (int)maxsize);
#endif 
                info.flags = dbColumnInfo.dwFlags;
                info.precision = dbColumnInfo.bPrecision; 
                info.scale = dbColumnInfo.bScale; 

                info.kind = dbColumnInfo.columnid.eKind; 
                switch(dbColumnInfo.columnid.eKind) {
                    case ODB.DBKIND_GUID_NAME:
                    case ODB.DBKIND_GUID_PROPID:
                    case ODB.DBKIND_GUID: 
                        info.guid = dbColumnInfo.columnid.uGuid;
                        break; 
                    default: 
                        Debug.Assert(ODB.DBKIND_PGUID_NAME != dbColumnInfo.columnid.eKind, "OLE DB providers never return pGuid-style bindings.");
                        Debug.Assert(ODB.DBKIND_PGUID_PROPID != dbColumnInfo.columnid.eKind, "OLE DB providers never return pGuid-style bindings."); 
                        info.guid = Guid.Empty;
                        break;
                }
                switch(dbColumnInfo.columnid.eKind) { 
                    case ODB.DBKIND_GUID_PROPID:
                    case ODB.DBKIND_PROPID: 
                        info.propid = dbColumnInfo.columnid.ulPropid; 
                        break;
                    case ODB.DBKIND_GUID_NAME: 
                    case ODB.DBKIND_NAME:
                        if (ADP.PtrZero != dbColumnInfo.columnid.ulPropid) {
                            info.idname = Marshal.PtrToStringUni(dbColumnInfo.columnid.ulPropid);
                        } 
                        else {
                            info.idname = null; 
                        } 
                        break;
                    default: 
                        info.propid = ADP.PtrZero;
                        break;
                }
                metainfo[rowCount] = info; 

#if DEBUG 
                if (AdapterSwitches.DataSchema.TraceVerbose) { 
                    Debug.WriteLine("OleDbDataReader[" + info.ordinal.ToInt64().ToString(CultureInfo.InvariantCulture) + ", " + dbColumnInfo.pwszName + "]=" + dbType.enumOleDbType.ToString() + "," + dbType.dataSourceType + ", " + dbType.wType);
                } 
#endif
                rowCount++;
            }
            if (rowCount < columnCount) { // shorten names array appropriately 
                MetaData[] tmpinfo = new MetaData[rowCount];
                for (int i = 0; i < rowCount; ++i) { 
                    tmpinfo[i] = metainfo[i]; 
                }
                metainfo = tmpinfo; 
            }
            _visibleFieldCount = rowCount;
            _metadata = metainfo;
        } 

        private void BuildSchemaTableRowset(object handle) { 
            Debug.Assert(null == _dbSchemaTable, "BuildSchemaTableRowset - non-null SchemaTable"); 
            Debug.Assert(null != handle, "BuildSchemaTableRowset(object) - unexpected null handle");
 
            Bid.Trace(" %d, IColumnsRowset\n", ObjectID);
            UnsafeNativeMethods.IColumnsRowset icolumnsRowset = (handle as UnsafeNativeMethods.IColumnsRowset);

            if (null != icolumnsRowset) { 
                UnsafeNativeMethods.IRowset rowset = null;
                IntPtr cOptColumns; 
                OleDbHResult hr; 

                using(DualCoTaskMem prgOptColumns = new DualCoTaskMem(icolumnsRowset, out cOptColumns, out hr)) { 
                    Debug.Assert((0 == hr) || prgOptColumns.IsInvalid, "GetAvailableCOlumns: unexpected return");

                    Bid.Trace(" %d#, IID_IRowset\n", ObjectID);
                    hr = icolumnsRowset.GetColumnsRowset(ADP.PtrZero, cOptColumns, prgOptColumns, ref ODB.IID_IRowset, 0, ADP.PtrZero, out rowset); 
                    Bid.Trace(" %08X{HRESULT}\n", hr);
                } 
 
                Debug.Assert((0 <= hr) || (null == rowset), "if GetColumnsRowset failed, rowset should be null");
                if (hr < 0) { 
                    ProcessResults(hr);
                }
                DumpToSchemaTable(rowset);
 
                // VSTFDEVDIV 479576: release the rowset to avoid race condition between the GC and the user code causing
                // "Connection is busy with results for another command" exception 
                if (null != rowset) { 
                    Marshal.ReleaseComObject(rowset);
                } 
            }
            else {
                Bid.Trace(" %08X{HRESULT}\n", OleDbHResult.E_NOINTERFACE);
                _useIColumnsRowset = false; // MDAC 72653 
                BuildSchemaTableInfo(handle, false, false);
            } 
        } 

        override public void Close() { 
            IntPtr hscp;
            Bid.ScopeEnter(out hscp, " %d#\n", ObjectID);
            try {
                OleDbConnection con = _connection; 
                OleDbCommand cmd = _command;
                Bindings bindings = _parameterBindings; 
                _connection = null; 
                _command = null;
                _parameterBindings = null; 

                _isClosed = true;

                DisposeOpenResults(); 
                _hasRows = false;
 
                if ((null != cmd) && cmd.canceling) { // MDAC 68964 
                    DisposeNativeMultipleResults();
 
                    if (null != bindings) {
                        bindings.CloseFromConnection();
                        bindings = null;
                    } 
                }
                else { 
                    UnsafeNativeMethods.IMultipleResults multipleResults = _imultipleResults; 
                    _imultipleResults = null;
 
                    if (null != multipleResults) {
                        // if we don't have a cmd, same as a cancel (don't call NextResults) which is ADODB behavior

                        try { 
                            // tricky code path is an exception is thrown
                            // causing connection to do a ResetState and connection.Close 
                            // resulting in OleDbCommand.CloseFromConnection 
                            if ((null != cmd) && !cmd.canceling) { // MDAC 71435
                                IntPtr affected = IntPtr.Zero; 
                                OleDbException nextResultsFailure = NextResults(multipleResults, null, cmd, out affected);
                                _recordsAffected = AddRecordsAffected(_recordsAffected, affected);
                                if (null != nextResultsFailure) {
                                    throw nextResultsFailure; 
                                }
                            } 
                        } 
                        finally {
                            if (null != multipleResults) { 
                                Marshal.ReleaseComObject(multipleResults);
                            }
                        }
                    } 
                }
 
                if ((null != cmd) && (0 == _depth)) { 
                    // return bindings back to the cmd after closure of root DataReader
                    cmd.CloseFromDataReader(bindings); // MDAC 52283 
                }

                if (null != con) {
                    con.RemoveWeakReference(this); 

                    // if the DataReader is Finalized it will not close the connection 
                    if (IsCommandBehavior(CommandBehavior.CloseConnection)) { 
                        con.Close();
                    } 
                }

                // release unmanaged objects
                RowHandleBuffer rowHandleNativeBuffer = _rowHandleNativeBuffer; 
                _rowHandleNativeBuffer = null;
                if (null != rowHandleNativeBuffer) { 
                    rowHandleNativeBuffer.Dispose(); 
                }
            } 
            finally {
                Bid.ScopeLeave(ref hscp);
            }
        } 

        internal void CloseReaderFromConnection(bool canceling) { 
            // being called from the connection, we will have a command. that command 
            // may be Disposed, but it doesn't matter since another command can't execute
            // until all DataReader are closed 
            if (null != _command) { //
                _command.canceling = canceling;
            }
 
            // called from the connection which will remove this from its ReferenceCollection
            // we want the NextResult behavior, but no errors 
            _connection = null; 

            Close(); 
        }

        private void DisposeManagedRowset() {
            //not cleared after last rowset 
            //_hasRows = false;
 
            _isRead = false; 
            _hasRowsReadCheck = false;
 
            _nextAccessorForRetrieval = 0;
            _nextValueForRetrieval = 0;

            Bindings[] bindings = _bindings; 
            _bindings = null;
 
            if (null != bindings) { 
                for (int i = 0; i < bindings.Length; ++i) {
                    if (null != bindings[i]) { // MDAC 77007 
                        bindings[i].Dispose();
                    }
                }
            } 

            _currentRow = 0; 
            _rowFetchedCount = IntPtr.Zero; 

            _dbSchemaTable = null; 
            _visibleFieldCount = 0;
            _metadata = null;
            _fieldNameLookup = null;
        } 

        private void DisposeNativeMultipleResults() { 
            UnsafeNativeMethods.IMultipleResults imultipleResults = _imultipleResults; 
            _imultipleResults = null;
 
            if (null != imultipleResults) {
                Marshal.ReleaseComObject(imultipleResults);
            }
        } 

        private void DisposeNativeRowset() { 
            UnsafeNativeMethods.IRowset irowset = _irowset; 
            _irowset = null;
 
            ChapterHandle chapter = _chapterHandle;
            _chapterHandle = ChapterHandle.DB_NULL_HCHAPTER;

            if (ChapterHandle.DB_NULL_HCHAPTER != chapter) { // MDAC 81441 
                chapter.Dispose();
            } 
 
            if (null != irowset) {
                Marshal.ReleaseComObject(irowset); 
            }
        }

        private void DisposeNativeRow() { 
            UnsafeNativeMethods.IRow irow = _irow;
            _irow = null; 
 
            if (null != irow) {
                Marshal.ReleaseComObject(irow); 
            }
        }

        private void DisposeOpenResults() { 
            DisposeManagedRowset();
 
            DisposeNativeRow(); 
            DisposeNativeRowset();
        } 

        override public Boolean GetBoolean(int ordinal) {
            ColumnBinding binding = GetColumnBinding(ordinal);
            return binding.ValueBoolean(); 
        }
 
        override public Byte GetByte(int ordinal) { 
            ColumnBinding binding = GetColumnBinding(ordinal);
            return binding.ValueByte(); 
        }

        private ColumnBinding DoSequentialCheck(int ordinal, Int64 dataIndex, string method) {
            ColumnBinding binding = GetColumnBinding(ordinal); 

            if (dataIndex > Int32.MaxValue) { 
                throw ADP.InvalidSourceBufferIndex(0, dataIndex, "dataIndex"); 
            }
            if (_sequentialOrdinal != ordinal) { 
                _sequentialOrdinal = ordinal;
                _sequentialBytesRead = 0;
            }
            else if (_sequentialAccess && (_sequentialBytesRead < dataIndex)) { 
                throw ADP.NonSeqByteAccess(dataIndex, _sequentialBytesRead, method);
            } 
            // getting the value doesn't really belong, but it's common to both 
            // callers GetBytes and GetChars so we might as well have the code here
            return binding; 
        }

        override public Int64 GetBytes(int ordinal, Int64 dataIndex, byte[] buffer, Int32 bufferIndex, Int32 length) {
            ColumnBinding binding = DoSequentialCheck(ordinal, dataIndex, ADP.GetBytes); 
            byte[] value = binding.ValueByteArray();
 
            if (null == buffer) { 
                return value.Length;
            } 
            int srcIndex = (int) dataIndex;
            int byteCount = Math.Min(value.Length - srcIndex, length);
            if (srcIndex < 0) { // MDAC 72830
                throw ADP.InvalidSourceBufferIndex(value.Length, srcIndex, "dataIndex"); 
            }
            else if ((bufferIndex < 0) || (bufferIndex >= buffer.Length)) { // MDAC 71013 
                throw ADP.InvalidDestinationBufferIndex(buffer.Length, bufferIndex, "bufferIndex"); 
            }
            if (0 < byteCount) { 
                // @usernote: user may encounter ArgumentException from Buffer.BlockCopy
                Buffer.BlockCopy(value, srcIndex, buffer, bufferIndex, byteCount);
                _sequentialBytesRead = srcIndex + byteCount; // MDAC 71013
            } 
            else if (length < 0) { // MDAC 71007
                throw ADP.InvalidDataLength(length); 
            } 
            else {
                byteCount = 0; 
            }
            return byteCount;
        }
 
        override public Int64 GetChars(int ordinal, Int64 dataIndex, char[] buffer, Int32 bufferIndex, Int32 length) {
            ColumnBinding binding = DoSequentialCheck(ordinal, dataIndex, ADP.GetChars); 
            string value =  binding.ValueString(); 

            if (null == buffer) { 
                return value.Length;
            }

            int srcIndex = (int) dataIndex; 
            int charCount = Math.Min(value.Length - srcIndex, length);
            if (srcIndex < 0) { // MDAC 72830 
                throw ADP.InvalidSourceBufferIndex(value.Length, srcIndex, "dataIndex"); 
            }
            else if ((bufferIndex < 0) || (bufferIndex >= buffer.Length)) { // MDAC 71013 
                throw ADP.InvalidDestinationBufferIndex(buffer.Length, bufferIndex, "bufferIndex");
            }
            if (0 < charCount) {
                // @usernote: user may encounter ArgumentException from String.CopyTo 
                value.CopyTo(srcIndex, buffer, bufferIndex, charCount);
                _sequentialBytesRead = srcIndex + charCount; // MDAC 71013 
            } 
            else if (length < 0) { // MDAC 71007
                throw ADP.InvalidDataLength(length); 
            }
            else {
                charCount = 0;
            } 
            return charCount;
        } 
 
        [ EditorBrowsableAttribute(EditorBrowsableState.Never) ] // MDAC 69508
        override public Char GetChar(int ordinal) { 
            throw ADP.NotSupported();
        }

        [ EditorBrowsableAttribute(EditorBrowsableState.Advanced) ] 
        new public OleDbDataReader GetData(int ordinal) {
            ColumnBinding binding = GetColumnBinding(ordinal); 
            return binding.ValueChapter(); 
        }
 
        override protected DbDataReader GetDbDataReader(int ordinal) {
            return GetData(ordinal);
        }
 
        internal OleDbDataReader ResetChapter(int bindingIndex, int index, RowBinding rowbinding, int valueOffset) {
            return GetDataForReader(_metadata[bindingIndex + index].ordinal, rowbinding, valueOffset); 
        } 

        private OleDbDataReader GetDataForReader(IntPtr ordinal, RowBinding rowbinding, int valueOffset) { 
            UnsafeNativeMethods.IRowsetInfo rowsetInfo = IRowsetInfo();
            UnsafeNativeMethods.IRowset result;
            OleDbHResult hr;
 
            Bid.Trace(" %d#, ColumnOrdinal=%Id\n", ObjectID, ordinal);
            hr = rowsetInfo.GetReferencedRowset((IntPtr)ordinal, ref ODB.IID_IRowset, out result); 
            Bid.Trace(" %08X{HRESULT}\n", hr); 

            ProcessResults(hr); 

            OleDbDataReader reader = null;
            if (null != result) {
                // only when the first datareader is closed will the connection close 
                ChapterHandle chapterHandle = ChapterHandle.CreateChapterHandle(result, rowbinding, valueOffset);
                reader = new OleDbDataReader(_connection, _command, 1+Depth, _commandBehavior & ~CommandBehavior.CloseConnection); 
                reader.InitializeIRowset(result, chapterHandle, ADP.RecordsUnaffected); 
                reader.BuildMetaInfo();
                reader.HasRowsRead(); 

                if (null != _connection) {
                    // connection tracks all readers to prevent cmd from executing
                    // until all readers (including nested) are closed 
                    _connection.AddWeakReference(reader, OleDbReferenceCollection.DataReaderTag);
                } 
            } 
            return reader;
        } 

        override public String GetDataTypeName(int index) {
            if (null != _metadata) {
                return _metadata[index].type.dataSourceType; 
            }
            throw ADP.DataReaderNoData(); 
        } 

        override public DateTime GetDateTime(int ordinal) { 
            ColumnBinding binding = GetColumnBinding(ordinal);
            return binding.ValueDateTime();
        }
 
        override public Decimal GetDecimal(int ordinal) {
            ColumnBinding binding = GetColumnBinding(ordinal); 
            return binding.ValueDecimal(); 
        }
 
        override public Double GetDouble(int ordinal) {
            ColumnBinding binding = GetColumnBinding(ordinal);
            return binding.ValueDouble();
        } 

        override public IEnumerator GetEnumerator() { 
            return new DbEnumerator((IDataReader)this, IsCommandBehavior(CommandBehavior.CloseConnection)); 
        }
 
        override public Type GetFieldType(int index) {
            if (null != _metadata) {
                return _metadata[index].type.dataType;
            } 
            throw ADP.DataReaderNoData();
        } 
 
        override public Single GetFloat(int ordinal) {
            ColumnBinding binding = GetColumnBinding(ordinal); 
            return binding.ValueSingle();
        }

        override public Guid GetGuid(int ordinal) { 
            ColumnBinding binding = GetColumnBinding(ordinal);
            return binding.ValueGuid(); 
        } 

        override public Int16 GetInt16(int ordinal) { 
            ColumnBinding binding = GetColumnBinding(ordinal);
            return binding.ValueInt16();
        }
 
        override public Int32 GetInt32(int ordinal) {
            ColumnBinding binding = GetColumnBinding(ordinal); 
            return binding.ValueInt32(); 
        }
 
        override public Int64 GetInt64(int ordinal) {
            ColumnBinding binding = GetColumnBinding(ordinal);
            return binding.ValueInt64();
        } 

        override public String GetName(int index) { 
            if (null != _metadata) { 
                Debug.Assert(null != _metadata[index].columnName, "MDAC 66681");
                return _metadata[index].columnName; 
            }
            throw ADP.DataReaderNoData();
        }
 
        override public Int32 GetOrdinal(String name) {
            if (null == _fieldNameLookup) { 
                if (null == _metadata) { 
                    throw ADP.DataReaderNoData();
                } 
                _fieldNameLookup = new FieldNameLookup(this, -1);
            }
            return _fieldNameLookup.GetOrdinal(name); // MDAC 71470
        } 

        override public String GetString(int ordinal) { 
            ColumnBinding binding = GetColumnBinding(ordinal); 
            return binding.ValueString();
        } 

        public TimeSpan GetTimeSpan(int ordinal) {
            return (TimeSpan) GetValue(ordinal);
        } 

        private MetaData DoValueCheck(int ordinal) { 
            if (!_isRead) { 
                // Read hasn't been called yet or no more data
                throw ADP.DataReaderNoData(); 
            }
            else if (_sequentialAccess && (ordinal < _nextValueForRetrieval)) {
                throw ADP.NonSequentialColumnAccess(ordinal, _nextValueForRetrieval);
            } 
            // @usernote: user may encounter the IndexOutOfRangeException
            MetaData info = _metadata[ordinal]; 
            return info; 
        }
 
        private ColumnBinding GetColumnBinding(int ordinal) {
            MetaData info = DoValueCheck(ordinal);
            return GetValueBinding(info);
        } 

        private ColumnBinding GetValueBinding(MetaData info) { 
            ColumnBinding binding = info.columnBinding; 
            Debug.Assert(null != binding, "null binding");
 
            // do we need to jump to the next accessor
            for (int i = _nextAccessorForRetrieval; i <= binding.IndexForAccessor; ++i) {
                Debug.Assert(_nextAccessorForRetrieval <= binding.IndexForAccessor, "backwards index for accessor");
                Debug.Assert(_nextAccessorForRetrieval == i, "failed to increment"); 

                if (_sequentialAccess) { 
                    if (_nextValueForRetrieval != binding.Index) { // release old value 
                        _metadata[_nextValueForRetrieval].columnBinding.ResetValue();
                    } 
                    _nextAccessorForRetrieval = binding.IndexForAccessor;
                }

                if (null != _irowset) { 
                    GetRowDataFromHandle(); // will increment _nextAccessorForRetrieval
                } 
                else if (null != _irow) { 
                    GetRowValue(); // will increment _nextAccessorForRetrieval
                } 
                else {
                    throw ADP.DataReaderNoData();
                }
            } 

            // to enforce sequential access 
            _nextValueForRetrieval = binding.Index; 
            return binding;
        } 

        override public object GetValue(int ordinal) {
            ColumnBinding binding = GetColumnBinding(ordinal);
            object value = binding.Value(); 
            return value;
        } 
 
        override public Int32 GetValues(object[] values) {
            if (null == values) { 
                throw ADP.ArgumentNull("values");
            }
            MetaData info = DoValueCheck(0);
            int count = Math.Min(values.Length, _visibleFieldCount); 
            for (int i = 0; (i < _metadata.Length) && (i < count); ++i) {
                ColumnBinding binding = GetValueBinding(_metadata[i]); 
                values[i] = binding.Value(); 
            }
            return count; 
        }

        private bool IsCommandBehavior(CommandBehavior condition) {
            return (condition == (condition & _commandBehavior)); 
        }
 
        override public Boolean IsDBNull(int ordinal) { 
            ColumnBinding binding = GetColumnBinding(ordinal);
            return binding.IsValueNull(); 
        }

        private void ProcessResults(OleDbHResult hr) {
            Exception e; 
            if (null != _command) {
                e = OleDbConnection.ProcessResults(hr, _connection, _command); 
            } 
            else {
                e = OleDbConnection.ProcessResults(hr, _connection, _connection); 
            }
            if (null != e) { throw e; }
        }
 

        static private IntPtr AddRecordsAffected(IntPtr recordsAffected, IntPtr affected) { // MDAC 65374 
#if WIN32 
            if (0 <= (int)affected) {
                if (0 <= (int)recordsAffected) { 
                    return (IntPtr)((int)recordsAffected + (int)affected);
#else
            if (0 <= (long)affected) {
                if (0 <= (long)recordsAffected) { 
                    return (IntPtr)((long)recordsAffected + (long)affected);
#endif 
                } 
                return affected;
            } 
            return recordsAffected;
        }

        override public int VisibleFieldCount { 
            get {
                Bid.Trace(" %d#\n", ObjectID); 
                if (IsClosed) { 
                    throw ADP.DataReaderClosed("VisibleFieldCount");
                } 
                return _visibleFieldCount;
            }
        }
 
        internal void HasRowsRead() { // MDAC 78405
            Debug.Assert(!_hasRowsReadCheck, "_hasRowsReadCheck not reset"); 
            bool flag = Read(); 
            _hasRows = flag;
            _hasRowsReadCheck = true; 
            _isRead = false;
        }

        static internal OleDbException NextResults(UnsafeNativeMethods.IMultipleResults imultipleResults, OleDbConnection connection, OleDbCommand command, out IntPtr recordsAffected) { 
            recordsAffected = ADP.RecordsUnaffected;
            List exceptions = null; // WebData 104564 
            if (null != imultipleResults) { 
                object result;
                IntPtr affected; 
                OleDbHResult hr;


                // MSOLAP provider doesn't move onto the next result when calling GetResult with IID_NULL, but does return S_OK with 0 affected records. 
                // we want to break out of that infinite loop for ExecuteNonQuery and the multiple result Close scenarios
                for (int loop = 0;; ++loop) { 
                    if ((null != command) && command.canceling) { // MDAC 68964 
                        break;
                    } 

                    Bid.Trace(" DBRESULTFLAG_DEFAULT, IID_NULL\n");
                    hr = imultipleResults.GetResult(ADP.PtrZero, ODB.DBRESULTFLAG_DEFAULT, ref ODB.IID_NULL, out affected, out result);
                    Bid.Trace(" %08X{HRESULT}, RecordAffected=%Id\n", hr, affected); 

                    // If a provider doesn't support IID_NULL and returns E_NOINTERFACE we want to break out 
                    // of the loop without throwing an exception.  Our behavior will match ADODB in that scenario 
                    // where Recordset.Close just releases the interfaces without proccessing remaining results
                    if ((OleDbHResult.DB_S_NORESULT == hr) || (OleDbHResult.E_NOINTERFACE == hr)) { // MDAC 70874 
                        break;
                    }
                    if (null != connection) {
                        Exception e = OleDbConnection.ProcessResults(hr, connection, command); 
                        if (null != e) {
                            OleDbException excep = (e as OleDbException); 
                            if (null != excep) { 
                                if (null == exceptions) {
                                    exceptions = new List(); 
                                }
                                exceptions.Add(excep);
                            }
                            else { 
                                Debug.Assert(OleDbHResult.DB_E_OBJECTOPEN == hr, "unexpected");
                                throw e; // we don't expect to be here, but it could happen 
                            } 
                        }
                    } 
                    else if (hr < 0) {
                        SafeNativeMethods.Wrapper.ClearErrorInfo();
                        break; // MDAC 72694
                    } 
                    recordsAffected = AddRecordsAffected(recordsAffected, affected);
 
                    if (0 != (int)affected) { 
                        loop = 0;
                    } 
                    else if (2000 <= loop) { // MDAC 72126 (reason for more than 1000 iterations)
                        NextResultsInfinite(); // MDAC 72738
                        break;
                    } 
                }
            } 
            if (null != exceptions) { 
                return OleDbException.CombineExceptions(exceptions);
            } 
            return null;
        }

        static private void NextResultsInfinite() { // MDAC 72738 
            Bid.Trace(" System.Data.OleDb.OleDbDataReader: 2000 IMultipleResult.GetResult(NULL, DBRESULTFLAG_DEFAULT, IID_NULL, NULL, NULL) iterations with 0 records affected. Stopping suspect infinite loop. To work-around try using ExecuteReader() and iterating through results with NextResult().\n");
 
            // [....]'s suggestion is that we debug assert so that users will learn of MSOLAP's misbehavior and not call ExecuteNonQuery 
            Debug.Assert(false, " System.Data.OleDb.OleDbDataReader: 2000 IMultipleResult.GetResult(NULL, DBRESULTFLAG_DEFAULT, IID_NULL, NULL, NULL) iterations with 0 records affected. Stopping suspect infinite loop. To work-around try using ExecuteReader() and iterating through results with NextResult().\n");
        } 

        override public bool NextResult() {
            IntPtr hscp;
            Bid.ScopeEnter(out hscp, " %d#\n", ObjectID); 
            try {
                bool retflag = false; 
                if (IsClosed) { 
                    throw ADP.DataReaderClosed("NextResult");
                } 
                _fieldNameLookup = null;

                OleDbCommand command = _command;
                UnsafeNativeMethods.IMultipleResults imultipleResults = _imultipleResults; 
                if (null != imultipleResults) {
                    DisposeOpenResults(); 
                    _hasRows = false; 

                    for (;;) { 
                        Debug.Assert(null == _irow, "NextResult: row loop check");
                        Debug.Assert(null == _irowset, "NextResult: rowset loop check");

                        object result = null; 
                        OleDbHResult hr;
                        IntPtr affected; 
 
                        if ((null != command) && command.canceling) { // MDAC 69986
                            Close(); 
                            break;
                        }

                        Bid.Trace(" %d#, IID_IRowset\n", ObjectID); 
                        hr = imultipleResults.GetResult(ADP.PtrZero, ODB.DBRESULTFLAG_DEFAULT, ref ODB.IID_IRowset, out affected, out result);
                        Bid.Trace(" %08X{HRESULT}, RecordAffected=%Id\n", hr, affected); 
 
                        if ((0 <= hr) && (null != result)) {
                            Bid.Trace(" %d#, IRowset\n", ObjectID); 
                            _irowset = (UnsafeNativeMethods.IRowset) result;
                        }
                        _recordsAffected = AddRecordsAffected(_recordsAffected, affected);
 
                        if (OleDbHResult.DB_S_NORESULT == hr) {
                            DisposeNativeMultipleResults(); 
                            break; 
                        }
                        // @devnote: infomessage events may be fired from here 
                        ProcessResults(hr);

                        if (null != _irowset) {
                            BuildMetaInfo(); 
                            HasRowsRead();
                            retflag = true; 
                            break; 
                        }
                    } 
                }
                else {
                    DisposeOpenResults(); // MDAC 70934
                    _hasRows = false; // MDAC 85850 
                }
                return retflag; 
            } 
            finally {
                Bid.ScopeLeave(ref hscp); 
            }
        }

        override public bool Read() { 
            IntPtr hscp;
            Bid.ScopeEnter(out hscp, " %d#\n", ObjectID); 
            try { 
                bool retflag = false;
                OleDbCommand command = _command; 
                if ((null != command) && command.canceling) { // MDAC 69986
                    DisposeOpenResults();
                }
                else if (null != _irowset) { 
                    if (_hasRowsReadCheck) {
                        _isRead = retflag = _hasRows; 
                        _hasRowsReadCheck = false; 
                    }
                    else if (_singleRow && _isRead) { 
                        DisposeOpenResults(); // MDAC 66109
                    }
                    else {
                        retflag = ReadRowset(); 
                    }
                } 
                else if (null != _irow) { 
                    retflag = ReadRow();
                } 
                else if (IsClosed) {
                    throw ADP.DataReaderClosed("Read");
                }
                return retflag; 
            }
            finally { 
                Bid.ScopeLeave(ref hscp); 
            }
        } 

        private bool ReadRow() {
            if (_isRead) {
                _isRead = false; // for DoValueCheck 

                DisposeNativeRow(); 
 
                _sequentialOrdinal = -1; // sequentialBytesRead will reset when used
            } 
            else {
                _isRead = true;
                return (0 < _metadata.Length);
            } 
            return false;
        } 
 
        private bool ReadRowset() {
            Debug.Assert(null != _irowset, "ReadRow: null IRowset"); 
            Debug.Assert(0 <= _metadata.Length, "incorrect state for fieldCount");

            // releases bindings as necessary
            // bumps current row, else resets it back to initial state 
            ReleaseCurrentRow();
 
            _sequentialOrdinal = -1; // sequentialBytesRead will reset when used 

            // making the check if (null != irowset) unnecessary 
            // if necessary, get next group of row handles
            if (IntPtr.Zero == _rowFetchedCount) { // starts at (-1 <= 0)
                Debug.Assert(0 == _currentRow, "incorrect state for _currentRow");
                Debug.Assert(0 <= _metadata.Length, "incorrect state for fieldCount"); 
                Debug.Assert(0 == _nextAccessorForRetrieval, "incorrect state for nextAccessorForRetrieval");
                Debug.Assert(0 == _nextValueForRetrieval, "incorrect state for nextValueForRetrieval"); 
 
                // @devnote: releasing row handles occurs next time user calls read, skip, or close
                GetRowHandles(/*skipCount*/); 
            }
            return ((_currentRow <= (int)_rowFetchedCount) && _isRead);
        }
 
        private void ReleaseCurrentRow() {
            Debug.Assert(null != _irowset, "ReleaseCurrentRow: no rowset"); 
 
            if (0 < (int)_rowFetchedCount) {
 
                // release the data in the current row
                Bindings[] bindings = _bindings;
                Debug.Assert(null != bindings, "ReleaseCurrentRow: null dbBindings");
                for (int i = 0; (i < bindings.Length) && (i < _nextAccessorForRetrieval); ++i) { 
                    bindings[i].CleanupBindings();
                } 
                _nextAccessorForRetrieval = 0; 
                _nextValueForRetrieval = 0;
 
                _currentRow++;
                if (_currentRow == (int)_rowFetchedCount) {
                    ReleaseRowHandles();
                } 
            }
        } 
 
        private void CreateAccessors(bool allowMultipleAccessor) {
            Debug.Assert(null == _bindings, "CreateAccessor: dbBindings already exists"); 
            Debug.Assert(null != _irowset, "CreateAccessor: no IRowset available");
            Debug.Assert(null != _metadata && 0 < _metadata.Length, "no columns");

            Bindings[] dbBindings = CreateBindingsFromMetaData(allowMultipleAccessor); 

            UnsafeNativeMethods.IAccessor iaccessor = IAccessor(); 
            for (int i = 0; i < dbBindings.Length; ++i) { 
                OleDbHResult hr = dbBindings[i].CreateAccessor(iaccessor, ODB.DBACCESSOR_ROWDATA);
                if (hr < 0) { 
                    ProcessResults(hr);
                }
            }
 
            if (IntPtr.Zero == _rowHandleFetchCount) {
                _rowHandleFetchCount = new IntPtr(1); 
 
                object maxRows = GetPropertyValue(ODB.DBPROP_MAXROWS);
                if (maxRows is Int32) { 
                    _rowHandleFetchCount = new IntPtr((int) maxRows);
                    if ((ADP.PtrZero == _rowHandleFetchCount) || (20 <= (int)_rowHandleFetchCount)) {
                        _rowHandleFetchCount = new IntPtr(20);
                    } 
                }
                else if (maxRows is Int64) { 
                    _rowHandleFetchCount = new IntPtr((long) maxRows); 
                    if ((ADP.PtrZero == _rowHandleFetchCount) || (20 <= (long)_rowHandleFetchCount)) {
                        _rowHandleFetchCount = new IntPtr(20); 
                    }
                }
            }
            if (null == _rowHandleNativeBuffer) { 
                _rowHandleNativeBuffer = new RowHandleBuffer(_rowHandleFetchCount);
            } 
        } 

        private Bindings[] CreateBindingsFromMetaData(bool allowMultipleAccessor) { 
            int bindingCount = 0;
            int currentBindingIndex = 0;

            MetaData[] metadata = _metadata; 

            int[] indexToBinding = new int[metadata.Length]; 
            int[] indexWithinBinding = new int[metadata.Length]; 

            // walk through the schemaRows to determine the number of binding groups 
            if (allowMultipleAccessor) {
                if (null != _irowset) {
                    for (int i = 0; i < indexToBinding.Length; ++i) {
                        indexToBinding[i] = bindingCount; 
                        indexWithinBinding[i] = currentBindingIndex;
#if false 
                        // @denote: single/multiple Accessors 
                        if ((bindingCount < 2) && IsLong(metadata[i].flags)) {
                            bindingCount++; 
                            currentBindingIndex = 0;
                        }
                        else {
                            currentBindingIndex++; 
                        }
#elif false 
                        // @devnote: one accessor per column option 
                        bindingCount++;
                        currentBindingIndex = 0; 
#else
                        // @devnote: one accessor only for IRowset
                        currentBindingIndex++;
#endif 
                    }
                    if (0 < currentBindingIndex) { // when blob is not the last column 
                        bindingCount++; 
                    }
                } 
                else if (null != _irow) {
                    for (int i = 0; i < indexToBinding.Length; ++i) {
                        indexToBinding[i] = i;
                        indexWithinBinding[i] = 0; 
                    }
                    bindingCount = metadata.Length; 
                } 
            }
            else { 
                for (int i = 0; i < indexToBinding.Length; ++i) {
                    indexToBinding[i] = 0;
                    indexWithinBinding[i] = i;
                } 
                bindingCount = 1;
            } 
 
            Bindings bindings;
            Bindings[] dbbindings = new Bindings[bindingCount]; 
            bindingCount = 0;

            // for every column, build tagDBBinding info
            for (int index = 0; index < metadata.Length; ++index) { 
                Debug.Assert(indexToBinding[index] < dbbindings.Length, "bad indexToAccessor");
                bindings = dbbindings[indexToBinding[index]]; 
                if (null == bindings) { 
                    bindingCount = 0;
                    for (int i = index; (i < metadata.Length) && (bindingCount == indexWithinBinding[i]); ++i) { 
                        bindingCount++;
                    }
                    dbbindings[indexToBinding[index]] = bindings = new Bindings((OleDbDataReader)this, (null != _irowset), bindingCount);
 
                    // runningTotal is buffered to start values on 16-byte boundary
                    // the first columnCount * 8 bytes are for the length and status fields 
                    //bindings.DataBufferSize = (bindingCount + (bindingCount % 2)) * sizeof_int64; 
                }
                MetaData info = metadata[index]; 

                int maxLen = info.type.fixlen;
                short getType = info.type.wType;
 
                Debug.Assert(NativeDBType.STR != getType, "Should have bound as WSTR");
                Debug.Assert(!NativeDBType.HasHighBit(getType), "CreateAccessor - unexpected high bits on datatype"); 
 
                if (-1 != info.size) {
                    if (info.type.islong) { 
                        maxLen = ADP.PtrSize;
                        getType = (short)((ushort) getType | (ushort) NativeDBType.BYREF);
                    }
                    else if (-1 == maxLen) { 
                        // @devnote: not using provider owned memory for PDC, no one really supports it anyway.
                        /*if (((null != connection) && connection.PropertyGetProviderOwnedMemory()) 
                            || ((null != command) && command.Connection.PropertyGetProviderOwnedMemory())) { 
                            bindings.MemOwner = DBMemOwner.ProviderOwned;
 
                            bindings.MaxLen = ADP.PtrSize;
                            bindings.DbType = (short) (getType | DbType.BYREF);
                        }
                        else*/ 

                        if (ODB.LargeDataSize < info.size) { 
                            maxLen = ADP.PtrSize; 
                            getType = (short)((ushort) getType | (ushort)NativeDBType.BYREF);
                        } 
                        else if ((NativeDBType.WSTR == getType) && (-1 != info.size)) { // WebData 99298
                            maxLen = info.size * 2 + 2;
                        }
                        else { 
                            maxLen = info.size;
                        } 
                    } 
                }
                else if (maxLen < 0) { 
                    // if variable length and no defined size we require this to be byref at this time
                    /*if (((null != connection) && connection.PropertyGetProviderOwnedMemory())
                        || ((null != command) && command.Connection.PropertyGetProviderOwnedMemory())) {
                        bindings.MemOwner = DBMemOwner.ProviderOwned; 
                    }*/
                    maxLen = ADP.PtrSize; 
                    getType = (short)((ushort) getType | (ushort)NativeDBType.BYREF); 
                }
 
                currentBindingIndex = indexWithinBinding[index];
                bindings.CurrentIndex = currentBindingIndex;

                bindings.Ordinal      = info.ordinal; 
                bindings.Part         = info.type.dbPart;
                bindings.Precision    = (byte) info.precision; 
                bindings.Scale        = (byte) info.scale; 
                bindings.DbType       = (short) getType;
                bindings.MaxLen       = maxLen; // also increments databuffer size (uses DbType) 

              //bindings.ValueOffset  = // set via MaxLen
              //bindings.LengthOffset = // set via MaxLen
              //bindings.StatusOffset = // set via MaxLen 
              //bindings.TypeInfoPtr  = 0;
              //bindings.ObjectPtr    = 0; 
              //bindings.BindExtPtr   = 0; 
              //bindings.MemOwner     = /*DBMEMOWNER_CLIENTOWNED*/0;
              //bindings.ParamIO      = ODB.DBPARAMIO_NOTPARAM; 
              //bindings.Flags        = 0;

                if (Bid.AdvancedOn) {
                    Bid.Trace(" index=%d, columnName='%ls'\n", index, info.columnName);//, bindings.bindings[index]); 
                }
            } 
 
            int count = 0, indexStart = 0;
            for (int i = 0; i < dbbindings.Length; ++i) { 
                indexStart = dbbindings[i].AllocateForAccessor(this, indexStart, i);

                ColumnBinding[] columnBindings = dbbindings[i].ColumnBindings();
                for (int k = 0; k < columnBindings.Length; ++k) { 
                    Debug.Assert(count == columnBindings[k].Index, "column binding mismatch");
                    metadata[count].columnBinding = columnBindings[k]; 
                    metadata[count].bindings = dbbindings[i]; 
                    count++;
                } 
            }

            _bindings = dbbindings;
            return dbbindings; 
        }
 
        private void GetRowHandles(/*int skipCount*/) { 
            Debug.Assert(0 < (int)_rowHandleFetchCount, "GetRowHandles: bad _rowHandleFetchCount");
            Debug.Assert(!_isRead, "GetRowHandles: _isRead"); 

            OleDbHResult hr = 0;

            RowHandleBuffer rowHandleBuffer = _rowHandleNativeBuffer; 
            bool mustRelease = false;
 
            RuntimeHelpers.PrepareConstrainedRegions(); 
            try {
                rowHandleBuffer.DangerousAddRef(ref mustRelease); 

                IntPtr rowHandlesPtr = rowHandleBuffer.DangerousGetHandle();
                UnsafeNativeMethods.IRowset irowset = IRowset();
                try { 
                    Bid.Trace(" %d#, Chapter=%Id, RowsRequested=%Id\n", ObjectID, _chapterHandle.HChapter, _rowHandleFetchCount);
                    hr = irowset.GetNextRows(_chapterHandle.HChapter, /*skipCount*/IntPtr.Zero, _rowHandleFetchCount, out _rowFetchedCount, ref rowHandlesPtr); 
                    Bid.Trace(" %08X{HRESULT}, RowsObtained=%Id\n", hr, _rowFetchedCount); 
                    Debug.Assert(rowHandleBuffer.DangerousGetHandle() == rowHandlesPtr, "rowhandlebuffer changed");
                } 
                catch(System.InvalidCastException e) { // MDAC 64320
                    throw ODB.ThreadApartmentState(e);
                }
            } 
            finally {
                if (mustRelease) { 
                    rowHandleBuffer.DangerousRelease(); 
                }
            } 

            //if (/*DB_S_ROWLIMITEXCEEDED*/0x00040EC0 == hr) {
            //    _rowHandleFetchCount = 1;
            //    _isRead = true; 
            //} else
            if (hr < 0) { 
                // filter out the BadStartPosition due to the skipCount which 
                // maybe greater than the number of rows in the return rowset
                //const int /*OLEDB_Error.*/DB_E_BADSTARTPOSITION = unchecked((int)0x80040E1E); 
                //if (DB_E_BADSTARTPOSITION != hr)
                ProcessResults(hr);
            }
            _isRead = ((OleDbHResult.DB_S_ENDOFROWSET != hr) || (0 < (int)_rowFetchedCount)); // MDAC 59264 
            _rowFetchedCount = (IntPtr)Math.Max((int)_rowFetchedCount, 0);
        } 
 
        private void GetRowDataFromHandle() {
            Debug.Assert(null != _bindings, "GetRowDataFromHandle: null dbBindings"); 
            Debug.Assert(null != _rowHandleNativeBuffer, "GetRowDataFromHandle: null dbBindings");

            OleDbHResult hr = 0;
            UnsafeNativeMethods.IRowset irowset = IRowset(); 

            IntPtr rowHandle = _rowHandleNativeBuffer.GetRowHandle(_currentRow); 
 
            RowBinding rowBinding = _bindings[_nextAccessorForRetrieval].RowBinding();
            IntPtr accessorHandle = rowBinding.DangerousGetAccessorHandle(); 

            bool mustRelease = false;
            RuntimeHelpers.PrepareConstrainedRegions();
            try { 
                rowBinding.DangerousAddRef(ref mustRelease);
                rowBinding.StartDataBlock(); 
 
                IntPtr dataPtr = rowBinding.DangerousGetDataPtr();
 
                Bid.Trace(" %d#, RowHandle=%Id, AccessorHandle=%Id\n", ObjectID, rowHandle, accessorHandle);
                hr = irowset.GetData(rowHandle, accessorHandle, dataPtr);
                Bid.Trace(" %08X{HRESULT}\n", hr);
            } 
            finally {
                if (mustRelease) { 
                    rowBinding.DangerousRelease(); 
                }
            } 

            //if (AdapterSwitches.DataError.TraceWarning) {
            //    DBBindings binding = _dbBindings[i];
            //    for (int k = 0; k < binding.Count; ++k) { 
            //        binding.CurrentIndex = k;
            //        Debug.WriteLine("Status[" + k.ToString(CultureInfo.InvariantCulture) + "] = " + binding.StatusValue.ToString("G", CultureInfo.InvariantCulture)); 
            //    } 
            //}
 
            _nextAccessorForRetrieval++;
            if (hr < 0) {
                ProcessResults(hr);
            } 
        }
 
        private void ReleaseRowHandles() { 
            Debug.Assert(0 < (int)_rowFetchedCount, "invalid _rowFetchedCount");
 
            OleDbHResult hr;
            UnsafeNativeMethods.IRowset irowset = IRowset();

            Bid.Trace(" %d#, Request=%Id\n", ObjectID, _rowFetchedCount); 
            hr = irowset.ReleaseRows(_rowFetchedCount, _rowHandleNativeBuffer, ADP.PtrZero, ADP.PtrZero, ADP.PtrZero);
            Bid.Trace(" %08X{HRESULT}\n", hr); 
 
            if (hr < 0) {
                //ProcessFailure(hr); 
                //ProcessFailure(hr);
                SafeNativeMethods.Wrapper.ClearErrorInfo();
            }
            _rowFetchedCount = IntPtr.Zero; 
            _currentRow = 0;
            _isRead = false; // MDAC 59264 
        } 

        private object GetPropertyValue(int propertyId) { // MDAC 72106 
            if (null != _irowset) {
                return GetPropertyOnRowset(OleDbPropertySetGuid.Rowset, propertyId);
            }
            else if (null != _command) { 
                return _command.GetPropertyValue(OleDbPropertySetGuid.Rowset, propertyId);
            } 
            return OleDbPropertyStatus.NotSupported; 
        }
 
        private object GetPropertyOnRowset(Guid propertySet, int propertyID) {
            OleDbHResult hr;
            tagDBPROP[] dbprops;
            UnsafeNativeMethods.IRowsetInfo irowsetinfo = IRowsetInfo(); 

            using(PropertyIDSet propidset = new PropertyIDSet(propertySet, propertyID)) { 
 
                using(DBPropSet propset = new DBPropSet(irowsetinfo, propidset, out hr)) {
                    if (hr < 0) { 
                        // VSDD 621427: OLEDB Data Reader masks provider specific errors by raising "Internal .Net Framework Data Provider error 30."
                        // DBPropSet c-tor will register the exception and it will be raised at GetPropertySet call in case of failure
                        SafeNativeMethods.Wrapper.ClearErrorInfo();
                    } 
                    dbprops = propset.GetPropertySet(0, out propertySet);
                } 
            } 
            if (OleDbPropertyStatus.Ok == dbprops[0].dwStatus) {
                return dbprops[0].vValue; 
            }
            return dbprops[0].dwStatus;
        }
 
        private void GetRowValue() {
            Debug.Assert(null != _irow, "GetRowValue: null IRow"); 
            Debug.Assert(null != _metadata, "GetRowValue: null MetaData"); 

            Bindings bindings = _bindings[_nextAccessorForRetrieval]; 
            ColumnBinding[] columnBindings = bindings.ColumnBindings();
            RowBinding rowBinding = bindings.RowBinding();
            Debug.Assert(_nextValueForRetrieval <= columnBindings[0].Index, "backwards retrieval");
 
            bool mustReleaseBinding = false;
            bool[] mustRelease = new bool[columnBindings.Length]; 
            StringMemHandle[] sptr = new StringMemHandle[columnBindings.Length]; 

            RuntimeHelpers.PrepareConstrainedRegions(); 
            try {
                for (int i = 0; i < columnBindings.Length; ++i) {
                    bindings.CurrentIndex = i;
 
                    sptr[i] = null;
                    MetaData info = _metadata[columnBindings[i].Index]; 
                    if ((ODB.DBKIND_GUID_NAME == info.kind) || (ODB.DBKIND_NAME == info.kind)) { 
                        sptr[i] = new StringMemHandle(info.idname);
                        columnBindings[i]._sptr = sptr[i]; 
                    }

                    sptr[i].DangerousAddRef(ref mustRelease[i]);
 
                    IntPtr ulPropid = ((null != sptr[i]) ? sptr[i].DangerousGetHandle() : info.propid);
                    bindings.GuidKindName(info.guid, info.kind, ulPropid); 
                } 

                OleDbHResult hr; 
                tagDBCOLUMNACCESS[] access = bindings.DBColumnAccess;

                rowBinding.DangerousAddRef(ref mustReleaseBinding);
                rowBinding.StartDataBlock(); 

                UnsafeNativeMethods.IRow irow = IRow(); 
 
                Bid.Trace(" %d#\n", ObjectID);
                hr = irow.GetColumns((IntPtr)access.Length, access); 
                Bid.Trace(" %08X{HRESULT}\n", hr);
            }
            finally {
                if (mustReleaseBinding) { 
                    rowBinding.DangerousRelease();
                } 
                for (int i = 0; i < mustRelease.Length; i++) { 
                    if (mustRelease[i]) {
                        sptr[i].DangerousRelease(); 
                    }
                }
            }
            _nextAccessorForRetrieval++; 
        }
 
        private Int32 IndexOf(Hashtable hash, string name) { // MDAC 67385 
            // via case sensitive search, first match with lowest ordinal matches
            object index = hash[name]; 
            if (null != index) {
                return (int) index; // match via case-insensitive or by chance lowercase
            }
 
            // via case insensitive search, first match with lowest ordinal matches
            string tmp = name.ToLower(CultureInfo.InvariantCulture); 
            index = hash[tmp]; // match via lowercase 
            return ((null != index) ? (int) index : -1);
        } 

        private void AppendSchemaInfo() {
            Debug.Assert(null != _connection, "null connection");
            Debug.Assert(null != _metadata, "no _metadata"); 

            if (_metadata.Length <= 0) { 
                return; 
            }
 
            int keyCount = 0;
            for (int i = 0; i < _metadata.Length; ++i) {
                if (_metadata[i].isKeyColumn && !_metadata[i].isHidden) { // MDAC 90411
                    keyCount++; 
                }
            } 
            if (0 != keyCount) /*|| _connection.IsServer_msdaora || _connection.IsServer_Microsoft_SQL)*/ { // MDAC 60109 
                return;
            } 

            string schemaName, catalogName; // enforce single table
            string baseSchemaName = null, baseCatalogName = null, baseTableName = null;
            for (int i = 0; i < _metadata.Length; ++i) { 
                MetaData info = _metadata[i];
                if ((null != info.baseTableName) && (0 < info.baseTableName.Length)) { 
                    catalogName = ((null != info.baseCatalogName) ? info.baseCatalogName : ""); // MDAC 67249 
                    schemaName = ((null != info.baseSchemaName) ? info.baseSchemaName : "");
                    if (null == baseTableName) { 
                        baseSchemaName = schemaName;
                        baseCatalogName = catalogName;
                        baseTableName = info.baseTableName;
                    } 
                    else if ((0 != ADP.SrcCompare(baseTableName, info.baseTableName))
                            || (0 != ADP.SrcCompare(baseCatalogName, catalogName)) 
                            || (0 != ADP.SrcCompare(baseSchemaName, schemaName))) { // MDAC 71808 
#if DEBUG
                        if (AdapterSwitches.DataSchema.TraceVerbose) { 
                            Debug.WriteLine("Multiple BaseTableName detected:"
                                +" <"+baseCatalogName+"."+baseCatalogName+"."+baseTableName+">"
                                +" <"+info.baseCatalogName+"."+info.baseCatalogName+"."+info.baseTableName+">");
                        } 
#endif
                        baseTableName = null; 
                        break; 
                    }
                } 
            }
            if (null == baseTableName) {
                return;
            } 
            baseCatalogName = ADP.IsEmpty(baseCatalogName) ? null : baseCatalogName;
            baseSchemaName = ADP.IsEmpty(baseSchemaName) ? null : baseSchemaName; 
 
            if (null != _connection) { // MDAC 67394
                if (ODB.DBPROPVAL_IC_SENSITIVE == _connection.QuotedIdentifierCase()) { 
                    string p = null, s = null;
                    _connection.GetLiteralQuotes(ADP.GetSchemaTable, out s, out p);
                    if (null == s) {
                        s = ""; 
                    }
                    if (null == p) { 
                        p = ""; 
                    }
                    baseTableName = s + baseTableName + p; 
                }
            }

            Hashtable baseColumnNames = new Hashtable(_metadata.Length * 2); // MDAC 67385 

            for (int i = _metadata.Length-1; 0 <= i; --i) { 
                string basecolumname = _metadata[i].baseColumnName; 
                if (!ADP.IsEmpty(basecolumname)) {
                    baseColumnNames[basecolumname] = i; 
                }
            }
            for (int i = 0; i < _metadata.Length; ++i) {
                string basecolumname = _metadata[i].baseColumnName; 
                if (!ADP.IsEmpty(basecolumname)) {
                    basecolumname = basecolumname.ToLower(CultureInfo.InvariantCulture); 
                    if (!baseColumnNames.Contains(basecolumname)) { 
                        baseColumnNames[basecolumname] = i;
                    } 
                }
            }

            // look for primary keys in the table 
            if (_connection.SupportSchemaRowset(OleDbSchemaGuid.Primary_Keys)) {
                Object[] restrictions = new Object[] { baseCatalogName, baseSchemaName, baseTableName }; 
                keyCount = AppendSchemaPrimaryKey(baseColumnNames, restrictions); 
            }
            if (0 != keyCount) { 
                return;
            }

            // look for a single unique contraint that can be upgraded 
            if (_connection.SupportSchemaRowset(OleDbSchemaGuid.Indexes)) {
                Object[] restrictions = new Object[] { baseCatalogName, baseSchemaName, null, null, baseTableName }; 
                AppendSchemaUniqueIndexAsKey(baseColumnNames, restrictions); 
            }
        } 

        private int AppendSchemaPrimaryKey(Hashtable baseColumnNames, object[] restrictions) {
            int keyCount = 0;
            bool partialPrimaryKey = false; 
            DataTable table = null;
            try { 
                table = _connection.GetSchemaRowset(OleDbSchemaGuid.Primary_Keys, restrictions); 
            }
            catch(Exception e) { 
                //
                if (!ADP.IsCatchableExceptionType(e)) {
                    throw;
                } 

                ADP.TraceExceptionWithoutRethrow(e); 
            } 
            if (null != table) {
                DataColumnCollection dataColumns = table.Columns; 
                int nameColumnIndex = dataColumns.IndexOf(ODB.COLUMN_NAME);

                if (-1 != nameColumnIndex) {
                    DataColumn nameColumn = dataColumns[nameColumnIndex]; 
                    foreach(DataRow dataRow in table.Rows) {
                        string name = (string) dataRow[nameColumn, DataRowVersion.Default]; 
 
                        int metaindex = IndexOf(baseColumnNames, name); // MDAC 67385
                        if (0 <= metaindex) { 
                            MetaData info = _metadata[metaindex];
                            info.isKeyColumn = true;
                            info.flags &= ~ODB.DBCOLUMNFLAGS_ISNULLABLE;
                            keyCount++; 
                        }
                        else { 
#if DEBUG 
                            if (AdapterSwitches.DataSchema.TraceVerbose) {
                                Debug.WriteLine("PartialKeyColumn detected: <" + name + "> metaindex=" + metaindex); 
                            }
#endif
                            partialPrimaryKey = true;
                            break; 
                        }
                    } 
                } 
            }
            if (partialPrimaryKey) { // partial primary key detected 
                for (int i = 0; i < _metadata.Length; ++i) {
                    _metadata[i].isKeyColumn = false;
                }
                return -1; 
            }
            return keyCount; 
        } 

        private void AppendSchemaUniqueIndexAsKey(Hashtable baseColumnNames, object[] restrictions) { 
            bool partialPrimaryKey = false;
            DataTable table = null;
            try { // MDAC 66209
                table = _connection.GetSchemaRowset(OleDbSchemaGuid.Indexes, restrictions); 
            }
            catch(Exception e) { 
                // 
                if (!ADP.IsCatchableExceptionType(e)) {
                    throw; 
                }

                ADP.TraceExceptionWithoutRethrow(e);
            } 
            if (null != table) {
                DataColumnCollection dataColumns = table.Columns; 
 
                int indxIndex = dataColumns.IndexOf(ODB.INDEX_NAME);
                int pkeyIndex = dataColumns.IndexOf(ODB.PRIMARY_KEY); 
                int uniqIndex = dataColumns.IndexOf(ODB.UNIQUE);
                int nameIndex = dataColumns.IndexOf(ODB.COLUMN_NAME);
                int nullIndex = dataColumns.IndexOf(ODB.NULLS);
 
                if ((-1 != indxIndex) && (-1 != pkeyIndex) && (-1 != uniqIndex) && (-1 != nameIndex)) {
 
                    DataColumn indxColumn = dataColumns[indxIndex]; 
                    DataColumn pkeyColumn = dataColumns[pkeyIndex];
                    DataColumn uniqCOlumn = dataColumns[uniqIndex]; 
                    DataColumn nameColumn = dataColumns[nameIndex];
                    DataColumn nulls = ((-1 != nullIndex) ? dataColumns[nullIndex] : null);

                    bool[] keys = new bool[_metadata.Length]; 
                    bool[] uniq = new bool[_metadata.Length];
                    string uniqueIndexName = null; 
 
                    // match pkey name BaseColumnName
                    foreach(DataRow dataRow in table.Rows) { 

                        bool isPKey = (!dataRow.IsNull(pkeyColumn, DataRowVersion.Default) && (bool)dataRow[pkeyColumn, DataRowVersion.Default]);
                        bool isUniq = (!dataRow.IsNull(uniqCOlumn, DataRowVersion.Default) && (bool)dataRow[uniqCOlumn, DataRowVersion.Default]);
                        bool nullsVal = (null != nulls) && (dataRow.IsNull(nulls, DataRowVersion.Default) || (ODB.DBPROPVAL_IN_ALLOWNULL == Convert.ToInt32(dataRow[nulls, DataRowVersion.Default], CultureInfo.InvariantCulture))); 

                        if (isPKey || isUniq) { 
                            string name = (string) dataRow[nameColumn, DataRowVersion.Default]; 

                            int metaindex = IndexOf(baseColumnNames, name); // MDAC 67385 
                            if (0 <= metaindex) {
                                if (isPKey) {
                                    keys[metaindex] = true;
                                } 
                                if (isUniq && (null != uniq)) {
                                    uniq[metaindex] = true; 
 
                                    string indexname = (string) dataRow[indxColumn, DataRowVersion.Default];
                                    if (null == uniqueIndexName) { 
                                        uniqueIndexName = indexname;
                                    }
                                    else if (indexname != uniqueIndexName) {
#if DEBUG 
                                        if (AdapterSwitches.DataSchema.TraceVerbose) {
                                            Debug.WriteLine("MultipleUniqueIndexes detected: <" + uniqueIndexName + "> <" + indexname + ">"); 
                                        } 
#endif
                                        uniq = null; 
                                    }
                                }
                            }
                            else if (isPKey) { 
#if DEBUG
                                if (AdapterSwitches.DataSchema.TraceVerbose) { 
                                    Debug.WriteLine("PartialKeyColumn detected: " + name); 
                                }
#endif 
                                partialPrimaryKey = true;
                                break;
                            }
                            else if (null != uniqueIndexName) { 
                                string indexname = (string) dataRow[indxColumn, DataRowVersion.Default];
 
                                if (indexname != uniqueIndexName) { 
#if DEBUG
                                    if (AdapterSwitches.DataSchema.TraceVerbose) { 
                                        Debug.WriteLine("PartialUniqueIndexes detected: <" + uniqueIndexName + "> <" + indexname + ">");
                                    }
#endif
                                    uniq = null; 
                                }
                            } 
                        } 
                    }
                    if (partialPrimaryKey) { 
                        for (int i = 0; i < _metadata.Length; ++i) {
                            _metadata[i].isKeyColumn = false;
                        }
                        return; 
                    }
                    else if (null != uniq) { 
#if DEBUG 
                        if (AdapterSwitches.DataSchema.TraceVerbose) {
                            Debug.WriteLine("upgrade single unique index to be a key: <" + uniqueIndexName + ">"); 
                        }
#endif
                        // upgrade single unique index to be a key
                        for (int i = 0; i < _metadata.Length; ++i) { 
                            _metadata[i].isKeyColumn = uniq[i];
                        } 
                    } 
                }
            } 
        }

        private MetaData FindMetaData(string name) {
            int index = _fieldNameLookup.IndexOfName(name); 
            return ((-1 != index) ? _metadata[index] : null);
        } 
 
        internal void DumpToSchemaTable(UnsafeNativeMethods.IRowset rowset) {
            List metainfo = new List(); 

            object hiddenColumns = null;
            using (OleDbDataReader dataReader = new OleDbDataReader(_connection, _command, Int32.MinValue, 0)) {
                dataReader.InitializeIRowset(rowset, ChapterHandle.DB_NULL_HCHAPTER, IntPtr.Zero); 
                dataReader.BuildSchemaTableInfo(rowset, true, false);
 
                hiddenColumns = GetPropertyValue(ODB.DBPROP_HIDDENCOLUMNS); // MDAC 55611, 72106 
                if (0 == dataReader.FieldCount) {
                    return; 
                }

                Debug.Assert(null == dataReader._fieldNameLookup, "lookup already exists");
                FieldNameLookup lookup = new FieldNameLookup(dataReader, -1); 
                dataReader._fieldNameLookup = lookup;
 
                // This column, together with the DBCOLUMN_GUID and DBCOLUMN_PROPID 
                // columns, forms the ID of the column. One or more (but not all) of these columns
                // will be NULL, depending on which elements of the DBID structure the provider uses. 
                MetaData columnidname = dataReader.FindMetaData(ODB.DBCOLUMN_IDNAME);
                MetaData columnguid = dataReader.FindMetaData(ODB.DBCOLUMN_GUID);
                MetaData columnpropid = dataReader.FindMetaData(ODB.DBCOLUMN_PROPID);
 
                MetaData columnname = dataReader.FindMetaData(ODB.DBCOLUMN_NAME);
                MetaData columnordinal = dataReader.FindMetaData(ODB.DBCOLUMN_NUMBER); 
                MetaData dbtype = dataReader.FindMetaData(ODB.DBCOLUMN_TYPE); 
                MetaData columnsize = dataReader.FindMetaData(ODB.DBCOLUMN_COLUMNSIZE);
                MetaData numericprecision = dataReader.FindMetaData(ODB.DBCOLUMN_PRECISION); 
                MetaData numericscale = dataReader.FindMetaData(ODB.DBCOLUMN_SCALE);
                MetaData columnflags = dataReader.FindMetaData(ODB.DBCOLUMN_FLAGS);
                MetaData baseschemaname = dataReader.FindMetaData(ODB.DBCOLUMN_BASESCHEMANAME);
                MetaData basecatalogname = dataReader.FindMetaData(ODB.DBCOLUMN_BASECATALOGNAME); 
                MetaData basetablename = dataReader.FindMetaData(ODB.DBCOLUMN_BASETABLENAME);
                MetaData basecolumnname = dataReader.FindMetaData(ODB.DBCOLUMN_BASECOLUMNNAME); 
                MetaData isautoincrement = dataReader.FindMetaData(ODB.DBCOLUMN_ISAUTOINCREMENT); 
                MetaData isunique = dataReader.FindMetaData(ODB.DBCOLUMN_ISUNIQUE);
                MetaData iskeycolumn = dataReader.FindMetaData(ODB.DBCOLUMN_KEYCOLUMN); 

                // @devnote: because we want to use the DBACCESSOR_OPTIMIZED bit,
                // we are required to create the accessor before fetching any rows
                dataReader.CreateAccessors(false); 

                ColumnBinding binding; 
                while (dataReader.ReadRowset()) { 
                    dataReader.GetRowDataFromHandle();
 
                    MetaData info = new MetaData();

                    binding = columnidname.columnBinding; // MDAC 72627
                    if (!binding.IsValueNull()) { 
                        info.idname = (string)binding.Value();
                        info.kind = ODB.DBKIND_NAME; 
                    } 

                    binding = columnguid.columnBinding; 
                    if (!binding.IsValueNull()) {
                        info.guid = binding.Value_GUID();
                        info.kind = ((ODB.DBKIND_NAME == info.kind) ? ODB.DBKIND_GUID_NAME : ODB.DBKIND_GUID);
                    } 

                    binding = columnpropid.columnBinding; 
                    if (!binding.IsValueNull()) { 
                        info.propid = new IntPtr(binding.Value_UI4());
                        info.kind = ((ODB.DBKIND_GUID == info.kind) ? ODB.DBKIND_GUID_PROPID : ODB.DBKIND_PROPID); 
                    }

                    binding = columnname.columnBinding;
                    if (!binding.IsValueNull()) { 
                        info.columnName = (string)binding.Value();
                    } 
                    else { 
                        info.columnName = "";
                    } 

                    if (4 == ADP.PtrSize) {
                        info.ordinal = (IntPtr)columnordinal.columnBinding.Value_UI4();
                    } 
                    else {
                        info.ordinal = (IntPtr)columnordinal.columnBinding.Value_UI8(); 
                    } 
                    short wType = unchecked((short) dbtype.columnBinding.Value_UI2());
 
                    if (4 == ADP.PtrSize) {
                        info.size = unchecked((int) columnsize.columnBinding.Value_UI4()); // WebData 99298
                    }
                    else { 
                        info.size = ADP.IntPtrToInt32((IntPtr)unchecked((long)columnsize.columnBinding.Value_UI8()));
                    } 
 
                    binding = numericprecision.columnBinding;
                    if (!binding.IsValueNull()) { 
                        info.precision = (byte)binding.Value_UI2();
                    }

                    binding = numericscale.columnBinding; 
                    if (!binding.IsValueNull()) {
                        info.scale = (byte)binding.Value_I2(); 
                    } 

                    info.flags = unchecked((int) columnflags.columnBinding.Value_UI4()); 

                    bool islong = OleDbDataReader.IsLong(info.flags);
                    bool isfixed = OleDbDataReader.IsFixed(info.flags);
                    NativeDBType dbType = NativeDBType.FromDBType(wType, islong, isfixed); 

                    info.type = dbType; 
 
                    if (null != isautoincrement) {
                        binding = isautoincrement.columnBinding; 
                        if (!binding.IsValueNull()) {
                            info.isAutoIncrement = binding.Value_BOOL();
                        }
                    } 
                    if (null != isunique) {
                        binding = isunique.columnBinding; 
                        if (!binding.IsValueNull()) { 
                            info.isUnique = binding.Value_BOOL();
                        } 
                    }
                    if (null != iskeycolumn) {
                        binding = iskeycolumn.columnBinding;
                        if (!binding.IsValueNull()) { 
                            info.isKeyColumn = binding.Value_BOOL();
                        } 
                    } 
                    if (null != baseschemaname) {
                        binding = baseschemaname.columnBinding; 
                        if (!binding.IsValueNull()) {
                            info.baseSchemaName = binding.ValueString();
                        }
                    } 
                    if (null != basecatalogname) {
                        binding = basecatalogname.columnBinding; 
                        if (!binding.IsValueNull()) { 
                            info.baseCatalogName = binding.ValueString();
                        } 
                    }
                    if (null != basetablename) {
                        binding = basetablename.columnBinding;
                        if (!binding.IsValueNull()) { 
                            info.baseTableName = binding.ValueString();
                        } 
                    } 
                    if (null != basecolumnname) {
                        binding = basecolumnname.columnBinding; 
                        if (!binding.IsValueNull()) {
                            info.baseColumnName = binding.ValueString();
                        }
                    } 
                    metainfo.Add(info);
                } 
            } 

            int visibleCount = metainfo.Count; 
            if (hiddenColumns is Int32) {
                visibleCount -= (int)hiddenColumns;
            }
 
            // VSTFDevDiv 479578:
            //  if one key column is invalidated, they all need to be invalidated. The SET is the key, 
            //  and subsets likely are not accurate keys. Note the assumption that the two loops below 
            //  will traverse the entire set of columns.
            bool disallowKeyColumns = false; 

            for (int index = metainfo.Count - 1; visibleCount <= index; --index) {
                MetaData info = metainfo[index];
 
                info.isHidden = true;
 
                if (disallowKeyColumns) { 
                    info.isKeyColumn = false;
                } 
                else if (info.guid.Equals(ODB.DBCOL_SPECIALCOL)) { // MDAC 90827
                    info.isKeyColumn = false;

                    // This is the first key column to be invalidated, scan back through the 
                    //  columns we already processed to make sure none of those are marked as keys.
                    disallowKeyColumns = true; 
                    for (int index2 = metainfo.Count-1; index < index2; --index2) { 
                        metainfo[index2].isKeyColumn = false;
                    } 
                }
            }

            for (int index = visibleCount - 1; 0 <= index; --index) { 
                MetaData info = metainfo[index];
 
                if (disallowKeyColumns) { 
                    info.isKeyColumn = false;
                } 

                if (info.guid.Equals(ODB.DBCOL_SPECIALCOL)) { // MDAC 72390
#if DEBUG
                    if (AdapterSwitches.DataSchema.TraceVerbose) { 
                        Debug.WriteLine("Filtered Column: DBCOLUMN_GUID=DBCOL_SPECIALCOL DBCOLUMN_NAME=" + info.columnName + " DBCOLUMN_KEYCOLUMN=" + info.isKeyColumn);
                    } 
#endif 
                    info.isHidden = true;
                    visibleCount--; 
                }
#if WIN32
                else if (0 >= (int)info.ordinal) {
#else 
                else if (0 >= (long)info.ordinal) {
#endif 
#if DEBUG 
                    if (AdapterSwitches.DataSchema.TraceVerbose) {
                        Debug.WriteLine("Filtered Column: DBCOLUMN_NUMBER=" + info.ordinal.ToInt64().ToString(CultureInfo.InvariantCulture) + " DBCOLUMN_NAME=" + info.columnName); 
                    }
#endif
                    info.isHidden = true;
                    visibleCount--; 
                }
                else if (OleDbDataReader.DoColumnDropFilter(info.flags)) { 
#if DEBUG 
                    if (AdapterSwitches.DataSchema.TraceVerbose) {
                        Debug.WriteLine("Filtered Column: DBCOLUMN_FLAGS=" + info.flags.ToString("X8", (System.IFormatProvider)null) + " DBCOLUMN_NAME=" + info.columnName); 
                    }
#endif
                    info.isHidden = true;
                    visibleCount--; 
                }
            } 
 
            //
            metainfo.Sort(); // MDAC 68319 
            _visibleFieldCount = visibleCount;
            _metadata = metainfo.ToArray();
        }
 
        static internal void GenerateSchemaTable(OleDbDataReader dataReader, object handle, CommandBehavior behavior) {
            if (0 != (CommandBehavior.KeyInfo & behavior)) { 
                dataReader.BuildSchemaTableRowset(handle); // tries IColumnsRowset first then IColumnsInfo 
                dataReader.AppendSchemaInfo();
            } 
            else {
                dataReader.BuildSchemaTableInfo(handle, false, false); // only tries IColumnsInfo
            }
            MetaData[] metadata = dataReader.MetaData; 
            if ((null != metadata) && (0 < metadata.Length)) {
                dataReader.BuildSchemaTable(metadata); 
            } 
        }
 
        static private bool DoColumnDropFilter(int flags) {
            return (0 != (ODB.DBCOLUMNFLAGS_ISBOOKMARK & flags));
        }
        static private bool IsLong(int flags) { 
            return (0 != (ODB.DBCOLUMNFLAGS_ISLONG & flags));
        } 
        static private bool IsFixed(int flags) { 
            return (0 != (ODB.DBCOLUMNFLAGS_ISFIXEDLENGTH & flags));
        } 
        static private bool IsRowVersion(int flags) {
            return (0 != (ODB.DBCOLUMNFLAGS_ISROWID_DBCOLUMNFLAGS_ISROWVER & flags));
        }
        static private bool AllowDBNull(int flags) { 
            return (0 != (ODB.DBCOLUMNFLAGS_ISNULLABLE & flags));
        } 
        static private bool AllowDBNullMaybeNull(int flags) { 
            return (0 != (ODB.DBCOLUMNFLAGS_ISNULLABLE_DBCOLUMNFLAGS_MAYBENULL & flags));
        } 
        static private bool IsReadOnly(int flags) {
            return (0 == (ODB.DBCOLUMNFLAGS_WRITE_DBCOLUMNFLAGS_WRITEUNKNOWN & flags));
        }
    } 

    sealed internal class MetaData : IComparable { 
 
        internal Bindings bindings;
        internal ColumnBinding columnBinding; 

        internal string columnName;

        internal Guid guid; // MDAC 72627 
        internal int kind;
        internal IntPtr propid; 
        internal string idname; 

        internal NativeDBType type; 

        internal IntPtr ordinal;
        internal int size;
 
        internal int flags;
 
        internal byte precision; 
        internal byte scale;
 
        internal bool isAutoIncrement;
        internal bool isUnique;
        internal bool isKeyColumn;
        internal bool isHidden; 

        internal string baseSchemaName; 
        internal string baseCatalogName; 
        internal string baseTableName;
        internal string baseColumnName; 

        int IComparable.CompareTo(object obj) { // MDAC 68319
            if (isHidden == (obj as MetaData).isHidden) {
#if WIN32 
                return ((int)ordinal - (int)(obj as MetaData).ordinal);
#else 
                long v = ((long)ordinal - (long)(obj as MetaData).ordinal); 
                return ((0 < v) ? 1 : ((v < 0) ? -1 : 0));
#endif 

            }
            return (isHidden) ? 1 : -1; // ensure that all hidden columns come after non-hidden columns
        } 

        internal MetaData() { 
        } 
    }
} 

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