You've already forked linux-packaging-mono
Imported Upstream version 4.6.0.125
Former-commit-id: a2155e9bd80020e49e72e86c44da02a8ac0e57a4
This commit is contained in:
parent
a569aebcfd
commit
e79aa3c0ed
@@ -0,0 +1,393 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <copyright file="DbConnectionHelper.cs" company="Microsoft">
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// </copyright>
|
||||
// <owner current="true" primary="true">[....]</owner>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace NAMESPACE {
|
||||
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Data;
|
||||
using System.Data.Common;
|
||||
using System.Data.ProviderBase;
|
||||
using System.Diagnostics;
|
||||
using System.Globalization;
|
||||
using System.Runtime.ConstrainedExecution;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading;
|
||||
using SysTx = System.Transactions;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
public sealed partial class CONNECTIONOBJECTNAME : DbConnection {
|
||||
private static readonly DbConnectionFactory _connectionFactory = CONNECTIONFACTORYOBJECTNAME;
|
||||
internal static readonly System.Security.CodeAccessPermission ExecutePermission = CONNECTIONOBJECTNAME.CreateExecutePermission();
|
||||
|
||||
private DbConnectionOptions _userConnectionOptions;
|
||||
private DbConnectionPoolGroup _poolGroup;
|
||||
private DbConnectionInternal _innerConnection;
|
||||
private int _closeCount; // used to distinguish between different uses of this object, so we don't have to maintain a list of it's children
|
||||
|
||||
private static int _objectTypeCount; // Bid counter
|
||||
internal readonly int ObjectID = System.Threading.Interlocked.Increment(ref _objectTypeCount);
|
||||
|
||||
public CONNECTIONOBJECTNAME() : base() {
|
||||
GC.SuppressFinalize(this);
|
||||
_innerConnection = DbConnectionClosedNeverOpened.SingletonInstance;
|
||||
}
|
||||
|
||||
// Copy Constructor
|
||||
private void CopyFrom(CONNECTIONOBJECTNAME connection) { // V1.2.3300
|
||||
ADP.CheckArgumentNull(connection, "connection");
|
||||
_userConnectionOptions = connection.UserConnectionOptions;
|
||||
_poolGroup = connection.PoolGroup;
|
||||
|
||||
// SQLBU 432115
|
||||
// Match the original connection's behavior for whether the connection was never opened,
|
||||
// but ensure Clone is in the closed state.
|
||||
if (DbConnectionClosedNeverOpened.SingletonInstance == connection._innerConnection)
|
||||
{
|
||||
_innerConnection = DbConnectionClosedNeverOpened.SingletonInstance;
|
||||
}
|
||||
else
|
||||
{
|
||||
_innerConnection = DbConnectionClosedPreviouslyOpened.SingletonInstance;
|
||||
}
|
||||
}
|
||||
|
||||
/// <devdoc>We use the _closeCount to avoid having to know about all our
|
||||
/// children; instead of keeping a collection of all the objects that
|
||||
/// would be affected by a close, we simply increment the _closeCount
|
||||
/// and have each of our children check to see if they're "orphaned"
|
||||
/// </devdoc>
|
||||
internal int CloseCount {
|
||||
get {
|
||||
return _closeCount;
|
||||
}
|
||||
}
|
||||
|
||||
internal DbConnectionFactory ConnectionFactory {
|
||||
get {
|
||||
return _connectionFactory;
|
||||
}
|
||||
}
|
||||
|
||||
internal DbConnectionOptions ConnectionOptions {
|
||||
get {
|
||||
System.Data.ProviderBase.DbConnectionPoolGroup poolGroup = PoolGroup;
|
||||
return ((null != poolGroup) ? poolGroup.ConnectionOptions : null);
|
||||
}
|
||||
}
|
||||
|
||||
private string ConnectionString_Get() {
|
||||
Bid.Trace( "<prov.DbConnectionHelper.ConnectionString_Get|API> %d#\n", ObjectID);
|
||||
bool hidePassword = InnerConnection.ShouldHidePassword;
|
||||
DbConnectionOptions connectionOptions = UserConnectionOptions;
|
||||
return ((null != connectionOptions) ? connectionOptions.UsersConnectionString(hidePassword) : "");
|
||||
}
|
||||
|
||||
private void ConnectionString_Set(string value) {
|
||||
DbConnectionPoolKey key = new DbConnectionPoolKey(value);
|
||||
|
||||
ConnectionString_Set(key);
|
||||
}
|
||||
|
||||
private void ConnectionString_Set(DbConnectionPoolKey key) {
|
||||
DbConnectionOptions connectionOptions = null;
|
||||
System.Data.ProviderBase.DbConnectionPoolGroup poolGroup = ConnectionFactory.GetConnectionPoolGroup(key, null, ref connectionOptions);
|
||||
DbConnectionInternal connectionInternal = InnerConnection;
|
||||
bool flag = connectionInternal.AllowSetConnectionString;
|
||||
if (flag) {
|
||||
//try {
|
||||
// NOTE: There's a race condition with multiple threads changing
|
||||
// ConnectionString and any thread throws an exception
|
||||
// Closed->Busy: prevent Open during set_ConnectionString
|
||||
flag = SetInnerConnectionFrom(DbConnectionClosedBusy.SingletonInstance, connectionInternal);
|
||||
if (flag) {
|
||||
_userConnectionOptions = connectionOptions;
|
||||
_poolGroup = poolGroup;
|
||||
_innerConnection = DbConnectionClosedNeverOpened.SingletonInstance;
|
||||
}
|
||||
//}
|
||||
//catch {
|
||||
// // recover from exceptions to avoid sticking in busy state
|
||||
// SetInnerConnectionFrom(connectionInternal, DbConnectionClosedBusy.SingletonInstance);
|
||||
// throw;
|
||||
//}
|
||||
}
|
||||
if (!flag) {
|
||||
throw ADP.OpenConnectionPropertySet(ADP.ConnectionString, connectionInternal.State);
|
||||
}
|
||||
if (Bid.TraceOn) {
|
||||
string cstr = ((null != connectionOptions) ? connectionOptions.UsersConnectionStringForTrace() : "");
|
||||
Bid.Trace("<prov.DbConnectionHelper.ConnectionString_Set|API> %d#, '%ls'\n", ObjectID, cstr);
|
||||
}
|
||||
}
|
||||
|
||||
internal DbConnectionInternal InnerConnection {
|
||||
get {
|
||||
return _innerConnection;
|
||||
}
|
||||
}
|
||||
|
||||
internal System.Data.ProviderBase.DbConnectionPoolGroup PoolGroup {
|
||||
get {
|
||||
return _poolGroup;
|
||||
}
|
||||
set {
|
||||
// when a poolgroup expires and the connection eventually activates, the pool entry will be replaced
|
||||
Debug.Assert(null != value, "null poolGroup");
|
||||
_poolGroup = value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
internal DbConnectionOptions UserConnectionOptions {
|
||||
get {
|
||||
return _userConnectionOptions;
|
||||
}
|
||||
}
|
||||
|
||||
// Open->ClosedPreviouslyOpened, and doom the internal connection too...
|
||||
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
|
||||
internal void Abort(Exception e) {
|
||||
DbConnectionInternal innerConnection = _innerConnection; // Should not cause memory allocation...
|
||||
if (ConnectionState.Open == innerConnection.State) {
|
||||
Interlocked.CompareExchange(ref _innerConnection, DbConnectionClosedPreviouslyOpened.SingletonInstance, innerConnection);
|
||||
innerConnection.DoomThisConnection();
|
||||
}
|
||||
|
||||
// NOTE: we put the tracing last, because the ToString() calls (and
|
||||
// the Bid.Trace, for that matter) have no reliability contract and
|
||||
// will end the reliable try...
|
||||
if (e is OutOfMemoryException) {
|
||||
Bid.Trace("<prov.DbConnectionHelper.Abort|RES|INFO|CPOOL> %d#, Aborting operation due to asynchronous exception: %ls\n", ObjectID, "OutOfMemory");
|
||||
}
|
||||
else {
|
||||
Bid.Trace("<prov.DbConnectionHelper.Abort|RES|INFO|CPOOL> %d#, Aborting operation due to asynchronous exception: %ls\n", ObjectID, e.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
internal void AddWeakReference(object value, int tag) {
|
||||
InnerConnection.AddWeakReference(value, tag);
|
||||
}
|
||||
|
||||
|
||||
override protected DbCommand CreateDbCommand() {
|
||||
DbCommand command = null;
|
||||
IntPtr hscp;
|
||||
Bid.ScopeEnter(out hscp, "<prov.DbConnectionHelper.CreateDbCommand|API> %d#\n", ObjectID);
|
||||
try {
|
||||
DbProviderFactory providerFactory = ConnectionFactory.ProviderFactory;
|
||||
command = providerFactory.CreateCommand();
|
||||
command.Connection = this;
|
||||
}
|
||||
finally {
|
||||
Bid.ScopeLeave(ref hscp);
|
||||
}
|
||||
return command;
|
||||
}
|
||||
|
||||
private static System.Security.CodeAccessPermission CreateExecutePermission() {
|
||||
DBDataPermission p = (DBDataPermission)CONNECTIONFACTORYOBJECTNAME.ProviderFactory.CreatePermission(System.Security.Permissions.PermissionState.None);
|
||||
p.Add(String.Empty, String.Empty, KeyRestrictionBehavior.AllowOnly);
|
||||
return p;
|
||||
}
|
||||
|
||||
override protected void Dispose(bool disposing) {
|
||||
if (disposing) {
|
||||
_userConnectionOptions = null;
|
||||
_poolGroup= null;
|
||||
Close();
|
||||
}
|
||||
DisposeMe(disposing);
|
||||
base.Dispose(disposing); // notify base classes
|
||||
}
|
||||
|
||||
partial void RepairInnerConnection();
|
||||
|
||||
#if !MOBILE
|
||||
// NOTE: This is just a private helper because OracleClient V1.1 shipped
|
||||
// with a different argument name and it's a breaking change to not use
|
||||
// the same argument names in V2.0 (VB Named Parameter Binding--Ick)
|
||||
private void EnlistDistributedTransactionHelper(System.EnterpriseServices.ITransaction transaction) {
|
||||
System.Security.PermissionSet permissionSet = new System.Security.PermissionSet(System.Security.Permissions.PermissionState.None);
|
||||
permissionSet.AddPermission(CONNECTIONOBJECTNAME.ExecutePermission); // MDAC 81476
|
||||
permissionSet.AddPermission(new System.Security.Permissions.SecurityPermission(System.Security.Permissions.SecurityPermissionFlag.UnmanagedCode));
|
||||
permissionSet.Demand();
|
||||
|
||||
Bid.Trace( "<prov.DbConnectionHelper.EnlistDistributedTransactionHelper|RES|TRAN> %d#, Connection enlisting in a transaction.\n", ObjectID);
|
||||
SysTx.Transaction indigoTransaction = null;
|
||||
|
||||
if (null != transaction) {
|
||||
indigoTransaction = SysTx.TransactionInterop.GetTransactionFromDtcTransaction((SysTx.IDtcTransaction)transaction);
|
||||
}
|
||||
|
||||
RepairInnerConnection();
|
||||
// NOTE: since transaction enlistment involves round trips to the
|
||||
// server, we don't want to lock here, we'll handle the race conditions
|
||||
// elsewhere.
|
||||
InnerConnection.EnlistTransaction(indigoTransaction);
|
||||
|
||||
// NOTE: If this outer connection were to be GC'd while we're
|
||||
// enlisting, the pooler would attempt to reclaim the inner connection
|
||||
// while we're attempting to enlist; not sure how likely that is but
|
||||
// we should consider a GC.KeepAlive(this) here.
|
||||
GC.KeepAlive(this);
|
||||
}
|
||||
#endif
|
||||
|
||||
override public void EnlistTransaction(SysTx.Transaction transaction) {
|
||||
CONNECTIONOBJECTNAME.ExecutePermission.Demand();
|
||||
|
||||
Bid.Trace( "<prov.DbConnectionHelper.EnlistTransaction|RES|TRAN> %d#, Connection enlisting in a transaction.\n", ObjectID);
|
||||
|
||||
// If we're currently enlisted in a transaction and we were called
|
||||
// on the EnlistTransaction method (Whidbey) we're not allowed to
|
||||
// enlist in a different transaction.
|
||||
|
||||
DbConnectionInternal innerConnection = InnerConnection;
|
||||
|
||||
// NOTE: since transaction enlistment involves round trips to the
|
||||
// server, we don't want to lock here, we'll handle the race conditions
|
||||
// elsewhere.
|
||||
SysTx.Transaction enlistedTransaction = innerConnection.EnlistedTransaction;
|
||||
if (enlistedTransaction != null) {
|
||||
// Allow calling enlist if already enlisted (no-op)
|
||||
if (enlistedTransaction.Equals(transaction)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Allow enlisting in a different transaction if the enlisted transaction has completed.
|
||||
if (enlistedTransaction.TransactionInformation.Status == SysTx.TransactionStatus.Active)
|
||||
{
|
||||
throw ADP.TransactionPresent();
|
||||
}
|
||||
}
|
||||
RepairInnerConnection();
|
||||
InnerConnection.EnlistTransaction(transaction);
|
||||
|
||||
// NOTE: If this outer connection were to be GC'd while we're
|
||||
// enlisting, the pooler would attempt to reclaim the inner connection
|
||||
// while we're attempting to enlist; not sure how likely that is but
|
||||
// we should consider a GC.KeepAlive(this) here.
|
||||
GC.KeepAlive(this);
|
||||
}
|
||||
|
||||
private DbMetaDataFactory GetMetaDataFactory(DbConnectionInternal internalConnection) {
|
||||
return ConnectionFactory.GetMetaDataFactory(_poolGroup, internalConnection);
|
||||
}
|
||||
|
||||
internal DbMetaDataFactory GetMetaDataFactoryInternal(DbConnectionInternal internalConnection) {
|
||||
return GetMetaDataFactory(internalConnection);
|
||||
}
|
||||
|
||||
override public DataTable GetSchema() {
|
||||
return this.GetSchema(DbMetaDataCollectionNames.MetaDataCollections, null);
|
||||
}
|
||||
|
||||
override public DataTable GetSchema(string collectionName) {
|
||||
return this.GetSchema(collectionName, null);
|
||||
}
|
||||
|
||||
override public DataTable GetSchema(string collectionName, string[] restrictionValues) {
|
||||
// NOTE: This is virtual because not all providers may choose to support
|
||||
// returning schema data
|
||||
CONNECTIONOBJECTNAME.ExecutePermission.Demand();
|
||||
return InnerConnection.GetSchema(ConnectionFactory, PoolGroup, this, collectionName, restrictionValues);
|
||||
}
|
||||
|
||||
internal void NotifyWeakReference(int message) {
|
||||
InnerConnection.NotifyWeakReference(message);
|
||||
}
|
||||
|
||||
internal void PermissionDemand() {
|
||||
Debug.Assert(DbConnectionClosedConnecting.SingletonInstance == _innerConnection, "not connecting");
|
||||
|
||||
System.Data.ProviderBase.DbConnectionPoolGroup poolGroup = PoolGroup;
|
||||
DbConnectionOptions connectionOptions = ((null != poolGroup) ? poolGroup.ConnectionOptions : null);
|
||||
if ((null == connectionOptions) || connectionOptions.IsEmpty) {
|
||||
throw ADP.NoConnectionString();
|
||||
}
|
||||
|
||||
DbConnectionOptions userConnectionOptions = UserConnectionOptions;
|
||||
Debug.Assert(null != userConnectionOptions, "null UserConnectionOptions");
|
||||
|
||||
userConnectionOptions.DemandPermission();
|
||||
}
|
||||
|
||||
internal void RemoveWeakReference(object value) {
|
||||
InnerConnection.RemoveWeakReference(value);
|
||||
}
|
||||
|
||||
// OpenBusy->Closed (previously opened)
|
||||
// Connecting->Open
|
||||
internal void SetInnerConnectionEvent(DbConnectionInternal to) {
|
||||
// Set's the internal connection without verifying that it's a specific value
|
||||
Debug.Assert(null != _innerConnection, "null InnerConnection");
|
||||
Debug.Assert(null != to, "to null InnerConnection");
|
||||
|
||||
ConnectionState originalState = _innerConnection.State & ConnectionState.Open;
|
||||
ConnectionState currentState = to.State & ConnectionState.Open;
|
||||
|
||||
if ((originalState != currentState) && (ConnectionState.Closed == currentState)) {
|
||||
// Increment the close count whenever we switch to Closed
|
||||
unchecked { _closeCount++; }
|
||||
}
|
||||
|
||||
_innerConnection = to;
|
||||
|
||||
if (ConnectionState.Closed == originalState && ConnectionState.Open == currentState) {
|
||||
OnStateChange(DbConnectionInternal.StateChangeOpen);
|
||||
}
|
||||
else if (ConnectionState.Open == originalState && ConnectionState.Closed == currentState) {
|
||||
OnStateChange(DbConnectionInternal.StateChangeClosed);
|
||||
}
|
||||
else {
|
||||
Debug.Assert(false, "unexpected state switch");
|
||||
if (originalState != currentState) {
|
||||
OnStateChange(new StateChangeEventArgs(originalState, currentState));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// this method is used to securely change state with the resource being
|
||||
// the open connection protected by the connectionstring via a permission demand
|
||||
|
||||
// Closed->Connecting: prevent set_ConnectionString during Open
|
||||
// Open->OpenBusy: guarantee internal connection is returned to correct pool
|
||||
// Closed->ClosedBusy: prevent Open during set_ConnectionString
|
||||
internal bool SetInnerConnectionFrom(DbConnectionInternal to, DbConnectionInternal from) {
|
||||
// Set's the internal connection, verifying that it's a specific value before doing so.
|
||||
Debug.Assert(null != _innerConnection, "null InnerConnection");
|
||||
Debug.Assert(null != from, "from null InnerConnection");
|
||||
Debug.Assert(null != to, "to null InnerConnection");
|
||||
|
||||
bool result = (from == Interlocked.CompareExchange<DbConnectionInternal>(ref _innerConnection, to, from));
|
||||
return result;
|
||||
}
|
||||
|
||||
// ClosedBusy->Closed (never opened)
|
||||
// Connecting->Closed (exception during open, return to previous closed state)
|
||||
internal void SetInnerConnectionTo(DbConnectionInternal to) {
|
||||
// Set's the internal connection without verifying that it's a specific value
|
||||
Debug.Assert(null != _innerConnection, "null InnerConnection");
|
||||
Debug.Assert(null != to, "to null InnerConnection");
|
||||
_innerConnection = to;
|
||||
}
|
||||
|
||||
[ConditionalAttribute("DEBUG")]
|
||||
internal static void VerifyExecutePermission() {
|
||||
try {
|
||||
// use this to help validate this code path is only used after the following permission has been previously demanded in the current codepath
|
||||
CONNECTIONOBJECTNAME.ExecutePermission.Demand();
|
||||
}
|
||||
catch(System.Security.SecurityException) {
|
||||
System.Diagnostics.Debug.Assert(false, "unexpected SecurityException for current codepath");
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user