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