Technical Article

consolidated script generator for multiple stored procedures

,

Overview:

This document describes how to generate script for multiple stored procedures ('Create' or 'Alter') with the help of a generalized stored procedure.

 

Script generation narration :
In an existing large production environment it often happens that there are multiple users exist and they have different access permission on existing procedres. Now if we require to do some changes in those procedures, we need to keep the existing permisions intact. In this scenario we need to pass the 'Alter' script instead of 'Drop' & 'Create' script. We may also need to generate create script for new procedures.

There are many situations when such requirements come to us.

Let's take one example-

We are working on a development or an enhancement ticket where we are required to modify many existing stored procedures and also create some number of them. After the job is done we need to send a consolidated script of the changes to be run in the uat, production environment.

Normally it is a manual affair of selecting the stored procedures and create either ALTER or CREATE scripts depending upon whether the stored procedure is modified or new respectively. In this scenario my new generalized stored procedure will come handy as you will have to pass only the name of the stored procedures and identifier to notify if they are 'N'ew or 'O'ld.

To use this script

1. Run the above stored procedure in your sql server database.

2. Please select 'Results to Text' or 'Results to File' option in Query analyzer.

3. After completing step 1,2 execute the procedure as shown below:

Exec uspScriptGenerator 'Proc1~N|Proc2~O|' or 'Proc1~N|Proc2~O'

Note: 'N' is used to notify it's 'New' hence it will be 'Create' script.'O' is used to notify it's 'Old' (existing) hence it will be 'Alter' script.

The consolidated script will generate like

 

/*** Start of script ***/
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO

Create Procesure Proc1 ...

.

.

.

GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER OFF
GO

/*** End of script ***/

/*** Start of script ***/
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO

Alter Procesure Proc2 ...

.

.

.

GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER OFF
GO

/*** End of script ***/

/****** Object: StoredProcedure [dbo].[uspScriptGenerator] ******/IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[uspScriptGenerator]') AND type in (N'P', N'PC'))
DROP PROCEDURE [dbo].[uspScriptGenerator]
GO


/****** Object: StoredProcedure [dbo].[uspScriptGenerator] ******/SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO


CREATE Procedure [dbo].[uspScriptGenerator] 
(
    @Psp_name_list varchar(max) -- parameter consisting the procedures name and there type ie ('N'ew / 'O'ld) 'Proc1~N|Proc2~O|' or 'Proc3~N|Proc4~O'
)
As

