Add MONO_PARTIAL_DATA_IMPORT.
[mono.git] / mcs / class / referencesource / System.Data / System / Data / ProviderBase / DbConnectionInternal.cs
1 //------------------------------------------------------------------------------
2 // <copyright file="DbConnectionInternal.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.ProviderBase {
10
11     using System;
12     using System.ComponentModel;
13     using System.Data;
14     using System.Data.Common;
15     using System.Diagnostics;
16     using System.Globalization;
17     using System.Runtime.ConstrainedExecution;
18     using System.Runtime.InteropServices;
19     using System.Runtime.InteropServices.ComTypes;
20     using System.Security;
21     using System.Security.Permissions;
22     using System.Threading;
23     using System.Threading.Tasks;
24     using SysTx = System.Transactions;
25
26     internal abstract class DbConnectionInternal { // V1.1.3300
27
28         
29         private static int _objectTypeCount;
30         internal readonly int _objectID = Interlocked.Increment(ref _objectTypeCount);
31
32         internal static readonly StateChangeEventArgs StateChangeClosed = new StateChangeEventArgs(ConnectionState.Open, ConnectionState.Closed);
33         internal static readonly StateChangeEventArgs StateChangeOpen   = new StateChangeEventArgs(ConnectionState.Closed, ConnectionState.Open);
34
35         private readonly bool            _allowSetConnectionString;
36         private readonly bool            _hidePassword;
37         private readonly ConnectionState _state;
38
39         private readonly WeakReference   _owningObject = new WeakReference(null, false);  // [usage must be thread safe] the owning object, when not in the pool. (both Pooled and Non-Pooled connections)
40
41         private DbConnectionPool         _connectionPool;           // the pooler that the connection came from (Pooled connections only)
42         private DbConnectionPoolCounters _performanceCounters;      // the performance counters we're supposed to update
43         private DbReferenceCollection    _referenceCollection;      // collection of objects that we need to notify in some way when we're being deactivated
44         private int                      _pooledCount;              // [usage must be thread safe] the number of times this object has been pushed into the pool less the number of times it's been popped (0 != inPool)
45
46         private bool                     _connectionIsDoomed;       // true when the connection should no longer be used.
47         private bool                     _cannotBePooled;           // true when the connection should no longer be pooled.
48         private bool                     _isInStasis;
49
50         private DateTime                 _createTime;               // when the connection was created.
51
52         private SysTx.Transaction        _enlistedTransaction;      // [usage must be thread-safe] the transaction that we're enlisted in, either manually or automatically
53
54         // _enlistedTransaction is a clone, so that transaction information can be queried even if the original transaction object is disposed.
55         // However, there are times when we need to know if the original transaction object was disposed, so we keep a reference to it here.
56         // This field should only be assigned a value at the same time _enlistedTransaction is updated.
57         // Also, this reference should not be disposed, since we aren't taking ownership of it.
58         private SysTx.Transaction _enlistedTransactionOriginal;     
59
60 #if DEBUG
61         private int                      _activateCount;            // debug only counter to verify activate/deactivates are in [....].
62 #endif //DEBUG
63
64         protected DbConnectionInternal() : this(ConnectionState.Open, true, false) { // V1.1.3300
65         }
66
67         // Constructor for internal connections
68         internal DbConnectionInternal(ConnectionState state, bool hidePassword, bool allowSetConnectionString) {
69             _allowSetConnectionString = allowSetConnectionString;
70             _hidePassword = hidePassword;
71             _state = state;
72         }
73
74         internal bool AllowSetConnectionString {
75             get {
76                 return _allowSetConnectionString;
77             }
78         }
79
80         internal bool CanBePooled {
81             get {
82                 bool flag = (!_connectionIsDoomed && !_cannotBePooled && !_owningObject.IsAlive);
83                 return flag;
84             }
85         }
86
87         protected internal SysTx.Transaction EnlistedTransaction {
88             get {
89                 return _enlistedTransaction;
90             }
91             set {
92                 SysTx.Transaction currentEnlistedTransaction = _enlistedTransaction;
93                 if (((null == currentEnlistedTransaction) && (null != value))
94                     || ((null != currentEnlistedTransaction) && !currentEnlistedTransaction.Equals(value))) {  // WebData 20000024
95
96                     // Pay attention to the order here:
97                     // 1) defect from any notifications
98                     // 2) replace the transaction
99                     // 3) re-enlist in notifications for the new transaction
100
101                     // SQLBUDT #230558 we need to use a clone of the transaction
102                     // when we store it, or we'll end up keeping it past the
103                     // duration of the using block of the TransactionScope
104                     SysTx.Transaction valueClone = null;
105                     SysTx.Transaction previousTransactionClone = null;
106                     try {
107                         if (null != value) {
108                             valueClone = value.Clone();
109                         }
110
111                         // NOTE: rather than take locks around several potential round-
112                         // trips to the server, and/or virtual function calls, we simply
113                         // presume that you aren't doing something illegal from multiple
114                         // threads, and check once we get around to finalizing things
115                         // inside a lock.
116
117                         lock(this) {
118                             // NOTE: There is still a race condition here, when we are
119                             // called from EnlistTransaction (which cannot re-enlist)
120                             // instead of EnlistDistributedTransaction (which can),
121                             // however this should have been handled by the outer
122                             // connection which checks to ensure that it's OK.  The
123                             // only case where we have the race condition is multiple
124                             // concurrent enlist requests to the same connection, which
125                             // is a bit out of line with something we should have to
126                             // support.
127
128                             // enlisted transaction can be nullified in Dispose call without lock
129                             previousTransactionClone = Interlocked.Exchange(ref _enlistedTransaction, valueClone);
130                             _enlistedTransactionOriginal = value;
131                             value = valueClone;
132                             valueClone = null; // we've stored it, don't dispose it.
133                         }
134                     }
135                     finally {
136                         // we really need to dispose our clones; they may have
137                         // native resources and GC may not happen soon enough.
138                         // VSDevDiv 479564: don't dispose if still holding reference in _enlistedTransaction
139                         if (null != previousTransactionClone && 
140                                 !Object.ReferenceEquals(previousTransactionClone, _enlistedTransaction)) {
141                             previousTransactionClone.Dispose();
142                         }
143                         if (null != valueClone && !Object.ReferenceEquals(valueClone, _enlistedTransaction)) {
144                             valueClone.Dispose();
145                         }
146                     }
147
148                     // I don't believe that we need to lock to protect the actual
149                     // enlistment in the transaction; it would only protect us
150                     // against multiple concurrent calls to enlist, which really
151                     // isn't supported anyway.
152
153                     if (null != value) {
154                         if (Bid.IsOn(DbConnectionPool.PoolerTracePoints)) {
155                             int x = value.GetHashCode();
156                             Bid.PoolerTrace("<prov.DbConnectionInternal.set_EnlistedTransaction|RES|CPOOL> %d#, Transaction %d#, Enlisting.\n", ObjectID, x);
157                         }
158                         TransactionOutcomeEnlist(value);
159                     }
160                 }
161             }
162         }
163
164         /// <summary>
165         /// Get boolean value that indicates whether the enlisted transaction has been disposed.
166         /// </summary>
167         /// <value>
168         /// True if there is an enlisted transaction, and it has been diposed.
169         /// False if there is an enlisted transaction that has not been disposed, or if the transaction reference is null.
170         /// </value>
171         /// <remarks>
172         /// This method must be called while holding a lock on the DbConnectionInternal instance.
173         /// </remarks>
174         protected bool EnlistedTransactionDisposed
175         {
176             get
177             {
178                 // Until the Transaction.Disposed property is public it is necessary to access a member
179                 // that throws if the object is disposed to determine if in fact the transaction is disposed.
180                 try
181                 {
182                     bool disposed;
183
184                     SysTx.Transaction currentEnlistedTransactionOriginal = _enlistedTransactionOriginal;
185                     if (currentEnlistedTransactionOriginal != null)
186                     {
187                         disposed = currentEnlistedTransactionOriginal.TransactionInformation == null;
188                     }
189                     else
190                     {
191                         // Don't expect to get here in the general case,
192                         // Since this getter is called by CheckEnlistedTransactionBinding
193                         // after checking for a non-null enlisted transaction (and it does so under lock).
194                         disposed = false;
195                     }
196
197                     return disposed;
198                 }
199                 catch (ObjectDisposedException)
200                 {
201                     return true;
202                 }
203             }
204         }
205
206         // Is this connection in stasis, waiting for transaction to end before returning to pool?
207         internal bool IsTxRootWaitingForTxEnd {
208             get {
209                 return _isInStasis;
210             }
211         }
212
213         /// <summary>
214         /// Get boolean that specifies whether an enlisted transaction can be unbound from 
215         /// the connection when that transaction completes.
216         /// </summary>
217         /// <value>
218         /// True if the enlisted transaction can be unbound on transaction completion; otherwise false.
219         /// </value>
220         virtual protected bool UnbindOnTransactionCompletion
221         {
222             get
223             {
224                 return true;
225             }
226         }
227
228         // Is this a connection that must be put in stasis (or is already in stasis) pending the end of it's transaction?
229         virtual protected internal bool IsNonPoolableTransactionRoot {
230             get {
231                 return false; // if you want to have delegated transactions that are non-poolable, you better override this...
232             }
233         }
234
235         virtual internal bool IsTransactionRoot {
236             get {
237                 return false; // if you want to have delegated transactions, you better override this...
238             }
239         }
240
241         protected internal bool IsConnectionDoomed {
242             get {
243                 return _connectionIsDoomed;
244             }
245         }
246
247         internal bool IsEmancipated {
248             get {
249                 // NOTE: There are race conditions between PrePush, PostPop and this
250                 //       property getter -- only use this while this object is locked;
251                 //       (DbConnectionPool.Clear and ReclaimEmancipatedObjects
252                 //       do this for us)
253
254                 // Remember how this works (I keep getting confused...)
255                 //
256                 //    _pooledCount is incremented when the connection is pushed into the pool
257                 //    _pooledCount is decremented when the connection is popped from the pool
258                 //    _pooledCount is set to -1 when the connection is not pooled (just in case...)
259                 //
260                 // That means that:
261                 //
262                 //    _pooledCount > 1    connection is in the pool multiple times (this is a serious bug...)
263                 //    _pooledCount == 1   connection is in the pool
264                 //    _pooledCount == 0   connection is out of the pool
265                 //    _pooledCount == -1  connection is not a pooled connection; we shouldn't be here for non-pooled connections.
266                 //    _pooledCount < -1   connection out of the pool multiple times (not sure how this could happen...)
267                 //
268                 // Now, our job is to return TRUE when the connection is out
269                 // of the pool and it's owning object is no longer around to
270                 // return it.
271
272                 bool value = !IsTxRootWaitingForTxEnd && (_pooledCount < 1) && !_owningObject.IsAlive;
273                 return value;
274             }
275         }
276
277         internal bool IsInPool {
278             get {
279                 Debug.Assert(_pooledCount <= 1 && _pooledCount >= -1, "Pooled count for object is invalid");
280                 return (_pooledCount == 1);
281             }
282         }
283
284         internal int ObjectID {
285             get {
286                 return _objectID;
287             }
288         }
289
290         protected internal object Owner {
291             // We use a weak reference to the owning object so we can identify when
292             // it has been garbage collected without thowing exceptions.
293             get {
294                 return _owningObject.Target;
295             }
296         }
297
298         internal DbConnectionPool Pool {
299             get {
300                 return _connectionPool;
301             }
302         }
303
304         protected DbConnectionPoolCounters PerformanceCounters {
305             get {
306                 return _performanceCounters;
307             }
308         }
309
310         virtual protected bool ReadyToPrepareTransaction {
311             get {
312                 return true;
313             }
314         }
315
316         protected internal DbReferenceCollection ReferenceCollection {
317             get {
318                 return _referenceCollection;
319             }
320         }
321
322         abstract public string ServerVersion {
323             get;
324         }
325
326         // this should be abstract but untill it is added to all the providers virtual will have to do [....]
327         virtual public string ServerVersionNormalized {
328             get{
329                 throw ADP.NotSupported();
330             }
331         }
332
333         public bool ShouldHidePassword {
334             get {
335                 return _hidePassword;
336             }
337         }
338
339         public ConnectionState State {
340             get {
341                 return _state;
342             }
343         }
344
345         abstract protected void Activate(SysTx.Transaction transaction);
346
347         internal void ActivateConnection(SysTx.Transaction transaction) {
348             // Internal method called from the connection pooler so we don't expose
349             // the Activate method publicly.
350
351             Bid.PoolerTrace("<prov.DbConnectionInternal.ActivateConnection|RES|INFO|CPOOL> %d#, Activating\n", ObjectID);
352 #if DEBUG
353             int activateCount = Interlocked.Increment(ref _activateCount);
354             Debug.Assert(1 == activateCount, "activated multiple times?");
355 #endif // DEBUG
356
357             Activate(transaction);
358
359 #if !MOBILE
360             PerformanceCounters.NumberOfActiveConnections.Increment();
361 #endif
362         }
363
364         internal void AddWeakReference(object value, int tag) {
365             if (null == _referenceCollection) {
366                 _referenceCollection = CreateReferenceCollection();
367                 if (null == _referenceCollection) {
368                     throw ADP.InternalError(ADP.InternalErrorCode.CreateReferenceCollectionReturnedNull);
369                 }
370             }
371             _referenceCollection.Add(value, tag);
372         }
373
374         abstract public DbTransaction BeginTransaction(IsolationLevel il);
375
376         virtual public void ChangeDatabase(string value) {
377             throw ADP.MethodNotImplemented("ChangeDatabase");
378         }
379
380         internal virtual void CloseConnection(DbConnection owningObject, DbConnectionFactory connectionFactory) {
381             // The implementation here is the implementation required for the
382             // "open" internal connections, since our own private "closed"
383             // singleton internal connection objects override this method to
384             // prevent anything funny from happening (like disposing themselves
385             // or putting them into a connection pool)
386             //
387             // Derived class should override DbConnectionInternal.Deactivate and DbConnectionInternal.Dispose
388             // for cleaning up after DbConnection.Close
389             //     protected override void Deactivate() { // override DbConnectionInternal.Close
390             //         // do derived class connection deactivation for both pooled & non-pooled connections
391             //     }
392             //     public override void Dispose() { // override DbConnectionInternal.Close
393             //         // do derived class cleanup
394             //         base.Dispose();
395             //     }
396             //
397             // overriding DbConnection.Close is also possible, but must provider for their own synchronization
398             //     public override void Close() { // override DbConnection.Close
399             //         base.Close();
400             //         // do derived class outer connection for both pooled & non-pooled connections
401             //         // user must do their own synchronization here
402             //     }
403             //
404             //     if the DbConnectionInternal derived class needs to close the connection it should
405             //     delegate to the DbConnection if one exists or directly call dispose
406             //         DbConnection owningObject = (DbConnection)Owner;
407             //         if (null != owningObject) {
408             //             owningObject.Close(); // force the closed state on the outer object.
409             //         }
410             //         else {
411             //             Dispose();
412             //         }
413             //
414             ////////////////////////////////////////////////////////////////
415             // DON'T MESS WITH THIS CODE UNLESS YOU KNOW WHAT YOU'RE DOING!
416             ////////////////////////////////////////////////////////////////
417             Debug.Assert(null != owningObject, "null owningObject");
418             Debug.Assert(null != connectionFactory, "null connectionFactory");
419
420             Bid.PoolerTrace("<prov.DbConnectionInternal.CloseConnection|RES|CPOOL> %d# Closing.\n", ObjectID);
421
422             // if an exception occurs after the state change but before the try block
423             // the connection will be stuck in OpenBusy state.  The commented out try-catch
424             // block doesn't really help because a ThreadAbort during the finally block
425             // would just refert the connection to a bad state.
426             // Open->Closed: guarantee internal connection is returned to correct pool
427             if (connectionFactory.SetInnerConnectionFrom(owningObject, DbConnectionOpenBusy.SingletonInstance, this)) {
428                 
429                 // Lock to prevent race condition with cancellation
430                 lock (this) {
431
432                     object lockToken = ObtainAdditionalLocksForClose();
433                     try {
434                         PrepareForCloseConnection();
435
436                         DbConnectionPool connectionPool = Pool;
437
438                         // Detach from enlisted transactions that are no longer active on close
439                         DetachCurrentTransactionIfEnded();
440
441                         // The singleton closed classes won't have owners and
442                         // connection pools, and we won't want to put them back
443                         // into the pool.
444                         if (null != connectionPool) {
445                             connectionPool.PutObject(this, owningObject);   // PutObject calls Deactivate for us...
446                             // NOTE: Before we leave the PutObject call, another
447                             // thread may have already popped the connection from
448                             // the pool, so don't expect to be able to verify it.
449                         }
450                         else {
451                             Deactivate();   // ensure we de-activate non-pooled connections, or the data readers and transactions may not get cleaned up...
452
453 #if !MOBILE
454                             PerformanceCounters.HardDisconnectsPerSecond.Increment();
455 #endif
456                         
457                             // To prevent an endless recursion, we need to clear
458                             // the owning object before we call dispose so that
459                             // we can't get here a second time... Ordinarily, I
460                             // would call setting the owner to null a hack, but
461                             // this is safe since we're about to dispose the
462                             // object and it won't have an owner after that for
463                             // certain.
464                             _owningObject.Target = null;
465
466                             if (IsTransactionRoot) {
467                                 SetInStasis();                           
468                             }
469                             else {
470 #if MONO_PARTIAL_DATA_IMPORT
471                                 Dispose();
472 #else
473 #if !MOBILE
474                                 PerformanceCounters.NumberOfNonPooledConnections.Decrement();
475 #endif
476                                 if (this.GetType() != typeof(System.Data.SqlClient.SqlInternalConnectionSmi))
477                                 {
478                                     Dispose();
479                                 }
480 #endif
481                             }
482                         }
483                     }
484                     finally {
485                         ReleaseAdditionalLocksForClose(lockToken);
486                         // if a ThreadAbort puts us here then its possible the outer connection will not reference
487                         // this and this will be orphaned, not reclaimed by object pool until outer connection goes out of scope.
488                         connectionFactory.SetInnerConnectionEvent(owningObject, DbConnectionClosedPreviouslyOpened.SingletonInstance);
489                     }
490                 }
491             }
492         }
493
494         virtual internal void PrepareForReplaceConnection() {
495             // By default, there is no preperation required
496         }
497
498         virtual protected void PrepareForCloseConnection() {
499             // By default, there is no preperation required
500         }
501
502         virtual protected object ObtainAdditionalLocksForClose() {
503             return null; // no additional locks in default implementation
504         }
505
506         virtual protected void ReleaseAdditionalLocksForClose(object lockToken) {
507             // no additional locks in default implementation
508         }
509
510         virtual protected DbReferenceCollection CreateReferenceCollection() {
511             throw ADP.InternalError(ADP.InternalErrorCode.AttemptingToConstructReferenceCollectionOnStaticObject);
512         }
513
514         abstract protected void Deactivate();
515
516         internal void DeactivateConnection() {
517             // Internal method called from the connection pooler so we don't expose
518             // the Deactivate method publicly.
519
520             Bid.PoolerTrace("<prov.DbConnectionInternal.DeactivateConnection|RES|INFO|CPOOL> %d#, Deactivating\n", ObjectID);
521 #if DEBUG
522             int activateCount = Interlocked.Decrement(ref _activateCount);
523             Debug.Assert(0 == activateCount, "activated multiple times?");
524 #endif // DEBUG
525
526 #if !MOBILE
527             if (PerformanceCounters != null) { // Pool.Clear will DestroyObject that will clean performanceCounters before going here 
528                 PerformanceCounters.NumberOfActiveConnections.Decrement();
529             }
530 #endif
531
532             if (!_connectionIsDoomed && Pool.UseLoadBalancing) {
533                 // If we're not already doomed, check the connection's lifetime and
534                 // doom it if it's lifetime has elapsed.
535
536                 DateTime now = DateTime.UtcNow;  // WebData 111116
537                 if ((now.Ticks - _createTime.Ticks) > Pool.LoadBalanceTimeout.Ticks) {
538                     DoNotPoolThisConnection();
539                 }
540             }
541             Deactivate();
542         }
543
544         virtual internal void DelegatedTransactionEnded() {
545             // Called by System.Transactions when the delegated transaction has
546             // completed.  We need to make closed connections that are in stasis
547             // available again, or disposed closed/leaked non-pooled connections.
548
549             // IMPORTANT NOTE: You must have taken a lock on the object before
550             // you call this method to prevent race conditions with Clear and
551             // ReclaimEmancipatedObjects.
552
553             Bid.Trace("<prov.DbConnectionInternal.DelegatedTransactionEnded|RES|CPOOL> %d#, Delegated Transaction Completed.\n", ObjectID);
554
555             if (1 == _pooledCount) {
556                 // When _pooledCount is 1, it indicates a closed, pooled,
557                 // connection so it is ready to put back into the pool for
558                 // general use.
559
560                 TerminateStasis(true);
561
562                 Deactivate(); // call it one more time just in case
563
564                 DbConnectionPool pool = Pool;
565
566                 if (null == pool) {
567                     throw ADP.InternalError(ADP.InternalErrorCode.PooledObjectWithoutPool);      // pooled connection does not have a pool
568                 }
569                 pool.PutObjectFromTransactedPool(this);
570             }
571             else if (-1 == _pooledCount && !_owningObject.IsAlive) {
572                 // When _pooledCount is -1 and the owning object no longer exists,
573                 // it indicates a closed (or leaked), non-pooled connection so 
574                 // it is safe to dispose.
575
576                 TerminateStasis(false);
577         
578                 Deactivate(); // call it one more time just in case
579
580                 // it's a non-pooled connection, we need to dispose of it
581                 // once and for all, or the server will have fits about us
582                 // leaving connections open until the client-side GC kicks 
583                 // in.
584 #if !MOBILE
585                 PerformanceCounters.NumberOfNonPooledConnections.Decrement();
586 #endif
587                 Dispose();
588             }
589             // When _pooledCount is 0, the connection is a pooled connection
590             // that is either open (if the owning object is alive) or leaked (if
591             // the owning object is not alive)  In either case, we can't muck 
592             // with the connection here.
593         }
594
595         public virtual void Dispose()
596         {
597             _connectionPool = null;
598             _performanceCounters = null;
599             _connectionIsDoomed = true;
600             _enlistedTransactionOriginal = null; // should not be disposed
601
602             // Dispose of the _enlistedTransaction since it is a clone
603             // of the original reference.
604             // VSDD 780271 - _enlistedTransaction can be changed by another thread (TX end event)
605             SysTx.Transaction enlistedTransaction = Interlocked.Exchange(ref _enlistedTransaction, null);
606             if (enlistedTransaction != null)
607             {
608                 enlistedTransaction.Dispose();
609             }
610         }
611
612         protected internal void DoNotPoolThisConnection() {
613             _cannotBePooled = true;
614             Bid.PoolerTrace("<prov.DbConnectionInternal.DoNotPoolThisConnection|RES|INFO|CPOOL> %d#, Marking pooled object as non-poolable so it will be disposed\n", ObjectID);
615         }
616
617         /// <devdoc>Ensure that this connection cannot be put back into the pool.</devdoc>
618         [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
619         protected internal void DoomThisConnection() {
620             _connectionIsDoomed = true;
621             Bid.PoolerTrace("<prov.DbConnectionInternal.DoomThisConnection|RES|INFO|CPOOL> %d#, Dooming\n", ObjectID);
622         }
623
624         abstract public void EnlistTransaction(SysTx.Transaction transaction);
625
626         virtual protected internal DataTable GetSchema(DbConnectionFactory factory, DbConnectionPoolGroup poolGroup, DbConnection outerConnection, string collectionName, string[] restrictions){
627             Debug.Assert(outerConnection != null,"outerConnection may not be null.");
628
629             DbMetaDataFactory metaDataFactory = factory.GetMetaDataFactory(poolGroup, this);
630             Debug.Assert(metaDataFactory != null,"metaDataFactory may not be null.");
631
632             return metaDataFactory.GetSchema(outerConnection, collectionName,restrictions);
633         }
634
635         internal void MakeNonPooledObject(object owningObject, DbConnectionPoolCounters performanceCounters) {
636             // Used by DbConnectionFactory to indicate that this object IS NOT part of
637             // a connection pool.
638
639             _connectionPool = null;
640             _performanceCounters = performanceCounters;
641             _owningObject.Target = owningObject;
642             _pooledCount = -1;
643         }
644
645         internal void MakePooledConnection(DbConnectionPool connectionPool) {
646             // Used by DbConnectionFactory to indicate that this object IS part of
647             // a connection pool.
648
649             // 
650             _createTime = DateTime.UtcNow; // WebData 111116
651
652             _connectionPool = connectionPool;
653             _performanceCounters = connectionPool.PerformanceCounters;
654         }
655
656         internal void NotifyWeakReference(int message) {
657             DbReferenceCollection referenceCollection = ReferenceCollection;
658             if (null != referenceCollection) {
659                 referenceCollection.Notify(message);
660             }
661         }
662
663         internal virtual void OpenConnection(DbConnection outerConnection, DbConnectionFactory connectionFactory) {
664             if (!TryOpenConnection(outerConnection, connectionFactory, null, null)) {
665                 throw ADP.InternalError(ADP.InternalErrorCode.SynchronousConnectReturnedPending);
666             }
667         }
668
669         /// <devdoc>The default implementation is for the open connection objects, and
670         /// it simply throws.  Our private closed-state connection objects
671         /// override this and do the correct thing.</devdoc>
672         // User code should either override DbConnectionInternal.Activate when it comes out of the pool
673         // or override DbConnectionFactory.CreateConnection when the connection is created for non-pooled connections
674         internal virtual bool TryOpenConnection(DbConnection outerConnection, DbConnectionFactory connectionFactory, TaskCompletionSource<DbConnectionInternal> retry, DbConnectionOptions userOptions) {
675             throw ADP.ConnectionAlreadyOpen(State);
676         }
677
678         internal virtual bool TryReplaceConnection(DbConnection outerConnection, DbConnectionFactory connectionFactory, TaskCompletionSource<DbConnectionInternal> retry, DbConnectionOptions userOptions) {
679             throw ADP.MethodNotImplemented("TryReplaceConnection");
680         }
681
682         protected bool TryOpenConnectionInternal(DbConnection outerConnection, DbConnectionFactory connectionFactory, TaskCompletionSource<DbConnectionInternal> retry, DbConnectionOptions userOptions) {
683             // ?->Connecting: prevent set_ConnectionString during Open
684             if (connectionFactory.SetInnerConnectionFrom(outerConnection, DbConnectionClosedConnecting.SingletonInstance, this)) {
685                 DbConnectionInternal openConnection = null;
686                 try {
687                     connectionFactory.PermissionDemand(outerConnection);
688                     if (!connectionFactory.TryGetConnection(outerConnection, retry, userOptions, this, out openConnection)) {
689                         return false;
690                     }
691                 }
692                 catch {
693                     // This should occure for all exceptions, even ADP.UnCatchableExceptions.
694                     connectionFactory.SetInnerConnectionTo(outerConnection, this);
695                     throw;
696                 }
697                 if (null == openConnection) {
698                     connectionFactory.SetInnerConnectionTo(outerConnection, this);
699                     throw ADP.InternalConnectionError(ADP.ConnectionError.GetConnectionReturnsNull);
700                 }
701                 connectionFactory.SetInnerConnectionEvent(outerConnection, openConnection);
702             }
703
704             return true;
705         }
706
707         internal void PrePush(object expectedOwner) {
708             // Called by DbConnectionPool when we're about to be put into it's pool, we
709             // take this opportunity to ensure ownership and pool counts are legit.
710
711             // IMPORTANT NOTE: You must have taken a lock on the object before
712             // you call this method to prevent race conditions with Clear and
713             // ReclaimEmancipatedObjects.
714
715             //3 // The following tests are retail assertions of things we can't allow to happen.
716             if (null == expectedOwner) {
717                 if (null != _owningObject.Target) {
718                     throw ADP.InternalError(ADP.InternalErrorCode.UnpooledObjectHasOwner);      // new unpooled object has an owner
719                 }
720             }
721             else if (_owningObject.Target != expectedOwner) {
722                 throw ADP.InternalError(ADP.InternalErrorCode.UnpooledObjectHasWrongOwner); // unpooled object has incorrect owner
723             }
724             if (0 != _pooledCount) {
725                 throw ADP.InternalError(ADP.InternalErrorCode.PushingObjectSecondTime);         // pushing object onto stack a second time
726             }
727             if (Bid.IsOn(DbConnectionPool.PoolerTracePoints)) {
728                 //DbConnection x = (expectedOwner as DbConnection);
729                 Bid.PoolerTrace("<prov.DbConnectionInternal.PrePush|RES|CPOOL> %d#, Preparing to push into pool, owning connection %d#, pooledCount=%d\n", ObjectID, 0, _pooledCount);
730             }
731             _pooledCount++;
732             _owningObject.Target = null; // NOTE: doing this and checking for InternalError.PooledObjectHasOwner degrades the close by 2%
733         }
734
735         internal void PostPop(object newOwner) {
736             // Called by DbConnectionPool right after it pulls this from it's pool, we
737             // take this opportunity to ensure ownership and pool counts are legit.
738
739             Debug.Assert(!IsEmancipated,"pooled object not in pool");
740             
741             // SQLBUDT #356871 -- When another thread is clearing this pool, it 
742             // will doom all connections in this pool without prejudice which 
743             // causes the following assert to fire, which really mucks up stress 
744             // against checked bits.  The assert is benign, so we're commenting 
745             // it out.
746             //Debug.Assert(CanBePooled,   "pooled object is not poolable");
747
748             // IMPORTANT NOTE: You must have taken a lock on the object before
749             // you call this method to prevent race conditions with Clear and
750             // ReclaimEmancipatedObjects.
751
752             if (null != _owningObject.Target) {
753                 throw ADP.InternalError(ADP.InternalErrorCode.PooledObjectHasOwner);        // pooled connection already has an owner!
754             }
755             _owningObject.Target = newOwner;
756             _pooledCount--;
757             if (Bid.IsOn(DbConnectionPool.PoolerTracePoints)) {
758                 //DbConnection x = (newOwner as DbConnection);
759                 Bid.PoolerTrace("<prov.DbConnectionInternal.PostPop|RES|CPOOL> %d#, Preparing to pop from pool,  owning connection %d#, pooledCount=%d\n", ObjectID, 0, _pooledCount);
760             }
761             //3 // The following tests are retail assertions of things we can't allow to happen.
762             if (null != Pool) {
763                 if (0 != _pooledCount) {
764                     throw ADP.InternalError(ADP.InternalErrorCode.PooledObjectInPoolMoreThanOnce);  // popping object off stack with multiple pooledCount
765                 }
766             }
767             else if (-1 != _pooledCount) {
768                 throw ADP.InternalError(ADP.InternalErrorCode.NonPooledObjectUsedMoreThanOnce); // popping object off stack with multiple pooledCount
769             }
770         }
771
772         internal void RemoveWeakReference(object value) {
773             DbReferenceCollection referenceCollection = ReferenceCollection;
774             if (null != referenceCollection) {
775                 referenceCollection.Remove(value);
776             }
777         }
778
779         // Cleanup connection's transaction-specific structures (currently used by Delegated transaction).
780         //  This is a separate method because cleanup can be triggered in multiple ways for a delegated
781         //  transaction.
782         virtual protected void CleanupTransactionOnCompletion(SysTx.Transaction transaction) {
783         }
784
785         internal void DetachCurrentTransactionIfEnded() {
786             SysTx.Transaction enlistedTransaction = EnlistedTransaction;
787             if (enlistedTransaction != null) {
788                 bool transactionIsDead;
789                 try {
790                     transactionIsDead = (SysTx.TransactionStatus.Active != enlistedTransaction.TransactionInformation.Status);
791                 }
792                 catch (SysTx.TransactionException) {
793                     // If the transaction is being processed (i.e. is part way through a rollback\commit\etc then TransactionInformation.Status will throw an exception)
794                     transactionIsDead = true;
795                 }
796                 if  (transactionIsDead) {
797                     DetachTransaction(enlistedTransaction, true);
798                 }
799             }
800         }
801
802         // Detach transaction from connection.
803         internal void DetachTransaction(SysTx.Transaction transaction, bool isExplicitlyReleasing) {
804             Bid.Trace("<prov.DbConnectionInternal.DetachTransaction|RES|CPOOL> %d#, Transaction Completed. (pooledCount=%d)\n", ObjectID, _pooledCount);
805
806             // potentially a multi-threaded event, so lock the connection to make sure we don't enlist in a new
807             // transaction between compare and assignment. No need to short circuit outside of lock, since failed comparisons should
808             // be the exception, not the rule.
809             lock (this) {
810                 // Detach if detach-on-end behavior, or if outer connection was closed
811                 DbConnection owner = (DbConnection)Owner;
812                 if (isExplicitlyReleasing || UnbindOnTransactionCompletion || null == owner) {
813                     SysTx.Transaction currentEnlistedTransaction = _enlistedTransaction;
814                     if (currentEnlistedTransaction != null && transaction.Equals(currentEnlistedTransaction)) {
815
816                         EnlistedTransaction = null;
817
818                         if (IsTxRootWaitingForTxEnd) {
819                             DelegatedTransactionEnded();
820                         }
821                     }
822                 }
823             }
824         }
825
826         // Handle transaction detach, pool cleanup and other post-transaction cleanup tasks associated with
827         internal void CleanupConnectionOnTransactionCompletion(SysTx.Transaction transaction) {
828             DetachTransaction(transaction, false);
829
830             DbConnectionPool pool = Pool;
831             if (null != pool) {
832                 pool.TransactionEnded(transaction, this);
833             }
834         }
835
836         void TransactionCompletedEvent(object sender, SysTx.TransactionEventArgs e) {
837             SysTx.Transaction transaction = e.Transaction;
838
839             Bid.Trace("<prov.DbConnectionInternal.TransactionCompletedEvent|RES|CPOOL> %d#, Transaction Completed. (pooledCount=%d)\n", ObjectID, _pooledCount);
840
841             CleanupTransactionOnCompletion(transaction);
842
843             CleanupConnectionOnTransactionCompletion(transaction);
844         }
845
846
847         // 
848         [SecurityPermission(SecurityAction.Assert, Flags=SecurityPermissionFlag.UnmanagedCode)]
849         private void TransactionOutcomeEnlist(SysTx.Transaction transaction) {
850             transaction.TransactionCompleted += new SysTx.TransactionCompletedEventHandler(TransactionCompletedEvent);
851         }
852
853         internal void SetInStasis() {
854             _isInStasis = true;
855             Bid.PoolerTrace("<prov.DbConnectionInternal.SetInStasis|RES|CPOOL> %d#, Non-Pooled Connection has Delegated Transaction, waiting to Dispose.\n", ObjectID);
856 #if !MOBILE
857             PerformanceCounters.NumberOfStasisConnections.Increment();
858 #endif
859         }
860
861         private void TerminateStasis(bool returningToPool) {
862             if (returningToPool) {
863                 Bid.PoolerTrace("<prov.DbConnectionInternal.TerminateStasis|RES|CPOOL> %d#, Delegated Transaction has ended, connection is closed.  Returning to general pool.\n", ObjectID);
864             }
865             else {
866                 Bid.PoolerTrace("<prov.DbConnectionInternal.TerminateStasis|RES|CPOOL> %d#, Delegated Transaction has ended, connection is closed/leaked.  Disposing.\n", ObjectID);
867             }
868 #if !MOBILE
869             PerformanceCounters.NumberOfStasisConnections.Decrement();
870 #endif
871             _isInStasis = false;
872         }
873
874         /// <summary>
875         /// When overridden in a derived class, will check if the underlying connection is still actually alive
876         /// </summary>
877         /// <param name="throwOnException">If true an exception will be thrown if the connection is dead instead of returning true\false
878         /// (this allows the caller to have the real reason that the connection is not alive (e.g. network error, etc))</param>
879         /// <returns>True if the connection is still alive, otherwise false (If not overridden, then always true)</returns>
880         internal virtual bool IsConnectionAlive(bool throwOnException = false)
881         {
882             return true;
883         }
884     }
885 }