/// <summary> /// Query disposal meant to be called from another service. Utilizes callbacks to allow /// custom actions to be performed on success or failure. /// </summary> /// <param name="ownerUri">The identifier of the query to be disposed</param> /// <param name="successAction">Action to perform on success</param> /// <param name="failureAction">Action to perform on failure</param> public async Task InterServiceDisposeQuery(string ownerUri, Func <Task> successAction, Func <string, Task> failureAction) { Validate.IsNotNull(nameof(successAction), successAction); Validate.IsNotNull(nameof(failureAction), failureAction); try { // Attempt to remove the query for the owner uri Query result; if (!ActiveQueries.TryRemove(ownerUri, out result)) { await failureAction(SR.QueryServiceRequestsNoQuery); return; } // Cleanup the query result.Dispose(); // Success await successAction(); } catch (Exception e) { await failureAction(e.Message); } }
public async Task HandleDisposeRequest(QueryDisposeParams disposeParams, RequestContext <QueryDisposeResult> requestContext) { try { // Attempt to remove the query for the owner uri Query result; if (!ActiveQueries.TryRemove(disposeParams.OwnerUri, out result)) { await requestContext.SendResult(new QueryDisposeResult { Messages = SR.QueryServiceRequestsNoQuery }); return; } // Cleanup the query result.Dispose(); // Success await requestContext.SendResult(new QueryDisposeResult { Messages = null }); } catch (Exception e) { await requestContext.SendError(e.Message); } }
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); }
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> /// Handles a request to execute a string and return the result /// </summary> internal async Task HandleSimpleExecuteRequest(SimpleExecuteParams executeParams, RequestContext <SimpleExecuteResult> requestContext) { try { string randomUri = Guid.NewGuid().ToString(); ExecuteStringParams executeStringParams = new ExecuteStringParams { Query = executeParams.QueryString, // generate guid as the owner uri to make sure every query is unique OwnerUri = randomUri }; // get connection ConnectionInfo connInfo; if (!ConnectionService.TryFindConnection(executeParams.OwnerUri, out connInfo)) { await requestContext.SendError(SR.QueryServiceQueryInvalidOwnerUri); return; } ConnectParams connectParams = new ConnectParams { OwnerUri = randomUri, Connection = connInfo.ConnectionDetails, Type = ConnectionType.Default }; Task workTask = Task.Run(async() => { await ConnectionService.Connect(connectParams); ConnectionInfo newConn; ConnectionService.TryFindConnection(randomUri, out newConn); 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 query => { try { // check to make sure any results were recieved if (query.Batches.Length == 0 || query.Batches[0].ResultSets.Count == 0) { await requestContext.SendError(SR.QueryServiceResultSetHasNoResults); return; } long rowCount = query.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); return; } SimpleExecuteResult result = new SimpleExecuteResult { RowCount = rowCount, ColumnInfo = query.Batches[0].ResultSets[0].Columns, Rows = new DbCellValue[0][] }; if (rowCount > 0) { SubsetParams subsetRequestParams = new SubsetParams { OwnerUri = randomUri, BatchIndex = 0, ResultSetIndex = 0, RowsStartIndex = 0, RowsCount = Convert.ToInt32(rowCount) }; // get the data to send back ResultSetSubset subset = await InterServiceResultSubset(subsetRequestParams); result.Rows = subset.Rows; } await requestContext.SendResult(result); } finally { Query removedQuery; Task removedTask; // remove the active query since we are done with it ActiveQueries.TryRemove(randomUri, out removedQuery); ActiveSimpleExecuteRequests.TryRemove(randomUri, out removedTask); ConnectionService.Disconnect(new DisconnectParams() { OwnerUri = randomUri, Type = null }); } }; // handle sending error back when query fails Query.QueryAsyncErrorEventHandler queryFail = async(q, e) => { await requestContext.SendError(e); }; await InterServiceExecuteQuery(executeStringParams, newConn, newContext, null, queryCreateFailureAction, queryComplete, queryFail); }); ActiveSimpleExecuteRequests.TryAdd(randomUri, workTask); } catch (Exception ex) { await requestContext.SendError(ex.ToString()); } }
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); }
private async Task <Query> CreateAndActivateNewQuery(QueryExecuteParams executeParams, RequestContext <QueryExecuteResult> requestContext) { try { // Attempt to get the connection for the editor ConnectionInfo connectionInfo; if (!ConnectionService.TryFindConnection(executeParams.OwnerUri, out connectionInfo)) { await requestContext.SendError(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 settings = WorkspaceService.CurrentSettings.QueryExecutionSettings; // Get query text from the workspace. ScriptFile queryFile = WorkspaceService.Workspace.GetFile(executeParams.OwnerUri); string queryText; if (executeParams.QuerySelection != null) { string[] queryTextArray = queryFile.GetLinesInRange( new BufferRange( new BufferPosition( executeParams.QuerySelection.StartLine + 1, executeParams.QuerySelection.StartColumn + 1 ), new BufferPosition( executeParams.QuerySelection.EndLine + 1, executeParams.QuerySelection.EndColumn + 1 ) ) ); queryText = queryTextArray.Aggregate((a, b) => a + '\r' + '\n' + b); } else { queryText = queryFile.Contents; } // If we can't add the query now, it's assumed the query is in progress Query newQuery = new Query(queryText, connectionInfo, settings, BufferFileFactory); if (!ActiveQueries.TryAdd(executeParams.OwnerUri, newQuery)) { await requestContext.SendError(SR.QueryServiceQueryInProgress); newQuery.Dispose(); return(null); } return(newQuery); } catch (Exception e) { await requestContext.SendError(e.Message); return(null); } // Any other exceptions will fall through here and be collected at the end }
/// <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)); }