Updates referencesource to .NET 4.7
[mono.git] / mcs / class / referencesource / System.Data / System / Data / OleDb / RowBinding.cs
1 //------------------------------------------------------------------------------
2 // <copyright file="RowBinding.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 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.CompilerServices;
18     using System.Runtime.InteropServices;
19     using System.Security;
20     using System.Security.Permissions;
21     using System.Text;
22     using System.Threading;
23     using System.Runtime.ConstrainedExecution;
24
25     sealed internal class RowBinding : System.Data.ProviderBase.DbBuffer {
26         private readonly int _bindingCount;
27         private readonly int _headerLength;
28         private readonly int _dataLength;
29         private readonly int _emptyStringOffset;
30
31         private UnsafeNativeMethods.IAccessor _iaccessor;
32         private IntPtr _accessorHandle;
33
34         private readonly bool _needToReset;
35         private bool _haveData;
36
37         // tagDBBINDING[] starting 64bit aligned
38         // all DBSTATUS values (32bit per value), starting 64bit aligned
39         // all DBLENGTH values (32/64bit per value), starting 64bit alignedsa
40         // all data values listed after that (variable length), each individual starting 64bit aligned
41         // Int64 - zero for pointers to emptystring
42
43         internal static RowBinding CreateBuffer(int bindingCount, int databuffersize, bool needToReset) {
44             int headerLength = RowBinding.AlignDataSize(bindingCount * ODB.SizeOf_tagDBBINDING);
45             int length = RowBinding.AlignDataSize(headerLength + databuffersize) + 8; // 8 bytes for a null terminated string
46             return new RowBinding(bindingCount, headerLength, databuffersize, length, needToReset);
47         }
48
49         private RowBinding(int bindingCount, int headerLength, int dataLength, int length, bool needToReset) : base(length) {
50             _bindingCount = bindingCount;
51             _headerLength = headerLength;
52             _dataLength = dataLength;
53             _emptyStringOffset = length - 8; // 8 bytes for a null terminated string
54             _needToReset = needToReset;
55
56             Debug.Assert(0 < _bindingCount, "bad _bindingCount");
57             Debug.Assert(0 < _headerLength, "bad _headerLength");
58             Debug.Assert(0 < _dataLength, "bad _dataLength");
59             Debug.Assert(_bindingCount * 3 * IntPtr.Size <= _dataLength, "_dataLength too small");
60             Debug.Assert(_headerLength + _dataLength <= _emptyStringOffset, "bad string offset");
61             Debug.Assert(_headerLength + _dataLength + 8 <= length, "bad length");
62         }
63
64         internal void StartDataBlock() {
65             if (_haveData) {
66                 Debug.Assert(false, "previous row not yet cleared");
67                 ResetValues();
68             }
69             _haveData = true;
70         }
71
72         internal int BindingCount() {
73             return _bindingCount;
74         }
75
76         internal IntPtr DangerousGetAccessorHandle() {
77             return _accessorHandle;
78         }
79
80         internal IntPtr DangerousGetDataPtr() {
81             //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
82             // NOTE: You must have called DangerousAddRef before calling this
83             //       method, or you run the risk of allowing Handle Recycling
84             //       to occur!
85             //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
86             return ADP.IntPtrOffset(DangerousGetHandle(), _headerLength);
87         }
88
89         internal IntPtr DangerousGetDataPtr(int valueOffset) {
90             //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
91             // NOTE: You must have called DangerousAddRef before calling this
92             //       method, or you run the risk of allowing Handle Recycling
93             //       to occur!
94             //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
95             return ADP.IntPtrOffset(DangerousGetHandle(), valueOffset);
96         }
97
98         internal OleDbHResult CreateAccessor(UnsafeNativeMethods.IAccessor iaccessor, int flags, ColumnBinding[] bindings) {
99             OleDbHResult hr = 0;
100             int[] rowBindStatus = new int[BindingCount()];
101
102             _iaccessor = iaccessor;
103
104             Bid.Trace("<oledb.IAccessor.CreateAccessor|API|OLEDB>\n");
105             hr = iaccessor.CreateAccessor(flags, (IntPtr)rowBindStatus.Length, this, (IntPtr)_dataLength, out _accessorHandle, rowBindStatus); // MDAC 69530
106             Bid.Trace("<oledb.IAccessor.CreateAccessor|API|OLEDB|RET> %08X{HRESULT}\n", hr);
107
108             for (int k = 0; k < rowBindStatus.Length; ++k) {
109                 if (DBBindStatus.OK != (DBBindStatus)rowBindStatus[k]) {
110                     if (ODB.DBACCESSOR_PARAMETERDATA == flags) {
111                         throw ODB.BadStatus_ParamAcc(bindings[k].ColumnBindingOrdinal, (DBBindStatus)rowBindStatus[k]);
112                     }
113                     else if (ODB.DBACCESSOR_ROWDATA == flags) {
114                         throw ODB.BadStatusRowAccessor(bindings[k].ColumnBindingOrdinal, (DBBindStatus)rowBindStatus[k]);
115                     }
116                     else Debug.Assert(false, "unknown accessor buffer");
117                 }
118             }
119             return hr;
120         }
121
122         internal ColumnBinding[] SetBindings(OleDbDataReader dataReader, Bindings bindings,
123                                              int indexStart, int indexForAccessor,
124                                              OleDbParameter[] parameters, tagDBBINDING[] dbbindings, bool ifIRowsetElseIRow) {
125             Debug.Assert(null != bindings, "null bindings");
126             Debug.Assert(dbbindings.Length == BindingCount(), "count mismatch");
127
128             bool mustRelease = false;
129
130             RuntimeHelpers.PrepareConstrainedRegions();
131             try {
132                 DangerousAddRef(ref mustRelease);
133
134                 IntPtr buffer = DangerousGetHandle();
135                 for(int i = 0; i < dbbindings.Length; ++i) {
136                     IntPtr ptr = ADP.IntPtrOffset(buffer, (i * ODB.SizeOf_tagDBBINDING));
137                     Marshal.StructureToPtr(dbbindings[i], ptr, false/*deleteold*/);
138                 }
139             }
140             finally {
141                 if (mustRelease) {
142                     DangerousRelease();
143                 }
144             }
145
146             ColumnBinding[] columns = new ColumnBinding[dbbindings.Length];
147             for(int indexWithinAccessor = 0; indexWithinAccessor < columns.Length; ++indexWithinAccessor) {
148                 int index = indexStart + indexWithinAccessor;
149                 OleDbParameter parameter = ((null != parameters) ? parameters[index] : null);
150                 columns[indexWithinAccessor] = new ColumnBinding(
151                     dataReader, index, indexForAccessor, indexWithinAccessor,
152                     parameter, this, bindings, dbbindings[indexWithinAccessor], _headerLength,
153                     ifIRowsetElseIRow);
154             }
155             return columns;
156         }
157
158         static internal int AlignDataSize(int value) {
159             // buffer data to start on 8-byte boundary
160             return Math.Max(8, (value + 7) & ~0x7); // MDAC 70350
161         }
162
163         internal object GetVariantValue(int offset) {
164             Debug.Assert(_needToReset, "data type requires reseting and _needToReset is false");
165             Debug.Assert(0 == (ODB.SizeOf_Variant % 8), "unexpected VARIANT size mutiplier");
166             Debug.Assert(0 == offset%8, "invalid alignment");
167             ValidateCheck(offset, 2*ODB.SizeOf_Variant);
168
169             object value = null;
170             bool mustRelease = false;
171             RuntimeHelpers.PrepareConstrainedRegions();
172             try {
173                 DangerousAddRef(ref mustRelease);
174
175                 IntPtr buffer = ADP.IntPtrOffset(DangerousGetHandle(), offset);
176                 value = Marshal.GetObjectForNativeVariant(buffer);
177             }
178             finally {
179                 if (mustRelease) {
180                     DangerousRelease();
181                 }
182             }
183
184             return ((null != value) ? value : DBNull.Value);
185         }
186
187         // translate to native
188         internal void SetVariantValue(int offset, object value) {
189             // two contigous VARIANT structures, second should be a binary copy of the first
190             Debug.Assert(_needToReset, "data type requires reseting and _needToReset is false");
191             Debug.Assert(0 == (ODB.SizeOf_Variant % 8), "unexpected VARIANT size mutiplier");
192             Debug.Assert(0 == offset%8, "invalid alignment");
193             ValidateCheck(offset, 2*ODB.SizeOf_Variant);
194
195             IntPtr buffer = ADP.PtrZero;
196             bool mustRelease = false;
197             RuntimeHelpers.PrepareConstrainedRegions();
198             try {
199                 DangerousAddRef(ref mustRelease);
200                 
201                 buffer = ADP.IntPtrOffset(DangerousGetHandle(), offset);
202
203                 RuntimeHelpers.PrepareConstrainedRegions();
204                 try {
205                     // GetNativeVariantForObject must be in try block since it has no reliability contract
206                     Marshal.GetNativeVariantForObject(value, buffer);
207                 }
208                 finally {
209                     // safe to copy memory(dst,src,count), even if GetNativeVariantForObject failed
210                     NativeOledbWrapper.MemoryCopy(ADP.IntPtrOffset(buffer,ODB.SizeOf_Variant), buffer, ODB.SizeOf_Variant);
211                 }
212             }
213             finally {
214                 if (mustRelease) {
215                     DangerousRelease();
216                 }
217             }
218         }
219
220         // value
221         // cached value
222         // cached zero value
223         // translate to native
224         internal void SetBstrValue(int offset, string value) {
225             // two contigous BSTR ptr, second should be a binary copy of the first
226             Debug.Assert(_needToReset, "data type requires reseting and _needToReset is false");
227             Debug.Assert(0 == offset%ADP.PtrSize, "invalid alignment");
228             ValidateCheck(offset, 2*IntPtr.Size);
229
230             IntPtr ptr;
231             bool mustRelease = false;
232             RuntimeHelpers.PrepareConstrainedRegions();
233             try {
234                 DangerousAddRef(ref mustRelease);
235
236                 RuntimeHelpers.PrepareConstrainedRegions();
237                 try { } finally {
238                     ptr = SafeNativeMethods.SysAllocStringLen(value, value.Length);
239
240                     // safe to copy ptr, even if SysAllocStringLen failed
241                     Marshal.WriteIntPtr(base.handle, offset, ptr);
242                     Marshal.WriteIntPtr(base.handle, offset + ADP.PtrSize, ptr);
243                 }
244             }
245             finally {
246                 if (mustRelease) {
247                     DangerousRelease();
248                 }
249             }
250             if (IntPtr.Zero == ptr) {
251                 throw new OutOfMemoryException();
252             }
253         }
254
255         // translate to native
256         internal void SetByRefValue(int offset, IntPtr pinnedValue) {
257             Debug.Assert(_needToReset, "data type requires reseting and _needToReset is false");
258             Debug.Assert(0 == offset%ADP.PtrSize, "invalid alignment");
259             ValidateCheck(offset, 2*IntPtr.Size);
260
261             if (ADP.PtrZero == pinnedValue) { // empty array scenario
262                 pinnedValue = ADP.IntPtrOffset(base.handle, _emptyStringOffset);
263             }
264             bool mustRelease = false;
265             RuntimeHelpers.PrepareConstrainedRegions();
266             try {
267                 DangerousAddRef(ref mustRelease);
268
269                 RuntimeHelpers.PrepareConstrainedRegions();
270                 try { } finally {
271                     Marshal.WriteIntPtr(base.handle, offset, pinnedValue);               // parameter input value
272                     Marshal.WriteIntPtr(base.handle, offset + ADP.PtrSize, pinnedValue); // original parameter value
273                 }
274             }
275             finally {
276                 if (mustRelease) {
277                     DangerousRelease();
278                 }
279             }
280         }
281
282         internal void CloseFromConnection() {
283             _iaccessor = null;
284             _accessorHandle = ODB.DB_INVALID_HACCESSOR;
285         }
286
287         internal new void Dispose() {
288             ResetValues();
289
290             UnsafeNativeMethods.IAccessor iaccessor = _iaccessor;
291             IntPtr accessorHandle = _accessorHandle;
292
293             _iaccessor = null;
294             _accessorHandle = ODB.DB_INVALID_HACCESSOR;
295
296             if ((ODB.DB_INVALID_HACCESSOR != accessorHandle) && (null != iaccessor)) {
297                 OleDbHResult hr;
298                 int refcount;
299                 hr = iaccessor.ReleaseAccessor(accessorHandle, out refcount);
300                 if (hr < 0) { // ignore any error msgs
301                     SafeNativeMethods.Wrapper.ClearErrorInfo();
302                 }
303             }
304
305             base.Dispose();
306         }
307
308         internal void ResetValues() {
309             if (_needToReset && _haveData) {
310                 lock(this) { // prevent Dispose/ResetValues race condition
311
312                     bool mustRelease = false;
313                     RuntimeHelpers.PrepareConstrainedRegions();
314                     try {
315                         DangerousAddRef(ref mustRelease);
316
317                         ResetValues(DangerousGetHandle(), _iaccessor);
318                     }
319                     finally {
320                         if (mustRelease) {
321                             DangerousRelease();
322                         }
323                     }
324                 }
325             }
326             else {
327                 _haveData = false;
328             }
329 #if DEBUG
330             // verify types that need reseting are not forgotton, since the code
331             // that sets this up is in dbbinding.cs, MaxLen { set; }
332             if (!_needToReset) {
333                 Debug.Assert(0 <= _bindingCount && (_bindingCount * ODB.SizeOf_tagDBBINDING) < Length, "bad _bindingCount");
334                 for (int i = 0; i < _bindingCount; ++i) {
335                     short wtype = ReadInt16((i * ODB.SizeOf_tagDBBINDING) + ODB.OffsetOf_tagDBBINDING_wType);
336                     switch(wtype) {
337                     case (NativeDBType.BYREF | NativeDBType.BYTES):
338                     case (NativeDBType.BYREF | NativeDBType.WSTR):
339                     case NativeDBType.PROPVARIANT:
340                     case NativeDBType.VARIANT:
341                     case NativeDBType.BSTR:
342                     case NativeDBType.HCHAPTER:
343                         Debug.Assert(false, "expected _needToReset");
344                         break;
345                     }
346                 }
347             }
348 #endif
349         }
350
351         // requires ReliabilityContract to be called by ReleaseHandle
352         [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
353         private void ResetValues(IntPtr buffer, object iaccessor) {
354             Debug.Assert(ADP.PtrZero != buffer && _needToReset && _haveData, "shouldn't be calling ResetValues");
355             for (int i = 0; i < _bindingCount; ++i) {
356                 IntPtr ptr = ADP.IntPtrOffset(buffer, (i * ODB.SizeOf_tagDBBINDING));
357
358                 int valueOffset = _headerLength + Marshal.ReadIntPtr(ptr, ODB.OffsetOf_tagDBBINDING_obValue).ToInt32();
359                 short wtype = Marshal.ReadInt16(ptr, ODB.OffsetOf_tagDBBINDING_wType);
360
361                 switch(wtype) {
362                 case (NativeDBType.BYREF | NativeDBType.BYTES):
363                 case (NativeDBType.BYREF | NativeDBType.WSTR):
364                     ValidateCheck(valueOffset, 2*IntPtr.Size);
365                     FreeCoTaskMem(buffer, valueOffset);
366                     break;
367                 case NativeDBType.PROPVARIANT:
368                     ValidateCheck(valueOffset, 2*NativeOledbWrapper.SizeOfPROPVARIANT);
369                     FreePropVariant(buffer, valueOffset);
370                     break;
371                 case NativeDBType.VARIANT:
372                     ValidateCheck(valueOffset, 2*ODB.SizeOf_Variant);
373                     FreeVariant(buffer, valueOffset);
374                     break;
375                 case NativeDBType.BSTR:
376                     ValidateCheck(valueOffset, 2*IntPtr.Size);
377                     FreeBstr(buffer, valueOffset);
378                     break;
379                 case NativeDBType.HCHAPTER:
380                     if (null != iaccessor) {
381                         // iaccessor will always be null when from ReleaseHandle
382                         FreeChapter(buffer, valueOffset, iaccessor);
383                     }
384                     break;
385 #if DEBUG
386
387                 case NativeDBType.EMPTY:
388                 case NativeDBType.NULL:
389                 case NativeDBType.I2:
390                 case NativeDBType.I4:
391                 case NativeDBType.R4:
392                 case NativeDBType.R8:
393                 case NativeDBType.CY:
394                 case NativeDBType.DATE:
395                 case NativeDBType.ERROR:
396                 case NativeDBType.BOOL:
397                 case NativeDBType.DECIMAL:
398                 case NativeDBType.I1:
399                 case NativeDBType.UI1:
400                 case NativeDBType.UI2:
401                 case NativeDBType.UI4:
402                 case NativeDBType.I8:
403                 case NativeDBType.UI8:
404                 case NativeDBType.FILETIME:
405                 case NativeDBType.GUID:
406                 case NativeDBType.BYTES:
407                 case NativeDBType.WSTR:
408                 case NativeDBType.NUMERIC:
409                 case NativeDBType.DBDATE:
410                 case NativeDBType.DBTIME:
411                 case NativeDBType.DBTIMESTAMP:
412                     break; // known, do nothing
413                 case NativeDBType.IDISPATCH:
414                 case NativeDBType.IUNKNOWN:
415                     break; // known, releasing RowHandle will handle lifetimes correctly
416                 default:
417                     Debug.Assert(false, "investigate");
418                     break;
419 #endif
420                 }
421             }
422             _haveData = false;
423         }
424
425         // this correctly does not have a ReliabilityContract, will not be called via ReleaseHandle
426         static private void FreeChapter(IntPtr buffer, int valueOffset, object iaccessor) {
427             Debug.Assert (0 == valueOffset % 8, "unexpected unaligned ptr offset");
428
429             UnsafeNativeMethods.IChapteredRowset chapteredRowset = (iaccessor as UnsafeNativeMethods.IChapteredRowset);
430             IntPtr chapter = SafeNativeMethods.InterlockedExchangePointer(ADP.IntPtrOffset(buffer, valueOffset), ADP.PtrZero);
431             if (ODB.DB_NULL_HCHAPTER != chapter) {
432                 int refCount;
433                 Bid.Trace("<oledb.IChapteredRowset.ReleaseChapter|API|OLEDB> Chapter=%Id\n", chapter);
434                 OleDbHResult hr = chapteredRowset.ReleaseChapter(chapter, out refCount);
435                 Bid.Trace("<oledb.IChapteredRowset.ReleaseChapter|API|OLEDB|RET> %08X{HRESULT}, RefCount=%d\n", hr, refCount);
436             }
437         }
438
439         [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
440         static private void FreeBstr(IntPtr buffer, int valueOffset) {
441             Debug.Assert (0 == valueOffset % 8, "unexpected unaligned ptr offset");
442
443             // two contigous BSTR ptrs that need to be freed
444             // the second should only be freed if different from the first
445             RuntimeHelpers.PrepareConstrainedRegions();
446             try {} finally {
447                 IntPtr currentValue = Marshal.ReadIntPtr(buffer, valueOffset);
448                 IntPtr originalValue = Marshal.ReadIntPtr(buffer, valueOffset + ADP.PtrSize);
449
450                 if ((ADP.PtrZero != currentValue) && (currentValue != originalValue)) {
451                     SafeNativeMethods.SysFreeString(currentValue);
452                 }
453                 if (ADP.PtrZero != originalValue) {
454                     SafeNativeMethods.SysFreeString(originalValue);
455                 }
456
457                 // for debugability - delay clearing memory until after FreeBSTR
458                 Marshal.WriteIntPtr(buffer, valueOffset, ADP.PtrZero);
459                 Marshal.WriteIntPtr(buffer, valueOffset + ADP.PtrSize, ADP.PtrZero);
460             }
461         }
462
463         [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
464         static private void FreeCoTaskMem(IntPtr buffer, int valueOffset) {
465             Debug.Assert (0 == valueOffset % 8, "unexpected unaligned ptr offset");
466
467             // two contigous CoTaskMemAlloc ptrs that need to be freed
468             // the first should only be freed if different from the first
469             RuntimeHelpers.PrepareConstrainedRegions();
470             try {} finally {
471                 IntPtr currentValue = Marshal.ReadIntPtr(buffer, valueOffset);
472                 IntPtr originalValue = Marshal.ReadIntPtr(buffer, valueOffset + ADP.PtrSize);
473
474                 // originalValue is pinned managed memory or pointer to emptyStringOffset
475                 if ((ADP.PtrZero != currentValue) && (currentValue != originalValue)) {
476                     SafeNativeMethods.CoTaskMemFree(currentValue);
477                 }
478
479                 // for debugability - delay clearing memory until after CoTaskMemFree
480                 Marshal.WriteIntPtr(buffer, valueOffset, ADP.PtrZero);
481                 Marshal.WriteIntPtr(buffer, valueOffset + ADP.PtrSize, ADP.PtrZero);
482             }
483         }
484
485         [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
486         static private void FreeVariant(IntPtr buffer, int valueOffset) {
487             // two contigous VARIANT structures that need to be freed
488             // the second should only be freed if different from the first
489
490             Debug.Assert(0 == (ODB.SizeOf_Variant % 8), "unexpected VARIANT size mutiplier");
491             Debug.Assert (0 == valueOffset % 8, "unexpected unaligned ptr offset");
492
493             IntPtr currentHandle = ADP.IntPtrOffset(buffer, valueOffset);
494             IntPtr originalHandle = ADP.IntPtrOffset(buffer, valueOffset+ODB.SizeOf_Variant);
495             bool different = NativeOledbWrapper.MemoryCompare(currentHandle, originalHandle, ODB.SizeOf_Variant);
496
497             RuntimeHelpers.PrepareConstrainedRegions();
498             try {} finally {
499                 // always clear the first structure
500                 SafeNativeMethods.VariantClear(currentHandle);
501                 if (different) {
502                     // second structure different from the first
503                     SafeNativeMethods.VariantClear(originalHandle);
504                 }
505                 else {
506                     // second structure same as the first, just clear the field
507                     SafeNativeMethods.ZeroMemory(originalHandle, (IntPtr)ODB.SizeOf_Variant);
508                 }
509             }
510         }
511
512         [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
513         static private void FreePropVariant(IntPtr buffer, int valueOffset) {
514             // two contigous PROPVARIANT structures that need to be freed
515             // the second should only be freed if different from the first
516             Debug.Assert(0 == (NativeOledbWrapper.SizeOfPROPVARIANT % 8), "unexpected PROPVARIANT size mutiplier");
517             Debug.Assert (0 == valueOffset % 8, "unexpected unaligned ptr offset");
518
519             IntPtr currentHandle = ADP.IntPtrOffset(buffer, valueOffset);
520             IntPtr originalHandle = ADP.IntPtrOffset(buffer, valueOffset+NativeOledbWrapper.SizeOfPROPVARIANT);
521             bool different = NativeOledbWrapper.MemoryCompare(currentHandle, originalHandle, NativeOledbWrapper.SizeOfPROPVARIANT);
522
523             RuntimeHelpers.PrepareConstrainedRegions();
524             try {} finally {
525                 // always clear the first structure
526                 SafeNativeMethods.PropVariantClear(currentHandle);
527                 if (different) {
528                     // second structure different from the first
529                     SafeNativeMethods.PropVariantClear(originalHandle);
530                 }
531                 else {
532                     // second structure same as the first, just clear the field
533                     SafeNativeMethods.ZeroMemory(originalHandle, (IntPtr)NativeOledbWrapper.SizeOfPROPVARIANT);
534                 }
535             }
536         }
537
538         [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
539         internal IntPtr InterlockedExchangePointer(int offset) {
540             ValidateCheck(offset, IntPtr.Size);
541             Debug.Assert(0 == offset%ADP.PtrSize, "invalid alignment");
542
543             IntPtr value;
544             bool   mustRelease = false;
545             RuntimeHelpers.PrepareConstrainedRegions();
546             try {
547                 DangerousAddRef(ref mustRelease);
548
549                 IntPtr ptr = ADP.IntPtrOffset(DangerousGetHandle(), offset);
550                 value = SafeNativeMethods.InterlockedExchangePointer(ptr, IntPtr.Zero);
551             }
552             finally {
553                 if (mustRelease) {
554                     DangerousRelease();
555                 }
556             }
557             return value;
558         }
559         
560         override protected bool ReleaseHandle() {
561             // NOTE: The SafeHandle class guarantees this will be called exactly once.
562             _iaccessor = null;
563             if (_needToReset && _haveData) {
564                 IntPtr buffer = base.handle;
565                 if (IntPtr.Zero != buffer) {
566                     ResetValues(buffer, null);
567                 }
568             }
569             return base.ReleaseHandle();
570         }
571     }
572 }