mirror of
https://github.com/ckaczor/sqltoolsservice.git
synced 2026-01-17 01:25:40 -05:00
Feature execution plan settings and request implementation (#213)
* experimental showplan implementation (tools side only) * fix for redundant massages from showplan executions * moved showplan batches to new variables to make it less confusing * returns showplan as part of batch summary with in each result summary * cleaned up showplan resultsets * cleaning up code and making showplan var optional * changes all var names to showplan * adding estimated support * small fixes * updatin var names and adding EPOptions struct * adding ssms execution plan logic based on server types * adding special actions logic * removing redundant name changes * execution plan query handler added * cleaning up functions and data structures * seperated special actions into its own class * cleaning up special actions * cleaning up code * small new line fixes * commenting out pre-yukon code * removing all pre yukon code * last yukon code commented out * fixes broken tests * adding related unit tests; integration tests incoming * finishing tests and cleaning up code * semantic changes * cleaning up semantics * changes and test fixes, also adding new exceptions into RS * fixing special actions and cleaning up request logic * fixing comment to trigger new build * triggering another build * fixed up specialaction and added tests for it
This commit is contained in:
@@ -55,6 +55,11 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution
|
||||
/// </summary>
|
||||
private readonly List<ResultSet> resultSets;
|
||||
|
||||
/// <summary>
|
||||
/// Special action which this batch performed
|
||||
/// </summary>
|
||||
private SpecialAction specialAction;
|
||||
|
||||
#endregion
|
||||
|
||||
internal Batch(string batchText, SelectionData selection, int ordinalId, IFileStreamFactory outputFileFactory)
|
||||
@@ -72,6 +77,7 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution
|
||||
Id = ordinalId;
|
||||
resultSets = new List<ResultSet>();
|
||||
this.outputFileFactory = outputFileFactory;
|
||||
specialAction = new SpecialAction();
|
||||
}
|
||||
|
||||
#region Events
|
||||
@@ -201,6 +207,7 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution
|
||||
summary.ResultSetSummaries = ResultSummaries;
|
||||
summary.ExecutionEnd = ExecutionEndTimeStamp;
|
||||
summary.ExecutionElapsed = ExecutionElapsedTime;
|
||||
summary.SpecialAction = ProcessResultSetSpecialActions();
|
||||
}
|
||||
|
||||
return summary;
|
||||
@@ -370,6 +377,30 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution
|
||||
return targetResultSet.GetSubset(startRow, rowCount);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generates an execution plan
|
||||
/// </summary>
|
||||
/// <param name="resultSetIndex">The index for selecting the result set</param>
|
||||
/// <returns>An exeuction plan object</returns>
|
||||
public Task<ExecutionPlan> GetExecutionPlan(int resultSetIndex)
|
||||
{
|
||||
ResultSet targetResultSet;
|
||||
lock (resultSets)
|
||||
{
|
||||
// Sanity check to make sure we have valid numbers
|
||||
if (resultSetIndex < 0 || resultSetIndex >= resultSets.Count)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(resultSetIndex),
|
||||
SR.QueryServiceSubsetResultSetOutOfRange);
|
||||
}
|
||||
|
||||
targetResultSet = resultSets[resultSetIndex];
|
||||
}
|
||||
|
||||
// Retrieve the result set
|
||||
return targetResultSet.GetExecutionPlan();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Saves a result to a file format selected by the user
|
||||
/// </summary>
|
||||
@@ -482,6 +513,19 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Aggregates all result sets in the batch into a single special action
|
||||
/// </summary>
|
||||
private SpecialAction ProcessResultSetSpecialActions()
|
||||
{
|
||||
foreach (ResultSet resultSet in resultSets)
|
||||
{
|
||||
specialAction.CombineSpecialAction(resultSet.Summary.SpecialAction);
|
||||
}
|
||||
|
||||
return specialAction;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IDisposable Implementation
|
||||
|
||||
@@ -44,5 +44,10 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution.Contracts
|
||||
/// The summaries of the result sets inside the batch
|
||||
/// </summary>
|
||||
public ResultSetSummary[] ResultSetSummaries { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The special action of the batch
|
||||
/// </summary>
|
||||
public SpecialAction SpecialAction { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
//
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
//
|
||||
|
||||
namespace Microsoft.SqlTools.ServiceLayer.QueryExecution.Contracts
|
||||
{
|
||||
/// <summary>
|
||||
/// Class used to represent an execution plan from a query for transmission across JSON RPC
|
||||
/// </summary>
|
||||
public class ExecutionPlan
|
||||
{
|
||||
/// <summary>
|
||||
/// The format of the execution plan
|
||||
/// </summary>
|
||||
public string Format { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The execution plan content
|
||||
/// </summary>
|
||||
public string Content { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
//
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
namespace Microsoft.SqlTools.ServiceLayer.QueryExecution.Contracts
|
||||
{
|
||||
/// <summary>
|
||||
/// Incoming execution plan options from the extension
|
||||
/// </summary>
|
||||
public struct ExecutionPlanOptions
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Setting to return the actual execution plan as XML
|
||||
/// </summary>
|
||||
public bool IncludeActualExecutionPlanXml { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Setting to return the estimated execution plan as XML
|
||||
/// </summary>
|
||||
public bool IncludeEstimatedExecutionPlanXml { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -21,6 +21,12 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution.Contracts
|
||||
/// URI for the editor that is asking for the query execute
|
||||
/// </summary>
|
||||
public string OwnerUri { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Execution plan options
|
||||
/// </summary>
|
||||
public ExecutionPlanOptions ExecutionPlanOptions { get; set; }
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
//
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
//
|
||||
|
||||
using Microsoft.SqlTools.ServiceLayer.Hosting.Protocol.Contracts;
|
||||
|
||||
namespace Microsoft.SqlTools.ServiceLayer.QueryExecution.Contracts
|
||||
{
|
||||
/// <summary>
|
||||
/// Parameters for query execution plan request
|
||||
/// </summary>
|
||||
public class QueryExecutionPlanParams
|
||||
{
|
||||
/// <summary>
|
||||
/// URI for the file that owns the query to look up the results for
|
||||
/// </summary>
|
||||
public string OwnerUri { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Index of the batch to get the results from
|
||||
/// </summary>
|
||||
public int BatchIndex { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Index of the result set to get the results from
|
||||
/// </summary>
|
||||
public int ResultSetIndex { get; set; }
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parameters for the query execution plan request
|
||||
/// </summary>
|
||||
public class QueryExecutionPlanResult
|
||||
{
|
||||
/// <summary>
|
||||
/// The requested execution plan. Optional, can be set to null to indicate an error
|
||||
/// </summary>
|
||||
public ExecutionPlan ExecutionPlan { get; set; }
|
||||
}
|
||||
|
||||
public class QueryExecutionPlanRequest
|
||||
{
|
||||
public static readonly
|
||||
RequestType<QueryExecutionPlanParams, QueryExecutionPlanResult> Type =
|
||||
RequestType<QueryExecutionPlanParams, QueryExecutionPlanResult>.Create("query/executionPlan");
|
||||
}
|
||||
}
|
||||
@@ -29,5 +29,11 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution.Contracts
|
||||
/// Details about the columns that are provided as solutions
|
||||
/// </summary>
|
||||
public DbColumnWrapper[] ColumnInfo { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The special action definition of the result set
|
||||
/// </summary>
|
||||
public SpecialAction SpecialAction { get; set; }
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ using Microsoft.SqlTools.ServiceLayer.QueryExecution.Contracts;
|
||||
using Microsoft.SqlTools.ServiceLayer.QueryExecution.DataStorage;
|
||||
using Microsoft.SqlTools.ServiceLayer.SqlContext;
|
||||
using Microsoft.SqlTools.ServiceLayer.Utility;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Microsoft.SqlTools.ServiceLayer.QueryExecution
|
||||
{
|
||||
@@ -51,6 +52,36 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution
|
||||
/// </summary>
|
||||
private bool hasExecuteBeenCalled;
|
||||
|
||||
/// <summary>
|
||||
/// Settings for query runtime
|
||||
/// </summary>
|
||||
private QueryExecutionSettings querySettings;
|
||||
|
||||
/// <summary>
|
||||
/// Streaming output factory for the query
|
||||
/// </summary>
|
||||
private IFileStreamFactory streamOutputFactory;
|
||||
|
||||
/// <summary>
|
||||
/// ON keyword
|
||||
/// </summary>
|
||||
private const string On = "ON";
|
||||
|
||||
/// <summary>
|
||||
/// OFF keyword
|
||||
/// </summary>
|
||||
private const string Off = "OFF";
|
||||
|
||||
/// <summary>
|
||||
/// showplan_xml statement
|
||||
/// </summary>
|
||||
private const string SetShowPlanXml = "SET SHOWPLAN_XML {0}";
|
||||
|
||||
/// <summary>
|
||||
/// statistics xml statement
|
||||
/// </summary>
|
||||
private const string SetStatisticsXml = "SET STATISTICS XML {0}";
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
@@ -72,6 +103,8 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution
|
||||
QueryText = queryText;
|
||||
editorConnection = connection;
|
||||
cancellationSource = new CancellationTokenSource();
|
||||
querySettings = settings;
|
||||
streamOutputFactory = outputFactory;
|
||||
|
||||
// Process the query into batches
|
||||
ParseResult parseResult = Parser.Parse(queryText, new ParseOptions
|
||||
@@ -89,7 +122,28 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution
|
||||
batch.EndLocation.LineNumber - 1,
|
||||
batch.EndLocation.ColumnNumber - 1),
|
||||
index, outputFactory));
|
||||
|
||||
Batches = batchSelection.ToArray();
|
||||
|
||||
// Create our batch lists
|
||||
BeforeBatches = new List<Batch>();
|
||||
AfterBatches = new List<Batch>();
|
||||
|
||||
if (DoesSupportExecutionPlan(connection))
|
||||
{
|
||||
// Checking settings for execution plan options
|
||||
if (querySettings.ExecutionPlanOptions.IncludeEstimatedExecutionPlanXml)
|
||||
{
|
||||
// Enable set showplan xml
|
||||
addBatch(string.Format(SetShowPlanXml, On), BeforeBatches, streamOutputFactory);
|
||||
addBatch(string.Format(SetShowPlanXml, Off), AfterBatches, streamOutputFactory);
|
||||
}
|
||||
else if (querySettings.ExecutionPlanOptions.IncludeActualExecutionPlanXml)
|
||||
{
|
||||
addBatch(string.Format(SetStatisticsXml, On), BeforeBatches, streamOutputFactory);
|
||||
addBatch(string.Format(SetStatisticsXml, Off), AfterBatches, streamOutputFactory);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#region Events
|
||||
@@ -145,11 +199,21 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution
|
||||
/// <param name="q">The query that completed</param>
|
||||
public delegate Task QueryAsyncEventHandler(Query q);
|
||||
|
||||
/// <summary>
|
||||
/// The batches which should run before the user batches
|
||||
/// </summary>
|
||||
internal List<Batch> BeforeBatches { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The batches underneath this query
|
||||
/// </summary>
|
||||
internal Batch[] Batches { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The batches which should run after the user batches
|
||||
/// </summary>
|
||||
internal List<Batch> AfterBatches { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The summaries of the batches underneath this query
|
||||
/// </summary>
|
||||
@@ -241,6 +305,23 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution
|
||||
return Batches[batchIndex].GetSubset(resultSetIndex, startRow, rowCount);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves a subset of the result sets
|
||||
/// </summary>
|
||||
/// <param name="batchIndex">The index for selecting the batch item</param>
|
||||
/// <param name="resultSetIndex">The index for selecting the result set</param>
|
||||
/// <returns>The Execution Plan, if the result set has one</returns>
|
||||
public Task<ExecutionPlan> GetExecutionPlan(int batchIndex, int resultSetIndex)
|
||||
{
|
||||
// Sanity check to make sure that the batch is within bounds
|
||||
if (batchIndex < 0 || batchIndex >= Batches.Length)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(batchIndex), SR.QueryServiceSubsetBatchOutOfRange);
|
||||
}
|
||||
|
||||
return Batches[batchIndex].GetExecutionPlan(resultSetIndex);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Saves the requested results to a file format of the user's choice
|
||||
/// </summary>
|
||||
@@ -316,9 +397,16 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution
|
||||
|
||||
try
|
||||
{
|
||||
// Execute beforeBatches synchronously, before the user defined batches
|
||||
foreach (Batch b in BeforeBatches)
|
||||
{
|
||||
await b.Execute(conn, cancellationSource.Token);
|
||||
}
|
||||
|
||||
// We need these to execute synchronously, otherwise the user will be very unhappy
|
||||
foreach (Batch b in Batches)
|
||||
{
|
||||
// Add completion callbacks
|
||||
b.BatchStart += BatchStarted;
|
||||
b.BatchCompletion += BatchCompleted;
|
||||
b.BatchMessageSent += BatchMessageSent;
|
||||
@@ -326,6 +414,12 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution
|
||||
await b.Execute(conn, cancellationSource.Token);
|
||||
}
|
||||
|
||||
// Execute afterBatches synchronously, after the user defined batches
|
||||
foreach (Batch b in AfterBatches)
|
||||
{
|
||||
await b.Execute(conn, cancellationSource.Token);
|
||||
}
|
||||
|
||||
// Call the query execution callback
|
||||
if (QueryCompleted != null)
|
||||
{
|
||||
@@ -374,6 +468,14 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Function to add a new batch to a Batch set
|
||||
/// </summary>
|
||||
private void addBatch(string query, List<Batch> batchSet, IFileStreamFactory outputFactory)
|
||||
{
|
||||
batchSet.Add(new Batch(query, null, batchSet.Count, outputFactory));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IDisposable Implementation
|
||||
@@ -403,6 +505,14 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution
|
||||
disposed = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Does this connection support XML Execution plans
|
||||
/// </summary>
|
||||
private bool DoesSupportExecutionPlan(ConnectionInfo connectionInfo) {
|
||||
// Determining which execution plan options may be applied (may be added to for pre-yukon support)
|
||||
return (!connectionInfo.IsSqlDW && connectionInfo.MajorVersion >= 9);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
@@ -126,6 +126,7 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution
|
||||
serviceHost.SetRequestHandler(QueryCancelRequest.Type, HandleCancelRequest);
|
||||
serviceHost.SetRequestHandler(SaveResultsAsCsvRequest.Type, HandleSaveResultsAsCsvRequest);
|
||||
serviceHost.SetRequestHandler(SaveResultsAsJsonRequest.Type, HandleSaveResultsAsJsonRequest);
|
||||
serviceHost.SetRequestHandler(QueryExecutionPlanRequest.Type, HandleExecutionPlanRequest);
|
||||
|
||||
// Register handler for shutdown event
|
||||
serviceHost.RegisterShutdownTask((shutdownParams, requestContext) =>
|
||||
@@ -208,6 +209,36 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handles a request to get an execution plan
|
||||
/// </summary>
|
||||
public async Task HandleExecutionPlanRequest(QueryExecutionPlanParams planParams,
|
||||
RequestContext<QueryExecutionPlanResult> requestContext)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Attempt to load the query
|
||||
Query query;
|
||||
if (!ActiveQueries.TryGetValue(planParams.OwnerUri, out query))
|
||||
{
|
||||
await requestContext.SendError(SR.QueryServiceRequestsNoQuery);
|
||||
return;
|
||||
}
|
||||
|
||||
// Retrieve the requested execution plan and return it
|
||||
var result = new QueryExecutionPlanResult
|
||||
{
|
||||
ExecutionPlan = await query.GetExecutionPlan(planParams.BatchIndex, planParams.ResultSetIndex)
|
||||
};
|
||||
await requestContext.SendResult(result);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
// This was unexpected, so send back as error
|
||||
await requestContext.SendError(e.Message);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handles a request to dispose of this query
|
||||
/// </summary>
|
||||
@@ -334,6 +365,9 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution
|
||||
// Retrieve the current settings for executing the query with
|
||||
QueryExecutionSettings settings = WorkspaceService.CurrentSettings.QueryExecutionSettings;
|
||||
|
||||
// Apply execution parameter settings
|
||||
settings.ExecutionPlanOptions = executeParams.ExecutionPlanOptions;
|
||||
|
||||
// Get query text from the workspace.
|
||||
ScriptFile queryFile = WorkspaceService.Workspace.GetFile(executeParams.OwnerUri);
|
||||
|
||||
@@ -425,6 +459,7 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution
|
||||
BatchSummary = b.Summary,
|
||||
OwnerUri = executeParams.OwnerUri
|
||||
};
|
||||
|
||||
await requestContext.SendEvent(QueryExecuteBatchStartEvent.Type, eventParams);
|
||||
};
|
||||
query.BatchStarted += batchStartCallback;
|
||||
@@ -436,6 +471,7 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution
|
||||
BatchSummary = b.Summary,
|
||||
OwnerUri = executeParams.OwnerUri
|
||||
};
|
||||
|
||||
await requestContext.SendEvent(QueryExecuteBatchCompleteEvent.Type, eventParams);
|
||||
};
|
||||
query.BatchCompleted += batchCompleteCallback;
|
||||
|
||||
@@ -27,6 +27,7 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution
|
||||
// Column names of 'for xml' and 'for json' queries
|
||||
private const string NameOfForXMLColumn = "XML_F52E2B61-18A1-11d1-B105-00805F49916B";
|
||||
private const string NameOfForJSONColumn = "JSON_F52E2B61-18A1-11d1-B105-00805F49916B";
|
||||
private const string YukonXmlShowPlanColumn = "Microsoft SQL Server 2005 XML Showplan";
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -68,6 +69,11 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution
|
||||
/// </summary>
|
||||
private readonly string outputFileName;
|
||||
|
||||
/// <summary>
|
||||
/// The special action which applied to this result set
|
||||
/// </summary>
|
||||
private SpecialAction specialAction;
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
@@ -89,6 +95,7 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution
|
||||
// Initialize the storage
|
||||
outputFileName = factory.CreateFile();
|
||||
fileOffsets = new LongList<long>();
|
||||
specialAction = new SpecialAction();
|
||||
|
||||
// Store the factory
|
||||
fileStreamFactory = factory;
|
||||
@@ -165,7 +172,9 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution
|
||||
ColumnInfo = Columns,
|
||||
Id = Id,
|
||||
BatchId = BatchId,
|
||||
RowCount = RowCount
|
||||
RowCount = RowCount,
|
||||
SpecialAction = ProcessSpecialAction()
|
||||
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -236,6 +245,51 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generates the execution plan from the table returned
|
||||
/// </summary>
|
||||
/// <returns>An execution plan object</returns>
|
||||
public Task<ExecutionPlan> GetExecutionPlan()
|
||||
{
|
||||
// Proccess the action just incase is hasn't been yet
|
||||
ProcessSpecialAction();
|
||||
|
||||
// Sanity check to make sure that the results have been read beforehand
|
||||
if (!hasBeenRead)
|
||||
{
|
||||
throw new InvalidOperationException(SR.QueryServiceResultSetNotRead);
|
||||
}
|
||||
// Check that we this result set contains a showplan
|
||||
else if (!specialAction.ExpectYukonXMLShowPlan)
|
||||
{
|
||||
throw new Exception(SR.QueryServiceExecutionPlanNotFound);
|
||||
}
|
||||
|
||||
|
||||
return Task.Factory.StartNew(() =>
|
||||
{
|
||||
string content = null;
|
||||
string format = null;
|
||||
|
||||
using (IFileStreamReader fileStreamReader = fileStreamFactory.GetReader(outputFileName))
|
||||
{
|
||||
// Determine the format and get the first col/row of XML
|
||||
content = fileStreamReader.ReadRow(0, Columns)[0].DisplayValue;
|
||||
|
||||
if (specialAction.ExpectYukonXMLShowPlan)
|
||||
{
|
||||
format = "xml";
|
||||
}
|
||||
}
|
||||
|
||||
return new ExecutionPlan
|
||||
{
|
||||
Format = format,
|
||||
Content = content
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads from the reader until there are no more results to read
|
||||
/// </summary>
|
||||
@@ -436,6 +490,21 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determine the special action, if any, for this result set
|
||||
/// </summary>
|
||||
private SpecialAction ProcessSpecialAction()
|
||||
{
|
||||
|
||||
// Check if this result set is a showplan
|
||||
if (dataReader.Columns.Length == 1 && string.Compare(dataReader.Columns[0].ColumnName, YukonXmlShowPlanColumn, StringComparison.OrdinalIgnoreCase) == 0)
|
||||
{
|
||||
specialAction.ExpectYukonXMLShowPlan = true;
|
||||
}
|
||||
|
||||
return specialAction;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
//
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
using System;
|
||||
|
||||
namespace Microsoft.SqlTools.ServiceLayer.QueryExecution
|
||||
{
|
||||
/// <summary>
|
||||
/// Class that represents a Special Action which occured by user request during the query
|
||||
/// </summary>
|
||||
public class SpecialAction {
|
||||
|
||||
#region Private Class variables
|
||||
|
||||
// Underlying representation as bitwise flags to simplify logic
|
||||
[Flags]
|
||||
private enum ActionFlags
|
||||
{
|
||||
None = 0,
|
||||
// All added options must be powers of 2
|
||||
ExpectYukonXmlShowPlan = 1
|
||||
}
|
||||
|
||||
private ActionFlags flags;
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// The type of XML execution plan that is contained with in a result set
|
||||
/// </summary>
|
||||
public SpecialAction()
|
||||
{
|
||||
flags = ActionFlags.None;
|
||||
}
|
||||
|
||||
#region Public Functions
|
||||
/// <summary>
|
||||
/// No Special action performed
|
||||
/// </summary>
|
||||
public bool None
|
||||
{
|
||||
get { return flags == ActionFlags.None; }
|
||||
set
|
||||
{
|
||||
flags = ActionFlags.None;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Contains an XML execution plan result set
|
||||
/// </summary>
|
||||
public bool ExpectYukonXMLShowPlan
|
||||
{
|
||||
get { return flags.HasFlag(ActionFlags.ExpectYukonXmlShowPlan); }
|
||||
set
|
||||
{
|
||||
if (value)
|
||||
{
|
||||
// OR flags with value to apply
|
||||
flags |= ActionFlags.ExpectYukonXmlShowPlan;
|
||||
}
|
||||
else
|
||||
{
|
||||
// AND flags with the inverse of the value we want to remove
|
||||
flags &= ~(ActionFlags.ExpectYukonXmlShowPlan);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Aggregate this special action with the input
|
||||
/// </summary>
|
||||
public void CombineSpecialAction(SpecialAction action)
|
||||
{
|
||||
flags |= action.flags;
|
||||
}
|
||||
|
||||
#endregion
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user