251146a92fe9eb40d051d4cbbdd3392880d86d42
[mono.git] / mcs / class / referencesource / System.Data / System / Data / OleDb / OleDbConnection.cs
1 //------------------------------------------------------------------------------
2 // <copyright file="OleDbConnection.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.Collections.Generic;
13     using System.ComponentModel;
14     using System.Data;
15     using System.Data.Common;
16     using System.Data.ProviderBase;
17     using System.Diagnostics;
18     using System.Diagnostics.CodeAnalysis;
19     using System.Globalization;
20     using System.IO;
21     using System.Runtime.InteropServices;
22     using System.Security;
23     using System.Security.Permissions;
24     using System.Text;
25     using System.Threading;
26     using SysTx = System.Transactions;
27
28     // wraps the OLEDB IDBInitialize interface which represents a connection
29     // Notes about connection pooling
30     // 1. Connection pooling isn't supported on Win95
31     // 2. Only happens if we use the IDataInitialize or IDBPromptInitialize interfaces
32     //    it won't happen if you directly create the provider and set its properties
33     // 3. First call on IDBInitialize must be Initialize, can't QI for any other interfaces before that
34     [DefaultEvent("InfoMessage")]
35     public sealed partial class OleDbConnection : DbConnection, ICloneable, IDbConnection { 
36
37         static private readonly object EventInfoMessage = new object();
38
39         public OleDbConnection(string connectionString) : this() {
40             ConnectionString = connectionString;
41         }
42
43         private OleDbConnection(OleDbConnection connection) : this() { // Clone
44             CopyFrom(connection);
45         }
46
47         [
48         DefaultValue(""),
49 #pragma warning disable 618 // ignore obsolete warning about RecommendedAsConfigurable to use SettingsBindableAttribute
50         RecommendedAsConfigurable(true),
51 #pragma warning restore 618
52         SettingsBindableAttribute(true),
53         RefreshProperties(RefreshProperties.All),
54         ResCategoryAttribute(Res.DataCategory_Data),
55         Editor("Microsoft.VSDesigner.Data.ADO.Design.OleDbConnectionStringEditor, " + AssemblyRef.MicrosoftVSDesigner, "System.Drawing.Design.UITypeEditor, " + AssemblyRef.SystemDrawing),
56         ResDescriptionAttribute(Res.OleDbConnection_ConnectionString),
57         ]
58         override public string ConnectionString {
59             get {
60                 return ConnectionString_Get();
61             }
62             set {
63                 ConnectionString_Set(value);
64             }
65         }
66
67         private OleDbConnectionString OleDbConnectionStringValue {
68             get { return (OleDbConnectionString)ConnectionOptions; }
69         }
70
71         [
72         DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
73         ResDescriptionAttribute(Res.OleDbConnection_ConnectionTimeout),
74         ]
75         override public int ConnectionTimeout {
76             get {
77                 IntPtr hscp;
78                 Bid.ScopeEnter(out hscp, "<oledb.OleDbConnection.get_ConnectionTimeout|API> %d#\n", ObjectID);
79                 try {
80                     object value = null;
81                     if (IsOpen) {
82                         value = GetDataSourceValue(OleDbPropertySetGuid.DBInit, ODB.DBPROP_INIT_TIMEOUT);
83                     }
84                     else {
85                         OleDbConnectionString constr = this.OleDbConnectionStringValue;
86                         value = (null != constr) ? constr.ConnectTimeout : ADP.DefaultConnectionTimeout;
87                     }
88                     if (null != value) {
89                         return Convert.ToInt32(value, CultureInfo.InvariantCulture);
90                     }
91                     else {
92                         return ADP.DefaultConnectionTimeout;
93                     }
94                 }
95                 finally {
96                     Bid.ScopeLeave(ref hscp);
97                 }
98             }
99         }
100
101         [
102         DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
103         ResDescriptionAttribute(Res.OleDbConnection_Database),
104         ]
105         override public string Database {
106             get {
107                 IntPtr hscp;
108                 Bid.ScopeEnter(out hscp, "<oledb.OleDbConnection.get_Database|API> %d#\n", ObjectID);
109                 try {
110                     OleDbConnectionString constr = (OleDbConnectionString)UserConnectionOptions;
111                     object value = (null != constr) ? constr.InitialCatalog : ADP.StrEmpty;
112                     if ((null != value) && !((string)value).StartsWith(DbConnectionOptions.DataDirectory, StringComparison.OrdinalIgnoreCase)) {
113                         OleDbConnectionInternal connection = GetOpenConnection();
114                         if (null != connection) {
115                             if (connection.HasSession) {
116                                 value = GetDataSourceValue(OleDbPropertySetGuid.DataSource, ODB.DBPROP_CURRENTCATALOG);
117                             }
118                             else {
119                                 value = GetDataSourceValue(OleDbPropertySetGuid.DBInit, ODB.DBPROP_INIT_CATALOG);
120                             }
121                         }
122                         else {
123                             constr = this.OleDbConnectionStringValue;
124                             value = (null != constr) ? constr.InitialCatalog : ADP.StrEmpty;
125                         }
126                     }
127                     return Convert.ToString(value, CultureInfo.InvariantCulture);
128                 }
129                 finally {
130                     Bid.ScopeLeave(ref hscp);
131                 }
132             }
133         }
134
135         [
136         Browsable(true),
137         ResDescriptionAttribute(Res.OleDbConnection_DataSource),
138         ]
139         override public string DataSource {
140             get {
141                 IntPtr hscp;
142                 Bid.ScopeEnter(out hscp, "<oledb.OleDbConnection.get_DataSource|API> %d#\n", ObjectID);
143                 try {
144                     OleDbConnectionString constr = (OleDbConnectionString)UserConnectionOptions;
145                     object value = (null != constr) ? constr.DataSource : ADP.StrEmpty;
146                     if ((null != value) && !((string)value).StartsWith(DbConnectionOptions.DataDirectory, StringComparison.OrdinalIgnoreCase)) {
147                         if (IsOpen) {
148                             value = GetDataSourceValue(OleDbPropertySetGuid.DBInit, ODB.DBPROP_INIT_DATASOURCE);
149                             if ((null == value) || ((value is string) && (0 == (value as string).Length))) {
150                                 value = GetDataSourceValue(OleDbPropertySetGuid.DataSourceInfo, ODB.DBPROP_DATASOURCENAME); // MDAC 76248
151                             }
152                         }
153                         else {
154                             constr = this.OleDbConnectionStringValue;
155                             value = (null != constr) ? constr.DataSource : ADP.StrEmpty;
156                         }
157                     }
158                     return Convert.ToString(value, CultureInfo.InvariantCulture);
159                 }
160                 finally {
161                     Bid.ScopeLeave(ref hscp);
162                 }
163             }
164         }
165
166         internal bool IsOpen {
167             get { return (null != GetOpenConnection()); }
168         }
169
170         internal OleDbTransaction LocalTransaction {
171             set {
172                 OleDbConnectionInternal openConnection = GetOpenConnection();
173
174                 if (null != openConnection) {
175                     openConnection.LocalTransaction = value;
176                 }
177             }
178         }
179
180         [
181         Browsable(true),
182         DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
183        ResCategoryAttribute(Res.DataCategory_Data),
184         ResDescriptionAttribute(Res.OleDbConnection_Provider),
185         ]
186         public String Provider {
187             get {
188                 Bid.Trace("<oledb.OleDbConnection.get_Provider|API> %d#\n", ObjectID);
189                 OleDbConnectionString constr = this.OleDbConnectionStringValue;
190                 string value = ((null != constr) ? constr.ConvertValueToString(ODB.Provider, null) : null);
191                 return ((null != value) ? value : ADP.StrEmpty);
192             }
193         }
194         
195         internal OleDbConnectionPoolGroupProviderInfo ProviderInfo {
196             get {
197                 return (OleDbConnectionPoolGroupProviderInfo)PoolGroup.ProviderInfo;
198             }
199         }
200
201         [
202         ResDescriptionAttribute(Res.OleDbConnection_ServerVersion),
203         ]
204         override public string ServerVersion { // MDAC 55481
205             get {
206                 return InnerConnection.ServerVersion;
207             }
208         }
209
210         [
211         Browsable(false),
212         DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
213         ResDescriptionAttribute(Res.DbConnection_State),
214         ]
215         override public ConnectionState State {
216             get {
217                 return InnerConnection.State;
218             }
219         }
220
221         [
222         EditorBrowsableAttribute(EditorBrowsableState.Advanced),
223         ]
224         public void ResetState() { // MDAC 58606
225             IntPtr hscp;
226             Bid.ScopeEnter(out hscp, "<oledb.OleDbCommand.ResetState|API> %d#\n", ObjectID);
227             try {
228                 if (IsOpen) {
229                     object value = GetDataSourcePropertyValue(OleDbPropertySetGuid.DataSourceInfo, ODB.DBPROP_CONNECTIONSTATUS);
230                     if (value is Int32) {
231                         int connectionStatus = (int) value;
232                         switch (connectionStatus) {
233                         case ODB.DBPROPVAL_CS_UNINITIALIZED: // provider closed on us
234                         case ODB.DBPROPVAL_CS_COMMUNICATIONFAILURE: // broken connection
235                             GetOpenConnection().DoomThisConnection();
236                             NotifyWeakReference(OleDbReferenceCollection.Canceling); // MDAC 71435
237                             Close();
238                             break;
239
240                         case ODB.DBPROPVAL_CS_INITIALIZED: // everything is okay
241                             break;
242
243                         default: // have to assume everything is okay
244                             Debug.Assert(false, "Unknown 'Connection Status' value " + connectionStatus.ToString("G", CultureInfo.InvariantCulture));
245                             break;
246                         }
247                     }
248                 }
249             }
250             finally {
251                 Bid.ScopeLeave(ref hscp);
252             }
253         }
254
255         [
256         ResCategoryAttribute(Res.DataCategory_InfoMessage),
257         ResDescriptionAttribute(Res.DbConnection_InfoMessage),
258         ]
259         public event OleDbInfoMessageEventHandler InfoMessage {
260             add {
261                 Events.AddHandler(EventInfoMessage, value);
262             }
263             remove {
264                 Events.RemoveHandler(EventInfoMessage, value);
265             }
266         }
267
268         internal UnsafeNativeMethods.ICommandText ICommandText() {
269             Debug.Assert(null != GetOpenConnection(), "ICommandText closed");
270             return GetOpenConnection().ICommandText();
271         }
272
273         private IDBPropertiesWrapper IDBProperties() {
274             Debug.Assert(null != GetOpenConnection(), "IDBProperties closed");
275             return GetOpenConnection().IDBProperties();
276         }
277
278         internal IOpenRowsetWrapper IOpenRowset() {
279             Debug.Assert(null != GetOpenConnection(), "IOpenRowset closed");
280             return GetOpenConnection().IOpenRowset();
281         }
282
283         internal int SqlSupport() {
284             Debug.Assert(null != this.OleDbConnectionStringValue, "no OleDbConnectionString SqlSupport");
285             return this.OleDbConnectionStringValue.GetSqlSupport(this);
286         }
287
288         internal bool SupportMultipleResults() {
289             Debug.Assert(null != this.OleDbConnectionStringValue, "no OleDbConnectionString SupportMultipleResults");
290             return this.OleDbConnectionStringValue.GetSupportMultipleResults(this);
291         }
292
293         internal bool SupportIRow(OleDbCommand cmd) { // MDAC 72902
294             Debug.Assert(null != this.OleDbConnectionStringValue, "no OleDbConnectionString SupportIRow");
295             return this.OleDbConnectionStringValue.GetSupportIRow(this, cmd);
296         }
297
298         internal int QuotedIdentifierCase() { // MDAC 67385
299             Debug.Assert(null != this.OleDbConnectionStringValue, "no OleDbConnectionString QuotedIdentifierCase");
300             
301             int quotedIdentifierCase;
302             object value = GetDataSourcePropertyValue(OleDbPropertySetGuid.DataSourceInfo, ODB.DBPROP_QUOTEDIDENTIFIERCASE);
303             if (value is Int32) {// not OleDbPropertyStatus
304                 quotedIdentifierCase =  (int) value;
305             }
306             else {
307                 quotedIdentifierCase = -1;
308             }
309             return quotedIdentifierCase;
310         }
311
312         new public OleDbTransaction BeginTransaction() {
313             return BeginTransaction(IsolationLevel.Unspecified);
314         }
315
316         new public OleDbTransaction BeginTransaction(IsolationLevel isolationLevel) {
317             return (OleDbTransaction)InnerConnection.BeginTransaction(isolationLevel);
318         }
319
320         override public void ChangeDatabase(string value) {
321             OleDbConnection.ExecutePermission.Demand();
322
323             IntPtr hscp;
324             Bid.ScopeEnter(out hscp, "<oledb.OleDbConnection.ChangeDatabase|API> %d#, value='%ls'\n", ObjectID, value);
325             try {
326                 CheckStateOpen(ADP.ChangeDatabase);
327                 if ((null == value) || (0 == value.Trim().Length)) { // MDAC 62679
328                     throw ADP.EmptyDatabaseName();
329                 }
330                 SetDataSourcePropertyValue(OleDbPropertySetGuid.DataSource, ODB.DBPROP_CURRENTCATALOG, ODB.Current_Catalog, true, value);
331             }
332             finally {
333                 Bid.ScopeLeave(ref hscp);
334             }
335         }
336
337         internal void CheckStateOpen(string method) {
338             ConnectionState state = State;
339             if (ConnectionState.Open != state) {
340                 throw ADP.OpenConnectionRequired(method, state);
341             }
342         }
343
344         object ICloneable.Clone() {
345             OleDbConnection clone = new OleDbConnection(this);
346             Bid.Trace("<oledb.OleDbConnection.Clone|API> %d#, clone=%d#\n", ObjectID, clone.ObjectID);
347             return clone;
348         }
349
350         override public void Close() {
351             InnerConnection.CloseConnection(this, ConnectionFactory);
352             // does not require GC.KeepAlive(this) because of OnStateChange
353         }
354
355         new public OleDbCommand CreateCommand() {
356             return new OleDbCommand("", this);
357         }
358
359         private void DisposeMe(bool disposing) { // MDAC 65459
360             if (disposing) { // release mananged objects
361                 if (DesignMode) {
362                     // release the object pool in design-mode so that
363                     // native MDAC can be properly released during shutdown
364                     OleDbConnection.ReleaseObjectPool();
365                 }
366             }
367         }
368
369
370         // suppress this message - we cannot use SafeHandle here. Also, see notes in the code (VSTFDEVDIV# 560355)
371         [SuppressMessage("Microsoft.Reliability", "CA2004:RemoveCallsToGCKeepAlive")]
372         override protected DbTransaction BeginDbTransaction(IsolationLevel isolationLevel) {
373             IntPtr hscp;
374
375             Bid.ScopeEnter(out hscp, "<prov.OleDbConnection.BeginDbTransaction|API> %d#, isolationLevel=%d{ds.IsolationLevel}", ObjectID, (int)isolationLevel);
376             try {
377
378                 DbTransaction transaction = InnerConnection.BeginTransaction(isolationLevel);
379
380                 // VSTFDEVDIV# 560355 - InnerConnection doesn't maintain a ref on the outer connection (this) and 
381                 //   subsequently leaves open the possibility that the outer connection could be GC'ed before the DbTransaction
382                 //   is fully hooked up (leaving a DbTransaction with a null connection property). Ensure that this is reachable
383                 //   until the completion of BeginTransaction with KeepAlive
384                 GC.KeepAlive(this);
385
386                 return transaction;
387             }
388             finally {
389                 Bid.ScopeLeave(ref hscp);
390             }
391         }
392
393         public void EnlistDistributedTransaction(System.EnterpriseServices.ITransaction transaction) {
394             EnlistDistributedTransactionHelper(transaction);
395         }
396
397         internal object GetDataSourcePropertyValue(Guid propertySet, int propertyID) {
398             OleDbConnectionInternal connection = GetOpenConnection();
399             return connection.GetDataSourcePropertyValue(propertySet, propertyID);
400         }
401
402         internal object GetDataSourceValue(Guid propertySet, int propertyID) {
403             object value = GetDataSourcePropertyValue(propertySet, propertyID);
404             if ((value is OleDbPropertyStatus) || Convert.IsDBNull(value)) {
405                 value = null;
406             }
407             return value;
408         }
409
410         private OleDbConnectionInternal GetOpenConnection() {
411             DbConnectionInternal innerConnection = InnerConnection;
412             return (innerConnection as OleDbConnectionInternal);
413         }
414
415         internal void GetLiteralQuotes(string method, out string quotePrefix, out string quoteSuffix) {
416             CheckStateOpen(method);
417             OleDbConnectionPoolGroupProviderInfo info = ProviderInfo;
418             if (info.HasQuoteFix) {
419                 quotePrefix = info.QuotePrefix;
420                 quoteSuffix = info.QuoteSuffix;
421             }
422             else {
423                 OleDbConnectionInternal connection = GetOpenConnection();
424                 quotePrefix = connection.GetLiteralInfo(ODB.DBLITERAL_QUOTE_PREFIX);
425                 quoteSuffix = connection.GetLiteralInfo(ODB.DBLITERAL_QUOTE_SUFFIX);
426                 if (null == quotePrefix) {
427                     quotePrefix = "";
428                 }
429                 if (null == quoteSuffix) {
430                     quoteSuffix = quotePrefix;
431                 }
432                 info.SetQuoteFix(quotePrefix, quoteSuffix);
433             }
434         }
435
436         public DataTable GetOleDbSchemaTable(Guid schema, object[] restrictions) { // MDAC 61846
437             OleDbConnection.ExecutePermission.Demand();
438             
439             IntPtr hscp;
440             Bid.ScopeEnter(out hscp, "<oledb.OleDbConnection.GetOleDbSchemaTable|API> %d#, schema=%ls, restrictions\n", ObjectID, schema);
441             try {
442                 CheckStateOpen(ADP.GetOleDbSchemaTable);
443                 OleDbConnectionInternal connection = GetOpenConnection();
444
445                 if (OleDbSchemaGuid.DbInfoLiterals == schema) {
446                     if ((null == restrictions) || (0 == restrictions.Length)) {
447                         return connection.BuildInfoLiterals();
448                     }
449                     throw ODB.InvalidRestrictionsDbInfoLiteral("restrictions");
450                 }
451                 else if (OleDbSchemaGuid.SchemaGuids == schema) {
452                     if ((null == restrictions) || (0 == restrictions.Length)) {
453                         return connection.BuildSchemaGuids();
454                     }
455                     throw ODB.InvalidRestrictionsSchemaGuids("restrictions");
456                 }
457                 else if (OleDbSchemaGuid.DbInfoKeywords == schema) {
458                     if ((null == restrictions) || (0 == restrictions.Length)) {
459                         return connection.BuildInfoKeywords();
460                     }
461                     throw ODB.InvalidRestrictionsDbInfoKeywords("restrictions");
462                 }
463
464                 if (connection.SupportSchemaRowset(schema)) {
465                     return connection.GetSchemaRowset(schema, restrictions);
466                 }
467                 else {
468                     using(IDBSchemaRowsetWrapper wrapper = connection.IDBSchemaRowset()) {
469                         if (null == wrapper.Value) {
470                             throw ODB.SchemaRowsetsNotSupported(Provider); // MDAC 72689
471                         }
472                     }
473                     throw ODB.NotSupportedSchemaTable(schema, this); // MDAC 63279
474                 }
475             }
476             finally {
477                 Bid.ScopeLeave(ref hscp);
478             }
479         }
480
481         internal DataTable GetSchemaRowset(Guid schema, object[] restrictions) {
482             Debug.Assert(null != GetOpenConnection(), "GetSchemaRowset closed");
483             return GetOpenConnection().GetSchemaRowset(schema, restrictions);
484         }
485
486         internal bool HasLiveReader(OleDbCommand cmd)  {
487             bool result = false;
488             OleDbConnectionInternal openConnection = GetOpenConnection();
489
490             if (null != openConnection) {
491                 result = openConnection.HasLiveReader(cmd);
492             }
493             return result;
494         }
495
496         internal void OnInfoMessage(UnsafeNativeMethods.IErrorInfo errorInfo, OleDbHResult errorCode) {
497             OleDbInfoMessageEventHandler handler = (OleDbInfoMessageEventHandler) Events[EventInfoMessage];
498             if (null != handler) {
499                 try {
500                     OleDbException exception = OleDbException.CreateException(errorInfo, errorCode, null);
501                     OleDbInfoMessageEventArgs e = new OleDbInfoMessageEventArgs(exception);
502                     if (Bid.TraceOn) {
503                         Bid.Trace("<oledb.OledbConnection.OnInfoMessage|API|INFO> %d#, Message='%ls'\n", ObjectID, e.Message);
504                     }
505                     handler(this, e);
506                 }
507                 catch (Exception e) { // eat the exception
508                     // 
509                     if (!ADP.IsCatchableOrSecurityExceptionType(e)) {
510                         throw;
511                     }
512
513                     ADP.TraceExceptionWithoutRethrow(e);
514                 }
515             }
516 #if DEBUG
517             else {
518                 OleDbException exception = OleDbException.CreateException(errorInfo, errorCode, null);
519                 Bid.Trace("<oledb.OledbConnection.OnInfoMessage|API|INFO> %d#, Message='%ls'\n", ObjectID, exception.Message);
520             }
521 #endif
522         }
523         
524         override public void Open() {
525             InnerConnection.OpenConnection(this, ConnectionFactory);
526             
527             // SQLBUDT #276132 - need to manually enlist in some cases, because
528             // native OLE DB doesn't know about SysTx transactions.
529             if ((0!=(ODB.DBPROPVAL_OS_TXNENLISTMENT & ((OleDbConnectionString)(this.ConnectionOptions)).OleDbServices)) 
530                         && ADP.NeedManualEnlistment()) {
531                 GetOpenConnection().EnlistTransactionInternal(SysTx.Transaction.Current);
532             }
533         }
534
535         internal void SetDataSourcePropertyValue(Guid propertySet, int propertyID, string description, bool required, object value) {
536             CheckStateOpen(ADP.SetProperties);
537             OleDbHResult hr;
538             using(IDBPropertiesWrapper idbProperties = IDBProperties()) {
539                 using(DBPropSet propSet = DBPropSet.CreateProperty(propertySet, propertyID, required, value)) {
540                     
541                     Bid.Trace("<oledb.IDBProperties.SetProperties|API|OLEDB> %d#\n", ObjectID);
542                     hr = idbProperties.Value.SetProperties(propSet.PropertySetCount, propSet);
543                     Bid.Trace("<oledb.IDBProperties.SetProperties|API|OLEDB|RET> %08X{HRESULT}\n", hr);
544                     
545                     if (hr < 0) {
546                         Exception e = OleDbConnection.ProcessResults(hr, null, this);
547                         if (OleDbHResult.DB_E_ERRORSOCCURRED == hr) {
548
549                             StringBuilder builder = new StringBuilder();
550                             Debug.Assert(1 == propSet.PropertySetCount, "too many PropertySets");
551
552                             tagDBPROP[] dbprops = propSet.GetPropertySet(0, out propertySet);
553                             Debug.Assert(1 == dbprops.Length, "too many Properties");
554
555                             ODB.PropsetSetFailure(builder, description, dbprops[0].dwStatus);
556
557                             e = ODB.PropsetSetFailure(builder.ToString(), e);
558                         }
559                         if (null != e) {
560                             throw e;
561                         }
562                     }
563                     else {
564                         SafeNativeMethods.Wrapper.ClearErrorInfo();
565                     }
566                 }
567             }
568         }
569
570         internal bool SupportSchemaRowset(Guid schema) {
571             return GetOpenConnection().SupportSchemaRowset(schema);
572         }
573
574         internal OleDbTransaction ValidateTransaction(OleDbTransaction transaction, string method) {
575             return GetOpenConnection().ValidateTransaction(transaction, method);
576         }
577
578         static internal Exception ProcessResults(OleDbHResult hresult, OleDbConnection connection, object src) {
579             if ((0 <= (int)hresult) && ((null == connection) || (null == connection.Events[EventInfoMessage]))) {
580                 SafeNativeMethods.Wrapper.ClearErrorInfo();
581                 return null;
582             }
583
584             // ErrorInfo object is to be checked regardless the hresult returned by the function called
585             Exception e = null;
586             UnsafeNativeMethods.IErrorInfo errorInfo = null;
587             OleDbHResult hr = UnsafeNativeMethods.GetErrorInfo(0, out errorInfo);  // 0 - IErrorInfo exists, 1 - no IErrorInfo
588             if ((OleDbHResult.S_OK == hr) && (null != errorInfo)) {
589                 if (hresult < 0) {
590                     // 
591
592
593
594
595
596                     e = OleDbException.CreateException(errorInfo, hresult, null);
597                     //}
598
599                     if (OleDbHResult.DB_E_OBJECTOPEN == hresult) {
600                         e = ADP.OpenReaderExists(e);
601                     }
602
603                     ResetState(connection);
604                 }
605                 else if (null != connection) {
606                     connection.OnInfoMessage(errorInfo, hresult);
607                 }
608                 else {
609                     Bid.Trace("<oledb.OledbConnection|WARN|INFO> ErrorInfo available, but not connection %08X{HRESULT}\n", hresult);
610                 }
611                 Marshal.ReleaseComObject(errorInfo);
612             }
613             else if (0 < hresult) {
614                 // @devnote: OnInfoMessage with no ErrorInfo
615                 Bid.Trace("<oledb.OledbConnection|ERR|INFO> ErrorInfo not available %08X{HRESULT}\n", hresult);
616             }
617             else if ((int)hresult < 0) {
618                 e = ODB.NoErrorInformation((null != connection) ? connection.Provider : null, hresult, null); // OleDbException
619
620                 ResetState(connection);
621             }
622             if (null != e) {
623                 ADP.TraceExceptionAsReturnValue(e);
624             }
625             return e;
626         }
627
628         // @devnote: should be multithread safe
629         static public void ReleaseObjectPool() {
630             (new OleDbPermission(PermissionState.Unrestricted)).Demand();
631
632             IntPtr hscp;
633             Bid.ScopeEnter(out hscp, "<oledb.OleDbConnection.ReleaseObjectPool|API>\n");
634             try {
635                 OleDbConnectionString.ReleaseObjectPool();
636                 OleDbConnectionInternal.ReleaseObjectPool();
637                 OleDbConnectionFactory.SingletonInstance.ClearAllPools();
638             }
639             finally {
640                 Bid.ScopeLeave(ref hscp);
641             }
642         }
643
644         static private void ResetState(OleDbConnection connection) {
645             if (null != connection) {
646                 connection.ResetState();
647             }
648         }
649     }
650 }