Ejemplo n.º 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);
            }

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

            if (sqlConn != null)
            {
                sqlConn.GetUnderlyingConnection().InfoMessage += ServerMessageHandler;
            }

            try
            {
                await DoExecute(conn, cancellationToken);
            }
            catch (TaskCanceledException)
            {
                // Cancellation isn't considered an error condition
                await SendMessage(SR.QueryServiceQueryCancelled, false);

                throw;
            }
            catch (Exception e)
            {
                HasError = true;
                await SendMessage(SR.QueryServiceQueryFailed(e.Message), true);

                throw;
            }
            finally
            {
                // Remove the message event handler from the connection
                if (sqlConn != null)
                {
                    sqlConn.GetUnderlyingConnection().InfoMessage -= ServerMessageHandler;
                }

                // 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);
                }
            }
        }
Ejemplo n.º 2
0
        private DbCommand CreateCommand(DbConnection conn)
        {
            // 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)
            {
                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");

            return(dbCommand);
        }
        private RestoreDatabaseTaskDataObject CreateRestoreForNewSession(string ownerUri, string targetDatabaseName = null)
        {
            ConnectionInfo connInfo;

            DisasterRecoveryService.ConnectionServiceInstance.TryFindConnection(
                ownerUri,
                out connInfo);

            if (connInfo != null)
            {
                SqlConnection         connection;
                DbConnection          dbConnection          = connInfo.AllConnections.First();
                ReliableSqlConnection reliableSqlConnection = dbConnection as ReliableSqlConnection;
                SqlConnection         sqlConnection         = dbConnection as SqlConnection;
                if (reliableSqlConnection != null)
                {
                    connection = reliableSqlConnection.GetUnderlyingConnection();
                }
                else if (sqlConnection != null)
                {
                    connection = sqlConnection;
                }
                else
                {
                    Logger.Write(LogLevel.Warning, "Cannot find any sql connection for restore operation");
                    return(null);
                }
                Server server = new Server(new ServerConnection(connection));

                RestoreDatabaseTaskDataObject restoreDataObject = new RestoreDatabaseTaskDataObject(server, targetDatabaseName);
                return(restoreDataObject);
            }
            return(null);
        }
Ejemplo n.º 4
0
        private SmoQueryContext CreateContext(IMultiServiceProvider serviceProvider)
        {
            string         exceptionMessage;
            ConnectionInfo connectionInfo;
            SqlConnection  connection = null;

            // Get server object from connection
            if (!connectionService.TryFindConnection(this.connectionUri, out connectionInfo) ||
                connectionInfo.AllConnections == null || connectionInfo.AllConnections.Count == 0)
            {
                ErrorStateMessage = string.Format(CultureInfo.CurrentCulture,
                                                  SR.ServerNodeConnectionError, connectionSummary.ServerName);
                return(null);
            }
            //TODO: figure out how to use existing connections
            DbConnection          dbConnection          = connectionInfo.AllConnections.First();
            ReliableSqlConnection reliableSqlConnection = dbConnection as ReliableSqlConnection;
            SqlConnection         sqlConnection         = dbConnection as SqlConnection;

            if (reliableSqlConnection != null)
            {
                connection = reliableSqlConnection.GetUnderlyingConnection();
            }
            else if (sqlConnection != null)
            {
                connection = sqlConnection;
            }
            else
            {
                ErrorStateMessage = string.Format(CultureInfo.CurrentCulture,
                                                  SR.ServerNodeConnectionError, connectionSummary.ServerName);
                return(null);
            }

            try
            {
                Server server = SmoWrapper.CreateServer(connection);
                return(new SmoQueryContext(server, serviceProvider, SmoWrapper)
                {
                    Parent = server,
                    SqlServerType = this.sqlServerType
                });
            }
            catch (ConnectionFailureException cfe)
            {
                exceptionMessage = cfe.Message;
            }
            catch (Exception ex)
            {
                exceptionMessage = ex.Message;
            }

            Logger.Write(LogLevel.Error, "Exception at ServerNode.CreateContext() : " + exceptionMessage);
            this.ErrorStateMessage = string.Format(SR.TreeNodeError, exceptionMessage);
            return(null);
        }
        public void ReliableSqlConnectionUsesAzureToken()
        {
            ConnectionDetails details = TestObjects.GetTestConnectionDetails();

            details.UserName = "";
            details.Password = "";
            string      connectionString  = ConnectionService.BuildConnectionString(details);
            string      azureAccountToken = "testAzureAccountToken";
            RetryPolicy retryPolicy       = RetryPolicyFactory.CreateDefaultConnectionRetryPolicy();

            // If I create a ReliableSqlConnection using an azure account token
            var reliableConnection = new ReliableSqlConnection(connectionString, retryPolicy, retryPolicy, azureAccountToken);

            // Then the connection's azureAccountToken gets set
            Assert.Equal(azureAccountToken, reliableConnection.GetUnderlyingConnection().AccessToken);
        }
        private Server CreateServerObject(ConnectionInfo connInfo)
        {
            SqlConnection         connection            = null;
            DbConnection          dbConnection          = connInfo.AllConnections.First();
            ReliableSqlConnection reliableSqlConnection = dbConnection as ReliableSqlConnection;
            SqlConnection         sqlConnection         = dbConnection as SqlConnection;

            if (reliableSqlConnection != null)
            {
                connection = reliableSqlConnection.GetUnderlyingConnection();
            }
            else if (sqlConnection != null)
            {
                connection = sqlConnection;
            }
            return(new Server(new ServerConnection(connection)));
        }
    public static SqlConnection GetAsSqlConnection(DbConnection connection)
    {
        SqlConnection sqlConn = connection as SqlConnection;

        if (sqlConn == null)
        {
            // It's not actually a SqlConnection, so let's try a reliable SQL connection
            ReliableSqlConnection reliableConn = connection as ReliableSqlConnection;
            if (reliableConn == null)
            {
                // If we don't have connection we can use with SMO, just give up on using SMO
                return(null);
            }

            // We have a reliable connection, use the underlying connection
            sqlConn = reliableConn.GetUnderlyingConnection();
        }
        return(sqlConn);
    }
Ejemplo n.º 8
0
        /// <summary>
        /// Generates a edit-ready metadata object using SMO
        /// </summary>
        /// <param name="connection">Connection to use for getting metadata</param>
        /// <param name="objectName">Name of the object to return metadata for</param>
        /// <param name="objectType">Type of the object to return metadata for</param>
        /// <returns>Metadata about the object requested</returns>
        public TableMetadata GetObjectMetadata(DbConnection connection, string schemaName, string objectName, string objectType)
        {
            // Get a connection to the database for SMO purposes
            SqlConnection sqlConn = connection as SqlConnection;

            if (sqlConn == null)
            {
                // It's not actually a SqlConnection, so let's try a reliable SQL connection
                ReliableSqlConnection reliableConn = connection as ReliableSqlConnection;
                if (reliableConn == null)
                {
                    // If we don't have connection we can use with SMO, just give up on using SMO
                    return(null);
                }

                // We have a reliable connection, use the underlying connection
                sqlConn = reliableConn.GetUnderlyingConnection();
            }

            // Connect with SMO and get the metadata for the table
            ServerConnection serverConnection;

            if (sqlConn.AccessToken == null)
            {
                serverConnection = new ServerConnection(sqlConn);
            }
            else
            {
                serverConnection = new ServerConnection(sqlConn, new AzureAccessToken(sqlConn.AccessToken));
            }
            Server   server   = new Server(serverConnection);
            Database database = server.Databases[sqlConn.Database];
            TableViewTableTypeBase smoResult;

            switch (objectType.ToLowerInvariant())
            {
            case "table":
                Table table = string.IsNullOrEmpty(schemaName) ? new Table(database, objectName) : new Table(database, objectName, schemaName);
                table.Refresh();
                smoResult = table;
                break;

            case "view":
                View view = string.IsNullOrEmpty(schemaName) ? new View(database, objectName) : new View(database, objectName, schemaName);
                view.Refresh();
                smoResult = view;
                break;

            default:
                throw new ArgumentOutOfRangeException(nameof(objectType), SR.EditDataUnsupportedObjectType(objectType));
            }
            if (smoResult == null)
            {
                throw new ArgumentOutOfRangeException(nameof(objectName), SR.EditDataObjectMetadataNotFound);
            }

            // Generate the edit column metadata
            List <ColumnMetadata> editColumns = new List <ColumnMetadata>();

            for (int i = 0; i < smoResult.Columns.Count; i++)
            {
                Column smoColumn = smoResult.Columns[i];

                // The default value may be escaped
                string defaultValue = smoColumn.DefaultConstraint == null
                    ? null
                    : FromSqlScript.UnwrapLiteral(smoColumn.DefaultConstraint.Text);

                ColumnMetadata column = new ColumnMetadata
                {
                    DefaultValue = defaultValue,
                    EscapedName  = ToSqlScript.FormatIdentifier(smoColumn.Name),
                    Ordinal      = i
                };
                editColumns.Add(column);
            }

            // Only tables can be memory-optimized
            Table smoTable          = smoResult as Table;
            bool  isMemoryOptimized = smoTable != null && smoTable.IsMemoryOptimized;

            // Escape the parts of the name
            string[] objectNameParts      = { smoResult.Schema, smoResult.Name };
            string   escapedMultipartName = ToSqlScript.FormatMultipartIdentifier(objectNameParts);

            return(new TableMetadata
            {
                Columns = editColumns.ToArray(),
                EscapedMultipartName = escapedMultipartName,
                IsMemoryOptimized = isMemoryOptimized,
            });
        }
Ejemplo n.º 9
0
        /// <summary>
        /// Generates a edit-ready metadata object using SMO
        /// </summary>
        /// <param name="connection">Connection to use for getting metadata</param>
        /// <param name="objectNamedParts">Split and unwrapped name parts</param>
        /// <param name="objectType">Type of the object to return metadata for</param>
        /// <returns>Metadata about the object requested</returns>
        public EditTableMetadata GetObjectMetadata(DbConnection connection, string[] objectNamedParts, string objectType)
        {
            Validate.IsNotNull(nameof(objectNamedParts), objectNamedParts);
            if (objectNamedParts.Length <= 0)
            {
                throw new ArgumentNullException(nameof(objectNamedParts), SR.EditDataMetadataObjectNameRequired);
            }
            if (objectNamedParts.Length > 2)
            {
                throw new InvalidOperationException(SR.EditDataMetadataTooManyIdentifiers);
            }

            // Get a connection to the database for SMO purposes
            SqlConnection sqlConn = connection as SqlConnection;

            if (sqlConn == null)
            {
                // It's not actually a SqlConnection, so let's try a reliable SQL connection
                ReliableSqlConnection reliableConn = connection as ReliableSqlConnection;
                if (reliableConn == null)
                {
                    // If we don't have connection we can use with SMO, just give up on using SMO
                    return(null);
                }

                // We have a reliable connection, use the underlying connection
                sqlConn = reliableConn.GetUnderlyingConnection();
            }

            // Connect with SMO and get the metadata for the table
            ServerConnection serverConnection;

            if (sqlConn.AccessToken == null)
            {
                serverConnection = new ServerConnection(sqlConn);
            }
            else
            {
                serverConnection = new ServerConnection(sqlConn, new AzureAccessToken(sqlConn.AccessToken));
            }
            Server   server = new Server(serverConnection);
            Database db     = new Database(server, sqlConn.Database);

            TableViewTableTypeBase smoResult;

            switch (objectType.ToLowerInvariant())
            {
            case "table":
                smoResult = objectNamedParts.Length == 1
                        ? new Table(db, objectNamedParts[0])                        // No schema provided
                        : new Table(db, objectNamedParts[1], objectNamedParts[0]);  // Schema provided
                break;

            case "view":
                smoResult = objectNamedParts.Length == 1
                        ? new View(db, objectNamedParts[0])                         // No schema provided
                        : new View(db, objectNamedParts[1], objectNamedParts[0]);   // Schema provided
                break;

            default:
                throw new ArgumentOutOfRangeException(nameof(objectType), SR.EditDataUnsupportedObjectType(objectType));
            }

            // A bug in SMO makes it necessary to call refresh to attain certain properties (such as IsMemoryOptimized)
            smoResult.Refresh();
            if (smoResult.State != SqlSmoState.Existing)
            {
                throw new ArgumentOutOfRangeException(nameof(objectNamedParts), SR.EditDataObjectNotFound);
            }

            // Generate the edit column metadata
            List <EditColumnMetadata> editColumns = new List <EditColumnMetadata>();

            for (int i = 0; i < smoResult.Columns.Count; i++)
            {
                Column smoColumn = smoResult.Columns[i];

                string defaultValue = null;
                try
                {
                    // The default value may be escaped
                    defaultValue = smoColumn.DefaultConstraint == null
                        ? null
                        : FromSqlScript.UnwrapLiteral(smoColumn.DefaultConstraint.Text);
                }
                catch (PropertyCannotBeRetrievedException)
                {
                    // This exception will be thrown when the user doesn't have view definition privilege,
                    // we can ignore it and use null as the default value;
                }

                EditColumnMetadata column = new EditColumnMetadata
                {
                    DefaultValue  = defaultValue,
                    EscapedName   = ToSqlScript.FormatIdentifier(smoColumn.Name),
                    Ordinal       = i,
                    IsHierarchyId = smoColumn.DataType.SqlDataType == SqlDataType.HierarchyId,
                };
                editColumns.Add(column);
            }

            // Only tables can be memory-optimized
            Table smoTable          = smoResult as Table;
            bool  isMemoryOptimized = false;

            // TODO: Remove IsSupported check once SMO fixes broken IsMemoryOptimized scenario (TFS #10871823)
            if (smoTable != null)
            {
                isMemoryOptimized = smoTable.IsSupportedProperty("IsMemoryOptimized") && smoTable.IsMemoryOptimized;
            }

            // Escape the parts of the name
            string[] objectNameParts      = { smoResult.Schema, smoResult.Name };
            string   escapedMultipartName = ToSqlScript.FormatMultipartIdentifier(objectNameParts);

            return(new EditTableMetadata
            {
                Columns = editColumns.ToArray(),
                EscapedMultipartName = escapedMultipartName,
                IsMemoryOptimized = isMemoryOptimized
            });
        }
Ejemplo n.º 10
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);
                }
            }
        }
