// // Copyright (c) Microsoft. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. // #nullable disable using System; using System.Threading.Tasks; using Microsoft.SqlTools.Hosting.Protocol; using Microsoft.SqlTools.ServiceLayer.ExecutionPlan.Contracts; using Microsoft.SqlTools.ServiceLayer.ExecutionPlan.ShowPlan; using Microsoft.SqlTools.ServiceLayer.ExecutionPlan.ShowPlan.Comparison; using Microsoft.SqlTools.ServiceLayer.Hosting; namespace Microsoft.SqlTools.ServiceLayer.ExecutionPlan { /// /// Main class for Execution Plan Service functionality /// public sealed class ExecutionPlanService : IDisposable { private static readonly Lazy instance = new Lazy(() => new ExecutionPlanService()); private bool disposed; /// /// Construct a new Execution Plan Service instance with default parameters /// private ExecutionPlanService() { } /// /// Gets the singleton instance object /// public static ExecutionPlanService Instance { get { return instance.Value; } } /// /// Service host object for sending/receiving requests/events. /// Internal for testing purposes. /// internal IProtocolEndpoint ServiceHost { get; set; } /// /// Initializes the Execution Plan Service instance /// public void InitializeService(ServiceHost serviceHost) { ServiceHost = serviceHost; ServiceHost.SetRequestHandler(GetExecutionPlanRequest.Type, HandleGetExecutionPlan, true); ServiceHost.SetRequestHandler(ExecutionPlanComparisonRequest.Type, HandleExecutionPlanComparisonRequest, true); } private async Task HandleGetExecutionPlan(GetExecutionPlanParams requestParams, RequestContext requestContext) { var plans = ExecutionPlanGraphUtils.CreateShowPlanGraph(requestParams.GraphInfo.GraphFileContent, ""); await requestContext.SendResult(new GetExecutionPlanResult { Graphs = plans }); } /// /// Handles requests for color matching similar nodes. /// internal async Task HandleExecutionPlanComparisonRequest( ExecutionPlanComparisonParams requestParams, RequestContext requestContext) { var nodeBuilder = new XmlPlanNodeBuilder(ShowPlanType.Unknown); var firstPlanXml = nodeBuilder.GetSingleStatementXml(requestParams.FirstExecutionPlanGraphInfo.GraphFileContent, requestParams.FirstExecutionPlanGraphInfo.PlanIndexInFile); var firstGraphSet = ShowPlanGraph.ParseShowPlanXML(firstPlanXml, ShowPlanType.Unknown); var firstRootNode = firstGraphSet?[0]?.Root; var secondPlanXml = nodeBuilder.GetSingleStatementXml(requestParams.SecondExecutionPlanGraphInfo.GraphFileContent, requestParams.SecondExecutionPlanGraphInfo.PlanIndexInFile); var secondGraphSet = ShowPlanGraph.ParseShowPlanXML(secondPlanXml, ShowPlanType.Unknown); var secondRootNode = secondGraphSet?[0]?.Root; var manager = new SkeletonManager(); var firstSkeletonNode = manager.CreateSkeleton(firstRootNode); var secondSkeletonNode = manager.CreateSkeleton(secondRootNode); manager.ColorMatchingSections(firstSkeletonNode, secondSkeletonNode, requestParams.IgnoreDatabaseName); var firstGraphComparisonResultDTO = firstSkeletonNode.ConvertToDTO(); var secondGraphComparisonResultDTO = secondSkeletonNode.ConvertToDTO(); ExecutionPlanGraphUtils.CopyMatchingNodesIntoSkeletonDTO(firstGraphComparisonResultDTO, secondGraphComparisonResultDTO); ExecutionPlanGraphUtils.CopyMatchingNodesIntoSkeletonDTO(secondGraphComparisonResultDTO, firstGraphComparisonResultDTO); var result = new ExecutionPlanComparisonResult() { FirstComparisonResult = firstGraphComparisonResultDTO, SecondComparisonResult = secondGraphComparisonResultDTO }; await requestContext.SendResult(result); } /// /// Disposes the Execution Plan Service /// public void Dispose() { if (!disposed) { disposed = true; } } } }