diff --git a/src/Microsoft.SqlTools.ServiceLayer/QueryExecution/Contracts/SaveResultsRequest.cs b/src/Microsoft.SqlTools.ServiceLayer/QueryExecution/Contracts/SaveResultsRequest.cs
new file mode 100644
index 00000000..78c2c72f
--- /dev/null
+++ b/src/Microsoft.SqlTools.ServiceLayer/QueryExecution/Contracts/SaveResultsRequest.cs
@@ -0,0 +1,70 @@
+//
+// 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.QueryExecution.Contracts
+{
+ ///
+ /// Parameters for the save results request
+ ///
+ public class SaveResultsRequestParams
+ {
+ ///
+ /// The path of the file to save results in
+ ///
+ public string FilePath { get; set; }
+
+ ///
+ /// The encoding of the file to save results in
+ ///
+ public string FileEncoding { get; set; }
+
+ ///
+ /// Include headers of columns in CSV
+ ///
+ public bool IncludeHeaders { get; set; }
+
+ ///
+ /// Index of the batch to get the results from
+ ///
+ public int BatchIndex { get; set; }
+
+ ///
+ /// Index of the result set to get the results from
+ ///
+ public int ResultSetIndex { get; set; }
+
+ ///
+ /// CSV - Write values in quotes
+ ///
+ public Boolean ValueInQuotes { get; set; }
+
+ ///
+ /// URI for the editor that called save results
+ ///
+ public string OwnerUri { get; set; }
+ }
+
+ ///
+ /// Parameters for the save results result
+ ///
+ public class SaveResultRequestResult
+ {
+ ///
+ /// Error messages for saving to file.
+ ///
+ public string Messages { get; set; }
+ }
+
+ public class SaveResultsAsCsvRequest
+ {
+ public static readonly
+ RequestType Type =
+ RequestType.Create("query/save");
+ }
+
+}
\ No newline at end of file
diff --git a/src/Microsoft.SqlTools.ServiceLayer/QueryExecution/QueryExecutionService.cs b/src/Microsoft.SqlTools.ServiceLayer/QueryExecution/QueryExecutionService.cs
index 97d89fc9..882cf11b 100644
--- a/src/Microsoft.SqlTools.ServiceLayer/QueryExecution/QueryExecutionService.cs
+++ b/src/Microsoft.SqlTools.ServiceLayer/QueryExecution/QueryExecutionService.cs
@@ -2,9 +2,10 @@
// 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 System.Collections.Concurrent;
+using System.IO;
+using System.Linq;
using System.Threading.Tasks;
using Microsoft.SqlTools.ServiceLayer.Connection;
using Microsoft.SqlTools.ServiceLayer.Hosting;
@@ -98,6 +99,7 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution
serviceHost.SetRequestHandler(QueryExecuteSubsetRequest.Type, HandleResultSubsetRequest);
serviceHost.SetRequestHandler(QueryDisposeRequest.Type, HandleDisposeRequest);
serviceHost.SetRequestHandler(QueryCancelRequest.Type, HandleCancelRequest);
+ serviceHost.SetRequestHandler(SaveResultsAsCsvRequest.Type, HandleSaveResultsAsCsvRequest);
// Register handler for shutdown event
serviceHost.RegisterShutdownTask((shutdownParams, requestContext) =>
@@ -256,6 +258,58 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution
}
}
+ ///
+ /// Process request to save a resultSet to a file in CSV format
+ ///
+ public async Task HandleSaveResultsAsCsvRequest( SaveResultsRequestParams saveParams,
+ RequestContext requestContext)
+ {
+ // retrieve query for OwnerUri
+ Query result;
+ if (!ActiveQueries.TryGetValue(saveParams.OwnerUri, out result))
+ {
+ await requestContext.SendResult(new SaveResultRequestResult
+ {
+ Messages = "Failed to save results, ID not found."
+ });
+ return;
+ }
+ try
+ {
+ using (StreamWriter csvFile = new StreamWriter(File.OpenWrite(saveParams.FilePath)))
+ {
+ // get the requested resultSet from query
+ Batch selectedBatch = result.Batches[saveParams.BatchIndex];
+ ResultSet selectedResultSet = (selectedBatch.ResultSets.ToList())[saveParams.ResultSetIndex];
+ if ( saveParams.IncludeHeaders)
+ {
+ // write column names to csv
+ await csvFile.WriteLineAsync( string.Join( ",", selectedResultSet.Columns.Select( column => SaveResults.EncodeCsvField(column.ColumnName) ?? string.Empty)));
+ }
+
+ // write rows to csv
+ foreach( var row in selectedResultSet.Rows)
+ {
+ await csvFile.WriteLineAsync(string.Join( ",", row.Select( field => SaveResults.EncodeCsvField( (field != null) ? field.ToString(): string.Empty))));
+ }
+ }
+ }
+ catch(Exception ex)
+ {
+ // Delete file when exception occurs
+ if(File.Exists(saveParams.FilePath))
+ {
+ File.Delete(saveParams.FilePath);
+ }
+ await requestContext.SendError(ex.Message);
+ return;
+ }
+ await requestContext.SendResult(new SaveResultRequestResult
+ {
+ Messages = "Success"
+ });
+ return;
+ }
#endregion
#region Private Helpers
diff --git a/src/Microsoft.SqlTools.ServiceLayer/QueryExecution/ResultSet.cs b/src/Microsoft.SqlTools.ServiceLayer/QueryExecution/ResultSet.cs
index 84e18c99..41978255 100644
--- a/src/Microsoft.SqlTools.ServiceLayer/QueryExecution/ResultSet.cs
+++ b/src/Microsoft.SqlTools.ServiceLayer/QueryExecution/ResultSet.cs
@@ -111,6 +111,14 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution
///
public long RowCount { get; private set; }
+ ///
+ /// The rows of this result set
+ ///
+ public IEnumerable