diff --git a/src/Microsoft.SqlTools.ServiceLayer/LanguageServices/LanguageService.cs b/src/Microsoft.SqlTools.ServiceLayer/LanguageServices/LanguageService.cs index 91994a50..3c1d1dee 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/LanguageServices/LanguageService.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/LanguageServices/LanguageService.cs @@ -15,6 +15,7 @@ using Microsoft.SqlServer.Management.SqlParser.Binder; using Microsoft.SqlServer.Management.SqlParser.Common; using Microsoft.SqlServer.Management.SqlParser.Intellisense; using Microsoft.SqlServer.Management.SqlParser.Parser; +using Microsoft.SqlServer.Management.SqlParser.SqlCodeDom; using Microsoft.SqlTools.Hosting.Protocol; using Microsoft.SqlTools.ServiceLayer.Connection; using Microsoft.SqlTools.ServiceLayer.Connection.Contracts; @@ -1702,6 +1703,10 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices continue; } + // If there is a single statement on the line, track it so that we can return it regardless of where the user's cursor is + SqlStatement lineStatement = null; + bool? lineHasSingleStatement = null; + // check if the batch matches parameters if (batch.StartLocation.LineNumber <= parserLine && batch.EndLocation.LineNumber >= parserLine) @@ -1712,10 +1717,29 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices if (statement.StartLocation.LineNumber <= parserLine && statement.EndLocation.LineNumber >= parserLine) { + if (statement.EndLocation.LineNumber == parserLine && statement.EndLocation.ColumnNumber < parserColumn + || statement.StartLocation.LineNumber == parserLine && statement.StartLocation.ColumnNumber > parserColumn) + { + if (lineHasSingleStatement == null) + { + lineHasSingleStatement = true; + lineStatement = statement; + } + else if (lineHasSingleStatement == true) + { + lineHasSingleStatement = false; + } + continue; + } return statement.Sql; } } } + + if (lineHasSingleStatement == true) + { + return lineStatement.Sql; + } } } diff --git a/test/Microsoft.SqlTools.ServiceLayer.UnitTests/Profiler/ProfilerServiceTests.cs b/test/Microsoft.SqlTools.ServiceLayer.UnitTests/Profiler/ProfilerServiceTests.cs index 9a9e1eb9..45053f43 100644 --- a/test/Microsoft.SqlTools.ServiceLayer.UnitTests/Profiler/ProfilerServiceTests.cs +++ b/test/Microsoft.SqlTools.ServiceLayer.UnitTests/Profiler/ProfilerServiceTests.cs @@ -27,7 +27,8 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.Profiler /// Test starting a profiling session and receiving event callback /// /// - [Fact] + // TODO: Fix flaky test. See https://github.com/Microsoft/sqltoolsservice/issues/459 + //[Fact] public async Task TestStartProfilingRequest() { string sessionId = null; diff --git a/test/Microsoft.SqlTools.ServiceLayer.UnitTests/QueryExecution/Execution/ServiceIntegrationTests.cs b/test/Microsoft.SqlTools.ServiceLayer.UnitTests/QueryExecution/Execution/ServiceIntegrationTests.cs index 67efcadd..f1597fc6 100644 --- a/test/Microsoft.SqlTools.ServiceLayer.UnitTests/QueryExecution/Execution/ServiceIntegrationTests.cs +++ b/test/Microsoft.SqlTools.ServiceLayer.UnitTests/QueryExecution/Execution/ServiceIntegrationTests.cs @@ -22,7 +22,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.QueryExecution.Execution #region Get SQL Tests - [Fact] + [Fact] public void ExecuteDocumentStatementTest() { string query = string.Format("{0}{1}GO{1}{0}", Constants.StandardQuery, Environment.NewLine); @@ -36,6 +36,37 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.QueryExecution.Execution Assert.Equal(queryText, Constants.StandardQuery); } + [Fact] + public void ExecuteDocumentStatementSameLine() + { + var statement1 = Constants.StandardQuery; + var statement2 = "SELECT * FROM sys.databases"; + // Test putting the cursor at the start of the line + ExecuteDocumentStatementSameLineHelper(statement1, statement2, 0, statement1); + // Test putting the cursor at the end of statement 1 + ExecuteDocumentStatementSameLineHelper(statement1, statement2, statement1.Length, statement1); + // Test putting the cursor at the start of statement 2 + ExecuteDocumentStatementSameLineHelper(statement1, statement2, statement1.Length + 1, statement2); + // Test putting the cursor at the end of the line + ExecuteDocumentStatementSameLineHelper(statement1, statement2, statement1.Length + 1 + statement2.Length, statement2); + // Test putting the cursor after a semicolon when only one statement is on the line + ExecuteDocumentStatementSameLineHelper(statement1, "", statement1.Length + 1, statement1); + } + + private void ExecuteDocumentStatementSameLineHelper(string statement1, string statement2, int cursorColumn, string expectedQueryText) + { + string query = string.Format("{0};{1}", statement1, statement2); + var workspaceService = GetDefaultWorkspaceService(query); + var queryService = new QueryExecutionService(null, workspaceService); + + // If a line has multiple statements and the cursor is somewhere in the line + var queryParams = new ExecuteDocumentStatementParams { OwnerUri = Constants.OwnerUri, Line = 0, Column = cursorColumn }; + var queryText = queryService.GetSqlText(queryParams); + + // The query text should match the expected statement at the cursor + Assert.Equal(expectedQueryText, queryText); + } + [Fact] public void GetSqlTextFromDocumentRequestFull() {