One Way to Find Broken Code on Your Server

,

Before we approached our last major SQL Server upgrade, I was curious about what might break.  Yes, I had used the DEA to check our code against deprecated or discontinued code.  But I am talking about code that might not have been used in some time and would break because objects no longer existed, or other things like that.  So I wrote these scripts to refresh the sprocs, views and functions in our (non-production) environment.  These scripts automatically weed out schema-bound objects (which will not work with these), give you a list of what’s left, and then the scripts to refresh the metadata.  When those scripts are run, if or when they fail, they generally give you a very good reason why, which you can then give to your developers (hopefully, in enough time to get them fixed prior to the upgrade).  I have left the line of code that would automatically execute the scripts commented out, but it can be used at your discretion. I hope you find these helpful.

Stored Procedures:

IF OBJECT_ID('tempdb..#SprocInfo') IS NOT NULL
    DROP TABLE #SprocInfo;
IF OBJECT_ID('tempdb..#ScriptInfo') IS NOT NULL
    DROP TABLE #ScriptInfo;
IF OBJECT_ID('tempdb..#SBSprocInfo') IS NOT NULL
    DROP TABLE #SBSprocInfo;
CREATE TABLE #SBSprocInfo
(
    DatabaseName sysname,
    SchemaName sysname,
    SchemaBoundSprocName sysname
);
CREATE TABLE #SprocInfo
(
    DatabaseName sysname,
    SchemaName sysname,
    EligibleSprocName sysname
);
CREATE TABLE #ScriptInfo
(
    Script NVARCHAR(MAX)
);
PRINT 'Gathering preliminary info.... finding schema bound sprocs. This will not work with schema bound sprocs.';
INSERT INTO #SBSprocInfo
(
    DatabaseName,
    SchemaName,
    SchemaBoundSprocName
)
	SELECT DB_NAME() AS DatabaseName,
	OBJECT_SCHEMA_NAME(i.object_id) AS SchemaName,
	OBJECT_NAME(i.object_id) AS SchemaBoundSprocName
	FROM sys.indexes AS i
	WHERE i.OBJECT_ID in (SELECT v.object_id FROM sys.procedures AS v);
SELECT *
FROM #SBSprocInfo;
PRINT 'Getting the eligible sprocs....';
	INSERT INTO #SprocInfo
	SELECT DB_NAME() AS DatabaseName, 
	s.name AS SchemaName, 
	o.name AS EligibleSprocName
