From 95409c7278e8274dc90077ab075bb0643580b8d7 Mon Sep 17 00:00:00 2001 From: Ben Russell Date: Mon, 18 Nov 2024 17:35:46 -0600 Subject: [PATCH 1/3] Moving LocalDbApi to the localdb folder --- .../netcore/src/Microsoft.Data.SqlClient.csproj | 4 ++-- .../netfx/src/Microsoft.Data.SqlClient.csproj | 4 ++-- .../{LocalDBAPI.Windows.cs => LocalDb/LocalDbApi.Windows.cs} | 0 3 files changed, 4 insertions(+), 4 deletions(-) rename src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/{LocalDBAPI.Windows.cs => LocalDb/LocalDbApi.Windows.cs} (100%) 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 a4531966aa..7f78be7ffd 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj @@ -786,8 +786,8 @@ Microsoft\Data\Sql\SqlDataSourceEnumerator.Windows.cs - - Microsoft\Data\SqlClient\LocalDBAPI.Windows.cs + + Microsoft\Data\SqlClient\LocalDb\LocalDbApi.Windows.cs Microsoft\Data\SqlClient\SqlColumnEncryptionCngProvider.Windows.cs 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 0c3f1f747a..7148160a20 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj @@ -394,8 +394,8 @@ Microsoft\Data\SqlClient\EnclaveSessionCache.cs - - Microsoft\Data\SqlClient\LocalDBAPI.Windows.cs + + Microsoft\Data\SqlClient\LocalDb\LocalDbApi.Windows.cs Microsoft\Data\SqlClient\LocalDb\LocalDbConfigurationSection.netfx.cs diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/LocalDBAPI.Windows.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/LocalDb/LocalDbApi.Windows.cs similarity index 100% rename from src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/LocalDBAPI.Windows.cs rename to src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/LocalDb/LocalDbApi.Windows.cs From 5c859b27b04c337566d1893d88932f3adfe2e471 Mon Sep 17 00:00:00 2001 From: Ben Russell Date: Mon, 18 Nov 2024 18:12:25 -0600 Subject: [PATCH 2/3] Cleanup for localdbapi --- .../src/Microsoft/Data/SqlClient/TdsParser.cs | 3 +- .../src/Microsoft/Data/SqlClient/TdsParser.cs | 5 +- .../SqlClient/LocalDb/LocalDbApi.Windows.cs | 270 ++++++++++-------- .../Data/SqlClient/SqlConnectionString.cs | 5 +- .../Microsoft/Data/SqlClient/SqlDependency.cs | 19 +- .../Data/SqlClient/SqlDependencyListener.cs | 15 +- .../SqlClient/TdsParserSafeHandles.Windows.cs | 3 +- 7 files changed, 182 insertions(+), 138 deletions(-) diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.cs index b7bc73d620..bb72ce7760 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.cs @@ -21,6 +21,7 @@ using Microsoft.Data.ProviderBase; using Microsoft.Data.Sql; using Microsoft.Data.SqlClient.DataClassification; +using Microsoft.Data.SqlClient.LocalDb; using Microsoft.Data.SqlClient.Server; using Microsoft.Data.SqlTypes; @@ -1557,7 +1558,7 @@ internal SqlError ProcessSNIError(TdsParserStateObject stateObj) // If its a LocalDB error, then nativeError actually contains a LocalDB-specific error code, not a win32 error code if (details.sniErrorNumber == SniErrors.LocalDBErrorCode) { - errorMessage += LocalDBAPI.GetLocalDBMessage((int)details.nativeError); + errorMessage += LocalDbApi.GetLocalDbMessage((int)details.nativeError); win32ErrorCode = 0; } SqlClientEventSource.Log.TryAdvancedTraceEvent(" Extracting the latest exception from native SNI. errorMessage: {0}", errorMessage); diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParser.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParser.cs index 61b9de2451..a53aaf42da 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParser.cs +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParser.cs @@ -24,6 +24,7 @@ using Microsoft.Data.Common; using Microsoft.Data.Sql; using Microsoft.Data.SqlClient.DataClassification; +using Microsoft.Data.SqlClient.LocalDb; using Microsoft.Data.SqlClient.Server; using Microsoft.Data.SqlTypes; using Microsoft.SqlServer.Server; @@ -418,7 +419,7 @@ internal void Connect(ServerInfo serverInfo, //Create LocalDB instance if necessary if (connHandler.ConnectionOptions.LocalDBInstance != null) { - LocalDBAPI.CreateLocalDBInstance(connHandler.ConnectionOptions.LocalDBInstance); + LocalDbApi.CreateLocalDbInstance(connHandler.ConnectionOptions.LocalDBInstance); if (encrypt == SqlConnectionEncryptOption.Mandatory) { // Encryption is not supported on SQL Local DB - disable it for current session. @@ -1678,7 +1679,7 @@ internal SqlError ProcessSNIError(TdsParserStateObject stateObj) // If its a LocalDB error, then nativeError actually contains a LocalDB-specific error code, not a win32 error code if (sniError.sniError == SniErrors.LocalDBErrorCode) { - errorMessage += LocalDBAPI.GetLocalDBMessage((int)sniError.nativeError); + errorMessage += LocalDbApi.GetLocalDbMessage((int)sniError.nativeError); win32ErrorCode = 0; } } diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/LocalDb/LocalDbApi.Windows.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/LocalDb/LocalDbApi.Windows.cs index efdad34495..ba7b3cea2f 100644 --- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/LocalDb/LocalDbApi.Windows.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/LocalDb/LocalDbApi.Windows.cs @@ -10,27 +10,30 @@ using System.Text; using Interop.Windows.Kernel32; using Interop.Windows.Sni; -using Microsoft.Data.SqlClient; #if NETFRAMEWORK using System.Collections.Generic; using System.Configuration; using System.Runtime.CompilerServices; using System.Threading; -using Microsoft.Data.SqlClient.LocalDb; #endif -namespace Microsoft.Data +namespace Microsoft.Data.SqlClient.LocalDb { - internal static class LocalDBAPI + internal static class LocalDbApi { - private const int const_ErrorMessageBufferSize = 1024; // Buffer size for Local DB error message 1K will be enough for all messages - private const uint const_LOCALDB_TRUNCATE_ERR_MESSAGE = 1;// flag for LocalDBFormatMessage that indicates that message can be truncated if it does not fit in the buffer + // Buffer size for Local DB error message 1K will be enough for all messages + private const int ErrorMessageBufferSize = 1024; + private const string LocalDbPrefix = @"(localdb)\"; - private const string LocalDbPrefix_NP = @"np:\\.\pipe\LOCALDB#"; + private const string LocalDbPrefixNamedPipe = @"np:\\.\pipe\LOCALDB#"; + // Flag for LocalDbFormatMessage that indicates that message can be truncated if it does + // not fit in the buffer. + private const uint LocalDbTruncateErrorMessage = 1; + #if NETFRAMEWORK - private const string Const_partialTrustFlagKey = "ALLOW_LOCALDB_IN_PARTIAL_TRUST"; + private const string PartialTrustFlagKey = "ALLOW_LOCALDB_IN_PARTIAL_TRUST"; #endif private static readonly object s_dllLock = new object(); @@ -39,63 +42,73 @@ internal static class LocalDBAPI private static readonly object s_configLock = new object(); #endif - private static LocalDBFormatMessageDelegate s_localDBFormatMessage = null; - //This is copy of handle that SNI maintains, so we are responsible for freeing it - therefore there we are not using SafeHandle - private static IntPtr s_userInstanceDLLHandle = IntPtr.Zero; + private static LocalDbFormatMessageDelegate s_localDbFormatMessage; + // This is copy of handle that SNI maintains, so we are responsible for freeing it - + // therefore there we are not using SafeHandle + private static IntPtr s_userInstanceDllHandle = IntPtr.Zero; #if NETFRAMEWORK - private static PermissionSet _fullTrust = null; - private static bool _partialTrustFlagChecked = false; - private static bool _partialTrustAllowed = false; - private static Dictionary s_configurableInstances = null; - private static LocalDBCreateInstanceDelegate s_localDBCreateInstance = null; + private static Dictionary s_configurableInstances; + private static PermissionSet s_fullTrust; + private static LocalDbCreateInstanceDelegate s_localDbCreateInstance; + private static bool s_partialTrustAllowed; + private static bool s_partialTrustFlagChecked; #endif #if NETFRAMEWORK [SuppressUnmanagedCodeSecurity] [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - private delegate int LocalDBCreateInstanceDelegate([MarshalAs(UnmanagedType.LPWStr)] string version, [MarshalAs(UnmanagedType.LPWStr)] string instance, UInt32 flags); + private delegate int LocalDbCreateInstanceDelegate( + [MarshalAs(UnmanagedType.LPWStr)] string version, + [MarshalAs(UnmanagedType.LPWStr)] string instance, + uint flags); #endif [SuppressUnmanagedCodeSecurity] [UnmanagedFunctionPointer(CallingConvention.Cdecl, CharSet = CharSet.Unicode)] - private delegate int LocalDBFormatMessageDelegate(int hrLocalDB, uint dwFlags, uint dwLanguageId, StringBuilder buffer, ref uint buflen); + private delegate int LocalDbFormatMessageDelegate( + int hrLocalDb, + uint dwFlags, + uint dwLanguageId, + StringBuilder buffer, + ref uint bufferLength); #if NETFRAMEWORK - private static LocalDBCreateInstanceDelegate LocalDBCreateInstance + private static LocalDbCreateInstanceDelegate LocalDbCreateInstance { get { - if (s_localDBCreateInstance == null) + if (s_localDbCreateInstance is null) { RuntimeHelpers.PrepareConstrainedRegions(); lock (s_dllLock) { - if (s_localDBCreateInstance == null) + if (s_localDbCreateInstance is null) { IntPtr functionAddr = LoadProcAddress("LocalDBCreateInstance"); if (functionAddr == IntPtr.Zero) { int hResult = Marshal.GetLastWin32Error(); SqlClientEventSource.Log.TryTraceEvent(" GetProcAddress for LocalDBCreateInstance error 0x{0}", hResult); - throw CreateLocalDBException(errorMessage: StringsHelper.GetString("LocalDB_MethodNotFound")); + throw CreateLocalDbException(errorMessage: StringsHelper.GetString("LocalDB_MethodNotFound")); } - s_localDBCreateInstance = (LocalDBCreateInstanceDelegate)Marshal.GetDelegateForFunctionPointer(functionAddr, typeof(LocalDBCreateInstanceDelegate)); + s_localDbCreateInstance = (LocalDbCreateInstanceDelegate)Marshal.GetDelegateForFunctionPointer(functionAddr, typeof(LocalDbCreateInstanceDelegate)); } } } - return s_localDBCreateInstance; + + return s_localDbCreateInstance; } } #endif - private static LocalDBFormatMessageDelegate LocalDBFormatMessage + private static LocalDbFormatMessageDelegate LocalDbFormatMessage { get { - if (s_localDBFormatMessage == null) + if (s_localDbFormatMessage is null) { #if NETFRAMEWORK RuntimeHelpers.PrepareConstrainedRegions(); @@ -103,7 +116,7 @@ private static LocalDBFormatMessageDelegate LocalDBFormatMessage lock (s_dllLock) { - if (s_localDBFormatMessage == null) + if (s_localDbFormatMessage is null) { IntPtr functionAddr = LoadProcAddress("LocalDBFormatMessage"); if (functionAddr == IntPtr.Zero) @@ -111,22 +124,23 @@ private static LocalDBFormatMessageDelegate LocalDBFormatMessage // SNI checks for LocalDBFormatMessage during DLL loading, so it is practically impossible to get this error. int hResult = Marshal.GetLastWin32Error(); SqlClientEventSource.Log.TryTraceEvent("LocalDBAPI.LocalDBFormatMessage> GetProcAddress for LocalDBFormatMessage error 0x{0}", hResult); - throw CreateLocalDBException(errorMessage: Strings.LocalDB_MethodNotFound); + throw CreateLocalDbException(errorMessage: Strings.LocalDB_MethodNotFound); } - s_localDBFormatMessage = Marshal.GetDelegateForFunctionPointer(functionAddr); + s_localDbFormatMessage = Marshal.GetDelegateForFunctionPointer(functionAddr); } } } - return s_localDBFormatMessage; + + return s_localDbFormatMessage; } } - private static IntPtr UserInstanceDLLHandle + private static IntPtr UserInstanceDllHandle { get { - if (s_userInstanceDLLHandle == IntPtr.Zero) + if (s_userInstanceDllHandle == IntPtr.Zero) { #if NETFRAMEWORK RuntimeHelpers.PrepareConstrainedRegions(); @@ -134,10 +148,10 @@ private static IntPtr UserInstanceDLLHandle lock (s_dllLock) { - if (s_userInstanceDLLHandle == IntPtr.Zero) + if (s_userInstanceDllHandle == IntPtr.Zero) { - SniNativeWrapper.SNIQueryInfo(QueryType.SNI_QUERY_LOCALDB_HMODULE, ref s_userInstanceDLLHandle); - if (s_userInstanceDLLHandle != IntPtr.Zero) + SniNativeWrapper.SNIQueryInfo(QueryType.SNI_QUERY_LOCALDB_HMODULE, ref s_userInstanceDllHandle); + if (s_userInstanceDllHandle != IntPtr.Zero) { #if NETFRAMEWORK SqlClientEventSource.Log.TryTraceEvent(" LocalDB - handle obtained"); @@ -148,80 +162,75 @@ private static IntPtr UserInstanceDLLHandle else { SniNativeWrapper.SNIGetLastError(out SniError sniError); - throw CreateLocalDBException(errorMessage: StringsHelper.GetString("LocalDB_FailedGetDLLHandle"), sniError: sniError.sniError); + throw CreateLocalDbException( + errorMessage: StringsHelper.GetString("LocalDB_FailedGetDLLHandle"), + sniError: sniError.sniError); } } } } - return s_userInstanceDLLHandle; + return s_userInstanceDllHandle; } } #if NETFRAMEWORK - internal static void AssertLocalDBPermissions() + internal static void AssertLocalDbPermissions() { - _partialTrustAllowed = true; + s_partialTrustAllowed = true; } #endif #if NETFRAMEWORK - internal static void CreateLocalDBInstance(string instance) + internal static void CreateLocalDbInstance(string instance) { - DemandLocalDBPermissions(); - if (s_configurableInstances == null) + DemandLocalDbPermissions(); + if (s_configurableInstances is null) { // load list of instances from configuration, mark them as not created - bool lockTaken = false; RuntimeHelpers.PrepareConstrainedRegions(); - try + + lock (s_configLock) { - Monitor.Enter(s_configLock, ref lockTaken); - if (s_configurableInstances == null) + if (s_configurableInstances is null) { - Dictionary tempConfigurableInstances = new Dictionary(StringComparer.OrdinalIgnoreCase); + Dictionary tempConfigurableInstances = + new Dictionary(StringComparer.OrdinalIgnoreCase); object section = ConfigurationManager.GetSection("system.data.localdb"); - if (section != null) // if no section just skip creation + if (section is not null) { - // validate section type - LocalDbConfigurationSection configSection = section as LocalDbConfigurationSection; - if (configSection == null) + // Validate section type + if (section is not LocalDbConfigurationSection configSection) { - throw CreateLocalDBException(errorMessage: StringsHelper.GetString("LocalDB_BadConfigSectionType")); + throw CreateLocalDbException(Strings.LocalDB_BadConfigSectionType); } foreach (LocalDbInstanceElement confElement in configSection.LocalDbInstances) { Debug.Assert(confElement.Name != null && confElement.Version != null, "Both name and version should not be null"); - tempConfigurableInstances.Add(confElement.Name.Trim(), new InstanceInfo(confElement.Version.Trim())); + tempConfigurableInstances.Add( + confElement.Name.Trim(), + new InstanceInfo(confElement.Version.Trim())); } } else { SqlClientEventSource.Log.TryTraceEvent(" No system.data.localdb section found in configuration"); } + s_configurableInstances = tempConfigurableInstances; } } - finally - { - if (lockTaken) - { - Monitor.Exit(s_configLock); - } - } } - InstanceInfo instanceInfo = null; - - if (!s_configurableInstances.TryGetValue(instance, out instanceInfo)) + if (!s_configurableInstances.TryGetValue(instance, out InstanceInfo instanceInfo)) { - // instance name was not in the config + // Instance name was not in the config return; } if (instanceInfo.created) { - // instance has already been created + // Instance has already been created return; } @@ -229,51 +238,52 @@ internal static void CreateLocalDBInstance(string instance) if (instanceInfo.version.Contains("\0")) { - throw CreateLocalDBException(errorMessage: StringsHelper.GetString("LocalDB_InvalidVersion"), instance: instance); + throw CreateLocalDbException(errorMessage: Strings.LocalDB_InvalidVersion, instance: instance); } - // LocalDBCreateInstance is thread- and cross-process safe method, it is OK to call from two threads simultaneously - int hr = LocalDBCreateInstance(instanceInfo.version, instance, flags: 0); + // LocalDBCreateInstance is thread- and cross-process safe method, it is OK to call + // from two threads simultaneously + int hr = LocalDbCreateInstance(instanceInfo.version, instance, flags: 0); SqlClientEventSource.Log.TryTraceEvent(" Starting creation of instance {0} version {1}", instance, instanceInfo.version); if (hr < 0) { - throw CreateLocalDBException(errorMessage: StringsHelper.GetString("LocalDB_CreateFailed"), instance: instance, localDbError: hr); + throw CreateLocalDbException(errorMessage: StringsHelper.GetString("LocalDB_CreateFailed"), instance: instance, localDbError: hr); } + // Mark instance as created SqlClientEventSource.Log.TryTraceEvent(" Finished creation of instance {0}", instance); - instanceInfo.created = true; // mark instance as created + instanceInfo.created = true; } #endif #if NETFRAMEWORK - internal static void DemandLocalDBPermissions() + internal static void DemandLocalDbPermissions() { - if (!_partialTrustAllowed) + if (!s_partialTrustAllowed) { - if (!_partialTrustFlagChecked) + if (!s_partialTrustFlagChecked) { - object partialTrustFlagValue = AppDomain.CurrentDomain.GetData(Const_partialTrustFlagKey); - if (partialTrustFlagValue != null && partialTrustFlagValue is bool) + object partialTrustFlagValue = AppDomain.CurrentDomain.GetData(PartialTrustFlagKey); + if (partialTrustFlagValue is bool partialTrustFlagValueBool) { - _partialTrustAllowed = (bool)partialTrustFlagValue; + s_partialTrustAllowed = partialTrustFlagValueBool; } - _partialTrustFlagChecked = true; - if (_partialTrustAllowed) + + s_partialTrustFlagChecked = true; + if (s_partialTrustAllowed) { return; } } - if (_fullTrust == null) - { - _fullTrust = new NamedPermissionSet("FullTrust"); - } - _fullTrust.Demand(); + + s_fullTrust ??= new NamedPermissionSet("FullTrust"); + s_fullTrust.Demand(); } } #endif - // check if name is in format (localdb)\ and return instance name if it is + // Check if name is in format (localdb)\ and return instance name if it is // localDB can also have a format of np:\\.\pipe\LOCALDB#\tsql\query internal static string GetLocalDbInstanceNameFromServerName(string serverName) { @@ -290,7 +300,7 @@ internal static string GetLocalDbInstanceNameFromServerName(string serverName) return input.ToString(); } } - else if (input.StartsWith(LocalDbPrefix_NP.AsSpan(), StringComparison.OrdinalIgnoreCase)) + else if (input.StartsWith(LocalDbPrefixNamedPipe.AsSpan(), StringComparison.OrdinalIgnoreCase)) { return input.ToString(); } @@ -299,37 +309,43 @@ internal static string GetLocalDbInstanceNameFromServerName(string serverName) return null; } - internal static string GetLocalDBMessage(int hrCode) + internal static string GetLocalDbMessage(int hrCode) { Debug.Assert(hrCode < 0, "HRCode does not indicate error"); try { - StringBuilder buffer = new StringBuilder((int)const_ErrorMessageBufferSize); + StringBuilder buffer = new StringBuilder(ErrorMessageBufferSize); uint len = (uint)buffer.Capacity; // First try for current culture - int hResult = LocalDBFormatMessage(hrLocalDB: hrCode, dwFlags: const_LOCALDB_TRUNCATE_ERR_MESSAGE, dwLanguageId: (uint)CultureInfo.CurrentCulture.LCID, - buffer: buffer, buflen: ref len); + int hResult = LocalDbFormatMessage( + hrLocalDb: hrCode, + dwFlags: LocalDbTruncateErrorMessage, + dwLanguageId: (uint)CultureInfo.CurrentCulture.LCID, + buffer: buffer, + bufferLength: ref len); + if (hResult >= 0) { return buffer.ToString(); } - else + + // Message is not available for current culture, try default + buffer = new StringBuilder(ErrorMessageBufferSize); + len = (uint)buffer.Capacity; + hResult = LocalDbFormatMessage( + hrLocalDb: hrCode, + dwFlags: LocalDbTruncateErrorMessage, + dwLanguageId: 0, // Thread locale with fallback to English + buffer: buffer, + bufferLength: ref len); + + if (hResult >= 0) { - // Message is not available for current culture, try default - buffer = new StringBuilder((int)const_ErrorMessageBufferSize); - len = (uint)buffer.Capacity; - hResult = LocalDBFormatMessage(hrLocalDB: hrCode, dwFlags: const_LOCALDB_TRUNCATE_ERR_MESSAGE, dwLanguageId: 0 /* thread locale with fallback to English */, - buffer: buffer, buflen: ref len); - if (hResult >= 0) - { - return buffer.ToString(); - } - else - { - return string.Format(CultureInfo.CurrentCulture, "{0} (0x{1:X}).", Strings.LocalDB_UnobtainableMessage, hResult); - } + return buffer.ToString(); } + + return string.Format(CultureInfo.CurrentCulture, "{0} (0x{1:X}).", Strings.LocalDB_UnobtainableMessage, hResult); } catch (SqlException exc) { @@ -337,39 +353,59 @@ internal static string GetLocalDBMessage(int hrCode) } } - internal static void ReleaseDLLHandles() + internal static void ReleaseDllHandles() { - s_userInstanceDLLHandle = IntPtr.Zero; - s_localDBFormatMessage = null; + s_userInstanceDllHandle = IntPtr.Zero; + s_localDbFormatMessage = null; #if NETFRAMEWORK - s_localDBCreateInstance = null; + s_localDbCreateInstance = null; #endif } - private static SqlException CreateLocalDBException(string errorMessage, string instance = null, int localDbError = 0, uint sniError = 0) + private static SqlException CreateLocalDbException( + string errorMessage, + string instance = null, + int localDbError = 0, + uint sniError = 0) { - Debug.Assert((localDbError == 0) || (sniError == 0), "LocalDB error and SNI error cannot be specified simultaneously"); + Debug.Assert(localDbError == 0 || sniError == 0, "LocalDB error and SNI error cannot be specified simultaneously"); Debug.Assert(!string.IsNullOrEmpty(errorMessage), "Error message should not be null or empty"); - SqlErrorCollection collection = new SqlErrorCollection(); - int errorCode = (localDbError == 0) ? (int)sniError : localDbError; + int errorCode = localDbError == 0 ? (int)sniError : localDbError; if (sniError != 0) { string sniErrorMessage = SQL.GetSNIErrorMessage(sniError); - errorMessage = string.Format("{0} (error: {1} - {2})", errorMessage, sniError, sniErrorMessage); + errorMessage = $"{errorMessage} (error: {sniError} - {sniErrorMessage})"; } - collection.Add(new SqlError(errorCode, 0, TdsEnums.FATAL_ERROR_CLASS, instance, errorMessage, null, 0)); + SqlErrorCollection collection = new SqlErrorCollection() + { + new SqlError( + infoNumber: errorCode, + errorState: 0, + errorClass: TdsEnums.FATAL_ERROR_CLASS, + server: instance, + errorMessage: errorMessage, + procedure: null, + lineNumber: 0) + }; if (localDbError != 0) { - collection.Add(new SqlError(errorCode, 0, TdsEnums.FATAL_ERROR_CLASS, instance, GetLocalDBMessage(localDbError), null, 0)); + collection.Add(new SqlError( + infoNumber: errorCode, + errorState: 0, + errorClass: TdsEnums.FATAL_ERROR_CLASS, + server: instance, + errorMessage: GetLocalDbMessage(localDbError), + procedure: null, + lineNumber: 0)); } - SqlException exc = SqlException.CreateException(collection, null); + SqlException exc = SqlException.CreateException(collection, null); exc._doNotReconnect = true; return exc; @@ -377,9 +413,9 @@ private static SqlException CreateLocalDBException(string errorMessage, string i private static IntPtr LoadProcAddress(string funcName) => #if NETFRAMEWORK - Kernel32Safe.GetProcAddress(UserInstanceDLLHandle, funcName); + Kernel32Safe.GetProcAddress(UserInstanceDllHandle, funcName); #else - Kernel32.GetProcAddress(UserInstanceDLLHandle, funcName); + Kernel32.GetProcAddress(UserInstanceDllHandle, funcName); #endif #if NETFRAMEWORK diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlConnectionString.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlConnectionString.cs index b8a66f06d7..58b34fd287 100644 --- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlConnectionString.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlConnectionString.cs @@ -13,6 +13,7 @@ using System.Security; using System.Security.Permissions; using Microsoft.Data.Common; +using Microsoft.Data.SqlClient.LocalDb; namespace Microsoft.Data.SqlClient { @@ -325,7 +326,7 @@ internal SqlConnectionString(string connectionString) : base(connectionString, G _contextConnection = ConvertValueToBoolean(KEY.Context_Connection, DEFAULT.Context_Connection); _currentLanguage = ConvertValueToString(KEY.Current_Language, DEFAULT.Current_Language); _dataSource = ConvertValueToString(KEY.Data_Source, DEFAULT.Data_Source); - _localDBInstance = LocalDBAPI.GetLocalDbInstanceNameFromServerName(_dataSource); + _localDBInstance = LocalDbApi.GetLocalDbInstanceNameFromServerName(_dataSource); _failoverPartner = ConvertValueToString(KEY.FailoverPartner, DEFAULT.FailoverPartner); _initialCatalog = ConvertValueToString(KEY.Initial_Catalog, DEFAULT.Initial_Catalog); _password = ConvertValueToString(KEY.Password, DEFAULT.Password); @@ -627,7 +628,7 @@ internal SqlConnectionString(SqlConnectionString connectionOptions, string dataS _contextConnection = connectionOptions._contextConnection; _currentLanguage = connectionOptions._currentLanguage; _dataSource = dataSource; - _localDBInstance = LocalDBAPI.GetLocalDbInstanceNameFromServerName(_dataSource); + _localDBInstance = LocalDbApi.GetLocalDbInstanceNameFromServerName(_dataSource); _failoverPartner = connectionOptions._failoverPartner; _initialCatalog = connectionOptions._initialCatalog; _password = connectionOptions._password; diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlDependency.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlDependency.cs index 534d42f866..44bee53a75 100644 --- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlDependency.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlDependency.cs @@ -7,19 +7,22 @@ using System.Diagnostics; using System.Globalization; using System.Runtime.CompilerServices; +using System.Text; +using System.Threading; +using System.Xml; +using Microsoft.Data.Common; +using Microsoft.Data.ProviderBase; +using Microsoft.Data.Sql; + #if NETFRAMEWORK using System.IO; using System.Runtime.Remoting; using System.Runtime.Serialization; using System.Runtime.Versioning; using System.Security.Permissions; +using Interop.Windows.Sni; +using Microsoft.Data.SqlClient.LocalDb; #endif -using System.Text; -using System.Threading; -using System.Xml; -using Microsoft.Data.Common; -using Microsoft.Data.ProviderBase; -using Microsoft.Data.Sql; namespace Microsoft.Data.SqlClient { @@ -600,7 +603,7 @@ internal static bool Start(string connectionString, string queue, bool useDefaul connectionStringObject.DemandPermission(); if (connectionStringObject.LocalDBInstance != null) { - LocalDBAPI.DemandLocalDBPermissions(); + LocalDbApi.DemandLocalDbPermissions(); } #endif // End duplicate Start/Stop logic. @@ -753,7 +756,7 @@ internal static bool Stop(string connectionString, string queue, bool useDefault connectionStringObject.DemandPermission(); if (connectionStringObject.LocalDBInstance != null) { - LocalDBAPI.DemandLocalDBPermissions(); + LocalDbApi.DemandLocalDbPermissions(); } #endif // End duplicate Start/Stop logic. diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlDependencyListener.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlDependencyListener.cs index 9e3644a94c..b7e1fe183e 100644 --- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlDependencyListener.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlDependencyListener.cs @@ -8,18 +8,19 @@ using System.Data.SqlTypes; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; -#if NETFRAMEWORK -using System.Runtime.CompilerServices; -using System.Runtime.Versioning; -using System.Security.Principal; -using Microsoft.Data; -#endif using System.Threading; using System.Xml; using Microsoft.Data.Common; using Microsoft.Data.ProviderBase; using Microsoft.Data.SqlClient; +#if NETFRAMEWORK +using System.Runtime.CompilerServices; +using System.Runtime.Versioning; +using System.Security.Principal; +using Microsoft.Data.SqlClient.LocalDb; +#endif + // This class is the process wide dependency dispatcher. It contains all connection listeners for the entire process and // receives notifications on those connections to dispatch to the corresponding AppDomain dispatcher to notify the // appropriate dependencies. @@ -100,7 +101,7 @@ internal SqlConnectionContainer(SqlConnectionContainerHashHelper hashHelper, str if (connStringObj.LocalDBInstance != null) { // If it is LocalDB, we demanded LocalDB permissions too - LocalDBAPI.AssertLocalDBPermissions(); + LocalDbApi.AssertLocalDbPermissions(); } #endif _con.Open(); diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/TdsParserSafeHandles.Windows.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/TdsParserSafeHandles.Windows.cs index bf5871c57e..99cb486bbb 100644 --- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/TdsParserSafeHandles.Windows.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/TdsParserSafeHandles.Windows.cs @@ -7,6 +7,7 @@ using System.Diagnostics; using System.Runtime.InteropServices; using Interop.Windows.Sni; +using Microsoft.Data.SqlClient.LocalDb; #if NETFRAMEWORK using System.Runtime.CompilerServices; @@ -77,7 +78,7 @@ override protected bool ReleaseHandle() { if (TdsEnums.SNI_SUCCESS == _sniStatus) { - LocalDBAPI.ReleaseDLLHandles(); + LocalDbApi.ReleaseDllHandles(); SniNativeWrapper.SNITerminate(); } base.handle = IntPtr.Zero; From a8c47dc235f7ec2410aff92af07de24197de3aa4 Mon Sep 17 00:00:00 2001 From: Ben Russell Date: Wed, 26 Feb 2025 14:40:14 -0600 Subject: [PATCH 3/3] Applying the same cleanup to the Unix LocalDbApi implementation --- .../netcore/src/Microsoft.Data.SqlClient.csproj | 4 ++-- .../{LocalDBAPI.Unix.cs => LocalDb/LocalDbApi.Unix.cs} | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) rename src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/{LocalDBAPI.Unix.cs => LocalDb/LocalDbApi.Unix.cs} (77%) 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 7f78be7ffd..e8fd02f14c 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj @@ -824,8 +824,8 @@ Microsoft\Data\ProviderBase\DbConnectionPoolIdentity.Unix.cs - - Microsoft\Data\SqlClient\LocalDBAPI.Unix.cs + + Microsoft\Data\SqlClient\LocalDb\LocalDbApi.Unix.cs diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/LocalDBAPI.Unix.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/LocalDb/LocalDbApi.Unix.cs similarity index 77% rename from src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/LocalDBAPI.Unix.cs rename to src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/LocalDb/LocalDbApi.Unix.cs index 7555a80d32..e6f7bcbd1e 100644 --- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/LocalDBAPI.Unix.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/LocalDb/LocalDbApi.Unix.cs @@ -4,14 +4,14 @@ using System; -namespace Microsoft.Data +namespace Microsoft.Data.SqlClient.LocalDb { - internal static partial class LocalDBAPI + internal static class LocalDbApi { internal static string GetLocalDbInstanceNameFromServerName(string serverName) => null; - internal static string GetLocalDBMessage(int hrCode) => + internal static string GetLocalDbMessage(int hrCode) => throw new PlatformNotSupportedException(Strings.LocalDBNotSupported); // LocalDB is not available for Unix and hence it cannot be supported. } }