Address warnings and (some) nullables (#2013)

This commit is contained in:
Cheena Malhotra
2023-04-18 20:57:13 -07:00
committed by GitHub
parent d56f2309da
commit 648d7dbd3c
83 changed files with 674 additions and 588 deletions

View File

@@ -413,22 +413,19 @@ namespace Microsoft.Kusto.ServiceLayer.DataSource.Kusto
{
var returnList = new List<DataSourceObjectMetadata>();
if (_folderMetadata.ContainsKey(key))
if (_folderMetadata.TryGetValue(key, out IEnumerable<FolderMetadata>? folderMetadata))
{
returnList.AddRange(_folderMetadata[key]
.OrderBy(x => x.PrettyName, StringComparer.OrdinalIgnoreCase));
returnList.AddRange(folderMetadata.OrderBy(x => x.PrettyName, StringComparer.OrdinalIgnoreCase));
}
if (_tableMetadata.ContainsKey(key))
if (_tableMetadata.TryGetValue(key, out IEnumerable<TableMetadata>? tableMetadata))
{
returnList.AddRange(_tableMetadata[key]
.OrderBy(x => x.PrettyName, StringComparer.OrdinalIgnoreCase));
returnList.AddRange(tableMetadata.OrderBy(x => x.PrettyName, StringComparer.OrdinalIgnoreCase));
}
if (_functionMetadata.ContainsKey(key))
if (_functionMetadata.TryGetValue(key, out IEnumerable<FunctionMetadata>? functionMetadata))
{
returnList.AddRange(_functionMetadata[key]
.OrderBy(x => x.PrettyName, StringComparer.OrdinalIgnoreCase));
returnList.AddRange(functionMetadata.OrderBy(x => x.PrettyName, StringComparer.OrdinalIgnoreCase));
}
return returnList;
@@ -515,16 +512,15 @@ namespace Microsoft.Kusto.ServiceLayer.DataSource.Kusto
private IEnumerable<DataSourceObjectMetadata> GetTableSchema(TableMetadata tableMetadata)
{
var key = GenerateMetadataKey(tableMetadata.DatabaseName, tableMetadata.Name);
if (_columnMetadata.ContainsKey(key))
if (_columnMetadata.TryGetValue(key, out IEnumerable<DataSourceObjectMetadata>? metadata))
{
return _columnMetadata[key];
return metadata;
}
SetTableSchema(tableMetadata);
return _columnMetadata.ContainsKey(key)
? _columnMetadata[key]
: Enumerable.Empty<DataSourceObjectMetadata>();
return _columnMetadata.TryGetValue(key, out IEnumerable<DataSourceObjectMetadata>? columnMetadata)
? columnMetadata : Enumerable.Empty<DataSourceObjectMetadata>();
}
private void SetTableSchema(TableMetadata tableMetadata)
@@ -683,9 +679,9 @@ namespace Microsoft.Kusto.ServiceLayer.DataSource.Kusto
Urn = $"{tableKey}.{table.TableName}"
};
if (tableFolders.ContainsKey(tableKey.ToString()))
if (tableFolders.TryGetValue(tableKey.ToString(), out List<TableMetadata>? tableMetadataList))
{
tableFolders[tableKey.ToString()].Add(tableMetadata);
tableMetadataList.Add(tableMetadata);
}
else
{

View File

@@ -12,7 +12,7 @@ using Microsoft.Kusto.ServiceLayer.DataSource.Metadata;
namespace Microsoft.Kusto.ServiceLayer.DataSource
{
public static class KustoQueryUtils
public static partial class KustoQueryUtils
{
public const string StatementSeparator = "\n | "; // Start each statement on a new line. Not required by Kusto, but doing this for readability of scripts generated from here.
@@ -30,7 +30,6 @@ namespace Microsoft.Kusto.ServiceLayer.DataSource
}
string result = name;
Regex rx = new Regex("[^_a-zA-Z0-9]");
string [] kustoKeywordList = {"and", "anomalychart", "areachart", "asc", "barchart", "between", "bool", "boolean", "by",
"columnchart", "consume", "contains", "containscs", "count", "date", "datetime", "default", "desc", "distinct",
"double", "dynamic", "endswith", "evaluate", "extend", "false", "filter", "find", "first", "flags", "float",
@@ -41,7 +40,7 @@ namespace Microsoft.Kusto.ServiceLayer.DataSource
"take", "time", "timechart", "timeline", "timepivot", "timespan", "to", "top", "toscalar", "true", "union",
"unstacked", "viewers", "where", "withsource"}; // add more keywords here
var escapeName = rx.IsMatch(name) || kustoKeywordList.Any(name.Contains) || alwaysEscape;
var escapeName = GetNameRegex().IsMatch(name) || kustoKeywordList.Any(name.Contains) || alwaysEscape;
if (escapeName)
{
if (name.IndexOf('"') > -1)
@@ -79,14 +78,14 @@ namespace Microsoft.Kusto.ServiceLayer.DataSource
public static void SafeAdd<T>(this Dictionary<string, Dictionary<string, T>> dictionary, string key,
T metadata) where T : DataSourceObjectMetadata
{
if (dictionary.ContainsKey(key))
if (dictionary.TryGetValue(key, out Dictionary<string, T>? metadataCollection))
{
if (dictionary[key].ContainsKey(metadata.Name))
if (metadataCollection.ContainsKey(metadata.Name))
{
return;
}
dictionary[key].Add(metadata.Name, metadata);
metadataCollection.Add(metadata.Name, metadata);
}
else
{
@@ -97,14 +96,14 @@ namespace Microsoft.Kusto.ServiceLayer.DataSource
public static void SafeAdd<T>(this Dictionary<string, SortedDictionary<string, DataSourceObjectMetadata>> dictionary, string key,
T node) where T : DataSourceObjectMetadata
{
if (dictionary.ContainsKey(key))
if (dictionary.TryGetValue(key, out SortedDictionary<string, DataSourceObjectMetadata>? metadataCollection))
{
if (dictionary[key].ContainsKey(node.PrettyName))
if (metadataCollection.ContainsKey(node.PrettyName))
{
return;
}
dictionary[key].Add(node.PrettyName, node);
metadataCollection.Add(node.PrettyName, node);
}
else
{
@@ -123,9 +122,9 @@ namespace Microsoft.Kusto.ServiceLayer.DataSource
public static void AddRange<T>(this ConcurrentDictionary<string, IEnumerable<T>> dictionary, string key,
List<T> metadatas) where T : DataSourceObjectMetadata
{
if (dictionary.ContainsKey(key))
if (dictionary.TryGetValue(key, out IEnumerable<T>? value))
{
metadatas.AddRange(dictionary[key]);
metadatas.AddRange(value);
}
dictionary[key] = metadatas.OrderBy(x => x.PrettyName, StringComparer.OrdinalIgnoreCase).ToList();
@@ -133,11 +132,16 @@ namespace Microsoft.Kusto.ServiceLayer.DataSource
public static string ParseDatabaseName(string databaseName)
{
var regex = new Regex(@"(?<=\().+?(?=\))");
var regex = GetDatabaseNameRegex();
return regex.IsMatch(databaseName)
? regex.Match(databaseName).Value
: databaseName;
}
[GeneratedRegex("(?<=\\().+?(?=\\))")]
private static partial Regex GetDatabaseNameRegex();
[GeneratedRegex("[^_a-zA-Z0-9]")]
private static partial Regex GetNameRegex();
}
}

View File

@@ -22,7 +22,7 @@ using Microsoft.Kusto.ServiceLayer.Workspace.Contracts;
namespace Microsoft.Kusto.ServiceLayer.DataSource.Monitor
{
public class MonitorDataSource : DataSourceBase
public partial class MonitorDataSource : DataSourceBase
{
private readonly MonitorClient _monitorClient;
private readonly IntellisenseClientBase _intellisenseClient;
@@ -158,7 +158,7 @@ namespace Microsoft.Kusto.ServiceLayer.DataSource.Monitor
private string ParseWorkspaceId(string workspace)
{
var regex = new Regex(@"(?<=\().+?(?=\))");
var regex = GetWorkspaceIdRegex();
return regex.IsMatch(workspace)
? regex.Match(workspace).Value
@@ -227,5 +227,8 @@ namespace Microsoft.Kusto.ServiceLayer.DataSource.Monitor
}
};
}
[GeneratedRegex("(?<=\\().+?(?=\\))")]
private static partial Regex GetWorkspaceIdRegex();
}
}

View File

@@ -198,11 +198,9 @@ namespace Microsoft.Kusto.ServiceLayer.LanguageServices
{
lock (this._bindingContextLock)
{
if (this.BindingContextMap.ContainsKey(key))
if (this.BindingContextMap.TryGetValue(key, out IBindingContext? bindingContext))
{
// disconnect existing connection
var bindingContext = this.BindingContextMap[key];
// remove key from the map
this.BindingContextMap.Remove(key);
this.BindingContextTasks.Remove(bindingContext);

View File

@@ -1011,13 +1011,13 @@ namespace Microsoft.Kusto.ServiceLayer.LanguageServices
/// </summary>
/// <param name="uri"></param>
/// <param name="createIfNotExists">Creates a new instance if one doesn't exist</param>
internal ScriptParseInfo GetScriptParseInfo(string uri, bool createIfNotExists = false)
internal ScriptParseInfo? GetScriptParseInfo(string uri, bool createIfNotExists = false)
{
lock (this.parseMapLock)
{
if (this.ScriptParseInfoMap.ContainsKey(uri))
if (this.ScriptParseInfoMap.TryGetValue(uri, out ScriptParseInfo? scriptParseInfo))
{
return this.ScriptParseInfoMap[uri];
return scriptParseInfo;
}
else if (createIfNotExists)
{
@@ -1091,7 +1091,7 @@ namespace Microsoft.Kusto.ServiceLayer.LanguageServices
}
// If there is a single statement on the line, track it so that we can return it regardless of where the user's cursor is
SqlStatement lineStatement = null;
SqlStatement? lineStatement = null;
bool? lineHasSingleStatement = null;
// check if the batch matches parameters
@@ -1125,7 +1125,7 @@ namespace Microsoft.Kusto.ServiceLayer.LanguageServices
if (lineHasSingleStatement == true)
{
return lineStatement.Sql;
return lineStatement?.Sql ?? string.Empty;
}
}
}

View File

@@ -13,8 +13,8 @@
<PreserveCompilationContext>true</PreserveCompilationContext>
<DebugType>portable</DebugType>
<RuntimeIdentifiers>$(ToolsServiceTargetRuntimes)</RuntimeIdentifiers>
<!-- TODO FIX THESE WARNINGS ASAP -->
<NoWarn>$(NoWarn);SYSLIB1045;CA1311;CA1854</NoWarn>
<!-- False alerts, disabled due to issue: https://github.com/dotnet/roslyn/issues/65850 -->
<NoWarn>$(NoWarn);CS8795</NoWarn>
<AssemblyTitle>SqlTools Kusto Editor Services Host Protocol Library</AssemblyTitle>
<Description>Provides message types and client/server APIs for the SqlTools Kusto Editor Services JSON protocol.</Description>
</PropertyGroup>

View File

@@ -3,6 +3,8 @@
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
#nullable disable
using Microsoft.Kusto.ServiceLayer.QueryExecution.Contracts;
using Microsoft.Kusto.ServiceLayer.QueryExecution.DataStorage;
using Microsoft.Kusto.ServiceLayer.Utility;
@@ -24,7 +26,7 @@ namespace Microsoft.Kusto.ServiceLayer.QueryExecution
/// Class that represents a resultset the was generated from a query. Contains logic for
/// storing and retrieving results. Is contained by a Batch class.
/// </summary>
public class ResultSet : IDisposable
public partial class ResultSet : IDisposable
{
#region Constants
@@ -343,7 +345,7 @@ namespace Microsoft.Kusto.ServiceLayer.QueryExecution
// Verify the request hasn't been cancelled
cancellationToken.ThrowIfCancellationRequested();
StorageDataReader dataReader = new StorageDataReader(dbDataReader);
var dataReader = new StorageDataReader(dbDataReader);
// Open a writer for the file
//
@@ -478,7 +480,7 @@ namespace Microsoft.Kusto.ServiceLayer.QueryExecution
}
// Create the new task
Task saveAsTask = new Task(async () =>
var saveAsTask = new Task(async () =>
{
try
{
@@ -602,7 +604,7 @@ namespace Microsoft.Kusto.ServiceLayer.QueryExecution
//
sendResultsSemphore.Wait();
ResultSet currentResultSetSnapshot = (ResultSet) MemberwiseClone();
var currentResultSetSnapshot = (ResultSet) MemberwiseClone();
if (LastUpdatedSummary == null) // We need to send results available message.
{
// Fire off results Available task and await it
@@ -677,13 +679,12 @@ namespace Microsoft.Kusto.ServiceLayer.QueryExecution
{
if (Columns?.Length > 0 && RowCount != 0)
{
Regex regex = new Regex(@"({.*?})");
var row = GetRow(0);
for (int i = 0; i < Columns.Length; i++)
{
if (Columns[i].DataTypeName.Equals("nvarchar"))
{
if (regex.IsMatch(row[i].DisplayValue))
if (GetJsonRegex().IsMatch(row[i].DisplayValue))
{
Columns[i].IsJson = true;
}
@@ -726,7 +727,7 @@ namespace Microsoft.Kusto.ServiceLayer.QueryExecution
// Returning false from .ReadAsync means there aren't any rows.
// Create a storage data reader, read it, make sure there were results
StorageDataReader dataReader = new StorageDataReader(dbDataReader);
var dataReader = new StorageDataReader(dbDataReader);
if (!await dataReader.ReadAsync(CancellationToken.None))
{
throw new InvalidOperationException(SR.QueryServiceResultSetAddNoRows);
@@ -742,6 +743,9 @@ namespace Microsoft.Kusto.ServiceLayer.QueryExecution
}
}
[GeneratedRegex("({.*?})")]
private static partial Regex GetJsonRegex();
#endregion
}
}

View File

@@ -99,7 +99,7 @@ namespace Microsoft.Kusto.ServiceLayer.Scripting
// Leaving the server name blank will automatically match whatever the server SMO is running against.
string urn = string.Format(
"Server[@Name='{0}']/Database[@Name='{1}']/{2}[@Name='{3}' {4}]",
server.ToUpper(),
server.ToUpper(System.Globalization.CultureInfo.InvariantCulture),
Urn.EscapeString(database),
scriptingObject.Type,
Urn.EscapeString(scriptingObject.Name),

View File

@@ -32,12 +32,6 @@ namespace Microsoft.Kusto.ServiceLayer.Utility
public bool CanReadFromDisk { get; private set; }
public string LowercaseClientUri
{
get
{
return ClientUri?.ToLower();
}
}
public string LowercaseClientUri => ClientUri?.ToLower(System.Globalization.CultureInfo.InvariantCulture);
}
}

View File

@@ -14,11 +14,11 @@ namespace Microsoft.Kusto.ServiceLayer.Utility.SqlScriptFormatters
/// <summary>
/// Provides utilities for converting from SQL script syntax into POCOs.
/// </summary>
public static class FromSqlScript
public static partial class FromSqlScript
{
// Regex: optionally starts with N, captures string wrapped in single quotes
private static readonly Regex StringRegex = new Regex("^N?'(.*)'$", RegexOptions.Compiled);
private static readonly Regex BracketRegex = new Regex(@"^\[(.*)\]$", RegexOptions.Compiled);
private static readonly Regex StringRegex = GetStringRegex();
private static readonly Regex BracketRegex = GetBracketRegex();
/// <summary>
/// Decodes a multipart identifier as used in a SQL script into an array of the multiple
@@ -33,8 +33,8 @@ namespace Microsoft.Kusto.ServiceLayer.Utility.SqlScriptFormatters
/// </exception>
public static string[] DecodeMultipartIdentifier(string multipartIdentifier)
{
StringBuilder sb = new StringBuilder();
List<string> namedParts = new List<string>();
var sb = new StringBuilder();
var namedParts = new List<string>();
bool insideBrackets = false;
bool bracketsClosed = false;
for (int i = 0; i < multipartIdentifier.Length; i++)
@@ -152,6 +152,11 @@ namespace Microsoft.Kusto.ServiceLayer.Utility.SqlScriptFormatters
return value.Replace(new string(escapeCharacter, 2), escapeCharacter.ToString());
}
[GeneratedRegex("^N?'(.*)'$", RegexOptions.Compiled)]
private static partial Regex GetStringRegex();
[GeneratedRegex("^\\[(.*)\\]$", RegexOptions.Compiled)]
private static partial Regex GetBracketRegex();
#endregion
}
}

View File

@@ -25,7 +25,7 @@ namespace Microsoft.Kusto.ServiceLayer.Workspace.Contracts
/// </summary>
public string Id
{
get { return this.ClientUri.ToLower(); }
get { return this.ClientUri.ToLower(System.Globalization.CultureInfo.InvariantCulture); }
}
/// <summary>

View File

@@ -21,7 +21,7 @@ namespace Microsoft.Kusto.ServiceLayer.Workspace
/// Manages a "workspace" of script files that are open for a particular
/// editing session. Also helps to navigate references between ScriptFiles.
/// </summary>
public class Workspace : IDisposable
public partial class Workspace : IDisposable
{
#region Private Fields
@@ -115,8 +115,8 @@ namespace Microsoft.Kusto.ServiceLayer.Workspace
}
// This method allows FileNotFoundException to bubble up
// if the file isn't found.
using (FileStream fileStream = new FileStream(resolvedFile.FilePath, FileMode.Open, FileAccess.Read))
using (StreamReader streamReader = new StreamReader(fileStream, Encoding.UTF8))
using (var fileStream = new FileStream(resolvedFile.FilePath, FileMode.Open, FileAccess.Read))
using (var streamReader = new StreamReader(fileStream, Encoding.UTF8))
{
scriptFile = new ScriptFile(resolvedFile.FilePath, resolvedFile.ClientUri,streamReader);
@@ -148,7 +148,7 @@ namespace Microsoft.Kusto.ServiceLayer.Workspace
// Client sent the path in URI format, extract the local path and trim
// any extraneous slashes
Uri fileUri = new Uri(clientUri);
var fileUri = new Uri(clientUri);
filePath = fileUri.LocalPath;
if (filePath.StartsWith("//") || filePath.StartsWith("\\\\") || filePath.StartsWith("/"))
{
@@ -206,7 +206,7 @@ namespace Microsoft.Kusto.ServiceLayer.Workspace
return path;
}
return Regex.Replace(path, @"`(?=[ \[\]])", "");
return GetEscapeRegex().Replace(path, "");
}
/// <summary>
@@ -361,6 +361,9 @@ namespace Microsoft.Kusto.ServiceLayer.Workspace
{
}
[GeneratedRegex("`(?=[ \\[\\]])")]
private static partial Regex GetEscapeRegex();
#endregion
}
}

View File

@@ -1,45 +1,47 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<AssemblyName>MicrosoftSqlToolsCredentials</AssemblyName>
<OutputType>Exe</OutputType>
<EnableDefaultItems>false</EnableDefaultItems>
<ValidateExecutableReferencesMatchSelfContained>false</ValidateExecutableReferencesMatchSelfContained>
<EnableDefaultCompileItems>false</EnableDefaultCompileItems>
<EnableDefaultEmbeddedResourceItems>false</EnableDefaultEmbeddedResourceItems>
<EmbeddedResourceUseDependentUponConvention>false</EmbeddedResourceUseDependentUponConvention>
<EnableDefaultNoneItems>false</EnableDefaultNoneItems>
<DefineConstants>$(DefineConstants);NETCOREAPP1_0</DefineConstants>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<PreserveCompilationContext>true</PreserveCompilationContext>
<RuntimeIdentifiers>$(ToolsServiceTargetRuntimes)</RuntimeIdentifiers>
<AssemblyTitle>SqlTools Editor Services Credentials Manager Library</AssemblyTitle>
<Description>Provides message types and client/server APIs for the SqlTools Credential Services JSON protocol.</Description>
<!-- TODO FIX THESE WARNINGS ASAP -->
<PropertyGroup>
<AssemblyName>MicrosoftSqlToolsCredentials</AssemblyName>
<OutputType>Exe</OutputType>
<EnableDefaultItems>false</EnableDefaultItems>
<ValidateExecutableReferencesMatchSelfContained>false</ValidateExecutableReferencesMatchSelfContained>
<EnableDefaultCompileItems>false</EnableDefaultCompileItems>
<EnableDefaultEmbeddedResourceItems>false</EnableDefaultEmbeddedResourceItems>
<EmbeddedResourceUseDependentUponConvention>false</EmbeddedResourceUseDependentUponConvention>
<EnableDefaultNoneItems>false</EnableDefaultNoneItems>
<DefineConstants>$(DefineConstants);NETCOREAPP1_0</DefineConstants>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<PreserveCompilationContext>true</PreserveCompilationContext>
<RuntimeIdentifiers>$(ToolsServiceTargetRuntimes)</RuntimeIdentifiers>
<AssemblyTitle>SqlTools Editor Services Credentials Manager Library</AssemblyTitle>
<Description>Provides message types and client/server APIs for the SqlTools Credential Services JSON protocol.</Description>
<!-- SYSLIB1054: Use LibraryImportAttribute instead of DllImportAttribute to generate p/invoke marshalling code at compile time.
This is a Diagnostic Alert .NET 7 onwards.Changing to LibraryImportAttribute would require additional code changes,
therefore this warning is suppressed.-->
<NoWarn>$(NoWarn);SYSLIB1054</NoWarn>
</PropertyGroup>
<ItemGroup>
<Compile Include="**\*.cs" Exclude="**/obj/**/*.cs" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Newtonsoft.Json"/>
<PackageReference Include="Microsoft.Extensions.DependencyModel" />
<PackageReference Include="System.IO.Packaging" />
<PackageReference Include="System.Runtime.Loader" />
<PackageReference Include="System.Composition" />
<PackageReference Include="System.Security.Permissions" />
<PackageReference Include="System.Text.Encoding.CodePages"/>
<PackageReference Include="System.Reactive.Core" />
</ItemGroup>
<ItemGroup>
<InternalsVisibleTo Include="Microsoft.SqlTools.ServiceLayer.UnitTests" />
<InternalsVisibleTo Include="Microsoft.SqlTools.ServiceLayer.IntegrationTests" />
<InternalsVisibleTo Include="Microsoft.SqlTools.ServiceLayer.Test.Common" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="../Microsoft.SqlTools.Hosting/Microsoft.SqlTools.Hosting.csproj" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Localization\*.resx" />
<None Include="Localization\sr.strings" />
</ItemGroup>
</PropertyGroup>
<ItemGroup>
<Compile Include="**\*.cs" Exclude="**/obj/**/*.cs" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Newtonsoft.Json"/>
<PackageReference Include="Microsoft.Extensions.DependencyModel" />
<PackageReference Include="System.IO.Packaging" />
<PackageReference Include="System.Runtime.Loader" />
<PackageReference Include="System.Composition" />
<PackageReference Include="System.Security.Permissions" />
<PackageReference Include="System.Text.Encoding.CodePages"/>
<PackageReference Include="System.Reactive.Core" />
</ItemGroup>
<ItemGroup>
<InternalsVisibleTo Include="Microsoft.SqlTools.ServiceLayer.UnitTests" />
<InternalsVisibleTo Include="Microsoft.SqlTools.ServiceLayer.IntegrationTests" />
<InternalsVisibleTo Include="Microsoft.SqlTools.ServiceLayer.Test.Common" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="../Microsoft.SqlTools.Hosting/Microsoft.SqlTools.Hosting.csproj" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Localization\*.resx" />
<None Include="Localization\sr.strings" />
</ItemGroup>
</Project>

View File

@@ -408,7 +408,7 @@ namespace Microsoft.SqlTools.ServiceLayer.BatchParser
/// <summary>
/// Internal implementation class to implement IBatchEventHandlers
/// </summary>
internal class BatchEventNotificationHandler : IBatchEventsHandler
internal sealed class BatchEventNotificationHandler : IBatchEventsHandler
{
public void OnBatchError(object sender, BatchErrorEventArgs args)
{
@@ -477,7 +477,7 @@ namespace Microsoft.SqlTools.ServiceLayer.BatchParser
}
#endregion
private class BatchInfo
private sealed class BatchInfo
{
public BatchInfo(int startLine, int startColumn, string batchText, SqlCmdCommand sqlCmdCommand, int repeatCount = 1)
{

View File

@@ -32,7 +32,7 @@
<Version>$(VersionPrefix)</Version>
<FileVersion>$(VersionPrefix)</FileVersion>
<InformationalVersion>$(VersionPrefix)</InformationalVersion>
<!-- TODO FIX THESE WARNINGS ASAP -->
<!-- Disable CA1852 (Seal internal types) as it depends on SrGen Tool -->
<NoWarn>$(NoWarn);CA1852</NoWarn>
</PropertyGroup>
<ItemGroup>

View File

@@ -374,7 +374,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Connection.ReliableConnection
/// <summary>
/// This class is used as value in the dictionary to ensure that the type of value is correct.
/// </summary>
private class AmbientValue
private sealed class AmbientValue
{
private readonly Type _type;
private readonly bool _isTypeNullable;

View File

@@ -45,7 +45,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Connection.ReliableConnection
}
#region CacheKey implementation
internal class CacheKey : IEquatable<CacheKey>
internal sealed class CacheKey : IEquatable<CacheKey>
{
private string dataSource;
private string dbName;

View File

@@ -407,7 +407,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Connection.ReliableConnection
}
}
internal class ExponentialDelayRetryPolicy : RetryPolicy
internal sealed class ExponentialDelayRetryPolicy : RetryPolicy
{
private readonly int _maxRetryCount;
private readonly double _intervalFactor;

View File

@@ -10,7 +10,7 @@
<StartupObject />
<Description>Provides the default for SqlTools applications.</Description>
<Copyright><EFBFBD> Microsoft Corporation. All rights reserved.</Copyright>
<!-- TODO FIX THESE WARNINGS ASAP -->
<!-- Disable CA1852 (Seal internal types) as it depends on SrGen Tool -->
<NoWarn>$(NoWarn);CA1852</NoWarn>
</PropertyGroup>
<ItemGroup>

View File

@@ -12,15 +12,15 @@
<EnableDefaultEmbeddedResourceItems>false</EnableDefaultEmbeddedResourceItems>
<EmbeddedResourceUseDependentUponConvention>false</EmbeddedResourceUseDependentUponConvention>
<RuntimeIdentifiers>$(ToolsServiceTargetRuntimes)</RuntimeIdentifiers>
<!-- TODO FIX THESE WARNINGS ASAP -->
<NoWarn>$(NoWarn);CA1852</NoWarn>
<!-- Disable CA1852 (Seal internal types) as it depends on SrGen Tool -->
<NoWarn>$(NoWarn);CA1852</NoWarn>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<DefineConstants>TRACE;DEBUG;NETCOREAPP1_0;NETCOREAPP2_0</DefineConstants>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="System.Text.Encoding.CodePages"/>
<PackageReference Include="System.Text.Encoding.CodePages" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Microsoft.SqlTools.Hosting\Microsoft.SqlTools.Hosting.csproj" />

View File

@@ -16,7 +16,7 @@ namespace Microsoft.SqlTools.ResourceProvider
/// <summary>
/// Main application class for the executable that supports the resource provider and identity services
/// </summary>
internal class Program
internal sealed class Program
{
private const string ServiceName = "SqlToolsResourceProviderService.exe";

View File

@@ -3,8 +3,6 @@
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
#nullable disable
using System;
using System.Collections.Generic;
using System.Diagnostics;
@@ -51,9 +49,9 @@ namespace Microsoft.SqlTools.ServiceLayer.Admin
return Name.GetHashCode();
}
public override bool Equals(object obj)
public override bool Equals(object? obj)
{
return obj is AzureEdition && ((AzureEdition)obj).Name.Equals(Name);
return obj is AzureEdition edition && edition.Name.Equals(Name);
}
public static bool operator ==(AzureEdition left, AzureEdition right)
@@ -82,7 +80,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Admin
var azureEdition =
AzureServiceObjectiveInfo.Keys.FirstOrDefault(
key => key.Name.ToLowerInvariant().Equals(edition.ToLowerInvariant()));
if (azureEdition != null)
if (azureEdition! != null)
{
return azureEdition;
}
@@ -358,9 +356,9 @@ namespace Microsoft.SqlTools.ServiceLayer.Admin
/// <returns>StorageAccountType string value for the current storageType</returns>
public static string GetStorageAccountTypeFromString(string storageAccountType)
{
if (bsrAPIToUIValueMapping.ContainsKey(storageAccountType))
if (bsrAPIToUIValueMapping.TryGetValue(storageAccountType, out string? value))
{
return bsrAPIToUIValueMapping[storageAccountType];
return value;
}
return storageAccountType;
}

View File

@@ -1100,7 +1100,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Agent
}
const string UrnFormatStr = "Server/JobServer[@Name='{0}']/Job[@Name='{1}']/Schedule[@Name='{2}']";
string serverName = dataContainer.Server.Name.ToUpper();
string serverName = dataContainer.Server.Name.ToUpper(System.Globalization.CultureInfo.InvariantCulture);
string scheduleUrn = string.Format(UrnFormatStr, serverName, jobData.Job.Name, schedule.Name);
STParameters param = new STParameters(dataContainer.Document);
@@ -1132,7 +1132,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Agent
ConnectionServiceInstance.TryFindConnection(ownerUri, out connInfo);
dataContainer = CDataContainer.CreateDataContainer(connInfo, databaseExists: true);
XmlDocument jobDoc = CreateJobXmlDocument(dataContainer.Server.Name.ToUpper(), jobName);
XmlDocument jobDoc = CreateJobXmlDocument(dataContainer.Server.Name.ToUpper(System.Globalization.CultureInfo.InvariantCulture), jobName);
dataContainer.Init(jobDoc.InnerXml);
STParameters param = new STParameters(dataContainer.Document);
@@ -1487,9 +1487,9 @@ namespace Microsoft.SqlTools.ServiceLayer.Agent
{
string jobRuntime = jobHistory.RunDate.ToString("yyyyMMddHHmmss");
AgentNotebookHistoryInfo notebookHistory = jobHistory;
if (notebookHistoriesDict.ContainsKey(jobRuntime))
if (notebookHistoriesDict.TryGetValue(jobRuntime, out DataRow dataRow))
{
notebookHistory.MaterializedNotebookId = (int)notebookHistoriesDict[jobRuntime]["materialized_id"];
notebookHistory.MaterializedNotebookId = (int)dataRow["materialized_id"];
notebookHistory.MaterializedNotebookErrorInfo = notebookHistoriesDict[jobRuntime]["notebook_error"] as string;
notebookHistory.MaterializedNotebookName = notebookHistoriesDict[jobRuntime]["notebook_name"] as string;
notebookHistory.MaterializedNotebookPin = (bool)notebookHistoriesDict[jobRuntime]["pin"];

View File

@@ -3,8 +3,6 @@
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
#nullable disable
using System;
using System.Collections.Generic;
using System.ComponentModel;
@@ -32,54 +30,56 @@ namespace Microsoft.SqlTools.ServiceLayer.Agent
{
this.data = data;
var availableSystems =
dataContainer.Server.JobServer.EnumSubSystems()
dataContainer.Server?.JobServer.EnumSubSystems()
.Rows.OfType<DataRow>()
.Select(r => (AgentSubSystem)Convert.ToInt32(r["subsystem_id"]));
foreach (var agentSubSystemId in availableSystems)
if (availableSystems != null)
{
var agentSubSystem = CreateJobStepSubSystem(agentSubSystemId, dataContainer, data);
// The server might have some new subsystem we don't know about, just ignore it.
if (agentSubSystem != null)
foreach (var agentSubSystemId in availableSystems)
{
subSystems[agentSubSystemId] = agentSubSystem;
var agentSubSystem = CreateJobStepSubSystem(agentSubSystemId, dataContainer, data);
// The server might have some new subsystem we don't know about, just ignore it.
if (agentSubSystem != null)
{
subSystems[agentSubSystemId] = agentSubSystem;
}
}
}
}
}
public JobStepSubSystem[] AvailableSubSystems
{
get { return this.subSystems.Keys.OrderBy(k => (int) k).Select(k => this.subSystems[k]).ToArray(); }
get { return this.subSystems.Keys.OrderBy(k => (int)k).Select(k => this.subSystems[k]).ToArray(); }
}
public JobStepSubSystem Lookup(AgentSubSystem key)
{
JobStepSubSystem rv = null;
if (this.subSystems.ContainsKey(key))
if (this.subSystems.TryGetValue(key, out JobStepSubSystem? value))
{
return this.subSystems[key];
return value;
}
return rv;
}
private static TypeConverter typeConverter = TypeDescriptor.GetConverter(typeof (AgentSubSystem));
private static TypeConverter typeConverter = TypeDescriptor.GetConverter(typeof(AgentSubSystem));
// Returns name of the subsystem for a given enum value
public static string LookupFriendlyName(AgentSubSystem key)
{
return (string)typeConverter.ConvertToString((Enum)key);
}
// Returns name of the subsystem for a given enum value
public static string LookupName(AgentSubSystem key)
{
// Have to subtract first enum value to bring the
// index to 0-based index
return typeConverter.ConvertToInvariantString((Enum) key);
return typeConverter.ConvertToInvariantString((Enum)key);
}
private static JobStepSubSystem CreateJobStepSubSystem(
AgentSubSystem agentSubSystem,
CDataContainer dataContainer,
AgentSubSystem agentSubSystem,
CDataContainer dataContainer,
JobStepData data)
{
switch (agentSubSystem)

View File

@@ -95,7 +95,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Agent
if (jobData.Job != null)
{
const string UrnFormatStr = "Server/JobServer[@Name='{0}']/Job[@Name='{1}']/Step[@Name='{2}']";
string serverName = this.DataContainer.Server.Name.ToUpper();
string serverName = this.DataContainer.Server.Name.ToUpper(System.Globalization.CultureInfo.InvariantCulture);
string urn = string.Format(UrnFormatStr, serverName, jobData.Job.Name, stepName);
jobStep = jobData.Job.Parent.Parent.GetSmoObject(urn) as JobStep;
}

View File

@@ -24,7 +24,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Agent
/// simple job schedule structure.
/// </summary>
public struct SimpleJobSchedule
public partial struct SimpleJobSchedule
{
#region consts
private const int EndOfDay = 235959;
@@ -44,7 +44,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Agent
private FrequencyTypes frequencyTypes;
private FrequencySubDayTypes frequencySubDayTypes;
private FrequencyRelativeIntervals frequencyRelativeIntervals;
private System.Boolean isEnabled;
private bool isEnabled;
#endregion
#region Init
@@ -100,7 +100,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Agent
public static DateTime ConvertIntToDateTime(int source)
{
return new DateTime(source / 10000
, (source / 100) % 100
, source / 100 % 100
, source % 100);
}
/// <summary>
@@ -126,7 +126,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Agent
public static TimeSpan ConvertIntToTimeSpan(int source)
{
return new TimeSpan(source / 10000
, (source / 100) % 100
, source / 100 % 100
, source % 100);
}
/// <summary>
@@ -150,13 +150,13 @@ namespace Microsoft.SqlTools.ServiceLayer.Agent
/// <returns>JobScheduleData object</returns>
public JobScheduleData ToJobScheduleData()
{
JobScheduleData data = new JobScheduleData();
var data = new JobScheduleData();
data.Name = this.Name;
data.Enabled = this.IsEnabled;
data.ActiveStartDate = SimpleJobSchedule.ConvertIntToDateLocalized(this.ActiveStartDate);
data.ActiveStartTime = SimpleJobSchedule.ConvertIntToTimeSpan(this.ActiveStartTimeOfDay);
data.ActiveEndDate = SimpleJobSchedule.ConvertIntToDateLocalized(this.ActiveEndDate);
data.ActiveEndTime = SimpleJobSchedule.ConvertIntToTimeSpan(this.ActiveEndTimeOfDay);
data.ActiveStartDate = ConvertIntToDateLocalized(this.ActiveStartDate);
data.ActiveStartTime = ConvertIntToTimeSpan(this.ActiveStartTimeOfDay);
data.ActiveEndDate = ConvertIntToDateLocalized(this.ActiveEndDate);
data.ActiveEndTime = ConvertIntToTimeSpan(this.ActiveEndTimeOfDay);
data.FrequencyTypes = this.FrequencyTypes;
data.FrequencyInterval = this.FrequencyInterval;
data.FrequencyRecurranceFactor = this.FrequencyRecurrenceFactor;
@@ -173,15 +173,15 @@ namespace Microsoft.SqlTools.ServiceLayer.Agent
/// <returns>new SimpleJobSchedule</returns>
public static SimpleJobSchedule FromJobScheduleData(JobScheduleData source)
{
SimpleJobSchedule schedule = new SimpleJobSchedule();
var schedule = new SimpleJobSchedule();
schedule.Name = source.Name;
schedule.ID = source.ID;
schedule.IsEnabled = source.Enabled;
schedule.ActiveStartDate = SimpleJobSchedule.ConvertDateTimeToInt(source.ActiveStartDate);
schedule.ActiveStartTimeOfDay = SimpleJobSchedule.ConvertTimeSpanToInt(source.ActiveStartTime);
schedule.ActiveEndDate = SimpleJobSchedule.ConvertDateTimeToInt(source.ActiveEndDate);
schedule.ActiveEndTimeOfDay = SimpleJobSchedule.ConvertTimeSpanToInt(source.ActiveEndTime);
schedule.ActiveStartDate = ConvertDateTimeToInt(source.ActiveStartDate);
schedule.ActiveStartTimeOfDay = ConvertTimeSpanToInt(source.ActiveStartTime);
schedule.ActiveEndDate = ConvertDateTimeToInt(source.ActiveEndDate);
schedule.ActiveEndTimeOfDay = ConvertTimeSpanToInt(source.ActiveEndTime);
schedule.FrequencyTypes = source.FrequencyTypes;
schedule.FrequencyInterval = source.FrequencyInterval;
schedule.FrequencyRecurrenceFactor = source.FrequencyRecurranceFactor;
@@ -293,7 +293,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Agent
return string.Empty;
}
StringBuilder daysOfWeek = new StringBuilder();
var daysOfWeek = new StringBuilder();
// Start matching with Monday. GetLocalizedDaysOfWeek() must start with Monday too.
WeekDays dayOfWeek = WeekDays.Monday;
foreach (string localizedDayOfWeek in GetLocalizedDaysOfWeek())
@@ -309,7 +309,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Agent
// There's no easy way to advance to the next enum value, so since we know
// it's a bitfield mask we do a left shift ourselves.
int nextDay = ((int)dayOfWeek) << 1;
int nextDay = (int)dayOfWeek << 1;
dayOfWeek = (WeekDays)nextDay;
if (dayOfWeek > WeekDays.Saturday)
{
@@ -449,7 +449,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Agent
{
get
{
MonthlyRelativeWeekDays relativeDays = (MonthlyRelativeWeekDays) this.FrequencyInterval;
var relativeDays = (MonthlyRelativeWeekDays) this.FrequencyInterval;
switch (relativeDays)
{
@@ -671,10 +671,10 @@ namespace Microsoft.SqlTools.ServiceLayer.Agent
/// <returns></returns>
string ExpandFormatString(string format)
{
StringBuilder stringBuilder = new StringBuilder();
var stringBuilder = new StringBuilder();
int lastIndex = 0;
MatchCollection matches = Regex.Matches(format, @"\{(?<property>\w+)\}");
MatchCollection matches = GetPropertyDescriptorRegex().Matches(format);
if (matches.Count > 0)
{
@@ -687,7 +687,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Agent
if (property != null)
{
object propertyValue = property.GetValue(this);
propertyValue = propertyValue != null ? propertyValue.ToString() : String.Empty;
propertyValue = propertyValue != null ? propertyValue.ToString() : string.Empty;
stringBuilder.Append(format.Substring(lastIndex, match.Index - lastIndex));
stringBuilder.Append(propertyValue as string);
@@ -705,6 +705,9 @@ namespace Microsoft.SqlTools.ServiceLayer.Agent
return new string[] { "SR.Monday", "SR.Tuesday", "SR.Wednesday", "SR.Thursday", "SR.Friday", "SR.Saturday", "SR.Sunday" };
}
[GeneratedRegex("\\{(?<property>\\w+)\\}")]
private static partial Regex GetPropertyDescriptorRegex();
#endregion
}

View File

@@ -102,7 +102,7 @@ namespace Microsoft.SqlTools.ServiceLayer.AzureFunctions
return a.ArgumentList
?.Arguments
.Where(a => a.Expression.Kind() == SyntaxKind.StringLiteralExpression && a.NameEquals == null) // Operations are string literals who don't have a name (Route is always a named param)
.Select(a => a.ToString().TrimStringQuotes().ToUpper()) // upper case for consistent naming
.Select(a => a.ToString().TrimStringQuotes().ToUpper(System.Globalization.CultureInfo.InvariantCulture)) // upper case for consistent naming
.ToArray();
}

View File

@@ -1420,7 +1420,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Connection
{
// Secure Enclaves is not mapped to SqlConnection, it's only used for throwing validation errors
// when Enclave Attestation Protocol is missing.
switch (connectionDetails.SecureEnclaves.ToUpper())
switch (connectionDetails.SecureEnclaves.ToUpper(CultureInfo.InvariantCulture))
{
case "ENABLED":
if (string.IsNullOrEmpty(connectionDetails.EnclaveAttestationProtocol))
@@ -1437,7 +1437,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Connection
if (!string.IsNullOrEmpty(connectionDetails.EnclaveAttestationProtocol))
{
if (connectionBuilder.ColumnEncryptionSetting != SqlConnectionColumnEncryptionSetting.Enabled
|| string.IsNullOrEmpty(connectionDetails.SecureEnclaves) || connectionDetails.SecureEnclaves.ToUpper() == "DISABLED")
|| string.IsNullOrEmpty(connectionDetails.SecureEnclaves) || connectionDetails.SecureEnclaves.ToUpper(CultureInfo.InvariantCulture) == "DISABLED")
{
throw new ArgumentException(SR.ConnectionServiceConnStringInvalidAlwaysEncryptedOptionCombination);
}
@@ -1454,7 +1454,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Connection
if (!string.IsNullOrEmpty(connectionDetails.EnclaveAttestationUrl))
{
if (connectionBuilder.ColumnEncryptionSetting != SqlConnectionColumnEncryptionSetting.Enabled
|| string.IsNullOrEmpty(connectionDetails.SecureEnclaves) || connectionDetails.SecureEnclaves.ToUpper() == "DISABLED")
|| string.IsNullOrEmpty(connectionDetails.SecureEnclaves) || connectionDetails.SecureEnclaves.ToUpper(CultureInfo.InvariantCulture) == "DISABLED")
{
throw new ArgumentException(SR.ConnectionServiceConnStringInvalidAlwaysEncryptedOptionCombination);
}

View File

@@ -65,7 +65,7 @@ namespace Microsoft.SqlTools.ServiceLayer.DacFx
/// </summary>
public static ModelTypeClass MapType(string type)
{
switch (type.ToLower())
switch (type.ToLower(System.Globalization.CultureInfo.InvariantCulture))
{
case "table":
return ModelSchema.Table;

View File

@@ -3,8 +3,6 @@
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
#nullable disable
using System;
using System.Collections.Generic;
using System.Diagnostics;
@@ -49,9 +47,9 @@ namespace Microsoft.SqlTools.ServiceLayer.DisasterRecovery.RestoreOperation
/// <returns></returns>
public RestorePlanDetailInfo CreateOptionInfo(string optionKey, IRestoreDatabaseTaskDataObject restoreDataObject)
{
if(optionBuilders.ContainsKey(optionKey))
if (optionBuilders.TryGetValue(optionKey, out OptionBuilder? value))
{
return Create(optionKey, restoreDataObject, optionBuilders[optionKey]);
return Create(optionKey, restoreDataObject, value);
}
else
{
@@ -68,9 +66,9 @@ namespace Microsoft.SqlTools.ServiceLayer.DisasterRecovery.RestoreOperation
/// <param name="optionInfo"></param>
public void UpdateOption(string optionKey, IRestoreDatabaseTaskDataObject restoreDataObject, RestorePlanDetailInfo optionInfo)
{
if (optionBuilders.ContainsKey(optionKey))
if (optionBuilders.TryGetValue(optionKey, out OptionBuilder? value))
{
var builder = optionBuilders[optionKey];
var builder = value;
var currentValue = builder.CurrentValueFunction(restoreDataObject);
var defaultValue = builder.DefaultValueFunction(restoreDataObject);
var validateResult = builder.ValidateFunction(restoreDataObject, currentValue, defaultValue);
@@ -102,9 +100,8 @@ namespace Microsoft.SqlTools.ServiceLayer.DisasterRecovery.RestoreOperation
{
if (restoreDataObject != null)
{
if (optionBuilders.ContainsKey(optionKey))
if (optionBuilders.TryGetValue(optionKey, out OptionBuilder? builder))
{
var builder = optionBuilders[optionKey];
if (restoreDataObject.RestoreParams != null && restoreDataObject.RestoreParams.Options.ContainsKey(optionKey))
{
try
@@ -149,15 +146,14 @@ namespace Microsoft.SqlTools.ServiceLayer.DisasterRecovery.RestoreOperation
public string ValidateOption(string optionKey, IRestoreDatabaseTaskDataObject restoreDataObject)
{
string errorMessage = string.Empty;
if (optionBuilders.ContainsKey(optionKey))
if (optionBuilders.TryGetValue(optionKey, out OptionBuilder? builder))
{
var builder = optionBuilders[optionKey];
var currentValue = builder.CurrentValueFunction(restoreDataObject);
var defaultValue = builder.DefaultValueFunction(restoreDataObject);
OptionValidationResult result = optionBuilders[optionKey].ValidateFunction(restoreDataObject, currentValue, defaultValue);
if (result.IsReadOnly)
{
if(!ValueEqualsDefault(currentValue, defaultValue))
if (!ValueEqualsDefault(currentValue, defaultValue))
{
builder.SetValueFunction(restoreDataObject, defaultValue);
errorMessage = $"{optionKey} is ready only and cannot be modified";
@@ -180,15 +176,11 @@ namespace Microsoft.SqlTools.ServiceLayer.DisasterRecovery.RestoreOperation
private bool ValueEqualsDefault(object currentValue, object defaultValue)
{
if(currentValue == null && defaultValue == null)
if (currentValue == null)
{
return true;
return defaultValue == null;
}
if(currentValue == null && defaultValue != null)
{
return false;
}
if (currentValue != null && defaultValue == null)
else if (defaultValue == null)
{
return false;
}
@@ -200,311 +192,311 @@ namespace Microsoft.SqlTools.ServiceLayer.DisasterRecovery.RestoreOperation
{
Register(RestoreOptionsHelper.RelocateDbFiles,
new OptionBuilder
{
DefaultValueFunction = (IRestoreDatabaseTaskDataObject restoreDataObject) =>
(
defaultValueFunction: (IRestoreDatabaseTaskDataObject restoreDataObject) =>
{
return false;
},
CurrentValueFunction = (IRestoreDatabaseTaskDataObject restoreDataObject) =>
currentValueFunction: (IRestoreDatabaseTaskDataObject restoreDataObject) =>
{
return restoreDataObject.RelocateAllFiles;
},
ValidateFunction = (IRestoreDatabaseTaskDataObject restoreDataObject, object currentValue, object defaultValue) =>
validateFunction: (IRestoreDatabaseTaskDataObject restoreDataObject, object currentValue, object defaultValue) =>
{
return new OptionValidationResult
{
IsReadOnly = restoreDataObject.DbFiles.Count == 0
};
},
SetValueFunction = (IRestoreDatabaseTaskDataObject restoreDataObject, object value) =>
setValueFunction: (IRestoreDatabaseTaskDataObject restoreDataObject, object value) =>
{
restoreDataObject.RelocateAllFiles = restoreDataObject.RestoreParams.GetOptionValue<bool>(RestoreOptionsHelper.RelocateDbFiles);
return true;
}
});
));
Register(RestoreOptionsHelper.DataFileFolder,
new OptionBuilder
{
DefaultValueFunction = (IRestoreDatabaseTaskDataObject restoreDataObject) =>
(
defaultValueFunction: (IRestoreDatabaseTaskDataObject restoreDataObject) =>
{
return restoreDataObject.DefaultDataFileFolder;
},
CurrentValueFunction = (IRestoreDatabaseTaskDataObject restoreDataObject) =>
currentValueFunction: (IRestoreDatabaseTaskDataObject restoreDataObject) =>
{
return restoreDataObject.DataFilesFolder;
},
ValidateFunction = (IRestoreDatabaseTaskDataObject restoreDataObject, object currentValue, object defaultValue) =>
validateFunction: (IRestoreDatabaseTaskDataObject restoreDataObject, object currentValue, object defaultValue) =>
{
return new OptionValidationResult
{
IsReadOnly = !restoreDataObject.RelocateAllFiles
};
},
SetValueFunction = (IRestoreDatabaseTaskDataObject restoreDataObject, object value) =>
setValueFunction: (IRestoreDatabaseTaskDataObject restoreDataObject, object value) =>
{
restoreDataObject.DataFilesFolder = GetValueAs<string>(value);
return true;
}
});
));
Register(RestoreOptionsHelper.LogFileFolder,
new OptionBuilder
{
DefaultValueFunction = (IRestoreDatabaseTaskDataObject restoreDataObject) =>
(
defaultValueFunction: (IRestoreDatabaseTaskDataObject restoreDataObject) =>
{
return restoreDataObject.DefaultLogFileFolder;
},
CurrentValueFunction = (IRestoreDatabaseTaskDataObject restoreDataObject) =>
currentValueFunction: (IRestoreDatabaseTaskDataObject restoreDataObject) =>
{
return restoreDataObject.LogFilesFolder;
},
ValidateFunction = (IRestoreDatabaseTaskDataObject restoreDataObject, object currentValue, object defaultValue) =>
validateFunction: (IRestoreDatabaseTaskDataObject restoreDataObject, object currentValue, object defaultValue) =>
{
return new OptionValidationResult
{
IsReadOnly = !restoreDataObject.RelocateAllFiles
};
},
SetValueFunction = (IRestoreDatabaseTaskDataObject restoreDataObject, object value) =>
setValueFunction: (IRestoreDatabaseTaskDataObject restoreDataObject, object value) =>
{
restoreDataObject.LogFilesFolder = GetValueAs<string>(value);
return true;
}
});
));
Register(RestoreOptionsHelper.ReplaceDatabase,
new OptionBuilder
{
DefaultValueFunction = (IRestoreDatabaseTaskDataObject restoreDataObject) =>
(
defaultValueFunction: (IRestoreDatabaseTaskDataObject restoreDataObject) =>
{
return false;
},
CurrentValueFunction = (IRestoreDatabaseTaskDataObject restoreDataObject) =>
currentValueFunction: (IRestoreDatabaseTaskDataObject restoreDataObject) =>
{
return restoreDataObject.RestoreOptions.ReplaceDatabase;
},
ValidateFunction = (IRestoreDatabaseTaskDataObject restoreDataObject, object currentValue, object defaultValue) =>
validateFunction: (IRestoreDatabaseTaskDataObject restoreDataObject, object currentValue, object defaultValue) =>
{
return new OptionValidationResult();
},
SetValueFunction = (IRestoreDatabaseTaskDataObject restoreDataObject, object value) =>
setValueFunction: (IRestoreDatabaseTaskDataObject restoreDataObject, object value) =>
{
restoreDataObject.RestoreOptions.ReplaceDatabase = GetValueAs<bool>(value);
return true;
}
});
));
Register(RestoreOptionsHelper.KeepReplication,
new OptionBuilder
{
DefaultValueFunction = (IRestoreDatabaseTaskDataObject restoreDataObject) =>
(
defaultValueFunction: (IRestoreDatabaseTaskDataObject restoreDataObject) =>
{
return false;
},
CurrentValueFunction = (IRestoreDatabaseTaskDataObject restoreDataObject) =>
currentValueFunction: (IRestoreDatabaseTaskDataObject restoreDataObject) =>
{
return restoreDataObject.RestoreOptions.KeepReplication;
},
ValidateFunction = (IRestoreDatabaseTaskDataObject restoreDataObject, object currentValue, object defaultValue) =>
validateFunction: (IRestoreDatabaseTaskDataObject restoreDataObject, object currentValue, object defaultValue) =>
{
return new OptionValidationResult()
{
IsReadOnly = restoreDataObject.RestoreOptions.RecoveryState == DatabaseRecoveryState.WithNoRecovery
};
},
SetValueFunction = (IRestoreDatabaseTaskDataObject restoreDataObject, object value) =>
setValueFunction: (IRestoreDatabaseTaskDataObject restoreDataObject, object value) =>
{
restoreDataObject.RestoreOptions.KeepReplication = GetValueAs<bool>(value);
return true;
}
});
));
Register(RestoreOptionsHelper.SetRestrictedUser,
new OptionBuilder
{
DefaultValueFunction = (IRestoreDatabaseTaskDataObject restoreDataObject) =>
(
defaultValueFunction: (IRestoreDatabaseTaskDataObject restoreDataObject) =>
{
return false;
},
CurrentValueFunction = (IRestoreDatabaseTaskDataObject restoreDataObject) =>
currentValueFunction: (IRestoreDatabaseTaskDataObject restoreDataObject) =>
{
return restoreDataObject.RestoreOptions.SetRestrictedUser;
},
ValidateFunction = (IRestoreDatabaseTaskDataObject restoreDataObject, object currentValue, object defaultValue) =>
validateFunction: (IRestoreDatabaseTaskDataObject restoreDataObject, object currentValue, object defaultValue) =>
{
return new OptionValidationResult()
{
};
},
SetValueFunction = (IRestoreDatabaseTaskDataObject restoreDataObject, object value) =>
setValueFunction: (IRestoreDatabaseTaskDataObject restoreDataObject, object value) =>
{
restoreDataObject.RestoreOptions.SetRestrictedUser = GetValueAs<bool>(value);
return true;
}
});
));
Register(RestoreOptionsHelper.RecoveryState,
new OptionBuilder
{
DefaultValueFunction = (IRestoreDatabaseTaskDataObject restoreDataObject) =>
(
defaultValueFunction: (IRestoreDatabaseTaskDataObject restoreDataObject) =>
{
return DatabaseRecoveryState.WithRecovery.ToString();
},
CurrentValueFunction = (IRestoreDatabaseTaskDataObject restoreDataObject) =>
currentValueFunction: (IRestoreDatabaseTaskDataObject restoreDataObject) =>
{
return restoreDataObject.RestoreOptions.RecoveryState.ToString();
},
ValidateFunction = (IRestoreDatabaseTaskDataObject restoreDataObject, object currentValue, object defaultValue) =>
validateFunction: (IRestoreDatabaseTaskDataObject restoreDataObject, object currentValue, object defaultValue) =>
{
return new OptionValidationResult()
{
};
},
SetValueFunction = (IRestoreDatabaseTaskDataObject restoreDataObject, object value) =>
setValueFunction: (IRestoreDatabaseTaskDataObject restoreDataObject, object value) =>
{
restoreDataObject.RestoreOptions.RecoveryState = GetValueAs<DatabaseRecoveryState>(value);
return true;
}
});
));
Register(RestoreOptionsHelper.StandbyFile,
new OptionBuilder
{
DefaultValueFunction = (IRestoreDatabaseTaskDataObject restoreDataObject) =>
(
defaultValueFunction: (IRestoreDatabaseTaskDataObject restoreDataObject) =>
{
return restoreDataObject.DefaultStandbyFile;
},
CurrentValueFunction = (IRestoreDatabaseTaskDataObject restoreDataObject) =>
currentValueFunction: (IRestoreDatabaseTaskDataObject restoreDataObject) =>
{
return restoreDataObject.RestoreOptions.StandByFile;
},
ValidateFunction = (IRestoreDatabaseTaskDataObject restoreDataObject, object currentValue, object defaultValue) =>
validateFunction: (IRestoreDatabaseTaskDataObject restoreDataObject, object currentValue, object defaultValue) =>
{
return new OptionValidationResult()
{
IsReadOnly = restoreDataObject.RestoreOptions.RecoveryState != DatabaseRecoveryState.WithStandBy
};
},
SetValueFunction = (IRestoreDatabaseTaskDataObject restoreDataObject, object value) =>
setValueFunction: (IRestoreDatabaseTaskDataObject restoreDataObject, object value) =>
{
restoreDataObject.RestoreOptions.StandByFile = GetValueAs<string>(value);
return true;
}
});
));
Register(RestoreOptionsHelper.BackupTailLog,
new OptionBuilder
{
DefaultValueFunction = (IRestoreDatabaseTaskDataObject restoreDataObject) =>
(
defaultValueFunction: (IRestoreDatabaseTaskDataObject restoreDataObject) =>
{
return restoreDataObject.IsTailLogBackupPossible;
},
CurrentValueFunction = (IRestoreDatabaseTaskDataObject restoreDataObject) =>
currentValueFunction: (IRestoreDatabaseTaskDataObject restoreDataObject) =>
{
return restoreDataObject.BackupTailLog;
},
ValidateFunction = (IRestoreDatabaseTaskDataObject restoreDataObject, object currentValue, object defaultValue) =>
validateFunction: (IRestoreDatabaseTaskDataObject restoreDataObject, object currentValue, object defaultValue) =>
{
return new OptionValidationResult()
{
IsReadOnly = !restoreDataObject.IsTailLogBackupPossible
};
},
SetValueFunction = (IRestoreDatabaseTaskDataObject restoreDataObject, object value) =>
setValueFunction: (IRestoreDatabaseTaskDataObject restoreDataObject, object value) =>
{
restoreDataObject.BackupTailLog = GetValueAs<bool>(value);
return true;
}
});
));
Register(RestoreOptionsHelper.TailLogBackupFile,
new OptionBuilder
{
DefaultValueFunction = (IRestoreDatabaseTaskDataObject restoreDataObject) =>
(
defaultValueFunction: (IRestoreDatabaseTaskDataObject restoreDataObject) =>
{
return restoreDataObject.DefaultTailLogbackupFile;
},
CurrentValueFunction = (IRestoreDatabaseTaskDataObject restoreDataObject) =>
currentValueFunction: (IRestoreDatabaseTaskDataObject restoreDataObject) =>
{
return restoreDataObject.TailLogBackupFile;
},
ValidateFunction = (IRestoreDatabaseTaskDataObject restoreDataObject, object currentValue, object defaultValue) =>
validateFunction: (IRestoreDatabaseTaskDataObject restoreDataObject, object currentValue, object defaultValue) =>
{
return new OptionValidationResult()
{
IsReadOnly = !restoreDataObject.BackupTailLog | !restoreDataObject.IsTailLogBackupPossible
};
},
SetValueFunction = (IRestoreDatabaseTaskDataObject restoreDataObject, object value) =>
setValueFunction: (IRestoreDatabaseTaskDataObject restoreDataObject, object value) =>
{
restoreDataObject.TailLogBackupFile = GetValueAs<string>(value);
return true;
}
});
));
Register(RestoreOptionsHelper.TailLogWithNoRecovery,
new OptionBuilder
{
DefaultValueFunction = (IRestoreDatabaseTaskDataObject restoreDataObject) =>
(
defaultValueFunction: (IRestoreDatabaseTaskDataObject restoreDataObject) =>
{
return restoreDataObject.IsTailLogBackupWithNoRecoveryPossible;
},
CurrentValueFunction = (IRestoreDatabaseTaskDataObject restoreDataObject) =>
currentValueFunction: (IRestoreDatabaseTaskDataObject restoreDataObject) =>
{
return restoreDataObject.TailLogWithNoRecovery;
},
ValidateFunction = (IRestoreDatabaseTaskDataObject restoreDataObject, object currentValue, object defaultValue) =>
validateFunction: (IRestoreDatabaseTaskDataObject restoreDataObject, object currentValue, object defaultValue) =>
{
return new OptionValidationResult()
{
IsReadOnly = !restoreDataObject.BackupTailLog | !restoreDataObject.IsTailLogBackupWithNoRecoveryPossible
};
},
SetValueFunction = (IRestoreDatabaseTaskDataObject restoreDataObject, object value) =>
setValueFunction: (IRestoreDatabaseTaskDataObject restoreDataObject, object value) =>
{
restoreDataObject.TailLogWithNoRecovery = GetValueAs<bool>(value);
return true;
}
});
));
Register(RestoreOptionsHelper.CloseExistingConnections,
new OptionBuilder
{
DefaultValueFunction = (IRestoreDatabaseTaskDataObject restoreDataObject) =>
(
defaultValueFunction: (IRestoreDatabaseTaskDataObject restoreDataObject) =>
{
return false;
},
CurrentValueFunction = (IRestoreDatabaseTaskDataObject restoreDataObject) =>
currentValueFunction: (IRestoreDatabaseTaskDataObject restoreDataObject) =>
{
return restoreDataObject.CloseExistingConnections;
},
ValidateFunction = (IRestoreDatabaseTaskDataObject restoreDataObject, object currentValue, object defaultValue) =>
validateFunction: (IRestoreDatabaseTaskDataObject restoreDataObject, object currentValue, object defaultValue) =>
{
return new OptionValidationResult()
{
IsReadOnly = !restoreDataObject.CanDropExistingConnections
};
},
SetValueFunction = (IRestoreDatabaseTaskDataObject restoreDataObject, object value) =>
setValueFunction: (IRestoreDatabaseTaskDataObject restoreDataObject, object value) =>
{
restoreDataObject.CloseExistingConnections = GetValueAs<bool>(value);
return true;
}
});
));
Register(RestoreOptionsHelper.SourceDatabaseName,
new OptionBuilder
{
DefaultValueFunction = (IRestoreDatabaseTaskDataObject restoreDataObject) =>
(
defaultValueFunction: (IRestoreDatabaseTaskDataObject restoreDataObject) =>
{
return restoreDataObject.DefaultSourceDbName;
},
CurrentValueFunction = (IRestoreDatabaseTaskDataObject restoreDataObject) =>
currentValueFunction: (IRestoreDatabaseTaskDataObject restoreDataObject) =>
{
return restoreDataObject.SourceDatabaseName;
},
ValidateFunction = (IRestoreDatabaseTaskDataObject restoreDataObject, object currentValue, object defaultValue) =>
validateFunction: (IRestoreDatabaseTaskDataObject restoreDataObject, object currentValue, object defaultValue) =>
{
string errorMessage = string.Empty;
var sourceDbNames = restoreDataObject.SourceDbNames;
@@ -514,41 +506,41 @@ namespace Microsoft.SqlTools.ServiceLayer.DisasterRecovery.RestoreOperation
}
return new OptionValidationResult()
{
ErrorMessage = errorMessage
ErrorMessage = errorMessage
};
},
SetValueFunction = (IRestoreDatabaseTaskDataObject restoreDataObject, object value) =>
setValueFunction: (IRestoreDatabaseTaskDataObject restoreDataObject, object value) =>
{
restoreDataObject.SourceDatabaseName = GetValueAs<string>(value);
return true;
}
});
));
Register(RestoreOptionsHelper.TargetDatabaseName,
new OptionBuilder
{
DefaultValueFunction = (IRestoreDatabaseTaskDataObject restoreDataObject) =>
(
defaultValueFunction: (IRestoreDatabaseTaskDataObject restoreDataObject) =>
{
return restoreDataObject.OverwriteTargetDatabase ? restoreDataObject.DefaultSourceDbName : restoreDataObject.DefaultTargetDbName;
},
CurrentValueFunction = (IRestoreDatabaseTaskDataObject restoreDataObject) =>
currentValueFunction: (IRestoreDatabaseTaskDataObject restoreDataObject) =>
{
return restoreDataObject.TargetDatabaseName;
},
ValidateFunction = (IRestoreDatabaseTaskDataObject restoreDataObject, object currentValue, object defaultValue) =>
validateFunction: (IRestoreDatabaseTaskDataObject restoreDataObject, object currentValue, object defaultValue) =>
{
return new OptionValidationResult()
{
IsReadOnly = false
};
},
SetValueFunction = (IRestoreDatabaseTaskDataObject restoreDataObject, object value) =>
setValueFunction: (IRestoreDatabaseTaskDataObject restoreDataObject, object value) =>
{
restoreDataObject.TargetDatabaseName = GetValueAs<string>(value);
return true;
}
});
));
}
internal T GetValueAs<T>(object value)
@@ -562,7 +554,7 @@ namespace Microsoft.SqlTools.ServiceLayer.DisasterRecovery.RestoreOperation
}
private RestorePlanDetailInfo Create(
string optionKey,
string optionKey,
IRestoreDatabaseTaskDataObject restoreDataObject,
OptionBuilder optionBuilder)
{
@@ -587,6 +579,14 @@ namespace Microsoft.SqlTools.ServiceLayer.DisasterRecovery.RestoreOperation
public Func<IRestoreDatabaseTaskDataObject, object, object, OptionValidationResult> ValidateFunction { get; set; }
public Func<IRestoreDatabaseTaskDataObject, object> CurrentValueFunction { get; set; }
public Func<IRestoreDatabaseTaskDataObject, object, bool> SetValueFunction { get; set; }
public OptionBuilder(Func<IRestoreDatabaseTaskDataObject, object> defaultValueFunction, Func<IRestoreDatabaseTaskDataObject, object, object, OptionValidationResult> validateFunction, Func<IRestoreDatabaseTaskDataObject, object> currentValueFunction, Func<IRestoreDatabaseTaskDataObject, object, bool> setValueFunction)
{
this.DefaultValueFunction = defaultValueFunction;
this.ValidateFunction = validateFunction;
this.CurrentValueFunction = currentValueFunction;
this.SetValueFunction = setValueFunction;
}
}
internal class OptionValidationResult

View File

@@ -18,11 +18,11 @@ namespace Microsoft.SqlTools.ServiceLayer.EditData.UpdateManagement
/// <summary>
/// Representation of a cell that should have a value inserted or updated
/// </summary>
public sealed class CellUpdate
public sealed partial class CellUpdate
{
private const string NullString = @"NULL";
private const string TextNullString = @"'NULL'";
private static readonly Regex HexRegex = new Regex("0x[0-9A-F]+", RegexOptions.Compiled | RegexOptions.IgnoreCase);
private static readonly Regex HexRegex = GetCharacterRegex();
private static readonly TimeSpan MaxTimespan = TimeSpan.FromHours(24);
/// <summary>
@@ -231,7 +231,7 @@ namespace Microsoft.SqlTools.ServiceLayer.EditData.UpdateManagement
private void ProcessTimespanColumn(string valueAsString)
{
TimeSpan ts = TimeSpan.Parse(valueAsString, CultureInfo.CurrentCulture);
var ts = TimeSpan.Parse(valueAsString, CultureInfo.CurrentCulture);
if (ts >= MaxTimespan)
{
throw new InvalidOperationException(SR.EditDataTimeOver24Hrs);
@@ -270,6 +270,9 @@ namespace Microsoft.SqlTools.ServiceLayer.EditData.UpdateManagement
ValueAsString = valueAsString;
}
[GeneratedRegex("0x[0-9A-F]+", RegexOptions.IgnoreCase | RegexOptions.Compiled)]
private static partial Regex GetCharacterRegex();
#endregion
}
}

View File

@@ -18,7 +18,7 @@ namespace Microsoft.SqlTools.ServiceLayer.ExecutionPlan.ShowPlan
/// <summary>
/// Base class for building hierarchy of Graph objects from ShowPlan Record Set
/// </summary>
internal abstract class DataReaderNodeBuilder: INodeBuilder
internal abstract partial class DataReaderNodeBuilder: INodeBuilder
{
#region Constructor
@@ -41,7 +41,7 @@ namespace Microsoft.SqlTools.ServiceLayer.ExecutionPlan.ShowPlan
/// <returns>An array of AnalysisServices Graph objects.</returns>
public ShowPlanGraph[] Execute(object dataSource)
{
IDataReader reader = dataSource as IDataReader;
var reader = dataSource as IDataReader;
if (reader == null)
{
@@ -49,7 +49,7 @@ namespace Microsoft.SqlTools.ServiceLayer.ExecutionPlan.ShowPlan
throw new ArgumentException(SR.Keys.UnknownShowPlanSource);
}
List<ShowPlanGraph> graphs = new List<ShowPlanGraph>();
var graphs = new List<ShowPlanGraph>();
Dictionary<int, Node> currentGraphNodes = null;
NodeBuilderContext context = null;
@@ -174,7 +174,7 @@ namespace Microsoft.SqlTools.ServiceLayer.ExecutionPlan.ShowPlan
for (int i = 0; i < count; i++)
{
if (names[i] != null && !((values[i] is DBNull) || values[i] == null))
if (names[i] != null && !(values[i] is DBNull || values[i] == null))
{
node[names[i]] = values[i];
}
@@ -220,7 +220,7 @@ namespace Microsoft.SqlTools.ServiceLayer.ExecutionPlan.ShowPlan
string argument = node["Argument"] as string;
if (argument != null)
{
Match match = argumentObjectExpression.Match(argument);
Match match = GetargumentObjectExpressionRegex().Match(argument);
if (match != Match.Empty)
{
node["Object"] = match.Groups["Object"].Value;
@@ -236,8 +236,8 @@ namespace Microsoft.SqlTools.ServiceLayer.ExecutionPlan.ShowPlan
}
// Remove spaces and other special characters from physical and logical names
physicalOpType = operatorReplaceExpression.Replace(physicalOpType, "");
logicalOpType = operatorReplaceExpression.Replace(logicalOpType, "");
physicalOpType = GetOperatorReplaceExpressionRegex().Replace(physicalOpType, "");
logicalOpType = GetOperatorReplaceExpressionRegex().Replace(logicalOpType, "");
Operation physicalOp = OperationTable.GetPhysicalOperation(physicalOpType);
Operation logicalOp = OperationTable.GetLogicalOperation(logicalOpType);
@@ -290,8 +290,11 @@ namespace Microsoft.SqlTools.ServiceLayer.ExecutionPlan.ShowPlan
#region Private members
private static Regex operatorReplaceExpression = new Regex(@"[ \-]", RegexOptions.CultureInvariant | RegexOptions.Compiled);
private static Regex argumentObjectExpression = new Regex(@"OBJECT:\((?<Object>[^\)]*)\)", RegexOptions.CultureInvariant | RegexOptions.Compiled);
[GeneratedRegex("[ \\-]", RegexOptions.Compiled | RegexOptions.CultureInvariant)]
private static partial Regex GetOperatorReplaceExpressionRegex();
[GeneratedRegex("OBJECT:\\((?<Object>[^\\)]*)\\)", RegexOptions.Compiled | RegexOptions.CultureInvariant)]
private static partial Regex GetargumentObjectExpressionRegex();
#endregion
}

View File

@@ -191,10 +191,9 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
{
lock (this.bindingContextLock)
{
if (this.BindingContextMap.ContainsKey(key))
if (this.BindingContextMap.TryGetValue(key, out IBindingContext? bindingContext))
{
// disconnect existing connection
var bindingContext = this.BindingContextMap[key];
if (bindingContext.ServerConnection != null && bindingContext.ServerConnection.IsOpen)
{
// Disconnecting can take some time so run it in a separate task so that it doesn't block removal

View File

@@ -19,9 +19,10 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices.Completion
/// <summary>
/// Creates a completion item from SQL parser declaration item
/// </summary>
public class SqlCompletionItem
public partial class SqlCompletionItem
{
private static Regex ValidSqlNameRegex = new Regex(@"^[\p{L}_@#][\p{L}\p{N}@$#_]{0,127}$");
[GeneratedRegex("^[\\p{L}_@#][\\p{L}\\p{N}@$#_]{0,127}$")]
private static partial Regex GetValidSqlNameRegex();
private static DelimitedIdentifier BracketedIdentifiers = new DelimitedIdentifier { Start = "[", End = "]" };
private static DelimitedIdentifier FunctionPostfix = new DelimitedIdentifier { Start = "", End = "()" };
private static DelimitedIdentifier[] DelimitedIdentifiers =
@@ -79,7 +80,7 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices.Completion
case DeclarationType.Schema:
// Only quote if we need to - i.e. if this isn't a valid name (has characters that need escaping such as [)
// or if it's a reserved word
if (!ValidSqlNameRegex.IsMatch(DeclarationTitle) || AutoCompleteHelper.IsReservedWord(InsertText))
if (!GetValidSqlNameRegex().IsMatch(DeclarationTitle) || AutoCompleteHelper.IsReservedWord(InsertText))
{
InsertText = WithDelimitedIdentifier(BracketedIdentifiers, DeclarationTitle);
}
@@ -197,7 +198,7 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices.Completion
int startColumn,
int endColumn)
{
CompletionItem item = new CompletionItem()
var item = new CompletionItem()
{
Label = label,
Kind = kind,

View File

@@ -1869,10 +1869,10 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
{
lock (this.parseMapLock)
{
if (this.ScriptParseInfoMap.ContainsKey(uri))
if (this.ScriptParseInfoMap.TryGetValue(uri, out ScriptParseInfo value))
{
Logger.Verbose($"Found ScriptParseInfo for uri {uri}");
return this.ScriptParseInfoMap[uri];
return value;
}
else if (createIfNotExists)
{

View File

@@ -1191,7 +1191,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Management
<urn>Server[@Name='{0}']</urn>
<itemtype>Database</itemtype>
</params></formdescription> ",
connInfo.ConnectionDetails.ServerName.ToUpper(),
connInfo.ConnectionDetails.ServerName.ToUpper(CultureInfo.InvariantCulture),
connInfo.ConnectionDetails.UserName);
}
else
@@ -1205,7 +1205,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Management
<urn>Server[@Name='{0}']</urn>
<database>{2}</database>
</params></formdescription> ",
connInfo.ConnectionDetails.ServerName.ToUpper(),
connInfo.ConnectionDetails.ServerName.ToUpper(CultureInfo.InvariantCulture),
connInfo.ConnectionDetails.UserName,
connInfo.ConnectionDetails.DatabaseName);
}

View File

@@ -12,10 +12,10 @@
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<PreserveCompilationContext>true</PreserveCompilationContext>
<RuntimeIdentifiers>$(ToolsServiceTargetRuntimes)</RuntimeIdentifiers>
<!-- TODO FIX THESE WARNINGS ASAP -->
<NoWarn>$(NoWarn);SYSLIB1045;CA1311;CA1854;CS8600;CS8603;CS8625</NoWarn>
<AssemblyTitle>SqlTools Editor Services Host Protocol Library</AssemblyTitle>
<Description>Provides message types and client/server APIs for the SqlTools Editor Services JSON protocol.</Description>
<!-- False alerts, disabled due to issue: https://github.com/dotnet/roslyn/issues/65850 -->
<NoWarn>$(NoWarn);CS8795</NoWarn>
</PropertyGroup>
<PropertyGroup>

View File

@@ -114,9 +114,9 @@ namespace Microsoft.SqlTools.ServiceLayer.Profiler
if ((currentEvent.Name.Equals("sql_batch_completed")
|| currentEvent.Name.Equals("sql_batch_starting"))
&& currentEvent.Values.ContainsKey("batch_text"))
&& currentEvent.Values.TryGetValue("batch_text", out string value))
{
return currentEvent.Values["batch_text"].Contains("SELECT target_data FROM sys.dm_xe_session_targets")
return value.Contains("SELECT target_data FROM sys.dm_xe_session_targets")
|| currentEvent.Values["batch_text"].Contains("SELECT target_data FROM sys.dm_xe_database_session_targets");
}

View File

@@ -19,10 +19,12 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution.DataStorage
/// <summary>
/// Writer for exporting results to a Markdown table.
/// </summary>
public class SaveAsMarkdownFileStreamWriter : SaveAsStreamWriter
public partial class SaveAsMarkdownFileStreamWriter : SaveAsStreamWriter
{
private const string Delimiter = "|";
private static readonly Regex NewlineRegex = new Regex(@"(\r\n|\n|\r)", RegexOptions.Compiled);
[GeneratedRegex("(\\r\\n|\\n|\\r)", RegexOptions.Compiled)]
private static partial Regex GetNewLineRegex();
private readonly Encoding _encoding;
private readonly string _lineSeparator;
@@ -72,7 +74,7 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution.DataStorage
this.WriteLine($"{Delimiter}{rowLine}{Delimiter}");
}
internal static string EncodeMarkdownField(string? field)
internal static string EncodeMarkdownField(string field)
{
// Special case for nulls
if (field == null)
@@ -89,7 +91,7 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution.DataStorage
// @TODO: Allow option to encode multiple whitespace characters as &nbsp;
// Replace newlines with br tags, since cell values must be single line
field = NewlineRegex.Replace(field, @"<br />");
field = GetNewLineRegex().Replace(field, @"<br />");
return field;
}

View File

@@ -25,7 +25,7 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution
/// Class that represents a resultset the was generated from a query. Contains logic for
/// storing and retrieving results. Is contained by a Batch class.
/// </summary>
public class ResultSet : IDisposable
public partial class ResultSet : IDisposable
{
#region Constants
@@ -279,7 +279,7 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution
// ReSharper disable once AccessToDisposedClosure The lambda is used immediately in string.Join call
IEnumerable<string> rowValues = fileOffsets.Select(rowOffset => fileStreamReader.ReadRow(rowOffset, 0, Columns)[0].DisplayValue);
string singleString = string.Join(string.Empty, rowValues);
DbCellValue cellValue = new DbCellValue
var cellValue = new DbCellValue
{
DisplayValue = singleString,
IsNull = false,
@@ -369,7 +369,7 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution
// Verify the request hasn't been cancelled
cancellationToken.ThrowIfCancellationRequested();
StorageDataReader dataReader = new StorageDataReader(dbDataReader);
var dataReader = new StorageDataReader(dbDataReader);
// Open a writer for the file
//
@@ -514,7 +514,7 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution
}
// Create the new task
Task saveAsTask = new Task(async () =>
var saveAsTask = new Task(async () =>
{
try
{
@@ -638,7 +638,7 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution
//
sendResultsSemphore.Wait();
ResultSet currentResultSetSnapshot = (ResultSet) MemberwiseClone();
var currentResultSetSnapshot = (ResultSet) MemberwiseClone();
if (LastUpdatedSummary == null) // We need to send results available message.
{
// Fire off results Available task and await it
@@ -739,13 +739,12 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution
{
if (Columns?.Length > 0 && RowCount != 0)
{
Regex regex = new Regex(@"({.*?})");
var row = GetRow(0);
for (int i = 0; i < Columns.Length; i++)
{
if (Columns[i].DataTypeName.Equals("nvarchar"))
{
if (regex.IsMatch(row[i].DisplayValue))
if (GetJsonRegex().IsMatch(row[i].DisplayValue))
{
Columns[i].IsJson = true;
}
@@ -788,7 +787,7 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution
// Returning false from .ReadAsync means there aren't any rows.
// Create a storage data reader, read it, make sure there were results
StorageDataReader dataReader = new StorageDataReader(dbDataReader);
var dataReader = new StorageDataReader(dbDataReader);
if (!await dataReader.ReadAsync(CancellationToken.None))
{
throw new InvalidOperationException(SR.QueryServiceResultSetAddNoRows);
@@ -804,6 +803,9 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution
}
}
[GeneratedRegex("({.*?})")]
private static partial Regex GetJsonRegex();
#endregion
}
}

View File

@@ -22,7 +22,7 @@ namespace Microsoft.SqlTools.ServiceLayer.SchemaCompare
/// <summary>
/// Internal class for utilities shared between multiple schema compare operations
/// </summary>
internal static class SchemaCompareUtils
internal static partial class SchemaCompareUtils
{
internal static DiffEntry CreateDiffEntry(SchemaDifference difference, DiffEntry parent)
{
@@ -31,7 +31,7 @@ namespace Microsoft.SqlTools.ServiceLayer.SchemaCompare
return null;
}
DiffEntry diffEntry = new DiffEntry();
var diffEntry = new DiffEntry();
diffEntry.UpdateAction = difference.UpdateAction;
diffEntry.DifferenceType = difference.DifferenceType;
diffEntry.Name = difference.Name;
@@ -86,8 +86,8 @@ namespace Microsoft.SqlTools.ServiceLayer.SchemaCompare
{
return null;
}
ObjectIdentifier id = new ObjectIdentifier(sourceObj.NameParts);
SchemaComparisonExcludedObjectId excludedObjId = new SchemaComparisonExcludedObjectId(sourceObj.SqlObjectType, id);
var id = new ObjectIdentifier(sourceObj.NameParts);
var excludedObjId = new SchemaComparisonExcludedObjectId(sourceObj.SqlObjectType, id);
return excludedObjId;
}
catch (ArgumentException)
@@ -145,7 +145,7 @@ namespace Microsoft.SqlTools.ServiceLayer.SchemaCompare
// remove leading and trailing whitespace
script = script.Trim();
// replace all multiple spaces with single space
script = Regex.Replace(script, " {2,}", " ");
script = GetScriptRegex().Replace(script, " ");
}
return script;
}
@@ -159,5 +159,8 @@ namespace Microsoft.SqlTools.ServiceLayer.SchemaCompare
}
return script;
}
[GeneratedRegex(" {2,}")]
private static partial Regex GetScriptRegex();
}
}

View File

@@ -189,7 +189,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Scripting
string tokenType = GetTokenTypeFromQuickInfo(quickInfoText, tokenText, caseSensitivity);
if (tokenType != null)
{
if (sqlObjectTypesFromQuickInfo.ContainsKey(tokenType.ToLowerInvariant()))
if (sqlObjectTypesFromQuickInfo.TryGetValue(tokenType.ToLowerInvariant(), out string sqlObjectType))
{
// With SqlLogin authentication, the defaultSchema property throws an Exception when accessed.
// This workaround ensures that a schema name is present by attempting
@@ -203,8 +203,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Scripting
Location[] locations = GetSqlObjectDefinition(
tokenText,
schemaName,
sqlObjectTypesFromQuickInfo[tokenType.ToLowerInvariant()]
);
sqlObjectType);
DefinitionResult result = new DefinitionResult
{
IsErrorResult = this.error,
@@ -232,7 +231,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Scripting
/// <returns></returns>
internal DefinitionResult GetDefinitionUsingDeclarationType(DeclarationType type, string databaseQualifiedName, string tokenText, string schemaName)
{
if (sqlObjectTypes.ContainsKey(type))
if (sqlObjectTypes.TryGetValue(type, out string sqlObjectType))
{
// With SqlLogin authentication, the defaultSchema property throws an Exception when accessed.
// This workaround ensures that a schema name is present by attempting
@@ -246,8 +245,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Scripting
Location[] locations = GetSqlObjectDefinition(
tokenText,
schemaName,
sqlObjectTypes[type]
);
sqlObjectType);
DefinitionResult result = new DefinitionResult
{
IsErrorResult = this.error,
@@ -288,7 +286,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Scripting
string[] lines = File.ReadAllLines(tempFileName);
int lineCount = 0;
string createSyntax = null;
if (objectScriptMap.ContainsKey(objectType.ToLower()))
if (objectScriptMap.ContainsKey(objectType.ToLower(System.Globalization.CultureInfo.InvariantCulture)))
{
createSyntax = string.Format("CREATE");
foreach (string line in lines)

View File

@@ -102,7 +102,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Scripting
// Leaving the server name blank will automatically match whatever the server SMO is running against.
StringBuilder urnBuilder = new StringBuilder();
urnBuilder.AppendFormat("Server[@Name='{0}']/", server.ToUpper());
urnBuilder.AppendFormat("Server[@Name='{0}']/", server.ToUpper(System.Globalization.CultureInfo.InvariantCulture));
urnBuilder.AppendFormat("Database[@Name='{0}']/", Urn.EscapeString(database));
bool hasParentObject = !string.IsNullOrWhiteSpace(scriptingObject.ParentName)

View File

@@ -38,9 +38,9 @@ namespace Microsoft.SqlTools.ServiceLayer.TableDesigner
public T GetValue(string displayName)
{
if (this.Mapping.ContainsKey(displayName))
if (this.Mapping.TryGetValue(displayName, out T value))
{
return this.Mapping[displayName];
return value;
}
else
{

View File

@@ -38,7 +38,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Utility
{
get
{
return ClientUri?.ToLower();
return ClientUri?.ToLower(System.Globalization.CultureInfo.InvariantCulture);
}
}
}

View File

@@ -16,11 +16,14 @@ namespace Microsoft.SqlTools.ServiceLayer.Utility.SqlScriptFormatters
/// <summary>
/// Provides utilities for converting from SQL script syntax into POCOs.
/// </summary>
public static class FromSqlScript
public static partial class FromSqlScript
{
// Regex: optionally starts with N, captures string wrapped in single quotes
private static readonly Regex StringRegex = new Regex("^N?'(.*)'$", RegexOptions.Compiled);
private static readonly Regex BracketRegex = new Regex(@"^\[(.*)\]$", RegexOptions.Compiled);
[GeneratedRegex("^N?'(.*)'$", RegexOptions.Compiled)]
private static partial Regex GetStringRegex();
[GeneratedRegex("^\\[(.*)\\]$", RegexOptions.Compiled)]
private static partial Regex GetBracketRegex();
/// <summary>
/// Decodes a multipart identifier as used in a SQL script into an array of the multiple
@@ -35,8 +38,8 @@ namespace Microsoft.SqlTools.ServiceLayer.Utility.SqlScriptFormatters
/// </exception>
public static string[] DecodeMultipartIdentifier(string multipartIdentifier)
{
StringBuilder sb = new StringBuilder();
List<string> namedParts = new List<string>();
var sb = new StringBuilder();
var namedParts = new List<string>();
bool insideBrackets = false;
bool bracketsClosed = false;
for (int i = 0; i < multipartIdentifier.Length; i++)
@@ -122,7 +125,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Utility.SqlScriptFormatters
literal = literal.Trim('(', ')');
// Attempt to unwrap inverted commas around a string
Match match = StringRegex.Match(literal);
Match match = GetStringRegex().Match(literal);
if (match.Success)
{
// Like: N'stuff' or 'stuff'
@@ -136,7 +139,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Utility.SqlScriptFormatters
/// </summary>
/// <param name="identifer">Identifier to check.</param>
/// <returns>Boolean indicating if identifier is escaped with brackets.</returns>
public static bool IsIdentifierBracketed(string identifer) => BracketRegex.IsMatch(identifer);
public static bool IsIdentifierBracketed(string identifer) => GetBracketRegex().IsMatch(identifer);
#region Private Helpers

View File

@@ -27,7 +27,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Workspace.Contracts
/// </summary>
public string Id
{
get { return this.ClientUri.ToLower(); }
get { return this.ClientUri.ToLower(System.Globalization.CultureInfo.InvariantCulture); }
}
/// <summary>

View File

@@ -23,7 +23,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Workspace
/// Manages a "workspace" of script files that are open for a particular
/// editing session. Also helps to navigate references between ScriptFiles.
/// </summary>
public class Workspace : IDisposable
public partial class Workspace : IDisposable
{
#region Private Fields
@@ -117,8 +117,8 @@ namespace Microsoft.SqlTools.ServiceLayer.Workspace
}
// This method allows FileNotFoundException to bubble up
// if the file isn't found.
using (FileStream fileStream = new FileStream(resolvedFile.FilePath, FileMode.Open, FileAccess.Read))
using (StreamReader streamReader = new StreamReader(fileStream, Encoding.UTF8))
using (var fileStream = new FileStream(resolvedFile.FilePath, FileMode.Open, FileAccess.Read))
using (var streamReader = new StreamReader(fileStream, Encoding.UTF8))
{
scriptFile = new ScriptFile(resolvedFile.FilePath, resolvedFile.ClientUri,streamReader);
@@ -150,7 +150,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Workspace
// Client sent the path in URI format, extract the local path and trim
// any extraneous slashes
Uri fileUri = new Uri(clientUri);
var fileUri = new Uri(clientUri);
filePath = fileUri.LocalPath;
if (filePath.StartsWith("//") || filePath.StartsWith("\\\\") || filePath.StartsWith("/"))
{
@@ -208,7 +208,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Workspace
return path;
}
return Regex.Replace(path, @"`(?=[ \[\]])", "");
return GetEscapeRegex().Replace(path, "");
}
/// <summary>
@@ -363,6 +363,9 @@ namespace Microsoft.SqlTools.ServiceLayer.Workspace
{
}
[GeneratedRegex("`(?=[ \\[\\]])")]
private static partial Regex GetEscapeRegex();
#endregion
}
}