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;
        }
        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;
        }
        // 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;
        }
        internal void DumpToSchemaTable(UnsafeNativeMethods.IRowset rowset) {
            List<MetaData> metainfo = new List<MetaData>();

            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();
        }