1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
4 
5 
6 
7 //------------------------------------------------------------------------------
8 
9 using System.Data.Common;
10 using System.Diagnostics;
11 using System.Threading.Tasks;
12 using System.Transactions;
13 
14 
15 namespace System.Data.ProviderBase
16 {
17     abstract internal class DbConnectionClosed : DbConnectionInternal
18     {
19         // Construct an "empty" connection
DbConnectionClosed(ConnectionState state, bool hidePassword, bool allowSetConnectionString)20         protected DbConnectionClosed(ConnectionState state, bool hidePassword, bool allowSetConnectionString) : base(state, hidePassword, allowSetConnectionString)
21         {
22         }
23 
24         public override string ServerVersion
25         {
26             get
27             {
28                 throw ADP.ClosedConnectionError();
29             }
30         }
31 
Activate(Transaction transaction)32         protected override void Activate(Transaction transaction)
33         {
34             throw ADP.ClosedConnectionError();
35         }
36 
BeginTransaction(IsolationLevel il)37         public override DbTransaction BeginTransaction(IsolationLevel il)
38         {
39             throw ADP.ClosedConnectionError();
40         }
41 
ChangeDatabase(string database)42         public override void ChangeDatabase(string database)
43         {
44             throw ADP.ClosedConnectionError();
45         }
46 
CloseConnection(DbConnection owningObject, DbConnectionFactory connectionFactory)47         internal override void CloseConnection(DbConnection owningObject, DbConnectionFactory connectionFactory)
48         {
49             // not much to do here...
50         }
51 
Deactivate()52         protected override void Deactivate()
53         {
54             throw ADP.ClosedConnectionError();
55         }
56 
EnlistTransaction(Transaction transaction)57         public override void EnlistTransaction(Transaction transaction)
58         {
59             throw ADP.ClosedConnectionError();
60         }
61 
CreateReferenceCollection()62         protected override DbReferenceCollection CreateReferenceCollection()
63         {
64             throw ADP.ClosedConnectionError();
65         }
66 
TryOpenConnection(DbConnection outerConnection, DbConnectionFactory connectionFactory, TaskCompletionSource<DbConnectionInternal> retry, DbConnectionOptions userOptions)67         internal override bool TryOpenConnection(DbConnection outerConnection, DbConnectionFactory connectionFactory, TaskCompletionSource<DbConnectionInternal> retry, DbConnectionOptions userOptions)
68         {
69             return base.TryOpenConnectionInternal(outerConnection, connectionFactory, retry, userOptions);
70         }
71     }
72 
73     abstract internal class DbConnectionBusy : DbConnectionClosed
74     {
DbConnectionBusy(ConnectionState state)75         protected DbConnectionBusy(ConnectionState state) : base(state, true, false)
76         {
77         }
78 
TryOpenConnection(DbConnection outerConnection, DbConnectionFactory connectionFactory, TaskCompletionSource<DbConnectionInternal> retry, DbConnectionOptions userOptions)79         internal override bool TryOpenConnection(DbConnection outerConnection, DbConnectionFactory connectionFactory, TaskCompletionSource<DbConnectionInternal> retry, DbConnectionOptions userOptions)
80         {
81             throw ADP.ConnectionAlreadyOpen(State);
82         }
83     }
84 
85     sealed internal class DbConnectionClosedBusy : DbConnectionBusy
86     {
87         // Closed Connection, Currently Busy - changing connection string
88         internal static readonly DbConnectionInternal SingletonInstance = new DbConnectionClosedBusy();   // singleton object
89 
DbConnectionClosedBusy()90         private DbConnectionClosedBusy() : base(ConnectionState.Closed)
91         {
92         }
93     }
94 
95     sealed internal class DbConnectionOpenBusy : DbConnectionBusy
96     {
97         // Open Connection, Currently Busy - closing connection
98         internal static readonly DbConnectionInternal SingletonInstance = new DbConnectionOpenBusy();   // singleton object
99 
DbConnectionOpenBusy()100         private DbConnectionOpenBusy() : base(ConnectionState.Open)
101         {
102         }
103     }
104 
105     sealed internal class DbConnectionClosedConnecting : DbConnectionBusy
106     {
107         // Closed Connection, Currently Connecting
108 
109         internal static readonly DbConnectionInternal SingletonInstance = new DbConnectionClosedConnecting();   // singleton object
110 
DbConnectionClosedConnecting()111         private DbConnectionClosedConnecting() : base(ConnectionState.Connecting)
112         {
113         }
114 
CloseConnection(DbConnection owningObject, DbConnectionFactory connectionFactory)115         internal override void CloseConnection(DbConnection owningObject, DbConnectionFactory connectionFactory)
116         {
117             connectionFactory.SetInnerConnectionTo(owningObject, DbConnectionClosedPreviouslyOpened.SingletonInstance);
118         }
119 
TryReplaceConnection(DbConnection outerConnection, DbConnectionFactory connectionFactory, TaskCompletionSource<DbConnectionInternal> retry, DbConnectionOptions userOptions)120         internal override bool TryReplaceConnection(DbConnection outerConnection, DbConnectionFactory connectionFactory, TaskCompletionSource<DbConnectionInternal> retry, DbConnectionOptions userOptions)
121         {
122             return TryOpenConnection(outerConnection, connectionFactory, retry, userOptions);
123         }
124 
TryOpenConnection(DbConnection outerConnection, DbConnectionFactory connectionFactory, TaskCompletionSource<DbConnectionInternal> retry, DbConnectionOptions userOptions)125         internal override bool TryOpenConnection(DbConnection outerConnection, DbConnectionFactory connectionFactory, TaskCompletionSource<DbConnectionInternal> retry, DbConnectionOptions userOptions)
126         {
127             if (retry == null || !retry.Task.IsCompleted)
128             {
129                 // retry is null if this is a synchronous call
130 
131                 // if someone calls Open or OpenAsync while in this state,
132                 // then the retry task will not be completed
133 
134                 throw ADP.ConnectionAlreadyOpen(State);
135             }
136 
137             // we are completing an asynchronous open
138             Debug.Assert(retry.Task.Status == TaskStatus.RanToCompletion, "retry task must be completed successfully");
139             DbConnectionInternal openConnection = retry.Task.Result;
140             if (null == openConnection)
141             {
142                 connectionFactory.SetInnerConnectionTo(outerConnection, this);
143                 throw ADP.InternalConnectionError(ADP.ConnectionError.GetConnectionReturnsNull);
144             }
145             connectionFactory.SetInnerConnectionEvent(outerConnection, openConnection);
146 
147             return true;
148         }
149     }
150 
151     sealed internal class DbConnectionClosedNeverOpened : DbConnectionClosed
152     {
153         // Closed Connection, Has Never Been Opened
154 
155         internal static readonly DbConnectionInternal SingletonInstance = new DbConnectionClosedNeverOpened();   // singleton object
156 
DbConnectionClosedNeverOpened()157         private DbConnectionClosedNeverOpened() : base(ConnectionState.Closed, false, true)
158         {
159         }
160     }
161 
162     sealed internal class DbConnectionClosedPreviouslyOpened : DbConnectionClosed
163     {
164         // Closed Connection, Has Previously Been Opened
165 
166         internal static readonly DbConnectionInternal SingletonInstance = new DbConnectionClosedPreviouslyOpened();   // singleton object
167 
DbConnectionClosedPreviouslyOpened()168         private DbConnectionClosedPreviouslyOpened() : base(ConnectionState.Closed, true, true)
169         {
170         }
171 
TryReplaceConnection(DbConnection outerConnection, DbConnectionFactory connectionFactory, TaskCompletionSource<DbConnectionInternal> retry, DbConnectionOptions userOptions)172         internal override bool TryReplaceConnection(DbConnection outerConnection, DbConnectionFactory connectionFactory, TaskCompletionSource<DbConnectionInternal> retry, DbConnectionOptions userOptions)
173         {
174             return TryOpenConnection(outerConnection, connectionFactory, retry, userOptions);
175         }
176     }
177 }
178