Imported Upstream version 4.6.0.125

Former-commit-id: a2155e9bd80020e49e72e86c44da02a8ac0e57a4
This commit is contained in:
Xamarin Public Jenkins (auto-signing)
2016-08-03 10:59:49 +00:00
parent a569aebcfd
commit e79aa3c0ed
17047 changed files with 3137615 additions and 392334 deletions

View File

@ -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

View File

@ -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);
}
}
}

View File

@ -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;
}
}
}
}

View File

@ -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);
}
}
}

View File

@ -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;
}
}
}

View File

@ -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 () {
}
}
}

View File

@ -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);
}
}
}
}

View File

@ -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;
}
}
}
}

View File

@ -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
}
}
}

View File

@ -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; }
}
}
}

View File

@ -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 {
}
}

View File

@ -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";
}
}

View File

@ -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";
}
}

View File

@ -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);
}
}
};
}

View File

@ -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