mirror of
https://github.com/ckaczor/sqltoolsservice.git
synced 2026-02-16 10:58:30 -05:00
WIP for query execution
This commit is contained in:
@@ -54,12 +54,6 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public IEnumerable<string> AutoCompleteList { get; private set; }
|
public IEnumerable<string> AutoCompleteList { get; private set; }
|
||||||
|
|
||||||
public void InitializeService(ServiceHost serviceHost)
|
|
||||||
{
|
|
||||||
// Register a callback for when a connection is created
|
|
||||||
ConnectionService.Instance.RegisterOnConnectionTask(UpdateAutoCompleteCache);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Update the cached autocomplete candidate list when the user connects to a database
|
/// Update the cached autocomplete candidate list when the user connects to a database
|
||||||
/// TODO: Update with refactoring/async
|
/// TODO: Update with refactoring/async
|
||||||
@@ -71,16 +65,17 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
|
|||||||
command.CommandText = "SELECT name FROM sys.tables";
|
command.CommandText = "SELECT name FROM sys.tables";
|
||||||
command.CommandTimeout = 15;
|
command.CommandTimeout = 15;
|
||||||
command.CommandType = CommandType.Text;
|
command.CommandType = CommandType.Text;
|
||||||
var reader = await command.ExecuteReaderAsync();
|
using (var reader = await command.ExecuteReaderAsync())
|
||||||
|
|
||||||
List<string> results = new List<string>();
|
|
||||||
while (await reader.ReadAsync())
|
|
||||||
{
|
{
|
||||||
results.Add(reader[0].ToString());
|
|
||||||
}
|
|
||||||
|
|
||||||
AutoCompleteList = results;
|
List<string> results = new List<string>();
|
||||||
await Task.FromResult(0);
|
while (await reader.ReadAsync())
|
||||||
|
{
|
||||||
|
results.Add(reader[0].ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
AutoCompleteList = results;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -0,0 +1,37 @@
|
|||||||
|
//
|
||||||
|
// Copyright (c) Microsoft. All rights reserved.
|
||||||
|
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||||
|
//
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using Microsoft.SqlTools.ServiceLayer.Hosting.Protocol.Contracts;
|
||||||
|
|
||||||
|
namespace Microsoft.SqlTools.ServiceLayer.QueryExecutionServices.Contracts
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Parameters for the query dispose request
|
||||||
|
/// </summary>
|
||||||
|
public class QueryDisposeParams
|
||||||
|
{
|
||||||
|
public Guid QueryId { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Parameters to return as the result of a query dispose request
|
||||||
|
/// </summary>
|
||||||
|
public class QueryDisposeResult
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Any error messages that occurred during disposing the result set. Optional, can be set
|
||||||
|
/// to null if there were no errors.
|
||||||
|
/// </summary>
|
||||||
|
public string Messages { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class QueryDisposeRequest
|
||||||
|
{
|
||||||
|
public static readonly
|
||||||
|
RequestType<QueryDisposeParams, QueryDisposeResult> Type =
|
||||||
|
RequestType<QueryDisposeParams, QueryDisposeResult>.Create("query/dispose");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Microsoft.SqlTools.ServiceLayer.QueryExecutionServices.Contracts
|
||||||
|
{
|
||||||
|
public class QueryExecuteCompleteNotification
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Any messages that came back from the server during execution of the query
|
||||||
|
/// </summary>
|
||||||
|
public string[] Messages { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Whether or not the query was successful. True indicates errors, false indicates success
|
||||||
|
/// </summary>
|
||||||
|
public bool Error { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Summaries of the result sets that were returned with the query
|
||||||
|
/// </summary>
|
||||||
|
public ResultSetSummary[] ResultSetSummaries { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
//
|
||||||
|
// Copyright (c) Microsoft. All rights reserved.
|
||||||
|
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||||
|
//
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using Microsoft.SqlTools.ServiceLayer.Hosting.Protocol.Contracts;
|
||||||
|
|
||||||
|
namespace Microsoft.SqlTools.ServiceLayer.QueryExecutionServices.Contracts
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Parameters for the query execute request
|
||||||
|
/// </summary>
|
||||||
|
public class QueryExecuteParams
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The text of the query to execute
|
||||||
|
/// </summary>
|
||||||
|
public string QueryText { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// URI for the editor that is asking for the query execute
|
||||||
|
/// </summary>
|
||||||
|
public string OwnerUri { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Parameters for the query execute result
|
||||||
|
/// </summary>
|
||||||
|
public class QueryExecuteResult
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Connection error messages. Optional, can be set to null to indicate no errors
|
||||||
|
/// </summary>
|
||||||
|
public string Messages { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class QueryExecuteRequest
|
||||||
|
{
|
||||||
|
public static readonly
|
||||||
|
RequestType<QueryExecuteParams, QueryExecuteResult> Type =
|
||||||
|
RequestType<QueryExecuteParams, QueryExecuteResult>.Create("query/execute");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
//
|
||||||
|
// Copyright (c) Microsoft. All rights reserved.
|
||||||
|
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||||
|
//
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using Microsoft.SqlTools.ServiceLayer.Hosting.Protocol.Contracts;
|
||||||
|
|
||||||
|
namespace Microsoft.SqlTools.ServiceLayer.QueryExecutionServices.Contracts
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Parameters for a query result subset retrieval request
|
||||||
|
/// </summary>
|
||||||
|
public class QueryExecuteSubsetParams
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// ID of the query to look up the results for
|
||||||
|
/// </summary>
|
||||||
|
public Guid QueryId { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Index of the result set to get the results from
|
||||||
|
/// </summary>
|
||||||
|
public int ResultSetIndex { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Beginning index of the rows to return from the selected resultset. This index will be
|
||||||
|
/// included in the results.
|
||||||
|
/// </summary>
|
||||||
|
public int RowsStartIndex { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Number of rows to include in the result of this request. If the number of the rows
|
||||||
|
/// exceeds the number of rows available after the start index, all available rows after
|
||||||
|
/// the start index will be returned.
|
||||||
|
/// </summary>
|
||||||
|
public int RowsCount { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
public class QueryExecuteSubsetResult
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public class QueryExecuteSubsetRequest
|
||||||
|
{
|
||||||
|
public static readonly
|
||||||
|
RequestType<QueryExecuteSubsetParams, QueryExecuteSubsetResult> Type =
|
||||||
|
RequestType<QueryExecuteSubsetParams, QueryExecuteSubsetResult>.Create("query/subset");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Data.Common;
|
||||||
|
|
||||||
|
namespace Microsoft.SqlTools.ServiceLayer.QueryExecutionServices.Contracts
|
||||||
|
{
|
||||||
|
public class ResultSet
|
||||||
|
{
|
||||||
|
public DbColumn[] Columns { get; set; }
|
||||||
|
|
||||||
|
public List<object[]> Rows { get; private set; }
|
||||||
|
|
||||||
|
public ResultSet()
|
||||||
|
{
|
||||||
|
Rows = new List<object[]>();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Add a row of data to the result set using a <see cref="DbDataReader"/> that has already
|
||||||
|
/// read in a row.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="reader">A <see cref="DbDataReader"/> that has already had a read performed</param>
|
||||||
|
public void AddRow(DbDataReader reader)
|
||||||
|
{
|
||||||
|
List<object> row = new List<object>();
|
||||||
|
for (int i = 0; i < reader.FieldCount; ++i)
|
||||||
|
{
|
||||||
|
row.Add(reader.GetValue(i));
|
||||||
|
}
|
||||||
|
Rows.Add(row.ToArray());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Microsoft.SqlTools.ServiceLayer.QueryExecutionServices.Contracts
|
||||||
|
{
|
||||||
|
public class ResultSetSubset
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Data.Common;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Microsoft.SqlTools.ServiceLayer.QueryExecutionServices.Contracts
|
||||||
|
{
|
||||||
|
public class ResultSetSummary
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The ID of the result set within the query results
|
||||||
|
/// </summary>
|
||||||
|
public int Id { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The number of rows that was returned with the resultset
|
||||||
|
/// </summary>
|
||||||
|
public long RowCount { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Details about the columns that are provided as solutions
|
||||||
|
/// </summary>
|
||||||
|
public DbColumn ColumnInfo { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,69 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Data;
|
||||||
|
using System.Data.Common;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.SqlTools.ServiceLayer.QueryExecutionServices.Contracts;
|
||||||
|
|
||||||
|
namespace Microsoft.SqlTools.ServiceLayer.QueryExecutionServices
|
||||||
|
{
|
||||||
|
public class Query //: IDisposable
|
||||||
|
{
|
||||||
|
public string QueryText { get; set; }
|
||||||
|
|
||||||
|
public DbConnection SqlConnection { get; set; }
|
||||||
|
|
||||||
|
private readonly CancellationTokenSource cancellationSource;
|
||||||
|
|
||||||
|
public List<ResultSet> ResultSets { get; set; }
|
||||||
|
|
||||||
|
public Query(string queryText, DbConnection connection)
|
||||||
|
{
|
||||||
|
QueryText = queryText;
|
||||||
|
SqlConnection = connection;
|
||||||
|
ResultSets = new List<ResultSet>();
|
||||||
|
cancellationSource = new CancellationTokenSource();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task Execute()
|
||||||
|
{
|
||||||
|
// Open the connection, if it's not already open
|
||||||
|
if ((SqlConnection.State & ConnectionState.Open) == 0)
|
||||||
|
{
|
||||||
|
await SqlConnection.OpenAsync(cancellationSource.Token);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a command that we'll use for executing the query
|
||||||
|
using (DbCommand command = SqlConnection.CreateCommand())
|
||||||
|
{
|
||||||
|
command.CommandText = QueryText;
|
||||||
|
command.CommandType = CommandType.Text;
|
||||||
|
|
||||||
|
// Execute the command to get back a reader
|
||||||
|
using (DbDataReader reader = await command.ExecuteReaderAsync(cancellationSource.Token))
|
||||||
|
{
|
||||||
|
do
|
||||||
|
{
|
||||||
|
// Create a new result set that we'll use to store all the data
|
||||||
|
ResultSet resultSet = new ResultSet();
|
||||||
|
if (reader.CanGetColumnSchema())
|
||||||
|
{
|
||||||
|
resultSet.Columns = reader.GetColumnSchema().ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read until we hit the end of the result set
|
||||||
|
while (await reader.ReadAsync(cancellationSource.Token))
|
||||||
|
{
|
||||||
|
resultSet.AddRow(reader);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add the result set to the results of the query
|
||||||
|
ResultSets.Add(resultSet);
|
||||||
|
} while (await reader.NextResultAsync(cancellationSource.Token));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,89 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Concurrent;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.SqlTools.ServiceLayer.Hosting;
|
||||||
|
using Microsoft.SqlTools.ServiceLayer.Hosting.Protocol;
|
||||||
|
using Microsoft.SqlTools.ServiceLayer.QueryExecutionServices.Contracts;
|
||||||
|
|
||||||
|
namespace Microsoft.SqlTools.ServiceLayer.QueryExecutionServices
|
||||||
|
{
|
||||||
|
public sealed class QueryExecutionService
|
||||||
|
{
|
||||||
|
#region Singleton Instance Implementation
|
||||||
|
|
||||||
|
private static readonly Lazy<QueryExecutionService> instance = new Lazy<QueryExecutionService>(() => new QueryExecutionService());
|
||||||
|
|
||||||
|
public static QueryExecutionService Instance
|
||||||
|
{
|
||||||
|
get { return instance.Value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
private QueryExecutionService() { }
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Properties
|
||||||
|
|
||||||
|
private readonly Lazy<ConcurrentDictionary<string, Query>> queries =
|
||||||
|
new Lazy<ConcurrentDictionary<string, Query>>(() => new ConcurrentDictionary<string, Query>());
|
||||||
|
|
||||||
|
private ConcurrentDictionary<string, Query> Queries
|
||||||
|
{
|
||||||
|
get { return queries.Value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Public Methods
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="serviceHost"></param>
|
||||||
|
public void InitializeService(ServiceHost serviceHost)
|
||||||
|
{
|
||||||
|
// Register handlers for requests
|
||||||
|
serviceHost.SetRequestHandler(QueryExecuteRequest.Type, HandleExecuteRequest);
|
||||||
|
serviceHost.SetRequestHandler(QueryExecuteSubsetRequest.Type, HandleResultSubsetRequest);
|
||||||
|
serviceHost.SetRequestHandler(QueryDisposeRequest.Type, HandleDisposeRequest);
|
||||||
|
|
||||||
|
// Register handlers for events
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Request Handlers
|
||||||
|
|
||||||
|
private async Task HandleExecuteRequest(QueryExecuteParams executeParams,
|
||||||
|
RequestContext<QueryExecuteResult> requestContext)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task HandleResultSubsetRequest(QueryExecuteSubsetParams subsetParams,
|
||||||
|
RequestContext<QueryExecuteSubsetResult> requestContext)
|
||||||
|
{
|
||||||
|
await Task.FromResult(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task HandleDisposeRequest(QueryDisposeParams disposeParams,
|
||||||
|
RequestContext<QueryDisposeResult> requestContext)
|
||||||
|
{
|
||||||
|
string messages = null;
|
||||||
|
|
||||||
|
Query result;
|
||||||
|
if (!Queries.TryRemove(disposeParams., out result))
|
||||||
|
{
|
||||||
|
messages = "Failed to dispose query, ID not found.";
|
||||||
|
}
|
||||||
|
|
||||||
|
await requestContext.SendResult(new QueryDisposeResult
|
||||||
|
{
|
||||||
|
Messages = messages
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user