1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150
|
//------------------------------------------------------------------------------
// <copyright file="DbDataRecord.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
// <owner current="true" primary="true">Microsoft</owner>
// <owner current="true" primary="false">Microsoft</owner>
//------------------------------------------------------------------------------
using System;
using System.ComponentModel; //Component
using System.Data;
using System.Runtime.InteropServices; //Marshal
using System.Reflection; //Missing
namespace System.Data.Odbc {
sealed internal class DbSchemaInfo {
internal DbSchemaInfo() {
}
internal string _name;
internal string _typename;
internal Type _type;
internal ODBC32.SQL_TYPE? _dbtype;
internal object _scale;
internal object _precision;
// extension to allow BindCol
//
internal int _columnlength; //
internal int _valueOffset; // offset to the data in the row buffer
internal int _lengthOffset; // offset to the length in the row buffer
internal ODBC32.SQL_C _sqlctype; // need this to bind the value
internal ODBC32.SQL_TYPE _sql_type; // need that to properly marshal the value
}
/////////////////////////////////////////////////////////////////////////////
// Cache
//
// This is a on-demand cache, only caching what the user requests.
// The reational is that for ForwardOnly access (the default and LCD of drivers)
// we cannot obtain the data more than once, and even GetData(0) (to determine is-null)
// still obtains data for fixed lenght types.
// So simple code like:
// if(!rReader.IsDBNull(i))
// rReader.GetInt32(i)
//
// Would fail, unless we cache on the IsDBNull call, and return the cached
// item for GetInt32. This actually improves perf anyway, (even if the driver could
// support it), since we are not making a seperate interop call...
// We do not cache all columns, so reading out of order is still not
//
/////////////////////////////////////////////////////////////////////////////
sealed internal class DbCache {
//Data
private bool[] _isBadValue;
private DbSchemaInfo[] _schema;
private object[] _values;
private OdbcDataReader _record;
internal int _count;
internal bool _randomaccess = true;
//Constructor
internal DbCache(OdbcDataReader record, int count) {
_count = count;
_record = record;
_randomaccess = (!record.IsBehavior(CommandBehavior.SequentialAccess));
_values = new object[count];
_isBadValue = new bool[count];
}
//Accessor
internal object this[int i] {
get {
if(_isBadValue[i]) {
OverflowException innerException = (OverflowException)Values[i];
throw new OverflowException(innerException.Message, innerException);
}
return Values[i];
}
set {
Values[i] = value;
_isBadValue[i] = false;
}
}
internal int Count {
get {
return _count;
}
}
internal void InvalidateValue(int i) {
_isBadValue[i] = true;
}
internal object[] Values {
get {
return _values;
}
}
internal object AccessIndex(int i) {
//Note: We could put this directly in this[i], instead of having an explicit overload.
//However that means that EVERY access into the cache takes the hit of checking, so
//something as simple as the following code would take two hits. It's nice not to
//have to take the hit when you know what your doing.
//
// if(cache[i] == null)
// ....
// return cache[i];
object[] values = this.Values;
if(_randomaccess) {
//Random
//Means that the user can ask for the values int any order (ie: out of order).
// In order to acheive this on a forward only stream, we need to actually
// retreive all the value in between so they can go back to values they've skipped
for(int c = 0; c < i; c++) {
if(values[c] == null) {
values[c] = _record.GetValue(c);
}
}
}
return values[i];
}
internal DbSchemaInfo GetSchema(int i) {
if(_schema == null) {
_schema = new DbSchemaInfo[Count];
}
if(_schema[i] == null) {
_schema[i] = new DbSchemaInfo();
}
return _schema[i];
}
internal void FlushValues() {
//Set all objects to null (to explcitly release them)
//Note: SchemaInfo remains the same for all rows - no need to reget those...
int count = _values.Length;
for(int i = 0; i < count; ++i) {
_values[i] = null;
}
}
}
}
|