views:

15

answers:

1

I'm in the course of doing some schema migrations, and would like to know if it's possible or advisable to run every stored procedure, view and function in my database as an alter statement to "compile" them all to make sure nothing is completely broken.

A: 

Well, I built a sproc to do this, not very elegant, but hopefully someone else will find it useful:

CREATE PROCEDURE [dbo].[UTIL_RunAlterOnAll]
    @debugMessages BIT = 0
AS
BEGIN
    BEGIN TRAN
        SET NOCOUNT ON

        DECLARE @allAlterTexts TABLE (name VARCHAR(256), alterText NVARCHAR(MAX), id INT, type CHAR(2))

        DECLARE @rowsInError TABLE (errorMessage NVARCHAR(2048), errorNumber INT, name VARCHAR(256), alterText NVARCHAR(MAX), id INT, type CHAR(2))

        ;WITH Texts AS
        (
            SELECT o.name, o.type, sm.definition AS text, o.id
            FROM sysobjects AS o
            INNER JOIN sys.sql_modules AS sm
            ON sm.object_id = o.id
            WHERE o.type IN ('P', 'V', 'FN')
        )
        INSERT INTO @allAlterTexts (name, alterText, id, type)
        SELECT name, alterStatement, id, type
        FROM
        (
            SELECT name, REPLACE(text, 'CREATE PROCEDURE', 'ALTER PROCEDURE') AS alterStatement, id, type
            FROM Texts AS procs
            WHERE procs.type = 'P'
            UNION ALL
            SELECT name, REPLACE(text, 'CREATE VIEW', 'ALTER VIEW') AS alterStatement, id, type
            FROM Texts AS procs
            WHERE procs.type = 'V'
            UNION ALL
            SELECT name, REPLACE(text, 'CREATE FUNCTION', 'ALTER FUNCTION') AS alterStatement, id, type
            FROM Texts AS procs
            WHERE procs.type = 'FN'
        ) AS allAlters

        DECLARE curs CURSOR FORWARD_ONLY
        FOR
            SELECT *
            FROM @allAlterTexts

        DECLARE @name VARCHAR(MAX)
            , @alterText VARCHAR(MAX)
            , @id INT
            , @type VARCHAR(2)

        OPEN curs
            FETCH NEXT FROM curs
            INTO @name, @alterText, @id, @type

            WHILE @@FETCH_STATUS = 0
            BEGIN
                IF @debugMessages = 1
                BEGIN
                    PRINT 'Alter text for @name'
                    PRINT '-----'
                    PRINT @alterText
                    PRINT '-----'
                END

                BEGIN TRY
                    IF @debugMessages = 1
                    BEGIN
                        PRINT 'Running ' + @name
                    END
                        EXEC(@alterText)
                    IF @debugMessages = 1
                    BEGIN
                        PRINT 'Success'
                    END
                END TRY
                BEGIN CATCH
                    IF @debugMessages = 1
                    BEGIN
                        PRINT 'ERROR!'
                        PRINT ERROR_MESSAGE()
                        PRINT '----'
                        PRINT 'Text:'
                        PRINT @alterText
                    END

                    INSERT INTO @rowsInError (errorMessage, errorNumber, name, alterText, id, type)
                    VALUES(LTRIM(RTRIM(ERROR_MESSAGE())), ERROR_NUMBER(), @name, @alterText, @id, @type)
                END CATCH


                IF @debugMessages = 1
                BEGIN
                    PRINT '-----'
                END

                FETCH NEXT FROM curs
                INTO @name, @alterText, @id, @type
            END
        CLOSE curs

        DEALLOCATE curs
        SET NOCOUNT OFF

        -- WTF? 3930 means transaction error, these get raised whenever another error is raised, 
        -- as the transaction is set to invalid
        SELECT *
        FROM @rowsInError
        WHERE errorNumber != 3930
        ORDER BY name

    ROLLBACK TRAN
END
GO
Khanzor