Ejemplo n.º 11
0
        /// <summary>
        /// Executes this query asynchronously and collects all result sets
        /// </summary>
        private async Task ExecuteInternal()
        {
            ReliableSqlConnection sqlConn = null;

            try
            {
                // Mark that we've internally executed
                hasExecuteBeenCalled = true;

                // Don't actually execute if there aren't any batches to execute
                if (Batches.Length == 0)
                {
                    if (BatchMessageSent != null)
                    {
                        await BatchMessageSent(new ResultMessage(SR.QueryServiceCompletedSuccessfully, false, null));
                    }
                    if (QueryCompleted != null)
                    {
                        await QueryCompleted(this);
                    }
                    return;
                }

                // Locate and setup the connection
                DbConnection queryConnection = await ConnectionService.Instance.GetOrOpenConnection(editorConnection.OwnerUri, ConnectionType.Query);

                sqlConn = queryConnection as ReliableSqlConnection;
                if (sqlConn != null)
                {
                    // Subscribe to database informational messages
                    sqlConn.GetUnderlyingConnection().FireInfoMessageEventOnUserErrors = true;
                    sqlConn.GetUnderlyingConnection().InfoMessage += OnInfoMessage;
                }


                // Execute beforeBatches synchronously, before the user defined batches
                foreach (Batch b in BeforeBatches)
                {
                    await b.Execute(queryConnection, cancellationSource.Token);
                }

                // We need these to execute synchronously, otherwise the user will be very unhappy
                foreach (Batch b in Batches)
                {
                    // Add completion callbacks
                    b.BatchStart          += BatchStarted;
                    b.BatchCompletion     += BatchCompleted;
                    b.BatchMessageSent    += BatchMessageSent;
                    b.ResultSetCompletion += ResultSetCompleted;
                    await b.Execute(queryConnection, cancellationSource.Token);
                }

                // Execute afterBatches synchronously, after the user defined batches
                foreach (Batch b in AfterBatches)
                {
                    await b.Execute(queryConnection, cancellationSource.Token);
                }

                // Call the query execution callback
                if (QueryCompleted != null)
                {
                    await QueryCompleted(this);
                }
            }
            catch (Exception e)
            {
                // Call the query failure callback
                if (QueryFailed != null)
                {
                    await QueryFailed(this, e);
                }
            }
            finally
            {
                // Remove the message handler from the connection
                if (sqlConn != null)
                {
                    // Subscribe to database informational messages
                    sqlConn.GetUnderlyingConnection().InfoMessage -= OnInfoMessage;
                }

                // If any message notified us we had changed databases, then we must let the connection service know
                if (newDatabaseName != null)
                {
                    ConnectionService.Instance.ChangeConnectionDatabaseContext(editorConnection.OwnerUri, newDatabaseName);
                }

                foreach (Batch b in Batches)
                {
                    if (b.HasError)
                    {
                        ConnectionService.EnsureConnectionIsOpen(sqlConn);
                        break;
                    }
                }
            }
        }
