1 //------------------------------------------------------------------------------
2 // <copyright file="DbDataRecord.cs" company="Microsoft">
3 // Copyright (c) Microsoft Corporation. All rights reserved.
5 // <owner current="true" primary="true">Microsoft</owner>
6 // <owner current="true" primary="false">Microsoft</owner>
7 //------------------------------------------------------------------------------
10 using System.ComponentModel; //Component
12 using System.Runtime.InteropServices; //Marshal
13 using System.Reflection; //Missing
15 namespace System.Data.Odbc {
16 sealed internal class DbSchemaInfo {
18 internal DbSchemaInfo() {
21 internal string _name;
22 internal string _typename;
24 internal ODBC32.SQL_TYPE? _dbtype;
25 internal object _scale;
26 internal object _precision;
28 // extension to allow BindCol
30 internal int _columnlength; //
31 internal int _valueOffset; // offset to the data in the row buffer
32 internal int _lengthOffset; // offset to the length in the row buffer
33 internal ODBC32.SQL_C _sqlctype; // need this to bind the value
34 internal ODBC32.SQL_TYPE _sql_type; // need that to properly marshal the value
37 /////////////////////////////////////////////////////////////////////////////
40 // This is a on-demand cache, only caching what the user requests.
41 // The reational is that for ForwardOnly access (the default and LCD of drivers)
42 // we cannot obtain the data more than once, and even GetData(0) (to determine is-null)
43 // still obtains data for fixed lenght types.
45 // So simple code like:
46 // if(!rReader.IsDBNull(i))
47 // rReader.GetInt32(i)
49 // Would fail, unless we cache on the IsDBNull call, and return the cached
50 // item for GetInt32. This actually improves perf anyway, (even if the driver could
51 // support it), since we are not making a seperate interop call...
53 // We do not cache all columns, so reading out of order is still not
55 /////////////////////////////////////////////////////////////////////////////
56 sealed internal class DbCache {
59 private bool[] _isBadValue;
60 private DbSchemaInfo[] _schema;
61 private object[] _values;
62 private OdbcDataReader _record;
64 internal bool _randomaccess = true;
67 internal DbCache(OdbcDataReader record, int count) {
70 _randomaccess = (!record.IsBehavior(CommandBehavior.SequentialAccess));
71 _values = new object[count];
72 _isBadValue = new bool[count];
76 internal object this[int i] {
79 OverflowException innerException = (OverflowException)Values[i];
80 throw new OverflowException(innerException.Message, innerException);
86 _isBadValue[i] = false;
96 internal void InvalidateValue(int i) {
97 _isBadValue[i] = true;
100 internal object[] Values {
106 internal object AccessIndex(int i) {
107 //Note: We could put this directly in this[i], instead of having an explicit overload.
108 //However that means that EVERY access into the cache takes the hit of checking, so
109 //something as simple as the following code would take two hits. It's nice not to
110 //have to take the hit when you know what your doing.
112 // if(cache[i] == null)
116 object[] values = this.Values;
119 //Means that the user can ask for the values int any order (ie: out of order).
120 // In order to acheive this on a forward only stream, we need to actually
121 // retreive all the value in between so they can go back to values they've skipped
122 for(int c = 0; c < i; c++) {
123 if(values[c] == null) {
124 values[c] = _record.GetValue(c);
131 internal DbSchemaInfo GetSchema(int i) {
132 if(_schema == null) {
133 _schema = new DbSchemaInfo[Count];
135 if(_schema[i] == null) {
136 _schema[i] = new DbSchemaInfo();
141 internal void FlushValues() {
142 //Set all objects to null (to explcitly release them)
143 //Note: SchemaInfo remains the same for all rows - no need to reget those...
144 int count = _values.Length;
145 for(int i = 0; i < count; ++i) {