Imported Upstream version 4.8.0.309

Former-commit-id: 5f9c6ae75f295e057a7d2971f3a6df4656fa8850
This commit is contained in:
Xamarin Public Jenkins (auto-signing)
2016-11-10 13:04:39 +00:00
parent ee1447783b
commit 94b2861243
4912 changed files with 390737 additions and 49310 deletions

View File

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

View File

@@ -1 +1 @@
cb0c072a6596823dda1c71424cf7f7567719a28b
44d81f07e1ef51520c0677f750ff35d1e6774efc

View File

@@ -1 +1 @@
637816ef0c379f684e5e1133aca1e168b9896e41
24673fa5c5120d868cf61c9ab74da5abe2261022

View File

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

View File

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

View File

@@ -1 +1 @@
2e560dbf344a2a5ef4577863f3342dc13d2498de
46a53537089cdd872b7c8964bfc4fc8718f9c782

View File

@@ -1 +1 @@
0ce4dbb08763054308721ed6139b428134b0cb54
306a42079800e4f74776c8f8f967a9df88f0c8f5

View File

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

View File

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

View File

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

View File

@@ -1 +1 @@
c07b195ac1ba68e64a6342f0c03bbc6e4bc32456
376909b9abd7bd6b626018dfbe5b83b5a12940c2

View File

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

View File

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

View File

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

View File

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