Skip to content

Commit 7622824

Browse files
fix
1 parent f1ba91d commit 7622824

File tree

6 files changed

+91
-32
lines changed

6 files changed

+91
-32
lines changed

src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/LocalDB.Windows.cs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,14 @@ private string GetConnectionString(string localDbInstance)
5050
{
5151
StringBuilder localDBConnectionString = new StringBuilder(MAX_LOCAL_DB_CONNECTION_STRING_SIZE + 1);
5252
int sizeOfbuffer = localDBConnectionString.Capacity;
53-
localDBStartInstanceFunc(localDbInstance, 0, localDBConnectionString, ref sizeOfbuffer);
54-
return localDBConnectionString.ToString();
53+
int result = localDBStartInstanceFunc(localDbInstance, 0, localDBConnectionString, ref sizeOfbuffer);
54+
if (result != TdsEnums.SNI_SUCCESS)
55+
{
56+
SNILoadHandle.SingletonInstance.LastError = new SNIError(SNIProviders.INVALID_PROV, 0, SNICommon.LocalDBErrorCode, Strings.SNI_ERROR_50);
57+
SqlClientEventSource.Log.TrySNITraceEvent(nameof(LocalDB), EventType.ERR, "Unsuccessful 'LocalDBStartInstance' method call with {0} result to start '{1}' localDb instance", result, localDbInstance);
58+
localDBConnectionString = null;
59+
}
60+
return localDBConnectionString?.ToString();
5561
}
5662

5763
internal enum LocalDBErrorState

src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNICommon.cs

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -21,16 +21,18 @@ namespace Microsoft.Data.SqlClient.SNI
2121
/// </summary>
2222
internal enum SNIProviders
2323
{
24-
HTTP_PROV, // HTTP Provider
25-
NP_PROV, // Named Pipes Provider
26-
SESSION_PROV, // Session Provider
27-
SIGN_PROV, // Sign Provider
28-
SM_PROV, // Shared Memory Provider
29-
SMUX_PROV, // SMUX Provider
30-
SSL_PROV, // SSL Provider
31-
TCP_PROV, // TCP Provider
32-
MAX_PROVS, // Number of providers
33-
INVALID_PROV // SQL Network Interfaces
24+
HTTP_PROV = 0, // HTTP Provider
25+
NP_PROV = 1, // Named Pipes Provider
26+
SESSION_PROV = 2, // Session Provider
27+
SIGN_PROV = 3, // Sign Provider
28+
SM_PROV = 4, // Shared Memory Provider
29+
SMUX_PROV = 5, // SMUX Provider
30+
SSL_PROV = 6, // SSL Provider
31+
TCP_PROV = 7, // TCP Provider
32+
VIA_PROV = 8, // Virtual Interface Architecture Provider
33+
CTAIP_PROV = 9,
34+
MAX_PROVS = 10, // Number of providers
35+
INVALID_PROV = 11 // SQL Network Interfaces
3436
}
3537

3638
/// <summary>

