//------------------------------------------------------------------------------ // // Copyright (c) Microsoft Corporation. All rights reserved. // // Microsoft // Microsoft //------------------------------------------------------------------------------ namespace System.Data.ProviderBase { using System; using System.ComponentModel; using System.Data; using System.Data.Common; using System.Diagnostics; using System.Globalization; using System.Threading; using System.Threading.Tasks; using SysTx = System.Transactions; abstract internal class DbConnectionClosed : DbConnectionInternal { // Construct an "empty" connection protected DbConnectionClosed(ConnectionState state, bool hidePassword, bool allowSetConnectionString) : base(state, hidePassword, allowSetConnectionString) { } override public string ServerVersion { get { throw ADP.ClosedConnectionError(); } } override protected void Activate(SysTx.Transaction transaction) { throw ADP.ClosedConnectionError(); } override public DbTransaction BeginTransaction(IsolationLevel il) { throw ADP.ClosedConnectionError(); } override public void ChangeDatabase(string database) { throw ADP.ClosedConnectionError(); } internal override void CloseConnection(DbConnection owningObject, DbConnectionFactory connectionFactory) { // not much to do here... } override protected void Deactivate() { throw ADP.ClosedConnectionError(); } override public void EnlistTransaction(SysTx.Transaction transaction) { throw ADP.ClosedConnectionError(); } override protected internal DataTable GetSchema(DbConnectionFactory factory, DbConnectionPoolGroup poolGroup, DbConnection outerConnection, string collectionName, string[] restrictions) { throw ADP.ClosedConnectionError(); } protected override DbReferenceCollection CreateReferenceCollection() { throw ADP.ClosedConnectionError(); } internal override bool TryOpenConnection(DbConnection outerConnection, DbConnectionFactory connectionFactory, TaskCompletionSource retry, DbConnectionOptions userOptions) { return base.TryOpenConnectionInternal(outerConnection, connectionFactory, retry, userOptions); } } abstract internal class DbConnectionBusy : DbConnectionClosed { protected DbConnectionBusy(ConnectionState state) : base(state, true, false) { } internal override bool TryOpenConnection(DbConnection outerConnection, DbConnectionFactory connectionFactory, TaskCompletionSource retry, DbConnectionOptions userOptions) { throw ADP.ConnectionAlreadyOpen(State); } } sealed internal class DbConnectionClosedBusy : DbConnectionBusy { // Closed Connection, Currently Busy - changing connection string internal static readonly DbConnectionInternal SingletonInstance = new DbConnectionClosedBusy(); // singleton object private DbConnectionClosedBusy() : base(ConnectionState.Closed) { } } sealed internal class DbConnectionOpenBusy : DbConnectionBusy { // Open Connection, Currently Busy - closing connection internal static readonly DbConnectionInternal SingletonInstance = new DbConnectionOpenBusy(); // singleton object private DbConnectionOpenBusy() : base(ConnectionState.Open) { } } sealed internal class DbConnectionClosedConnecting : DbConnectionBusy { // Closed Connection, Currently Connecting internal static readonly DbConnectionInternal SingletonInstance = new DbConnectionClosedConnecting(); // singleton object private DbConnectionClosedConnecting() : base(ConnectionState.Connecting) { } internal override void CloseConnection(DbConnection owningObject, DbConnectionFactory connectionFactory) { connectionFactory.SetInnerConnectionTo(owningObject, DbConnectionClosedPreviouslyOpened.SingletonInstance); } internal override bool TryReplaceConnection(DbConnection outerConnection, DbConnectionFactory connectionFactory, TaskCompletionSource retry, DbConnectionOptions userOptions) { return TryOpenConnection(outerConnection, connectionFactory, retry, userOptions); } internal override bool TryOpenConnection(DbConnection outerConnection, DbConnectionFactory connectionFactory, TaskCompletionSource retry, DbConnectionOptions userOptions) { if (retry == null || !retry.Task.IsCompleted) { // retry is null if this is a synchronous call // if someone calls Open or OpenAsync while in this state, // then the retry task will not be completed throw ADP.ConnectionAlreadyOpen(State); } // we are completing an asynchronous open Debug.Assert(retry.Task.Status == TaskStatus.RanToCompletion, "retry task must be completed successfully"); DbConnectionInternal openConnection = retry.Task.Result; if (null == openConnection) { connectionFactory.SetInnerConnectionTo(outerConnection, this); throw ADP.InternalConnectionError(ADP.ConnectionError.GetConnectionReturnsNull); } connectionFactory.SetInnerConnectionEvent(outerConnection, openConnection); return true; } } sealed internal class DbConnectionClosedNeverOpened : DbConnectionClosed { // Closed Connection, Has Never Been Opened internal static readonly DbConnectionInternal SingletonInstance = new DbConnectionClosedNeverOpened(); // singleton object private DbConnectionClosedNeverOpened() : base(ConnectionState.Closed, false, true) { } } sealed internal class DbConnectionClosedPreviouslyOpened : DbConnectionClosed { // Closed Connection, Has Previously Been Opened internal static readonly DbConnectionInternal SingletonInstance = new DbConnectionClosedPreviouslyOpened(); // singleton object private DbConnectionClosedPreviouslyOpened() : base(ConnectionState.Closed, true, true) { } internal override bool TryReplaceConnection(DbConnection outerConnection, DbConnectionFactory connectionFactory, TaskCompletionSource retry, DbConnectionOptions userOptions) { return TryOpenConnection(outerConnection, connectionFactory, retry, userOptions); } } }