Ejemplo n.º 12
0
        /// <summary>
        /// Executes this query asynchronously and collects all result sets
        /// </summary>
        private async Task ExecuteInternal()
        {
            // Mark that we've internally executed
            hasExecuteBeenCalled = true;

            // Don't actually execute if there aren't any batches to execute
            if (Batches.Length == 0)
            {
                return;
            }

            // Open up a connection for querying the database
            string connectionString = ConnectionService.BuildConnectionString(editorConnection.ConnectionDetails);

            // TODO: Don't create a new connection every time, see TFS #834978
            using (DbConnection conn = editorConnection.Factory.CreateSqlConnection(connectionString))
            {
                try
                {
                    await conn.OpenAsync();
                }
                catch (Exception exception)
                {
                    this.HasExecuted = true;
                    if (QueryConnectionException != null)
                    {
                        await QueryConnectionException(exception.Message);
                    }
                    return;
                }

                ReliableSqlConnection sqlConn = conn as ReliableSqlConnection;
                if (sqlConn != null)
                {
                    // Subscribe to database informational messages
                    sqlConn.GetUnderlyingConnection().InfoMessage += OnInfoMessage;
                }

                try
                {
                    // We need these to execute synchronously, otherwise the user will be very unhappy
                    foreach (Batch b in Batches)
                    {
                        b.BatchStart          += BatchStarted;
                        b.BatchCompletion     += BatchCompleted;
                        b.ResultSetCompletion += ResultSetCompleted;
                        await b.Execute(conn, cancellationSource.Token);
                    }

                    // Call the query execution callback
                    if (QueryCompleted != null)
                    {
                        await QueryCompleted(this);
                    }
                }
                catch (Exception)
                {
                    // Call the query failure callback
                    if (QueryFailed != null)
                    {
                        await QueryFailed(this);
                    }
                }
                finally
                {
                    if (sqlConn != null)
                    {
                        // Subscribe to database informational messages
                        sqlConn.GetUnderlyingConnection().InfoMessage -= OnInfoMessage;
                    }
                }

                // TODO: Close connection after eliminating using statement for above TODO
            }
        }