begin

    set nocount on

    /* table variable to hold the stored proc list */    declare @tbl_sp_name_list table (row_no int identity(1,1)
                                        , sp_name varchar(200)
                                        , sp_status char(1)
                                        )

    /* start computing the stored proc generation */    if @Psp_name_list is not null
    begin
        declare @sp_name_list_str varchar(8000)
                , @pipe_pos int
                , @tild_pos int
                , @curr_row_str varchar(8000)
                , @sp_name varchar(200)
                , @sp_status char(1)
                , @curr_sp_name varchar(200)
                , @curr_sp_status char(1)
                , @curr_row int
                , @max_row int 
                , @bl_end_of_str char(1)
                , @spid int

        declare @exec_script varchar(2000)
        declare @start_text varchar(200)
        declare @end_text varchar(200)

        set @spid = @@spid
        set @sp_name_list_str = @Psp_name_list
        set @bl_end_of_str = 'N'

        set @pipe_pos = charindex('|', @sp_name_list_str)

        if @@ERROR <> 0 GoTo IGoWithError

        if @pipe_pos = 0
        begin
            set @pipe_pos = len(@sp_name_list_str)
            set @bl_end_of_str = 'Y'
        end

        /* start looping to retrieve the proc name and it's type */        While @pipe_pos <> 0
        begin

            if @bl_end_of_str = 'N'
            begin
                set @curr_row_str = substring(@sp_name_list_str, 1, @pipe_pos - 1 )
                set @sp_name_list_str = substring(@sp_name_list_str, @pipe_pos + 1 , len(@sp_name_list_str))

                if @@ERROR <> 0 GoTo IGoWithError

            end

            if @bl_end_of_str = 'Y'
            begin
                set @curr_row_str = substring(@sp_name_list_str, 1, @pipe_pos )
                set @sp_name_list_str = '' 

                if @@ERROR <> 0 GoTo IGoWithError

            end


            set @tild_pos = charindex ('~', @curr_row_str)

            if @tild_pos = 0 GoTo IGoWithError

            set @sp_name = case when @tild_pos = 1 then null else substring(@curr_row_str, 1, @tild_pos -1 ) end
            set @curr_row_str = substring(@curr_row_str, @tild_pos +1, len(@curr_row_str))

            if @@ERROR <> 0 GoTo IGoWithError

            set @tild_pos = charindex ('~', @curr_row_str)
            set @sp_status = case when @curr_row_str = '' then null else @curr_row_str end


            if @@ERROR <> 0 GoTo IGoWithError

            /* Check if @sp_name exists */ 
            if (object_id(@sp_name) is not null)
            begin
                /* Check if @sp_name already considered*/                if not exists(select sp_name from @tbl_sp_name_list where sp_name = @sp_name)
                 begin
                 insert into @tbl_sp_name_list (sp_name, sp_status)
                 values (@sp_name, @sp_status)    
                 end
            end

            if @@ERROR <> 0 GoTo IGoWithError

            set @pipe_pos = charindex('|', @sp_name_list_str)

            if @pipe_pos = 0
            begin
                set @pipe_pos = len(@sp_name_list_str)
                set @bl_end_of_str = 'Y'

                if @@ERROR <> 0 GoTo IGoWithError
            
            end 
            end 

    end

    /* Select Number of procedure name passed */    select @max_row = count(*) from @tbl_sp_name_list

    if @max_row is not null
    begin

        declare @tbl_create_sp_script table (sp_name varchar(200) not null
                                             , row_no int null
                                             , sp_text varchar(4000) null)

        set @exec_script = 'create table ##tmp_tbl_sp_script_' + cast(@spid as varchar(10)) + ' (row_no int identity(1,1),sp_text varchar(4000) null)'
        exec(@exec_script)

        if @@ERROR <> 0 GoTo IGoWithError

        /* Set the header information for each procedure */        --set @start_text = ' ' + char(10) + char(13)
        set @start_text = '/*** Start of script ***/' + char(10)
        set @start_text = @start_text + 'GO ' + char(10) 
        set @start_text = @start_text + 'SET ANSI_NULLS ON ' + char(10) 
        set @start_text = @start_text + 'GO ' + char(10) 
        set @start_text = @start_text + 'SET QUOTED_IDENTIFIER ON ' + char(10)
        set @start_text = @start_text + 'GO ' + char(10) + char(13)

        set @curr_row = 1
        while @curr_row <= @max_row
        begin

            select @curr_sp_name = sp_name from @tbl_sp_name_list where row_no = @curr_row

            select @curr_sp_status = sp_status from @tbl_sp_name_list where row_no = @curr_row

            insert into @tbl_create_sp_script (sp_name,row_no,sp_text)
            select @curr_sp_name,0,@start_text

            set @exec_script = null

            set @exec_script = 'insert into ##tmp_tbl_sp_script_' + cast(@spid as varchar(10)) + ' (sp_text)'

            set @exec_script = @exec_script + ' exec sp_helptext ''' + @curr_sp_name + '''' 

            exec(@exec_script)

            if @@ERROR <> 0 GoTo IGoWithErrorAndDropTable

            /* Set the trailer information for each procedure */            set @end_text = char(10) + char(13)
            set @end_text = @end_text + 'GO ' + char(10
            set @end_text = @end_text + 'SET ANSI_NULLS ON ' + char(10) --+ char(13)
            set @end_text = @end_text + 'GO ' + char(10) --+ char(13)
            set @end_text = @end_text + 'SET QUOTED_IDENTIFIER OFF ' + char(10)-- + char(13)
            set @end_text = @end_text + 'GO ' + char(10) + char(13)
            set @end_text = @end_text + '/*** End of script ***/'
            set @end_text = @end_text + char(10) + char(13)

            /* Reset the variable to insert data in temporary table */            set @exec_script = null
            set @exec_script = 'insert into ##tmp_tbl_sp_script_' + cast(@spid as varchar(10)) + ' (sp_text) select ''' + @end_text + ''''

            exec(@exec_script)

            /* Adjust the procedure script from 'Create' to 'Alter' if it's old one */            set @exec_script = null

            set @exec_script = 'update ##tmp_tbl_sp_script_' + cast(@spid as varchar(10))
            set @exec_script = @exec_script + ' set sp_text = REPLACE ( sp_text , ltrim(rtrim(substring(sp_text,1,charindex(upper(''procedure''),upper(sp_text)) + 9 ))) , ''Alter Procedure'' )'
            set @exec_script = @exec_script + ' where sp_text like ''%create%procedure%'' and upper(''' + @curr_sp_status + ''') = ''O'''

            exec(@exec_script)

            if @@ERROR <> 0 GoTo IGoWithErrorAndDropTable

            /* Retrieve the procedure script and insert into table variable for final script generation */            set @exec_script = null
            set @exec_script = 'select ''' + @curr_sp_name + ''',row_no,sp_text'
            set @exec_script = @exec_script + ' from ##tmp_tbl_sp_script_' + cast(@spid as varchar(10)) 
            set @exec_script = @exec_script + ' order by row_no'

            insert into @tbl_create_sp_script (sp_name,row_no,sp_text)
            exec(@exec_script)

            if @@ERROR <> 0 GoTo IGoWithErrorAndDropTable
            set @exec_script = null
            set @exec_script = 'delete ##tmp_tbl_sp_script_' + cast(@spid as varchar(10)) 
            exec(@exec_script)

            if @@ERROR <> 0 GoTo IGoWithErrorAndDropTable

            set @curr_row = @curr_row + 1

        end

        select sp_text [All Stored Procedure Script Text] 
        from @tbl_create_sp_script
        order by sp_name,row_no

        goto IGoWithoutError

    end

    IGoWithoutError: 
        IF EXISTS(SELECT * FROM tempdb..sysobjects WHERE name = '##tmp_tbl_sp_script_' + cast(@spid as varchar(10)) ) 
        set @exec_script = 'drop table ##tmp_tbl_sp_script_' + cast(@spid as varchar(10))
        exec(@exec_script) 
        return (1)

    IGoWithErrorAndDropTable:
        IF EXISTS(SELECT * FROM tempdb..sysobjects WHERE name = '##tmp_tbl_sp_script_' + cast(@spid as varchar(10))) 
        set @exec_script = 'drop table ##tmp_tbl_sp_script_' + cast(@spid as varchar(10))
        exec(@exec_script) 
        raiserror ('Error generating script.',16,1) 
        return (-1)

    IGoWithError: 
        raiserror ('Error generating script. Please check the supplied stored procedure name(s) and/or value passed in.',16, 1)
        return (-1) 

end


GO

Rate

3 (2)

You rated this post out of 5. Change rating

Share

Share

Rate

3 (2)

You rated this post out of 5. Change rating