ea81451b667acc2dad6acbe4493254cde3fedcae
[mono.git] / mcs / class / referencesource / System.Data / System / Data / Odbc / DbDataRecord.cs
1 //------------------------------------------------------------------------------
2 // <copyright file="DbDataRecord.cs" company="Microsoft">
3 //      Copyright (c) Microsoft Corporation.  All rights reserved.
4 // </copyright>
5 // <owner current="true" primary="true">Microsoft</owner>
6 // <owner current="true" primary="false">Microsoft</owner>
7 //------------------------------------------------------------------------------
8
9 using System;
10 using System.ComponentModel;            //Component
11 using System.Data;
12 using System.Runtime.InteropServices;   //Marshal
13 using System.Reflection;                //Missing
14
15 namespace System.Data.Odbc {
16     sealed internal class DbSchemaInfo {
17
18         internal DbSchemaInfo() {
19         }
20
21         internal string _name;
22         internal string _typename;
23         internal Type _type;
24         internal ODBC32.SQL_TYPE? _dbtype;
25         internal object _scale;
26         internal object _precision;
27
28         // extension to allow BindCol
29         //
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
35     }
36
37     /////////////////////////////////////////////////////////////////////////////
38     // Cache
39     //
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.
44
45     //  So simple code like:
46     //      if(!rReader.IsDBNull(i))
47     //          rReader.GetInt32(i)
48     //
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...
52
53     //  We do not cache all columns, so reading out of order is still not
54     //
55     /////////////////////////////////////////////////////////////////////////////
56     sealed internal class DbCache {
57         //Data
58
59         private bool[] _isBadValue;
60         private DbSchemaInfo[] _schema;
61         private object[] _values;
62         private OdbcDataReader _record;
63         internal int _count;
64         internal bool _randomaccess = true;
65
66         //Constructor
67         internal DbCache(OdbcDataReader record, int count) {
68             _count = count;
69             _record = record;
70             _randomaccess = (!record.IsBehavior(CommandBehavior.SequentialAccess));
71             _values = new object[count];
72             _isBadValue = new bool[count];
73         }
74
75         //Accessor
76         internal object this[int i] {
77             get {
78                 if(_isBadValue[i]) {
79                     OverflowException innerException = (OverflowException)Values[i];
80                     throw new OverflowException(innerException.Message, innerException);
81                 }
82                 return Values[i];
83             }
84             set {
85                 Values[i] = value;
86                 _isBadValue[i] = false;
87             }
88         }
89
90         internal int Count {
91             get {
92                 return _count;
93             }
94         }
95
96         internal void InvalidateValue(int i) {
97             _isBadValue[i] = true;
98         }
99
100         internal object[] Values {
101             get {
102                 return _values;
103             }
104         }
105
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.
111             //
112             //  if(cache[i] == null)
113             //      ....
114             //  return cache[i];
115
116             object[] values = this.Values;
117             if(_randomaccess) {
118                 //Random
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);
125                     }
126                 }
127             }
128             return values[i];
129         }
130
131         internal DbSchemaInfo GetSchema(int i) {
132             if(_schema == null) {
133                 _schema = new DbSchemaInfo[Count];
134             }
135             if(_schema[i] == null) {
136                 _schema[i] = new DbSchemaInfo();
137             }
138             return _schema[i];
139         }
140
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) {
146                 _values[i] = null;
147             }
148         }
149     }
150 }