|
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System.Data.Common;
using System.Diagnostics;
using System.Threading.Tasks;
namespace System.Data.ProviderBase
{
internal abstract partial class DbConnectionClosed : DbConnectionInternal
{
// Construct an "empty" connection
protected DbConnectionClosed(ConnectionState state, bool hidePassword, bool allowSetConnectionString) : base(state, hidePassword, allowSetConnectionString)
{
}
public override string ServerVersion => throw ADP.ClosedConnectionError();
public override DbTransaction BeginTransaction(IsolationLevel il) => throw ADP.ClosedConnectionError();
public override void ChangeDatabase(string database) => throw ADP.ClosedConnectionError();
internal override void CloseConnection(DbConnection owningObject, DbConnectionFactory connectionFactory)
{
// not much to do here...
}
protected override void Deactivate() => ADP.ClosedConnectionError();
protected internal override 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<DbConnectionInternal>? retry, DbConnectionOptions? userOptions)
=> base.TryOpenConnectionInternal(outerConnection, connectionFactory, retry, userOptions);
}
internal abstract class DbConnectionBusy : DbConnectionClosed
{
protected DbConnectionBusy(ConnectionState state) : base(state, true, false)
{
}
internal override bool TryOpenConnection(DbConnection outerConnection, DbConnectionFactory connectionFactory, TaskCompletionSource<DbConnectionInternal>? retry, DbConnectionOptions? userOptions)
=> throw ADP.ConnectionAlreadyOpen(State);
}
internal sealed class DbConnectionClosedBusy : DbConnectionBusy
{
// Closed Connection, Currently Busy - changing connection string
internal static readonly DbConnectionInternal SingletonInstance = new DbConnectionClosedBusy(); // singleton object
private DbConnectionClosedBusy() : base(ConnectionState.Closed)
{
}
}
internal sealed class DbConnectionOpenBusy : DbConnectionBusy
{
// Open Connection, Currently Busy - closing connection
internal static readonly DbConnectionInternal SingletonInstance = new DbConnectionOpenBusy(); // singleton object
private DbConnectionOpenBusy() : base(ConnectionState.Open)
{
}
}
internal sealed 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<DbConnectionInternal>? retry, DbConnectionOptions? userOptions)
=> TryOpenConnection(outerConnection, connectionFactory, retry, userOptions);
internal override bool TryOpenConnection(DbConnection outerConnection, DbConnectionFactory connectionFactory, TaskCompletionSource<DbConnectionInternal>? 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;
}
}
internal sealed 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)
{
}
}
internal sealed 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<DbConnectionInternal>? retry, DbConnectionOptions? userOptions)
=> TryOpenConnection(outerConnection, connectionFactory, retry, userOptions);
}
}
|