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,133 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <copyright file="DataReaderContainer.cs" company="Microsoft">
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// </copyright>
|
||||
// <owner current="true" primary="true">[....]</owner>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace System.Data.ProviderBase {
|
||||
|
||||
using System;
|
||||
using System.Data;
|
||||
using System.Data.Common;
|
||||
using System.Diagnostics;
|
||||
|
||||
internal abstract class DataReaderContainer {
|
||||
|
||||
protected readonly IDataReader _dataReader;
|
||||
protected int _fieldCount;
|
||||
|
||||
static internal DataReaderContainer Create(IDataReader dataReader, bool returnProviderSpecificTypes) {
|
||||
if (returnProviderSpecificTypes) {
|
||||
DbDataReader providerSpecificDataReader = (dataReader as DbDataReader);
|
||||
if (null != providerSpecificDataReader) {
|
||||
return new ProviderSpecificDataReader(dataReader, providerSpecificDataReader);
|
||||
}
|
||||
}
|
||||
return new CommonLanguageSubsetDataReader(dataReader);
|
||||
}
|
||||
|
||||
protected DataReaderContainer(IDataReader dataReader) {
|
||||
Debug.Assert(null != dataReader, "null dataReader");
|
||||
_dataReader = dataReader;
|
||||
}
|
||||
|
||||
internal int FieldCount {
|
||||
get {
|
||||
return _fieldCount;
|
||||
}
|
||||
}
|
||||
|
||||
internal abstract bool ReturnProviderSpecificTypes { get; }
|
||||
protected abstract int VisibleFieldCount { get; }
|
||||
|
||||
internal abstract Type GetFieldType(int ordinal);
|
||||
internal abstract object GetValue(int ordinal);
|
||||
internal abstract int GetValues(object[] values);
|
||||
|
||||
internal string GetName(int ordinal) {
|
||||
string fieldName = _dataReader.GetName(ordinal);
|
||||
Debug.Assert(null != fieldName, "null GetName");
|
||||
return ((null != fieldName) ? fieldName : "");
|
||||
}
|
||||
internal DataTable GetSchemaTable() {
|
||||
return _dataReader.GetSchemaTable();
|
||||
}
|
||||
internal bool NextResult() {
|
||||
_fieldCount = 0;
|
||||
if (_dataReader.NextResult()) {
|
||||
_fieldCount = VisibleFieldCount;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
internal bool Read() {
|
||||
return _dataReader.Read();
|
||||
}
|
||||
|
||||
private sealed class ProviderSpecificDataReader : DataReaderContainer {
|
||||
private DbDataReader _providerSpecificDataReader;
|
||||
|
||||
internal ProviderSpecificDataReader(IDataReader dataReader, DbDataReader dbDataReader) : base(dataReader) {
|
||||
Debug.Assert(null != dataReader, "null dbDataReader");
|
||||
_providerSpecificDataReader = dbDataReader;
|
||||
_fieldCount = VisibleFieldCount;
|
||||
}
|
||||
|
||||
internal override bool ReturnProviderSpecificTypes {
|
||||
get {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
protected override int VisibleFieldCount {
|
||||
get {
|
||||
int fieldCount = _providerSpecificDataReader.VisibleFieldCount;
|
||||
Debug.Assert(0 <= fieldCount, "negative FieldCount");
|
||||
return ((0 <= fieldCount) ? fieldCount : 0);
|
||||
}
|
||||
}
|
||||
|
||||
internal override Type GetFieldType(int ordinal) {
|
||||
Type fieldType = _providerSpecificDataReader.GetProviderSpecificFieldType(ordinal);
|
||||
Debug.Assert(null != fieldType, "null FieldType");
|
||||
return fieldType;
|
||||
}
|
||||
internal override object GetValue(int ordinal) {
|
||||
return _providerSpecificDataReader.GetProviderSpecificValue(ordinal);
|
||||
}
|
||||
internal override int GetValues(object[] values) {
|
||||
return _providerSpecificDataReader.GetProviderSpecificValues(values);
|
||||
}
|
||||
}
|
||||
|
||||
private sealed class CommonLanguageSubsetDataReader : DataReaderContainer {
|
||||
|
||||
internal CommonLanguageSubsetDataReader(IDataReader dataReader ) : base(dataReader) {
|
||||
_fieldCount = VisibleFieldCount;
|
||||
}
|
||||
|
||||
internal override bool ReturnProviderSpecificTypes {
|
||||
get {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
protected override int VisibleFieldCount {
|
||||
get {
|
||||
int fieldCount = _dataReader.FieldCount;
|
||||
Debug.Assert(0 <= fieldCount, "negative FieldCount");
|
||||
return ((0 <= fieldCount) ? fieldCount : 0);
|
||||
}
|
||||
}
|
||||
|
||||
internal override Type GetFieldType(int ordinal) {
|
||||
return _dataReader.GetFieldType(ordinal);
|
||||
}
|
||||
internal override object GetValue(int ordinal) {
|
||||
return _dataReader.GetValue(ordinal);
|
||||
}
|
||||
internal override int GetValues(object[] values) {
|
||||
return _dataReader.GetValues(values);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,158 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <copyright file="DbConnectionClosed.cs" company="Microsoft">
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// </copyright>
|
||||
// <owner current="true" primary="true">[....]</owner>
|
||||
// <owner current="true" primary="false">[....]</owner>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
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<DbConnectionInternal> 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<DbConnectionInternal> 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<DbConnectionInternal> retry, DbConnectionOptions userOptions) {
|
||||
return 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;
|
||||
}
|
||||
}
|
||||
|
||||
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<DbConnectionInternal> retry, DbConnectionOptions userOptions) {
|
||||
return TryOpenConnection(outerConnection, connectionFactory, retry, userOptions);
|
||||
}
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,108 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <copyright file="DbConnectionPoolAuthenticationContext.cs" company="Microsoft">
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// </copyright>
|
||||
// <owner current="true" primary="true">harsudan</owner>
|
||||
// <owner current="true" primary="false">yuronhe</owner>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Runtime.ConstrainedExecution;
|
||||
using System.Threading;
|
||||
|
||||
namespace System.Data.ProviderBase
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents the context of an authentication attempt when using the new active directory based authentication mechanisms.
|
||||
/// All data members, except_isUpdateInProgressCounter, should be immutable.
|
||||
/// </summary>
|
||||
sealed internal class DbConnectionPoolAuthenticationContext
|
||||
{
|
||||
/// <summary>
|
||||
/// The value expected in _isUpdateInProgress if a thread has taken a lock on this context,
|
||||
/// to perform the update on the context.
|
||||
/// </summary>
|
||||
private const int STATUS_LOCKED = 1;
|
||||
|
||||
/// <summary>
|
||||
/// The value expected in _isUpdateInProgress if no thread has taken a lock on this context.
|
||||
/// </summary>
|
||||
private const int STATUS_UNLOCKED = 0;
|
||||
|
||||
/// <summary>
|
||||
/// Access Token, which is obtained from Active Directory Authentication Library for SQL Server, and needs to be sent to SQL Server
|
||||
/// as part of TDS Token type Federated Authentication Token.
|
||||
/// </summary>
|
||||
private readonly byte[] _accessToken;
|
||||
|
||||
/// <summary>
|
||||
/// Expiration time of the above access token.
|
||||
/// </summary>
|
||||
private readonly DateTime _expirationTime;
|
||||
|
||||
/// <summary>
|
||||
/// A member which is used to achieve a lock to control refresh attempt on this context.
|
||||
/// </summary>
|
||||
private int _isUpdateInProgress;
|
||||
|
||||
/// <summary>
|
||||
/// Constructor.
|
||||
/// </summary>
|
||||
/// <param name="accessToken">Access Token that will be used to connect to SQL Server. Carries identity information about a user.</param>
|
||||
/// <param name="expirationTime">The expiration time in UTC for the above accessToken.</param>
|
||||
internal DbConnectionPoolAuthenticationContext(byte[] accessToken, DateTime expirationTime) {
|
||||
|
||||
Debug.Assert(accessToken != null && accessToken.Length > 0);
|
||||
Debug.Assert(expirationTime > DateTime.MinValue && expirationTime < DateTime.MaxValue);
|
||||
|
||||
_accessToken = accessToken;
|
||||
_expirationTime = expirationTime;
|
||||
_isUpdateInProgress = STATUS_UNLOCKED;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Static Method.
|
||||
/// Given two contexts, choose one to update in the cache. Chooses based on expiration time.
|
||||
/// </summary>
|
||||
/// <param name="context1">Context1</param>
|
||||
/// <param name="context2">Context2</param>
|
||||
internal static DbConnectionPoolAuthenticationContext ChooseAuthenticationContextToUpdate(DbConnectionPoolAuthenticationContext context1, DbConnectionPoolAuthenticationContext context2) {
|
||||
|
||||
Debug.Assert(context1 != null, "context1 should not be null.");
|
||||
Debug.Assert(context2 != null, "context2 should not be null.");
|
||||
|
||||
return context1.ExpirationTime > context2.ExpirationTime ? context1 : context2;
|
||||
}
|
||||
|
||||
internal byte[] AccessToken {
|
||||
get {
|
||||
return _accessToken;
|
||||
}
|
||||
}
|
||||
|
||||
internal DateTime ExpirationTime {
|
||||
get {
|
||||
return _expirationTime;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Try locking the variable _isUpdateInProgressCounter and return if this thread got the lock to update.
|
||||
/// Whichever thread got the chance to update this variable to 1 wins the lock.
|
||||
/// </summary>
|
||||
internal bool LockToUpdate() {
|
||||
int oldValue = Interlocked.CompareExchange(ref _isUpdateInProgress, STATUS_LOCKED, STATUS_UNLOCKED);
|
||||
return (oldValue == STATUS_UNLOCKED);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Release the lock which was obtained through LockToUpdate.
|
||||
/// </summary>
|
||||
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
|
||||
internal void ReleaseLockToUpdate() {
|
||||
int oldValue = Interlocked.CompareExchange(ref _isUpdateInProgress, STATUS_UNLOCKED, STATUS_LOCKED);
|
||||
Debug.Assert(oldValue == STATUS_LOCKED);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,106 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <copyright file="DbConnectionPoolAuthenticationContextKey.cs" company="Microsoft">
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// </copyright>
|
||||
// <owner current="true" primary="true">harsudan</owner>
|
||||
// <owner current="true" primary="false">yuronhe</owner>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace System.Data.ProviderBase
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents the key of dbConnectionPoolAuthenticationContext.
|
||||
/// All data members should be immutable and so, hashCode is pre-computed.
|
||||
/// </summary>
|
||||
sealed internal class DbConnectionPoolAuthenticationContextKey
|
||||
{
|
||||
/// <summary>
|
||||
/// Security Token Service Authority.
|
||||
/// </summary>
|
||||
private readonly string _stsAuthority;
|
||||
|
||||
/// <summary>
|
||||
/// Service Principal Name.
|
||||
/// </summary>
|
||||
private readonly string _servicePrincipalName;
|
||||
|
||||
/// <summary>
|
||||
/// Pre-Computed Hash Code.
|
||||
/// </summary>
|
||||
private readonly int _hashCode;
|
||||
|
||||
internal string StsAuthority {
|
||||
get {
|
||||
return _stsAuthority;
|
||||
}
|
||||
}
|
||||
|
||||
internal string ServicePrincipalName {
|
||||
get {
|
||||
return _servicePrincipalName;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor for the type.
|
||||
/// </summary>
|
||||
/// <param name="stsAuthority">Token Endpoint URL</param>
|
||||
/// <param name="servicePrincipalName">SPN representing the SQL service in an active directory.</param>
|
||||
internal DbConnectionPoolAuthenticationContextKey(string stsAuthority, string servicePrincipalName) {
|
||||
Debug.Assert(!string.IsNullOrWhiteSpace(stsAuthority));
|
||||
Debug.Assert(!string.IsNullOrWhiteSpace(servicePrincipalName));
|
||||
|
||||
_stsAuthority = stsAuthority;
|
||||
_servicePrincipalName = servicePrincipalName;
|
||||
|
||||
// Pre-compute hash since data members are not going to change.
|
||||
_hashCode = ComputeHashCode();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Override the default Equals implementation.
|
||||
/// </summary>
|
||||
/// <param name="obj"></param>
|
||||
/// <returns></returns>
|
||||
public override bool Equals(object obj) {
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
DbConnectionPoolAuthenticationContextKey otherKey = obj as DbConnectionPoolAuthenticationContextKey;
|
||||
if (otherKey == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return (String.Equals(StsAuthority, otherKey.StsAuthority, StringComparison.InvariantCultureIgnoreCase)
|
||||
&& String.Equals(ServicePrincipalName, otherKey.ServicePrincipalName, StringComparison.InvariantCultureIgnoreCase));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Override the default GetHashCode implementation.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public override int GetHashCode() {
|
||||
return _hashCode;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Compute the hash code for this object.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private int ComputeHashCode() {
|
||||
int hashCode = 33;
|
||||
|
||||
unchecked
|
||||
{
|
||||
hashCode = (hashCode * 17) + StsAuthority.GetHashCode();
|
||||
hashCode = (hashCode * 17) + ServicePrincipalName.GetHashCode();
|
||||
}
|
||||
|
||||
return hashCode;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,325 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <copyright file="DbConnectionPoolCounters.cs" company="Microsoft">
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// </copyright>
|
||||
// <owner current="true" primary="true">[....]</owner>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace System.Data.ProviderBase {
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Data.Common;
|
||||
using System.Diagnostics;
|
||||
using System.Globalization;
|
||||
using System.Reflection;
|
||||
using System.Runtime.ConstrainedExecution;
|
||||
using System.Security;
|
||||
using System.Security.Permissions;
|
||||
using System.Security.Principal;
|
||||
using System.Runtime.Versioning;
|
||||
|
||||
internal abstract class DbConnectionPoolCounters {
|
||||
private static class CreationData {
|
||||
|
||||
static internal readonly CounterCreationData HardConnectsPerSecond = new CounterCreationData(
|
||||
"HardConnectsPerSecond",
|
||||
"The number of actual connections per second that are being made to servers",
|
||||
PerformanceCounterType.RateOfCountsPerSecond32);
|
||||
|
||||
static internal readonly CounterCreationData HardDisconnectsPerSecond = new CounterCreationData(
|
||||
"HardDisconnectsPerSecond",
|
||||
"The number of actual disconnects per second that are being made to servers",
|
||||
PerformanceCounterType.RateOfCountsPerSecond32);
|
||||
|
||||
static internal readonly CounterCreationData SoftConnectsPerSecond = new CounterCreationData(
|
||||
"SoftConnectsPerSecond",
|
||||
"The number of connections we get from the pool per second",
|
||||
PerformanceCounterType.RateOfCountsPerSecond32);
|
||||
|
||||
static internal readonly CounterCreationData SoftDisconnectsPerSecond = new CounterCreationData(
|
||||
"SoftDisconnectsPerSecond",
|
||||
"The number of connections we return to the pool per second",
|
||||
PerformanceCounterType.RateOfCountsPerSecond32);
|
||||
|
||||
static internal readonly CounterCreationData NumberOfNonPooledConnections = new CounterCreationData(
|
||||
"NumberOfNonPooledConnections",
|
||||
"The number of connections that are not using connection pooling",
|
||||
PerformanceCounterType.NumberOfItems32);
|
||||
|
||||
static internal readonly CounterCreationData NumberOfPooledConnections = new CounterCreationData(
|
||||
"NumberOfPooledConnections",
|
||||
"The number of connections that are managed by the connection pooler",
|
||||
PerformanceCounterType.NumberOfItems32);
|
||||
|
||||
static internal readonly CounterCreationData NumberOfActiveConnectionPoolGroups = new CounterCreationData(
|
||||
"NumberOfActiveConnectionPoolGroups",
|
||||
"The number of unique connection strings",
|
||||
PerformanceCounterType.NumberOfItems32);
|
||||
|
||||
static internal readonly CounterCreationData NumberOfInactiveConnectionPoolGroups = new CounterCreationData(
|
||||
"NumberOfInactiveConnectionPoolGroups",
|
||||
"The number of unique connection strings waiting for pruning",
|
||||
PerformanceCounterType.NumberOfItems32);
|
||||
|
||||
static internal readonly CounterCreationData NumberOfActiveConnectionPools = new CounterCreationData(
|
||||
"NumberOfActiveConnectionPools",
|
||||
"The number of connection pools",
|
||||
PerformanceCounterType.NumberOfItems32);
|
||||
|
||||
static internal readonly CounterCreationData NumberOfInactiveConnectionPools = new CounterCreationData(
|
||||
"NumberOfInactiveConnectionPools",
|
||||
"The number of connection pools",
|
||||
PerformanceCounterType.NumberOfItems32);
|
||||
|
||||
static internal readonly CounterCreationData NumberOfActiveConnections = new CounterCreationData(
|
||||
"NumberOfActiveConnections",
|
||||
"The number of connections currently in-use",
|
||||
PerformanceCounterType.NumberOfItems32);
|
||||
|
||||
static internal readonly CounterCreationData NumberOfFreeConnections = new CounterCreationData(
|
||||
"NumberOfFreeConnections",
|
||||
"The number of connections currently available for use",
|
||||
PerformanceCounterType.NumberOfItems32);
|
||||
|
||||
static internal readonly CounterCreationData NumberOfStasisConnections = new CounterCreationData(
|
||||
"NumberOfStasisConnections",
|
||||
"The number of connections currently waiting to be made ready for use",
|
||||
PerformanceCounterType.NumberOfItems32);
|
||||
|
||||
static internal readonly CounterCreationData NumberOfReclaimedConnections = new CounterCreationData(
|
||||
"NumberOfReclaimedConnections",
|
||||
"The number of connections we reclaim from GC'd external connections",
|
||||
PerformanceCounterType.NumberOfItems32);
|
||||
};
|
||||
|
||||
sealed internal class Counter {
|
||||
private PerformanceCounter _instance;
|
||||
|
||||
internal Counter (string categoryName, string instanceName, string counterName, PerformanceCounterType counterType) {
|
||||
if (ADP.IsPlatformNT5) {
|
||||
try {
|
||||
if (!ADP.IsEmpty(categoryName) && !ADP.IsEmpty(instanceName)) {
|
||||
PerformanceCounter instance = new PerformanceCounter();
|
||||
instance.CategoryName = categoryName;
|
||||
instance.CounterName = counterName;
|
||||
instance.InstanceName = instanceName;
|
||||
instance.InstanceLifetime = PerformanceCounterInstanceLifetime.Process;
|
||||
instance.ReadOnly = false;
|
||||
instance.RawValue = 0; // make sure we start out at zero
|
||||
_instance = instance;
|
||||
}
|
||||
}
|
||||
catch (InvalidOperationException e) {
|
||||
ADP.TraceExceptionWithoutRethrow(e);
|
||||
//
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
internal void Decrement() {
|
||||
PerformanceCounter instance = _instance;
|
||||
if (null != instance) {
|
||||
instance.Decrement();
|
||||
}
|
||||
}
|
||||
|
||||
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
|
||||
internal void Dispose () { //
|
||||
PerformanceCounter instance = _instance;
|
||||
_instance = null;
|
||||
if (null != instance) {
|
||||
instance.RemoveInstance();
|
||||
// should we be calling instance.Close?
|
||||
// if we do will it exacerbate the Dispose vs. Decrement race condition
|
||||
//instance.Close();
|
||||
}
|
||||
}
|
||||
|
||||
internal void Increment() {
|
||||
PerformanceCounter instance = _instance;
|
||||
if (null != instance) {
|
||||
instance.Increment();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const int CounterInstanceNameMaxLength = 127;
|
||||
|
||||
internal readonly Counter HardConnectsPerSecond;
|
||||
internal readonly Counter HardDisconnectsPerSecond;
|
||||
internal readonly Counter SoftConnectsPerSecond;
|
||||
internal readonly Counter SoftDisconnectsPerSecond;
|
||||
internal readonly Counter NumberOfNonPooledConnections;
|
||||
internal readonly Counter NumberOfPooledConnections;
|
||||
internal readonly Counter NumberOfActiveConnectionPoolGroups;
|
||||
internal readonly Counter NumberOfInactiveConnectionPoolGroups;
|
||||
internal readonly Counter NumberOfActiveConnectionPools;
|
||||
internal readonly Counter NumberOfInactiveConnectionPools;
|
||||
internal readonly Counter NumberOfActiveConnections;
|
||||
internal readonly Counter NumberOfFreeConnections;
|
||||
internal readonly Counter NumberOfStasisConnections;
|
||||
internal readonly Counter NumberOfReclaimedConnections;
|
||||
|
||||
protected DbConnectionPoolCounters() : this(null, null) {
|
||||
}
|
||||
|
||||
protected DbConnectionPoolCounters(string categoryName, string categoryHelp) {
|
||||
AppDomain.CurrentDomain.DomainUnload += new EventHandler(this.UnloadEventHandler);
|
||||
AppDomain.CurrentDomain.ProcessExit += new EventHandler(this.ExitEventHandler);
|
||||
AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(this.ExceptionEventHandler);
|
||||
|
||||
string instanceName = null;
|
||||
|
||||
if (!ADP.IsEmpty(categoryName)) {
|
||||
if (ADP.IsPlatformNT5) {
|
||||
instanceName = GetInstanceName();
|
||||
}
|
||||
}
|
||||
|
||||
// level 0-3: hard connects/disconnects, plus basic pool/pool entry statistics
|
||||
string basicCategoryName = categoryName;
|
||||
HardConnectsPerSecond = new Counter(basicCategoryName, instanceName, CreationData.HardConnectsPerSecond.CounterName, CreationData.HardConnectsPerSecond.CounterType);
|
||||
HardDisconnectsPerSecond = new Counter(basicCategoryName, instanceName, CreationData.HardDisconnectsPerSecond.CounterName, CreationData.HardDisconnectsPerSecond.CounterType);
|
||||
NumberOfNonPooledConnections = new Counter(basicCategoryName, instanceName, CreationData.NumberOfNonPooledConnections.CounterName, CreationData.NumberOfNonPooledConnections.CounterType);
|
||||
NumberOfPooledConnections = new Counter(basicCategoryName, instanceName, CreationData.NumberOfPooledConnections.CounterName, CreationData.NumberOfPooledConnections.CounterType);
|
||||
NumberOfActiveConnectionPoolGroups = new Counter(basicCategoryName, instanceName, CreationData.NumberOfActiveConnectionPoolGroups.CounterName, CreationData.NumberOfActiveConnectionPoolGroups.CounterType);
|
||||
NumberOfInactiveConnectionPoolGroups = new Counter(basicCategoryName, instanceName, CreationData.NumberOfInactiveConnectionPoolGroups.CounterName, CreationData.NumberOfInactiveConnectionPoolGroups.CounterType);
|
||||
NumberOfActiveConnectionPools = new Counter(basicCategoryName, instanceName, CreationData.NumberOfActiveConnectionPools.CounterName, CreationData.NumberOfActiveConnectionPools.CounterType);
|
||||
NumberOfInactiveConnectionPools = new Counter(basicCategoryName, instanceName, CreationData.NumberOfInactiveConnectionPools.CounterName, CreationData.NumberOfInactiveConnectionPools.CounterType);
|
||||
NumberOfStasisConnections = new Counter(basicCategoryName, instanceName, CreationData.NumberOfStasisConnections.CounterName, CreationData.NumberOfStasisConnections.CounterType);
|
||||
NumberOfReclaimedConnections = new Counter(basicCategoryName, instanceName, CreationData.NumberOfReclaimedConnections.CounterName, CreationData.NumberOfReclaimedConnections.CounterType);
|
||||
|
||||
// level 4: expensive stuff
|
||||
string verboseCategoryName = null;
|
||||
if (!ADP.IsEmpty(categoryName)) {
|
||||
// don't load TraceSwitch if no categoryName so that Odbc/OleDb have a chance of not loading TraceSwitch
|
||||
// which are also used by System.Diagnostics.PerformanceCounter.ctor & System.Transactions.get_Current
|
||||
TraceSwitch perfCtrSwitch = new TraceSwitch("ConnectionPoolPerformanceCounterDetail", "level of detail to track with connection pool performance counters");
|
||||
if (TraceLevel.Verbose == perfCtrSwitch.Level) {
|
||||
verboseCategoryName = categoryName;
|
||||
}
|
||||
}
|
||||
SoftConnectsPerSecond = new Counter(verboseCategoryName, instanceName, CreationData.SoftConnectsPerSecond.CounterName, CreationData.SoftConnectsPerSecond.CounterType);
|
||||
SoftDisconnectsPerSecond = new Counter(verboseCategoryName, instanceName, CreationData.SoftDisconnectsPerSecond.CounterName, CreationData.SoftDisconnectsPerSecond.CounterType);
|
||||
NumberOfActiveConnections = new Counter(verboseCategoryName, instanceName, CreationData.NumberOfActiveConnections.CounterName, CreationData.NumberOfActiveConnections.CounterType);
|
||||
NumberOfFreeConnections = new Counter(verboseCategoryName, instanceName, CreationData.NumberOfFreeConnections.CounterName, CreationData.NumberOfFreeConnections.CounterType);
|
||||
}
|
||||
|
||||
[FileIOPermission(SecurityAction.Assert, Unrestricted=true)]
|
||||
private string GetAssemblyName() {
|
||||
string result = null;
|
||||
|
||||
// First try GetEntryAssembly name, then AppDomain.FriendlyName.
|
||||
Assembly assembly = Assembly.GetEntryAssembly();
|
||||
|
||||
if (null != assembly) {
|
||||
AssemblyName name = assembly.GetName();
|
||||
if (name != null) {
|
||||
result = name.Name; // MDAC 73469
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// SxS: this method uses GetCurrentProcessId to construct the instance name.
|
||||
//
|
||||
[ResourceExposure(ResourceScope.None)]
|
||||
[ResourceConsumption(ResourceScope.Process, ResourceScope.Process)]
|
||||
private string GetInstanceName() {
|
||||
string result = null;
|
||||
|
||||
string instanceName = GetAssemblyName(); // instance perfcounter name
|
||||
|
||||
if (ADP.IsEmpty(instanceName)) {
|
||||
AppDomain appDomain = AppDomain.CurrentDomain;
|
||||
if (null != appDomain) {
|
||||
instanceName = appDomain.FriendlyName;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
int pid = SafeNativeMethods.GetCurrentProcessId();
|
||||
|
||||
|
||||
// SQLBUDT #366157 -there are several characters which have special meaning
|
||||
// to PERFMON. They recommend that we translate them as shown below, to
|
||||
// prevent problems.
|
||||
|
||||
result = String.Format((IFormatProvider)null, "{0}[{1}]", instanceName, pid);
|
||||
result = result.Replace('(','[').Replace(')',']').Replace('#','_').Replace('/','_').Replace('\\','_');
|
||||
|
||||
// SQLBUVSTS #94625 - counter instance name cannot be greater than 127
|
||||
if (result.Length > CounterInstanceNameMaxLength) {
|
||||
// Replacing the middle part with "[...]"
|
||||
// For example: if path is c:\long_path\very_(Ax200)_long__path\perftest.exe and process ID is 1234 than the resulted instance name will be:
|
||||
// c:\long_path\very_(AxM)[...](AxN)_long__path\perftest.exe[1234]
|
||||
// while M and N are adjusted to make each part before and after the [...] = 61 (making the total = 61 + 5 + 61 = 127)
|
||||
const string insertString = "[...]";
|
||||
int firstPartLength = (CounterInstanceNameMaxLength - insertString.Length) / 2;
|
||||
int lastPartLength = CounterInstanceNameMaxLength - firstPartLength - insertString.Length;
|
||||
result = string.Format((IFormatProvider)null, "{0}{1}{2}",
|
||||
result.Substring(0, firstPartLength),
|
||||
insertString,
|
||||
result.Substring(result.Length - lastPartLength, lastPartLength));
|
||||
|
||||
Debug.Assert(result.Length == CounterInstanceNameMaxLength,
|
||||
string.Format((IFormatProvider)null, "wrong calculation of the instance name: expected {0}, actual: {1}", CounterInstanceNameMaxLength, result.Length));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
|
||||
public void Dispose() {
|
||||
// ExceptionEventHandler with IsTerminiating may be called before
|
||||
// the Connection Close is called or the variables are initialized
|
||||
SafeDispose(HardConnectsPerSecond);
|
||||
SafeDispose(HardDisconnectsPerSecond);
|
||||
SafeDispose(SoftConnectsPerSecond);
|
||||
SafeDispose(SoftDisconnectsPerSecond);
|
||||
SafeDispose(NumberOfNonPooledConnections);
|
||||
SafeDispose(NumberOfPooledConnections);
|
||||
SafeDispose(NumberOfActiveConnectionPoolGroups);
|
||||
SafeDispose(NumberOfInactiveConnectionPoolGroups);
|
||||
SafeDispose(NumberOfActiveConnectionPools);
|
||||
SafeDispose(NumberOfActiveConnections);
|
||||
SafeDispose(NumberOfFreeConnections);
|
||||
SafeDispose(NumberOfStasisConnections);
|
||||
SafeDispose(NumberOfReclaimedConnections);
|
||||
}
|
||||
|
||||
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
|
||||
private void SafeDispose(Counter counter) { // WebData 103603
|
||||
if (null != counter) {
|
||||
counter.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
[PrePrepareMethod]
|
||||
void ExceptionEventHandler (object sender, UnhandledExceptionEventArgs e) {
|
||||
if ((null != e) && e.IsTerminating) {
|
||||
Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
[PrePrepareMethod]
|
||||
void ExitEventHandler (object sender, EventArgs e) {
|
||||
Dispose();
|
||||
}
|
||||
|
||||
[PrePrepareMethod]
|
||||
void UnloadEventHandler (object sender, EventArgs e) {
|
||||
Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
sealed internal class DbConnectionPoolCountersNoCounters : DbConnectionPoolCounters {
|
||||
|
||||
public static readonly DbConnectionPoolCountersNoCounters SingletonInstance = new DbConnectionPoolCountersNoCounters();
|
||||
|
||||
private DbConnectionPoolCountersNoCounters() : base () {
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,311 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <copyright file="DbConnectionPoolGroup.cs" company="Microsoft">
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// </copyright>
|
||||
// <owner current="true" primary="true">[....]</owner>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace System.Data.ProviderBase {
|
||||
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Data.Common;
|
||||
using System.Diagnostics;
|
||||
using System.Threading;
|
||||
|
||||
// set_ConnectionString calls DbConnectionFactory.GetConnectionPoolGroup
|
||||
// when not found a new pool entry is created and potentially added
|
||||
// DbConnectionPoolGroup starts in the Active state
|
||||
|
||||
// Open calls DbConnectionFactory.GetConnectionPool
|
||||
// if the existing pool entry is Disabled, GetConnectionPoolGroup is called for a new entry
|
||||
// DbConnectionFactory.GetConnectionPool calls DbConnectionPoolGroup.GetConnectionPool
|
||||
|
||||
// DbConnectionPoolGroup.GetConnectionPool will return pool for the current identity
|
||||
// or null if identity is restricted or pooling is disabled or state is disabled at time of add
|
||||
// state changes are Active->Active, Idle->Active
|
||||
|
||||
// DbConnectionFactory.PruneConnectionPoolGroups calls Prune
|
||||
// which will QueuePoolForRelease on all empty pools
|
||||
// and once no pools remain, change state from Active->Idle->Disabled
|
||||
// Once Disabled, factory can remove its reference to the pool entry
|
||||
|
||||
sealed internal class DbConnectionPoolGroup {
|
||||
private readonly DbConnectionOptions _connectionOptions;
|
||||
private readonly DbConnectionPoolKey _poolKey;
|
||||
private readonly DbConnectionPoolGroupOptions _poolGroupOptions;
|
||||
private ConcurrentDictionary<DbConnectionPoolIdentity, DbConnectionPool> _poolCollection;
|
||||
|
||||
private int _state; // see PoolGroupState* below
|
||||
|
||||
private DbConnectionPoolGroupProviderInfo _providerInfo;
|
||||
private DbMetaDataFactory _metaDataFactory;
|
||||
|
||||
private static int _objectTypeCount; // Bid counter
|
||||
internal readonly int _objectID = System.Threading.Interlocked.Increment(ref _objectTypeCount);
|
||||
|
||||
// always lock this before changing _state, we don't want to move out of the 'Disabled' state
|
||||
// PoolGroupStateUninitialized = 0;
|
||||
private const int PoolGroupStateActive = 1; // initial state, GetPoolGroup from cache, connection Open
|
||||
private const int PoolGroupStateIdle = 2; // all pools are pruned via Clear
|
||||
private const int PoolGroupStateDisabled = 4; // factory pool entry prunning method
|
||||
|
||||
internal DbConnectionPoolGroup (DbConnectionOptions connectionOptions, DbConnectionPoolKey key, DbConnectionPoolGroupOptions poolGroupOptions) {
|
||||
Debug.Assert(null != connectionOptions, "null connection options");
|
||||
Debug.Assert(null == poolGroupOptions || ADP.IsWindowsNT, "should not have pooling options on Win9x");
|
||||
|
||||
_connectionOptions = connectionOptions;
|
||||
_poolKey = key;
|
||||
_poolGroupOptions = poolGroupOptions;
|
||||
|
||||
// always lock this object before changing state
|
||||
// HybridDictionary does not create any sub-objects until add
|
||||
// so it is safe to use for non-pooled connection as long as
|
||||
// we check _poolGroupOptions first
|
||||
_poolCollection = new ConcurrentDictionary<DbConnectionPoolIdentity, DbConnectionPool>();
|
||||
_state = PoolGroupStateActive; // VSWhidbey 112102
|
||||
}
|
||||
|
||||
internal DbConnectionOptions ConnectionOptions {
|
||||
get {
|
||||
return _connectionOptions;
|
||||
}
|
||||
}
|
||||
|
||||
internal DbConnectionPoolKey PoolKey {
|
||||
get {
|
||||
return _poolKey;
|
||||
}
|
||||
}
|
||||
|
||||
internal DbConnectionPoolGroupProviderInfo ProviderInfo {
|
||||
get {
|
||||
return _providerInfo;
|
||||
}
|
||||
set {
|
||||
_providerInfo = value;
|
||||
if(null!=value) {
|
||||
_providerInfo.PoolGroup = this;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal bool IsDisabled {
|
||||
get {
|
||||
return (PoolGroupStateDisabled == _state);
|
||||
}
|
||||
}
|
||||
|
||||
internal int ObjectID {
|
||||
get {
|
||||
return _objectID;
|
||||
}
|
||||
}
|
||||
|
||||
internal DbConnectionPoolGroupOptions PoolGroupOptions {
|
||||
get {
|
||||
return _poolGroupOptions;
|
||||
}
|
||||
}
|
||||
|
||||
internal DbMetaDataFactory MetaDataFactory{
|
||||
get {
|
||||
return _metaDataFactory;
|
||||
}
|
||||
|
||||
set {
|
||||
_metaDataFactory = value;
|
||||
}
|
||||
}
|
||||
|
||||
internal int Clear() {
|
||||
// must be multi-thread safe with competing calls by Clear and Prune via background thread
|
||||
// will return the number of connections in the group after clearing has finished
|
||||
|
||||
// First, note the old collection and create a new collection to be used
|
||||
ConcurrentDictionary<DbConnectionPoolIdentity, DbConnectionPool> oldPoolCollection = null;
|
||||
lock (this) {
|
||||
if (_poolCollection.Count > 0) {
|
||||
oldPoolCollection = _poolCollection;
|
||||
_poolCollection = new ConcurrentDictionary<DbConnectionPoolIdentity, DbConnectionPool>();
|
||||
}
|
||||
}
|
||||
|
||||
// Then, if a new collection was created, release the pools from the old collection
|
||||
if (oldPoolCollection != null) {
|
||||
foreach (var entry in oldPoolCollection) {
|
||||
DbConnectionPool pool = entry.Value;
|
||||
if (pool != null) {
|
||||
//
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
DbConnectionFactory connectionFactory = pool.ConnectionFactory;
|
||||
#if !MOBILE
|
||||
connectionFactory.PerformanceCounters.NumberOfActiveConnectionPools.Decrement();
|
||||
#endif
|
||||
connectionFactory.QueuePoolForRelease(pool, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Finally, return the pool collection count - this may be non-zero if something was added while we were clearing
|
||||
return _poolCollection.Count;
|
||||
}
|
||||
|
||||
internal DbConnectionPool GetConnectionPool(DbConnectionFactory connectionFactory) {
|
||||
// When this method returns null it indicates that the connection
|
||||
// factory should not use pooling.
|
||||
|
||||
// We don't support connection pooling on Win9x; it lacks too
|
||||
// many of the APIs we require.
|
||||
// PoolGroupOptions will only be null when we're not supposed to pool
|
||||
// connections.
|
||||
DbConnectionPool pool = null;
|
||||
if (null != _poolGroupOptions) {
|
||||
Debug.Assert(ADP.IsWindowsNT, "should not be pooling on Win9x");
|
||||
|
||||
DbConnectionPoolIdentity currentIdentity = DbConnectionPoolIdentity.NoIdentity;
|
||||
if (_poolGroupOptions.PoolByIdentity) {
|
||||
// if we're pooling by identity (because integrated security is
|
||||
// being used for these connections) then we need to go out and
|
||||
// search for the connectionPool that matches the current identity.
|
||||
|
||||
currentIdentity = DbConnectionPoolIdentity.GetCurrent();
|
||||
|
||||
// If the current token is restricted in some way, then we must
|
||||
// not attempt to pool these connections.
|
||||
if (currentIdentity.IsRestricted) {
|
||||
currentIdentity = null;
|
||||
}
|
||||
}
|
||||
if (null != currentIdentity) {
|
||||
if (!_poolCollection.TryGetValue(currentIdentity, out pool)) { // find the pool
|
||||
DbConnectionPoolProviderInfo connectionPoolProviderInfo = connectionFactory.CreateConnectionPoolProviderInfo(this.ConnectionOptions);
|
||||
|
||||
// optimistically create pool, but its callbacks are delayed until after actual add
|
||||
DbConnectionPool newPool = new DbConnectionPool(connectionFactory, this, currentIdentity, connectionPoolProviderInfo);
|
||||
|
||||
lock (this) {
|
||||
// Did someone already add it to the list?
|
||||
if (!_poolCollection.TryGetValue(currentIdentity, out pool)) {
|
||||
if (MarkPoolGroupAsActive()) {
|
||||
// If we get here, we know for certain that we there isn't
|
||||
// a pool that matches the current identity, so we have to
|
||||
// add the optimistically created one
|
||||
newPool.Startup(); // must start pool before usage
|
||||
bool addResult = _poolCollection.TryAdd(currentIdentity, newPool);
|
||||
Debug.Assert(addResult, "No other pool with current identity should exist at this point");
|
||||
#if !MOBILE
|
||||
connectionFactory.PerformanceCounters.NumberOfActiveConnectionPools.Increment();
|
||||
#endif
|
||||
pool = newPool;
|
||||
newPool = null;
|
||||
}
|
||||
else {
|
||||
// else pool entry has been disabled so don't create new pools
|
||||
Debug.Assert(PoolGroupStateDisabled == _state, "state should be disabled");
|
||||
}
|
||||
}
|
||||
else {
|
||||
// else found an existing pool to use instead
|
||||
Debug.Assert(PoolGroupStateActive == _state, "state should be active since a pool exists and lock holds");
|
||||
}
|
||||
}
|
||||
|
||||
if (null != newPool) {
|
||||
// don't need to call connectionFactory.QueuePoolForRelease(newPool) because
|
||||
// pool callbacks were delayed and no risk of connections being created
|
||||
newPool.Shutdown();
|
||||
}
|
||||
}
|
||||
// the found pool could be in any state
|
||||
}
|
||||
}
|
||||
|
||||
if (null == pool) {
|
||||
lock(this) {
|
||||
// keep the pool entry state active when not pooling
|
||||
MarkPoolGroupAsActive();
|
||||
}
|
||||
}
|
||||
return pool;
|
||||
}
|
||||
|
||||
private bool MarkPoolGroupAsActive() {
|
||||
// when getting a connection, make the entry active if it was idle (but not disabled)
|
||||
// must always lock this before calling
|
||||
|
||||
if (PoolGroupStateIdle == _state) {
|
||||
_state = PoolGroupStateActive;
|
||||
Bid.Trace("<prov.DbConnectionPoolGroup.ClearInternal|RES|INFO|CPOOL> %d#, Active\n", ObjectID);
|
||||
}
|
||||
return (PoolGroupStateActive == _state);
|
||||
}
|
||||
|
||||
internal bool Prune() {
|
||||
// must only call from DbConnectionFactory.PruneConnectionPoolGroups on background timer thread
|
||||
// must lock(DbConnectionFactory._connectionPoolGroups.SyncRoot) before calling ReadyToRemove
|
||||
// to avoid conflict with DbConnectionFactory.CreateConnectionPoolGroup replacing pool entry
|
||||
lock (this) {
|
||||
if (_poolCollection.Count > 0) {
|
||||
var newPoolCollection = new ConcurrentDictionary<DbConnectionPoolIdentity, DbConnectionPool>();
|
||||
|
||||
foreach (var entry in _poolCollection) {
|
||||
DbConnectionPool pool = entry.Value;
|
||||
if (pool != null) {
|
||||
//
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// Actually prune the pool if there are no connections in the pool and no errors occurred.
|
||||
// Empty pool during pruning indicates zero or low activity, but
|
||||
// an error state indicates the pool needs to stay around to
|
||||
// throttle new connection attempts.
|
||||
if ((!pool.ErrorOccurred) && (0 == pool.Count)) {
|
||||
|
||||
// Order is important here. First we remove the pool
|
||||
// from the collection of pools so no one will try
|
||||
// to use it while we're processing and finally we put the
|
||||
// pool into a list of pools to be released when they
|
||||
// are completely empty.
|
||||
DbConnectionFactory connectionFactory = pool.ConnectionFactory;
|
||||
|
||||
#if !MOBILE
|
||||
connectionFactory.PerformanceCounters.NumberOfActiveConnectionPools.Decrement();
|
||||
#endif
|
||||
connectionFactory.QueuePoolForRelease(pool, false);
|
||||
}
|
||||
else {
|
||||
newPoolCollection.TryAdd(entry.Key, entry.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
_poolCollection = newPoolCollection;
|
||||
}
|
||||
|
||||
// must be pruning thread to change state and no connections
|
||||
// otherwise pruning thread risks making entry disabled soon after user calls ClearPool
|
||||
if (0 == _poolCollection.Count) {
|
||||
if (PoolGroupStateActive == _state) {
|
||||
_state = PoolGroupStateIdle;
|
||||
Bid.Trace("<prov.DbConnectionPoolGroup.ClearInternal|RES|INFO|CPOOL> %d#, Idle\n", ObjectID);
|
||||
}
|
||||
else if (PoolGroupStateIdle == _state) {
|
||||
_state = PoolGroupStateDisabled;
|
||||
Bid.Trace("<prov.DbConnectionPoolGroup.ReadyToRemove|RES|INFO|CPOOL> %d#, Disabled\n", ObjectID);
|
||||
}
|
||||
}
|
||||
return (PoolGroupStateDisabled == _state);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <copyright file="DbConnectionPoolGroupProviderInfo.cs" company="Microsoft">
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// </copyright>
|
||||
// <owner current="true" primary="true">[....]</owner>
|
||||
// <owner current="true" primary="false">[....]</owner>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace System.Data.ProviderBase {
|
||||
|
||||
using System;
|
||||
internal class DbConnectionPoolGroupProviderInfo {
|
||||
private DbConnectionPoolGroup _poolGroup;
|
||||
|
||||
internal DbConnectionPoolGroup PoolGroup {
|
||||
get {
|
||||
return _poolGroup;
|
||||
}
|
||||
set {
|
||||
_poolGroup = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,213 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <copyright file="DbConnectionPoolIdentity.cs" company="Microsoft">
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// </copyright>
|
||||
// <owner current="true" primary="true">[....]</owner>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace System.Data.ProviderBase {
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Data.Common;
|
||||
using System.Diagnostics;
|
||||
using System.Globalization;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Security;
|
||||
using System.Security.Permissions;
|
||||
using System.Security.Principal;
|
||||
using System.Threading;
|
||||
using System.Runtime.Versioning;
|
||||
|
||||
[Serializable] // Serializable so SqlDependencyProcessDispatcher can marshall cross domain to SqlDependency.
|
||||
sealed internal class DbConnectionPoolIdentity {
|
||||
private const int E_NotImpersonationToken = unchecked((int)0x8007051D);
|
||||
private const int Win32_CheckTokenMembership = 1;
|
||||
private const int Win32_GetTokenInformation_1 = 2;
|
||||
private const int Win32_GetTokenInformation_2 = 3;
|
||||
private const int Win32_ConvertSidToStringSidW = 4;
|
||||
private const int Win32_CreateWellKnownSid = 5;
|
||||
|
||||
static public readonly DbConnectionPoolIdentity NoIdentity = new DbConnectionPoolIdentity(String.Empty, false, true);
|
||||
static private readonly byte[] NetworkSid = (ADP.IsWindowsNT ? CreateWellKnownSid(WellKnownSidType.NetworkSid) : null);
|
||||
static private DbConnectionPoolIdentity _lastIdentity = null;
|
||||
|
||||
private readonly string _sidString;
|
||||
private readonly bool _isRestricted;
|
||||
private readonly bool _isNetwork;
|
||||
private readonly int _hashCode;
|
||||
|
||||
private DbConnectionPoolIdentity (string sidString, bool isRestricted, bool isNetwork) {
|
||||
_sidString = sidString;
|
||||
_isRestricted = isRestricted;
|
||||
_isNetwork = isNetwork;
|
||||
_hashCode = sidString == null ? 0 : sidString.GetHashCode();
|
||||
}
|
||||
|
||||
internal bool IsRestricted {
|
||||
get { return _isRestricted; }
|
||||
}
|
||||
|
||||
internal bool IsNetwork {
|
||||
get { return _isNetwork; }
|
||||
}
|
||||
|
||||
static private byte[] CreateWellKnownSid(WellKnownSidType sidType) {
|
||||
// Passing an array as big as it can ever be is a small price to pay for
|
||||
// not having to P/Invoke twice (once to get the buffer, once to get the data)
|
||||
|
||||
uint length = ( uint )SecurityIdentifier.MaxBinaryLength;
|
||||
byte[] resultSid = new byte[ length ];
|
||||
|
||||
// NOTE - We copied this code from System.Security.Principal.Win32.CreateWellKnownSid...
|
||||
|
||||
if ( 0 == UnsafeNativeMethods.CreateWellKnownSid(( int )sidType, null, resultSid, ref length )) {
|
||||
IntegratedSecurityError(Win32_CreateWellKnownSid);
|
||||
}
|
||||
return resultSid;
|
||||
}
|
||||
|
||||
override public bool Equals(object value) {
|
||||
bool result = ((this == NoIdentity) || (this == value));
|
||||
if (!result && (null != value)) {
|
||||
DbConnectionPoolIdentity that = ((DbConnectionPoolIdentity) value);
|
||||
result = ((this._sidString == that._sidString) && (this._isRestricted == that._isRestricted) && (this._isNetwork == that._isNetwork));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
[SecurityPermission(SecurityAction.Assert, Flags=SecurityPermissionFlag.ControlPrincipal)]
|
||||
static internal WindowsIdentity GetCurrentWindowsIdentity() {
|
||||
return WindowsIdentity.GetCurrent();
|
||||
}
|
||||
|
||||
[SecurityPermission(SecurityAction.Assert, Flags=SecurityPermissionFlag.UnmanagedCode)]
|
||||
static private IntPtr GetWindowsIdentityToken(WindowsIdentity identity) {
|
||||
return identity.Token;
|
||||
}
|
||||
|
||||
[ResourceExposure(ResourceScope.None)] // SxS: this method does not create named objects
|
||||
[ResourceConsumption(ResourceScope.Process, ResourceScope.Process)]
|
||||
static internal DbConnectionPoolIdentity GetCurrent() {
|
||||
|
||||
// DEVNOTE: GetTokenInfo and EqualSID do not work on 9x. WindowsIdentity does not
|
||||
// work either on 9x. In fact, after checking with native there is no way
|
||||
// to validate the user on 9x, so simply don't. It is a known issue in
|
||||
// native, and we will handle this the same way.
|
||||
|
||||
if (!ADP.IsWindowsNT) {
|
||||
return NoIdentity;
|
||||
}
|
||||
|
||||
WindowsIdentity identity = GetCurrentWindowsIdentity();
|
||||
IntPtr token = GetWindowsIdentityToken(identity); // Free'd by WindowsIdentity.
|
||||
uint bufferLength = 2048; // Suggested default given by Greg Fee.
|
||||
uint lengthNeeded = 0;
|
||||
|
||||
IntPtr tokenStruct = IntPtr.Zero;
|
||||
IntPtr SID;
|
||||
IntPtr sidStringBuffer = IntPtr.Zero;
|
||||
bool isNetwork;
|
||||
|
||||
// Win32NativeMethods.IsTokenRestricted will raise exception if the native call fails
|
||||
bool isRestricted = Win32NativeMethods.IsTokenRestrictedWrapper(token);
|
||||
|
||||
DbConnectionPoolIdentity current = null;
|
||||
|
||||
RuntimeHelpers.PrepareConstrainedRegions();
|
||||
try {
|
||||
if (!UnsafeNativeMethods.CheckTokenMembership(token, NetworkSid, out isNetwork)) {
|
||||
// will always fail with 0x8007051D if token is not an impersonation token
|
||||
IntegratedSecurityError(Win32_CheckTokenMembership);
|
||||
}
|
||||
|
||||
RuntimeHelpers.PrepareConstrainedRegions();
|
||||
try { } finally {
|
||||
// allocating memory and assigning to tokenStruct must happen
|
||||
tokenStruct = SafeNativeMethods.LocalAlloc(DbBuffer.LMEM_FIXED, (IntPtr)bufferLength);
|
||||
}
|
||||
if (IntPtr.Zero == tokenStruct) {
|
||||
throw new OutOfMemoryException();
|
||||
}
|
||||
if (!UnsafeNativeMethods.GetTokenInformation(token, 1, tokenStruct, bufferLength, ref lengthNeeded)) {
|
||||
if (lengthNeeded > bufferLength) {
|
||||
bufferLength = lengthNeeded;
|
||||
|
||||
RuntimeHelpers.PrepareConstrainedRegions();
|
||||
try { } finally {
|
||||
// freeing token struct and setting tokenstruct to null must happen together
|
||||
// allocating memory and assigning to tokenStruct must happen
|
||||
SafeNativeMethods.LocalFree(tokenStruct);
|
||||
tokenStruct = IntPtr.Zero; // protect against LocalAlloc throwing an exception
|
||||
tokenStruct = SafeNativeMethods.LocalAlloc(DbBuffer.LMEM_FIXED, (IntPtr)bufferLength);
|
||||
}
|
||||
if (IntPtr.Zero == tokenStruct) {
|
||||
throw new OutOfMemoryException();
|
||||
}
|
||||
|
||||
if (!UnsafeNativeMethods.GetTokenInformation(token, 1, tokenStruct, bufferLength, ref lengthNeeded)) {
|
||||
IntegratedSecurityError(Win32_GetTokenInformation_1);
|
||||
}
|
||||
}
|
||||
else {
|
||||
IntegratedSecurityError(Win32_GetTokenInformation_2);
|
||||
}
|
||||
}
|
||||
|
||||
identity.Dispose(); // Keep identity variable alive until after GetTokenInformation calls.
|
||||
|
||||
|
||||
SID = Marshal.ReadIntPtr(tokenStruct, 0);
|
||||
|
||||
if (!UnsafeNativeMethods.ConvertSidToStringSidW(SID, out sidStringBuffer)) {
|
||||
IntegratedSecurityError(Win32_ConvertSidToStringSidW);
|
||||
}
|
||||
|
||||
if (IntPtr.Zero == sidStringBuffer) {
|
||||
throw ADP.InternalError(ADP.InternalErrorCode.ConvertSidToStringSidWReturnedNull);
|
||||
}
|
||||
|
||||
string sidString = Marshal.PtrToStringUni(sidStringBuffer);
|
||||
|
||||
var lastIdentity = _lastIdentity;
|
||||
if ((lastIdentity != null) && (lastIdentity._sidString == sidString) && (lastIdentity._isRestricted == isRestricted) && (lastIdentity._isNetwork == isNetwork)) {
|
||||
current = lastIdentity;
|
||||
}
|
||||
else {
|
||||
current = new DbConnectionPoolIdentity(sidString, isRestricted, isNetwork);
|
||||
}
|
||||
}
|
||||
finally {
|
||||
// Marshal.FreeHGlobal does not have a ReliabilityContract
|
||||
if (IntPtr.Zero != tokenStruct) {
|
||||
SafeNativeMethods.LocalFree(tokenStruct);
|
||||
tokenStruct = IntPtr.Zero;
|
||||
}
|
||||
if (IntPtr.Zero != sidStringBuffer) {
|
||||
SafeNativeMethods.LocalFree(sidStringBuffer);
|
||||
sidStringBuffer = IntPtr.Zero;
|
||||
}
|
||||
}
|
||||
_lastIdentity = current;
|
||||
return current;
|
||||
}
|
||||
|
||||
override public int GetHashCode() {
|
||||
return _hashCode;
|
||||
}
|
||||
|
||||
static private void IntegratedSecurityError(int caller) {
|
||||
#if !FULL_AOT_RUNTIME
|
||||
// passing 1,2,3,4,5 instead of true/false so that with a debugger
|
||||
// we could determine more easily which Win32 method call failed
|
||||
int lastError = Marshal.GetHRForLastWin32Error();
|
||||
if ((Win32_CheckTokenMembership != caller) || (E_NotImpersonationToken != lastError)) {
|
||||
Marshal.ThrowExceptionForHR(lastError); // will only throw if (hresult < 0)
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,67 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <copyright file="DbConnectionPoolGroupOptions.cs" company="Microsoft">
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// </copyright>
|
||||
// <owner current="true" primary="true">[....]</owner>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace System.Data.ProviderBase {
|
||||
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
|
||||
internal sealed class DbConnectionPoolGroupOptions {
|
||||
|
||||
private readonly bool _poolByIdentity;
|
||||
private readonly int _minPoolSize;
|
||||
private readonly int _maxPoolSize;
|
||||
private readonly int _creationTimeout;
|
||||
private readonly TimeSpan _loadBalanceTimeout;
|
||||
private readonly bool _hasTransactionAffinity;
|
||||
private readonly bool _useLoadBalancing;
|
||||
|
||||
public DbConnectionPoolGroupOptions(
|
||||
bool poolByIdentity,
|
||||
int minPoolSize,
|
||||
int maxPoolSize,
|
||||
int creationTimeout,
|
||||
int loadBalanceTimeout,
|
||||
bool hasTransactionAffinity) {
|
||||
_poolByIdentity = poolByIdentity;
|
||||
_minPoolSize = minPoolSize;
|
||||
_maxPoolSize = maxPoolSize;
|
||||
_creationTimeout = creationTimeout;
|
||||
|
||||
if (0 != loadBalanceTimeout) {
|
||||
_loadBalanceTimeout = new TimeSpan(0, 0, loadBalanceTimeout);
|
||||
_useLoadBalancing = true;
|
||||
}
|
||||
|
||||
_hasTransactionAffinity = hasTransactionAffinity;
|
||||
}
|
||||
|
||||
public int CreationTimeout {
|
||||
get { return _creationTimeout; }
|
||||
}
|
||||
public bool HasTransactionAffinity {
|
||||
get { return _hasTransactionAffinity; }
|
||||
}
|
||||
public TimeSpan LoadBalanceTimeout {
|
||||
get { return _loadBalanceTimeout; }
|
||||
}
|
||||
public int MaxPoolSize {
|
||||
get { return _maxPoolSize; }
|
||||
}
|
||||
public int MinPoolSize {
|
||||
get { return _minPoolSize; }
|
||||
}
|
||||
public bool PoolByIdentity {
|
||||
get { return _poolByIdentity; }
|
||||
}
|
||||
public bool UseLoadBalancing {
|
||||
get { return _useLoadBalancing; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,15 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <copyright file="DbConnectionPoolProviderInfo.cs" company="Microsoft">
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// </copyright>
|
||||
// <owner current="true" primary="true">stevesta</owner>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace System.Data.ProviderBase {
|
||||
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
|
||||
internal class DbConnectionPoolProviderInfo {
|
||||
}
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <copyright file="DbMetaDataCollectionNames.cs" company="Microsoft">
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// </copyright>
|
||||
// <owner current="true" primary="true">[....]</owner>
|
||||
// <owner current="true" primary="false">[....]</owner>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace System.Data.Common {
|
||||
|
||||
public static class DbMetaDataCollectionNames {
|
||||
|
||||
public static readonly string MetaDataCollections = "MetaDataCollections";
|
||||
public static readonly string DataSourceInformation = "DataSourceInformation";
|
||||
public static readonly string DataTypes = "DataTypes";
|
||||
public static readonly string Restrictions = "Restrictions";
|
||||
public static readonly string ReservedWords = "ReservedWords";
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,58 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <copyright file="DbMetaDataColumnNames.cs" company="Microsoft">
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// </copyright>
|
||||
// <owner current="true" primary="true">[....]</owner>
|
||||
// <owner current="true" primary="false">[....]</owner>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace System.Data.Common {
|
||||
|
||||
public static class DbMetaDataColumnNames {
|
||||
|
||||
public static readonly string CollectionName = "CollectionName";
|
||||
public static readonly string ColumnSize = "ColumnSize";
|
||||
public static readonly string CompositeIdentifierSeparatorPattern = "CompositeIdentifierSeparatorPattern";
|
||||
public static readonly string CreateFormat = "CreateFormat";
|
||||
public static readonly string CreateParameters = "CreateParameters";
|
||||
public static readonly string DataSourceProductName = "DataSourceProductName";
|
||||
public static readonly string DataSourceProductVersion = "DataSourceProductVersion";
|
||||
public static readonly string DataType = "DataType";
|
||||
public static readonly string DataSourceProductVersionNormalized = "DataSourceProductVersionNormalized";
|
||||
public static readonly string GroupByBehavior = "GroupByBehavior";
|
||||
public static readonly string IdentifierCase = "IdentifierCase";
|
||||
public static readonly string IdentifierPattern = "IdentifierPattern";
|
||||
public static readonly string IsAutoIncrementable = "IsAutoIncrementable";
|
||||
public static readonly string IsBestMatch = "IsBestMatch";
|
||||
public static readonly string IsCaseSensitive = "IsCaseSensitive";
|
||||
public static readonly string IsConcurrencyType = "IsConcurrencyType";
|
||||
public static readonly string IsFixedLength = "IsFixedLength";
|
||||
public static readonly string IsFixedPrecisionScale = "IsFixedPrecisionScale";
|
||||
public static readonly string IsLiteralSupported = "IsLiteralSupported";
|
||||
public static readonly string IsLong = "IsLong";
|
||||
public static readonly string IsNullable = "IsNullable";
|
||||
public static readonly string IsSearchable = "IsSearchable";
|
||||
public static readonly string IsSearchableWithLike = "IsSearchableWithLike";
|
||||
public static readonly string IsUnsigned = "IsUnsigned";
|
||||
public static readonly string LiteralPrefix = "LiteralPrefix";
|
||||
public static readonly string LiteralSuffix = "LiteralSuffix";
|
||||
public static readonly string MaximumScale = "MaximumScale";
|
||||
public static readonly string MinimumScale = "MinimumScale";
|
||||
public static readonly string NumberOfIdentifierParts = "NumberOfIdentifierParts";
|
||||
public static readonly string NumberOfRestrictions = "NumberOfRestrictions";
|
||||
public static readonly string OrderByColumnsInSelect = "OrderByColumnsInSelect";
|
||||
public static readonly string ParameterMarkerFormat = "ParameterMarkerFormat";
|
||||
public static readonly string ParameterMarkerPattern = "ParameterMarkerPattern";
|
||||
public static readonly string ParameterNameMaxLength = "ParameterNameMaxLength";
|
||||
public static readonly string ParameterNamePattern = "ParameterNamePattern";
|
||||
public static readonly string ProviderDbType = "ProviderDbType";
|
||||
public static readonly string QuotedIdentifierCase = "QuotedIdentifierCase";
|
||||
public static readonly string QuotedIdentifierPattern = "QuotedIdentifierPattern";
|
||||
public static readonly string ReservedWord = "ReservedWord";
|
||||
public static readonly string StatementSeparatorPattern = "StatementSeparatorPattern";
|
||||
public static readonly string StringLiteralPattern = "StringLiteralPattern";
|
||||
public static readonly string SupportedJoinOperators = "SupportedJoinOperators";
|
||||
public static readonly string TypeName = "TypeName";
|
||||
}
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,288 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <copyright file="DbParameterCollectionBase.cs" company="Microsoft">
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// </copyright>
|
||||
// <owner current="true" primary="true">[....]</owner>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace NAMESPACE
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Data;
|
||||
using System.Data.Common;
|
||||
using System.Data.ProviderBase;
|
||||
using System.Diagnostics;
|
||||
using System.Globalization;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
public sealed partial class PARAMETERCOLLECTIONOBJECTNAME : DbParameterCollection {
|
||||
private List<PARAMETEROBJECTNAME> _items; // the collection of parameters
|
||||
|
||||
override public int Count {
|
||||
get {
|
||||
// NOTE: we don't construct the list just to get the count.
|
||||
return ((null != _items) ? _items.Count : 0);
|
||||
}
|
||||
}
|
||||
|
||||
private List<PARAMETEROBJECTNAME> InnerList {
|
||||
get {
|
||||
List<PARAMETEROBJECTNAME> items = _items;
|
||||
|
||||
if (null == items) {
|
||||
items = new List<PARAMETEROBJECTNAME>();
|
||||
_items = items;
|
||||
}
|
||||
return items;
|
||||
}
|
||||
}
|
||||
|
||||
override public bool IsFixedSize {
|
||||
get {
|
||||
return ((System.Collections.IList)InnerList).IsFixedSize;
|
||||
}
|
||||
}
|
||||
|
||||
override public bool IsReadOnly {
|
||||
get {
|
||||
return ((System.Collections.IList)InnerList).IsReadOnly;
|
||||
}
|
||||
}
|
||||
|
||||
override public bool IsSynchronized {
|
||||
get {
|
||||
return ((System.Collections.ICollection)InnerList).IsSynchronized;
|
||||
}
|
||||
}
|
||||
|
||||
override public object SyncRoot {
|
||||
get {
|
||||
return ((System.Collections.ICollection)InnerList).SyncRoot;
|
||||
}
|
||||
}
|
||||
|
||||
[
|
||||
EditorBrowsableAttribute(EditorBrowsableState.Never)
|
||||
]
|
||||
override public int Add(object value) {
|
||||
OnChange(); // fire event before value is validated
|
||||
ValidateType(value);
|
||||
Validate(-1, value);
|
||||
InnerList.Add((PARAMETEROBJECTNAME)value);
|
||||
return Count-1;
|
||||
}
|
||||
|
||||
override public void AddRange(System.Array values) {
|
||||
OnChange(); // fire event before value is validated
|
||||
if (null == values) {
|
||||
throw ADP.ArgumentNull("values");
|
||||
}
|
||||
foreach(object value in values) {
|
||||
ValidateType(value);
|
||||
}
|
||||
foreach(PARAMETEROBJECTNAME value in values) {
|
||||
Validate(-1, value);
|
||||
InnerList.Add((PARAMETEROBJECTNAME)value);
|
||||
}
|
||||
}
|
||||
|
||||
private int CheckName(string parameterName) {
|
||||
int index = IndexOf(parameterName);
|
||||
if (index < 0) {
|
||||
throw ADP.ParametersSourceIndex(parameterName, this, ItemType);
|
||||
}
|
||||
return index;
|
||||
}
|
||||
|
||||
override public void Clear() {
|
||||
OnChange(); // fire event before value is validated
|
||||
List<PARAMETEROBJECTNAME> items = InnerList;
|
||||
|
||||
if (null != items) {
|
||||
foreach(PARAMETEROBJECTNAME item in items) {
|
||||
item.ResetParent();
|
||||
}
|
||||
items.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
override public bool Contains(object value) {
|
||||
return (-1 != IndexOf(value));
|
||||
}
|
||||
|
||||
override public void CopyTo(Array array, int index) {
|
||||
((System.Collections.ICollection)InnerList).CopyTo(array, index);
|
||||
}
|
||||
|
||||
override public System.Collections.IEnumerator GetEnumerator() {
|
||||
return ((System.Collections.ICollection)InnerList).GetEnumerator();
|
||||
}
|
||||
|
||||
override protected DbParameter GetParameter(int index) {
|
||||
RangeCheck(index);
|
||||
return InnerList[index];
|
||||
}
|
||||
|
||||
override protected DbParameter GetParameter(string parameterName) {
|
||||
int index = IndexOf(parameterName);
|
||||
if (index < 0) {
|
||||
throw ADP.ParametersSourceIndex(parameterName, this, ItemType);
|
||||
}
|
||||
return InnerList[index];
|
||||
}
|
||||
|
||||
private static int IndexOf(System.Collections.IEnumerable items, string parameterName) {
|
||||
if (null != items) {
|
||||
int i = 0;
|
||||
// first case, kana, width sensitive search
|
||||
foreach(PARAMETEROBJECTNAME parameter in items) {
|
||||
if (0 == ADP.SrcCompare(parameterName, parameter.ParameterName)) {
|
||||
return i;
|
||||
}
|
||||
++i;
|
||||
}
|
||||
i = 0;
|
||||
// then insensitive search
|
||||
foreach(PARAMETEROBJECTNAME parameter in items) {
|
||||
if (0 == ADP.DstCompare(parameterName, parameter.ParameterName)) {
|
||||
return i;
|
||||
}
|
||||
++i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
override public int IndexOf(string parameterName) {
|
||||
return IndexOf(InnerList, parameterName);
|
||||
}
|
||||
|
||||
override public int IndexOf(object value) {
|
||||
if (null != value) {
|
||||
ValidateType(value);
|
||||
|
||||
List<PARAMETEROBJECTNAME> items = InnerList;
|
||||
|
||||
if (null != items) {
|
||||
int count = items.Count;
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
if (value == items[i]) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
override public void Insert(int index, object value) {
|
||||
OnChange(); // fire event before value is validated
|
||||
ValidateType(value);
|
||||
Validate(-1, (PARAMETEROBJECTNAME)value);
|
||||
InnerList.Insert(index, (PARAMETEROBJECTNAME)value);
|
||||
}
|
||||
|
||||
private void RangeCheck(int index) {
|
||||
if ((index < 0) || (Count <= index)) {
|
||||
throw ADP.ParametersMappingIndex(index, this);
|
||||
}
|
||||
}
|
||||
|
||||
override public void Remove(object value) {
|
||||
OnChange(); // fire event before value is validated
|
||||
ValidateType(value);
|
||||
int index = IndexOf(value);
|
||||
if (-1 != index) {
|
||||
RemoveIndex(index);
|
||||
}
|
||||
else if (this != ((PARAMETEROBJECTNAME)value).CompareExchangeParent(null, this)) {
|
||||
throw ADP.CollectionRemoveInvalidObject(ItemType, this);
|
||||
}
|
||||
}
|
||||
|
||||
override public void RemoveAt(int index) {
|
||||
OnChange(); // fire event before value is validated
|
||||
RangeCheck(index);
|
||||
RemoveIndex(index);
|
||||
}
|
||||
|
||||
override public void RemoveAt(string parameterName) {
|
||||
OnChange(); // fire event before value is validated
|
||||
int index = CheckName(parameterName);
|
||||
RemoveIndex(index);
|
||||
}
|
||||
|
||||
private void RemoveIndex(int index) {
|
||||
List<PARAMETEROBJECTNAME> items = InnerList;
|
||||
Debug.Assert((null != items) && (0 <= index) && (index < Count), "RemoveIndex, invalid");
|
||||
PARAMETEROBJECTNAME item = items[index];
|
||||
items.RemoveAt(index);
|
||||
item.ResetParent();
|
||||
}
|
||||
|
||||
private void Replace(int index, object newValue) {
|
||||
List<PARAMETEROBJECTNAME> items = InnerList;
|
||||
Debug.Assert((null != items) && (0 <= index) && (index < Count), "Replace Index invalid");
|
||||
ValidateType(newValue);
|
||||
Validate(index, newValue);
|
||||
PARAMETEROBJECTNAME item = items[index];
|
||||
items[index] = (PARAMETEROBJECTNAME)newValue;
|
||||
item.ResetParent();
|
||||
}
|
||||
|
||||
override protected void SetParameter(int index, DbParameter value) {
|
||||
OnChange(); // fire event before value is validated
|
||||
RangeCheck(index);
|
||||
Replace(index, value);
|
||||
}
|
||||
|
||||
override protected void SetParameter(string parameterName, DbParameter value) {
|
||||
OnChange(); // fire event before value is validated
|
||||
int index = IndexOf(parameterName);
|
||||
if (index < 0) {
|
||||
throw ADP.ParametersSourceIndex(parameterName, this, ItemType);
|
||||
}
|
||||
Replace(index, value);
|
||||
}
|
||||
|
||||
private void Validate(int index, object value) {
|
||||
if (null == value) {
|
||||
throw ADP.ParameterNull("value", this, ItemType);
|
||||
}
|
||||
// Validate assigns the parent - remove clears the parent
|
||||
object parent = ((PARAMETEROBJECTNAME)value).CompareExchangeParent(this, null);
|
||||
if (null != parent) {
|
||||
if (this != parent) {
|
||||
throw ADP.ParametersIsNotParent(ItemType, this);
|
||||
}
|
||||
if (index != IndexOf(value)) {
|
||||
throw ADP.ParametersIsParent(ItemType, this);
|
||||
}
|
||||
}
|
||||
// generate a ParameterName
|
||||
String name = ((PARAMETEROBJECTNAME)value).ParameterName;
|
||||
if (0 == name.Length) {
|
||||
index = 1;
|
||||
do {
|
||||
name = ADP.Parameter + index.ToString(CultureInfo.CurrentCulture);
|
||||
index++;
|
||||
} while (-1 != IndexOf(name));
|
||||
((PARAMETEROBJECTNAME)value).ParameterName = name;
|
||||
}
|
||||
}
|
||||
|
||||
private void ValidateType(object value) {
|
||||
if (null == value) {
|
||||
throw ADP.ParameterNull("value", this, ItemType);
|
||||
}
|
||||
else if (!ItemType.IsInstanceOfType(value)) {
|
||||
throw ADP.InvalidParameterType(this, ItemType, value);
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
@ -0,0 +1,271 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <copyright file="DbParameterHelper.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.Globalization;
|
||||
|
||||
public sealed partial class PARAMETEROBJECTNAME : DbParameter { // V1.2.3300
|
||||
private object _value;
|
||||
|
||||
private object _parent;
|
||||
|
||||
private ParameterDirection _direction;
|
||||
private int _size;
|
||||
#if USEOFFSET // USEOFFSET is set in makefile.inc for SqlParameter class only
|
||||
private int _offset;
|
||||
#endif
|
||||
private string _sourceColumn;
|
||||
private DataRowVersion _sourceVersion;
|
||||
private bool _sourceColumnNullMapping;
|
||||
|
||||
private bool _isNullable;
|
||||
|
||||
private object _coercedValue;
|
||||
|
||||
private PARAMETEROBJECTNAME(PARAMETEROBJECTNAME source) : this() { // V1.2.3300, Clone
|
||||
ADP.CheckArgumentNull(source, "source");
|
||||
|
||||
source.CloneHelper(this);
|
||||
|
||||
ICloneable cloneable = (_value as ICloneable);
|
||||
if (null != cloneable) { // MDAC 49322
|
||||
_value = cloneable.Clone();
|
||||
}
|
||||
}
|
||||
|
||||
private object CoercedValue { // V1.2.3300
|
||||
get {
|
||||
return _coercedValue;
|
||||
}
|
||||
set {
|
||||
_coercedValue = value;
|
||||
}
|
||||
}
|
||||
|
||||
[
|
||||
RefreshProperties(RefreshProperties.All),
|
||||
RESNAMESPACE.ResCategoryAttribute(Res.DataCategory_Data),
|
||||
RESNAMESPACE.ResDescriptionAttribute(Res.DbParameter_Direction),
|
||||
]
|
||||
override public ParameterDirection Direction { // V1.2.3300, XXXParameter V1.0.3300
|
||||
get {
|
||||
ParameterDirection direction = _direction;
|
||||
return ((0 != direction) ? direction : ParameterDirection.Input);
|
||||
}
|
||||
set {
|
||||
if (_direction != value) {
|
||||
switch (value) { // @perfnote: Enum.IsDefined
|
||||
case ParameterDirection.Input:
|
||||
case ParameterDirection.Output:
|
||||
case ParameterDirection.InputOutput:
|
||||
case ParameterDirection.ReturnValue:
|
||||
PropertyChanging();
|
||||
_direction = value;
|
||||
break;
|
||||
default:
|
||||
throw ADP.InvalidParameterDirection(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override public bool IsNullable { // V1.2.3300, XXXParameter V1.0.3300
|
||||
get {
|
||||
return _isNullable;
|
||||
}
|
||||
set {
|
||||
_isNullable = value;
|
||||
}
|
||||
}
|
||||
|
||||
#if USEOFFSET
|
||||
[
|
||||
Browsable(false),
|
||||
EditorBrowsableAttribute(EditorBrowsableState.Advanced), // MDAC 69508
|
||||
RESNAMESPACE.ResCategoryAttribute(Res.DataCategory_Data),
|
||||
RESNAMESPACE.ResDescriptionAttribute(Res.DbParameter_Offset),
|
||||
]
|
||||
public int Offset {
|
||||
get {
|
||||
return _offset;
|
||||
}
|
||||
set {
|
||||
if (value < 0) {
|
||||
throw ADP.InvalidOffsetValue(value);
|
||||
}
|
||||
_offset = value;
|
||||
}
|
||||
}
|
||||
#else
|
||||
internal int Offset {
|
||||
get {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
[
|
||||
RESNAMESPACE.ResCategoryAttribute(Res.DataCategory_Data),
|
||||
RESNAMESPACE.ResDescriptionAttribute(Res.DbParameter_Size),
|
||||
]
|
||||
override public int Size { // V1.2.3300, XXXParameter V1.0.3300
|
||||
get {
|
||||
int size = _size;
|
||||
if (0 == size) {
|
||||
size = ValueSize(Value);
|
||||
}
|
||||
return size;
|
||||
}
|
||||
set {
|
||||
if (_size != value) {
|
||||
if (value < -1) {
|
||||
throw ADP.InvalidSizeValue(value);
|
||||
}
|
||||
PropertyChanging();
|
||||
_size = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ResetSize() {
|
||||
if (0 != _size) {
|
||||
PropertyChanging();
|
||||
_size = 0;
|
||||
}
|
||||
}
|
||||
|
||||
private bool ShouldSerializeSize() { // V1.2.3300
|
||||
return (0 != _size);
|
||||
}
|
||||
|
||||
[
|
||||
RESNAMESPACE.ResCategoryAttribute(Res.DataCategory_Update),
|
||||
RESNAMESPACE.ResDescriptionAttribute(Res.DbParameter_SourceColumn),
|
||||
]
|
||||
override public string SourceColumn { // V1.2.3300, XXXParameter V1.0.3300
|
||||
get {
|
||||
string sourceColumn = _sourceColumn;
|
||||
return ((null != sourceColumn) ? sourceColumn : ADP.StrEmpty);
|
||||
}
|
||||
set {
|
||||
_sourceColumn = value;
|
||||
}
|
||||
}
|
||||
|
||||
public override bool SourceColumnNullMapping {
|
||||
get {
|
||||
return _sourceColumnNullMapping;
|
||||
}
|
||||
set {
|
||||
_sourceColumnNullMapping = value;
|
||||
}
|
||||
}
|
||||
|
||||
[
|
||||
RESNAMESPACE.ResCategoryAttribute(Res.DataCategory_Update),
|
||||
RESNAMESPACE.ResDescriptionAttribute(Res.DbParameter_SourceVersion),
|
||||
]
|
||||
override public DataRowVersion SourceVersion { // V1.2.3300, XXXParameter V1.0.3300
|
||||
get {
|
||||
DataRowVersion sourceVersion = _sourceVersion;
|
||||
return ((0 != sourceVersion) ? sourceVersion : DataRowVersion.Current);
|
||||
}
|
||||
set {
|
||||
switch(value) { // @perfnote: Enum.IsDefined
|
||||
case DataRowVersion.Original:
|
||||
case DataRowVersion.Current:
|
||||
case DataRowVersion.Proposed:
|
||||
case DataRowVersion.Default:
|
||||
_sourceVersion = value;
|
||||
break;
|
||||
default:
|
||||
throw ADP.InvalidDataRowVersion(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void CloneHelperCore(PARAMETEROBJECTNAME destination) {
|
||||
destination._value = _value;
|
||||
// NOTE: _parent is not cloned
|
||||
destination._direction = _direction;
|
||||
destination._size = _size;
|
||||
#if USEOFFSET
|
||||
destination._offset = _offset;
|
||||
#endif
|
||||
destination._sourceColumn = _sourceColumn;
|
||||
destination._sourceVersion = _sourceVersion;
|
||||
destination._sourceColumnNullMapping = _sourceColumnNullMapping;
|
||||
destination._isNullable = _isNullable;
|
||||
}
|
||||
|
||||
internal void CopyTo(DbParameter destination) {
|
||||
ADP.CheckArgumentNull(destination, "destination");
|
||||
CloneHelper((PARAMETEROBJECTNAME)destination);
|
||||
}
|
||||
|
||||
internal object CompareExchangeParent(object value, object comparand) {
|
||||
// the interlock guarantees same parameter won't belong to multiple collections
|
||||
// at the same time, but to actually occur the user must really try
|
||||
// since we never declared thread safety, we don't care at this time
|
||||
//return System.Threading.Interlocked.CompareExchange(ref _parent, value, comparand);
|
||||
object parent = _parent;
|
||||
if (comparand == parent) {
|
||||
_parent = value;
|
||||
}
|
||||
return parent;
|
||||
}
|
||||
|
||||
internal void ResetParent() {
|
||||
_parent = null;
|
||||
}
|
||||
|
||||
override public string ToString() { // V1.2.3300, XXXParameter V1.0.3300
|
||||
return ParameterName;
|
||||
}
|
||||
|
||||
private byte ValuePrecisionCore(object value) { // V1.2.3300
|
||||
if (value is Decimal) {
|
||||
return ((System.Data.SqlTypes.SqlDecimal)(Decimal) value).Precision; // WebData 102913
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
private byte ValueScaleCore(object value) { // V1.2.3300
|
||||
if (value is Decimal) {
|
||||
return (byte)((Decimal.GetBits((Decimal)value)[3] & 0x00ff0000) >> 0x10);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
private int ValueSizeCore(object value) { // V1.2.3300
|
||||
if (!ADP.IsNull(value)) {
|
||||
string svalue = (value as string);
|
||||
if (null != svalue) {
|
||||
return svalue.Length;
|
||||
}
|
||||
byte[] bvalue = (value as byte[]);
|
||||
if (null != bvalue) {
|
||||
return bvalue.Length;
|
||||
}
|
||||
char[] cvalue = (value as char[]);
|
||||
if (null != cvalue) {
|
||||
return cvalue.Length;
|
||||
}
|
||||
if ((value is byte) || (value is char)) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user