You've already forked linux-packaging-mono
Imported Upstream version 5.16.0.100
Former-commit-id: 38faa55fb9669e35e7d8448b15c25dc447f25767
This commit is contained in:
parent
0a9828183b
commit
7d7f676260
@@ -2,7 +2,7 @@
|
||||
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="..\dir.props" />
|
||||
<PropertyGroup>
|
||||
<AssemblyVersion>4.3.1.0</AssemblyVersion>
|
||||
<AssemblyVersion>4.4.0.0</AssemblyVersion>
|
||||
<AssemblyKey>MSFT</AssemblyKey>
|
||||
<IsUAP>true</IsUAP>
|
||||
</PropertyGroup>
|
||||
|
||||
@@ -3,13 +3,9 @@
|
||||
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\ref\System.Data.SqlClient.csproj">
|
||||
<SupportedFramework>net461;netcoreapp2.0;$(UAPvNextTFM);$(AllXamarinFrameworks)</SupportedFramework>
|
||||
<SupportedFramework>net461;netcoreapp2.0;uap10.0.16299;$(UAPvNextTFM);$(AllXamarinFrameworks)</SupportedFramework>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\src\System.Data.SqlClient.csproj" />
|
||||
<InboxOnTargetFramework Include="$(UAPvNextTFM)" />
|
||||
<File Include="$(PlaceHolderFile)">
|
||||
<TargetPath>runtimes/win/lib/$(UAPvNextTFM)</TargetPath>
|
||||
</File>
|
||||
<HarvestIncludePaths Include="ref/net451;lib/net451;runtimes/win/lib/net451" />
|
||||
<HarvestIncludePaths Include="ref/net46;lib/net46;runtimes/win/lib/net46" />
|
||||
<HarvestIncludePaths Include="ref/netstandard1.2">
|
||||
@@ -19,6 +15,15 @@
|
||||
<SupportedFramework>net46;netcoreapp1.0</SupportedFramework>
|
||||
</HarvestIncludePaths>
|
||||
<HarvestIncludePaths Include="runtimes/unix/lib/netstandard1.3;runtimes/win/lib/netstandard1.3" />
|
||||
|
||||
<!-- Since UAP and .NETCoreApp are package based we still want to enable
|
||||
OOBing libraries that happen to overlap with their framework package.
|
||||
This avoids us having to lock the API in our NuGet packages just
|
||||
to match what shipped inbox: since we can provide a new library
|
||||
we can update it to add API without raising the netstandard version. -->
|
||||
<ValidatePackageSuppression Include="TreatAsOutOfBox">
|
||||
<Value>.NETCoreApp;UAP</Value>
|
||||
</ValidatePackageSuppression>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<InboxOnTargetFramework Include="$(AllXamarinFrameworks)" />
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
<BuildConfigurations>
|
||||
netstandard;
|
||||
netfx;
|
||||
netcoreapp;
|
||||
</BuildConfigurations>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
14
external/corefx/src/System.Data.SqlClient/ref/System.Data.SqlClient.NetCoreApp.cs
vendored
Normal file
14
external/corefx/src/System.Data.SqlClient/ref/System.Data.SqlClient.NetCoreApp.cs
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
// ------------------------------------------------------------------------------
|
||||
// Changes to this file must follow the http://aka.ms/api-review process.
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
namespace System.Data.SqlClient
|
||||
{
|
||||
public partial class SqlDataReader : System.Data.Common.IDbColumnSchemaGenerator
|
||||
{
|
||||
public System.Collections.ObjectModel.ReadOnlyCollection<System.Data.Common.DbColumn> GetColumnSchema() { throw null; }
|
||||
}
|
||||
}
|
||||
@@ -158,7 +158,12 @@ namespace Microsoft.SqlServer.Server
|
||||
public SqlMetaData(string name, System.Data.SqlDbType dbType, long maxLength, long locale, System.Data.SqlTypes.SqlCompareOptions compareOptions, bool useServerDefault, bool isUniqueKey, System.Data.SqlClient.SortOrder columnSortOrder, int sortOrdinal) { }
|
||||
public SqlMetaData(string name, System.Data.SqlDbType dbType, string database, string owningSchema, string objectName) { }
|
||||
public SqlMetaData(string name, System.Data.SqlDbType dbType, string database, string owningSchema, string objectName, bool useServerDefault, bool isUniqueKey, System.Data.SqlClient.SortOrder columnSortOrder, int sortOrdinal) { }
|
||||
public SqlMetaData(string name, System.Data.SqlDbType dbType, System.Type userDefinedType) { }
|
||||
public SqlMetaData(string name, System.Data.SqlDbType dbType, System.Type userDefinedType, string serverTypeName) { }
|
||||
public SqlMetaData(string name, System.Data.SqlDbType dbType, System.Type userDefinedType, string serverTypeName, bool useServerDefault, bool isUniqueKey, System.Data.SqlClient.SortOrder columnSortOrder, int sortOrdinal) { }
|
||||
|
||||
public System.Data.SqlTypes.SqlCompareOptions CompareOptions { get { throw null; } }
|
||||
public System.Data.DbType DbType { get { throw null; } }
|
||||
public bool IsUniqueKey { get { throw null; } }
|
||||
public long LocaleId { get { throw null; } }
|
||||
public static long Max { get { throw null; } }
|
||||
@@ -169,6 +174,7 @@ namespace Microsoft.SqlServer.Server
|
||||
public System.Data.SqlClient.SortOrder SortOrder { get { throw null; } }
|
||||
public int SortOrdinal { get { throw null; } }
|
||||
public System.Data.SqlDbType SqlDbType { get { throw null; } }
|
||||
public System.Type Type{ get { throw null; } }
|
||||
public string TypeName { get { throw null; } }
|
||||
public bool UseServerDefault { get { throw null; } }
|
||||
public string XmlSchemaCollectionDatabase { get { throw null; } }
|
||||
@@ -416,6 +422,9 @@ namespace System.Data.SqlClient
|
||||
public System.Xml.XmlReader ExecuteXmlReader() { throw null; }
|
||||
public System.Threading.Tasks.Task<System.Xml.XmlReader> ExecuteXmlReaderAsync() { throw null; }
|
||||
public System.Threading.Tasks.Task<System.Xml.XmlReader> ExecuteXmlReaderAsync(System.Threading.CancellationToken cancellationToken) { throw null; }
|
||||
public System.IAsyncResult BeginExecuteXmlReader() { throw null; }
|
||||
public System.IAsyncResult BeginExecuteXmlReader(System.AsyncCallback callback, object stateObject) { throw null; }
|
||||
public System.Xml.XmlReader EndExecuteXmlReader(System.IAsyncResult asyncResult) { throw null; }
|
||||
public override void Prepare() { }
|
||||
public System.Data.Sql.SqlNotificationRequest Notification { get { throw null; } set { } }
|
||||
public void ResetCommandTimeout() { }
|
||||
@@ -451,6 +460,7 @@ namespace System.Data.SqlClient
|
||||
{
|
||||
public SqlConnection() { }
|
||||
public SqlConnection(string connectionString) { }
|
||||
public SqlConnection(string connectionString, System.Data.SqlClient.SqlCredential credential) { }
|
||||
public System.Guid ClientConnectionId { get { throw null; } }
|
||||
object ICloneable.Clone() { throw null; }
|
||||
public override string ConnectionString { get { throw null; } set { } }
|
||||
@@ -463,6 +473,7 @@ namespace System.Data.SqlClient
|
||||
public override System.Data.ConnectionState State { get { throw null; } }
|
||||
public bool StatisticsEnabled { get { throw null; } set { } }
|
||||
public string WorkstationId { get { throw null; } }
|
||||
public System.Data.SqlClient.SqlCredential Credential { get { throw null; } set { } }
|
||||
public event System.Data.SqlClient.SqlInfoMessageEventHandler InfoMessage { add { } remove { } }
|
||||
protected override System.Data.Common.DbTransaction BeginDbTransaction(System.Data.IsolationLevel isolationLevel) { throw null; }
|
||||
public new System.Data.SqlClient.SqlTransaction BeginTransaction() { throw null; }
|
||||
@@ -475,10 +486,16 @@ namespace System.Data.SqlClient
|
||||
public override void Close() { }
|
||||
public new System.Data.SqlClient.SqlCommand CreateCommand() { throw null; }
|
||||
protected override System.Data.Common.DbCommand CreateDbCommand() { throw null; }
|
||||
public override System.Data.DataTable GetSchema() { throw null; }
|
||||
public override System.Data.DataTable GetSchema(string collectionName) { throw null; }
|
||||
public override System.Data.DataTable GetSchema(string collectionName, string[] restrictionValues) { throw null; }
|
||||
public override void Open() { }
|
||||
public override System.Threading.Tasks.Task OpenAsync(System.Threading.CancellationToken cancellationToken) { throw null; }
|
||||
public void ResetStatistics() { }
|
||||
public System.Collections.IDictionary RetrieveStatistics() { throw null; }
|
||||
public static void ChangePassword(string connectionString, string newPassword) { throw null; }
|
||||
public static void ChangePassword(string connectionString, System.Data.SqlClient.SqlCredential credential, System.Security.SecureString newPassword) { throw null; }
|
||||
|
||||
}
|
||||
public sealed partial class SqlConnectionStringBuilder : System.Data.Common.DbConnectionStringBuilder
|
||||
{
|
||||
@@ -678,6 +695,7 @@ namespace System.Data.SqlClient
|
||||
public virtual object GetSqlValue(int i) { throw null; }
|
||||
public virtual int GetSqlValues(object[] values) { throw null; }
|
||||
public virtual System.Data.SqlTypes.SqlXml GetSqlXml(int i) { throw null; }
|
||||
public override System.Data.DataTable GetSchemaTable() { throw null; }
|
||||
public override System.IO.Stream GetStream(int i) { throw null; }
|
||||
public override string GetString(int i) { throw null; }
|
||||
public override System.IO.TextReader GetTextReader(int i) { throw null; }
|
||||
@@ -686,6 +704,7 @@ namespace System.Data.SqlClient
|
||||
public override int GetValues(object[] values) { throw null; }
|
||||
public virtual System.Xml.XmlReader GetXmlReader(int i) { throw null; }
|
||||
public override bool IsDBNull(int i) { throw null; }
|
||||
protected internal bool IsCommandBehavior(System.Data.CommandBehavior condition) { throw null; }
|
||||
public override System.Threading.Tasks.Task<bool> IsDBNullAsync(int i, System.Threading.CancellationToken cancellationToken) { throw null; }
|
||||
public override bool NextResult() { throw null; }
|
||||
public override System.Threading.Tasks.Task<bool> NextResultAsync(System.Threading.CancellationToken cancellationToken) { throw null; }
|
||||
@@ -779,6 +798,8 @@ namespace System.Data.SqlClient
|
||||
{
|
||||
internal SqlParameterCollection() { }
|
||||
public override int Count { get { throw null; } }
|
||||
public override bool IsFixedSize { get { throw null; } }
|
||||
public override bool IsReadOnly { get { throw null; } }
|
||||
public new System.Data.SqlClient.SqlParameter this[int index] { get { throw null; } set { } }
|
||||
public new System.Data.SqlClient.SqlParameter this[string parameterName] { get { throw null; } set { } }
|
||||
public override object SyncRoot { get { throw null; } }
|
||||
@@ -830,6 +851,13 @@ namespace System.Data.SqlClient
|
||||
public void Rollback(string transactionName) { }
|
||||
public void Save(string savePointName) { }
|
||||
}
|
||||
|
||||
public sealed class SqlCredential
|
||||
{
|
||||
public SqlCredential(string userId, System.Security.SecureString password) { }
|
||||
public string UserId { get { throw null; } }
|
||||
public System.Security.SecureString Password { get { throw null; } }
|
||||
}
|
||||
}
|
||||
namespace System.Data
|
||||
{
|
||||
|
||||
@@ -4,24 +4,35 @@
|
||||
<PropertyGroup>
|
||||
<ProjectGuid>{D58E8D2B-3331-4660-8DFB-512D66F8EC63}</ProjectGuid>
|
||||
<IsPartialFacadeAssembly Condition="'$(TargetGroup)' == 'netfx'">true</IsPartialFacadeAssembly>
|
||||
<!-- Must match version supported by frameworks which support 4.3.* inbox.
|
||||
Can be removed when API is added and this assembly is versioned to 4.4.* -->
|
||||
<AssemblyVersion Condition="'$(TargetsNetFx)' != 'true'">4.3.1.0</AssemblyVersion>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netfx-Debug|AnyCPU'" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netfx-Release|AnyCPU'" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netstandard-Debug|AnyCPU'" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netstandard-Release|AnyCPU'" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Debug|AnyCPU'" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Release|AnyCPU'" />
|
||||
<ItemGroup>
|
||||
<SuppressPackageTargetFrameworkCompatibility Include="$(UAPvNextTFM)" />
|
||||
<SuppressPackageTargetFrameworkCompatibility Include="$(UAPvNextTFM);uap10.0.16299" />
|
||||
<Compile Include="System.Data.SqlClient.cs" />
|
||||
<Compile Include="System.Data.SqlClient.Manual.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup Condition="'$(TargetGroup)' == 'netcoreapp'">
|
||||
<Compile Include="System.Data.SqlClient.NetCoreApp.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup Condition="'$(TargetGroup)' == 'netfx'">
|
||||
<Reference Include="mscorlib" />
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup Condition="'$(TargetGroup)' == 'netcoreapp'">
|
||||
<ProjectReference Include="..\..\System.Runtime\ref\System.Runtime.csproj" />
|
||||
<ProjectReference Include="..\..\System.Runtime.Extensions\ref\System.Runtime.Extensions.csproj" />
|
||||
<ProjectReference Include="..\..\System.Data.Common\ref\System.Data.Common.csproj" />
|
||||
<ProjectReference Include="..\..\System.Collections.NonGeneric\ref\System.Collections.NonGeneric.csproj" />
|
||||
<ProjectReference Include="..\..\System.ComponentModel.Primitives\ref\System.ComponentModel.Primitives.csproj" />
|
||||
<ProjectReference Include="..\..\System.Xml.ReaderWriter\ref\System.Xml.ReaderWriter.csproj" />
|
||||
<ProjectReference Include="..\..\System.Runtime.InteropServices\ref\System.Runtime.InteropServices.csproj" />
|
||||
</ItemGroup>
|
||||
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
|
||||
</Project>
|
||||
@@ -8,10 +8,14 @@
|
||||
netstandard1.3;
|
||||
netstandard;
|
||||
netfx-Windows_NT;
|
||||
netcoreapp;
|
||||
netcoreapp-Unix;
|
||||
netcoreapp-Windows_NT;
|
||||
uap10.0.16299-Windows_NT;
|
||||
uap-Windows_NT;
|
||||
</PackageConfigurations>
|
||||
<BuildConfigurations>
|
||||
$(PackageConfigurations)
|
||||
uap-Windows_NT;
|
||||
</BuildConfigurations>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
10
external/corefx/src/System.Data.SqlClient/src/MatchingRefApiCompatBaseline.txt
vendored
Normal file
10
external/corefx/src/System.Data.SqlClient/src/MatchingRefApiCompatBaseline.txt
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
#
|
||||
# netstandard dll has been shipped with IDbColumnSchemaGenerator inherited and SqlDataReader.GetColumnScheme() implemented in source, but not exposed in ref contract.
|
||||
# Removing SqlDataReader.GetColumnScheme() from netstandard implementation potentially breaks existing customer source code
|
||||
# that utilizes SqlDataReader.GetColumnScheme() indirectly by casting SqlDataReader to IDbColumnSchemaGenerator type.
|
||||
# In order to prevent it, the API needs to be kept in public, and following 2 error message should be remaining in this baseline file.
|
||||
#
|
||||
Compat issues with assembly System.Data.SqlClient:
|
||||
CannotRemoveBaseTypeOrInterface : Type 'System.Data.SqlClient.SqlDataReader' does not implement interface 'System.Data.Common.IDbColumnSchemaGenerator' in the implementation but it does in the contract.
|
||||
MembersMustExist : Member 'System.Data.SqlClient.SqlDataReader.GetColumnSchema()' does not exist in the implementation but it does exist in the contract.
|
||||
Total Issues: 2
|
||||
@@ -729,7 +729,7 @@ namespace Microsoft.SqlServer.Server
|
||||
}
|
||||
}
|
||||
|
||||
IDataReader System.Data.IDataRecord.GetData (int ordinal)
|
||||
IDataReader System.Data.IDataRecord.GetData(int ordinal)
|
||||
{
|
||||
throw ADP.NotSupported();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
<!-- Not a bug. sni.dll is a native component that ships as part of the package. -->
|
||||
kernel32.dll!LoadLibraryExW
|
||||
sni.dll!GetSniMaxComposedSpnLength
|
||||
sni.dll!SNIAddProviderWrapper
|
||||
sni.dll!SNICheckConnectionWrapper
|
||||
sni.dll!SNICloseWrapper
|
||||
sni.dll!SNIGetInfoWrapper
|
||||
sni.dll!SNIGetLastError
|
||||
sni.dll!SNIInitialize
|
||||
sni.dll!SNIOpenSyncExWrapper
|
||||
sni.dll!SNIOpenWrapper
|
||||
sni.dll!SNIPacketAllocateWrapper
|
||||
sni.dll!SNIPacketGetDataWrapper
|
||||
sni.dll!SNIPacketRelease
|
||||
sni.dll!SNIPacketResetWrapper
|
||||
sni.dll!SNIPacketSetData
|
||||
sni.dll!SNIQueryInfo
|
||||
sni.dll!SNIReadAsyncWrapper
|
||||
sni.dll!SNIReadSyncOverAsync
|
||||
sni.dll!SNIRemoveProviderWrapper
|
||||
sni.dll!SNISecGenClientContextWrapper
|
||||
sni.dll!SNISecInitPackage
|
||||
sni.dll!SNISetInfoWrapper
|
||||
sni.dll!SNITerminate
|
||||
sni.dll!SNIWaitForSSLHandshakeToCompleteWrapper
|
||||
sni.dll!SNIWriteAsyncWrapper
|
||||
sni.dll!SNIWriteSyncOverAsync
|
||||
sni.dll!UnmanagedIsTokenRestricted
|
||||
sspicli.dll!AcceptSecurityContext
|
||||
sspicli.dll!AcquireCredentialsHandleW
|
||||
sspicli.dll!ApplyControlToken
|
||||
sspicli.dll!CompleteAuthToken
|
||||
sspicli.dll!DecryptMessage
|
||||
sspicli.dll!DeleteSecurityContext
|
||||
sspicli.dll!EncryptMessage
|
||||
sspicli.dll!EnumerateSecurityPackagesW
|
||||
sspicli.dll!FreeContextBuffer
|
||||
sspicli.dll!FreeCredentialsHandle
|
||||
sspicli.dll!InitializeSecurityContextW
|
||||
sspicli.dll!QueryContextAttributesW
|
||||
sspicli.dll!QuerySecurityContextToken
|
||||
sspicli.dll!SetContextAttributesW
|
||||
sspicli.dll!SspiEncodeStringsAsAuthIdentity
|
||||
sspicli.dll!SspiFreeAuthIdentity
|
||||
@@ -1,5 +1,64 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
@@ -431,7 +490,7 @@
|
||||
<value>Failed to generate SSPI context.</value>
|
||||
</data>
|
||||
<data name="SQL_KerberosTicketMissingError" xml:space="preserve">
|
||||
<value>Cannot access Kerberos ticket. Ensure Kerberos has been initialized with 'kinit'.</value>
|
||||
<value>Cannot authenticate using Kerberos. Ensure Kerberos has been initialized on the client with 'kinit' and a Service Principal Name has been registered for the SQL Server to allow Kerberos authentication.</value>
|
||||
</data>
|
||||
<data name="SQL_SqlServerBrowserNotAccessible" xml:space="preserve">
|
||||
<value>Cannot connect to SQL Server Browser. Ensure SQL Server Browser has been started.</value>
|
||||
@@ -1091,7 +1150,7 @@
|
||||
<value>TCP Provider</value>
|
||||
</data>
|
||||
<data name="SNI_PN8" xml:space="preserve">
|
||||
<value></value>
|
||||
<value />
|
||||
</data>
|
||||
<data name="SNI_PN9" xml:space="preserve">
|
||||
<value>SQL Network Interfaces</value>
|
||||
@@ -1165,32 +1224,32 @@
|
||||
<data name="SqlProvider_InvalidDataColumnMaxLength" xml:space="preserve">
|
||||
<value>The size of column '{0}' is not supported. The size is {1}.</value>
|
||||
</data>
|
||||
<data name="MDF_InvalidXmlInvalidValue" xml:space="preserve">
|
||||
<data name="MDF_InvalidXmlInvalidValue" xml:space="preserve">
|
||||
<value>The metadata XML is invalid. The {1} column of the {0} collection must contain a non-empty string.</value>
|
||||
</data>
|
||||
<data name="MDF_CollectionNameISNotUnique" xml:space="preserve">
|
||||
<data name="MDF_CollectionNameISNotUnique" xml:space="preserve">
|
||||
<value>There are multiple collections named '{0}'.</value>
|
||||
</data>
|
||||
<data name="MDF_InvalidXmlMissingColumn" xml:space="preserve">
|
||||
<data name="MDF_InvalidXmlMissingColumn" xml:space="preserve">
|
||||
<value>The metadata XML is invalid. The {0} collection must contain a {1} column and it must be a string column.</value>
|
||||
</data>
|
||||
<data name="MDF_InvalidXml" xml:space="preserve">
|
||||
<data name="MDF_InvalidXml" xml:space="preserve">
|
||||
<value>The metadata XML is invalid.</value>
|
||||
</data>
|
||||
<data name="MDF_NoColumns" xml:space="preserve">
|
||||
<data name="MDF_NoColumns" xml:space="preserve">
|
||||
<value>The schema table contains no columns.</value>
|
||||
</data>
|
||||
<data name="MDF_QueryFailed" xml:space="preserve">
|
||||
<data name="MDF_QueryFailed" xml:space="preserve">
|
||||
<value>Unable to build the '{0}' collection because execution of the SQL query failed. See the inner exception for details.</value>
|
||||
</data>
|
||||
<data name="MDF_TooManyRestrictions" xml:space="preserve">
|
||||
<data name="MDF_TooManyRestrictions" xml:space="preserve">
|
||||
<value>More restrictions were provided than the requested schema ('{0}') supports.</value>
|
||||
</data>
|
||||
<data name="MDF_DataTableDoesNotExist" xml:space="preserve">
|
||||
<data name="MDF_DataTableDoesNotExist" xml:space="preserve">
|
||||
<value>The collection '{0}' is missing from the metadata XML.</value>
|
||||
</data>
|
||||
<data name="MDF_UndefinedCollection" xml:space="preserve">
|
||||
<value>The requested collection ({0}) is not defined.</value>
|
||||
<data name="MDF_UndefinedCollection" xml:space="preserve">
|
||||
<value>The requested collection ({0}) is not defined.</value>
|
||||
</data>
|
||||
<data name="MDF_UnsupportedVersion" xml:space="preserve">
|
||||
<value> requested collection ({0}) is not supported by this version of the provider.</value>
|
||||
@@ -1213,4 +1272,28 @@
|
||||
<data name="MDF_UnableToBuildCollection" xml:space="preserve">
|
||||
<value>Unable to build schema collection '{0}';</value>
|
||||
</data>
|
||||
<data name="ADP_InvalidArgumentLength" xml:space="preserve">
|
||||
<value>The length of argument '{0}' exceeds its limit of '{1}'.</value>
|
||||
</data>
|
||||
<data name="ADP_MustBeReadOnly" xml:space="preserve">
|
||||
<value>{0} must be marked as read only.</value>
|
||||
</data>
|
||||
<data name="ADP_InvalidMixedUsageOfSecureAndClearCredential" xml:space="preserve">
|
||||
<value>Cannot use Credential with UserID, UID, Password, or PWD connection string keywords.</value>
|
||||
</data>
|
||||
<data name="ADP_InvalidMixedUsageOfSecureCredentialAndIntegratedSecurity" xml:space="preserve">
|
||||
<value>Cannot use Credential with Integrated Security connection string keyword.</value>
|
||||
</data>
|
||||
<data name="SQL_ChangePasswordArgumentMissing" xml:space="preserve">
|
||||
<value>The '{0}' argument must not be null or empty.</value>
|
||||
</data>
|
||||
<data name="SQL_ChangePasswordConflictsWithSSPI" xml:space="preserve">
|
||||
<value>ChangePassword can only be used with SQL authentication, not with integrated security.</value>
|
||||
</data>
|
||||
<data name="SQL_ChangePasswordRequiresYukon" xml:space="preserve">
|
||||
<value>ChangePassword requires SQL Server 9.0 or later.</value>
|
||||
</data>
|
||||
<data name="SQL_ChangePasswordUseOfUnallowedKey" xml:space="preserve">
|
||||
<value>The keyword '{0}' must not be specified in the connectionString argument to ChangePassword.</value>
|
||||
</data>
|
||||
</root>
|
||||
@@ -6,6 +6,7 @@
|
||||
<AssemblyName>System.Data.SqlClient</AssemblyName>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<IsPartialFacadeAssembly Condition="'$(TargetGroup)' == 'netfx'">true</IsPartialFacadeAssembly>
|
||||
<IsUAPAssembly Condition="'$(TargetGroup)' == 'uap' OR '$(TargetGroup)' == 'uap10.0.16299'">true</IsUAPAssembly>
|
||||
<GeneratePlatformNotSupportedAssemblyMessage Condition="'$(OSGroup)' == 'AnyOS'">SR.PlatformNotSupported_DataSqlClient</GeneratePlatformNotSupportedAssemblyMessage>
|
||||
<AssemblyVersion Condition="'$(TargetGroup)' == 'netstandard1.2'">4.0.0.0</AssemblyVersion>
|
||||
<AssemblyVersion Condition="'$(TargetGroup)' == 'netstandard1.3'">4.1.0.0</AssemblyVersion>
|
||||
@@ -14,6 +15,8 @@
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netfx-Windows_NT-Release|AnyCPU'" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'uap-Windows_NT-Debug|AnyCPU'" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'uap-Windows_NT-Release|AnyCPU'" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'uap10.0.16299-Windows_NT-Debug|AnyCPU'" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'uap10.0.16299-Windows_NT-Release|AnyCPU'" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netstandard-Debug|AnyCPU'" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netstandard-Release|AnyCPU'" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netstandard-Unix-Debug|AnyCPU'" />
|
||||
@@ -24,7 +27,13 @@
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netstandard1.2-Release|AnyCPU'" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netstandard1.3-Debug|AnyCPU'" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netstandard1.3-Release|AnyCPU'" />
|
||||
<ItemGroup Condition="'$(TargetGroup)' == 'netstandard' OR '$(TargetGroup)' == 'uap' ">
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Debug|AnyCPU'" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Release|AnyCPU'" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Unix-Debug|AnyCPU'" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Unix-Release|AnyCPU'" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Windows_NT-Debug|AnyCPU'" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Windows_NT-Release|AnyCPU'" />
|
||||
<ItemGroup Condition="'$(TargetGroup)' == 'netstandard' OR '$(TargetGroup)' == 'netcoreapp' OR '$(IsUAPAssembly)' == 'true' ">
|
||||
<Compile Include="System.Data.SqlClient.TypeForwards.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup Condition="'$(IsPartialFacadeAssembly)' != 'true' AND '$(OSGroup)' != 'AnyOS'">
|
||||
@@ -55,6 +64,9 @@
|
||||
<Compile Include="$(CommonPath)\System\Data\Common\AdapterUtil.cs">
|
||||
<Link>System\Data\Common\AdapterUtil.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="$(CommonPath)\System\Data\Common\AdapterUtil.Drivers.cs">
|
||||
<Link>System\Data\Common\AdapterUtil.Drivers.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="System\Data\Common\AdapterUtil.SqlClient.cs" />
|
||||
<Compile Include="System\Data\Common\SR.cs" />
|
||||
<Compile Include="System\Data\Common\DbConnectionOptions.cs" />
|
||||
@@ -77,18 +89,35 @@
|
||||
<Compile Include="$(CommonPath)\System\Data\Common\NameValuePair.cs">
|
||||
<Link>System\Data\Common\NameValuePair.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="$(CommonPath)\System\Data\ProviderBase\DbConnectionInternal.cs">
|
||||
<Link>Common\System\Data\ProviderBase\DbConnectionInternal.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="$(CommonPath)\System\Data\ProviderBase\DbConnectionFactory.cs">
|
||||
<Link>Common\System\Data\ProviderBase\DbConnectionFactory.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="$(CommonPath)\System\Data\ProviderBase\DbConnectionPoolGroup.cs">
|
||||
<Link>Common\System\Data\ProviderBase\DbConnectionPoolGroup.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="$(CommonPath)\System\Data\ProviderBase\TimeoutTimer.cs">
|
||||
<Link>Common\System\Data\ProviderBase\TimeoutTimer.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="$(CommonPath)\System\Data\ProviderBase\DbReferenceCollection.cs">
|
||||
<Link>Common\System\Data\ProviderBase\DbReferenceCollection.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="$(CommonPath)\System\Data\ProviderBase\DbMetaDataFactory.cs">
|
||||
<Link>Common\System\Data\ProviderBase\DbMetaDataFactory.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="$(CommonPath)\System\Data\ProviderBase\DbConnectionClosed.cs">
|
||||
<Link>Common\System\Data\ProviderBase\DbConnectionClosed.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="System\Data\ProviderBase\DbConnectionClosed.cs" />
|
||||
<Compile Include="System\Data\ProviderBase\DbConnectionFactory.cs" />
|
||||
<Compile Include="System\Data\ProviderBase\DbConnectionInternal.cs" />
|
||||
<Compile Include="System\Data\ProviderBase\DbConnectionPool.cs" />
|
||||
<Compile Include="System\Data\ProviderBase\DbConnectionPoolGroup.cs" />
|
||||
<Compile Include="System\Data\ProviderBase\DbConnectionPoolGroupProviderInfo.cs" />
|
||||
<Compile Include="System\Data\ProviderBase\DbConnectionPoolIdentity.cs" />
|
||||
<Compile Include="System\Data\ProviderBase\DbConnectionPoolOptions.cs" />
|
||||
<Compile Include="System\Data\ProviderBase\DbConnectionPoolProviderInfo.cs" />
|
||||
<Compile Include="System\Data\ProviderBase\DbMetaDataFactory.cs" />
|
||||
<Compile Include="System\Data\ProviderBase\DbReferenceCollection.cs" />
|
||||
<Compile Include="System\Data\ProviderBase\TimeoutTimer.cs" />
|
||||
<Compile Include="System\Data\Sql\IBinarySerialize.cs" />
|
||||
<Compile Include="System\Data\Sql\InvalidUdtException.cs" />
|
||||
<Compile Include="System\Data\Sql\SqlFunctionAttribute.cs" />
|
||||
@@ -198,12 +227,13 @@
|
||||
<Compile Include="System\Data\SqlClient\SNI\SSRP.cs" />
|
||||
<Compile Include="System\Data\SqlClient\TdsParserStateObjectManaged.cs" />
|
||||
<Compile Include="Interop\SNINativeMethodWrapper.Common.cs" />
|
||||
<Compile Include="System\Data\SqlClient\SqlCredential.cs" />
|
||||
</ItemGroup>
|
||||
<!-- Manage the SNI toggle for Windows netstandard and UWP -->
|
||||
<ItemGroup Condition="'$(TargetGroup)' == 'netstandard' AND '$(TargetsWindows)' == 'true'">
|
||||
<ItemGroup Condition="('$(TargetGroup)' == 'netstandard' OR '$(TargetGroup)' == 'netcoreapp') AND '$(TargetsWindows)' == 'true'">
|
||||
<Compile Include="System\Data\SqlClient\TdsParserStateObjectFactory.Windows.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup Condition="'$(TargetGroup)' == 'uap'">
|
||||
<ItemGroup Condition="'$(IsUAPAssembly)' == 'true'">
|
||||
<Compile Include="System\Data\SqlClient\TdsParserStateObjectFactory.Managed.cs" />
|
||||
<Compile Include="System\Data\SqlClient\LocalDBAPI.uap.cs" />
|
||||
<Compile Include="System\Data\SqlClient\SNI\LocalDB.uap.cs" />
|
||||
@@ -211,7 +241,7 @@
|
||||
<Compile Include="System\Data\SqlClient\TdsParser.Unix.cs" />
|
||||
</ItemGroup>
|
||||
<!-- Assets needed on Windows but should be avoided on UAP to avoid sni.dll -->
|
||||
<ItemGroup Condition=" '$(TargetsWindows)' == 'true' And '$(IsPartialFacadeAssembly)' != 'true' and '$(TargetGroup)' != 'uap' ">
|
||||
<ItemGroup Condition=" '$(TargetsWindows)' == 'true' And '$(IsPartialFacadeAssembly)' != 'true' and '$(IsUAPAssembly)' != 'true'">
|
||||
<Compile Include="System\Data\SqlClient\TdsParserStateObjectNative.cs" />
|
||||
<Compile Include="Interop\SNINativeMethodWrapper.Windows.cs" />
|
||||
<Compile Include="System\Data\SqlClient\TdsParserSafeHandles.cs" />
|
||||
@@ -286,9 +316,6 @@
|
||||
<Compile Include="$(CommonPath)\Interop\Windows\sspicli\SecurityPackageInfo.cs">
|
||||
<Link>Common\Interop\Windows\sspicli\SecurityPackageInfo.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="$(CommonPath)\System\Net\IntPtrHelper.cs">
|
||||
<Link>Common\System\Net\IntPtrHelper.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="$(CommonPath)\Interop\Windows\sspicli\SSPIAuthType.cs">
|
||||
<Link>Common\Interop\Windows\sspicli\SSPIAuthType.cs</Link>
|
||||
</Compile>
|
||||
@@ -406,7 +433,7 @@
|
||||
<Compile Include="System\Data\SqlClient\LocalDBAPI.Unix.cs" />
|
||||
<Compile Include="System\Data\SqlClient\SNI\LocalDB.Unix.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup Condition="'$(TargetsWindows)' == 'true' And '$(IsPartialFacadeAssembly)' != 'true' and '$(TargetGroup)' != 'uap'">
|
||||
<ItemGroup Condition="'$(TargetsWindows)' == 'true' And '$(IsPartialFacadeAssembly)' != 'true' and '$(IsUAPAssembly)' != 'true'">
|
||||
<Reference Include="Microsoft.Win32.Registry" />
|
||||
</ItemGroup>
|
||||
<ItemGroup Condition="'$(IsPartialFacadeAssembly)' != 'true'">
|
||||
@@ -420,6 +447,7 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup Condition="'$(IsPartialFacadeAssembly)' != 'true' AND '$(OSGroup)' != 'AnyOS'">
|
||||
<Reference Include="Microsoft.Win32.Primitives" />
|
||||
<Reference Include="System.Buffers" />
|
||||
<Reference Include="System.Collections" />
|
||||
<Reference Include="System.Collections.Concurrent" />
|
||||
<Reference Include="System.ComponentModel" />
|
||||
@@ -450,7 +478,7 @@
|
||||
<Reference Include="System.Net.NameResolution" />
|
||||
<Reference Include="System.Diagnostics.Tracing" />
|
||||
</ItemGroup>
|
||||
<ItemGroup Condition="'$(OSGroup)' != 'AnyOS' AND '$(TargetGroup)' == 'uap'">
|
||||
<ItemGroup Condition="('$(OSGroup)' != 'AnyOS' AND '$(IsUAPAssembly)' == 'true') OR '$(TargetGroup)' == 'netcoreapp'">
|
||||
<Reference Include="System.Transactions.Local" />
|
||||
<Reference Include="System.Collections.NonGeneric" />
|
||||
</ItemGroup>
|
||||
@@ -463,6 +491,13 @@
|
||||
<LogicalName>System.Data.SqlClient.SqlMetaData.xml</LogicalName>
|
||||
</EmbeddedResource>
|
||||
</ItemGroup>
|
||||
<ItemGroup Condition="'$(TargetGroup)' == 'netcoreapp'">
|
||||
<Reference Include="System.Runtime.Extensions" />
|
||||
<Reference Include="System.Data.Common" />
|
||||
<Reference Include="System.ComponentModel.Primitives" />
|
||||
<Reference Include="System.Xml.ReaderWriter" />
|
||||
<Reference Include="System.Runtime.InteropServices" />
|
||||
</ItemGroup>
|
||||
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
|
||||
<Import Project=".\GenerateThisAssemblyCs.targets" Condition="'$(IsPartialFacadeAssembly)' != 'true'" />
|
||||
</Project>
|
||||
</Project>
|
||||
|
||||
@@ -880,5 +880,35 @@ namespace System.Data.Common
|
||||
TraceExceptionAsReturnValue(e);
|
||||
return e;
|
||||
}
|
||||
|
||||
internal static ArgumentException InvalidArgumentLength(string argumentName, int limit)
|
||||
{
|
||||
return Argument(SR.GetString(SR.ADP_InvalidArgumentLength, argumentName, limit));
|
||||
}
|
||||
|
||||
internal static ArgumentException MustBeReadOnly(string argumentName)
|
||||
{
|
||||
return Argument(SR.GetString(SR.ADP_MustBeReadOnly, argumentName));
|
||||
}
|
||||
|
||||
internal static InvalidOperationException InvalidMixedUsageOfSecureAndClearCredential()
|
||||
{
|
||||
return InvalidOperation(SR.GetString(SR.ADP_InvalidMixedUsageOfSecureAndClearCredential));
|
||||
}
|
||||
|
||||
internal static ArgumentException InvalidMixedArgumentOfSecureAndClearCredential()
|
||||
{
|
||||
return Argument(SR.GetString(SR.ADP_InvalidMixedUsageOfSecureAndClearCredential));
|
||||
}
|
||||
|
||||
internal static InvalidOperationException InvalidMixedUsageOfSecureCredentialAndIntegratedSecurity()
|
||||
{
|
||||
return InvalidOperation(SR.GetString(SR.ADP_InvalidMixedUsageOfSecureCredentialAndIntegratedSecurity));
|
||||
}
|
||||
|
||||
internal static ArgumentException InvalidMixedArgumentOfSecureCredentialAndIntegratedSecurity()
|
||||
{
|
||||
return Argument(SR.GetString(SR.ADP_InvalidMixedUsageOfSecureCredentialAndIntegratedSecurity));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,176 +2,15 @@
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
using System.Data.Common;
|
||||
using System.Diagnostics;
|
||||
using System.Threading.Tasks;
|
||||
using System.Transactions;
|
||||
|
||||
|
||||
namespace System.Data.ProviderBase
|
||||
{
|
||||
abstract internal class DbConnectionClosed : DbConnectionInternal
|
||||
internal abstract partial class DbConnectionClosed : DbConnectionInternal
|
||||
{
|
||||
// Construct an "empty" connection
|
||||
protected DbConnectionClosed(ConnectionState state, bool hidePassword, bool allowSetConnectionString) : base(state, hidePassword, allowSetConnectionString)
|
||||
{
|
||||
}
|
||||
protected override void Activate(Transaction transaction) => throw ADP.ClosedConnectionError();
|
||||
|
||||
public override string ServerVersion
|
||||
{
|
||||
get
|
||||
{
|
||||
throw ADP.ClosedConnectionError();
|
||||
}
|
||||
}
|
||||
|
||||
protected override void Activate(Transaction transaction)
|
||||
{
|
||||
throw ADP.ClosedConnectionError();
|
||||
}
|
||||
|
||||
public override DbTransaction BeginTransaction(IsolationLevel il)
|
||||
{
|
||||
throw ADP.ClosedConnectionError();
|
||||
}
|
||||
|
||||
public override void ChangeDatabase(string database)
|
||||
{
|
||||
throw ADP.ClosedConnectionError();
|
||||
}
|
||||
|
||||
internal override void CloseConnection(DbConnection owningObject, DbConnectionFactory connectionFactory)
|
||||
{
|
||||
// not much to do here...
|
||||
}
|
||||
|
||||
protected override void Deactivate()
|
||||
{
|
||||
throw ADP.ClosedConnectionError();
|
||||
}
|
||||
|
||||
public override void EnlistTransaction(Transaction transaction)
|
||||
{
|
||||
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);
|
||||
}
|
||||
public override void EnlistTransaction(Transaction transaction) => throw ADP.ClosedConnectionError();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,11 +2,6 @@
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Data.Common;
|
||||
using System.Threading;
|
||||
@@ -14,141 +9,8 @@ using System.Threading.Tasks;
|
||||
|
||||
namespace System.Data.ProviderBase
|
||||
{
|
||||
internal abstract class DbConnectionFactory
|
||||
internal abstract partial class DbConnectionFactory
|
||||
{
|
||||
private Dictionary<DbConnectionPoolKey, DbConnectionPoolGroup> _connectionPoolGroups;
|
||||
private readonly List<DbConnectionPool> _poolsToRelease;
|
||||
private readonly List<DbConnectionPoolGroup> _poolGroupsToRelease;
|
||||
private readonly Timer _pruningTimer;
|
||||
private const int PruningDueTime = 4 * 60 * 1000; // 4 minutes
|
||||
private const int PruningPeriod = 30 * 1000; // thirty seconds
|
||||
|
||||
|
||||
// s_pendingOpenNonPooled is an array of tasks used to throttle creation of non-pooled connections to
|
||||
// a maximum of Environment.ProcessorCount at a time.
|
||||
private static uint s_pendingOpenNonPooledNext = 0;
|
||||
private static Task<DbConnectionInternal>[] s_pendingOpenNonPooled = new Task<DbConnectionInternal>[Environment.ProcessorCount];
|
||||
private static Task<DbConnectionInternal> s_completedTask;
|
||||
|
||||
protected DbConnectionFactory()
|
||||
{
|
||||
_connectionPoolGroups = new Dictionary<DbConnectionPoolKey, DbConnectionPoolGroup>();
|
||||
_poolsToRelease = new List<DbConnectionPool>();
|
||||
_poolGroupsToRelease = new List<DbConnectionPoolGroup>();
|
||||
_pruningTimer = CreatePruningTimer();
|
||||
}
|
||||
|
||||
|
||||
abstract public DbProviderFactory ProviderFactory
|
||||
{
|
||||
get;
|
||||
}
|
||||
|
||||
|
||||
public void ClearAllPools()
|
||||
{
|
||||
Dictionary<DbConnectionPoolKey, DbConnectionPoolGroup> connectionPoolGroups = _connectionPoolGroups;
|
||||
foreach (KeyValuePair<DbConnectionPoolKey, DbConnectionPoolGroup> entry in connectionPoolGroups)
|
||||
{
|
||||
DbConnectionPoolGroup poolGroup = entry.Value;
|
||||
if (null != poolGroup)
|
||||
{
|
||||
poolGroup.Clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void ClearPool(DbConnection connection)
|
||||
{
|
||||
ADP.CheckArgumentNull(connection, nameof(connection));
|
||||
|
||||
DbConnectionPoolGroup poolGroup = GetConnectionPoolGroup(connection);
|
||||
if (null != poolGroup)
|
||||
{
|
||||
poolGroup.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
public void ClearPool(DbConnectionPoolKey key)
|
||||
{
|
||||
Debug.Assert(key != null, "key cannot be null");
|
||||
ADP.CheckArgumentNull(key.ConnectionString, nameof(key) + "." + nameof(key.ConnectionString));
|
||||
|
||||
DbConnectionPoolGroup poolGroup;
|
||||
Dictionary<DbConnectionPoolKey, DbConnectionPoolGroup> connectionPoolGroups = _connectionPoolGroups;
|
||||
if (connectionPoolGroups.TryGetValue(key, out poolGroup))
|
||||
{
|
||||
poolGroup.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
internal virtual DbConnectionPoolProviderInfo CreateConnectionPoolProviderInfo(DbConnectionOptions connectionOptions)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
internal DbConnectionInternal CreateNonPooledConnection(DbConnection owningConnection, DbConnectionPoolGroup poolGroup, DbConnectionOptions userOptions)
|
||||
{
|
||||
Debug.Assert(null != owningConnection, "null owningConnection?");
|
||||
Debug.Assert(null != poolGroup, "null poolGroup?");
|
||||
|
||||
DbConnectionOptions connectionOptions = poolGroup.ConnectionOptions;
|
||||
DbConnectionPoolGroupProviderInfo poolGroupProviderInfo = poolGroup.ProviderInfo;
|
||||
DbConnectionPoolKey poolKey = poolGroup.PoolKey;
|
||||
|
||||
DbConnectionInternal newConnection = CreateConnection(connectionOptions, poolKey, poolGroupProviderInfo, null, owningConnection, userOptions);
|
||||
if (null != newConnection)
|
||||
{
|
||||
newConnection.MakeNonPooledObject(owningConnection);
|
||||
}
|
||||
return newConnection;
|
||||
}
|
||||
|
||||
internal DbConnectionInternal CreatePooledConnection(DbConnectionPool pool, DbConnection owningObject, DbConnectionOptions options, DbConnectionPoolKey poolKey, DbConnectionOptions userOptions)
|
||||
{
|
||||
Debug.Assert(null != pool, "null pool?");
|
||||
DbConnectionPoolGroupProviderInfo poolGroupProviderInfo = pool.PoolGroup.ProviderInfo;
|
||||
|
||||
DbConnectionInternal newConnection = CreateConnection(options, poolKey, poolGroupProviderInfo, pool, owningObject, userOptions);
|
||||
if (null != newConnection)
|
||||
{
|
||||
newConnection.MakePooledConnection(pool);
|
||||
}
|
||||
return newConnection;
|
||||
}
|
||||
|
||||
virtual internal DbConnectionPoolGroupProviderInfo CreateConnectionPoolGroupProviderInfo(DbConnectionOptions connectionOptions)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
private Timer CreatePruningTimer()
|
||||
{
|
||||
TimerCallback callback = new TimerCallback(PruneConnectionPoolGroups);
|
||||
return new Timer(callback, null, PruningDueTime, PruningPeriod);
|
||||
}
|
||||
|
||||
protected DbConnectionOptions FindConnectionOptions(DbConnectionPoolKey key)
|
||||
{
|
||||
Debug.Assert(key != null, "key cannot be null");
|
||||
if (!string.IsNullOrEmpty(key.ConnectionString))
|
||||
{
|
||||
DbConnectionPoolGroup connectionPoolGroup;
|
||||
Dictionary<DbConnectionPoolKey, DbConnectionPoolGroup> connectionPoolGroups = _connectionPoolGroups;
|
||||
if (connectionPoolGroups.TryGetValue(key, out connectionPoolGroup))
|
||||
{
|
||||
return connectionPoolGroup.ConnectionOptions;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static Task<DbConnectionInternal> GetCompletedTask()
|
||||
{
|
||||
Debug.Assert(Monitor.IsEntered(s_pendingOpenNonPooled), $"Expected {nameof(s_pendingOpenNonPooled)} lock to be held.");
|
||||
return s_completedTask ?? (s_completedTask = Task.FromResult<DbConnectionInternal>(null));
|
||||
}
|
||||
|
||||
internal bool TryGetConnection(DbConnection owningConnection, TaskCompletionSource<DbConnectionInternal> retry, DbConnectionOptions userOptions, DbConnectionInternal oldConnection, out DbConnectionInternal connection)
|
||||
{
|
||||
@@ -320,283 +182,5 @@ namespace System.Data.ProviderBase
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private DbConnectionPool GetConnectionPool(DbConnection owningObject, DbConnectionPoolGroup connectionPoolGroup)
|
||||
{
|
||||
// if poolgroup is disabled, it will be replaced with a new entry
|
||||
|
||||
Debug.Assert(null != owningObject, "null owningObject?");
|
||||
Debug.Assert(null != connectionPoolGroup, "null connectionPoolGroup?");
|
||||
|
||||
// It is possible that while the outer connection object has
|
||||
// been sitting around in a closed and unused state in some long
|
||||
// running app, the pruner may have come along and remove this
|
||||
// the pool entry from the master list. If we were to use a
|
||||
// pool entry in this state, we would create "unmanaged" pools,
|
||||
// which would be bad. To avoid this problem, we automagically
|
||||
// re-create the pool entry whenever it's disabled.
|
||||
|
||||
// however, don't rebuild connectionOptions if no pooling is involved - let new connections do that work
|
||||
if (connectionPoolGroup.IsDisabled && (null != connectionPoolGroup.PoolGroupOptions))
|
||||
{
|
||||
// reusing existing pool option in case user originally used SetConnectionPoolOptions
|
||||
DbConnectionPoolGroupOptions poolOptions = connectionPoolGroup.PoolGroupOptions;
|
||||
|
||||
// get the string to hash on again
|
||||
DbConnectionOptions connectionOptions = connectionPoolGroup.ConnectionOptions;
|
||||
Debug.Assert(null != connectionOptions, "prevent expansion of connectionString");
|
||||
|
||||
connectionPoolGroup = GetConnectionPoolGroup(connectionPoolGroup.PoolKey, poolOptions, ref connectionOptions);
|
||||
Debug.Assert(null != connectionPoolGroup, "null connectionPoolGroup?");
|
||||
SetConnectionPoolGroup(owningObject, connectionPoolGroup);
|
||||
}
|
||||
DbConnectionPool connectionPool = connectionPoolGroup.GetConnectionPool(this);
|
||||
return connectionPool;
|
||||
}
|
||||
|
||||
internal DbConnectionPoolGroup GetConnectionPoolGroup(DbConnectionPoolKey key, DbConnectionPoolGroupOptions poolOptions, ref DbConnectionOptions userConnectionOptions)
|
||||
{
|
||||
if (string.IsNullOrEmpty(key.ConnectionString))
|
||||
{
|
||||
return (DbConnectionPoolGroup)null;
|
||||
}
|
||||
|
||||
DbConnectionPoolGroup connectionPoolGroup;
|
||||
Dictionary<DbConnectionPoolKey, DbConnectionPoolGroup> connectionPoolGroups = _connectionPoolGroups;
|
||||
if (!connectionPoolGroups.TryGetValue(key, out connectionPoolGroup) || (connectionPoolGroup.IsDisabled && (null != connectionPoolGroup.PoolGroupOptions)))
|
||||
{
|
||||
// If we can't find an entry for the connection string in
|
||||
// our collection of pool entries, then we need to create a
|
||||
// new pool entry and add it to our collection.
|
||||
|
||||
DbConnectionOptions connectionOptions = CreateConnectionOptions(key.ConnectionString, userConnectionOptions);
|
||||
if (null == connectionOptions)
|
||||
{
|
||||
throw ADP.InternalConnectionError(ADP.ConnectionError.ConnectionOptionsMissing);
|
||||
}
|
||||
|
||||
if (null == userConnectionOptions)
|
||||
{ // we only allow one expansion on the connection string
|
||||
userConnectionOptions = connectionOptions;
|
||||
}
|
||||
|
||||
// We don't support connection pooling on Win9x
|
||||
if (null == poolOptions)
|
||||
{
|
||||
if (null != connectionPoolGroup)
|
||||
{
|
||||
// reusing existing pool option in case user originally used SetConnectionPoolOptions
|
||||
poolOptions = connectionPoolGroup.PoolGroupOptions;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Note: may return null for non-pooled connections
|
||||
poolOptions = CreateConnectionPoolGroupOptions(connectionOptions);
|
||||
}
|
||||
}
|
||||
|
||||
lock (this)
|
||||
{
|
||||
connectionPoolGroups = _connectionPoolGroups;
|
||||
if (!connectionPoolGroups.TryGetValue(key, out connectionPoolGroup))
|
||||
{
|
||||
DbConnectionPoolGroup newConnectionPoolGroup = new DbConnectionPoolGroup(connectionOptions, key, poolOptions);
|
||||
newConnectionPoolGroup.ProviderInfo = CreateConnectionPoolGroupProviderInfo(connectionOptions);
|
||||
|
||||
// build new dictionary with space for new connection string
|
||||
Dictionary<DbConnectionPoolKey, DbConnectionPoolGroup> newConnectionPoolGroups = new Dictionary<DbConnectionPoolKey, DbConnectionPoolGroup>(1 + connectionPoolGroups.Count);
|
||||
foreach (KeyValuePair<DbConnectionPoolKey, DbConnectionPoolGroup> entry in connectionPoolGroups)
|
||||
{
|
||||
newConnectionPoolGroups.Add(entry.Key, entry.Value);
|
||||
}
|
||||
|
||||
// lock prevents race condition with PruneConnectionPoolGroups
|
||||
newConnectionPoolGroups.Add(key, newConnectionPoolGroup);
|
||||
connectionPoolGroup = newConnectionPoolGroup;
|
||||
_connectionPoolGroups = newConnectionPoolGroups;
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.Assert(!connectionPoolGroup.IsDisabled, "Disabled pool entry discovered");
|
||||
}
|
||||
}
|
||||
Debug.Assert(null != connectionPoolGroup, "how did we not create a pool entry?");
|
||||
Debug.Assert(null != userConnectionOptions, "how did we not have user connection options?");
|
||||
}
|
||||
else if (null == userConnectionOptions)
|
||||
{
|
||||
userConnectionOptions = connectionPoolGroup.ConnectionOptions;
|
||||
}
|
||||
return connectionPoolGroup;
|
||||
}
|
||||
|
||||
|
||||
private void PruneConnectionPoolGroups(object state)
|
||||
{
|
||||
// First, walk the pool release list and attempt to clear each
|
||||
// pool, when the pool is finally empty, we dispose of it. If the
|
||||
// pool isn't empty, it's because there are active connections or
|
||||
// distributed transactions that need it.
|
||||
lock (_poolsToRelease)
|
||||
{
|
||||
if (0 != _poolsToRelease.Count)
|
||||
{
|
||||
DbConnectionPool[] poolsToRelease = _poolsToRelease.ToArray();
|
||||
foreach (DbConnectionPool pool in poolsToRelease)
|
||||
{
|
||||
if (null != pool)
|
||||
{
|
||||
pool.Clear();
|
||||
|
||||
if (0 == pool.Count)
|
||||
{
|
||||
_poolsToRelease.Remove(pool);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Next, walk the pool entry release list and dispose of each
|
||||
// pool entry when it is finally empty. If the pool entry isn't
|
||||
// empty, it's because there are active pools that need it.
|
||||
lock (_poolGroupsToRelease)
|
||||
{
|
||||
if (0 != _poolGroupsToRelease.Count)
|
||||
{
|
||||
DbConnectionPoolGroup[] poolGroupsToRelease = _poolGroupsToRelease.ToArray();
|
||||
foreach (DbConnectionPoolGroup poolGroup in poolGroupsToRelease)
|
||||
{
|
||||
if (null != poolGroup)
|
||||
{
|
||||
int poolsLeft = poolGroup.Clear(); // may add entries to _poolsToRelease
|
||||
|
||||
if (0 == poolsLeft)
|
||||
{
|
||||
_poolGroupsToRelease.Remove(poolGroup);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Finally, we walk through the collection of connection pool entries
|
||||
// and prune each one. This will cause any empty pools to be put
|
||||
// into the release list.
|
||||
lock (this)
|
||||
{
|
||||
Dictionary<DbConnectionPoolKey, DbConnectionPoolGroup> connectionPoolGroups = _connectionPoolGroups;
|
||||
Dictionary<DbConnectionPoolKey, DbConnectionPoolGroup> newConnectionPoolGroups = new Dictionary<DbConnectionPoolKey, DbConnectionPoolGroup>(connectionPoolGroups.Count);
|
||||
|
||||
foreach (KeyValuePair<DbConnectionPoolKey, DbConnectionPoolGroup> entry in connectionPoolGroups)
|
||||
{
|
||||
if (null != entry.Value)
|
||||
{
|
||||
Debug.Assert(!entry.Value.IsDisabled, "Disabled pool entry discovered");
|
||||
|
||||
// entries start active and go idle during prune if all pools are gone
|
||||
// move idle entries from last prune pass to a queue for pending release
|
||||
// otherwise process entry which may move it from active to idle
|
||||
if (entry.Value.Prune())
|
||||
{ // may add entries to _poolsToRelease
|
||||
QueuePoolGroupForRelease(entry.Value);
|
||||
}
|
||||
else
|
||||
{
|
||||
newConnectionPoolGroups.Add(entry.Key, entry.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
_connectionPoolGroups = newConnectionPoolGroups;
|
||||
}
|
||||
}
|
||||
|
||||
internal void QueuePoolForRelease(DbConnectionPool pool, bool clearing)
|
||||
{
|
||||
// Queue the pool up for release -- we'll clear it out and dispose
|
||||
// of it as the last part of the pruning timer callback so we don't
|
||||
// do it with the pool entry or the pool collection locked.
|
||||
Debug.Assert(null != pool, "null pool?");
|
||||
|
||||
// set the pool to the shutdown state to force all active
|
||||
// connections to be automatically disposed when they
|
||||
// are returned to the pool
|
||||
pool.Shutdown();
|
||||
|
||||
lock (_poolsToRelease)
|
||||
{
|
||||
if (clearing)
|
||||
{
|
||||
pool.Clear();
|
||||
}
|
||||
_poolsToRelease.Add(pool);
|
||||
}
|
||||
}
|
||||
|
||||
internal void QueuePoolGroupForRelease(DbConnectionPoolGroup poolGroup)
|
||||
{
|
||||
Debug.Assert(null != poolGroup, "null poolGroup?");
|
||||
|
||||
lock (_poolGroupsToRelease)
|
||||
{
|
||||
_poolGroupsToRelease.Add(poolGroup);
|
||||
}
|
||||
}
|
||||
|
||||
virtual protected DbConnectionInternal CreateConnection(DbConnectionOptions options, DbConnectionPoolKey poolKey, object poolGroupProviderInfo, DbConnectionPool pool, DbConnection owningConnection, DbConnectionOptions userOptions)
|
||||
{
|
||||
return CreateConnection(options, poolKey, poolGroupProviderInfo, pool, owningConnection);
|
||||
}
|
||||
|
||||
internal DbMetaDataFactory GetMetaDataFactory(DbConnectionPoolGroup connectionPoolGroup, DbConnectionInternal internalConnection)
|
||||
{
|
||||
Debug.Assert(connectionPoolGroup != null, "connectionPoolGroup may not be null.");
|
||||
|
||||
// get the matadatafactory from the pool entry. If it does not already have one
|
||||
// create one and save it on the pool entry
|
||||
DbMetaDataFactory metaDataFactory = connectionPoolGroup.MetaDataFactory;
|
||||
|
||||
// consider serializing this so we don't construct multiple metadata factories
|
||||
// if two threads happen to hit this at the same time. One will be GC'd
|
||||
if (metaDataFactory == null)
|
||||
{
|
||||
bool allowCache = false;
|
||||
metaDataFactory = CreateMetaDataFactory(internalConnection, out allowCache);
|
||||
if (allowCache)
|
||||
{
|
||||
connectionPoolGroup.MetaDataFactory = metaDataFactory;
|
||||
}
|
||||
}
|
||||
return metaDataFactory;
|
||||
}
|
||||
|
||||
protected virtual DbMetaDataFactory CreateMetaDataFactory(DbConnectionInternal internalConnection, out bool cacheMetaDataFactory)
|
||||
{
|
||||
// providers that support GetSchema must override this with a method that creates a meta data
|
||||
// factory appropriate for them.
|
||||
cacheMetaDataFactory = false;
|
||||
throw ADP.NotSupported();
|
||||
}
|
||||
|
||||
abstract protected DbConnectionInternal CreateConnection(DbConnectionOptions options, DbConnectionPoolKey poolKey, object poolGroupProviderInfo, DbConnectionPool pool, DbConnection owningConnection);
|
||||
|
||||
abstract protected DbConnectionOptions CreateConnectionOptions(string connectionString, DbConnectionOptions previous);
|
||||
|
||||
abstract protected DbConnectionPoolGroupOptions CreateConnectionPoolGroupOptions(DbConnectionOptions options);
|
||||
|
||||
abstract internal DbConnectionPoolGroup GetConnectionPoolGroup(DbConnection connection);
|
||||
|
||||
abstract internal DbConnectionInternal GetInnerConnection(DbConnection connection);
|
||||
|
||||
|
||||
abstract internal void PermissionDemand(DbConnection outerConnection);
|
||||
|
||||
abstract internal void SetConnectionPoolGroup(DbConnection outerConnection, DbConnectionPoolGroup poolGroup);
|
||||
|
||||
abstract internal void SetInnerConnectionEvent(DbConnection owningObject, DbConnectionInternal to);
|
||||
|
||||
abstract internal bool SetInnerConnectionFrom(DbConnection owningObject, DbConnectionInternal to, DbConnectionInternal from);
|
||||
|
||||
abstract internal void SetInnerConnectionTo(DbConnection owningObject, DbConnectionInternal to);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,40 +3,18 @@
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
using System.Data.Common;
|
||||
using System.Data.SqlClient;
|
||||
using System.Diagnostics;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Transactions;
|
||||
|
||||
|
||||
namespace System.Data.ProviderBase
|
||||
{
|
||||
internal abstract class DbConnectionInternal
|
||||
internal abstract partial class DbConnectionInternal
|
||||
{
|
||||
internal static readonly StateChangeEventArgs StateChangeClosed = new StateChangeEventArgs(ConnectionState.Open, ConnectionState.Closed);
|
||||
internal static readonly StateChangeEventArgs StateChangeOpen = new StateChangeEventArgs(ConnectionState.Closed, ConnectionState.Open);
|
||||
|
||||
private readonly bool _allowSetConnectionString;
|
||||
private readonly bool _hidePassword;
|
||||
private readonly ConnectionState _state;
|
||||
|
||||
private readonly WeakReference _owningObject = new WeakReference(null, false); // [usage must be thread safe] the owning object, when not in the pool. (both Pooled and Non-Pooled connections)
|
||||
|
||||
private DbConnectionPool _connectionPool; // the pooler that the connection came from (Pooled connections only)
|
||||
private DbReferenceCollection _referenceCollection; // collection of objects that we need to notify in some way when we're being deactivated
|
||||
private int _pooledCount; // [usage must be thread safe] the number of times this object has been pushed into the pool less the number of times it's been popped (0 != inPool)
|
||||
|
||||
private bool _connectionIsDoomed; // true when the connection should no longer be used.
|
||||
private bool _cannotBePooled; // true when the connection should no longer be pooled.
|
||||
private bool _isInStasis;
|
||||
|
||||
private DateTime _createTime; // when the connection was created.
|
||||
|
||||
private Transaction _enlistedTransaction; // [usage must be thread-safe] the transaction that we're enlisted in, either manually or automatically
|
||||
|
||||
// _enlistedTransaction is a clone, so that transaction information can be queried even if the original transaction object is disposed.
|
||||
@@ -45,39 +23,6 @@ namespace System.Data.ProviderBase
|
||||
// Also, this reference should not be disposed, since we aren't taking ownership of it.
|
||||
private Transaction _enlistedTransactionOriginal;
|
||||
|
||||
#if DEBUG
|
||||
private int _activateCount; // debug only counter to verify activate/deactivates are in sync.
|
||||
#endif //DEBUG
|
||||
|
||||
protected DbConnectionInternal() : this(ConnectionState.Open, true, false)
|
||||
{
|
||||
}
|
||||
|
||||
// Constructor for internal connections
|
||||
internal DbConnectionInternal(ConnectionState state, bool hidePassword, bool allowSetConnectionString)
|
||||
{
|
||||
_allowSetConnectionString = allowSetConnectionString;
|
||||
_hidePassword = hidePassword;
|
||||
_state = state;
|
||||
}
|
||||
|
||||
internal bool AllowSetConnectionString
|
||||
{
|
||||
get
|
||||
{
|
||||
return _allowSetConnectionString;
|
||||
}
|
||||
}
|
||||
|
||||
internal bool CanBePooled
|
||||
{
|
||||
get
|
||||
{
|
||||
bool flag = (!_connectionIsDoomed && !_cannotBePooled && !_owningObject.IsAlive);
|
||||
return flag;
|
||||
}
|
||||
}
|
||||
|
||||
protected internal Transaction EnlistedTransaction
|
||||
{
|
||||
get
|
||||
@@ -237,74 +182,6 @@ namespace System.Data.ProviderBase
|
||||
}
|
||||
}
|
||||
|
||||
protected internal bool IsConnectionDoomed
|
||||
{
|
||||
get
|
||||
{
|
||||
return _connectionIsDoomed;
|
||||
}
|
||||
}
|
||||
|
||||
internal bool IsEmancipated
|
||||
{
|
||||
get
|
||||
{
|
||||
// NOTE: There are race conditions between PrePush, PostPop and this
|
||||
// property getter -- only use this while this object is locked;
|
||||
// (DbConnectionPool.Clear and ReclaimEmancipatedObjects
|
||||
// do this for us)
|
||||
|
||||
// The functionality is as follows:
|
||||
//
|
||||
// _pooledCount is incremented when the connection is pushed into the pool
|
||||
// _pooledCount is decremented when the connection is popped from the pool
|
||||
// _pooledCount is set to -1 when the connection is not pooled (just in case...)
|
||||
//
|
||||
// That means that:
|
||||
//
|
||||
// _pooledCount > 1 connection is in the pool multiple times (This should not happen)
|
||||
// _pooledCount == 1 connection is in the pool
|
||||
// _pooledCount == 0 connection is out of the pool
|
||||
// _pooledCount == -1 connection is not a pooled connection; we shouldn't be here for non-pooled connections.
|
||||
// _pooledCount < -1 connection out of the pool multiple times
|
||||
//
|
||||
// Now, our job is to return TRUE when the connection is out
|
||||
// of the pool and it's owning object is no longer around to
|
||||
// return it.
|
||||
|
||||
bool value = (_pooledCount < 1) && !_owningObject.IsAlive;
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
internal bool IsInPool
|
||||
{
|
||||
get
|
||||
{
|
||||
Debug.Assert(_pooledCount <= 1 && _pooledCount >= -1, "Pooled count for object is invalid");
|
||||
return (_pooledCount == 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected internal object Owner
|
||||
{
|
||||
// We use a weak reference to the owning object so we can identify when
|
||||
// it has been garbage collected without thowing exceptions.
|
||||
get
|
||||
{
|
||||
return _owningObject.Target;
|
||||
}
|
||||
}
|
||||
|
||||
internal DbConnectionPool Pool
|
||||
{
|
||||
get
|
||||
{
|
||||
return _connectionPool;
|
||||
}
|
||||
}
|
||||
|
||||
virtual protected bool ReadyToPrepareTransaction
|
||||
{
|
||||
get
|
||||
@@ -313,44 +190,6 @@ namespace System.Data.ProviderBase
|
||||
}
|
||||
}
|
||||
|
||||
protected internal DbReferenceCollection ReferenceCollection
|
||||
{
|
||||
get
|
||||
{
|
||||
return _referenceCollection;
|
||||
}
|
||||
}
|
||||
|
||||
abstract public string ServerVersion
|
||||
{
|
||||
get;
|
||||
}
|
||||
|
||||
// this should be abstract but until it is added to all the providers virtual will have to do
|
||||
virtual public string ServerVersionNormalized
|
||||
{
|
||||
get
|
||||
{
|
||||
throw ADP.NotSupported();
|
||||
}
|
||||
}
|
||||
|
||||
public bool ShouldHidePassword
|
||||
{
|
||||
get
|
||||
{
|
||||
return _hidePassword;
|
||||
}
|
||||
}
|
||||
|
||||
public ConnectionState State
|
||||
{
|
||||
get
|
||||
{
|
||||
return _state;
|
||||
}
|
||||
}
|
||||
|
||||
abstract protected void Activate(Transaction transaction);
|
||||
|
||||
internal void ActivateConnection(Transaction transaction)
|
||||
@@ -361,26 +200,6 @@ namespace System.Data.ProviderBase
|
||||
Activate(transaction);
|
||||
}
|
||||
|
||||
internal void AddWeakReference(object value, int tag)
|
||||
{
|
||||
if (null == _referenceCollection)
|
||||
{
|
||||
_referenceCollection = CreateReferenceCollection();
|
||||
if (null == _referenceCollection)
|
||||
{
|
||||
throw ADP.InternalError(ADP.InternalErrorCode.CreateReferenceCollectionReturnedNull);
|
||||
}
|
||||
}
|
||||
_referenceCollection.Add(value, tag);
|
||||
}
|
||||
|
||||
abstract public DbTransaction BeginTransaction(IsolationLevel il);
|
||||
|
||||
virtual public void ChangeDatabase(string value)
|
||||
{
|
||||
throw ADP.MethodNotImplemented();
|
||||
}
|
||||
|
||||
internal virtual void CloseConnection(DbConnection owningObject, DbConnectionFactory connectionFactory)
|
||||
{
|
||||
// The implementation here is the implementation required for the
|
||||
@@ -487,57 +306,6 @@ namespace System.Data.ProviderBase
|
||||
}
|
||||
}
|
||||
|
||||
virtual internal void PrepareForReplaceConnection()
|
||||
{
|
||||
// By default, there is no preparation required
|
||||
}
|
||||
|
||||
virtual protected void PrepareForCloseConnection()
|
||||
{
|
||||
// By default, there is no preparation required
|
||||
}
|
||||
|
||||
virtual protected object ObtainAdditionalLocksForClose()
|
||||
{
|
||||
return null; // no additional locks in default implementation
|
||||
}
|
||||
|
||||
virtual protected void ReleaseAdditionalLocksForClose(object lockToken)
|
||||
{
|
||||
// no additional locks in default implementation
|
||||
}
|
||||
|
||||
virtual protected DbReferenceCollection CreateReferenceCollection()
|
||||
{
|
||||
throw ADP.InternalError(ADP.InternalErrorCode.AttemptingToConstructReferenceCollectionOnStaticObject);
|
||||
}
|
||||
|
||||
abstract protected void Deactivate();
|
||||
|
||||
internal void DeactivateConnection()
|
||||
{
|
||||
// Internal method called from the connection pooler so we don't expose
|
||||
// the Deactivate method publicly.
|
||||
|
||||
#if DEBUG
|
||||
int activateCount = Interlocked.Decrement(ref _activateCount);
|
||||
#endif // DEBUG
|
||||
|
||||
|
||||
if (!_connectionIsDoomed && Pool.UseLoadBalancing)
|
||||
{
|
||||
// If we're not already doomed, check the connection's lifetime and
|
||||
// doom it if it's lifetime has elapsed.
|
||||
|
||||
DateTime now = DateTime.UtcNow;
|
||||
if ((now.Ticks - _createTime.Ticks) > Pool.LoadBalanceTimeout.Ticks)
|
||||
{
|
||||
DoNotPoolThisConnection();
|
||||
}
|
||||
}
|
||||
Deactivate();
|
||||
}
|
||||
|
||||
virtual internal void DelegatedTransactionEnded()
|
||||
{
|
||||
// Called by System.Transactions when the delegated transaction has
|
||||
@@ -604,188 +372,9 @@ namespace System.Data.ProviderBase
|
||||
enlistedTransaction.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
protected internal void DoNotPoolThisConnection()
|
||||
{
|
||||
_cannotBePooled = true;
|
||||
}
|
||||
|
||||
/// <devdoc>Ensure that this connection cannot be put back into the pool.</devdoc>
|
||||
protected internal void DoomThisConnection()
|
||||
{
|
||||
_connectionIsDoomed = true;
|
||||
}
|
||||
|
||||
|
||||
abstract public void EnlistTransaction(Transaction transaction);
|
||||
|
||||
protected internal virtual DataTable GetSchema(DbConnectionFactory factory, DbConnectionPoolGroup poolGroup, DbConnection outerConnection, string collectionName, string[] restrictions)
|
||||
{
|
||||
Debug.Assert(outerConnection != null, "outerConnection may not be null.");
|
||||
|
||||
DbMetaDataFactory metaDataFactory = factory.GetMetaDataFactory(poolGroup, this);
|
||||
Debug.Assert(metaDataFactory != null, "metaDataFactory may not be null.");
|
||||
|
||||
return metaDataFactory.GetSchema(outerConnection, collectionName, restrictions);
|
||||
}
|
||||
|
||||
internal void MakeNonPooledObject(object owningObject)
|
||||
{
|
||||
// Used by DbConnectionFactory to indicate that this object IS NOT part of
|
||||
// a connection pool.
|
||||
|
||||
_connectionPool = null;
|
||||
_owningObject.Target = owningObject;
|
||||
_pooledCount = -1;
|
||||
}
|
||||
|
||||
internal void MakePooledConnection(DbConnectionPool connectionPool)
|
||||
{
|
||||
// Used by DbConnectionFactory to indicate that this object IS part of
|
||||
// a connection pool.
|
||||
_createTime = DateTime.UtcNow;
|
||||
|
||||
_connectionPool = connectionPool;
|
||||
}
|
||||
|
||||
internal void NotifyWeakReference(int message)
|
||||
{
|
||||
DbReferenceCollection referenceCollection = ReferenceCollection;
|
||||
if (null != referenceCollection)
|
||||
{
|
||||
referenceCollection.Notify(message);
|
||||
}
|
||||
}
|
||||
|
||||
internal virtual void OpenConnection(DbConnection outerConnection, DbConnectionFactory connectionFactory)
|
||||
{
|
||||
if (!TryOpenConnection(outerConnection, connectionFactory, null, null))
|
||||
{
|
||||
throw ADP.InternalError(ADP.InternalErrorCode.SynchronousConnectReturnedPending);
|
||||
}
|
||||
}
|
||||
|
||||
/// <devdoc>The default implementation is for the open connection objects, and
|
||||
/// it simply throws. Our private closed-state connection objects
|
||||
/// override this and do the correct thing.</devdoc>
|
||||
// User code should either override DbConnectionInternal.Activate when it comes out of the pool
|
||||
// or override DbConnectionFactory.CreateConnection when the connection is created for non-pooled connections
|
||||
internal virtual bool TryOpenConnection(DbConnection outerConnection, DbConnectionFactory connectionFactory, TaskCompletionSource<DbConnectionInternal> retry, DbConnectionOptions userOptions)
|
||||
{
|
||||
throw ADP.ConnectionAlreadyOpen(State);
|
||||
}
|
||||
|
||||
internal virtual bool TryReplaceConnection(DbConnection outerConnection, DbConnectionFactory connectionFactory, TaskCompletionSource<DbConnectionInternal> retry, DbConnectionOptions userOptions)
|
||||
{
|
||||
throw ADP.MethodNotImplemented();
|
||||
}
|
||||
|
||||
protected bool TryOpenConnectionInternal(DbConnection outerConnection, DbConnectionFactory connectionFactory, TaskCompletionSource<DbConnectionInternal> retry, DbConnectionOptions userOptions)
|
||||
{
|
||||
// ?->Connecting: prevent set_ConnectionString during Open
|
||||
if (connectionFactory.SetInnerConnectionFrom(outerConnection, DbConnectionClosedConnecting.SingletonInstance, this))
|
||||
{
|
||||
DbConnectionInternal openConnection = null;
|
||||
try
|
||||
{
|
||||
connectionFactory.PermissionDemand(outerConnection);
|
||||
if (!connectionFactory.TryGetConnection(outerConnection, retry, userOptions, this, out openConnection))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// This should occur for all exceptions, even ADP.UnCatchableExceptions.
|
||||
connectionFactory.SetInnerConnectionTo(outerConnection, this);
|
||||
throw;
|
||||
}
|
||||
if (null == openConnection)
|
||||
{
|
||||
connectionFactory.SetInnerConnectionTo(outerConnection, this);
|
||||
throw ADP.InternalConnectionError(ADP.ConnectionError.GetConnectionReturnsNull);
|
||||
}
|
||||
connectionFactory.SetInnerConnectionEvent(outerConnection, openConnection);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
internal void PrePush(object expectedOwner)
|
||||
{
|
||||
// Called by DbConnectionPool when we're about to be put into it's pool, we
|
||||
// take this opportunity to ensure ownership and pool counts are legit.
|
||||
|
||||
// IMPORTANT NOTE: You must have taken a lock on the object before
|
||||
// you call this method to prevent race conditions with Clear and
|
||||
// ReclaimEmancipatedObjects.
|
||||
|
||||
//3 // The following tests are retail assertions of things we can't allow to happen.
|
||||
if (null == expectedOwner)
|
||||
{
|
||||
if (null != _owningObject.Target)
|
||||
{
|
||||
throw ADP.InternalError(ADP.InternalErrorCode.UnpooledObjectHasOwner); // new unpooled object has an owner
|
||||
}
|
||||
}
|
||||
else if (_owningObject.Target != expectedOwner)
|
||||
{
|
||||
throw ADP.InternalError(ADP.InternalErrorCode.UnpooledObjectHasWrongOwner); // unpooled object has incorrect owner
|
||||
}
|
||||
if (0 != _pooledCount)
|
||||
{
|
||||
throw ADP.InternalError(ADP.InternalErrorCode.PushingObjectSecondTime); // pushing object onto stack a second time
|
||||
}
|
||||
_pooledCount++;
|
||||
_owningObject.Target = null; // NOTE: doing this and checking for InternalError.PooledObjectHasOwner degrades the close by 2%
|
||||
}
|
||||
|
||||
internal void PostPop(object newOwner)
|
||||
{
|
||||
// Called by DbConnectionPool right after it pulls this from it's pool, we
|
||||
// take this opportunity to ensure ownership and pool counts are legit.
|
||||
|
||||
Debug.Assert(!IsEmancipated, "pooled object not in pool");
|
||||
|
||||
// When another thread is clearing this pool, it
|
||||
// will doom all connections in this pool without prejudice which
|
||||
// causes the following assert to fire, which really mucks up stress
|
||||
// against checked bits. The assert is benign, so we're commenting
|
||||
// it out.
|
||||
//Debug.Assert(CanBePooled, "pooled object is not poolable");
|
||||
|
||||
// IMPORTANT NOTE: You must have taken a lock on the object before
|
||||
// you call this method to prevent race conditions with Clear and
|
||||
// ReclaimEmancipatedObjects.
|
||||
|
||||
if (null != _owningObject.Target)
|
||||
{
|
||||
throw ADP.InternalError(ADP.InternalErrorCode.PooledObjectHasOwner); // pooled connection already has an owner!
|
||||
}
|
||||
_owningObject.Target = newOwner;
|
||||
_pooledCount--;
|
||||
//3 // The following tests are retail assertions of things we can't allow to happen.
|
||||
if (null != Pool)
|
||||
{
|
||||
if (0 != _pooledCount)
|
||||
{
|
||||
throw ADP.InternalError(ADP.InternalErrorCode.PooledObjectInPoolMoreThanOnce); // popping object off stack with multiple pooledCount
|
||||
}
|
||||
}
|
||||
else if (-1 != _pooledCount)
|
||||
{
|
||||
throw ADP.InternalError(ADP.InternalErrorCode.NonPooledObjectUsedMoreThanOnce); // popping object off stack with multiple pooledCount
|
||||
}
|
||||
}
|
||||
|
||||
internal void RemoveWeakReference(object value)
|
||||
{
|
||||
DbReferenceCollection referenceCollection = ReferenceCollection;
|
||||
if (null != referenceCollection)
|
||||
{
|
||||
referenceCollection.Remove(value);
|
||||
}
|
||||
}
|
||||
|
||||
// Cleanup connection's transaction-specific structures (currently used by Delegated transaction).
|
||||
// This is a separate method because cleanup can be triggered in multiple ways for a delegated
|
||||
// transaction.
|
||||
@@ -876,16 +465,5 @@ namespace System.Data.ProviderBase
|
||||
{
|
||||
_isInStasis = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// When overridden in a derived class, will check if the underlying connection is still actually alive
|
||||
/// </summary>
|
||||
/// <param name="throwOnException">If true an exception will be thrown if the connection is dead instead of returning true\false
|
||||
/// (this allows the caller to have the real reason that the connection is not alive (e.g. network error, etc))</param>
|
||||
/// <returns>True if the connection is still alive, otherwise false (If not overridden, then always true)</returns>
|
||||
internal virtual bool IsConnectionAlive(bool throwOnException = false)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -413,10 +413,7 @@ namespace System.Data.ProviderBase
|
||||
|
||||
_objectList = new List<DbConnectionInternal>(MaxPoolSize);
|
||||
|
||||
if (ADP.IsPlatformNT5)
|
||||
{
|
||||
_transactedConnectionPool = new TransactedConnectionPool(this);
|
||||
}
|
||||
_transactedConnectionPool = new TransactedConnectionPool(this); // initialize irrespective of platform
|
||||
|
||||
_poolCreateRequest = new WaitCallback(PoolCreateRequest); // used by CleanupCallback
|
||||
_state = State.Running;
|
||||
@@ -664,10 +661,12 @@ namespace System.Data.ProviderBase
|
||||
ReclaimEmancipatedObjects();
|
||||
}
|
||||
|
||||
private Timer CreateCleanupTimer()
|
||||
{
|
||||
return (new Timer(new TimerCallback(this.CleanupCallback), null, _cleanupWait, _cleanupWait));
|
||||
}
|
||||
private Timer CreateCleanupTimer() =>
|
||||
ADP.UnsafeCreateTimer(
|
||||
new TimerCallback(CleanupCallback),
|
||||
null,
|
||||
_cleanupWait,
|
||||
_cleanupWait);
|
||||
|
||||
private DbConnectionInternal CreateObject(DbConnection owningObject, DbConnectionOptions userOptions, DbConnectionInternal oldConnection)
|
||||
{
|
||||
@@ -728,6 +727,7 @@ namespace System.Data.ProviderBase
|
||||
|
||||
// timer allocation has to be done out of CER block
|
||||
Timer t = new Timer(new TimerCallback(this.ErrorCallback), null, Timeout.Infinite, Timeout.Infinite);
|
||||
|
||||
bool timerIsNotDisposed;
|
||||
try { }
|
||||
finally
|
||||
@@ -1373,9 +1373,19 @@ namespace System.Data.ProviderBase
|
||||
{
|
||||
while (NeedToReplenish)
|
||||
{
|
||||
// Don't specify any user options because there is no outer connection associated with the new connection
|
||||
newObj = CreateObject(owningObject: null, userOptions: null, oldConnection: null);
|
||||
|
||||
try
|
||||
{
|
||||
// Don't specify any user options because there is no outer connection associated with the new connection
|
||||
newObj = CreateObject(owningObject: null, userOptions: null, oldConnection: null);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Catch all the exceptions occuring during CreateObject so that they
|
||||
// don't emerge as unhandled on the thread pool and don't crash applications
|
||||
// The error is handled in CreateObject and surfaced to the caller of the Connection Pool
|
||||
// using the ErrorEvent. Hence it is OK to swallow all exceptions here.
|
||||
break;
|
||||
}
|
||||
// We do not need to check error flag here, since we know if
|
||||
// CreateObject returned null, we are in error case.
|
||||
if (null != newObj)
|
||||
|
||||
@@ -1,313 +0,0 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
using System.Collections.Concurrent;
|
||||
using System.Data.Common;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace System.Data.ProviderBase
|
||||
{
|
||||
// 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;
|
||||
|
||||
// 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 pruning method
|
||||
|
||||
internal DbConnectionPoolGroup(DbConnectionOptions connectionOptions, DbConnectionPoolKey key, DbConnectionPoolGroupOptions poolGroupOptions)
|
||||
{
|
||||
Debug.Assert(null != connectionOptions, "null connection options");
|
||||
|
||||
_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;
|
||||
}
|
||||
|
||||
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 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;
|
||||
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;
|
||||
// PoolGroupOptions will only be null when we're not supposed to pool
|
||||
// connections.
|
||||
DbConnectionPool pool = null;
|
||||
if (null != _poolGroupOptions)
|
||||
{
|
||||
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
|
||||
{
|
||||
lock (this)
|
||||
{
|
||||
// Did someone already add it to the list?
|
||||
if (!_poolCollection.TryGetValue(currentIdentity, out pool))
|
||||
{
|
||||
DbConnectionPoolProviderInfo connectionPoolProviderInfo = connectionFactory.CreateConnectionPoolProviderInfo(this.ConnectionOptions);
|
||||
DbConnectionPool newPool = new DbConnectionPool(connectionFactory, this, currentIdentity, connectionPoolProviderInfo);
|
||||
|
||||
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");
|
||||
pool = newPool;
|
||||
}
|
||||
else
|
||||
{
|
||||
// else pool entry has been disabled so don't create new pools
|
||||
Debug.Assert(PoolGroupStateDisabled == _state, "state should be disabled");
|
||||
|
||||
// don't need to call connectionFactory.QueuePoolForRelease(newPool) because
|
||||
// pool callbacks were delayed and no risk of connections being created
|
||||
newPool.Shutdown();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// else found an existing pool to use instead
|
||||
Debug.Assert(PoolGroupStateActive == _state, "state should be active since a pool exists and lock holds");
|
||||
}
|
||||
}
|
||||
}
|
||||
// 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;
|
||||
}
|
||||
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;
|
||||
|
||||
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;
|
||||
}
|
||||
else if (PoolGroupStateIdle == _state)
|
||||
{
|
||||
_state = PoolGroupStateDisabled;
|
||||
}
|
||||
}
|
||||
return (PoolGroupStateDisabled == _state);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,286 +0,0 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
using System.Diagnostics;
|
||||
using System.Threading;
|
||||
|
||||
namespace System.Data.ProviderBase
|
||||
{
|
||||
internal abstract class DbReferenceCollection
|
||||
{
|
||||
private struct CollectionEntry
|
||||
{
|
||||
private int _tag; // information about the reference
|
||||
private WeakReference _weak; // the reference itself.
|
||||
|
||||
public void NewTarget(int tag, object target)
|
||||
{
|
||||
Debug.Assert(!HasTarget, "Entry already has a valid target");
|
||||
Debug.Assert(tag != 0, "Bad tag");
|
||||
Debug.Assert(target != null, "Invalid target");
|
||||
|
||||
if (_weak == null)
|
||||
{
|
||||
_weak = new WeakReference(target, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
_weak.Target = target;
|
||||
}
|
||||
_tag = tag;
|
||||
}
|
||||
|
||||
public void RemoveTarget()
|
||||
{
|
||||
_tag = 0;
|
||||
}
|
||||
|
||||
public bool HasTarget
|
||||
{
|
||||
get
|
||||
{
|
||||
return ((_tag != 0) && (_weak.IsAlive));
|
||||
}
|
||||
}
|
||||
|
||||
public int Tag
|
||||
{
|
||||
get
|
||||
{
|
||||
return _tag;
|
||||
}
|
||||
}
|
||||
|
||||
public object Target
|
||||
{
|
||||
get
|
||||
{
|
||||
return (_tag == 0 ? null : _weak.Target);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private const int LockPollTime = 100; // Time to wait (in ms) between attempting to get the _itemLock
|
||||
private const int DefaultCollectionSize = 20; // Default size for the collection, and the amount to grow every time the collection is full
|
||||
private CollectionEntry[] _items; // The collection of items we are keeping track of
|
||||
private readonly object _itemLock; // Used to synchronize access to the _items collection
|
||||
private int _optimisticCount; // (#ItemsAdded - #ItemsRemoved) - This estimates the number of items that we *should* have (but doesn't take into account item targets being GC'd)
|
||||
private int _lastItemIndex; // Location of the last item in _items
|
||||
private volatile bool _isNotifying; // Indicates that the collection is currently being notified (and, therefore, about to be cleared)
|
||||
|
||||
protected DbReferenceCollection()
|
||||
{
|
||||
_items = new CollectionEntry[DefaultCollectionSize];
|
||||
_itemLock = new object();
|
||||
_optimisticCount = 0;
|
||||
_lastItemIndex = 0;
|
||||
}
|
||||
|
||||
abstract public void Add(object value, int tag);
|
||||
|
||||
protected void AddItem(object value, int tag)
|
||||
{
|
||||
Debug.Assert(null != value && 0 != tag, "AddItem with null value or 0 tag");
|
||||
bool itemAdded = false;
|
||||
|
||||
lock (_itemLock)
|
||||
{
|
||||
// Try to find a free spot
|
||||
for (int i = 0; i <= _lastItemIndex; ++i)
|
||||
{
|
||||
if (_items[i].Tag == 0)
|
||||
{
|
||||
_items[i].NewTarget(tag, value);
|
||||
Debug.Assert(_items[i].HasTarget, "missing expected target");
|
||||
itemAdded = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// No free spots, can we just add on to the end?
|
||||
if ((!itemAdded) && (_lastItemIndex + 1 < _items.Length))
|
||||
{
|
||||
_lastItemIndex++;
|
||||
_items[_lastItemIndex].NewTarget(tag, value);
|
||||
itemAdded = true;
|
||||
}
|
||||
|
||||
// If no free spots and no space at the end, try to find a dead item
|
||||
if (!itemAdded)
|
||||
{
|
||||
for (int i = 0; i <= _lastItemIndex; ++i)
|
||||
{
|
||||
if (!_items[i].HasTarget)
|
||||
{
|
||||
_items[i].NewTarget(tag, value);
|
||||
Debug.Assert(_items[i].HasTarget, "missing expected target");
|
||||
itemAdded = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If nothing was free, then resize and add to the end
|
||||
if (!itemAdded)
|
||||
{
|
||||
Array.Resize<CollectionEntry>(ref _items, _items.Length * 2);
|
||||
_lastItemIndex++;
|
||||
_items[_lastItemIndex].NewTarget(tag, value);
|
||||
}
|
||||
|
||||
_optimisticCount++;
|
||||
}
|
||||
}
|
||||
|
||||
internal T FindItem<T>(int tag, Func<T, bool> filterMethod) where T : class
|
||||
{
|
||||
bool lockObtained = false;
|
||||
try
|
||||
{
|
||||
TryEnterItemLock(ref lockObtained);
|
||||
if (lockObtained)
|
||||
{
|
||||
if (_optimisticCount > 0)
|
||||
{
|
||||
// Loop through the items
|
||||
for (int counter = 0; counter <= _lastItemIndex; counter++)
|
||||
{
|
||||
// Check tag (should be easiest and quickest)
|
||||
if (_items[counter].Tag == tag)
|
||||
{
|
||||
// NOTE: Check if the returned value is null twice may seem wasteful, but this if for performance
|
||||
// Since checking for null twice is cheaper than calling both HasTarget and Target OR always attempting to typecast
|
||||
object value = _items[counter].Target;
|
||||
if (value != null)
|
||||
{
|
||||
// Make sure the item has the correct type and passes the filtering
|
||||
T tempItem = value as T;
|
||||
if ((tempItem != null) && (filterMethod(tempItem)))
|
||||
{
|
||||
return tempItem;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
ExitItemLockIfNeeded(lockObtained);
|
||||
}
|
||||
|
||||
// If we got to here, then no item was found, so return null
|
||||
return null;
|
||||
}
|
||||
|
||||
public void Notify(int message)
|
||||
{
|
||||
bool lockObtained = false;
|
||||
try
|
||||
{
|
||||
TryEnterItemLock(ref lockObtained);
|
||||
if (lockObtained)
|
||||
{
|
||||
try
|
||||
{
|
||||
_isNotifying = true;
|
||||
|
||||
// Loop through each live item and notify it
|
||||
if (_optimisticCount > 0)
|
||||
{
|
||||
for (int index = 0; index <= _lastItemIndex; ++index)
|
||||
{
|
||||
object value = _items[index].Target; // checks tag & gets target
|
||||
if (null != value)
|
||||
{
|
||||
NotifyItem(message, _items[index].Tag, value);
|
||||
_items[index].RemoveTarget();
|
||||
}
|
||||
Debug.Assert(!_items[index].HasTarget, "Unexpected target after notifying");
|
||||
}
|
||||
_optimisticCount = 0;
|
||||
}
|
||||
|
||||
// Shrink collection (if needed)
|
||||
if (_items.Length > 100)
|
||||
{
|
||||
_lastItemIndex = 0;
|
||||
_items = new CollectionEntry[DefaultCollectionSize];
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
_isNotifying = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
ExitItemLockIfNeeded(lockObtained);
|
||||
}
|
||||
}
|
||||
|
||||
abstract protected void NotifyItem(int message, int tag, object value);
|
||||
|
||||
abstract public void Remove(object value);
|
||||
|
||||
protected void RemoveItem(object value)
|
||||
{
|
||||
Debug.Assert(null != value, "RemoveItem with null");
|
||||
|
||||
bool lockObtained = false;
|
||||
try
|
||||
{
|
||||
TryEnterItemLock(ref lockObtained);
|
||||
|
||||
if (lockObtained)
|
||||
{
|
||||
// Find the value, and then remove the target from our collection
|
||||
if (_optimisticCount > 0)
|
||||
{
|
||||
for (int index = 0; index <= _lastItemIndex; ++index)
|
||||
{
|
||||
if (value == _items[index].Target)
|
||||
{ // checks tag & gets target
|
||||
_items[index].RemoveTarget();
|
||||
_optimisticCount--;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
ExitItemLockIfNeeded(lockObtained);
|
||||
}
|
||||
}
|
||||
|
||||
// This is polling lock that will abandon getting the lock if _isNotifying is set to true
|
||||
private void TryEnterItemLock(ref bool lockObtained)
|
||||
{
|
||||
// Assume that we couldn't take the lock
|
||||
lockObtained = false;
|
||||
// Keep trying to take the lock until either we've taken it, or the collection is being notified
|
||||
while ((!_isNotifying) && (!lockObtained))
|
||||
{
|
||||
Monitor.TryEnter(_itemLock, LockPollTime, ref lockObtained);
|
||||
}
|
||||
}
|
||||
|
||||
private void ExitItemLockIfNeeded(bool lockObtained)
|
||||
{
|
||||
if (lockObtained)
|
||||
{
|
||||
Monitor.Exit(_itemLock);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user