mirror of
https://github.com/ckaczor/sqltoolsservice.git
synced 2026-01-14 17:23:27 -05:00
Adds a execute and return result message (#383)
* inital request * refactored query execution failure callback to take exception * added failure callback to execute and return * added test for query execute and return * updated params * removed dead code * addressed feedback; added multiple active result set support; updated tests * addessed feedback and added testing and errors and verification * change <= to == * changed name of trashQ to removedQuery
This commit is contained in:
@@ -137,6 +137,7 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution
|
||||
serviceHost.SetRequestHandler(SaveResultsAsExcelRequest.Type, HandleSaveResultsAsExcelRequest);
|
||||
serviceHost.SetRequestHandler(SaveResultsAsJsonRequest.Type, HandleSaveResultsAsJsonRequest);
|
||||
serviceHost.SetRequestHandler(QueryExecutionPlanRequest.Type, HandleExecutionPlanRequest);
|
||||
serviceHost.SetRequestHandler(SimpleExecuteRequest.Type, HandleSimpleExecuteRequest);
|
||||
|
||||
// Register handler for shutdown event
|
||||
serviceHost.RegisterShutdownTask((shutdownParams, requestContext) =>
|
||||
@@ -165,7 +166,88 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution
|
||||
Func<string, Task> queryCreateFailureAction = message => requestContext.SendError(message);
|
||||
|
||||
// Use the internal handler to launch the query
|
||||
return InterServiceExecuteQuery(executeParams, requestContext, queryCreateSuccessAction, queryCreateFailureAction, null, null);
|
||||
return InterServiceExecuteQuery(executeParams, null, requestContext, queryCreateSuccessAction, queryCreateFailureAction, null, null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handles a request to execute a string and return the result
|
||||
/// </summary>
|
||||
internal Task HandleSimpleExecuteRequest(SimpleExecuteParams executeParams,
|
||||
RequestContext<SimpleExecuteResult> requestContext)
|
||||
{
|
||||
ExecuteStringParams executeStringParams = new ExecuteStringParams
|
||||
{
|
||||
Query = executeParams.QueryString,
|
||||
// generate guid as the owner uri to make sure every query is unique
|
||||
OwnerUri = Guid.NewGuid().ToString()
|
||||
};
|
||||
|
||||
// get connection
|
||||
ConnectionInfo connInfo;
|
||||
if (!ConnectionService.TryFindConnection(executeParams.OwnerUri, out connInfo))
|
||||
{
|
||||
return requestContext.SendError(SR.QueryServiceQueryInvalidOwnerUri);
|
||||
}
|
||||
|
||||
if (connInfo.ConnectionDetails.MultipleActiveResultSets == null || connInfo.ConnectionDetails.MultipleActiveResultSets == false) {
|
||||
// if multipleActive result sets is not allowed, don't specific a connection and make the ownerURI the true owneruri
|
||||
connInfo = null;
|
||||
executeStringParams.OwnerUri = executeParams.OwnerUri;
|
||||
}
|
||||
|
||||
Func<string, Task> queryCreateFailureAction = message => requestContext.SendError(message);
|
||||
|
||||
ResultOnlyContext<SimpleExecuteResult> newContext = new ResultOnlyContext<SimpleExecuteResult>(requestContext);
|
||||
|
||||
// handle sending event back when the query completes
|
||||
Query.QueryAsyncEventHandler queryComplete = async q =>
|
||||
{
|
||||
Query removedQuery;
|
||||
// check to make sure any results were recieved
|
||||
if (q.Batches.Length == 0 || q.Batches[0].ResultSets.Count == 0)
|
||||
{
|
||||
await requestContext.SendError(SR.QueryServiceResultSetHasNoResults);
|
||||
ActiveQueries.TryRemove(executeStringParams.OwnerUri, out removedQuery);
|
||||
return;
|
||||
}
|
||||
|
||||
var rowCount = q.Batches[0].ResultSets[0].RowCount;
|
||||
// check to make sure there is a safe amount of rows to load into memory
|
||||
if (rowCount > Int32.MaxValue)
|
||||
{
|
||||
await requestContext.SendError(SR.QueryServiceResultSetTooLarge);
|
||||
ActiveQueries.TryRemove(executeStringParams.OwnerUri, out removedQuery);
|
||||
return;
|
||||
}
|
||||
|
||||
SubsetParams subsetRequestParams = new SubsetParams
|
||||
{
|
||||
OwnerUri = executeStringParams.OwnerUri,
|
||||
BatchIndex = 0,
|
||||
ResultSetIndex = 0,
|
||||
RowsStartIndex = 0,
|
||||
RowsCount = Convert.ToInt32(rowCount)
|
||||
};
|
||||
// get the data to send back
|
||||
ResultSetSubset subset = await InterServiceResultSubset(subsetRequestParams);
|
||||
SimpleExecuteResult result = new SimpleExecuteResult
|
||||
{
|
||||
RowCount = q.Batches[0].ResultSets[0].RowCount,
|
||||
ColumnInfo = q.Batches[0].ResultSets[0].Columns,
|
||||
Rows = subset.Rows
|
||||
};
|
||||
await requestContext.SendResult(result);
|
||||
// remove the active query since we are done with it
|
||||
ActiveQueries.TryRemove(executeStringParams.OwnerUri, out removedQuery);
|
||||
};
|
||||
|
||||
// handle sending error back when query fails
|
||||
Query.QueryAsyncErrorEventHandler queryFail = async (q, e) =>
|
||||
{
|
||||
await requestContext.SendError(e);
|
||||
};
|
||||
|
||||
return InterServiceExecuteQuery(executeStringParams, connInfo, newContext, null, queryCreateFailureAction, queryComplete, queryFail);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -325,6 +407,7 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution
|
||||
/// custom actions to be taken upon creation of query and failure to create query.
|
||||
/// </summary>
|
||||
/// <param name="executeParams">Parameters for execution</param>
|
||||
/// <param name="connInfo">Connection Info to use; will try and get the connection from owneruri if not provided</param>
|
||||
/// <param name="queryEventSender">Event sender that will send progressive events during execution of the query</param>
|
||||
/// <param name="queryCreateSuccessFunc">
|
||||
/// Callback for when query has been created successfully. If result is <c>true</c>, query
|
||||
@@ -342,6 +425,7 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution
|
||||
/// Callback to call when query has completed execution with errors. May be <c>null</c>.
|
||||
/// </param>
|
||||
public async Task InterServiceExecuteQuery(ExecuteRequestParamsBase executeParams,
|
||||
ConnectionInfo connInfo,
|
||||
IEventSender queryEventSender,
|
||||
Func<Query, Task<bool>> queryCreateSuccessFunc,
|
||||
Func<string, Task> queryCreateFailFunc,
|
||||
@@ -355,7 +439,7 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution
|
||||
try
|
||||
{
|
||||
// Get a new active query
|
||||
newQuery = CreateQuery(executeParams);
|
||||
newQuery = CreateQuery(executeParams, connInfo);
|
||||
if (queryCreateSuccessFunc != null && !await queryCreateSuccessFunc(newQuery))
|
||||
{
|
||||
// The callback doesn't want us to continue, for some reason
|
||||
@@ -441,11 +525,13 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution
|
||||
|
||||
#region Private Helpers
|
||||
|
||||
private Query CreateQuery(ExecuteRequestParamsBase executeParams)
|
||||
private Query CreateQuery(ExecuteRequestParamsBase executeParams, ConnectionInfo connInfo)
|
||||
{
|
||||
// Attempt to get the connection for the editor
|
||||
ConnectionInfo connectionInfo;
|
||||
if (!ConnectionService.TryFindConnection(executeParams.OwnerUri, out connectionInfo))
|
||||
if (connInfo != null) {
|
||||
connectionInfo = connInfo;
|
||||
} else if (!ConnectionService.TryFindConnection(executeParams.OwnerUri, out connectionInfo))
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(executeParams.OwnerUri), SR.QueryServiceQueryInvalidOwnerUri);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user