You've already forked linux-packaging-mono
Imported Upstream version 4.8.0.309
Former-commit-id: 5f9c6ae75f295e057a7d2971f3a6df4656fa8850
This commit is contained in:
parent
ee1447783b
commit
94b2861243
@@ -323,6 +323,143 @@ namespace System.Data.Common {
|
||||
}
|
||||
}
|
||||
|
||||
#region <<PoolBlockingPeriod Utility>>
|
||||
const string PoolBlockingPeriodAutoString = "Auto";
|
||||
const string PoolBlockingPeriodAlwaysBlockString = "AlwaysBlock";
|
||||
const string PoolBlockingPeriodNeverBlockString = "NeverBlock";
|
||||
|
||||
internal static bool TryConvertToPoolBlockingPeriod(string value, out PoolBlockingPeriod result)
|
||||
{
|
||||
Debug.Assert(Enum.GetNames(typeof(PoolBlockingPeriod)).Length == 3, "PoolBlockingPeriod enum has changed, update needed");
|
||||
Debug.Assert(null != value, "TryConvertToPoolBlockingPeriod(null,...)");
|
||||
|
||||
if (StringComparer.OrdinalIgnoreCase.Equals(value, PoolBlockingPeriodAutoString))
|
||||
{
|
||||
result = PoolBlockingPeriod.Auto;
|
||||
return true;
|
||||
}
|
||||
else if (StringComparer.OrdinalIgnoreCase.Equals(value, PoolBlockingPeriodAlwaysBlockString))
|
||||
{
|
||||
result = PoolBlockingPeriod.AlwaysBlock;
|
||||
return true;
|
||||
}
|
||||
else if (StringComparer.OrdinalIgnoreCase.Equals(value, PoolBlockingPeriodNeverBlockString))
|
||||
{
|
||||
result = PoolBlockingPeriod.NeverBlock;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
result = DbConnectionStringDefaults.PoolBlockingPeriod;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
internal static bool IsValidPoolBlockingPeriodValue(PoolBlockingPeriod value)
|
||||
{
|
||||
Debug.Assert(Enum.GetNames(typeof(PoolBlockingPeriod)).Length == 3, "PoolBlockingPeriod enum has changed, update needed");
|
||||
return value == PoolBlockingPeriod.Auto || value == PoolBlockingPeriod.AlwaysBlock || value == PoolBlockingPeriod.NeverBlock;
|
||||
}
|
||||
|
||||
internal static string PoolBlockingPeriodToString(PoolBlockingPeriod value)
|
||||
{
|
||||
Debug.Assert(IsValidPoolBlockingPeriodValue(value));
|
||||
|
||||
if (value == PoolBlockingPeriod.AlwaysBlock)
|
||||
{
|
||||
return PoolBlockingPeriodAlwaysBlockString;
|
||||
}
|
||||
if (value == PoolBlockingPeriod.NeverBlock)
|
||||
{
|
||||
return PoolBlockingPeriodNeverBlockString;
|
||||
}
|
||||
else
|
||||
{
|
||||
return PoolBlockingPeriodAutoString;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This method attempts to convert the given value to a PoolBlockingPeriod enum. The algorithm is:
|
||||
/// * if the value is from type string, it will be matched against PoolBlockingPeriod enum names only, using ordinal, case-insensitive comparer
|
||||
/// * if the value is from type PoolBlockingPeriod, it will be used as is
|
||||
/// * if the value is from integral type (SByte, Int16, Int32, Int64, Byte, UInt16, UInt32, or UInt64), it will be converted to enum
|
||||
/// * if the value is another enum or any other type, it will be blocked with an appropriate ArgumentException
|
||||
///
|
||||
/// in any case above, if the conerted value is out of valid range, the method raises ArgumentOutOfRangeException.
|
||||
/// </summary>
|
||||
/// <returns>PoolBlockingPeriod value in the valid range</returns>
|
||||
internal static PoolBlockingPeriod ConvertToPoolBlockingPeriod(string keyword, object value)
|
||||
{
|
||||
Debug.Assert(null != value, "ConvertToPoolBlockingPeriod(null)");
|
||||
string sValue = (value as string);
|
||||
PoolBlockingPeriod result;
|
||||
if (null != sValue)
|
||||
{
|
||||
// We could use Enum.TryParse<PoolBlockingPeriod> here, but it accepts value combinations like
|
||||
// "ReadOnly, ReadWrite" which are unwelcome here
|
||||
// Also, Enum.TryParse is 100x slower than plain StringComparer.OrdinalIgnoreCase.Equals method.
|
||||
|
||||
if (TryConvertToPoolBlockingPeriod(sValue, out result))
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
// try again after remove leading & trailing whitespaces.
|
||||
sValue = sValue.Trim();
|
||||
if (TryConvertToPoolBlockingPeriod(sValue, out result))
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
// string values must be valid
|
||||
throw ADP.InvalidConnectionOptionValue(keyword);
|
||||
}
|
||||
else
|
||||
{
|
||||
// the value is not string, try other options
|
||||
PoolBlockingPeriod eValue;
|
||||
|
||||
if (value is PoolBlockingPeriod)
|
||||
{
|
||||
// quick path for the most common case
|
||||
eValue = (PoolBlockingPeriod)value;
|
||||
}
|
||||
else if (value.GetType().IsEnum)
|
||||
{
|
||||
// explicitly block scenarios in which user tries to use wrong enum types, like:
|
||||
// builder["PoolBlockingPeriod"] = EnvironmentVariableTarget.Process;
|
||||
// workaround: explicitly cast non-PoolBlockingPeriod enums to int
|
||||
throw ADP.ConvertFailed(value.GetType(), typeof(PoolBlockingPeriod), null);
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
// Enum.ToObject allows only integral and enum values (enums are blocked above), rasing ArgumentException for the rest
|
||||
eValue = (PoolBlockingPeriod)Enum.ToObject(typeof(PoolBlockingPeriod), value);
|
||||
}
|
||||
catch (ArgumentException e)
|
||||
{
|
||||
// to be consistent with the messages we send in case of wrong type usage, replace
|
||||
// the error with our exception, and keep the original one as inner one for troubleshooting
|
||||
throw ADP.ConvertFailed(value.GetType(), typeof(PoolBlockingPeriod), e);
|
||||
}
|
||||
}
|
||||
|
||||
// ensure value is in valid range
|
||||
if (IsValidPoolBlockingPeriodValue(eValue))
|
||||
{
|
||||
return eValue;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw ADP.InvalidEnumerationValue(typeof(ApplicationIntent), (int)eValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
const string ApplicationIntentReadWriteString = "ReadWrite";
|
||||
const string ApplicationIntentReadOnlyString = "ReadOnly";
|
||||
|
||||
@@ -752,6 +889,7 @@ namespace System.Data.Common {
|
||||
internal const int ConnectRetryInterval = 10;
|
||||
internal static readonly SqlAuthenticationMethod Authentication = SqlAuthenticationMethod.NotSpecified;
|
||||
internal static readonly SqlConnectionColumnEncryptionSetting ColumnEncryptionSetting = SqlConnectionColumnEncryptionSetting.Disabled;
|
||||
internal const PoolBlockingPeriod PoolBlockingPeriod = SqlClient.PoolBlockingPeriod.Auto;
|
||||
}
|
||||
|
||||
internal static class DbConnectionOptionKeywords {
|
||||
@@ -819,6 +957,7 @@ namespace System.Data.Common {
|
||||
internal const string Authentication = "Authentication";
|
||||
internal const string Certificate = "Certificate";
|
||||
internal const string ColumnEncryptionSetting = "Column Encryption Setting";
|
||||
internal const string PoolBlockingPeriod = "PoolBlockingPeriod";
|
||||
|
||||
// common keywords (OleDb, OracleClient, SqlClient)
|
||||
internal const string DataSource = "Data Source";
|
||||
|
@@ -1 +1 @@
|
||||
cb0c072a6596823dda1c71424cf7f7567719a28b
|
||||
44d81f07e1ef51520c0677f750ff35d1e6774efc
|
@@ -1 +1 @@
|
||||
637816ef0c379f684e5e1133aca1e168b9896e41
|
||||
24673fa5c5120d868cf61c9ab74da5abe2261022
|
@@ -12,6 +12,7 @@ namespace System.Data.ProviderBase {
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Data.Common;
|
||||
using System.Data.SqlClient;
|
||||
using System.Diagnostics;
|
||||
using System.Globalization;
|
||||
using System.Runtime.CompilerServices;
|
||||
@@ -756,7 +757,81 @@ namespace System.Data.ProviderBase {
|
||||
private Timer CreateCleanupTimer() {
|
||||
return (new Timer(new TimerCallback(this.CleanupCallback), null, _cleanupWait, _cleanupWait));
|
||||
}
|
||||
|
||||
|
||||
private static readonly string[] AzureSqlServerEndpoints = {Res.GetString(Res.AZURESQL_GenericEndpoint),
|
||||
Res.GetString(Res.AZURESQL_GermanEndpoint),
|
||||
Res.GetString(Res.AZURESQL_UsGovEndpoint),
|
||||
Res.GetString(Res.AZURESQL_ChinaEndpoint) };
|
||||
private static bool IsAzureSqlServerEndpoint(string dataSource)
|
||||
{
|
||||
// remove server port
|
||||
var i = dataSource.LastIndexOf(',');
|
||||
if (i >= 0)
|
||||
{
|
||||
dataSource = dataSource.Substring(0, i);
|
||||
}
|
||||
|
||||
// check for the instance name
|
||||
i = dataSource.LastIndexOf('\\');
|
||||
if (i >= 0)
|
||||
{
|
||||
dataSource = dataSource.Substring(0, i);
|
||||
}
|
||||
|
||||
// trim redundant whitespaces
|
||||
dataSource = dataSource.Trim();
|
||||
|
||||
// check if servername end with any azure endpoints
|
||||
for (i = 0; i < AzureSqlServerEndpoints.Length; i++)
|
||||
{
|
||||
if (dataSource.EndsWith(AzureSqlServerEndpoints[i], StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private bool IsBlockingPeriodEnabled()
|
||||
{
|
||||
var poolGroupConnectionOptions = _connectionPoolGroup.ConnectionOptions as SqlConnectionString;
|
||||
if (poolGroupConnectionOptions == null)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
var policy = poolGroupConnectionOptions.PoolBlockingPeriod;
|
||||
|
||||
switch (policy)
|
||||
{
|
||||
case PoolBlockingPeriod.Auto:
|
||||
{
|
||||
if (IsAzureSqlServerEndpoint(poolGroupConnectionOptions.DataSource))
|
||||
{
|
||||
return false; // in Azure it will be Disabled
|
||||
}
|
||||
else
|
||||
{
|
||||
return true; // in Non Azure, it will be Enabled
|
||||
}
|
||||
}
|
||||
case PoolBlockingPeriod.AlwaysBlock:
|
||||
{
|
||||
return true; //Enabled
|
||||
}
|
||||
case PoolBlockingPeriod.NeverBlock:
|
||||
{
|
||||
return false; //Disabled
|
||||
}
|
||||
default:
|
||||
{
|
||||
//we should never get into this path.
|
||||
Debug.Fail("Unknown PoolBlockingPeriod. Please specify explicit results in above switch case statement.");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private DbConnectionInternal CreateObject(DbConnection owningObject, DbConnectionOptions userOptions, DbConnectionInternal oldConnection) {
|
||||
DbConnectionInternal newObj = null;
|
||||
|
||||
@@ -797,7 +872,7 @@ namespace System.Data.ProviderBase {
|
||||
// Reset the error wait:
|
||||
_errorWait = ERROR_WAIT_DEFAULT;
|
||||
}
|
||||
catch(Exception e) {
|
||||
catch(Exception e) {
|
||||
//
|
||||
if (!ADP.IsCatchableExceptionType(e)) {
|
||||
throw;
|
||||
@@ -805,6 +880,11 @@ namespace System.Data.ProviderBase {
|
||||
|
||||
ADP.TraceExceptionForCapture(e);
|
||||
|
||||
if (!IsBlockingPeriodEnabled())
|
||||
{
|
||||
throw;
|
||||
}
|
||||
|
||||
newObj = null; // set to null, so we do not return bad new object
|
||||
// Failed to create instance
|
||||
_resError = e;
|
||||
|
@@ -15,10 +15,9 @@ namespace System.Data.SqlClient
|
||||
/// Base class containing raw key bytes for symmetric key algorithms. Some encryption algorithms can use the key directly while others derive sub keys from this.
|
||||
/// If an algorithm needs to derive more keys, have a derived class from this and use it in the corresponding encryption algorithm.
|
||||
/// </summary>
|
||||
internal class SqlClientSymmetricKey
|
||||
{
|
||||
internal class SqlClientSymmetricKey {
|
||||
/// <summary>
|
||||
/// DPAPI protected key
|
||||
/// The underlying key material
|
||||
/// </summary>
|
||||
protected readonly byte[] _rootKey;
|
||||
|
||||
@@ -26,8 +25,7 @@ namespace System.Data.SqlClient
|
||||
/// Constructor that initializes the root key.
|
||||
/// </summary>
|
||||
/// <param name="rootKey">root key</param>
|
||||
internal SqlClientSymmetricKey(byte[] rootKey)
|
||||
{
|
||||
internal SqlClientSymmetricKey(byte[] rootKey) {
|
||||
// Key validation
|
||||
if (rootKey == null || rootKey.Length == 0) {
|
||||
throw SQL.NullColumnEncryptionKeySysErr();
|
||||
@@ -36,14 +34,24 @@ namespace System.Data.SqlClient
|
||||
_rootKey = rootKey;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Destructor that cleans up the key material.
|
||||
/// This is a best effort approach since there are no guarantees around GC.
|
||||
/// </summary>
|
||||
~SqlClientSymmetricKey() {
|
||||
if (_rootKey != null) {
|
||||
for (int i = 0; i < _rootKey.Length; i++) {
|
||||
_rootKey[i] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a copy of the plain text key
|
||||
/// This is needed for actual encryption/decryption.
|
||||
/// </summary>
|
||||
internal virtual byte[] RootKey
|
||||
{
|
||||
get
|
||||
{
|
||||
internal virtual byte[] RootKey {
|
||||
get {
|
||||
return _rootKey;
|
||||
}
|
||||
}
|
||||
@@ -52,8 +60,7 @@ namespace System.Data.SqlClient
|
||||
/// Computes SHA256 value of the plain text key bytes
|
||||
/// </summary>
|
||||
/// <returns>A string containing SHA256 hash of the root key</returns>
|
||||
internal virtual string GetKeyHash()
|
||||
{
|
||||
internal virtual string GetKeyHash() {
|
||||
return SqlSecurityUtility.GetSHA256Hash(RootKey);
|
||||
}
|
||||
|
||||
@@ -63,10 +70,7 @@ namespace System.Data.SqlClient
|
||||
/// <returns>
|
||||
/// Returns the length of the root key
|
||||
/// </returns>
|
||||
internal virtual int Length()
|
||||
{
|
||||
// Note: DPAPI preserves the original byte length
|
||||
// so for now, this is as same as returning the length of the raw key.
|
||||
internal virtual int Length() {
|
||||
return _rootKey.Length;
|
||||
}
|
||||
}
|
||||
|
@@ -1 +1 @@
|
||||
2e560dbf344a2a5ef4577863f3342dc13d2498de
|
||||
46a53537089cdd872b7c8964bfc4fc8718f9c782
|
@@ -1 +1 @@
|
||||
0ce4dbb08763054308721ed6139b428134b0cb54
|
||||
306a42079800e4f74776c8f8f967a9df88f0c8f5
|
@@ -30,6 +30,7 @@ namespace System.Data.SqlClient {
|
||||
internal const string Application_Name = TdsEnums.SQL_PROVIDER_NAME;
|
||||
internal const bool Asynchronous = false;
|
||||
internal const string AttachDBFilename = "";
|
||||
internal const PoolBlockingPeriod PoolBlockingPeriod = DbConnectionStringDefaults.PoolBlockingPeriod;
|
||||
internal const int Connect_Timeout = ADP.DefaultConnectionTimeout;
|
||||
internal const bool Connection_Reset = true;
|
||||
internal const bool Context_Connection = false;
|
||||
@@ -69,6 +70,7 @@ namespace System.Data.SqlClient {
|
||||
internal const string Application_Name = "application name";
|
||||
internal const string AsynchronousProcessing = "asynchronous processing";
|
||||
internal const string AttachDBFilename = "attachdbfilename";
|
||||
internal const string PoolBlockingPeriod = "poolblockingperiod";
|
||||
internal const string ColumnEncryptionSetting = "column encryption setting";
|
||||
internal const string Connect_Timeout = "connect timeout";
|
||||
internal const string Connection_Reset = "connection reset";
|
||||
@@ -190,6 +192,7 @@ namespace System.Data.SqlClient {
|
||||
|
||||
private readonly bool _integratedSecurity;
|
||||
|
||||
private readonly PoolBlockingPeriod _poolBlockingPeriod;
|
||||
private readonly bool _connectionReset;
|
||||
private readonly bool _contextConnection;
|
||||
private readonly bool _encrypt;
|
||||
@@ -247,6 +250,7 @@ namespace System.Data.SqlClient {
|
||||
ConvertValueToBoolean(KEY.AsynchronousProcessing, DEFAULT.Asynchronous); // while we don't use it anymore, we still need to verify it is true/false
|
||||
|
||||
// SQLPT 41700: Ignore ResetConnection=False (still validate the keyword/value)
|
||||
_poolBlockingPeriod = ConvertValueToPoolBlockingPeriod();
|
||||
_connectionReset = ConvertValueToBoolean(KEY.Connection_Reset, DEFAULT.Connection_Reset);
|
||||
_contextConnection = ConvertValueToBoolean(KEY.Context_Connection, DEFAULT.Context_Connection);
|
||||
_encrypt = ConvertValueToEncrypt();
|
||||
@@ -490,6 +494,7 @@ namespace System.Data.SqlClient {
|
||||
_userInstance = userInstance;
|
||||
_connectTimeout = connectionOptions._connectTimeout;
|
||||
_loadBalanceTimeout = connectionOptions._loadBalanceTimeout;
|
||||
_poolBlockingPeriod = connectionOptions._poolBlockingPeriod;
|
||||
_maxPoolSize = connectionOptions._maxPoolSize;
|
||||
_minPoolSize = connectionOptions._minPoolSize;
|
||||
_multiSubnetFailover = connectionOptions._multiSubnetFailover;
|
||||
@@ -525,6 +530,8 @@ namespace System.Data.SqlClient {
|
||||
// will work. In the future we can deprecate the keyword entirely.
|
||||
internal bool Asynchronous { get { return true; } }
|
||||
|
||||
internal PoolBlockingPeriod PoolBlockingPeriod { get { return _poolBlockingPeriod; } }
|
||||
|
||||
// SQLPT 41700: Ignore ResetConnection=False, always reset the connection for security
|
||||
internal bool ConnectionReset { get { return true; } }
|
||||
internal bool ContextConnection { get { return _contextConnection; } }
|
||||
@@ -620,6 +627,7 @@ namespace System.Data.SqlClient {
|
||||
hash.Add(KEY.Application_Name, KEY.Application_Name);
|
||||
hash.Add(KEY.AsynchronousProcessing, KEY.AsynchronousProcessing);
|
||||
hash.Add(KEY.AttachDBFilename, KEY.AttachDBFilename);
|
||||
hash.Add(KEY.PoolBlockingPeriod, KEY.PoolBlockingPeriod);
|
||||
hash.Add(KEY.Connect_Timeout, KEY.Connect_Timeout);
|
||||
hash.Add(KEY.Connection_Reset, KEY.Connection_Reset);
|
||||
hash.Add(KEY.Context_Connection, KEY.Context_Connection);
|
||||
@@ -779,6 +787,28 @@ namespace System.Data.SqlClient {
|
||||
// ArgumentException and other types are raised as is (no wrapping)
|
||||
}
|
||||
|
||||
internal System.Data.SqlClient.PoolBlockingPeriod ConvertValueToPoolBlockingPeriod()
|
||||
{
|
||||
object value = base.Parsetable[KEY.PoolBlockingPeriod];
|
||||
if (value == null)
|
||||
{
|
||||
return DEFAULT.PoolBlockingPeriod;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
return DbConnectionStringBuilderUtil.ConvertToPoolBlockingPeriod(KEY.PoolBlockingPeriod, value);
|
||||
}
|
||||
catch (FormatException e)
|
||||
{
|
||||
throw ADP.InvalidConnectionOptionValue(KEY.PoolBlockingPeriod, e);
|
||||
}
|
||||
catch (OverflowException e)
|
||||
{
|
||||
throw ADP.InvalidConnectionOptionValue(KEY.PoolBlockingPeriod, e);
|
||||
}
|
||||
}
|
||||
|
||||
internal SqlAuthenticationMethod ConvertValueToAuthenticationType() {
|
||||
object value = base.Parsetable[KEY.Authentication];
|
||||
|
||||
|
@@ -41,6 +41,7 @@ namespace System.Data.SqlClient {
|
||||
Pooling,
|
||||
MinPoolSize,
|
||||
MaxPoolSize,
|
||||
PoolBlockingPeriod,
|
||||
|
||||
AsynchronousProcessing,
|
||||
ConnectionReset,
|
||||
@@ -127,6 +128,7 @@ namespace System.Data.SqlClient {
|
||||
private bool _userInstance = DbConnectionStringDefaults.UserInstance;
|
||||
private SqlAuthenticationMethod _authentication = DbConnectionStringDefaults.Authentication;
|
||||
private SqlConnectionColumnEncryptionSetting _columnEncryptionSetting = DbConnectionStringDefaults.ColumnEncryptionSetting;
|
||||
private PoolBlockingPeriod _poolBlockingPeriod = DbConnectionStringDefaults.PoolBlockingPeriod;
|
||||
|
||||
static SqlConnectionStringBuilder() {
|
||||
string[] validKeywords = new string[KeywordsCount];
|
||||
@@ -134,6 +136,7 @@ namespace System.Data.SqlClient {
|
||||
validKeywords[(int)Keywords.ApplicationName] = DbConnectionStringKeywords.ApplicationName;
|
||||
validKeywords[(int)Keywords.AsynchronousProcessing] = DbConnectionStringKeywords.AsynchronousProcessing;
|
||||
validKeywords[(int)Keywords.AttachDBFilename] = DbConnectionStringKeywords.AttachDBFilename;
|
||||
validKeywords[(int)Keywords.PoolBlockingPeriod] = DbConnectionStringKeywords.PoolBlockingPeriod;
|
||||
validKeywords[(int)Keywords.ConnectionReset] = DbConnectionStringKeywords.ConnectionReset;
|
||||
validKeywords[(int)Keywords.ContextConnection] = DbConnectionStringKeywords.ContextConnection;
|
||||
validKeywords[(int)Keywords.ConnectTimeout] = DbConnectionStringKeywords.ConnectTimeout;
|
||||
@@ -174,6 +177,7 @@ namespace System.Data.SqlClient {
|
||||
hash.Add(DbConnectionStringKeywords.ApplicationName, Keywords.ApplicationName);
|
||||
hash.Add(DbConnectionStringKeywords.AsynchronousProcessing, Keywords.AsynchronousProcessing);
|
||||
hash.Add(DbConnectionStringKeywords.AttachDBFilename, Keywords.AttachDBFilename);
|
||||
hash.Add(DbConnectionStringKeywords.PoolBlockingPeriod, Keywords.PoolBlockingPeriod);
|
||||
hash.Add(DbConnectionStringKeywords.ConnectTimeout, Keywords.ConnectTimeout);
|
||||
hash.Add(DbConnectionStringKeywords.ConnectionReset, Keywords.ConnectionReset);
|
||||
hash.Add(DbConnectionStringKeywords.ContextConnection, Keywords.ContextConnection);
|
||||
@@ -278,6 +282,7 @@ namespace System.Data.SqlClient {
|
||||
case Keywords.Authentication: Authentication = ConvertToAuthenticationType(keyword, value); break;
|
||||
case Keywords.ColumnEncryptionSetting: ColumnEncryptionSetting = ConvertToColumnEncryptionSetting(keyword, value); break;
|
||||
case Keywords.AsynchronousProcessing: AsynchronousProcessing = ConvertToBoolean(value); break;
|
||||
case Keywords.PoolBlockingPeriod: PoolBlockingPeriod = ConvertToPoolBlockingPeriod(keyword, value); break;
|
||||
#pragma warning disable 618 // Obsolete ConnectionReset
|
||||
case Keywords.ConnectionReset: ConnectionReset = ConvertToBoolean(value); break;
|
||||
#pragma warning restore 618
|
||||
@@ -360,6 +365,25 @@ namespace System.Data.SqlClient {
|
||||
}
|
||||
}
|
||||
|
||||
[DisplayName(DbConnectionStringKeywords.PoolBlockingPeriod)]
|
||||
[ResCategoryAttribute(Res.DataCategory_Pooling)]
|
||||
[ResDescriptionAttribute(Res.DbConnectionString_PoolBlockingPeriod)]
|
||||
[RefreshPropertiesAttribute(RefreshProperties.All)]
|
||||
public PoolBlockingPeriod PoolBlockingPeriod
|
||||
{
|
||||
get { return _poolBlockingPeriod; }
|
||||
set
|
||||
{
|
||||
if (!DbConnectionStringBuilderUtil.IsValidPoolBlockingPeriodValue(value))
|
||||
{
|
||||
throw ADP.InvalidEnumerationValue(typeof(PoolBlockingPeriod), (int)value);
|
||||
}
|
||||
|
||||
SetPoolBlockingPeriodValue(value);
|
||||
_poolBlockingPeriod = value;
|
||||
}
|
||||
}
|
||||
|
||||
[Browsable(false)]
|
||||
[DisplayName(DbConnectionStringKeywords.ConnectionReset)]
|
||||
[Obsolete("ConnectionReset has been deprecated. SqlConnection will ignore the 'connection reset' keyword and always reset the connection")] // SQLPT 41700
|
||||
@@ -881,6 +905,10 @@ namespace System.Data.SqlClient {
|
||||
private static SqlAuthenticationMethod ConvertToAuthenticationType(string keyword, object value) {
|
||||
return DbConnectionStringBuilderUtil.ConvertToAuthenticationType(keyword, value);
|
||||
}
|
||||
private static PoolBlockingPeriod ConvertToPoolBlockingPeriod(string keyword, object value)
|
||||
{
|
||||
return DbConnectionStringBuilderUtil.ConvertToPoolBlockingPeriod(keyword, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Convert to SqlConnectionColumnEncryptionSetting.
|
||||
@@ -906,6 +934,7 @@ namespace System.Data.SqlClient {
|
||||
case Keywords.ApplicationName: return ApplicationName;
|
||||
case Keywords.AsynchronousProcessing: return AsynchronousProcessing;
|
||||
case Keywords.AttachDBFilename: return AttachDBFilename;
|
||||
case Keywords.PoolBlockingPeriod: return PoolBlockingPeriod;
|
||||
case Keywords.ConnectTimeout: return ConnectTimeout;
|
||||
#pragma warning disable 618 // Obsolete ConnectionReset
|
||||
case Keywords.ConnectionReset: return ConnectionReset;
|
||||
@@ -1012,6 +1041,10 @@ namespace System.Data.SqlClient {
|
||||
case Keywords.Authentication:
|
||||
_authentication = DbConnectionStringDefaults.Authentication;
|
||||
break;
|
||||
case Keywords.PoolBlockingPeriod:
|
||||
_poolBlockingPeriod = DbConnectionStringDefaults.PoolBlockingPeriod;
|
||||
break;
|
||||
|
||||
case Keywords.ConnectTimeout:
|
||||
_connectTimeout = DbConnectionStringDefaults.ConnectTimeout;
|
||||
break;
|
||||
@@ -1128,6 +1161,11 @@ namespace System.Data.SqlClient {
|
||||
Debug.Assert(DbConnectionStringBuilderUtil.IsValidApplicationIntentValue(value), "Invalid value for ApplicationIntent");
|
||||
base[DbConnectionStringKeywords.ApplicationIntent] = DbConnectionStringBuilderUtil.ApplicationIntentToString(value);
|
||||
}
|
||||
private void SetPoolBlockingPeriodValue(PoolBlockingPeriod value)
|
||||
{
|
||||
Debug.Assert(DbConnectionStringBuilderUtil.IsValidPoolBlockingPeriodValue(value), "Invalid value for PoolBlockingPeriod");
|
||||
base[DbConnectionStringKeywords.PoolBlockingPeriod] = DbConnectionStringBuilderUtil.PoolBlockingPeriodToString(value);
|
||||
}
|
||||
private void SetAuthenticationValue(SqlAuthenticationMethod value) {
|
||||
Debug.Assert(DbConnectionStringBuilderUtil.IsValidAuthenticationTypeValue(value), "Invalid value for AuthenticationType");
|
||||
base[DbConnectionStringKeywords.Authentication] = DbConnectionStringBuilderUtil.AuthenticationTypeToString(value);
|
||||
|
@@ -207,10 +207,10 @@ namespace System.Data.SqlClient
|
||||
durationString = null;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
// This message is to be added only when within the various stages of a connection.
|
||||
// In all other cases, it will default to the original error message.
|
||||
if ((currentPhase != SqlConnectionTimeoutErrorPhase.Undefined) || (currentPhase != SqlConnectionTimeoutErrorPhase.Complete))
|
||||
if ((currentPhase != SqlConnectionTimeoutErrorPhase.Undefined) && (currentPhase != SqlConnectionTimeoutErrorPhase.Complete))
|
||||
{
|
||||
// NOTE: In case of a failover scenario, add a string that this failure occured as part of the primary or secondary server
|
||||
if (isFailoverScenario)
|
||||
@@ -229,13 +229,13 @@ namespace System.Data.SqlClient
|
||||
originalPhaseDurations[(int)SqlConnectionTimeoutErrorPhase.ProcessConnectionAuth].GetMilliSecondDuration(),
|
||||
originalPhaseDurations[(int)SqlConnectionTimeoutErrorPhase.PostLogin].GetMilliSecondDuration());
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE: To display duration in each phase.
|
||||
if (durationString != null)
|
||||
{
|
||||
errorBuilder.Append(" ");
|
||||
errorBuilder.Append(durationString);
|
||||
}
|
||||
// NOTE: To display duration in each phase.
|
||||
if (durationString != null)
|
||||
{
|
||||
errorBuilder.Append(" ");
|
||||
errorBuilder.Append(durationString);
|
||||
}
|
||||
|
||||
return errorBuilder.ToString();
|
||||
|
@@ -1 +1 @@
|
||||
c07b195ac1ba68e64a6342f0c03bbc6e4bc32456
|
||||
376909b9abd7bd6b626018dfbe5b83b5a12940c2
|
@@ -99,9 +99,6 @@ namespace System.Data.SqlClient {
|
||||
}
|
||||
|
||||
set {
|
||||
Debug.Assert(_columnEncryptionCipherMetadata == null || value == null,
|
||||
"_columnEncryptionCipherMetadata should be set to a non-null value only once.");
|
||||
|
||||
_columnEncryptionCipherMetadata = value;
|
||||
}
|
||||
}
|
||||
|
@@ -13,18 +13,19 @@ namespace System.Data.SqlClient {
|
||||
using System.Diagnostics;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Runtime.Caching;
|
||||
using System.Text;
|
||||
|
||||
/// <summary>
|
||||
/// <para> Implements a cache of Symmetric Keys (once they are decrypted).Useful for rapidly decrypting multiple data values.</para>
|
||||
/// </summary>
|
||||
sealed internal class SqlSymmetricKeyCache {
|
||||
private readonly ConcurrentDictionary<string,SqlClientSymmetricKey> _cache;
|
||||
private readonly MemoryCache _cache;
|
||||
private static readonly SqlSymmetricKeyCache _singletonInstance = new SqlSymmetricKeyCache();
|
||||
|
||||
|
||||
private SqlSymmetricKeyCache () {
|
||||
_cache = new ConcurrentDictionary<string, SqlClientSymmetricKey>(concurrencyLevel: 4 * Environment.ProcessorCount /* default value in ConcurrentDictionary*/, capacity: 2);
|
||||
_cache = new MemoryCache("ColumnEncryptionKeyCache");
|
||||
}
|
||||
|
||||
internal static SqlSymmetricKeyCache GetInstance () {
|
||||
@@ -54,10 +55,10 @@ namespace System.Data.SqlClient {
|
||||
Debug.Assert(cacheLookupKey.Length <= capacity, "We needed to allocate a larger array");
|
||||
#endif //DEBUG
|
||||
|
||||
encryptionKey = null;
|
||||
|
||||
// Lookup the key in cache
|
||||
if (!_cache.TryGetValue(cacheLookupKey, out encryptionKey)) {
|
||||
encryptionKey = _cache.Get(cacheLookupKey) as SqlClientSymmetricKey;
|
||||
|
||||
if (encryptionKey == null) {
|
||||
Debug.Assert(SqlConnection.ColumnEncryptionTrustedMasterKeyPaths != null, @"SqlConnection.ColumnEncryptionTrustedMasterKeyPaths should not be null");
|
||||
|
||||
// Check against the trusted key paths
|
||||
@@ -96,9 +97,13 @@ namespace System.Data.SqlClient {
|
||||
|
||||
encryptionKey = new SqlClientSymmetricKey (plaintextKey);
|
||||
|
||||
// In case multiple threads reach here at the same time, the first one wins.
|
||||
// The allocated memory will be reclaimed by Garbage Collector.
|
||||
_cache.TryAdd(cacheLookupKey, encryptionKey);
|
||||
// If the cache TTL is zero, don't even bother inserting to the cache.
|
||||
if (SqlConnection.ColumnEncryptionKeyCacheTtl != TimeSpan.Zero) {
|
||||
// In case multiple threads reach here at the same time, the first one wins.
|
||||
// The allocated memory will be reclaimed by Garbage Collector.
|
||||
DateTimeOffset expirationTime = DateTimeOffset.UtcNow.Add(SqlConnection.ColumnEncryptionKeyCacheTtl);
|
||||
_cache.Add(cacheLookupKey, encryptionKey, expirationTime);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@@ -1543,7 +1543,7 @@ namespace System.Data.SqlClient {
|
||||
return Res.GetString(Res.SQL_SSPIGenerateError);
|
||||
}
|
||||
static internal string Timeout() {
|
||||
return Res.GetString(Res.SQL_Timeout);
|
||||
return Res.GetString(Res.SQL_Timeout_Execution);
|
||||
}
|
||||
static internal string Timeout_PreLogin_Begin() {
|
||||
return Res.GetString(Res.SQL_Timeout_PreLogin_Begin);
|
||||
|
@@ -544,6 +544,9 @@ namespace System.Data.SqlClient {
|
||||
public const int IMPERSONATION_FAILED = 1346;
|
||||
public const int P_TOKENTOOLONG = 103;
|
||||
|
||||
// SQL error that indicates retry for Always Encrypted
|
||||
public const int TCE_CONVERSION_ERROR_CLIENT_RETRY = 33514;
|
||||
|
||||
// SNI\Win32 error values
|
||||
// NOTE: these are simply windows system error codes, not SNI specific
|
||||
public const uint SNI_UNINITIALIZED = unchecked((uint)-1);
|
||||
|
Reference in New Issue
Block a user