//
// 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;
}
}
}
}