FROM sys.objects AS o
INNER JOIN sys.schemas AS s 
ON o.schema_id = s.schema_id
WHERE type_desc = 'SQL_STORED_PROCEDURE'
AND is_ms_shipped = 0
AND o.name NOT IN (SELECT SchemaBoundSprocName COLLATE DATABASE_DEFAULT FROM #SBSprocInfo);
SELECT *
FROM #SprocInfo;
PRINT 'Building and executing the script!';
INSERT INTO #ScriptInfo
(
    Script
)
SELECT N'USE [' + DatabaseName + N']; EXECUTE sp_refreshsqlmodule N''' + SchemaName + '.' + EligibleSprocName + N''';'
FROM #SprocInfo;
DECLARE @FinalScriptName sysname;
DECLARE @FinalScriptCursor CURSOR;
SET @FinalScriptCursor = CURSOR FAST_FORWARD LOCAL FOR
SELECT Script
FROM #ScriptInfo;
OPEN @FinalScriptCursor;
FETCH NEXT FROM @FinalScriptCursor
INTO @FinalScriptName;
WHILE (@@FETCH_STATUS = 0)
BEGIN
    PRINT @FinalScriptName;
    --EXECUTE sp_executesql @FinalScriptName;
    FETCH NEXT FROM @FinalScriptCursor
    INTO @FinalScriptName;
END;
CLOSE @FinalScriptCursor;
DEALLOCATE @FinalScriptCursor;
SELECT *
FROM #ScriptInfo;
DROP TABLE #SprocInfo;
DROP TABLE #ScriptInfo;
DROP TABLE #SBSprocInfo;

Views:

IF OBJECT_ID('tempdb..#ViewInfo') IS NOT NULL
    DROP TABLE #ViewInfo;
IF OBJECT_ID('tempdb..#ScriptInfo') IS NOT NULL
    DROP TABLE #ScriptInfo;
IF OBJECT_ID('tempdb..#SBViewInfo') IS NOT NULL
    DROP TABLE #SBViewInfo;
CREATE TABLE #SBViewInfo
(
    DatabaseName sysname,
    SchemaName sysname,
    SchemaBoundViewName sysname
);
CREATE TABLE #ViewInfo
(
    DatabaseName sysname,
    SchemaName sysname,
    EligibleViewName sysname
);
CREATE TABLE #ScriptInfo
(
    Script NVARCHAR(MAX)
);
PRINT 'Gathering preliminary info.... finding schema bound views. This will not work with schema bound views.';
DECLARE @SBViewsName sysname;
DECLARE @SBViewsCursor CURSOR;
DECLARE @SBViewsSQL NVARCHAR(MAX);
SET @SBViewsCursor = CURSOR FAST_FORWARD LOCAL FOR
SELECT name
FROM sys.databases
WHERE source_database_id IS NULL
      AND database_id > 4
      AND is_read_only = 0
      AND state_desc = 'ONLINE'
      AND name NOT LIKE 'ReportServer%'
ORDER BY name;
OPEN @SBViewsCursor;
FETCH NEXT FROM @SBViewsCursor
INTO @SBViewsName;
WHILE (@@FETCH_STATUS = 0)
BEGIN
    SET @SBViewsSQL
        = N'USE [' + @SBViewsName + N'];
	
	SELECT '''        + @SBViewsName
          + N''' AS DatabaseName,
	OBJECT_SCHEMA_NAME(i.object_id) AS SchemaName,
	OBJECT_NAME(i.object_id) AS SchemaBoundViewName
	FROM sys.indexes AS i
	WHERE i.OBJECT_ID in (SELECT v.object_id FROM sys.views AS v);';
    PRINT @SBViewsSQL;
    INSERT INTO #SBViewInfo
    EXECUTE sp_executesql @SBViewsSQL;
    FETCH NEXT FROM @SBViewsCursor
    INTO @SBViewsName;
END;
CLOSE @SBViewsCursor;
DEALLOCATE @SBViewsCursor;
SELECT *
FROM #SBViewInfo;
PRINT 'Getting the eligible views....';
DECLARE @ViewInfoName sysname;
DECLARE @ViewInfoCursor CURSOR;
DECLARE @ViewSQLCursor NVARCHAR(MAX);
SET @ViewInfoCursor = CURSOR FAST_FORWARD LOCAL FOR
SELECT name
FROM sys.databases
WHERE source_database_id IS NULL
      AND database_id > 4
      AND is_read_only = 0
      AND state_desc = 'ONLINE'
ORDER BY name;
OPEN @ViewInfoCursor;
FETCH NEXT FROM @ViewInfoCursor
INTO @ViewInfoName;
WHILE (@@FETCH_STATUS = 0)
BEGIN
    SET @ViewSQLCursor
        = N'USE [' + @ViewInfoName + N'];
	INSERT INTO #ViewInfo
	SELECT '''           + @ViewInfoName
          + N''' AS DatabaseName, 
	s.name AS SchemaName, 
	o.name AS EligibleViewName
FROM sys.objects AS o
INNER JOIN sys.schemas AS s 
ON o.schema_id = s.schema_id
WHERE type_desc = ''VIEW''
AND is_ms_shipped = 0
AND o.name NOT IN (SELECT SchemaBoundViewName COLLATE DATABASE_DEFAULT FROM #SBViewInfo)';
    PRINT @ViewSQLCursor;
    EXECUTE sp_executesql @ViewSQLCursor;
    FETCH NEXT FROM @ViewInfoCursor
    INTO @ViewInfoName;
END;
CLOSE @ViewInfoCursor;
DEALLOCATE @ViewInfoCursor;
SELECT *
FROM #ViewInfo;
PRINT 'Building and executing the script!';
INSERT INTO #ScriptInfo
(
    Script
)
SELECT N'USE [' + DatabaseName + N']; EXECUTE sp_refreshview N''' + SchemaName + '.' + EligibleViewName + N''';'
FROM #ViewInfo;
DECLARE @FinalScriptName sysname;
DECLARE @FinalScriptCursor CURSOR;
SET @FinalScriptCursor = CURSOR FAST_FORWARD LOCAL FOR
SELECT Script
FROM #ScriptInfo;
OPEN @FinalScriptCursor;
FETCH NEXT FROM @FinalScriptCursor
INTO @FinalScriptName;
WHILE (@@FETCH_STATUS = 0)
BEGIN
    PRINT @FinalScriptName;
    --EXECUTE sp_executesql @FinalScriptName;
    FETCH NEXT FROM @FinalScriptCursor
    INTO @FinalScriptName;
END;
CLOSE @FinalScriptCursor;
DEALLOCATE @FinalScriptCursor;
SELECT *
FROM #ScriptInfo;
DROP TABLE #ViewInfo;
DROP TABLE #ScriptInfo;
DROP TABLE #SBViewInfo;

Functions:

IF OBJECT_ID('tempdb..#FunctionInfo') IS NOT NULL
    DROP TABLE #FunctionInfo;
IF OBJECT_ID('tempdb..#ScriptInfo') IS NOT NULL
    DROP TABLE #ScriptInfo;
IF OBJECT_ID('tempdb..#SBFunctionInfo') IS NOT NULL
    DROP TABLE #SBFunctionInfo;
CREATE TABLE #SBFunctionInfo
(
    DatabaseName sysname,
    SchemaName sysname,
    SchemaBoundFunctionName sysname
);
CREATE TABLE #FunctionInfo
(
    DatabaseName sysname,
    SchemaName sysname,
    EligibleFunctionName sysname
);
CREATE TABLE #ScriptInfo
(
    Script NVARCHAR(MAX)
);
PRINT 'Gathering preliminary info.... finding schema bound functions. This will not work with schema bound functions.';
DECLARE @SBFunctionsName sysname;
DECLARE @SBFunctionsCursor CURSOR;
DECLARE @SBFunctionsSQL NVARCHAR(MAX);
SET @SBFunctionsCursor = CURSOR FAST_FORWARD LOCAL FOR
SELECT name
FROM sys.databases
WHERE source_database_id IS NULL
      AND database_id > 4
      AND is_read_only = 0
      AND state_desc = 'ONLINE'
      AND name NOT LIKE 'ReportServer%'
	 ORDER BY name;
OPEN @SBFunctionsCursor;
FETCH NEXT FROM @SBFunctionsCursor
INTO @SBFunctionsName;
WHILE (@@FETCH_STATUS = 0)
BEGIN
    SET @SBFunctionsSQL
        = N'USE [' + @SBFunctionsName + N'];
	
	SELECT '''        + @SBFunctionsName
          + N''' AS DatabaseName,
	OBJECT_SCHEMA_NAME(i.object_id) AS SchemaName,
	OBJECT_NAME(i.object_id) AS SchemaBoundFunctionName
	FROM sys.indexes AS i
	WHERE i.OBJECT_ID in (SELECT v.object_id FROM sys.views AS v);';
    PRINT @SBFunctionsSQL;
    INSERT INTO #SBFunctionInfo
    EXECUTE sp_executesql @SBFunctionsSQL;
    FETCH NEXT FROM @SBFunctionsCursor
    INTO @SBFunctionsName;
END;
CLOSE @SBFunctionsCursor;
DEALLOCATE @SBFunctionsCursor;
SELECT *
FROM #SBFunctionInfo;
PRINT 'Getting the eligible Functions....';
DECLARE @FunctionInfoName sysname;
DECLARE @FunctionInfoCursor CURSOR;
DECLARE @FunctionSQLCursor NVARCHAR(MAX);
SET @FunctionInfoCursor = CURSOR FAST_FORWARD LOCAL FOR
SELECT name
FROM sys.databases
WHERE source_database_id IS NULL
      AND database_id > 4
      AND is_read_only = 0
      AND state_desc = 'ONLINE'
      AND name NOT LIKE 'ReportServer%'
	 ORDER BY name;
OPEN @FunctionInfoCursor;
FETCH NEXT FROM @FunctionInfoCursor
INTO @FunctionInfoName;
WHILE (@@FETCH_STATUS = 0)
BEGIN
    SET @FunctionSQLCursor
        = N'USE [' + @FunctionInfoName + N'];
	INSERT INTO #FunctionInfo
	SELECT '''           + @FunctionInfoName
          + N''' AS DatabaseName, 
	s.name AS SchemaName, 
	o.name AS EligibleFunctionName
FROM sys.objects AS o
INNER JOIN sys.schemas AS s 
ON o.schema_id = s.schema_id
WHERE type_desc LIKE ''%Function%''
AND is_ms_shipped = 0
AND o.name NOT IN (SELECT SchemaBoundFunctionName COLLATE DATABASE_DEFAULT FROM #SBFunctionInfo)';
    PRINT @FunctionSQLCursor;
    EXECUTE sp_executesql @FunctionSQLCursor;
    FETCH NEXT FROM @FunctionInfoCursor
    INTO @FunctionInfoName;
END;
CLOSE @FunctionInfoCursor;
DEALLOCATE @FunctionInfoCursor;
SELECT *
FROM #FunctionInfo;
PRINT 'Building and executing the script!';
INSERT INTO #ScriptInfo
(
    Script
)
SELECT N'USE [' + DatabaseName + N']; EXECUTE sp_refreshsqlmodule N''' + SchemaName + '.' + EligibleFunctionName + N''';'
FROM #FunctionInfo;
DECLARE @FinalScriptName sysname;
DECLARE @FinalScriptCursor CURSOR;
SET @FinalScriptCursor = CURSOR FAST_FORWARD LOCAL FOR
SELECT Script
FROM #ScriptInfo;
OPEN @FinalScriptCursor;
FETCH NEXT FROM @FinalScriptCursor
INTO @FinalScriptName;
WHILE (@@FETCH_STATUS = 0)
BEGIN
    PRINT @FinalScriptName;
    --EXECUTE sp_executesql @FinalScriptName;
    FETCH NEXT FROM @FinalScriptCursor
    INTO @FinalScriptName;
END;
CLOSE @FinalScriptCursor;
DEALLOCATE @FinalScriptCursor;
SELECT *
FROM #ScriptInfo;
DROP TABLE #FunctionInfo;
DROP TABLE #ScriptInfo;
DROP TABLE #SBFunctionInfo;

Original post (opens in new tab)
View comments in original post (opens in new tab)

Rate

Share

Share

Rate