示例#1
0
        /// <summary>
        /// Executes this batch and captures any server messages that are returned.
        /// </summary>
        /// <param name="conn">The connection to use to execute the batch</param>
        /// <param name="cancellationToken">Token for cancelling the execution</param>
        public async Task Execute(DbConnection conn, CancellationToken cancellationToken)
        {
            // Sanity check to make sure we haven't already run this batch
            if (HasExecuted)
            {
                throw new InvalidOperationException("Batch has already executed.");
            }

            // Notify that we've started execution
            if (BatchStart != null)
            {
                await BatchStart(this);
            }

            try
            {
                // Register the message listener to *this instance* of the batch
                // Note: This is being done to associate messages with batches
                ReliableSqlConnection sqlConn = conn as ReliableSqlConnection;
                DbCommand             command;
                if (sqlConn != null)
                {
                    // Register the message listener to *this instance* of the batch
                    // Note: This is being done to associate messages with batches
                    sqlConn.GetUnderlyingConnection().InfoMessage += StoreDbMessage;
                    command = sqlConn.GetUnderlyingConnection().CreateCommand();

                    // Add a handler for when the command completes
                    SqlCommand sqlCommand = (SqlCommand)command;
                    sqlCommand.StatementCompleted += StatementCompletedHandler;
                }
                else
                {
                    command = conn.CreateCommand();
                }

                // Make sure we aren't using a ReliableCommad since we do not want automatic retry
                Debug.Assert(!(command is ReliableSqlConnection.ReliableSqlCommand),
                             "ReliableSqlCommand command should not be used to execute queries");

                // Create a command that we'll use for executing the query
                using (command)
                {
                    command.CommandText    = BatchText;
                    command.CommandType    = CommandType.Text;
                    command.CommandTimeout = 0;
                    executionStartTime     = DateTime.Now;

                    // Execute the command to get back a reader
                    using (DbDataReader reader = await command.ExecuteReaderAsync(cancellationToken))
                    {
                        int resultSetOrdinal = 0;
                        do
                        {
                            // Skip this result set if there aren't any rows (ie, UPDATE/DELETE/etc queries)
                            if (!reader.HasRows && reader.FieldCount == 0)
                            {
                                continue;
                            }

                            // This resultset has results (ie, SELECT/etc queries)
                            ResultSet resultSet = new ResultSet(reader, resultSetOrdinal, Id, outputFileFactory);
                            resultSet.ResultCompletion += ResultSetCompletion;

                            // Add the result set to the results of the query
                            lock (resultSets)
                            {
                                resultSets.Add(resultSet);
                                resultSetOrdinal++;
                            }

                            // Read until we hit the end of the result set
                            await resultSet.ReadResultToEnd(cancellationToken).ConfigureAwait(false);
                        } 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 (resultMessages.Count == 0)
                        {
                            resultMessages.Add(new ResultMessage(SR.QueryServiceCompletedSuccessfully));
                        }
                    }
                }
            }
            catch (DbException dbe)
            {
                HasError = true;
                UnwrapDbException(dbe);
            }
            catch (TaskCanceledException)
            {
                resultMessages.Add(new ResultMessage(SR.QueryServiceQueryCancelled));
                throw;
            }
            catch (Exception e)
            {
                HasError = true;
                resultMessages.Add(new ResultMessage(SR.QueryServiceQueryFailed(e.Message)));
                throw;
            }
            finally
            {
                // Remove the message event handler from the connection
                ReliableSqlConnection sqlConn = conn as ReliableSqlConnection;
                if (sqlConn != null)
                {
                    sqlConn.GetUnderlyingConnection().InfoMessage -= StoreDbMessage;
                }

                // Mark that we have executed
                HasExecuted      = true;
                executionEndTime = DateTime.Now;

                // Fire an event to signify that the batch has completed
                if (BatchCompletion != null)
                {
                    await BatchCompletion(this);
                }
            }
        }
示例#2
0
        private async Task ExecuteOnce(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;
                executionStartTime       = DateTime.Now;

                List <DbColumn[]> 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;

                    // 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 <DbColumn[]>();
                    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));
                        }
                    }
                }

                // 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.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);
                }
            }
        }
示例#3
0
        private async Task ExecuteOnce(DbConnection conn, CancellationToken cancellationToken)
        {
            // Make sure we haven't cancelled yet
            cancellationToken.ThrowIfCancellationRequested();

            // Register the message listener to *this instance* of the batch
            // Note: This is being done to associate messages with batches
            ReliableSqlConnection sqlConn = conn as ReliableSqlConnection;
            DbCommand             dbCommand;

            if (sqlConn != null)
            {
                // Register the message listener to *this instance* of the batch
                // Note: This is being done to associate messages with batches
                sqlConn.GetUnderlyingConnection().InfoMessage += ServerMessageHandler;
                dbCommand = sqlConn.GetUnderlyingConnection().CreateCommand();

                // Add a handler for when the command completes
                SqlCommand sqlCommand = (SqlCommand)dbCommand;
                sqlCommand.StatementCompleted += StatementCompletedHandler;
            }
            else
            {
                dbCommand = conn.CreateCommand();
            }

            // Make sure we aren't using a ReliableCommad since we do not want automatic retry
            Debug.Assert(!(dbCommand is ReliableSqlConnection.ReliableSqlCommand),
                         "ReliableSqlCommand command should not be used to execute queries");

            // Create a command that we'll use for executing the query
            using (dbCommand)
            {
                // 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;
                executionStartTime       = DateTime.Now;

                // Execute the command to get back a reader
                using (DbDataReader reader = await dbCommand.ExecuteReaderAsync(cancellationToken))
                {
                    int resultSetOrdinal = 0;
                    do
                    {
                        // Verify that the cancellation token hasn't benn cancelled
                        cancellationToken.ThrowIfCancellationRequested();

                        // Skip this result set if there aren't any rows (ie, UPDATE/DELETE/etc queries)
                        if (!reader.HasRows && reader.FieldCount == 0)
                        {
                            continue;
                        }

                        // This resultset has results (ie, SELECT/etc queries)
                        ResultSet resultSet = new ResultSet(resultSetOrdinal, Id, outputFileFactory);
                        resultSet.ResultCompletion += ResultSetCompletion;

                        // Add the result set to the results of the query
                        lock (resultSets)
                        {
                            resultSets.Add(resultSet);
                            resultSetOrdinal++;
                        }

                        // 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);
                    }
                }
            }
        }