diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj
index 7e64b8fd9e..91ac3e6fee 100644
--- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj
+++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj
@@ -55,6 +55,9 @@
Microsoft\Data\Common\NameValuePair.cs
+
+ Microsoft\Data\Common\DbConnectionOptions.Common.cs
+
Microsoft\Data\SqlClient\DataClassification\SensitivityClassification.cs
@@ -438,9 +441,6 @@
-
- Microsoft\Data\Common\DbConnectionOptions.Common.cs
-
Common\Microsoft\Data\ProviderBase\DbConnectionInternal.cs
diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/Common/DbConnectionOptions.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/Common/DbConnectionOptions.cs
index c90bb1f3bf..35440e9e11 100644
--- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/Common/DbConnectionOptions.cs
+++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/Common/DbConnectionOptions.cs
@@ -3,8 +3,6 @@
// See the LICENSE file in the project root for more information.
using System;
-using System.Collections.Generic;
-using System.Globalization;
using System.IO;
using System.Text;
@@ -12,104 +10,25 @@ namespace Microsoft.Data.Common
{
internal partial class DbConnectionOptions
{
- // instances of this class are intended to be immutable, i.e readonly
- // used by pooling classes so it is much easier to verify correctness
- // when not worried about the class being modified during execution
-
- public DbConnectionOptions(string connectionString, Dictionary synonyms)
- {
- _parsetable = new Dictionary();
- _usersConnectionString = ((null != connectionString) ? connectionString : "");
-
- // first pass on parsing, initial syntax check
- if (0 < _usersConnectionString.Length)
- {
- _keyChain = ParseInternal(_parsetable, _usersConnectionString, true, synonyms, false);
- HasPasswordKeyword = (_parsetable.ContainsKey(KEY.Password) || _parsetable.ContainsKey(SYNONYM.Pwd));
- HasUserIdKeyword = (_parsetable.ContainsKey(KEY.User_ID) || _parsetable.ContainsKey(SYNONYM.UID));
- }
- }
-
- protected DbConnectionOptions(DbConnectionOptions connectionOptions)
- { // Clone used by SqlConnectionString
- _usersConnectionString = connectionOptions._usersConnectionString;
- _parsetable = connectionOptions._parsetable;
- _keyChain = connectionOptions._keyChain;
- HasPasswordKeyword = connectionOptions.HasPasswordKeyword;
- HasUserIdKeyword = connectionOptions.HasUserIdKeyword;
- }
-
- public bool IsEmpty => _keyChain == null;
-
- internal bool TryGetParsetableValue(string key, out string value) => _parsetable.TryGetValue(key, out value);
-
- // same as Boolean, but with SSPI thrown in as valid yes
- public bool ConvertValueToIntegratedSecurity()
+ internal string ExpandAttachDbFileName(string replacementValue)
{
- string value;
- return _parsetable.TryGetValue(KEY.Integrated_Security, out value) && value != null ?
- ConvertValueToIntegratedSecurityInternal(value) :
- false;
- }
+ int copyPosition = 0;
- internal bool ConvertValueToIntegratedSecurityInternal(string stringValue)
- {
- if (CompareInsensitiveInvariant(stringValue, "sspi") || CompareInsensitiveInvariant(stringValue, "true") || CompareInsensitiveInvariant(stringValue, "yes"))
- return true;
- else if (CompareInsensitiveInvariant(stringValue, "false") || CompareInsensitiveInvariant(stringValue, "no"))
- return false;
- else
+ StringBuilder builder = new(_usersConnectionString.Length);
+ for (NameValuePair current = _keyChain; null != current; current = current.Next)
{
- string tmp = stringValue.Trim(); // Remove leading & trailing whitespace.
- if (CompareInsensitiveInvariant(tmp, "sspi") || CompareInsensitiveInvariant(tmp, "true") || CompareInsensitiveInvariant(tmp, "yes"))
- return true;
- else if (CompareInsensitiveInvariant(tmp, "false") || CompareInsensitiveInvariant(tmp, "no"))
- return false;
+ if (string.Equals(current.Name, DbConnectionStringKeywords.AttachDBFilename, StringComparison.InvariantCultureIgnoreCase))
+ {
+ builder.Append($"{current.Name}={replacementValue};");
+ }
else
{
- throw ADP.InvalidConnectionOptionValue(KEY.Integrated_Security);
+ builder.Append(_usersConnectionString, copyPosition, current.Length);
}
+ copyPosition += current.Length;
}
- }
-
- public int ConvertValueToInt32(string keyName, int defaultValue)
- {
- string value;
- return _parsetable.TryGetValue(keyName, out value) && value != null ?
- ConvertToInt32Internal(keyName, value) :
- defaultValue;
- }
-
- internal static int ConvertToInt32Internal(string keyname, string stringValue)
- {
- try
- {
- return int.Parse(stringValue, System.Globalization.NumberStyles.Integer, CultureInfo.InvariantCulture);
- }
- catch (FormatException e)
- {
- throw ADP.InvalidConnectionOptionValue(keyname, e);
- }
- catch (OverflowException e)
- {
- throw ADP.InvalidConnectionOptionValue(keyname, e);
- }
- }
- public string ConvertValueToString(string keyName, string defaultValue)
- {
- string value;
- return _parsetable.TryGetValue(keyName, out value) && value != null ? value : defaultValue;
- }
-
- public bool ContainsKey(string keyword)
- {
- return _parsetable.ContainsKey(keyword);
- }
-
- protected internal virtual string Expand()
- {
- return _usersConnectionString;
+ return builder.ToString();
}
// SxS notes:
@@ -151,25 +70,5 @@ internal static string ExpandDataDirectory(string keyword, string value)
return fullPath;
}
- internal string ExpandAttachDbFileName(string replacementValue)
- {
- int copyPosition = 0;
-
- StringBuilder builder = new StringBuilder(_usersConnectionString.Length);
- for (NameValuePair current = _keyChain; null != current; current = current.Next)
- {
- if (current.Name == KEY.AttachDBFileName)
- {
- builder.Append($"{KEY.AttachDBFileName}={replacementValue};");
- }
- else
- {
- builder.Append(_usersConnectionString, copyPosition, current.Length);
- }
- copyPosition += current.Length;
- }
-
- return builder.ToString();
- }
}
}
diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlConnection.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlConnection.cs
index abad0809cb..3946a09f33 100644
--- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlConnection.cs
+++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlConnection.cs
@@ -1820,7 +1820,7 @@ private bool TryOpen(TaskCompletionSource retry, SqlConnec
(connectionOptions.Authentication == SqlAuthenticationMethod.SqlPassword ||
connectionOptions.Authentication == SqlAuthenticationMethod.ActiveDirectoryPassword ||
connectionOptions.Authentication == SqlAuthenticationMethod.ActiveDirectoryServicePrincipal) &&
- (!connectionOptions.HasUserIdKeyword || !connectionOptions.HasPasswordKeyword) &&
+ (!connectionOptions._hasUserIdKeyword || !connectionOptions._hasPasswordKeyword) &&
_credential == null)
{
throw SQL.CredentialsNotProvided(connectionOptions.Authentication);
diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlConnectionString.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlConnectionString.cs
index 819d796312..598367b0a0 100644
--- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlConnectionString.cs
+++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlConnectionString.cs
@@ -456,32 +456,32 @@ internal SqlConnectionString(string connectionString) : base(connectionString, G
throw SQL.AuthenticationAndIntegratedSecurity();
}
- if (Authentication == SqlClient.SqlAuthenticationMethod.ActiveDirectoryIntegrated && HasPasswordKeyword)
+ if (Authentication == SqlClient.SqlAuthenticationMethod.ActiveDirectoryIntegrated && _hasPasswordKeyword)
{
throw SQL.IntegratedWithPassword();
}
- if (Authentication == SqlAuthenticationMethod.ActiveDirectoryInteractive && HasPasswordKeyword)
+ if (Authentication == SqlAuthenticationMethod.ActiveDirectoryInteractive && _hasPasswordKeyword)
{
throw SQL.InteractiveWithPassword();
}
- if (Authentication == SqlAuthenticationMethod.ActiveDirectoryDeviceCodeFlow && (HasUserIdKeyword || HasPasswordKeyword))
+ if (Authentication == SqlAuthenticationMethod.ActiveDirectoryDeviceCodeFlow && (_hasUserIdKeyword || _hasPasswordKeyword))
{
throw SQL.DeviceFlowWithUsernamePassword();
}
- if (Authentication == SqlAuthenticationMethod.ActiveDirectoryManagedIdentity && HasPasswordKeyword)
+ if (Authentication == SqlAuthenticationMethod.ActiveDirectoryManagedIdentity && _hasPasswordKeyword)
{
throw SQL.NonInteractiveWithPassword(DbConnectionStringBuilderUtil.ActiveDirectoryManagedIdentityString);
}
- if (Authentication == SqlAuthenticationMethod.ActiveDirectoryMSI && HasPasswordKeyword)
+ if (Authentication == SqlAuthenticationMethod.ActiveDirectoryMSI && _hasPasswordKeyword)
{
throw SQL.NonInteractiveWithPassword(DbConnectionStringBuilderUtil.ActiveDirectoryMSIString);
}
- if (Authentication == SqlAuthenticationMethod.ActiveDirectoryDefault && HasPasswordKeyword)
+ if (Authentication == SqlAuthenticationMethod.ActiveDirectoryDefault && _hasPasswordKeyword)
{
throw SQL.NonInteractiveWithPassword(DbConnectionStringBuilderUtil.ActiveDirectoryDefaultString);
}
diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlInternalConnectionTds.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlInternalConnectionTds.cs
index d46baf18e2..9b85ced97f 100644
--- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlInternalConnectionTds.cs
+++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlInternalConnectionTds.cs
@@ -2117,7 +2117,7 @@ internal void OnLoginAck(SqlLoginAck rec)
/// Federated Authentication Info.
internal void OnFedAuthInfo(SqlFedAuthInfo fedAuthInfo)
{
- Debug.Assert((ConnectionOptions.HasUserIdKeyword && ConnectionOptions.HasPasswordKeyword)
+ Debug.Assert((ConnectionOptions._hasUserIdKeyword && ConnectionOptions._hasPasswordKeyword)
|| _credential != null
|| ConnectionOptions.Authentication == SqlAuthenticationMethod.ActiveDirectoryInteractive
|| ConnectionOptions.Authentication == SqlAuthenticationMethod.ActiveDirectoryDeviceCodeFlow
diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj
index ae61c39607..9a5615c00c 100644
--- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj
+++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj
@@ -110,6 +110,9 @@
Microsoft\Data\Common\NameValuePair.cs
+
+ Microsoft\Data\Common\DbConnectionOptions.Common.cs
+
Microsoft\Data\Sql\SqlNotificationRequest.cs
diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/Common/DBConnectionString.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/Common/DBConnectionString.cs
index c51f4f2730..57391584d2 100644
--- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/Common/DBConnectionString.cs
+++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/Common/DBConnectionString.cs
@@ -23,16 +23,16 @@ internal sealed class DBConnectionString
private static class KEY
{
- internal const string Password = "password";
- internal const string PersistSecurityInfo = "persist security info";
- internal const string Pwd = "pwd";
+ internal const string Password = DbConnectionStringKeywords.Password;
+ internal const string PersistSecurityInfo = DbConnectionStringKeywords.PersistSecurityInfo;
+ internal const string Pwd = DbConnectionStringSynonyms.Pwd;
};
// this class is serializable with Everett, so ugly field names can't be changed
readonly private string _encryptedUsersConnectionString;
// hash of unique keys to values
- readonly private Hashtable _parsetable;
+ readonly private Dictionary _parsetable;
// a linked list of key/value and their length in _encryptedUsersConnectionString
readonly private NameValuePair _keychain;
@@ -52,21 +52,21 @@ private static class KEY
readonly private string _encryptedActualConnectionString;
#pragma warning restore 169
- internal DBConnectionString(string value, string restrictions, KeyRestrictionBehavior behavior, Hashtable synonyms, bool useOdbcRules)
- : this(new DbConnectionOptions(value, synonyms, useOdbcRules), restrictions, behavior, synonyms, false)
+ internal DBConnectionString(string value, string restrictions, KeyRestrictionBehavior behavior, Dictionary synonyms, bool useOdbcRules)
+ : this(new DbConnectionOptions(value, synonyms), restrictions, behavior, synonyms, false)
{
// useOdbcRules is only used to parse the connection string, not to parse restrictions because values don't apply there
// the hashtable doesn't need clone since it isn't shared with anything else
}
internal DBConnectionString(DbConnectionOptions connectionOptions)
- : this(connectionOptions, (string)null, KeyRestrictionBehavior.AllowOnly, (Hashtable)null, true)
+ : this(connectionOptions, (string)null, KeyRestrictionBehavior.AllowOnly, null, true)
{
// used by DBDataPermission to convert from DbConnectionOptions to DBConnectionString
// since backward compatibility requires Everett level classes
}
- private DBConnectionString(DbConnectionOptions connectionOptions, string restrictions, KeyRestrictionBehavior behavior, Hashtable synonyms, bool mustCloneDictionary)
+ private DBConnectionString(DbConnectionOptions connectionOptions, string restrictions, KeyRestrictionBehavior behavior, Dictionary synonyms, bool mustCloneDictionary)
{ // used by DBDataPermission
Debug.Assert(null != connectionOptions, "null connectionOptions");
switch (behavior)
@@ -81,9 +81,9 @@ private DBConnectionString(DbConnectionOptions connectionOptions, string restric
// grab all the parsed details from DbConnectionOptions
_encryptedUsersConnectionString = connectionOptions.UsersConnectionString(false);
- _hasPassword = connectionOptions.HasPasswordKeyword;
+ _hasPassword = connectionOptions._hasPasswordKeyword;
_parsetable = connectionOptions.Parsetable;
- _keychain = connectionOptions.KeyChain;
+ _keychain = connectionOptions._keyChain;
// we do not want to serialize out user password unless directed so by "persist security info=true"
// otherwise all instances of user's password will be replaced with "*"
@@ -94,7 +94,7 @@ private DBConnectionString(DbConnectionOptions connectionOptions, string restric
{
// clone the hashtable to replace user's password/pwd value with "*"
// we only need to clone if coming from DbConnectionOptions and password exists
- _parsetable = (Hashtable)_parsetable.Clone();
+ _parsetable = new Dictionary(_parsetable, _parsetable.Comparer);
}
// different than Everett in that instead of removing password/pwd from
@@ -467,7 +467,7 @@ static private string[] NoDuplicateUnion(string[] a, string[] b)
return restrictionValues;
}
- private static string[] ParseRestrictions(string restrictions, Hashtable synonyms)
+ private static string[] ParseRestrictions(string restrictions, Dictionary synonyms)
{
#if DEBUG
SqlClientEventSource.Log.TryAdvancedTraceEvent(" Restrictions='{0}'", restrictions);
diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/Common/DbConnectionOptions.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/Common/DbConnectionOptions.cs
index 07431834fb..364f256fdc 100644
--- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/Common/DbConnectionOptions.cs
+++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/Common/DbConnectionOptions.cs
@@ -2,183 +2,28 @@
// 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;
+using System.Runtime.Versioning;
+using System.Security;
+using System.Text;
+
namespace Microsoft.Data.Common
{
-
- using System;
- using System.Collections;
- using System.Diagnostics;
- using System.Globalization;
- using System.Runtime.Versioning;
- using System.Text;
- using System.Text.RegularExpressions;
- using Microsoft.Data.SqlClient;
-
- internal class DbConnectionOptions
+ internal partial class DbConnectionOptions
{
- // instances of this class are intended to be immutable, i.e readonly
- // used by pooling classes so it is much easier to verify correctness
- // when not worried about the class being modified during execution
-
-#if DEBUG
- /*private const string ConnectionStringPatternV1 =
- "[\\s;]*"
- +"(?([^=\\s]|\\s+[^=\\s]|\\s+==|==)+)"
- + "\\s*=(?!=)\\s*"
- +"(?("
- + "(" + "\"" + "([^\"]|\"\")*" + "\"" + ")"
- + "|"
- + "(" + "'" + "([^']|'')*" + "'" + ")"
- + "|"
- + "(" + "(?![\"'])" + "([^\\s;]|\\s+[^\\s;])*" + "(?([^=\\s\\p{Cc}]|\\s+[^=\\s\\p{Cc}]|\\s+==|==)+)" // allow any visible character for keyname except '=' which must quoted as '=='
- + "\\s*=(?!=)\\s*" // the equal sign divides the key and value parts
- + "(?"
- + "(\"([^\"\u0000]|\"\")*\")" // double quoted string, " must be quoted as ""
- + "|"
- + "('([^'\u0000]|'')*')" // single quoted string, ' must be quoted as ''
- + "|"
- + "((?![\"'\\s])" // unquoted value must not start with " or ' or space, would also like = but too late to change
- + "([^;\\s\\p{Cc}]|\\s+[^;\\s\\p{Cc}])*" // control characters must be quoted
- + "(?([^=\\s\\p{Cc}]|\\s+[^=\\s\\p{Cc}])+)" // allow any visible character for keyname except '='
- + "\\s*=\\s*" // the equal sign divides the key and value parts
- + "(?"
- + "(\\{([^\\}\u0000]|\\}\\})*\\})" // quoted string, starts with { and ends with }
- + "|"
- + "((?![\\{\\s])" // unquoted value must not start with { or space, would also like = but too late to change
- + "([^;\\s\\p{Cc}]|\\s+[^;\\s\\p{Cc}])*" // control characters must be quoted
-
- + ")" // VSTFDEVDIV 94761: although the spec does not allow {}
- // embedded within a value, the retail code does.
- // + "(? _parsetable[keyword];
- // known connection string common synonyms
- private static class SYNONYM
- {
- internal const string Pwd = "pwd";
- internal const string UID = "uid";
- };
-
- private readonly string _usersConnectionString;
- private readonly Hashtable _parsetable;
- internal readonly NameValuePair KeyChain;
- internal readonly bool HasPasswordKeyword;
- internal readonly bool HasUserIdKeyword;
-
- // differences between OleDb and Odbc
- // ODBC:
- // http://msdn.microsoft.com/library/default.asp?url=/library/en-us/odbc/htm/odbcsqldriverconnect.asp
- // http://msdn.microsoft.com/library/default.asp?url=/library/en-us/odbcsql/od_odbc_d_4x4k.asp
- // do not support == -> = in keywords
- // first key-value pair wins
- // quote values using \{ and \}, only driver= and pwd= appear to generically allow quoting
- // do not strip quotes from value, or add quotes except for driver keyword
- // OLEDB:
- // http://msdn.microsoft.com/library/default.asp?url=/library/en-us/oledb/htm/oledbconnectionstringsyntax.asp
- // support == -> = in keywords
- // last key-value pair wins
- // quote values using \" or \'
- // strip quotes from value
- internal readonly bool UseOdbcRules;
-
- private System.Security.PermissionSet _permissionset;
-
- // called by derived classes that may cache based on connectionString
- public DbConnectionOptions(string connectionString)
- : this(connectionString, null, false)
- {
- }
-
- // synonyms hashtable is meant to be read-only translation of parsed string
- // keywords/synonyms to a known keyword string
- public DbConnectionOptions(string connectionString, Hashtable synonyms, bool useOdbcRules)
- {
- UseOdbcRules = useOdbcRules;
- _parsetable = new Hashtable();
- _usersConnectionString = ((null != connectionString) ? connectionString : "");
+ private PermissionSet _permissionset;
- // first pass on parsing, initial syntax check
- if (0 < _usersConnectionString.Length)
- {
- KeyChain = ParseInternal(_parsetable, _usersConnectionString, true, synonyms, UseOdbcRules);
- HasPasswordKeyword = (_parsetable.ContainsKey(KEY.Password) || _parsetable.ContainsKey(SYNONYM.Pwd));
- HasUserIdKeyword = (_parsetable.ContainsKey(KEY.User_ID) || _parsetable.ContainsKey(SYNONYM.UID));
- }
- }
+ protected internal virtual PermissionSet CreatePermissionSet() => null;
- protected DbConnectionOptions(DbConnectionOptions connectionOptions)
- { // Clone used by SqlConnectionString
- _usersConnectionString = connectionOptions._usersConnectionString;
- HasPasswordKeyword = connectionOptions.HasPasswordKeyword;
- HasUserIdKeyword = connectionOptions.HasUserIdKeyword;
- UseOdbcRules = connectionOptions.UseOdbcRules;
- _parsetable = connectionOptions._parsetable;
- KeyChain = connectionOptions.KeyChain;
- }
-
-
- public string UsersConnectionString(bool hidePassword)
- {
- return UsersConnectionString(hidePassword, false);
- }
-
- private string UsersConnectionString(bool hidePassword, bool forceHidePassword)
+ internal void DemandPermission()
{
- string connectionString = _usersConnectionString;
- if (HasPasswordKeyword && (forceHidePassword || (hidePassword && !HasPersistablePassword)))
+ if (_permissionset is null)
{
- ReplacePasswordPwd(out connectionString, false);
+ _permissionset = CreatePermissionSet();
}
- return ((null != connectionString) ? connectionString : "");
- }
-
- internal string UsersConnectionStringForTrace()
- {
- return UsersConnectionString(true, true);
+ _permissionset.Demand();
}
internal bool HasBlankPassword
@@ -189,60 +34,61 @@ internal bool HasBlankPassword
{
if (_parsetable.ContainsKey(KEY.Password))
{
- return ADP.IsEmpty((string)_parsetable[KEY.Password]);
+ return ADP.IsEmpty(_parsetable[KEY.Password]);
}
else
if (_parsetable.ContainsKey(SYNONYM.Pwd))
{
- return ADP.IsEmpty((string)_parsetable[SYNONYM.Pwd]); // MDAC 83097
+ return ADP.IsEmpty(_parsetable[SYNONYM.Pwd]); // MDAC 83097
}
else
{
- return ((_parsetable.ContainsKey(KEY.User_ID) && !ADP.IsEmpty((string)_parsetable[KEY.User_ID])) || (_parsetable.ContainsKey(SYNONYM.UID) && !ADP.IsEmpty((string)_parsetable[SYNONYM.UID])));
+ return (_parsetable.ContainsKey(KEY.User_ID) && !ADP.IsEmpty(_parsetable[KEY.User_ID])) ||
+ (_parsetable.ContainsKey(SYNONYM.UID) && !ADP.IsEmpty(_parsetable[SYNONYM.UID]));
}
}
return false;
}
}
- internal bool HasPersistablePassword
+ internal string ExpandKeyword(string keyword, string replacementValue)
{
- get
+ // preserve duplicates, updated keyword value with replacement value
+ // if keyword not specified, append to end of the string
+ bool expanded = false;
+ int copyPosition = 0;
+
+ StringBuilder builder = new(_usersConnectionString.Length);
+ for (NameValuePair current = _keyChain; null != current; current = current.Next)
{
- if (HasPasswordKeyword)
+ if ((current.Name == keyword) && (current.Value == this[keyword]))
+ {
+ // only replace the parse end-result value instead of all values
+ // so that when duplicate-keywords occur other original values remain in place
+ AppendKeyValuePairBuilder(builder, current.Name, replacementValue);
+ builder.Append(';');
+ expanded = true;
+ }
+ else
{
- return ConvertValueToBoolean(KEY.Persist_Security_Info, false);
+ builder.Append(_usersConnectionString, copyPosition, current.Length);
}
- return true; // no password means persistable password so we don't have to munge
+ copyPosition += current.Length;
}
- }
-
- public bool IsEmpty
- {
- get { return (null == KeyChain); }
- }
-
- internal Hashtable Parsetable
- {
- get { return _parsetable; }
- }
-
- public ICollection Keys
- {
- get { return _parsetable.Keys; }
- }
- public string this[string keyword]
- {
- get { return (string)_parsetable[keyword]; }
+ if (!expanded)
+ {
+ AppendKeyValuePairBuilder(builder, keyword, replacementValue);
+ }
+ return builder.ToString();
}
- internal static void AppendKeyValuePairBuilder(StringBuilder builder, string keyName, string keyValue, bool useOdbcRules)
+ internal static void AppendKeyValuePairBuilder(StringBuilder builder, string keyName, string keyValue, bool useOdbcRules = false)
{
- ADP.CheckArgumentNull(builder, "builder");
- ADP.CheckArgumentLength(keyName, "keyName");
+ ADP.CheckArgumentNull(builder, nameof(builder));
+ ADP.CheckArgumentLength(keyName, nameof(keyName));
- if ((null == keyName) || !ConnectionStringValidKeyRegex.IsMatch(keyName))
+ if ((null == keyName) || !s_connectionStringValidKeyRegex.IsMatch(keyName))
{
throw ADP.InvalidKeyname(keyName);
}
@@ -271,8 +117,8 @@ internal static void AppendKeyValuePairBuilder(StringBuilder builder, string key
if (useOdbcRules)
{
if ((0 < keyValue.Length) &&
- (('{' == keyValue[0]) || (0 <= keyValue.IndexOf(';')) || (0 == String.Compare(DbConnectionStringKeywords.Driver, keyName, StringComparison.OrdinalIgnoreCase))) &&
- !ConnectionStringQuoteOdbcValueRegex.IsMatch(keyValue))
+ (('{' == keyValue[0]) || (0 <= keyValue.IndexOf(';')) || (0 == string.Compare(DbConnectionStringKeywords.Driver, keyName, StringComparison.OrdinalIgnoreCase))) &&
+ !s_connectionStringQuoteOdbcValueRegex.IsMatch(keyValue))
{
// always quote Driver value (required for ODBC Version 2.65 and earlier)
// always quote values that contain a ';'
@@ -283,7 +129,7 @@ internal static void AppendKeyValuePairBuilder(StringBuilder builder, string key
builder.Append(keyValue);
}
}
- else if (ConnectionStringQuoteValueRegex.IsMatch(keyValue))
+ else if (s_connectionStringQuoteValueRegex.IsMatch(keyValue))
{
// ->
builder.Append(keyValue);
@@ -310,128 +156,6 @@ internal static void AppendKeyValuePairBuilder(StringBuilder builder, string key
}
}
- public bool ConvertValueToBoolean(string keyName, bool defaultValue)
- {
- object value = _parsetable[keyName];
- if (null == value)
- {
- return defaultValue;
- }
- return ConvertValueToBooleanInternal(keyName, (string)value);
- }
-
- internal static bool ConvertValueToBooleanInternal(string keyName, string stringValue)
- {
- if (CompareInsensitiveInvariant(stringValue, "true") || CompareInsensitiveInvariant(stringValue, "yes"))
- return true;
- else if (CompareInsensitiveInvariant(stringValue, "false") || CompareInsensitiveInvariant(stringValue, "no"))
- return false;
- else
- {
- string tmp = stringValue.Trim(); // Remove leading & trailing white space.
- if (CompareInsensitiveInvariant(tmp, "true") || CompareInsensitiveInvariant(tmp, "yes"))
- return true;
- else if (CompareInsensitiveInvariant(tmp, "false") || CompareInsensitiveInvariant(tmp, "no"))
- return false;
- else
- {
- throw ADP.InvalidConnectionOptionValue(keyName);
- }
- }
- }
-
- // same as Boolean, but with SSPI thrown in as valid yes
- public bool ConvertValueToIntegratedSecurity()
- {
- object value = _parsetable[KEY.Integrated_Security];
- if (null == value)
- {
- return false;
- }
- return ConvertValueToIntegratedSecurityInternal((string)value);
- }
-
- internal bool ConvertValueToIntegratedSecurityInternal(string stringValue)
- {
- if (CompareInsensitiveInvariant(stringValue, "sspi") || CompareInsensitiveInvariant(stringValue, "true") || CompareInsensitiveInvariant(stringValue, "yes"))
- return true;
- else if (CompareInsensitiveInvariant(stringValue, "false") || CompareInsensitiveInvariant(stringValue, "no"))
- return false;
- else
- {
- string tmp = stringValue.Trim(); // Remove leading & trailing white space.
- if (CompareInsensitiveInvariant(tmp, "sspi") || CompareInsensitiveInvariant(tmp, "true") || CompareInsensitiveInvariant(tmp, "yes"))
- return true;
- else if (CompareInsensitiveInvariant(tmp, "false") || CompareInsensitiveInvariant(tmp, "no"))
- return false;
- else
- {
- throw ADP.InvalidConnectionOptionValue(KEY.Integrated_Security);
- }
- }
- }
-
- public int ConvertValueToInt32(string keyName, int defaultValue)
- {
- object value = _parsetable[keyName];
- if (null == value)
- {
- return defaultValue;
- }
- return ConvertToInt32Internal(keyName, (string)value);
- }
-
- internal static int ConvertToInt32Internal(string keyname, string stringValue)
- {
- try
- {
- return System.Int32.Parse(stringValue, System.Globalization.NumberStyles.Integer, CultureInfo.InvariantCulture);
- }
- catch (FormatException e)
- {
- throw ADP.InvalidConnectionOptionValue(keyname, e);
- }
- catch (OverflowException e)
- {
- throw ADP.InvalidConnectionOptionValue(keyname, e);
- }
- }
-
- public string ConvertValueToString(string keyName, string defaultValue)
- {
- string value = (string)_parsetable[keyName];
- return ((null != value) ? value : defaultValue);
- }
-
- static private bool CompareInsensitiveInvariant(string strvalue, string strconst)
- {
- return (0 == StringComparer.OrdinalIgnoreCase.Compare(strvalue, strconst));
- }
-
- public bool ContainsKey(string keyword)
- {
- return _parsetable.ContainsKey(keyword);
- }
-
- protected internal virtual System.Security.PermissionSet CreatePermissionSet()
- {
- return null;
- }
-
- internal void DemandPermission()
- {
- if (null == _permissionset)
- {
- _permissionset = CreatePermissionSet();
- }
- _permissionset.Demand();
- }
-
- protected internal virtual string Expand()
- {
- return _usersConnectionString;
- }
-
// SxS notes:
// * this method queries "DataDirectory" value from the current AppDomain.
// This string is used for to replace "!DataDirectory!" values in the connection string, it is not considered as an "exposed resource".
@@ -496,660 +220,5 @@ internal static string ExpandDataDirectory(string keyword, string value, ref str
}
return fullPath;
}
-
- internal string ExpandDataDirectories(ref string filename, ref int position)
- {
- string value = null;
- StringBuilder builder = new StringBuilder(_usersConnectionString.Length);
- string datadir = null;
-
- int copyPosition = 0;
- bool expanded = false;
-
- for (NameValuePair current = KeyChain; null != current; current = current.Next)
- {
- value = current.Value;
-
- // remove duplicate keyswords from connectionstring
- //if ((object)this[current.Name] != (object)value) {
- // expanded = true;
- // copyPosition += current.Length;
- // continue;
- //}
-
- // There is a set of keywords we explictly do NOT want to expand |DataDirectory| on
- if (UseOdbcRules)
- {
- switch (current.Name)
- {
- case DbConnectionOptionKeywords.Driver:
- case DbConnectionOptionKeywords.Pwd:
- case DbConnectionOptionKeywords.UID:
- break;
- default:
- value = ExpandDataDirectory(current.Name, value, ref datadir);
- break;
- }
- }
- else
- {
- switch (current.Name)
- {
- case DbConnectionOptionKeywords.Provider:
- case DbConnectionOptionKeywords.DataProvider:
- case DbConnectionOptionKeywords.RemoteProvider:
- case DbConnectionOptionKeywords.ExtendedProperties:
- case DbConnectionOptionKeywords.UserID:
- case DbConnectionOptionKeywords.Password:
- case DbConnectionOptionKeywords.UID:
- case DbConnectionOptionKeywords.Pwd:
- break;
- default:
- value = ExpandDataDirectory(current.Name, value, ref datadir);
- break;
- }
- }
- if (null == value)
- {
- value = current.Value;
- }
- if (UseOdbcRules || (DbConnectionOptionKeywords.FileName != current.Name))
- {
- if (value != current.Value)
- {
- expanded = true;
- AppendKeyValuePairBuilder(builder, current.Name, value, UseOdbcRules);
- builder.Append(';');
- }
- else
- {
- builder.Append(_usersConnectionString, copyPosition, current.Length);
- }
- }
- else
- {
- // strip out 'File Name=myconnection.udl' for OleDb
- // remembering is value for which UDL file to open
- // and where to insert the strnig
- expanded = true;
- filename = value;
- position = builder.Length;
- }
- copyPosition += current.Length;
- }
-
- if (expanded)
- {
- value = builder.ToString();
- }
- else
- {
- value = null;
- }
- return value;
- }
-
- internal string ExpandKeyword(string keyword, string replacementValue)
- {
- // preserve duplicates, updated keyword value with replacement value
- // if keyword not specified, append to end of the string
- bool expanded = false;
- int copyPosition = 0;
-
- StringBuilder builder = new StringBuilder(_usersConnectionString.Length);
- for (NameValuePair current = KeyChain; null != current; current = current.Next)
- {
- if ((current.Name == keyword) && (current.Value == this[keyword]))
- {
- // only replace the parse end-result value instead of all values
- // so that when duplicate-keywords occur other original values remain in place
- AppendKeyValuePairBuilder(builder, current.Name, replacementValue, UseOdbcRules);
- builder.Append(';');
- expanded = true;
- }
- else
- {
- builder.Append(_usersConnectionString, copyPosition, current.Length);
- }
- copyPosition += current.Length;
- }
-
- if (!expanded)
- {
- // TODO: technically for ODBC it should be prepended but not using the method from ODBC
- Debug.Assert(!UseOdbcRules, "ExpandKeyword not ready for Odbc");
- AppendKeyValuePairBuilder(builder, keyword, replacementValue, UseOdbcRules);
- }
- return builder.ToString();
- }
-
-#if DEBUG
- [System.Diagnostics.Conditional("DEBUG")]
- private static void DebugTraceKeyValuePair(string keyname, string keyvalue, Hashtable synonyms)
- {
- if (SqlClientEventSource.Log.IsAdvancedTraceOn())
- {
- Debug.Assert(keyname == keyname.ToLower(CultureInfo.InvariantCulture), "missing ToLower");
- string realkeyname = ((null != synonyms) ? (string)synonyms[keyname] : keyname);
-
- if ((KEY.Password != realkeyname) && (SYNONYM.Pwd != realkeyname))
- {
- // don't trace passwords ever!
- if (null != keyvalue)
- {
- SqlClientEventSource.Log.AdvancedTraceEvent(" KeyName='{0}', KeyValue='{1}'", keyname, keyvalue);
- }
- else
- {
- SqlClientEventSource.Log.TryAdvancedTraceEvent(" KeyName='{0}'", keyname);
- }
- }
- }
- }
-#endif
-
- static private string GetKeyName(StringBuilder buffer)
- {
- int count = buffer.Length;
- while ((0 < count) && Char.IsWhiteSpace(buffer[count - 1]))
- {
- count--; // trailing whitespace
- }
- return buffer.ToString(0, count).ToLower(CultureInfo.InvariantCulture);
- }
-
- static private string GetKeyValue(StringBuilder buffer, bool trimWhitespace)
- {
- int count = buffer.Length;
- int index = 0;
- if (trimWhitespace)
- {
- while ((index < count) && Char.IsWhiteSpace(buffer[index]))
- {
- index++; // leading whitespace
- }
- while ((0 < count) && Char.IsWhiteSpace(buffer[count - 1]))
- {
- count--; // trailing whitespace
- }
- }
- return buffer.ToString(index, count - index);
- }
-
- // transition states used for parsing
- private enum ParserState
- {
- NothingYet = 1, //start point
- Key,
- KeyEqual,
- KeyEnd,
- UnquotedValue,
- DoubleQuoteValue,
- DoubleQuoteValueQuote,
- SingleQuoteValue,
- SingleQuoteValueQuote,
- BraceQuoteValue,
- BraceQuoteValueQuote,
- QuotedValueEnd,
- NullTermination,
- };
-
- static internal int GetKeyValuePair(string connectionString, int currentPosition, StringBuilder buffer, bool useOdbcRules, out string keyname, out string keyvalue)
- {
- int startposition = currentPosition;
-
- buffer.Length = 0;
- keyname = null;
- keyvalue = null;
-
- char currentChar = '\0';
-
- ParserState parserState = ParserState.NothingYet;
- int length = connectionString.Length;
- for (; currentPosition < length; ++currentPosition)
- {
- currentChar = connectionString[currentPosition];
-
- switch (parserState)
- {
- case ParserState.NothingYet: // [\\s;]*
- if ((';' == currentChar) || Char.IsWhiteSpace(currentChar))
- {
- continue;
- }
- if ('\0' == currentChar)
- { parserState = ParserState.NullTermination; continue; } // MDAC 83540
- if (Char.IsControl(currentChar))
- { throw ADP.ConnectionStringSyntax(startposition); }
- startposition = currentPosition;
- if ('=' != currentChar)
- { // MDAC 86902
- parserState = ParserState.Key;
- break;
- }
- else
- {
- parserState = ParserState.KeyEqual;
- continue;
- }
-
- case ParserState.Key: // (?([^=\\s\\p{Cc}]|\\s+[^=\\s\\p{Cc}]|\\s+==|==)+)
- if ('=' == currentChar)
- { parserState = ParserState.KeyEqual; continue; }
- if (Char.IsWhiteSpace(currentChar))
- { break; }
- if (Char.IsControl(currentChar))
- { throw ADP.ConnectionStringSyntax(startposition); }
- break;
-
- case ParserState.KeyEqual: // \\s*=(?!=)\\s*
- if (!useOdbcRules && '=' == currentChar)
- { parserState = ParserState.Key; break; }
- keyname = GetKeyName(buffer);
- if (ADP.IsEmpty(keyname))
- { throw ADP.ConnectionStringSyntax(startposition); }
- buffer.Length = 0;
- parserState = ParserState.KeyEnd;
- goto case ParserState.KeyEnd;
-
- case ParserState.KeyEnd:
- if (Char.IsWhiteSpace(currentChar))
- { continue; }
- if (useOdbcRules)
- {
- if ('{' == currentChar)
- { parserState = ParserState.BraceQuoteValue; break; }
- }
- else
- {
- if ('\'' == currentChar)
- { parserState = ParserState.SingleQuoteValue; continue; }
- if ('"' == currentChar)
- { parserState = ParserState.DoubleQuoteValue; continue; }
- }
- if (';' == currentChar)
- { goto ParserExit; }
- if ('\0' == currentChar)
- { goto ParserExit; }
- if (Char.IsControl(currentChar))
- { throw ADP.ConnectionStringSyntax(startposition); }
- parserState = ParserState.UnquotedValue;
- break;
-
- case ParserState.UnquotedValue: // "((?![\"'\\s])" + "([^;\\s\\p{Cc}]|\\s+[^;\\s\\p{Cc}])*" + "(?");
- Debug.Assert(value1 == value2, "ParseInternal code vs. regex mismatch keyvalue <" + value1 + "> <" + value2 + ">");
- }
-
- }
- catch (ArgumentException f)
- {
- if (null != e)
- {
- string msg1 = e.Message;
- string msg2 = f.Message;
-
- const string KeywordNotSupportedMessagePrefix = "Keyword not supported:";
- const string WrongFormatMessagePrefix = "Format of the initialization string";
- bool isEquivalent = (msg1 == msg2);
- if (!isEquivalent)
- {
- // VSTFDEVDIV 479587: we also accept cases were Regex parser (debug only) reports "wrong format" and
- // retail parsing code reports format exception in different location or "keyword not supported"
- if (msg2.StartsWith(WrongFormatMessagePrefix, StringComparison.Ordinal))
- {
- if (msg1.StartsWith(KeywordNotSupportedMessagePrefix, StringComparison.Ordinal) || msg1.StartsWith(WrongFormatMessagePrefix, StringComparison.Ordinal))
- {
- isEquivalent = true;
- }
- }
- }
- Debug.Assert(isEquivalent, "ParseInternal code vs regex message mismatch: <" + msg1 + "> <" + msg2 + ">");
- }
- else
- {
- Debug.Assert(false, "ParseInternal code vs regex throw mismatch " + f.Message);
- }
- e = null;
- }
- if (null != e)
- {
- Debug.Assert(false, "ParseInternal code threw exception vs regex mismatch");
- }
- }
-#endif
- private static NameValuePair ParseInternal(Hashtable parsetable, string connectionString, bool buildChain, Hashtable synonyms, bool firstKey)
- {
- Debug.Assert(null != connectionString, "null connectionstring");
- StringBuilder buffer = new StringBuilder();
- NameValuePair localKeychain = null, keychain = null;
-#if DEBUG
- try
- {
-#endif
- int nextStartPosition = 0;
- int endPosition = connectionString.Length;
- while (nextStartPosition < endPosition)
- {
- int startPosition = nextStartPosition;
-
- string keyname, keyvalue;
- nextStartPosition = GetKeyValuePair(connectionString, startPosition, buffer, firstKey, out keyname, out keyvalue);
- if (ADP.IsEmpty(keyname))
- {
- // if (nextStartPosition != endPosition) { throw; }
- break;
- }
-#if DEBUG
- DebugTraceKeyValuePair(keyname, keyvalue, synonyms);
-
- Debug.Assert(IsKeyNameValid(keyname), "ParseFailure, invalid keyname");
- Debug.Assert(IsValueValidInternal(keyvalue), "parse failure, invalid keyvalue");
-#endif
- string realkeyname = ((null != synonyms) ? (string)synonyms[keyname] : keyname);
- if (!IsKeyNameValid(realkeyname))
- {
- throw ADP.KeywordNotSupported(keyname);
- }
- if (!firstKey || !parsetable.Contains(realkeyname))
- {
- parsetable[realkeyname] = keyvalue; // last key-value pair wins (or first)
- }
-
- if (null != localKeychain)
- {
- localKeychain = localKeychain.Next = new NameValuePair(realkeyname, keyvalue, nextStartPosition - startPosition);
- }
- else if (buildChain)
- { // first time only - don't contain modified chain from UDL file
- keychain = localKeychain = new NameValuePair(realkeyname, keyvalue, nextStartPosition - startPosition);
- }
- }
-#if DEBUG
- }
- catch (ArgumentException e)
- {
- ParseComparison(parsetable, connectionString, synonyms, firstKey, e);
- throw;
- }
- ParseComparison(parsetable, connectionString, synonyms, firstKey, null);
-#endif
- return keychain;
- }
-
- internal NameValuePair ReplacePasswordPwd(out string constr, bool fakePassword)
- {
- bool expanded = false;
- int copyPosition = 0;
- NameValuePair head = null, tail = null, next = null;
- StringBuilder builder = new StringBuilder(_usersConnectionString.Length);
- for (NameValuePair current = KeyChain; null != current; current = current.Next)
- {
- if ((KEY.Password != current.Name) && (SYNONYM.Pwd != current.Name))
- {
- builder.Append(_usersConnectionString, copyPosition, current.Length);
- if (fakePassword)
- {
- next = new NameValuePair(current.Name, current.Value, current.Length);
- }
- }
- else if (fakePassword)
- { // replace user password/pwd value with *
- const string equalstar = "=*;";
- builder.Append(current.Name).Append(equalstar);
- next = new NameValuePair(current.Name, "*", current.Name.Length + equalstar.Length);
- expanded = true;
- }
- else
- { // drop the password/pwd completely in returning for user
- expanded = true;
- }
-
- if (fakePassword)
- {
- if (null != tail)
- {
- tail = tail.Next = next;
- }
- else
- {
- tail = head = next;
- }
- }
- copyPosition += current.Length;
- }
- Debug.Assert(expanded, "password/pwd was not removed");
- constr = builder.ToString();
- return head;
- }
-
- internal static void ValidateKeyValuePair(string keyword, string value)
- {
- if ((null == keyword) || !ConnectionStringValidKeyRegex.IsMatch(keyword))
- {
- throw ADP.InvalidKeyname(keyword);
- }
- if ((null != value) && !ConnectionStringValidValueRegex.IsMatch(value))
- {
- throw ADP.InvalidValue(keyword);
- }
- }
}
}
diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlConnection.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlConnection.cs
index a6e417f18f..919f8f2c4d 100644
--- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlConnection.cs
+++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlConnection.cs
@@ -2059,7 +2059,7 @@ private bool TryOpen(TaskCompletionSource retry, SqlConnec
(connectionOptions.Authentication == SqlAuthenticationMethod.SqlPassword ||
connectionOptions.Authentication == SqlAuthenticationMethod.ActiveDirectoryPassword ||
connectionOptions.Authentication == SqlAuthenticationMethod.ActiveDirectoryServicePrincipal) &&
- (!connectionOptions.HasUserIdKeyword || !connectionOptions.HasPasswordKeyword) &&
+ (!connectionOptions._hasUserIdKeyword || !connectionOptions._hasPasswordKeyword) &&
_credential == null)
{
throw SQL.CredentialsNotProvided(connectionOptions.Authentication);
diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlConnectionString.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlConnectionString.cs
index 7cde4cf58e..d62177ec09 100644
--- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlConnectionString.cs
+++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlConnectionString.cs
@@ -4,6 +4,7 @@
using System;
using System.Collections;
+using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Runtime.Versioning;
@@ -219,7 +220,7 @@ internal static class TRANSACIONBINDING
internal const string ExplicitUnbind = "Explicit Unbind";
}
- static private Hashtable _sqlClientSynonyms;
+ private static Dictionary s_sqlClientSynonyms;
static private Hashtable _netlibMapping;
private readonly bool _integratedSecurity;
@@ -281,7 +282,7 @@ internal static class TRANSACIONBINDING
// SxS: reading Software\\Microsoft\\MSSQLServer\\Client\\SuperSocketNetLib\Encrypt value from registry
[ResourceExposure(ResourceScope.None)]
[ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
- internal SqlConnectionString(string connectionString) : base(connectionString, GetParseSynonyms(), false)
+ internal SqlConnectionString(string connectionString) : base(connectionString, GetParseSynonyms())
{
bool runningInProc = InOutOfProcHelper.InProc;
@@ -352,10 +353,10 @@ internal SqlConnectionString(string connectionString) : base(connectionString, G
// When using a context connection, we need to ensure that no
// other connection string keywords are specified.
- foreach (DictionaryEntry entry in Parsetable)
+ foreach (KeyValuePair entry in Parsetable)
{
- if ((string)entry.Key != KEY.Context_Connection &&
- (string)entry.Key != KEY.Type_System_Version)
+ if (entry.Key != KEY.Context_Connection &&
+ entry.Key != KEY.Type_System_Version)
{
throw SQL.ContextAllowsLimitedKeywords();
}
@@ -555,32 +556,32 @@ internal SqlConnectionString(string connectionString) : base(connectionString, G
throw SQL.AuthenticationAndIntegratedSecurity();
}
- if (Authentication == SqlAuthenticationMethod.ActiveDirectoryIntegrated && (HasUserIdKeyword || HasPasswordKeyword))
+ if (Authentication == SqlAuthenticationMethod.ActiveDirectoryIntegrated && (_hasUserIdKeyword || _hasPasswordKeyword))
{
throw SQL.IntegratedWithUserIDAndPassword();
}
- if (Authentication == SqlAuthenticationMethod.ActiveDirectoryInteractive && (HasPasswordKeyword))
+ if (Authentication == SqlAuthenticationMethod.ActiveDirectoryInteractive && (_hasPasswordKeyword))
{
throw SQL.InteractiveWithPassword();
}
- if (Authentication == SqlAuthenticationMethod.ActiveDirectoryDeviceCodeFlow && (HasUserIdKeyword || HasPasswordKeyword))
+ if (Authentication == SqlAuthenticationMethod.ActiveDirectoryDeviceCodeFlow && (_hasUserIdKeyword || _hasPasswordKeyword))
{
throw SQL.DeviceFlowWithUsernamePassword();
}
- if (Authentication == SqlAuthenticationMethod.ActiveDirectoryManagedIdentity && HasPasswordKeyword)
+ if (Authentication == SqlAuthenticationMethod.ActiveDirectoryManagedIdentity && _hasPasswordKeyword)
{
throw SQL.NonInteractiveWithPassword(DbConnectionStringBuilderUtil.ActiveDirectoryManagedIdentityString);
}
- if (Authentication == SqlAuthenticationMethod.ActiveDirectoryMSI && HasPasswordKeyword)
+ if (Authentication == SqlAuthenticationMethod.ActiveDirectoryMSI && _hasPasswordKeyword)
{
throw SQL.NonInteractiveWithPassword(DbConnectionStringBuilderUtil.ActiveDirectoryMSIString);
}
- if (Authentication == SqlAuthenticationMethod.ActiveDirectoryDefault && HasPasswordKeyword)
+ if (Authentication == SqlAuthenticationMethod.ActiveDirectoryDefault && _hasPasswordKeyword)
{
throw SQL.NonInteractiveWithPassword(DbConnectionStringBuilderUtil.ActiveDirectoryDefaultString);
}
@@ -783,89 +784,91 @@ private static bool CompareHostName(ref string host, string name, bool fixup)
// this hashtable is meant to be read-only translation of parsed string
// keywords/synonyms to a known keyword string
- internal static Hashtable GetParseSynonyms()
+ internal static Dictionary GetParseSynonyms()
{
-
- Hashtable hash = _sqlClientSynonyms;
- if (null == hash)
+ Dictionary synonyms = s_sqlClientSynonyms;
+ if (synonyms is null)
{
- hash = new Hashtable(SqlConnectionStringBuilder.KeywordsCount + SynonymCount);
- hash.Add(KEY.ApplicationIntent, KEY.ApplicationIntent);
- hash.Add(KEY.Application_Name, KEY.Application_Name);
- hash.Add(KEY.AttachDBFilename, KEY.AttachDBFilename);
- hash.Add(KEY.PoolBlockingPeriod, KEY.PoolBlockingPeriod);
- hash.Add(KEY.Connect_Timeout, KEY.Connect_Timeout);
- hash.Add(KEY.Command_Timeout, KEY.Command_Timeout);
- hash.Add(KEY.Connection_Reset, KEY.Connection_Reset);
- hash.Add(KEY.Context_Connection, KEY.Context_Connection);
- hash.Add(KEY.Current_Language, KEY.Current_Language);
- hash.Add(KEY.Data_Source, KEY.Data_Source);
- hash.Add(KEY.Encrypt, KEY.Encrypt);
- hash.Add(KEY.Enlist, KEY.Enlist);
- hash.Add(KEY.FailoverPartner, KEY.FailoverPartner);
- hash.Add(KEY.Initial_Catalog, KEY.Initial_Catalog);
- hash.Add(KEY.Integrated_Security, KEY.Integrated_Security);
- hash.Add(KEY.Load_Balance_Timeout, KEY.Load_Balance_Timeout);
- hash.Add(KEY.MARS, KEY.MARS);
- hash.Add(KEY.Max_Pool_Size, KEY.Max_Pool_Size);
- hash.Add(KEY.Min_Pool_Size, KEY.Min_Pool_Size);
- hash.Add(KEY.MultiSubnetFailover, KEY.MultiSubnetFailover);
- hash.Add(KEY.TransparentNetworkIPResolution, KEY.TransparentNetworkIPResolution);
- hash.Add(KEY.Network_Library, KEY.Network_Library);
- hash.Add(KEY.Packet_Size, KEY.Packet_Size);
- hash.Add(KEY.Password, KEY.Password);
- hash.Add(KEY.Persist_Security_Info, KEY.Persist_Security_Info);
- hash.Add(KEY.Pooling, KEY.Pooling);
- hash.Add(KEY.Replication, KEY.Replication);
- hash.Add(KEY.TrustServerCertificate, KEY.TrustServerCertificate);
- hash.Add(KEY.TransactionBinding, KEY.TransactionBinding);
- hash.Add(KEY.Type_System_Version, KEY.Type_System_Version);
- hash.Add(KEY.ColumnEncryptionSetting, KEY.ColumnEncryptionSetting);
- hash.Add(KEY.EnclaveAttestationUrl, KEY.EnclaveAttestationUrl);
- hash.Add(KEY.AttestationProtocol, KEY.AttestationProtocol);
- hash.Add(KEY.User_ID, KEY.User_ID);
- hash.Add(KEY.User_Instance, KEY.User_Instance);
- hash.Add(KEY.Workstation_Id, KEY.Workstation_Id);
- hash.Add(KEY.Connect_Retry_Count, KEY.Connect_Retry_Count);
- hash.Add(KEY.Connect_Retry_Interval, KEY.Connect_Retry_Interval);
- hash.Add(KEY.Authentication, KEY.Authentication);
- hash.Add(KEY.IPAddressPreference, KEY.IPAddressPreference);
+ int count = SqlConnectionStringBuilder.KeywordsCount + SynonymCount;
+ synonyms = new Dictionary(count)
+ {
+ { KEY.ApplicationIntent, KEY.ApplicationIntent},
+ { KEY.Application_Name, KEY.Application_Name },
+ { KEY.AttachDBFilename, KEY.AttachDBFilename },
+ { KEY.PoolBlockingPeriod, KEY.PoolBlockingPeriod },
+ { KEY.Connect_Timeout, KEY.Connect_Timeout },
+ { KEY.Command_Timeout, KEY.Command_Timeout },
+ { KEY.Connection_Reset, KEY.Connection_Reset },
+ { KEY.Context_Connection, KEY.Context_Connection },
+ { KEY.Current_Language, KEY.Current_Language },
+ { KEY.Data_Source, KEY.Data_Source },
+ { KEY.Encrypt, KEY.Encrypt },
+ { KEY.Enlist, KEY.Enlist },
+ { KEY.FailoverPartner, KEY.FailoverPartner },
+ { KEY.Initial_Catalog, KEY.Initial_Catalog },
+ { KEY.Integrated_Security, KEY.Integrated_Security },
+ { KEY.Load_Balance_Timeout, KEY.Load_Balance_Timeout },
+ { KEY.MARS, KEY.MARS },
+ { KEY.Max_Pool_Size, KEY.Max_Pool_Size },
+ { KEY.Min_Pool_Size, KEY.Min_Pool_Size },
+ { KEY.MultiSubnetFailover, KEY.MultiSubnetFailover },
+ { KEY.TransparentNetworkIPResolution, KEY.TransparentNetworkIPResolution },
+ { KEY.Network_Library, KEY.Network_Library },
+ { KEY.Packet_Size, KEY.Packet_Size },
+ { KEY.Password, KEY.Password },
+ { KEY.Persist_Security_Info, KEY.Persist_Security_Info },
+ { KEY.Pooling, KEY.Pooling },
+ { KEY.Replication, KEY.Replication },
+ { KEY.TrustServerCertificate, KEY.TrustServerCertificate },
+ { KEY.TransactionBinding, KEY.TransactionBinding },
+ { KEY.Type_System_Version, KEY.Type_System_Version },
+ { KEY.ColumnEncryptionSetting, KEY.ColumnEncryptionSetting },
+ { KEY.EnclaveAttestationUrl, KEY.EnclaveAttestationUrl },
+ { KEY.AttestationProtocol, KEY.AttestationProtocol },
+ { KEY.User_ID, KEY.User_ID },
+ { KEY.User_Instance, KEY.User_Instance },
+ { KEY.Workstation_Id, KEY.Workstation_Id },
+ { KEY.Connect_Retry_Count, KEY.Connect_Retry_Count },
+ { KEY.Connect_Retry_Interval, KEY.Connect_Retry_Interval },
+ { KEY.Authentication, KEY.Authentication },
+ { KEY.IPAddressPreference, KEY.IPAddressPreference },
#if ADONET_CERT_AUTH
- hash.Add(KEY.Certificate, KEY.Certificate);
+ { KEY.Certificate, KEY.Certificate },
#endif
- hash.Add(SYNONYM.APPLICATIONINTENT, KEY.ApplicationIntent);
- hash.Add(SYNONYM.APP, KEY.Application_Name);
- hash.Add(SYNONYM.EXTENDED_PROPERTIES, KEY.AttachDBFilename);
- hash.Add(SYNONYM.INITIAL_FILE_NAME, KEY.AttachDBFilename);
- hash.Add(SYNONYM.CONNECTION_TIMEOUT, KEY.Connect_Timeout);
- hash.Add(SYNONYM.CONNECTRETRYCOUNT, KEY.Connect_Retry_Count);
- hash.Add(SYNONYM.CONNECTRETRYINTERVAL, KEY.Connect_Retry_Interval);
- hash.Add(SYNONYM.TIMEOUT, KEY.Connect_Timeout);
- hash.Add(SYNONYM.LANGUAGE, KEY.Current_Language);
- hash.Add(SYNONYM.ADDR, KEY.Data_Source);
- hash.Add(SYNONYM.ADDRESS, KEY.Data_Source);
- hash.Add(SYNONYM.MULTIPLEACTIVERESULTSETS, KEY.MARS);
- hash.Add(SYNONYM.MULTISUBNETFAILOVER, KEY.MultiSubnetFailover);
- hash.Add(SYNONYM.NETWORK_ADDRESS, KEY.Data_Source);
- hash.Add(SYNONYM.SERVER, KEY.Data_Source);
- hash.Add(SYNONYM.DATABASE, KEY.Initial_Catalog);
- hash.Add(SYNONYM.TRUSTED_CONNECTION, KEY.Integrated_Security);
- hash.Add(SYNONYM.Connection_Lifetime, KEY.Load_Balance_Timeout);
- hash.Add(SYNONYM.NET, KEY.Network_Library);
- hash.Add(SYNONYM.NETWORK, KEY.Network_Library);
- hash.Add(SYNONYM.Pwd, KEY.Password);
- hash.Add(SYNONYM.POOLBLOCKINGPERIOD, KEY.PoolBlockingPeriod);
- hash.Add(SYNONYM.PERSISTSECURITYINFO, KEY.Persist_Security_Info);
- hash.Add(SYNONYM.TRANSPARENTNETWORKIPRESOLUTION, KEY.TransparentNetworkIPResolution);
- hash.Add(SYNONYM.TRUSTSERVERCERTIFICATE, KEY.TrustServerCertificate);
- hash.Add(SYNONYM.UID, KEY.User_ID);
- hash.Add(SYNONYM.User, KEY.User_ID);
- hash.Add(SYNONYM.WSID, KEY.Workstation_Id);
- hash.Add(SYNONYM.IPADDRESSPREFERENCE, KEY.IPAddressPreference);
- Debug.Assert(SqlConnectionStringBuilder.KeywordsCount + SynonymCount == hash.Count, "incorrect initial ParseSynonyms size");
- _sqlClientSynonyms = hash;
- }
- return hash;
+ { SYNONYM.APPLICATIONINTENT, KEY.ApplicationIntent },
+ { SYNONYM.APP, KEY.Application_Name },
+ { SYNONYM.EXTENDED_PROPERTIES, KEY.AttachDBFilename },
+ { SYNONYM.INITIAL_FILE_NAME, KEY.AttachDBFilename },
+ { SYNONYM.CONNECTION_TIMEOUT, KEY.Connect_Timeout },
+ { SYNONYM.CONNECTRETRYCOUNT, KEY.Connect_Retry_Count },
+ { SYNONYM.CONNECTRETRYINTERVAL, KEY.Connect_Retry_Interval },
+ { SYNONYM.TIMEOUT, KEY.Connect_Timeout },
+ { SYNONYM.LANGUAGE, KEY.Current_Language },
+ { SYNONYM.ADDR, KEY.Data_Source },
+ { SYNONYM.ADDRESS, KEY.Data_Source },
+ { SYNONYM.MULTIPLEACTIVERESULTSETS, KEY.MARS },
+ { SYNONYM.MULTISUBNETFAILOVER, KEY.MultiSubnetFailover },
+ { SYNONYM.NETWORK_ADDRESS, KEY.Data_Source },
+ { SYNONYM.SERVER, KEY.Data_Source },
+ { SYNONYM.DATABASE, KEY.Initial_Catalog },
+ { SYNONYM.TRUSTED_CONNECTION, KEY.Integrated_Security },
+ { SYNONYM.Connection_Lifetime, KEY.Load_Balance_Timeout },
+ { SYNONYM.NET, KEY.Network_Library },
+ { SYNONYM.NETWORK, KEY.Network_Library },
+ { SYNONYM.Pwd, KEY.Password },
+ { SYNONYM.POOLBLOCKINGPERIOD, KEY.PoolBlockingPeriod },
+ { SYNONYM.PERSISTSECURITYINFO, KEY.Persist_Security_Info },
+ { SYNONYM.TRANSPARENTNETWORKIPRESOLUTION, KEY.TransparentNetworkIPResolution },
+ { SYNONYM.TRUSTSERVERCERTIFICATE, KEY.TrustServerCertificate },
+ { SYNONYM.UID, KEY.User_ID },
+ { SYNONYM.User, KEY.User_ID },
+ { SYNONYM.WSID, KEY.Workstation_Id },
+ { SYNONYM.IPADDRESSPREFERENCE, KEY.IPAddressPreference }
+ };
+ Debug.Assert(count == synonyms.Count, "incorrect initial ParseSynonyms size");
+ s_sqlClientSynonyms = synonyms;
+ }
+ return synonyms;
}
internal string ObtainWorkstationId()
@@ -964,8 +967,8 @@ internal static void VerifyLocalHostAndFixup(ref string host, bool enforceLocalH
internal Microsoft.Data.SqlClient.ApplicationIntent ConvertValueToApplicationIntent()
{
- object value = base.Parsetable[KEY.ApplicationIntent];
- if (value == null)
+ string value;
+ if (!base.Parsetable.TryGetValue(KEY.ApplicationIntent, out value))
{
return DEFAULT.ApplicationIntent;
}
@@ -989,8 +992,8 @@ internal Microsoft.Data.SqlClient.ApplicationIntent ConvertValueToApplicationInt
internal Microsoft.Data.SqlClient.PoolBlockingPeriod ConvertValueToPoolBlockingPeriod()
{
- object value = base.Parsetable[KEY.PoolBlockingPeriod];
- if (value == null)
+ string value;
+ if (!base.Parsetable.TryGetValue(KEY.PoolBlockingPeriod, out value))
{
return DEFAULT.PoolBlockingPeriod;
}
@@ -1011,10 +1014,8 @@ internal Microsoft.Data.SqlClient.PoolBlockingPeriod ConvertValueToPoolBlockingP
internal SqlAuthenticationMethod ConvertValueToAuthenticationType()
{
- object value = base.Parsetable[KEY.Authentication];
-
- string valStr = value as string;
- if (valStr == null)
+ string valStr;
+ if (!base.Parsetable.TryGetValue(KEY.Authentication, out valStr))
{
return DEFAULT.Authentication;
}
@@ -1039,10 +1040,8 @@ internal SqlAuthenticationMethod ConvertValueToAuthenticationType()
///
internal SqlConnectionColumnEncryptionSetting ConvertValueToColumnEncryptionSetting()
{
- object value = base.Parsetable[KEY.ColumnEncryptionSetting];
-
- string valStr = value as string;
- if (valStr == null)
+ string valStr;
+ if (!base.Parsetable.TryGetValue(KEY.ColumnEncryptionSetting, out valStr))
{
return DEFAULT.ColumnEncryptionSetting;
}
@@ -1063,10 +1062,8 @@ internal SqlConnectionColumnEncryptionSetting ConvertValueToColumnEncryptionSett
internal SqlConnectionAttestationProtocol ConvertValueToAttestationProtocol()
{
- object value = base.Parsetable[KEY.AttestationProtocol];
-
- string valStr = value as string;
- if (valStr == null)
+ string valStr;
+ if (!base.Parsetable.TryGetValue(KEY.AttestationProtocol, out valStr))
{
return DEFAULT.AttestationProtocol;
}
@@ -1091,10 +1088,8 @@ internal SqlConnectionAttestationProtocol ConvertValueToAttestationProtocol()
///
internal SqlConnectionIPAddressPreference ConvertValueToIPAddressPreference()
{
- object value = base.Parsetable[KEY.IPAddressPreference];
-
- string valStr = value as string;
- if (valStr == null)
+ string valStr;
+ if (!base.Parsetable.TryGetValue(KEY.IPAddressPreference, out valStr))
{
return DEFAULT.s_IPAddressPreference;
}
@@ -1115,10 +1110,7 @@ internal SqlConnectionIPAddressPreference ConvertValueToIPAddressPreference()
internal bool ConvertValueToEncrypt()
{
- // If the Authentication keyword is provided, default to Encrypt=true;
- // otherwise keep old default for backwards compatibility
- object authValue = base.Parsetable[KEY.Authentication];
- bool defaultEncryptValue = (authValue == null) ? DEFAULT.Encrypt : true;
+ bool defaultEncryptValue = !base.Parsetable.ContainsKey(KEY.Authentication) ? DEFAULT.Encrypt : true;
return ConvertValueToBoolean(KEY.Encrypt, defaultEncryptValue);
}
}
diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlInternalConnectionTds.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlInternalConnectionTds.cs
index 13f0454c8c..c6844a0568 100644
--- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlInternalConnectionTds.cs
+++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlInternalConnectionTds.cs
@@ -1987,7 +1987,7 @@ private bool ShouldDisableTnir(SqlConnectionString connectionOptions)
// Check if the user had explicitly specified the TNIR option in the connection string or the connection string builder.
// If the user has specified the option in the connection string explicitly, then we shouldn't disable TNIR.
- bool isTnirExplicitlySpecifiedInConnectionOptions = connectionOptions.Parsetable[SqlConnectionString.KEY.TransparentNetworkIPResolution] != null;
+ bool isTnirExplicitlySpecifiedInConnectionOptions = connectionOptions.Parsetable.ContainsKey(SqlConnectionString.KEY.TransparentNetworkIPResolution);
return isTnirExplicitlySpecifiedInConnectionOptions ? false : (isAzureEndPoint || isFedAuthEnabled);
}
@@ -2566,7 +2566,7 @@ internal void OnLoginAck(SqlLoginAck rec)
/// Federated Authentication Info.
internal void OnFedAuthInfo(SqlFedAuthInfo fedAuthInfo)
{
- Debug.Assert((ConnectionOptions.HasUserIdKeyword && ConnectionOptions.HasPasswordKeyword)
+ Debug.Assert((ConnectionOptions._hasUserIdKeyword && ConnectionOptions._hasPasswordKeyword)
|| _credential != null
|| ConnectionOptions.Authentication == SqlAuthenticationMethod.ActiveDirectoryInteractive
|| ConnectionOptions.Authentication == SqlAuthenticationMethod.ActiveDirectoryManagedIdentity
diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Common/src/Microsoft/Data/Common/DbConnectionOptions.Common.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Common/DbConnectionOptions.Common.cs
similarity index 83%
rename from src/Microsoft.Data.SqlClient/netcore/src/Common/src/Microsoft/Data/Common/DbConnectionOptions.Common.cs
rename to src/Microsoft.Data.SqlClient/src/Microsoft/Data/Common/DbConnectionOptions.Common.cs
index 50b1c83559..de5d1cb9e5 100644
--- a/src/Microsoft.Data.SqlClient/netcore/src/Common/src/Microsoft/Data/Common/DbConnectionOptions.Common.cs
+++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Common/DbConnectionOptions.Common.cs
@@ -14,6 +14,26 @@ namespace Microsoft.Data.Common
{
partial class DbConnectionOptions
{
+ // instances of this class are intended to be immutable, i.e readonly
+ // used by pooling classes so it is much easier to verify correctness
+ // when not worried about the class being modified during execution
+
+ // connection string common keywords
+ private static class KEY
+ {
+ internal const string Integrated_Security = DbConnectionStringKeywords.IntegratedSecurity;
+ internal const string Password = DbConnectionStringKeywords.Password;
+ internal const string Persist_Security_Info = DbConnectionStringKeywords.PersistSecurityInfo;
+ internal const string User_ID = DbConnectionStringKeywords.UserID;
+ }
+
+ // known connection string common synonyms
+ private static class SYNONYM
+ {
+ internal const string Pwd = DbConnectionStringSynonyms.Pwd;
+ internal const string UID = DbConnectionStringSynonyms.UID;
+ }
+
#if DEBUG
/*private const string ConnectionStringPatternV1 =
"[\\s;]*"
@@ -79,52 +99,115 @@ partial class DbConnectionOptions
private static readonly Regex s_connectionStringQuoteValueRegex = new Regex(ConnectionStringQuoteValuePattern, RegexOptions.Compiled);
private static readonly Regex s_connectionStringQuoteOdbcValueRegex = new Regex(ConnectionStringQuoteOdbcValuePattern, RegexOptions.ExplicitCapture | RegexOptions.Compiled);
- // connection string common keywords
- private static class KEY
+ internal readonly bool _hasPasswordKeyword;
+ internal readonly bool _hasUserIdKeyword;
+ internal readonly NameValuePair _keyChain;
+
+ private readonly string _usersConnectionString;
+ private readonly Dictionary _parsetable;
+
+ internal Dictionary Parsetable => _parsetable;
+ public bool IsEmpty => _keyChain == null;
+
+ public DbConnectionOptions(string connectionString, Dictionary synonyms)
{
- internal const string Integrated_Security = "integrated security";
- internal const string Password = "password";
- internal const string Persist_Security_Info = "persist security info";
- internal const string User_ID = "user id";
- internal const string AttachDBFileName = "attachdbfilename";
+ _parsetable = new Dictionary(StringComparer.InvariantCultureIgnoreCase);
+ _usersConnectionString = ((null != connectionString) ? connectionString : "");
+
+ // first pass on parsing, initial syntax check
+ if (0 < _usersConnectionString.Length)
+ {
+ _keyChain = ParseInternal(_parsetable, _usersConnectionString, true, synonyms, false);
+ _hasPasswordKeyword = (_parsetable.ContainsKey(KEY.Password) || _parsetable.ContainsKey(SYNONYM.Pwd));
+ _hasUserIdKeyword = (_parsetable.ContainsKey(KEY.User_ID) || _parsetable.ContainsKey(SYNONYM.UID));
+ }
}
- // known connection string common synonyms
- private static class SYNONYM
+ protected DbConnectionOptions(DbConnectionOptions connectionOptions)
+ { // Clone used by SqlConnectionString
+ _usersConnectionString = connectionOptions._usersConnectionString;
+ _parsetable = connectionOptions._parsetable;
+ _keyChain = connectionOptions._keyChain;
+ _hasPasswordKeyword = connectionOptions._hasPasswordKeyword;
+ _hasUserIdKeyword = connectionOptions._hasUserIdKeyword;
+ }
+
+ internal bool TryGetParsetableValue(string key, out string value) => _parsetable.TryGetValue(key, out value);
+
+ // same as Boolean, but with SSPI thrown in as valid yes
+ public bool ConvertValueToIntegratedSecurity()
{
- internal const string Pwd = "pwd";
- internal const string UID = "uid";
+ return _parsetable.TryGetValue(KEY.Integrated_Security, out string value) && value != null ?
+ ConvertValueToIntegratedSecurityInternal(value) :
+ false;
}
- internal readonly bool HasPasswordKeyword;
- internal readonly bool HasUserIdKeyword;
+ internal bool ConvertValueToIntegratedSecurityInternal(string stringValue)
+ {
+ if (CompareInsensitiveInvariant(stringValue, "sspi") || CompareInsensitiveInvariant(stringValue, "true") || CompareInsensitiveInvariant(stringValue, "yes"))
+ return true;
+ else if (CompareInsensitiveInvariant(stringValue, "false") || CompareInsensitiveInvariant(stringValue, "no"))
+ return false;
+ else
+ {
+ string tmp = stringValue.Trim(); // Remove leading & trailing whitespace.
+ if (CompareInsensitiveInvariant(tmp, "sspi") || CompareInsensitiveInvariant(tmp, "true") || CompareInsensitiveInvariant(tmp, "yes"))
+ return true;
+ else if (CompareInsensitiveInvariant(tmp, "false") || CompareInsensitiveInvariant(tmp, "no"))
+ return false;
+ else
+ {
+ throw ADP.InvalidConnectionOptionValue(KEY.Integrated_Security);
+ }
+ }
+ }
- private readonly string _usersConnectionString;
- private readonly Dictionary _parsetable;
- internal readonly NameValuePair _keyChain;
+ public int ConvertValueToInt32(string keyName, int defaultValue)
+ {
+ return _parsetable.TryGetValue(keyName, out string value) && value != null ?
+ ConvertToInt32Internal(keyName, value) :
+ defaultValue;
+ }
- internal Dictionary Parsetable
+ internal static int ConvertToInt32Internal(string keyname, string stringValue)
{
- get { return _parsetable; }
+ try
+ {
+ return int.Parse(stringValue, System.Globalization.NumberStyles.Integer, CultureInfo.InvariantCulture);
+ }
+ catch (FormatException e)
+ {
+ throw ADP.InvalidConnectionOptionValue(keyname, e);
+ }
+ catch (OverflowException e)
+ {
+ throw ADP.InvalidConnectionOptionValue(keyname, e);
+ }
}
- public string UsersConnectionString(bool hidePassword) =>
- UsersConnectionString(hidePassword, false);
+ public string ConvertValueToString(string keyName, string defaultValue)
+ => _parsetable.TryGetValue(keyName, out string value) && value != null ? value : defaultValue;
+
+ public bool ContainsKey(string keyword) => _parsetable.ContainsKey(keyword);
+
+ protected internal virtual string Expand() => _usersConnectionString;
+
+ public string UsersConnectionString(bool hidePassword) => UsersConnectionString(hidePassword, false);
internal string UsersConnectionStringForTrace() => UsersConnectionString(true, true);
private string UsersConnectionString(bool hidePassword, bool forceHidePassword)
{
string connectionString = _usersConnectionString;
- if (HasPasswordKeyword && (forceHidePassword || (hidePassword && !HasPersistablePassword)))
+ if (_hasPasswordKeyword && (forceHidePassword || (hidePassword && !HasPersistablePassword)))
{
ReplacePasswordPwd(out connectionString, false);
}
return connectionString ?? string.Empty;
}
- internal bool HasPersistablePassword => HasPasswordKeyword ?
- ConvertValueToBoolean(KEY.Persist_Security_Info, false) :
+ internal bool HasPersistablePassword => _hasPasswordKeyword ?
+ ConvertValueToBoolean(KEY.Persist_Security_Info, DbConnectionStringDefaults.PersistSecurityInfo) :
true; // no password means persistable password so we don't have to munge
public bool ConvertValueToBoolean(string keyName, bool defaultValue)
@@ -155,8 +238,8 @@ internal static bool ConvertValueToBooleanInternal(string keyName, string string
}
}
- private static bool CompareInsensitiveInvariant(string strvalue, string strconst) =>
- (0 == StringComparer.OrdinalIgnoreCase.Compare(strvalue, strconst));
+ private static bool CompareInsensitiveInvariant(string strvalue, string strconst)
+ => (0 == StringComparer.OrdinalIgnoreCase.Compare(strvalue, strconst));
[System.Diagnostics.Conditional("DEBUG")]
private static void DebugTraceKeyValuePair(string keyname, string keyvalue, Dictionary synonyms)
@@ -164,9 +247,10 @@ private static void DebugTraceKeyValuePair(string keyname, string keyvalue, Dict
if (SqlClientEventSource.Log.IsAdvancedTraceOn())
{
Debug.Assert(string.Equals(keyname, keyname?.ToLower(), StringComparison.InvariantCulture), "missing ToLower");
- string realkeyname = ((null != synonyms) ? (string)synonyms[keyname] : keyname);
+ string realkeyname = ((null != synonyms) ? synonyms[keyname] : keyname);
- if ((KEY.Password != realkeyname) && (SYNONYM.Pwd != realkeyname))
+ if (!string.Equals(KEY.Password, realkeyname, StringComparison.InvariantCultureIgnoreCase) &&
+ !string.Equals(SYNONYM.Pwd, realkeyname, StringComparison.InvariantCultureIgnoreCase))
{
// don't trace passwords ever!
if (null != keyvalue)
@@ -450,7 +534,7 @@ private static bool IsKeyNameValid(string keyname)
{
#if DEBUG
bool compValue = s_connectionStringValidKeyRegex.IsMatch(keyname);
- Debug.Assert(((0 < keyname.Length) && (';' != keyname[0]) && !Char.IsWhiteSpace(keyname[0]) && (-1 == keyname.IndexOf('\u0000'))) == compValue, "IsValueValid mismatch with regex");
+ Debug.Assert(((0 < keyname.Length) && (';' != keyname[0]) && !char.IsWhiteSpace(keyname[0]) && (-1 == keyname.IndexOf('\u0000'))) == compValue, "IsValueValid mismatch with regex");
#endif
return ((0 < keyname.Length) && (';' != keyname[0]) && !char.IsWhiteSpace(keyname[0]) && (-1 == keyname.IndexOf('\u0000')));
}
@@ -595,14 +679,14 @@ private static NameValuePair ParseInternal(Dictionary parsetable
}
#if DEBUG
DebugTraceKeyValuePair(keyname, keyvalue, synonyms);
-
+#endif
Debug.Assert(IsKeyNameValid(keyname), "ParseFailure, invalid keyname");
Debug.Assert(IsValueValidInternal(keyvalue), "parse failure, invalid keyvalue");
-#endif
- string synonym;
- string realkeyname = null != synonyms ?
- (synonyms.TryGetValue(keyname, out synonym) ? synonym : null) :
- keyname;
+
+ string realkeyname = (synonyms is not null) ?
+ (synonyms.TryGetValue(keyname, out string synonym) ? synonym : null) :
+ keyname;
+
if (!IsKeyNameValid(realkeyname))
{
throw ADP.KeywordNotSupported(keyname);
@@ -641,7 +725,8 @@ internal NameValuePair ReplacePasswordPwd(out string constr, bool fakePassword)
StringBuilder builder = new StringBuilder(_usersConnectionString.Length);
for (NameValuePair current = _keyChain; null != current; current = current.Next)
{
- if ((KEY.Password != current.Name) && (SYNONYM.Pwd != current.Name))
+ if(!string.Equals(KEY.Password, current.Name, StringComparison.InvariantCultureIgnoreCase) &&
+ !string.Equals(SYNONYM.Pwd, current.Name, StringComparison.InvariantCultureIgnoreCase))
{
builder.Append(_usersConnectionString, copyPosition, current.Length);
if (fakePassword)