/// <summary> /// Handles request to execute a selection of a document in the workspace service /// </summary> internal async Task HandleExecuteRequest(ExecuteRequestParamsBase executeParams, RequestContext <ExecuteRequestResult> requestContext) { try { // Setup actions to perform upon successful start and on failure to start Func <Query, Task <bool> > queryCreateSuccessAction = async q => { await requestContext.SendResult(new ExecuteRequestResult()); Logger.Write(TraceEventType.Stop, $"Response for Query: '{executeParams.OwnerUri} sent. Query Complete!"); return(true); }; Func <string, Task> queryCreateFailureAction = message => { Logger.Write(TraceEventType.Warning, $"Failed to create Query: '{executeParams.OwnerUri}. Message: '{message}' Complete!"); return(requestContext.SendError(message)); }; // Use the internal handler to launch the query WorkTask = Task.Run(async() => { await InterServiceExecuteQuery(executeParams, null, requestContext, queryCreateSuccessAction, queryCreateFailureAction, null, null); }); } catch (Exception ex) { await requestContext.SendError(ex.ToString()); } }
// Internal for testing purposes internal string GetSqlText(ExecuteRequestParamsBase request) { // If it is a document selection, we'll retrieve the text from the document ExecuteDocumentSelectionParams docRequest = request as ExecuteDocumentSelectionParams; if (docRequest != null) { return(GetSqlTextFromSelectionData(docRequest.OwnerUri, docRequest.QuerySelection)); } // If it is a document statement, we'll retrieve the text from the document ExecuteDocumentStatementParams stmtRequest = request as ExecuteDocumentStatementParams; if (stmtRequest != null) { return(GetSqlStatementAtPosition(stmtRequest.OwnerUri, stmtRequest.Line, stmtRequest.Column)); } // If it is an ExecuteStringParams, return the text as is ExecuteStringParams stringRequest = request as ExecuteStringParams; if (stringRequest != null) { return(stringRequest.Query); } // Note, this shouldn't be possible due to inheritance rules throw new InvalidCastException("Invalid request type"); }
/// <summary> /// Handles request to execute a selection of a document in the workspace service /// </summary> internal Task HandleExecuteRequest(ExecuteRequestParamsBase executeParams, RequestContext <ExecuteRequestResult> requestContext) { // Setup actions to perform upon successful start and on failure to start Func <Task> queryCreationAction = () => requestContext.SendResult(new ExecuteRequestResult()); Func <string, Task> queryFailAction = requestContext.SendError; // Use the internal handler to launch the query return(InterServiceExecuteQuery(executeParams, requestContext, queryCreationAction, queryFailAction)); }
/// <summary> /// Handles request to execute a selection of a document in the workspace service /// </summary> internal Task HandleExecuteRequest(ExecuteRequestParamsBase executeParams, RequestContext <ExecuteRequestResult> requestContext) { // Setup actions to perform upon successful start and on failure to start Func <Query, Task <bool> > queryCreateSuccessAction = async q => { await requestContext.SendResult(new ExecuteRequestResult()); return(true); }; Func <string, Task> queryCreateFailureAction = message => requestContext.SendError(message); // Use the internal handler to launch the query return(InterServiceExecuteQuery(executeParams, null, requestContext, queryCreateSuccessAction, queryCreateFailureAction, null, null)); }
/// <summary> /// Query execution meant to be called from another service. Utilizes callbacks to allow /// custom actions to be taken upon creation of query and failure to create query. /// </summary> /// <param name="executeParams">Params for creating the new query</param> /// <param name="eventSender">Object that can send events for query execution progress</param> /// <param name="queryCreatedAction"> /// Action to perform when query has been successfully created, right before execution of /// the query /// </param> /// <param name="failureAction">Action to perform if query was not successfully created</param> public async Task InterServiceExecuteQuery(ExecuteRequestParamsBase executeParams, IEventSender eventSender, Func <Task> queryCreatedAction, Func <string, Task> failureAction) { Validate.IsNotNull(nameof(executeParams), executeParams); Validate.IsNotNull(nameof(eventSender), eventSender); Validate.IsNotNull(nameof(queryCreatedAction), queryCreatedAction); Validate.IsNotNull(nameof(failureAction), failureAction); // Get a new active query Query newQuery = await CreateAndActivateNewQuery(executeParams, queryCreatedAction, failureAction); // Execute the query asynchronously ExecuteAndCompleteQuery(executeParams.OwnerUri, eventSender, newQuery); }
private async Task <Query> CreateAndActivateNewQuery(ExecuteRequestParamsBase executeParams, Func <Task> successAction, Func <string, Task> failureAction) { try { // Attempt to get the connection for the editor ConnectionInfo connectionInfo; if (!ConnectionService.TryFindConnection(executeParams.OwnerUri, out connectionInfo)) { await failureAction(SR.QueryServiceQueryInvalidOwnerUri); return(null); } // Attempt to clean out any old query on the owner URI Query oldQuery; if (ActiveQueries.TryGetValue(executeParams.OwnerUri, out oldQuery) && oldQuery.HasExecuted) { oldQuery.Dispose(); ActiveQueries.TryRemove(executeParams.OwnerUri, out oldQuery); } // Retrieve the current settings for executing the query with QueryExecutionSettings querySettings = Settings.QueryExecutionSettings; // Apply execution parameter settings querySettings.ExecutionPlanOptions = executeParams.ExecutionPlanOptions; // If we can't add the query now, it's assumed the query is in progress Query newQuery = new Query(GetSqlText(executeParams), connectionInfo, querySettings, BufferFileFactory); if (!ActiveQueries.TryAdd(executeParams.OwnerUri, newQuery)) { await failureAction(SR.QueryServiceQueryInProgress); newQuery.Dispose(); return(null); } // Successfully created query await successAction(); return(newQuery); } catch (Exception e) { await failureAction(e.Message); return(null); } }
private Query CreateQuery(ExecuteRequestParamsBase executeParams, ConnectionInfo connInfo) { // Attempt to get the connection for the editor ConnectionInfo connectionInfo; if (connInfo != null) { connectionInfo = connInfo; } else if (!ConnectionService.TryFindConnection(executeParams.OwnerUri, out connectionInfo)) { throw new ArgumentOutOfRangeException(nameof(executeParams.OwnerUri), SR.QueryServiceQueryInvalidOwnerUri); } // Attempt to clean out any old query on the owner URI Query oldQuery; // DevNote: // if any oldQuery exists on the executeParams.OwnerUri but it has not yet executed, // then shouldn't we cancel and clean out that query since we are about to create a new query object on the current OwnerUri. // if (ActiveQueries.TryGetValue(executeParams.OwnerUri, out oldQuery) && (oldQuery.HasExecuted || oldQuery.HasCancelled)) { oldQuery.Dispose(); ActiveQueries.TryRemove(executeParams.OwnerUri, out oldQuery); } // Retrieve the current settings for executing the query with QueryExecutionSettings settings = Settings.QueryExecutionSettings; // Apply execution parameter settings settings.ExecutionPlanOptions = executeParams.ExecutionPlanOptions; // If we can't add the query now, it's assumed the query is in progress Query newQuery = new Query(GetSqlText(executeParams), connectionInfo, settings, BufferFileFactory, executeParams.GetFullColumnSchema); if (!ActiveQueries.TryAdd(executeParams.OwnerUri, newQuery)) { newQuery.Dispose(); throw new InvalidOperationException(SR.QueryServiceQueryInProgress); } Logger.Write(TraceEventType.Information, $"Query object for URI:'{executeParams.OwnerUri}' created"); return(newQuery); }
// Internal for testing purposes internal string GetSqlText(ExecuteRequestParamsBase request) { // If it is a document selection, we'll retrieve the text from the document ExecuteDocumentSelectionParams docRequest = request as ExecuteDocumentSelectionParams; if (docRequest != null) { // Get the document from the parameters ScriptFile queryFile = WorkspaceService.Workspace.GetFile(docRequest.OwnerUri); // If a selection was not provided, use the entire document if (docRequest.QuerySelection == null) { return(queryFile.Contents); } // A selection was provided, so get the lines in the selected range string[] queryTextArray = queryFile.GetLinesInRange( new BufferRange( new BufferPosition( docRequest.QuerySelection.StartLine + 1, docRequest.QuerySelection.StartColumn + 1 ), new BufferPosition( docRequest.QuerySelection.EndLine + 1, docRequest.QuerySelection.EndColumn + 1 ) ) ); return(string.Join(Environment.NewLine, queryTextArray)); } // If it is an ExecuteStringParams, return the text as is ExecuteStringParams stringRequest = request as ExecuteStringParams; if (stringRequest != null) { return(stringRequest.Query); } // Note, this shouldn't be possible due to inheritance rules throw new InvalidCastException("Invalid request type"); }
private Query CreateQuery(ExecuteRequestParamsBase executeParams, ConnectionInfo connInfo) { // Attempt to get the connection for the editor ConnectionInfo connectionInfo; if (connInfo != null) { connectionInfo = connInfo; } else if (!ConnectionService.TryFindConnection(executeParams.OwnerUri, out connectionInfo)) { throw new ArgumentOutOfRangeException(nameof(executeParams.OwnerUri), SR.QueryServiceQueryInvalidOwnerUri); } // Attempt to clean out any old query on the owner URI Query oldQuery; if (ActiveQueries.TryGetValue(executeParams.OwnerUri, out oldQuery) && oldQuery.HasExecuted) { oldQuery.Dispose(); ActiveQueries.TryRemove(executeParams.OwnerUri, out oldQuery); } // Retrieve the current settings for executing the query with QueryExecutionSettings settings = Settings.QueryExecutionSettings; // Apply execution parameter settings settings.ExecutionPlanOptions = executeParams.ExecutionPlanOptions; // If we can't add the query now, it's assumed the query is in progress Query newQuery = new Query(GetSqlText(executeParams), connectionInfo, settings, BufferFileFactory, executeParams.GetFullColumnSchema); if (!ActiveQueries.TryAdd(executeParams.OwnerUri, newQuery)) { newQuery.Dispose(); throw new InvalidOperationException(SR.QueryServiceQueryInProgress); } return(newQuery); }
/// <summary> /// Query execution meant to be called from another service. Utilizes callbacks to allow /// 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 /// will be executed asynchronously. If result is <c>false</c>, query will be disposed. May /// be <c>null</c> /// </param> /// <param name="queryCreateFailFunc"> /// Callback for when query failed to be created successfully. Error message is provided. /// May be <c>null</c>. /// </param> /// <param name="querySuccessFunc"> /// Callback to call when query has completed execution successfully. May be <c>null</c>. /// </param> /// <param name="queryFailureFunc"> /// 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, Query.QueryAsyncEventHandler querySuccessFunc, Query.QueryAsyncErrorEventHandler queryFailureFunc, bool applyExecutionSettings = false) { Validate.IsNotNull(nameof(executeParams), executeParams); Validate.IsNotNull(nameof(queryEventSender), queryEventSender); Query newQuery; try { // Get a new active query newQuery = CreateQuery(executeParams, connInfo, applyExecutionSettings); if (queryCreateSuccessFunc != null && !await queryCreateSuccessFunc(newQuery)) { // The callback doesn't want us to continue, for some reason // It's ok if we leave the query behind in the active query list, the next call // to execute will replace it. newQuery.Dispose(); return; } } catch (Exception e) { // Call the failure callback if it was provided if (queryCreateFailFunc != null) { await queryCreateFailFunc(e.Message); } return; } // Execute the query asynchronously ExecuteAndCompleteQuery(executeParams.OwnerUri, newQuery, queryEventSender, querySuccessFunc, queryFailureFunc); }
private Query CreateQuery( ExecuteRequestParamsBase executeParams, ConnectionInfo connInfo, bool applyExecutionSettings) { // Attempt to get the connection for the editor ConnectionInfo connectionInfo; if (connInfo != null) { connectionInfo = connInfo; } else if (!ConnectionService.TryFindConnection(executeParams.OwnerUri, out connectionInfo)) { throw new ArgumentOutOfRangeException(nameof(executeParams.OwnerUri), SR.QueryServiceQueryInvalidOwnerUri); } // Attempt to clean out any old query on the owner URI Query oldQuery; // DevNote: // if any oldQuery exists on the executeParams.OwnerUri but it has not yet executed, // then shouldn't we cancel and clean out that query since we are about to create a new query object on the current OwnerUri. // if (ActiveQueries.TryGetValue(executeParams.OwnerUri, out oldQuery) && (oldQuery.HasExecuted || oldQuery.HasCancelled || oldQuery.HasErrored)) { oldQuery.Dispose(); ActiveQueries.TryRemove(executeParams.OwnerUri, out oldQuery); } // check if there are active query execution settings for the editor, otherwise, use the global settings QueryExecutionSettings settings; if (this.ActiveQueryExecutionSettings.TryGetValue(executeParams.OwnerUri, out settings)) { // special-case handling for query plan options to maintain compat with query execution API parameters // the logic is that if either the query execute API parameters or the active query setttings // request a plan then enable the query option ExecutionPlanOptions executionPlanOptions = executeParams.ExecutionPlanOptions; if (settings.IncludeActualExecutionPlanXml) { executionPlanOptions.IncludeActualExecutionPlanXml = settings.IncludeActualExecutionPlanXml; } if (settings.IncludeEstimatedExecutionPlanXml) { executionPlanOptions.IncludeEstimatedExecutionPlanXml = settings.IncludeEstimatedExecutionPlanXml; } settings.ExecutionPlanOptions = executionPlanOptions; } else { settings = Settings.QueryExecutionSettings; settings.ExecutionPlanOptions = executeParams.ExecutionPlanOptions; } // If we can't add the query now, it's assumed the query is in progress Query newQuery = new Query( GetSqlText(executeParams), connectionInfo, settings, BufferFileFactory, executeParams.GetFullColumnSchema, applyExecutionSettings); if (!ActiveQueries.TryAdd(executeParams.OwnerUri, newQuery)) { newQuery.Dispose(); throw new InvalidOperationException(SR.QueryServiceQueryInProgress); } Logger.Write(TraceEventType.Information, $"Query object for URI:'{executeParams.OwnerUri}' created"); return(newQuery); }