Update Reference Sources to .NET Framework 4.6.1
[mono.git] / mcs / class / referencesource / System.Data / System / Data / OleDb / DBBindings.cs
1 //------------------------------------------------------------------------------
2 // <copyright file="DBBindings.cs" company="Microsoft">
3 //      Copyright (c) Microsoft Corporation.  All rights reserved.
4 // </copyright>
5 // <owner current="true" primary="true">[....]</owner>
6 // <owner current="true" primary="false">[....]</owner>
7 //------------------------------------------------------------------------------
8
9 namespace System.Data.OleDb {
10
11     using System;
12     using System.ComponentModel;
13     using System.Diagnostics;
14     using System.Data;
15     using System.Data.Common;
16     using System.Globalization;
17     using System.Runtime.InteropServices;
18     using System.Security;
19     using System.Security.Permissions;
20     using System.Text;
21     using System.Threading;
22
23     sealed internal class Bindings {
24
25         private readonly tagDBPARAMBINDINFO[] _bindInfo;
26         private readonly tagDBBINDING[] _dbbindings;
27         private readonly tagDBCOLUMNACCESS[] _dbcolumns;
28
29         private OleDbParameter[] _parameters;
30         private int _collectionChangeID;
31
32         private OleDbDataReader _dataReader;
33         private ColumnBinding[] _columnBindings;
34         private RowBinding _rowBinding;
35
36         private int _index;
37         private int _count;
38         private int _dataBufferSize;
39         private bool _ifIRowsetElseIRow;
40         private bool _forceRebind;
41         private bool _needToReset;
42
43         private Bindings(int count) {
44             _count = count;
45
46              _dbbindings = new tagDBBINDING[count];
47             for(int i = 0;i < _dbbindings.Length;++i) {
48                 _dbbindings[i] = new tagDBBINDING();
49             }
50             _dbcolumns = new tagDBCOLUMNACCESS[count];
51         }
52
53         internal Bindings(OleDbParameter[] parameters, int collectionChangeID) : this(parameters.Length) {
54             _bindInfo = new tagDBPARAMBINDINFO[parameters.Length];            
55             _parameters = parameters;
56             _collectionChangeID = collectionChangeID;
57             _ifIRowsetElseIRow = true;
58         }
59
60         internal Bindings(OleDbDataReader dataReader, bool ifIRowsetElseIRow, int count) : this(count) {
61             _dataReader = dataReader;
62             _ifIRowsetElseIRow = ifIRowsetElseIRow;
63         }
64
65         internal tagDBPARAMBINDINFO[] BindInfo {
66             get { return _bindInfo; }
67         }
68         internal tagDBCOLUMNACCESS[] DBColumnAccess {
69             get { return _dbcolumns; }
70         }
71
72         internal int CurrentIndex {
73             //get { return _index; }
74             set {
75                 Debug.Assert((0 <= value) &&  (value < _count), "bad binding index");
76                 _index = value;
77             }
78         }
79
80         internal ColumnBinding[] ColumnBindings() {
81             Debug.Assert(null != _columnBindings, "null ColumnBindings");
82             return _columnBindings;
83         }
84
85         internal OleDbParameter[] Parameters() {
86             Debug.Assert(null != _parameters, "null Parameters");
87             return _parameters;
88         }
89
90         internal RowBinding RowBinding() {
91             //Debug.Assert(null != _rowBinding, "null RowBinding");
92             return _rowBinding;
93         }
94
95         internal bool ForceRebind {
96             get { return _forceRebind; }
97             set { _forceRebind = value; }
98         }
99
100         // tagDBPARAMBINDINFO member access
101         internal IntPtr DataSourceType {
102             //get { return _bindInfo[_index].pwszDataSourceType; }
103             set {
104                 _bindInfo[_index].pwszDataSourceType = value;
105             }
106         }
107         internal IntPtr Name {
108             //get { return _bindInfo[_index].pwszName; }
109             set {
110                 _bindInfo[_index].pwszName= value;
111             }
112         }
113         internal IntPtr ParamSize {
114             get {
115                 if (null != _bindInfo) {
116                     return _bindInfo[_index].ulParamSize;
117                 }
118                 return IntPtr.Zero;
119             }
120             set {
121                 _bindInfo[_index].ulParamSize= value;
122             }
123         }
124         internal int Flags {
125             //get { return _bindInfo[_index].dwFlag; }
126             set {
127                 _bindInfo[_index].dwFlags= value;
128             }
129         }
130         
131         // tagDBBINDING member access
132         //
133         internal IntPtr Ordinal { // iOrdinal
134             //get { return _dbbindings[_index].iOrdinal.ToInt32(); }
135             set {
136                 _dbbindings[_index].iOrdinal = value;
137             }
138         }
139 #if DEBUG
140         /*internal int ValueOffset { // obValue
141             get { return _dbbindings[_index].obValue.ToInt32(); }
142         }
143         internal int LengthOffset { // obLength
144             get { return _dbbindings[_index].obLength.ToInt32(); }
145         }
146         internal int StatusOffset { // obStatus
147             get { return _dbbindings[_index].obStatus.ToInt32(); }
148         }*/
149 #endif
150         internal int Part { // dwPart
151 #if DEBUG
152             //get { return _dbbindings[_index].dwPart; }
153 #endif
154             set { _dbbindings[_index].dwPart = value; }
155         }
156         internal int ParamIO { // eParamIO
157 #if DEBUG
158             //get { return _dbbindings[_index].eParamIO; }
159 #endif
160             set { _dbbindings[_index].eParamIO = value; }
161         }
162         internal int MaxLen { // cbMaxLen
163             //get { return (int) _dbbindings[_index].cbMaxLen; }
164             set {
165                 Debug.Assert(0 <= value, "invalid MaxLen");
166
167                 _dbbindings[_index].obStatus = (IntPtr) (_dataBufferSize +  0);
168                 _dbbindings[_index].obLength = (IntPtr) (_dataBufferSize +  ADP.PtrSize);
169                 _dbbindings[_index].obValue  = (IntPtr) (_dataBufferSize +  ADP.PtrSize + ADP.PtrSize);
170                 _dataBufferSize += ADP.PtrSize + ADP.PtrSize;
171
172                 switch(DbType) {
173                 case (NativeDBType.BSTR):  // ADP.PtrSize
174                 case (NativeDBType.HCHAPTER): // ADP.PtrSize
175                 case (NativeDBType.PROPVARIANT): // sizeof(PROPVARIANT)
176                 case (NativeDBType.VARIANT): // 16 or 24 (8 + ADP.PtrSize *2)
177                 case (NativeDBType.BYREF | NativeDBType.BYTES): // ADP.PtrSize
178                 case (NativeDBType.BYREF | NativeDBType.WSTR): // ADP.PtrSize
179                     // allocate extra space to cache original value for disposal
180                     _dataBufferSize += System.Data.OleDb.RowBinding.AlignDataSize(value*2);
181                     _needToReset = true;
182                     break;
183                 default:
184                     _dataBufferSize += System.Data.OleDb.RowBinding.AlignDataSize(value);
185                     break;
186                 }
187
188                 _dbbindings[_index].cbMaxLen = (IntPtr)value;
189                 _dbcolumns[_index].cbMaxLen = (IntPtr)value;
190             }
191         }
192         internal int DbType { // wType
193             get { return _dbbindings[_index].wType; }
194             set {
195                 _dbbindings[_index].wType = (short) value;
196                 _dbcolumns[_index].wType = (short) value;
197             }
198         }
199         internal byte Precision { // bPrecision
200 #if DEBUG
201             //get { return _dbbindings[_index].bPrecision; }
202
203 #endif
204             set {
205                 if (null != _bindInfo) {
206                     _bindInfo[_index].bPrecision = value;
207                 }
208                 _dbbindings[_index].bPrecision = value;
209                 _dbcolumns[_index].bPrecision = value;
210             }
211         }
212         internal byte Scale { // bScale
213 #if DEBUG
214             //get { return _dbbindings[_index].bScale; }
215 #endif
216             set {
217                 if (null != _bindInfo) {
218                     _bindInfo[_index].bScale = value;
219                 }
220                 _dbbindings[_index].bScale = value;
221                 _dbcolumns[_index].bScale = value;
222             }
223         }
224
225         internal int AllocateForAccessor(OleDbDataReader dataReader, int indexStart, int indexForAccessor) {
226             Debug.Assert(null == _rowBinding, "row binding already allocated");
227             Debug.Assert(null == _columnBindings, "column bindings already allocated");
228
229             RowBinding rowBinding = System.Data.OleDb.RowBinding.CreateBuffer(_count, _dataBufferSize, _needToReset);
230             _rowBinding = rowBinding;
231
232             ColumnBinding[] columnBindings = rowBinding.SetBindings(dataReader, this, indexStart, indexForAccessor, _parameters, _dbbindings, _ifIRowsetElseIRow);
233             Debug.Assert(null != columnBindings, "null column bindings");
234             _columnBindings = columnBindings;
235
236             if (!_ifIRowsetElseIRow) {
237                 Debug.Assert(columnBindings.Length == _dbcolumns.Length, "length mismatch");
238                 for(int i = 0; i < columnBindings.Length; ++i) { // WebData 94427
239                     _dbcolumns[i].pData = rowBinding.DangerousGetDataPtr(columnBindings[i].ValueOffset); // We are simply pointing at a location later in the buffer, so we're OK to not addref the buffer.
240                 }
241             }
242
243 #if DEBUG
244             int index = -1;
245             foreach(ColumnBinding binding in columnBindings) {
246                 Debug.Assert(index < binding.Index, "invaild index");
247                 index = binding.Index;
248             }
249 #endif
250             return (indexStart + columnBindings.Length);
251         }
252
253
254         internal void ApplyInputParameters() {
255             ColumnBinding[] columnBindings = this.ColumnBindings();
256             OleDbParameter[] parameters = this.Parameters();
257
258             RowBinding().StartDataBlock();
259             for(int i = 0; i < parameters.Length; ++i) {
260                 if (ADP.IsDirection(parameters[i], ParameterDirection.Input)) {
261                     columnBindings[i].SetOffset(parameters[i].Offset); // MDAC 80657
262                     columnBindings[i].Value(parameters[i].GetCoercedValue());
263                 }
264                 else {
265                     // always set ouput only and return value parameter values to null when executing
266                     parameters[i].Value = null;
267
268                     //columnBindings[i].SetValueEmpty(); // webdata 115079
269                 }
270             }
271         }
272
273         internal void ApplyOutputParameters() {
274             ColumnBinding[] columnBindings = this.ColumnBindings();
275             OleDbParameter[] parameters = this.Parameters();
276
277             for(int i = 0; i < parameters.Length; ++i) {
278                 if (ADP.IsDirection(parameters[i], ParameterDirection.Output)) {
279                     parameters[i].Value = columnBindings[i].Value();
280                 }
281             }
282             CleanupBindings();
283         }
284
285         internal bool AreParameterBindingsInvalid(OleDbParameterCollection collection) {
286             Debug.Assert(null != collection, "null parameter collection");
287             Debug.Assert(null != _parameters, "null parameters");
288
289             ColumnBinding[] columnBindings = this.ColumnBindings();
290             if (!ForceRebind && ((collection.ChangeID == _collectionChangeID) && (_parameters.Length == collection.Count))) {
291                 for(int i = 0; i < columnBindings.Length; ++i) {
292                     ColumnBinding binding = columnBindings[i];
293
294                     Debug.Assert(null != binding, "null column binding");
295                     Debug.Assert(binding.Parameter() == _parameters[i], "parameter mismatch");
296                     if (binding.IsParameterBindingInvalid(collection[i])) {
297                         //Debug.WriteLine("ParameterBindingsInvalid");
298                         return true;
299                     }
300                 }
301                 //Debug.WriteLine("ParameterBindingsValid");
302                 return false; // collection and cached values are the same
303             }
304             //Debug.WriteLine("ParameterBindingsInvalid");
305             return true;
306         }
307
308         internal void CleanupBindings() {
309             RowBinding rowBinding = this.RowBinding();
310             if (null != rowBinding) {
311                 rowBinding.ResetValues();
312
313                 ColumnBinding[] columnBindings = this.ColumnBindings();
314                 for(int i = 0; i < columnBindings.Length; ++i) {
315                     ColumnBinding binding = columnBindings[i];
316                     if (null != binding) {
317                         binding.ResetValue();
318                     }
319                 }
320             }
321         }
322
323         internal void CloseFromConnection() {
324             if (null != _rowBinding) {
325                 _rowBinding.CloseFromConnection();
326             }
327             Dispose();            
328         }
329
330         internal OleDbHResult CreateAccessor(UnsafeNativeMethods.IAccessor iaccessor, int flags) {
331             Debug.Assert(null != _rowBinding, "no row binding");
332             Debug.Assert(null != _columnBindings, "no column bindings");
333             return _rowBinding.CreateAccessor(iaccessor, flags, _columnBindings);
334         }
335
336         public void Dispose() {
337             _parameters = null;
338             _dataReader = null;
339             _columnBindings = null;
340
341             RowBinding rowBinding = _rowBinding;
342             _rowBinding = null;
343             if (null != rowBinding) {
344                 rowBinding.Dispose();
345             }
346         }
347
348         internal void GuidKindName(Guid guid, int eKind, IntPtr propid) {
349             tagDBCOLUMNACCESS[] dbcolumns = DBColumnAccess;
350             dbcolumns[_index].columnid.uGuid = guid;
351             dbcolumns[_index].columnid.eKind = eKind;
352             dbcolumns[_index].columnid.ulPropid = propid;
353         }
354
355         internal void ParameterStatus(StringBuilder builder) {
356             ColumnBinding[] columnBindings = ColumnBindings();
357             for(int i = 0; i < columnBindings.Length; ++i) {
358                 ODB.CommandParameterStatus(builder, i, columnBindings[i].StatusValue());
359             }
360         }
361     }
362 }
363