Ejemplo n.º 13
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);
                    }
                }
            }
        }
Ejemplo n.º 14
0
        /// <summary>
        /// Generates a edit-ready metadata object using SMO
        /// </summary>
        /// <param name="connection">Connection to use for getting metadata</param>
        /// <param name="objectNamedParts">Split and unwrapped name parts</param>
        /// <param name="objectType">Type of the object to return metadata for</param>
        /// <returns>Metadata about the object requested</returns>
        public EditTableMetadata GetObjectMetadata(DbConnection connection, string[] objectNamedParts, string objectType)
        {
            Validate.IsNotNull(nameof(objectNamedParts), objectNamedParts);
            if (objectNamedParts.Length <= 0)
            {
                throw new ArgumentNullException(nameof(objectNamedParts), SR.EditDataMetadataObjectNameRequired);
            }
            if (objectNamedParts.Length > 2)
            {
                throw new InvalidOperationException(SR.EditDataMetadataTooManyIdentifiers);
            }

            // Get a connection to the database for SMO purposes
            SqlConnection sqlConn = connection as SqlConnection;

            if (sqlConn == null)
            {
                // It's not actually a SqlConnection, so let's try a reliable SQL connection
                ReliableSqlConnection reliableConn = connection as ReliableSqlConnection;
                if (reliableConn == null)
                {
                    // If we don't have connection we can use with SMO, just give up on using SMO
                    return(null);
                }

                // We have a reliable connection, use the underlying connection
                sqlConn = reliableConn.GetUnderlyingConnection();
            }

            // Connect with SMO and get the metadata for the table
            Server   server = new Server(new ServerConnection(sqlConn));
            Database db     = new Database(server, sqlConn.Database);

            TableViewTableTypeBase smoResult;

            switch (objectType.ToLowerInvariant())
            {
            case "table":
                smoResult = objectNamedParts.Length == 1
                        ? new Table(db, objectNamedParts[0])                        // No schema provided
                        : new Table(db, objectNamedParts[1], objectNamedParts[0]);  // Schema provided
                break;

            case "view":
                smoResult = objectNamedParts.Length == 1
                        ? new View(db, objectNamedParts[0])                         // No schema provided
                        : new View(db, objectNamedParts[1], objectNamedParts[0]);   // Schema provided
                break;

            default:
                throw new ArgumentOutOfRangeException(nameof(objectType), SR.EditDataUnsupportedObjectType(objectType));
            }

            // A bug in SMO makes it necessary to call refresh to attain certain properties (such as IsMemoryOptimized)
            smoResult.Refresh();
            if (smoResult.State != SqlSmoState.Existing)
            {
                throw new ArgumentOutOfRangeException(nameof(objectNamedParts), SR.EditDataObjectNotFound);
            }

            // Generate the edit column metadata
            List <EditColumnMetadata> editColumns = new List <EditColumnMetadata>();

            for (int i = 0; i < smoResult.Columns.Count; i++)
            {
                Column smoColumn = smoResult.Columns[i];

                // The default value may be escaped
                string defaultValue = smoColumn.DefaultConstraint == null
                    ? null
                    : SqlScriptFormatter.UnwrapLiteral(smoColumn.DefaultConstraint.Text);

                EditColumnMetadata column = new EditColumnMetadata
                {
                    DefaultValue = defaultValue,
                    EscapedName  = SqlScriptFormatter.FormatIdentifier(smoColumn.Name),
                    Ordinal      = i,
                };
                editColumns.Add(column);
            }

            // Only tables can be memory-optimized
            Table smoTable          = smoResult as Table;
            bool  isMemoryOptimized = smoTable != null && smoTable.IsMemoryOptimized;

            // Escape the parts of the name
            string[] objectNameParts      = { smoResult.Schema, smoResult.Name };
            string   escapedMultipartName = SqlScriptFormatter.FormatMultipartIdentifier(objectNameParts);

            return(new EditTableMetadata
            {
                Columns = editColumns.ToArray(),
                EscapedMultipartName = escapedMultipartName,
                IsMemoryOptimized = isMemoryOptimized,
            });
        }