src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNIProxy.cs

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,7 @@ internal static SNIHandle CreateConnectionHandle(
188188
case DataSource.Protocol.TCP:
189189
sniHandle = CreateTcpHandle(details, timerExpire, parallel, ipPreference, cachedFQDN, ref pendingDNSInfo,
190190
tlsFirst, hostNameInCertificate, serverCertificateFilename);
191-
break;
191+
break;
192192
case DataSource.Protocol.NP:
193193
sniHandle = CreateNpHandle(details, timerExpire, parallel, tlsFirst);
194194
break;
@@ -390,7 +390,7 @@ private static string GetLocalDBDataSource(string fullServerName, out bool error
390390
Debug.Assert(!string.IsNullOrWhiteSpace(localDBInstance), "Local DB Instance name cannot be empty.");
391391
localDBConnectionString = LocalDB.GetLocalDBConnectionString(localDBInstance);
392392

393-
if (fullServerName == null)
393+
if (fullServerName == null || string.IsNullOrEmpty(localDBConnectionString))
394394
{
395395
// The Last error is set in LocalDB.GetLocalDBConnectionString. We don't need to set Last here.
396396
error = true;
@@ -520,7 +520,18 @@ internal static string GetLocalDBInstance(string dataSource, out bool error)
520520
ReadOnlySpan<char> input = dataSource.AsSpan().TrimStart();
521521
error = false;
522522
// NetStandard 2.0 does not support passing a string to ReadOnlySpan<char>
523-
if (input.StartsWith(LocalDbHost.AsSpan().Trim(), StringComparison.InvariantCultureIgnoreCase))
523+
int index = input.IndexOf(LocalDbHost.AsSpan().Trim(), StringComparison.InvariantCultureIgnoreCase);
524+
if (input.StartsWith(LocalDbHost_NP.AsSpan().Trim(), StringComparison.InvariantCultureIgnoreCase))
525+
{
526+
instanceName = input.Trim().ToString();
527+
}
528+
else if (index > 0)
529+
{
530+
SNILoadHandle.SingletonInstance.LastError = new SNIError(SNIProviders.INVALID_PROV, 0, SNICommon.ErrorLocatingServerInstance, Strings.SNI_ERROR_26);
531+
SqlClientEventSource.Log.TrySNITraceEvent(nameof(SNIProxy), EventType.ERR, "Incompatible use of prefix with LocalDb: '{0}'", dataSource);
532+
error = true;
533+
}
534+
else if (index == 0)
524535
{
525536
// When netcoreapp support for netcoreapp2.1 is dropped these slice calls could be converted to System.Range\System.Index
526537
// Such ad input = input[1..];
@@ -539,10 +550,6 @@ internal static string GetLocalDBInstance(string dataSource, out bool error)
539550
error = true;
540551
}
541552
}
542-
else if (input.StartsWith(LocalDbHost_NP.AsSpan().Trim(), StringComparison.InvariantCultureIgnoreCase))
543-
{
544-
instanceName = input.Trim().ToString();
545-
}
546553

547554
return instanceName;
548555
}

src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.cs

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1514,20 +1514,17 @@ internal SqlError ProcessSNIError(TdsParserStateObject stateObj)
15141514
}
15151515
else
15161516
{
1517-
15181517
if (TdsParserStateObjectFactory.UseManagedSNI)
15191518
{
1520-
// SNI error. Append additional error message info if available.
1521-
//
1519+
// SNI error. Append additional error message info if available and hasn't been included.
15221520
string sniLookupMessage = SQL.GetSNIErrorMessage((int)details.sniErrorNumber);
1523-
errorMessage = (errorMessage != string.Empty) ?
1524-
(sniLookupMessage + ": " + errorMessage) :
1525-
sniLookupMessage;
1521+
errorMessage = (string.IsNullOrEmpty(errorMessage) || errorMessage.Contains(sniLookupMessage))
1522+
? sniLookupMessage
1523+
: (sniLookupMessage + ": " + errorMessage);
15261524
}
15271525
else
15281526
{
15291527
// SNI error. Replace the entire message.
1530-
//
15311528
errorMessage = SQL.GetSNIErrorMessage((int)details.sniErrorNumber);
15321529

15331530
// If its a LocalDB error, then nativeError actually contains a LocalDB-specific error code, not a win32 error code
@@ -1536,6 +1533,7 @@ internal SqlError ProcessSNIError(TdsParserStateObject stateObj)
15361533
errorMessage += LocalDBAPI.GetLocalDBMessage((int)details.nativeError);
15371534
win32ErrorCode = 0;
15381535
}
1536+
SqlClientEventSource.Log.TryAdvancedTraceEvent("<sc.TdsParser.ProcessSNIError |ERR|ADV > Extracting the latest exception from native SNI. errorMessage: {0}", errorMessage);
15391537
}
15401538
}
15411539
errorMessage = string.Format("{0} (provider: {1}, error: {2} - {3})",
@@ -12606,7 +12604,7 @@ internal bool TryReadPlpUnicodeChars(ref char[] buff, int offst, int len, TdsPar
1260612604
return true; // No data
1260712605
}
1260812606

12609-
Debug.Assert(((ulong)stateObj._longlen != TdsEnums.SQL_PLP_NULL),"Out of sync plp read request");
12607+
Debug.Assert(((ulong)stateObj._longlen != TdsEnums.SQL_PLP_NULL), "Out of sync plp read request");
1261012608

1261112609
Debug.Assert((buff == null && offst == 0) || (buff.Length >= offst + len), "Invalid length sent to ReadPlpUnicodeChars()!");
1261212610
charsLeft = len;

src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/DataTestUtility.cs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -361,8 +361,12 @@ public static bool IsTargetReadyForAeWithKeyStore()
361361

362362
public static bool IsNotUsingManagedSNIOnWindows() => !UseManagedSNIOnWindows;
363363

364-
public static bool IsUsingNativeSNI() => !IsUsingManagedSNI();
365-
364+
public static bool IsUsingNativeSNI() =>
365+
#if !NETFRAMEWORK
366+
DataTestUtility.IsNotUsingManagedSNIOnWindows();
367+
#else
368+
true;
369+
#endif
366370
// Synapse: UTF8 collations are not supported with Azure Synapse.
367371
// Ref: https://feedback.azure.com/forums/307516-azure-synapse-analytics/suggestions/40103791-utf-8-collations-should-be-supported-in-azure-syna
368372
public static bool IsUTF8Supported()
@@ -885,7 +889,7 @@ public static bool ParseDataSource(string dataSource, out string hostname, out i
885889

886890
if (dataSource.Contains(","))
887891
{
888-
if (!Int32.TryParse(dataSource.Substring(dataSource.LastIndexOf(",",StringComparison.Ordinal) + 1), out port))
892+
if (!Int32.TryParse(dataSource.Substring(dataSource.LastIndexOf(",", StringComparison.Ordinal) + 1), out port))
889893
{
890894
return false;
891895
}

src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/LocalDBTest/LocalDBTest.cs

Lines changed: 44 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ private enum InfoType
1616
state
1717
}
1818
private static bool IsLocalDBEnvironmentSet() => DataTestUtility.IsLocalDBInstalled();
19+
private static bool IsNativeSNI() => DataTestUtility.IsUsingNativeSNI();
1920
private static bool IsLocalDbSharedInstanceSet() => DataTestUtility.IsLocalDbSharedInstanceSetup();
2021
private static readonly string s_localDbConnectionString = @$"server=(localdb)\{DataTestUtility.LocalDbAppName}";
2122
private static readonly string[] s_sharedLocalDbInstances = new string[] { @$"server=(localdb)\.\{DataTestUtility.LocalDbSharedInstanceName}", @$"server=(localdb)\." };
@@ -123,6 +124,47 @@ public static void LocalDBNamepipeMarsTest()
123124

124125
#endregion
125126

127+
#region Failures
128+
// ToDo: After adding shared memory support on managed SNI, the IsNativeSNI could be taken out
129+
[SkipOnTargetFramework(TargetFrameworkMonikers.Uap)] // No Registry support on UAP
130+
[ConditionalTheory(nameof(IsLocalDBEnvironmentSet), nameof(IsNativeSNI))]
131+
[InlineData("lpc:")]
132+
public static void SharedMemoryAndSqlLocalDbConnectionTest(string prefix)
133+
{
134+
SqlConnectionStringBuilder stringBuilder = new(s_localDbConnectionString);
135+
stringBuilder.DataSource = prefix + stringBuilder.DataSource;
136+
SqlException ex = Assert.Throws<SqlException>(() => ConnectionTest(stringBuilder.ConnectionString));
137+
Assert.Contains("A network-related or instance-specific error occurred while establishing a connection to SQL Server. The server was not found or was not accessible. Verify that the instance name is correct and that SQL Server is configured to allow remote connections. (provider: SQL Network Interfaces, error: 41 - Cannot open a Shared Memory connection to a remote SQL server)", ex.Message);
138+
}
139+
140+
[SkipOnTargetFramework(TargetFrameworkMonikers.Uap)] // No Registry support on UAP
141+
[InlineData("tcp:")]
142+
[InlineData("np:")]
143+
[InlineData("undefinded:")]
144+
[ConditionalTheory(nameof(IsLocalDBEnvironmentSet)/*, nameof(IsNativeSNI)*/)]
145+
public static void PrefixAndSqlLocalDbConnectionTest(string prefix)
146+
{
147+
SqlConnectionStringBuilder stringBuilder = new(s_localDbConnectionString);
148+
stringBuilder.DataSource = prefix + stringBuilder.DataSource;
149+
SqlException ex = Assert.Throws<SqlException>(() => ConnectionTest(stringBuilder.ConnectionString));
150+
Assert.Contains("A network-related or instance-specific error occurred while establishing a connection to SQL Server. The server was not found or was not accessible. Verify that the instance name is correct and that SQL Server is configured to allow remote connections. (provider: SQL Network Interfaces, error: 26 - Error Locating Server/Instance Specified)", ex.Message);
151+
}
152+
153+
[SkipOnTargetFramework(TargetFrameworkMonikers.Uap)] // No Registry support on UAP
154+
[ConditionalFact(nameof(IsLocalDBEnvironmentSet)/*, nameof(IsNativeSNI)*/)]
155+
public static void InvalidSqlLocalDbConnectionTest()
156+
{
157+
SqlConnectionStringBuilder stringBuilder = new(s_localDbConnectionString);
158+
stringBuilder.DataSource = stringBuilder.DataSource + "Invalid123";
159+
SqlException ex = Assert.Throws<SqlException>(() => ConnectionTest(stringBuilder.ConnectionString));
160+
Assert.Contains("A network-related or instance-specific error occurred while establishing a connection to SQL Server. The server was not found or was not accessible. Verify that the instance name is correct and that SQL Server is configured to allow remote connections. (provider: SQL Network Interfaces, error: 50 - Local Database Runtime error occurred.", ex.Message);
161+
if (IsNativeSNI())
162+
{
163+
Assert.Contains("The specified LocalDB instance does not exist.", ex.Message);
164+
}
165+
}
166+
#endregion
167+
126168
private static void ConnectionWithMarsTest(string connectionString)
127169
{
128170
SqlConnectionStringBuilder builder = new(connectionString)
@@ -178,13 +220,13 @@ private static void RestartLocalDB()
178220
{
179221
string state = ExecuteLocalDBCommandProcess(s_commandPrompt, s_sqlLocalDbInfo, InfoType.state);
180222
int count = 5;
181-
while (state.Equals("stopped", StringComparison.InvariantCultureIgnoreCase) && count>0)
223+
while (state.Equals("stopped", StringComparison.InvariantCultureIgnoreCase) && count > 0)
182224
{
183225
count--;
184226
state = ExecuteLocalDBCommandProcess(s_commandPrompt, s_startLocalDbCommand, InfoType.state);
185227
Thread.Sleep(2000);
186228
}
187-
if(state == null || state != "Running")
229+
if (state == null || state != "Running")
188230
{
189231
throw new LocalDBNotStartedException();
190232
}

0 commit comments

Comments
 (0)