Support GO N syntax to execute multiple times (#551)

* Support `GO N` syntax to execute multiple times
- Plumbed through the batch execution count from the parser and used in the batch execution code path
- Functionality matches SSMS:
  - Outputs loop start/end messages that match SSMS if you're doing multi-batch execution
  - Outputs an "ignoring failure" error if an error happens during a batch
- Added tests for this
- Manually verified end to end also

* Fixing test error
This commit is contained in:
Kevin Cunnane
2017-11-22 11:33:19 -08:00
committed by GitHub
parent 42ee96f99f
commit b8e46ce65f
35 changed files with 623 additions and 367 deletions

View File

@@ -8,6 +8,7 @@ using System.Collections.Generic;
using System.Data;
using System.Data.Common;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.SqlTools.ServiceLayer.Connection;
@@ -157,6 +158,43 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.QueryExecution.Execution
ValidateMessages(batch, 1, messages);
}
[Fact]
public async Task BatchExecuteMultiExecutions()
{
// Setup:
// ... Keep track of callbacks being called
int batchStartCalls = 0;
int batchEndCalls = 0;
int resultSetCalls = 0;
List<ResultMessage> messages = new List<ResultMessage>();
// ... Build a data set to return
const int resultSets = 1;
ConnectionInfo ci = Common.CreateTestConnectionInfo(Common.GetTestDataSet(resultSets), false, false);
// If I execute a query that should get one result set, but execute it twice using "GO 2" syntax
var fileStreamFactory = MemoryFileSystem.GetFileStreamFactory();
Batch batch = new Batch(Constants.StandardQuery, Common.SubsectionDocument, Common.Ordinal, fileStreamFactory, 2);
BatchCallbackHelper(batch,
b => batchStartCalls++,
b => batchEndCalls++,
m => messages.Add(m),
r => resultSetCalls++);
await batch.Execute(GetConnection(ci), CancellationToken.None);
// Then:
// ... Callbacks should have been called the appropriate number of times
Assert.Equal(1, batchStartCalls);
Assert.Equal(1, batchEndCalls);
Assert.Equal(2, resultSetCalls);
// ... There should be exactly two result sets
ValidateBatch(batch, 2, false);
ValidateBatchSummary(batch);
// ... And there should be an additional loop start in addition to the batch end message
ValidateMessages(batch, 2, messages);
}
[Fact]
public async Task BatchExecuteInvalidQuery()
{
@@ -195,6 +233,44 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.QueryExecution.Execution
});
}
[Fact]
public async Task BatchExecuteInvalidQueryMultiExecutions()
{
// Setup:
// ... Keep track of callbacks being called
int batchStartCalls = 0;
int batchEndCalls = 0;
List<ResultMessage> messages = new List<ResultMessage>();
// If I execute a batch that is invalid, and if "GO 2" is added to execute more than once
var ci = Common.CreateTestConnectionInfo(null, true, false);
var fileStreamFactory = MemoryFileSystem.GetFileStreamFactory();
Batch batch = new Batch(Constants.StandardQuery + Environment.NewLine, Common.SubsectionDocument, Common.Ordinal, fileStreamFactory, 2);
BatchCallbackHelper(batch,
b => batchStartCalls++,
b => batchEndCalls++,
m => messages.Add(m),
r => { throw new Exception("ResultSet callback was called when it should not have been."); });
await batch.Execute(GetConnection(ci), CancellationToken.None);
// Then:
// ... Callbacks should have been called the appropriate number of times
Assert.Equal(1, batchStartCalls);
Assert.Equal(1, batchEndCalls);
// ... It should have executed with error
ValidateBatch(batch, 0, true);
ValidateBatchSummary(batch);
// ... There should be two error messages returned and 4 info messages (loop start/end, plus 2 for ignoring the error)
Assert.Equal(6, messages.Count);
Assert.All(messages, m =>
{
Assert.Equal(batch.Id, m.BatchId);
});
Assert.Equal(2, messages.Where(m => m.IsError).Count());
}
[Fact]
public async Task BatchExecuteExecuted()
{

View File

@@ -58,7 +58,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.Utility
Assert.NotNull(ServiceLayerSr.EE_ExecutionError_CommandNotSupported);
Assert.NotNull(ServiceLayerSr.EE_ExecutionError_VariableNotFound);
Assert.NotNull(ServiceLayerSr.EE_ExecutionInfo_FinalizingLoop);
Assert.NotNull(ServiceLayerSr.EE_ExecutionInfo_InitilizingLoop);
Assert.NotNull(ServiceLayerSr.EE_ExecutionInfo_InitializingLoop);
Assert.NotNull(ServiceLayerSr.EE_ExecutionInfo_QueryCancelledbyUser);
Assert.NotNull(ServiceLayerSr.EE_ExecutionNotYetCompleteError);
Assert.NotNull(ServiceLayerSr.EE_ScriptError_Error);