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
2010-05-07 04:40:00