From 043d9daaab5cf63076b47933b279a655a554ca2a Mon Sep 17 00:00:00 2001 From: Alex Ma Date: Thu, 16 Sep 2021 14:30:47 -0700 Subject: [PATCH 1/5] added WIP sync execute method --- .../QueryExecution/Batch.cs | 98 ++++++++++++++++++- 1 file changed, 97 insertions(+), 1 deletion(-) diff --git a/src/Microsoft.SqlTools.ServiceLayer/QueryExecution/Batch.cs b/src/Microsoft.SqlTools.ServiceLayer/QueryExecution/Batch.cs index db8639683a..fd81c2e027 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/QueryExecution/Batch.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/QueryExecution/Batch.cs @@ -337,7 +337,6 @@ public async Task Execute(DbConnection conn, CancellationToken cancellationToken } } - private async Task DoExecute(DbConnection conn, CancellationToken cancellationToken, OnErrorAction onErrorAction = OnErrorAction.Ignore) { bool canContinue = true; @@ -481,6 +480,103 @@ private async Task ExecuteOnce(DbConnection conn, CancellationToken cancellation } } + + private async Task SyncExecuteOnce(DbConnection conn, CancellationToken cancellationToken) + { + // Make sure we haven't cancelled yet + cancellationToken.ThrowIfCancellationRequested(); + + // Create a command that we'll use for executing the query + using (DbCommand dbCommand = CreateCommand(conn)) + { + // Make sure that we cancel the command if the cancellation token is cancelled + cancellationToken.Register(() => dbCommand?.Cancel()); + + // Setup the command for executing the batch + dbCommand.CommandText = BatchText; + dbCommand.CommandType = CommandType.Text; + dbCommand.CommandTimeout = 0; + + if (WorkspaceService.Instance.CurrentSettings.QueryExecutionSettings.IsAlwaysEncryptedParameterizationEnabled) + { + dbCommand.Parameterize(); + } + + List columnSchemas = null; + if (getFullColumnSchema) + { + // Executing the same query twice with different command behavior causes the second + // execution to return no rows if there's a trailing comment with no newline after, + // so add a newline to the end of the query. See https://github.com/Microsoft/sqlopsstudio/issues/1424 + dbCommand.CommandText += Environment.NewLine; + + ConnectionService.EnsureConnectionIsOpen(conn); + + // Fetch schema info separately, since CommandBehavior.KeyInfo will include primary + // key columns in the result set, even if they weren't part of the select statement. + // Extra key columns get added to the end, so just correlate via Column Ordinal. + columnSchemas = new List(); + using (DbDataReader reader = dbCommand.ExecuteReader(CommandBehavior.KeyInfo | CommandBehavior.SchemaOnly)) + { + if (reader != null && reader.CanGetColumnSchema()) + { + do + { + columnSchemas.Add(reader.GetColumnSchema().ToArray()); + } while (reader.NextResult()); + } + } + } + + ConnectionService.EnsureConnectionIsOpen(conn); + + // Execute the command to get back a reader + using (DbDataReader reader = dbCommand.ExecuteReader()) + { + do + { + // Verify that the cancellation token hasn't been canceled + cancellationToken.ThrowIfCancellationRequested(); + + // Skip this result set if there aren't any rows (i.e. UPDATE/DELETE/etc queries) + if (!reader.HasRows && reader.FieldCount == 0) + { + continue; + } + + // This resultset has results (i.e. SELECT/etc queries) + ResultSet resultSet = new ResultSet(resultSets.Count, Id, outputFileFactory); + resultSet.ResultAvailable += ResultSetAvailable; + resultSet.ResultUpdated += ResultSetUpdated; + resultSet.ResultCompletion += ResultSetCompletion; + + // Add the result set to the results of the query + lock (resultSets) + { + resultSets.Add(resultSet); + } + + // Read until we hit the end of the result set + await resultSet.ReadResultToEnd(reader, cancellationToken); + + } while (reader.NextResult()); + + // If there were no messages, for whatever reason (NO COUNT set, messages + // were emitted, records returned), output a "successful" message + if (!messagesSent) + { + await SendMessage(SR.QueryServiceCompletedSuccessfully, false); + } + } + + if (columnSchemas != null) + { + ExtendResultMetadata(columnSchemas, resultSets); + } + } + } + + private void ExtendResultMetadata(List columnSchemas, List results) { if (columnSchemas.Count != results.Count) From bc835f7051ad85bd52e1298a106edf1738f18cb3 Mon Sep 17 00:00:00 2001 From: Alex Ma Date: Thu, 16 Sep 2021 18:19:57 -0700 Subject: [PATCH 2/5] added syncexecuteonce --- src/Microsoft.SqlTools.ServiceLayer/QueryExecution/Batch.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Microsoft.SqlTools.ServiceLayer/QueryExecution/Batch.cs b/src/Microsoft.SqlTools.ServiceLayer/QueryExecution/Batch.cs index fd81c2e027..c1f73934ab 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/QueryExecution/Batch.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/QueryExecution/Batch.cs @@ -350,7 +350,7 @@ private async Task DoExecute(DbConnection conn, CancellationToken cancellationTo { try { - await ExecuteOnce(conn, cancellationToken); + await SyncExecuteOnce(conn, cancellationToken); } catch (DbException dbe) { From 3c821a3cccb73b9f2f02f717cd1b5371618bac14 Mon Sep 17 00:00:00 2001 From: Alex Ma Date: Fri, 17 Sep 2021 09:28:37 -0700 Subject: [PATCH 3/5] replaced executeonce with synchronous reading --- .../QueryExecution/Batch.cs | 99 +------------------ 1 file changed, 1 insertion(+), 98 deletions(-) diff --git a/src/Microsoft.SqlTools.ServiceLayer/QueryExecution/Batch.cs b/src/Microsoft.SqlTools.ServiceLayer/QueryExecution/Batch.cs index c1f73934ab..36c6344e81 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/QueryExecution/Batch.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/QueryExecution/Batch.cs @@ -350,7 +350,7 @@ private async Task DoExecute(DbConnection conn, CancellationToken cancellationTo { try { - await SyncExecuteOnce(conn, cancellationToken); + await ExecuteOnce(conn, cancellationToken); } catch (DbException dbe) { @@ -390,102 +390,6 @@ private async Task ExecuteOnce(DbConnection conn, CancellationToken cancellation // Make sure we haven't cancelled yet cancellationToken.ThrowIfCancellationRequested(); - // Create a command that we'll use for executing the query - using (DbCommand dbCommand = CreateCommand(conn)) - { - // Make sure that we cancel the command if the cancellation token is cancelled - cancellationToken.Register(() => dbCommand?.Cancel()); - - // Setup the command for executing the batch - dbCommand.CommandText = BatchText; - dbCommand.CommandType = CommandType.Text; - dbCommand.CommandTimeout = 0; - - if (WorkspaceService.Instance.CurrentSettings.QueryExecutionSettings.IsAlwaysEncryptedParameterizationEnabled) - { - dbCommand.Parameterize(); - } - - List columnSchemas = null; - if (getFullColumnSchema) - { - // Executing the same query twice with different command behavior causes the second - // execution to return no rows if there's a trailing comment with no newline after, - // so add a newline to the end of the query. See https://github.com/Microsoft/sqlopsstudio/issues/1424 - dbCommand.CommandText += Environment.NewLine; - - ConnectionService.EnsureConnectionIsOpen(conn); - - // Fetch schema info separately, since CommandBehavior.KeyInfo will include primary - // key columns in the result set, even if they weren't part of the select statement. - // Extra key columns get added to the end, so just correlate via Column Ordinal. - columnSchemas = new List(); - using (DbDataReader reader = await dbCommand.ExecuteReaderAsync(CommandBehavior.KeyInfo | CommandBehavior.SchemaOnly, cancellationToken)) - { - if (reader != null && reader.CanGetColumnSchema()) - { - do - { - columnSchemas.Add(reader.GetColumnSchema().ToArray()); - } while (await reader.NextResultAsync(cancellationToken)); - } - } - } - - ConnectionService.EnsureConnectionIsOpen(conn); - - // Execute the command to get back a reader - using (DbDataReader reader = await dbCommand.ExecuteReaderAsync(cancellationToken)) - { - do - { - // Verify that the cancellation token hasn't been canceled - cancellationToken.ThrowIfCancellationRequested(); - - // Skip this result set if there aren't any rows (i.e. UPDATE/DELETE/etc queries) - if (!reader.HasRows && reader.FieldCount == 0) - { - continue; - } - - // This resultset has results (i.e. SELECT/etc queries) - ResultSet resultSet = new ResultSet(resultSets.Count, Id, outputFileFactory); - resultSet.ResultAvailable += ResultSetAvailable; - resultSet.ResultUpdated += ResultSetUpdated; - resultSet.ResultCompletion += ResultSetCompletion; - - // Add the result set to the results of the query - lock (resultSets) - { - resultSets.Add(resultSet); - } - - // Read until we hit the end of the result set - await resultSet.ReadResultToEnd(reader, cancellationToken); - - } while (await reader.NextResultAsync(cancellationToken)); - - // If there were no messages, for whatever reason (NO COUNT set, messages - // were emitted, records returned), output a "successful" message - if (!messagesSent) - { - await SendMessage(SR.QueryServiceCompletedSuccessfully, false); - } - } - - if (columnSchemas != null) - { - ExtendResultMetadata(columnSchemas, resultSets); - } - } - } - - - private async Task SyncExecuteOnce(DbConnection conn, CancellationToken cancellationToken) - { - // Make sure we haven't cancelled yet - cancellationToken.ThrowIfCancellationRequested(); - // Create a command that we'll use for executing the query using (DbCommand dbCommand = CreateCommand(conn)) { @@ -575,7 +479,6 @@ private async Task SyncExecuteOnce(DbConnection conn, CancellationToken cancella } } } - private void ExtendResultMetadata(List columnSchemas, List results) { From ac4c38f422f15dff3c1d6c8b96e36cd440fef8e1 Mon Sep 17 00:00:00 2001 From: Alex Ma Date: Fri, 17 Sep 2021 10:43:59 -0700 Subject: [PATCH 4/5] removed batch.cs change --- src/Microsoft.SqlTools.ServiceLayer/QueryExecution/Batch.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Microsoft.SqlTools.ServiceLayer/QueryExecution/Batch.cs b/src/Microsoft.SqlTools.ServiceLayer/QueryExecution/Batch.cs index 36c6344e81..427910c3fa 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/QueryExecution/Batch.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/QueryExecution/Batch.cs @@ -337,6 +337,7 @@ public async Task Execute(DbConnection conn, CancellationToken cancellationToken } } + private async Task DoExecute(DbConnection conn, CancellationToken cancellationToken, OnErrorAction onErrorAction = OnErrorAction.Ignore) { bool canContinue = true; From 49fcd5ac81e8b675fb4e7aa8ad930f7bc2033934 Mon Sep 17 00:00:00 2001 From: Alex Ma Date: Fri, 17 Sep 2021 10:48:58 -0700 Subject: [PATCH 5/5] restore space --- src/Microsoft.SqlTools.ServiceLayer/QueryExecution/Batch.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Microsoft.SqlTools.ServiceLayer/QueryExecution/Batch.cs b/src/Microsoft.SqlTools.ServiceLayer/QueryExecution/Batch.cs index 427910c3fa..efee66971e 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/QueryExecution/Batch.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/QueryExecution/Batch.cs @@ -337,7 +337,7 @@ public async Task Execute(DbConnection conn, CancellationToken cancellationToken } } - + private async Task DoExecute(DbConnection conn, CancellationToken cancellationToken, OnErrorAction onErrorAction = OnErrorAction.Ignore) { bool canContinue = true;