diff --git a/src/Microsoft.SqlTools.ServiceLayer/LanguageServices/LanguageService.cs b/src/Microsoft.SqlTools.ServiceLayer/LanguageServices/LanguageService.cs
index 87001466..c788e734 100644
--- a/src/Microsoft.SqlTools.ServiceLayer/LanguageServices/LanguageService.cs
+++ b/src/Microsoft.SqlTools.ServiceLayer/LanguageServices/LanguageService.cs
@@ -1679,5 +1679,42 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
FileUtilities.SafeDirectoryDelete(FileUtilities.PeekDefinitionTempFolder, true);
}
}
+
+ internal string ParseStatementAtPosition(string sql, int line, int column)
+ {
+ // adjust from 0-based to 1-based index
+ int parserLine = line + 1;
+ int parserColumn = column + 1;
+
+ // parse current SQL file contents to retrieve a list of errors
+ ParseResult parseResult = Parser.Parse(sql, this.DefaultParseOptions);
+ if (parseResult != null && parseResult.Script != null && parseResult.Script.Batches != null)
+ {
+ foreach (var batch in parseResult.Script.Batches)
+ {
+ if (batch.Statements == null)
+ {
+ continue;
+ }
+
+ // check if the batch matches parameters
+ if (batch.StartLocation.LineNumber <= parserLine
+ && batch.EndLocation.LineNumber >= parserLine)
+ {
+ foreach (var statement in batch.Statements)
+ {
+ // check if the statement matches parameters
+ if (statement.StartLocation.LineNumber <= parserLine
+ && statement.EndLocation.LineNumber >= parserLine)
+ {
+ return statement.Sql;
+ }
+ }
+ }
+ }
+ }
+
+ return string.Empty;
+ }
}
}
\ No newline at end of file
diff --git a/src/Microsoft.SqlTools.ServiceLayer/QueryExecution/Contracts/ExecuteRequests/ExecuteDocumentStatementRequest.cs b/src/Microsoft.SqlTools.ServiceLayer/QueryExecution/Contracts/ExecuteRequests/ExecuteDocumentStatementRequest.cs
new file mode 100644
index 00000000..2c575b43
--- /dev/null
+++ b/src/Microsoft.SqlTools.ServiceLayer/QueryExecution/Contracts/ExecuteRequests/ExecuteDocumentStatementRequest.cs
@@ -0,0 +1,32 @@
+//
+// 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.Hosting.Protocol.Contracts;
+
+namespace Microsoft.SqlTools.ServiceLayer.QueryExecution.Contracts.ExecuteRequests
+{
+ ///
+ /// Parameters for executing a query from a document open in the workspace
+ ///
+ public class ExecuteDocumentStatementParams : ExecuteRequestParamsBase
+ {
+ ///
+ /// Line in the document for the location of the SQL statement
+ ///
+ public int Line { get; set; }
+
+ ///
+ /// Column in the document for the location of the SQL statement
+ ///
+ public int Column { get; set; }
+ }
+
+ public class ExecuteDocumentStatementRequest
+ {
+ public static readonly
+ RequestType Type =
+ RequestType.Create("query/executedocumentstatement");
+ }
+}
diff --git a/src/Microsoft.SqlTools.ServiceLayer/QueryExecution/QueryExecutionService.cs b/src/Microsoft.SqlTools.ServiceLayer/QueryExecution/QueryExecutionService.cs
index 857f3cb1..088d6f16 100644
--- a/src/Microsoft.SqlTools.ServiceLayer/QueryExecution/QueryExecutionService.cs
+++ b/src/Microsoft.SqlTools.ServiceLayer/QueryExecution/QueryExecutionService.cs
@@ -129,6 +129,7 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution
{
// Register handlers for requests
serviceHost.SetRequestHandler(ExecuteDocumentSelectionRequest.Type, HandleExecuteRequest);
+ serviceHost.SetRequestHandler(ExecuteDocumentStatementRequest.Type, HandleExecuteRequest);
serviceHost.SetRequestHandler(ExecuteStringRequest.Type, HandleExecuteRequest);
serviceHost.SetRequestHandler(SubsetRequest.Type, HandleResultSubsetRequest);
serviceHost.SetRequestHandler(QueryDisposeRequest.Type, HandleDisposeRequest);
@@ -691,32 +692,14 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution
ExecuteDocumentSelectionParams docRequest = request as ExecuteDocumentSelectionParams;
if (docRequest != null)
{
- // Get the document from the parameters
- ScriptFile queryFile = WorkspaceService.Workspace.GetFile(docRequest.OwnerUri);
- if (queryFile == null)
- {
- return string.Empty;
- }
- // If a selection was not provided, use the entire document
- if (docRequest.QuerySelection == null)
- {
- return queryFile.Contents;
- }
+ return GetSqlTextFromSelectionData(docRequest.OwnerUri, docRequest.QuerySelection);
+ }
- // 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 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
@@ -730,6 +713,55 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution
throw new InvalidCastException("Invalid request type");
}
+ ///
+ /// Return portion of document corresponding to the selection range
+ ///
+ internal string GetSqlTextFromSelectionData(string ownerUri, SelectionData selection)
+ {
+ // Get the document from the parameters
+ ScriptFile queryFile = WorkspaceService.Workspace.GetFile(ownerUri);
+ if (queryFile == null)
+ {
+ return string.Empty;
+ }
+ // If a selection was not provided, use the entire document
+ if (selection == null)
+ {
+ return queryFile.Contents;
+ }
+
+ // A selection was provided, so get the lines in the selected range
+ string[] queryTextArray = queryFile.GetLinesInRange(
+ new BufferRange(
+ new BufferPosition(
+ selection.StartLine + 1,
+ selection.StartColumn + 1
+ ),
+ new BufferPosition(
+ selection.EndLine + 1,
+ selection.EndColumn + 1
+ )
+ )
+ );
+ return string.Join(Environment.NewLine, queryTextArray);
+ }
+
+ ///
+ /// Return portion of document corresponding to the statement at the line and column
+ ///
+ internal string GetSqlStatementAtPosition(string ownerUri, int line, int column)
+ {
+ // Get the document from the parameters
+ ScriptFile queryFile = WorkspaceService.Workspace.GetFile(ownerUri);
+ if (queryFile == null)
+ {
+ return string.Empty;
+ }
+
+ return LanguageServices.LanguageService.Instance.ParseStatementAtPosition(
+ queryFile.Contents, line, column);
+ }
+
/// Internal for testing purposes
internal Task UpdateSettings(SqlToolsSettings newSettings, SqlToolsSettings oldSettings, EventContext eventContext)
{
diff --git a/test/Microsoft.SqlTools.ServiceLayer.UnitTests/QueryExecution/Execution/ServiceIntegrationTests.cs b/test/Microsoft.SqlTools.ServiceLayer.UnitTests/QueryExecution/Execution/ServiceIntegrationTests.cs
index 4a4a6952..929feb8b 100644
--- a/test/Microsoft.SqlTools.ServiceLayer.UnitTests/QueryExecution/Execution/ServiceIntegrationTests.cs
+++ b/test/Microsoft.SqlTools.ServiceLayer.UnitTests/QueryExecution/Execution/ServiceIntegrationTests.cs
@@ -21,6 +21,20 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.QueryExecution.Execution
#region Get SQL Tests
+ [Fact]
+ public void ExecuteDocumentStatementTest()
+ {
+ string query = string.Format("{0}{1}GO{1}{0}", Constants.StandardQuery, Environment.NewLine);
+ var workspaceService = GetDefaultWorkspaceService(query);
+ var queryService = new QueryExecutionService(null, workspaceService);
+
+ var queryParams = new ExecuteDocumentStatementParams { OwnerUri = Constants.OwnerUri, Line = 0, Column = 0 };
+ var queryText = queryService.GetSqlText(queryParams);
+
+ // The text should match the standard query
+ Assert.Equal(queryText, Constants.StandardQuery);
+ }
+
[Fact]
public void GetSqlTextFromDocumentRequestFull()
{