inplace upgrade failed

  • Hi,

    We are doing in-place upgrade from sql 2000 standard edition to sql 2005 developer edition and the upgrade failed with the below error

    SQL Server Setup has encountered the following problem: [Microsoft][SQL Native Client][SQL Server]Password validation failed. The password does not meet Windows policy requirements because it is too short... To continue, correct the problem, and then run SQL Server Setup again

    event viewer error:

    Error: 50000 Severity: 20 State: 127 Cannot create ##MS_AgentSigningCertificate## in msdb. INSTMSDB.SQL terminating.

    please advice me

  • See if this helps:

    A workaround solution has been discovered, in relation to this Microsoft KB (Knowledge Base) Article : Error message in the SQL Server Error log file after you upgrade SQL Server 2000 to SQL Server 2005 on a server that is running Windows Server 2003: "Unable to update password policy" – http://support.microsoft.com/kb/936892/en-us.Which provides us with the information that this Trace Flag (-T4606) can be used to bypass the Windows Server 2003 Local GPO Password Policy requirements for a SQL Server 2005 Installation. This Trace Flag is added into the Windows Server 2003 System Registry before any subsequent Instances of SQL Server 2005 (whether that be 2, 3, 4, 5, 6 etc) commence, it’s entered into this Registry Key Hive : HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\MSSQL.X\MSSQLServer\Parameters

    Where the ‘x’ represents the actual numerical increment to the SQL Server 2005 Multi-Instance Environment.

    MJ

  • Thanks Manu.

    I did the Registry hive HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\MSSQL.1\MSSQLServer\Parameters . In parameters I gave SQLArg3 value as -T4606.

    The sql 2000 has Microsoft SQL Server

    ->8.00.000

    +80

    I mean to say there is no MSSQL folder in the registry for sql server 2000. So in that case when I install sql server 2005 do I need to do the regestry hive in MSSQL or MSSQL.1. Because I did the registry hive in MSSQL.1 as I noticed while the setup running its going to this path C:\Program Files\Microsoft SQL Server\MSSQL.1\MSSQL\Install\instmsdb.sql

    thats why I did the regestry hike in MSSQL.1.BUT after we got the error I went and look for the the registry hive I created in MSSQl.1, But it has been removed?

    So Please advice me considering sql 2000 is a default instance and Iam doing in-place upgrade to sql 2005, where exactly I need to do the regestry hive?

    But enquired many other DBAs, but they did not face this issue. Why we are only getting this error?

  • Have you tried Method1 stated in KB article-->http://support.microsoft.com/kb/936892/en-us.

    Method 1: Update the password of the SQL Server login to comply with the password policy in Windows Server 2003

    MJ

  • If there is no sql server 2005 was installed We can not use method 1 as it saying

    Open configuration manager(If do not have sql server 2005 installed, there is no Sql server configuration manager right?)

  • Try performing those steps for SQL 2000 instance:

    Instead of configuration manager use services applet.

    MJ

  • Leave what I said above.

    Try this:

    It appears that the offending password is in the line:

    encryption by password = 'Yukon90_'

    in the script sqlagent90_msdb_upgrade.sql.

    I found this problem, changed the password in the script to match my system policy, and reran a clean install and all worked well. There is another line that enters this into a table, and you should change it there as well.

    From-->http://social.msdn.microsoft.com/Forums/en-US/sqlsetupandupgrade/thread/5ce5ef27-7311-4477-9b48-5f3553fa3c9c/

    MJ

  • Thanks Manu,

    There is no option to add -T4606 in services applet( in serverces.msc) any other workaround please...

  • Have you tried what I suggested just now. Changin hard coded password.

    Check-->

    The work-around is to edit the INSTMSDB.SQL script and change two instances of Yukon90_ to something more complex. In my case, I used: 1qaz@WSX3edc$RFV

    You need to anticipate where the SQL installer will copy the file and replace the file while the install is running, but BEFORE the script is run by the installer. You may need to create empty directories ahead of time to do this. In my case, the script was placed in

    http://social.msdn.microsoft.com/Forums/en-US/sqlsetupandupgrade/thread/5ce5ef27-7311-4477-9b48-5f3553fa3c9c/

    MJ

  • Thanks for prompt response Manu,

    found this problem, changed the password in the script to match my system policy, and reran a clean install and all worked well. There is another line that enters this into a table, and you should change it there as well

    .

    in the above you mentioned that My system policy. How should I know what is our system policy? could you please explain me a little more.

  • TYpe gpedit.msc at the run command of the machine where your are performing the upgrade. Go to COmputer configuration-->windows settings-->security settings-->Account Policies-->Password....

    Or

    Just use a strong password.

    MJ

  • Hi manu,

    I will clarly explain you my scenario.

    1.Right now in the server there is only sql server 2000 default instance is there.

    2.I went to the path C:\Program Files\Microsoft SQL Server\MSSQL\Install and open the INSTMSDB.SQL file BUT there is NO such 'Yukon90_' to edit with some complex password.

    /**********************************************************************/

    /* INSTMSDB.SQL */

    /* */

    /* Installs the tables, triggers and stored procedures necessary for */

    /* supporting local (and multi-server) jobs, alerts, operators, and */

    /* backup history. These objects are used by SQLDMO, SQL Enterprise */

    /* Manager, and SQLServerAgent. */

    /* */

    /* Also contains SQL DTS (Data Transformation Services) tables and */

    /* stored procedures for local SQL Server storage of DTS Packages. */

    /* */

    /*

    ** Copyright Microsoft, Inc. 1994 - 2000

    ** All Rights Reserved.

    */

    /**********************************************************************/

    PRINT '----------------------------------'

    PRINT 'Starting execution of INSTMSDB.SQL'

    PRINT '----------------------------------'

    go

    /**************************************************************/

    /* Turn 'System Object' marking ON */

    /**************************************************************/

    EXECUTE master.dbo.sp_MS_upd_sysobj_category 1

    go

    -- Explicitly set the options that the server stores with the object in sysobjects.status

    -- so that it doesn't matter if the script is run using a DBLib or ODBC based client.

    SET QUOTED_IDENTIFIER OFF -- We don't use quoted identifiers

    SET ANSI_NULLS ON -- We don't want (NULL = NULL) == TRUE

    go

    SET ANSI_PADDING ON -- Set so that trailing zeros aren't trimmed off sysjobs.owner_login_sid

    go

    -- Allow updates to system catalogs so that all our SP's inherit full DML capability on

    -- system objects and so that we can exercise full DDL control on our system objects

    EXECUTE master.dbo.sp_configure N'allow updates', 1

    go

    RECONFIGURE WITH OVERRIDE

    go

    /**************************************************************/

    /* */

    /* D A T A B A S E C R E A T I O N */

    /* */

    /**************************************************************/

    IF (NOT EXISTS (SELECT name

    FROM master.dbo.sysdatabases

    WHERE (name = N'msdb')))

    BEGIN

    PRINT 'Creating the msdb database...'

    END

    go

    USE master

    go

    SET NOCOUNT ON

    -- NOTE: It is important that this script can be re-run WITHOUT causing loss of data, hence

    -- we only create the database if it missing (if the database already exists we test

    -- that it has enough free space and if not we expand both the device and the database).

    DECLARE @model_db_size INT

    DECLARE @msdb_db_size INT

    DECLARE @sz_msdb_db_size VARCHAR(10)

    DECLARE @device_directory NVARCHAR(520)

    DECLARE @page_size INT

    DECLARE @size INT

    DECLARE @free_db_space FLOAT

    SELECT @page_size = 8

    IF (NOT EXISTS (SELECT name

    FROM master.dbo.sysdatabases

    WHERE (name = N'msdb')))

    BEGIN

    -- Make sure that we create [the data portion of] MSDB to be at least as large as

    -- the MODEL database

    SELECT @model_db_size = (SUM(size) * @page_size)

    FROM model.dbo.sysfiles

    IF (@model_db_size > 3072) -- 3 is the minimum required size for MSDB (in megabytes)

    SELECT @msdb_db_size = @model_db_size

    ELSE

    SELECT @msdb_db_size = 3072

    SELECT @device_directory = SUBSTRING(phyname, 1, CHARINDEX(N'master.mdf', LOWER(phyname)) - 1)

    FROM master.dbo.sysdevices

    WHERE (name = N'master')

    -- Drop any existing MSDBData / MSDBLog file(s)

    EXECUTE(N'EXECUTE master.dbo.xp_cmdshell N''DEL ' + @device_directory + N'MSDBData.mdf'', no_output')

    EXECUTE(N'EXECUTE master.dbo.xp_cmdshell N''DEL ' + @device_directory + N'MSDBLog.ldf'', no_output')

    -- Create the database

    PRINT ''

    PRINT 'Creating MSDB database...'

    SELECT @sz_msdb_db_size = RTRIM(LTRIM(CONVERT(VARCHAR, @msdb_db_size)))

    EXECUTE (N'CREATE DATABASE msdb ON (NAME = N''MSDBData'', FILENAME = N''' + @device_directory + N'MSDBData.mdf'', SIZE = ' + @sz_msdb_db_size + N'KB, MAXSIZE = UNLIMITED, FILEGROWTH = 256KB)

    LOG ON (NAME = N''MSDBLog'', FILENAME = N''' + @device_directory + N'MSDBLog.ldf'', SIZE = 512KB, MAXSIZE = UNLIMITED, FILEGROWTH = 256KB)')

    PRINT ''

    END

    ELSE

    BEGIN

    PRINT 'Checking the size of MSDB...'

    DBCC UPDATEUSAGE(N'msdb') WITH NO_INFOMSGS

    -- Make sure that MSDBLog has unlimited growth

    ALTER DATABASE msdb MODIFY FILE (NAME = N'MSDBLog', MAXSIZE = UNLIMITED)

    -- Determine amount of free space in msdb. We need at least 2MB free.

    SELECT @free_db_space = ((((SELECT SUM(size)

    FROM msdb.dbo.sysfiles

    WHERE status & 0x8040 = 0) -

    (SELECT SUM(reserved)

    FROM msdb.dbo.sysindexes

    WHERE indid IN (0, 1, 255))) * @page_size) / 1024.0)

    IF (@free_db_space < 2)

    BEGIN

    DECLARE @logical_file_name sysname

    DECLARE @os_file_name NVARCHAR(255)

    DECLARE @size_as_char VARCHAR(10)

    SELECT @logical_file_name = name,

    @os_file_name = phyname,

    @size_as_char = CONVERT(VARCHAR(10), ((high + 1) / 4) + 2048)

    FROM master.dbo.sysdevices

    WHERE (name = N'MSDBData')

    PRINT 'Attempting to expand the msdb database...'

    EXECUTE (N'ALTER DATABASE msdb MODIFY FILE (NAME = N''' + @logical_file_name + N''',

    FILENAME = N''' + @os_file_name + N''',

    SIZE = @size_as_char)')

    IF (@@error <> 0)

    RAISERROR('Unable to expand the msdb database. INSTMSDB.SQL terminating.', 20, 127) WITH LOG

    END

    PRINT ''

    END

    go

    EXECUTE sp_dboption msdb, N'trunc. log on chkpt.', TRUE

    go

    USE msdb

    go

    -- Check that we're in msdb

    IF (DB_NAME() <> N'msdb')

    RAISERROR('A problem was encountered accessing msdb. INSTMSDB.SQL terminating.', 20, 127) WITH LOG

    go

    -- Add the guest user

    IF (NOT EXISTS (SELECT *

    FROM msdb.dbo.sysusers

    WHERE (name = N'guest')

    AND (hasdbaccess = 1)))

    BEGIN

    PRINT ''

    EXECUTE sp_adduser N'guest'

    END

    go

    DUMP TRANSACTION msdb WITH NO_LOG

    go

    CHECKPOINT

    go

    /**************************************************************/

    /* */

    /* U P G R A D E S */

    /* */

    /**************************************************************/

    /**************************************************************/

    -- If not on Windows 9x, use LSA instead of Registry to store

    -- confidential information

    /**************************************************************/

    DECLARE @os int

    EXECUTE master.dbo.xp_MSplatform @os OUTPUT

    IF (@OS <> 2)

    BEGIN

    PRINT 'Update SQL Agent Registry Settings'

    DECLARE @host_login_name sysname

    DECLARE @host_login_password VARBINARY(512)

    -- HostLoginID

    EXECUTE master.dbo.xp_instance_regread N'HKEY_LOCAL_MACHINE',

    N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',

    N'HostLoginID',

    @host_login_name OUTPUT,

    N'no_output'

    IF (@host_login_name IS NULL) SELECT @host_login_name = N'sa'

    EXECUTE master.dbo.xp_sqlagent_param 1,

    N'HostLoginID',

    @host_login_name

    EXECUTE master.dbo.xp_instance_regwrite

    N'HKEY_LOCAL_MACHINE',

    N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',

    N'HostLoginID',

    N'REG_SZ',

    N''

    EXECUTE master.dbo.xp_instance_regdeletevalue

    N'HKEY_LOCAL_MACHINE',

    N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',

    N'HostLoginID'

    -- HostPassword

    EXECUTE master.dbo.xp_instance_regread N'HKEY_LOCAL_MACHINE',

    N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',

    N'HostPassword',

    @host_login_password OUTPUT,

    N'no_output'

    EXECUTE master.dbo.xp_sqlagent_param 1,

    N'HostPassword',

    @host_login_password

    EXECUTE master.dbo.xp_instance_regwrite

    N'HKEY_LOCAL_MACHINE',

    N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',

    N'HostPassword',

    N'REG_BINARY',

    N''

    EXECUTE master.dbo.xp_instance_regdeletevalue

    N'HKEY_LOCAL_MACHINE',

    N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',

    N'HostPassword'

    END -- If not Windows 9x, use LSA instead of Registry

    /**************************************************************/

    go

    /**************************************************************/

    -- Upgrade the SQLAgent table to no longer use "(local)"

    -- but always use the server name or server\instance name

    /**************************************************************/

    IF EXISTS (SELECT * FROM msdb.dbo.sysobjects WHERE name = N'sysjobs' and type = 'U')

    BEGIN

    PRINT ''

    PRINT 'Update sysjobs'

    UPDATE msdb.dbo.sysjobs

    SET originating_server = CONVERT(NVARCHAR(30), SERVERPROPERTY('servername'))

    WHERE UPPER(originating_server) = '(LOCAL)'

    END

    IF EXISTS (SELECT * FROM msdb.dbo.sysobjects WHERE name = N'sysjobhistory' and type = 'U')

    BEGIN

    PRINT ''

    PRINT 'Update sysjobhistory'

    UPDATE msdb.dbo.sysjobhistory

    SET server = CONVERT(NVARCHAR(30), SERVERPROPERTY('servername'))

    WHERE UPPER(server) = '(LOCAL)'

    END

    /**************************************************************/

    go

    /**************************************************************/

    /* */

    /* T A B L E D R O P S */

    /* */

    /**************************************************************/

    SET NOCOUNT ON

    DECLARE @build_number INT

    DECLARE @rebuild_needed TINYINT

    SELECT @build_number = @@microsoftversion & 0xffff

    IF (@build_number <= 0) -- The last build that we changed the schema in

    SELECT @rebuild_needed = 1

    ELSE

    SELECT @rebuild_needed = 0

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = N'sqlagent_info')

    AND (type = 'U')

    AND (@rebuild_needed = 1)))

    BEGIN

    PRINT ''

    PRINT 'Dropping table sqlagent_info...'

    DROP TABLE dbo.sqlagent_info

    END

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = N'sysdownloadlist')

    AND (type = 'U')

    AND (@rebuild_needed = 1)))

    BEGIN

    PRINT ''

    PRINT 'Dropping table sysdownloadlist...'

    IF (EXISTS (SELECT *

    FROM msdb.dbo.syscolumns

    WHERE (id = OBJECT_ID(N'sysdownloadlist'))

    AND (name = N'error_message')

    AND (cdefault <> 0)))

    EXECUTE sp_unbindefault N'sysdownloadlist.error_message'

    IF (EXISTS (SELECT *

    FROM msdb.dbo.syscolumns

    WHERE (id = OBJECT_ID(N'sysdownloadlist'))

    AND (name = N'date_posted')

    AND (cdefault <> 0)))

    EXECUTE sp_unbindefault N'sysdownloadlist.date_posted'

    IF (EXISTS (SELECT *

    FROM msdb.dbo.syscolumns

    WHERE (id = OBJECT_ID(N'sysdownloadlist'))

    AND (name = N'status')

    AND (cdefault <> 0)))

    EXECUTE sp_unbindefault N'sysdownloadlist.status'

    DROP TABLE dbo.sysdownloadlist

    END

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = N'sysjobhistory')

    AND (type = 'U')

    AND (@rebuild_needed = 1)))

    BEGIN

    PRINT ''

    PRINT 'Dropping table sysjobhistory...'

    DROP TABLE dbo.sysjobhistory

    END

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = N'sysjobservers')

    AND (type = 'U')

    AND (@rebuild_needed = 1)))

    BEGIN

    PRINT ''

    PRINT 'Dropping table sysjobservers...'

    DROP TABLE dbo.sysjobservers

    END

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = N'sysjobs')

    AND (type = 'U')

    AND (@rebuild_needed = 1)))

    BEGIN

    PRINT ''

    PRINT 'Dropping table sysjobs...'

    DROP TABLE dbo.sysjobs

    END

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = N'sysjobsteps')

    AND (type = 'U')

    AND (@rebuild_needed = 1)))

    BEGIN

    PRINT ''

    PRINT 'Dropping table sysjobsteps...'

    DROP TABLE dbo.sysjobsteps

    END

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = N'sysjobschedules')

    AND (type = 'U')

    AND (@rebuild_needed = 1)))

    BEGIN

    PRINT ''

    PRINT 'Dropping table sysjobschedules...'

    IF (EXISTS (SELECT *

    FROM msdb.dbo.syscolumns

    WHERE (id = OBJECT_ID(N'sysjobschedules'))

    AND (name = N'date_created')

    AND (cdefault <> 0)))

    EXECUTE sp_unbindefault N'sysjobschedules.date_created'

    DROP TABLE dbo.sysjobschedules

    END

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = N'syscategories')

    AND (type = 'U')

    AND (@rebuild_needed = 1)))

    BEGIN

    PRINT ''

    PRINT 'Dropping table syscategories...'

    DROP TABLE dbo.syscategories

    END

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = N'systargetservers')

    AND (type = 'U')

    AND (@rebuild_needed = 1)))

    BEGIN

    PRINT ''

    PRINT 'Dropping table systargetservers...'

    IF (EXISTS (SELECT *

    FROM msdb.dbo.syscolumns

    WHERE (id = OBJECT_ID(N'systargetservers'))

    AND (name = N'enlist_date')

    AND (cdefault <> 0)))

    EXECUTE sp_unbindefault N'systargetservers.enlist_date'

    IF (EXISTS (SELECT *

    FROM msdb.dbo.syscolumns

    WHERE (id = OBJECT_ID(N'systargetservers'))

    AND (name = N'last_poll_date')

    AND (cdefault <> 0)))

    EXECUTE sp_unbindefault N'systargetservers.last_poll_date'

    IF (EXISTS (SELECT *

    FROM msdb.dbo.syscolumns

    WHERE (id = OBJECT_ID(N'systargetservers'))

    AND (name = N'status')

    AND (cdefault <> 0)))

    EXECUTE sp_unbindefault N'systargetservers.status'

    DROP TABLE dbo.systargetservers

    END

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = N'systargetservergroups')

    AND (type = 'U')

    AND (@rebuild_needed = 1)))

    BEGIN

    PRINT ''

    PRINT 'Dropping table systargetservergroups...'

    DROP TABLE dbo.systargetservergroups

    END

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = N'systargetservergroupmembers')

    AND (type = 'U')

    AND (@rebuild_needed = 1)))

    BEGIN

    PRINT ''

    PRINT 'Dropping table systargetservergroupmembers...'

    DROP TABLE dbo.systargetservergroupmembers

    END

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = N'systaskids')

    AND (type = 'U')

    AND (@rebuild_needed = 1)))

    BEGIN

    PRINT ''

    PRINT 'Dropping table systaskids...'

    DROP TABLE dbo.systaskids

    END

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = N'sysalerts')

    AND (type = 'U')

    AND (@rebuild_needed = 1)))

    BEGIN

    PRINT ''

    PRINT 'Dropping table sysalerts...'

    DROP TABLE dbo.sysalerts

    END

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = N'sysoperators')

    AND (type = 'U')

    AND (@rebuild_needed = 1)))

    BEGIN

    PRINT ''

    PRINT 'Dropping table sysoperators...'

    DROP TABLE dbo.sysoperators

    END

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = N'sysnotifications')

    AND (type = 'U')

    AND (@rebuild_needed = 1)))

    BEGIN

    PRINT ''

    PRINT 'Dropping table sysnotifications...'

    DROP TABLE dbo.sysnotifications

    END

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = N'sysdbmaintplan_jobs')

    AND (type = 'U')

    AND (@rebuild_needed = 1)))

    BEGIN

    PRINT ''

    PRINT 'Dropping table sysdbmaintplan_jobs...'

    DROP TABLE sysdbmaintplan_jobs

    END

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = N'sysdbmaintplan_databases')

    AND (type = 'U')

    AND (@rebuild_needed = 1)))

    BEGIN

    PRINT ''

    PRINT 'Dropping table sysdbmaintplan_databases...'

    DROP TABLE sysdbmaintplan_databases

    END

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = N'sysdbmaintplan_history')

    AND (type = 'U')

    AND (@rebuild_needed = 1)))

    BEGIN

    PRINT ''

    PRINT 'Dropping table sysdbmaintplan_history...'

    DROP TABLE sysdbmaintplan_history

    END

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = N'sysdbmaintplans')

    AND (type = 'U')

    AND (@rebuild_needed = 1)))

    BEGIN

    PRINT ''

    PRINT 'Dropping table sysdbmaintplans...'

    DROP TABLE sysdbmaintplans

    END

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = N'syscachedcredentials')

    AND (type = 'U')

    AND (@rebuild_needed = 1)))

    BEGIN

    PRINT ''

    PRINT 'Dropping table syscachedcredentials...'

    DROP TABLE syscachedcredentials

    END

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = N'default_sdl_error_message')

    AND (type = 'D')

    AND (@rebuild_needed = 1)))

    DROP DEFAULT default_sdl_error_message

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = N'default_current_date')

    AND (type = 'D')

    AND (@rebuild_needed = 1)))

    DROP DEFAULT default_current_date

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = N'default_zero')

    AND (type = 'D')

    AND (@rebuild_needed = 1)))

    DROP DEFAULT default_zero

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = N'default_one')

    AND (type = 'D')

    AND (@rebuild_needed = 1)))

    DROP DEFAULT default_one

    go

    DUMP TRANSACTION msdb WITH NO_LOG

    go

    CHECKPOINT

    go

    /**************************************************************/

    /* */

    /* D E F A U L T S */

    /* */

    /**************************************************************/

    IF (NOT EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = N'default_sdl_error_message')

    AND (type = 'D')))

    EXECUTE('CREATE DEFAULT default_sdl_error_message AS NULL')

    go

    IF (NOT EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = N'default_current_date')

    AND (type = 'D')))

    EXECUTE('CREATE DEFAULT default_current_date AS GETDATE()')

    go

    IF (NOT EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = N'default_zero')

    AND (type = 'D')))

    EXECUTE('CREATE DEFAULT default_zero AS 0')

    go

    IF (NOT EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = N'default_one')

    AND (type = 'D')))

    EXECUTE('CREATE DEFAULT default_one AS 1')

    go

    /**************************************************************/

    /* */

    /* T A B L E S */

    /* */

    /**************************************************************/

    /**************************************************************/

    /* SQLAGENT_INFO */

    /**************************************************************/

    IF (NOT EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = N'sqlagent_info')

    AND (type = 'U')))

    BEGIN

    PRINT ''

    PRINT 'Creating table sqlagent_info...'

    CREATE TABLE sqlagent_info

    (

    attribute sysname NOT NULL,

    value NVARCHAR(512) NOT NULL

    )

    END

    go

    /**************************************************************/

    /* SYSDOWNLOADLIST */

    /**************************************************************/

    IF (NOT EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = N'sysdownloadlist')

    AND (type = 'U')))

    BEGIN

    PRINT ''

    PRINT 'Creating table sysdownloadlist...'

    CREATE TABLE sysdownloadlist

    (

    instance_id INT IDENTITY NOT NULL,

    source_server NVARCHAR(30) NOT NULL,

    operation_code TINYINT NOT NULL,

    object_type TINYINT NOT NULL,

    object_id UNIQUEIDENTIFIER NOT NULL,

    target_server NVARCHAR(30) NOT NULL,

    error_message NVARCHAR(1024) NULL,

    date_posted DATETIME NOT NULL,

    date_downloaded DATETIME NULL,

    status TINYINT NOT NULL,

    deleted_object_name sysname NULL

    )

    EXECUTE sp_bindefault default_sdl_error_message, N'sysdownloadlist.error_message'

    EXECUTE sp_bindefault default_current_date, N'sysdownloadlist.date_posted'

    EXECUTE sp_bindefault default_zero, N'sysdownloadlist.status'

    CREATE UNIQUE CLUSTERED INDEX clust ON sysdownloadlist(instance_id)

    CREATE NONCLUSTERED INDEX nc1 ON sysdownloadlist(target_server)

    CREATE NONCLUSTERED INDEX nc2 ON sysdownloadlist(object_id)

    END

    go

    /**************************************************************/

    /* SYSJOBHISTORY */

    /**************************************************************/

    IF (NOT EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = N'sysjobhistory')

    AND (type = 'U')))

    BEGIN

    PRINT ''

    PRINT 'Creating table sysjobhistory...'

    CREATE TABLE sysjobhistory

    (

    instance_id INT IDENTITY NOT NULL,

    job_id UNIQUEIDENTIFIER NOT NULL,

    step_id INT NOT NULL,

    step_name sysname NOT NULL,

    sql_message_id INT NOT NULL,

    sql_severity INT NOT NULL,

    message NVARCHAR(1024) NULL,

    run_status INT NOT NULL,

    run_date INT NOT NULL,

    run_time INT NOT NULL,

    run_duration INT NOT NULL,

    operator_id_emailed INT NOT NULL,

    operator_id_netsent INT NOT NULL,

    operator_id_paged INT NOT NULL,

    retries_attempted INT NOT NULL,

    server NVARCHAR(30) NOT NULL

    )

    CREATE UNIQUE CLUSTERED INDEX clust ON sysjobhistory(instance_id)

    CREATE NONCLUSTERED INDEX nc1 ON sysjobhistory(job_id)

    END

    go

    /**************************************************************/

    /* SYSJOBS */

    /**************************************************************/

    IF (NOT EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = N'sysjobs')

    AND (type = 'U')))

    BEGIN

    PRINT ''

    PRINT 'Creating table sysjobs...'

    CREATE TABLE sysjobs

    (

    job_id UNIQUEIDENTIFIER NOT NULL,

    originating_server NVARCHAR(30) NOT NULL,

    name sysname NOT NULL,

    enabled TINYINT NOT NULL,

    description NVARCHAR(512) NULL,

    start_step_id INT NOT NULL,

    category_id INT NOT NULL,

    owner_sid VARBINARY(85) NOT NULL,

    notify_level_eventlog INT NOT NULL,

    notify_level_email INT NOT NULL,

    notify_level_netsend INT NOT NULL,

    notify_level_page INT NOT NULL,

    notify_email_operator_id INT NOT NULL,

    notify_netsend_operator_id INT NOT NULL,

    notify_page_operator_id INT NOT NULL,

    delete_level INT NOT NULL,

    date_created DATETIME NOT NULL,

    date_modified DATETIME NOT NULL,

    version_number INT NOT NULL

    )

    CREATE UNIQUE CLUSTERED INDEX clust ON sysjobs(job_id)

    CREATE NONCLUSTERED INDEX nc1 ON sysjobs(name) -- NOTE: This is deliberately non-unique

    CREATE NONCLUSTERED INDEX nc2 ON sysjobs(originating_server)

    CREATE NONCLUSTERED INDEX nc3 ON sysjobs(category_id)

    CREATE NONCLUSTERED INDEX nc4 ON sysjobs(owner_sid)

    END

    go

    /**************************************************************/

    /* SYSJOBS_VIEW */

    /**************************************************************/

    PRINT ''

    PRINT 'Creating view sysjobs_view...'

    go

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = N'sysjobs_view')

    AND (type = 'V')))

    DROP VIEW sysjobs_view

    go

    CREATE VIEW sysjobs_view

    AS

    SELECT *

    FROM msdb.dbo.sysjobs

    WHERE (owner_sid = SUSER_SID())

    OR (ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) = 1)

    OR (ISNULL(IS_MEMBER(N'TargetServersRole'), 0) = 1)

    go

    /**************************************************************/

    /* SYSJOBSERVERS */

    /**************************************************************/

    IF (NOT EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = N'sysjobservers')

    AND (type = 'U')))

    BEGIN

    PRINT ''

    PRINT 'Creating table sysjobservers...'

    CREATE TABLE sysjobservers

    (

    job_id UNIQUEIDENTIFIER NOT NULL,

    server_id INT NOT NULL,

    last_run_outcome TINYINT NOT NULL,

    last_outcome_message NVARCHAR(1024) NULL,

    last_run_date INT NOT NULL,

    last_run_time INT NOT NULL,

    last_run_duration INT NOT NULL

    )

    CREATE CLUSTERED INDEX clust ON sysjobservers(job_id)

    CREATE NONCLUSTERED INDEX nc1 ON sysjobservers(server_id)

    END

    go

    /**************************************************************/

    /* SYSJOBSTEPS */

    /**************************************************************/

    IF (NOT EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = N'sysjobsteps')

    AND (type = 'U')))

    BEGIN

    PRINT ''

    PRINT 'Creating table sysjobsteps...'

    CREATE TABLE sysjobsteps

    (

    job_id UNIQUEIDENTIFIER NOT NULL,

    step_id INT NOT NULL,

    step_name sysname NOT NULL,

    subsystem NVARCHAR(40) NOT NULL,

    command NVARCHAR(3200) NULL, -- NOTE: 3.125K since unicode requires 2x space

    flags INT NOT NULL,

    additional_parameters NTEXT NULL,

    cmdexec_success_code INT NOT NULL,

    on_success_action TINYINT NOT NULL,

    on_success_step_id INT NOT NULL,

    on_fail_action TINYINT NOT NULL,

    on_fail_step_id INT NOT NULL,

    server sysname NULL, -- Used only by replication

    database_name sysname NULL,

    database_user_name sysname NULL,

    retry_attempts INT NOT NULL,

    retry_interval INT NOT NULL,

    os_run_priority INT NOT NULL, -- NOTE: Cannot use TINYINT because we need a signed number

    output_file_name NVARCHAR(200) NULL,

    last_run_outcome INT NOT NULL,

    last_run_duration INT NOT NULL,

    last_run_retries INT NOT NULL,

    last_run_date INT NOT NULL,

    last_run_time INT NOT NULL

    )

    CREATE UNIQUE CLUSTERED INDEX clust ON sysjobsteps(job_id, step_id)

    CREATE UNIQUE NONCLUSTERED INDEX nc1 ON sysjobsteps(job_id, step_name)

    END

    go

    /**************************************************************/

    /* SYSJOBSCHEDULES */

    /**************************************************************/

    IF (NOT EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = N'sysjobschedules')

    AND (type = 'U')))

    BEGIN

    PRINT ''

    PRINT 'Creating table sysjobschedules...'

    CREATE TABLE sysjobschedules

    (

    schedule_id INT IDENTITY NOT NULL,

    job_id UNIQUEIDENTIFIER NOT NULL,

    name sysname NOT NULL,

    enabled INT NOT NULL,

    freq_type INT NOT NULL,

    freq_interval INT NOT NULL,

    freq_subday_type INT NOT NULL,

    freq_subday_interval INT NOT NULL,

    freq_relative_interval INT NOT NULL,

    freq_recurrence_factor INT NOT NULL,

    active_start_date INT NOT NULL,

    active_end_date INT NOT NULL,

    active_start_time INT NOT NULL,

    active_end_time INT NOT NULL,

    next_run_date INT NOT NULL,

    next_run_time INT NOT NULL,

    date_created DATETIME NOT NULL

    )

    EXECUTE sp_bindefault default_current_date, N'sysjobschedules.date_created'

    CREATE UNIQUE CLUSTERED INDEX clust ON sysjobschedules(job_id, name)

    CREATE UNIQUE NONCLUSTERED INDEX nc1 ON sysjobschedules(schedule_id)

    END

    go

    /**************************************************************/

    /* SYSCATEGORIES */

    /**************************************************************/

    IF (NOT EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = N'syscategories')

    AND (type = 'U')))

    BEGIN

    PRINT ''

    PRINT 'Creating table syscategories...'

    CREATE TABLE syscategories

    (

    category_id INT IDENTITY NOT NULL,

    category_class INT NOT NULL, -- 1 = Job, 2 = Alert, 3 = Operator

    category_type TINYINT NOT NULL, -- 1 = Local, 2 = Multi-Server [Only relevant if class is 1; otherwise, 3 (None)]

    name sysname NOT NULL

    )

    CREATE UNIQUE CLUSTERED INDEX clust ON syscategories(name, category_class)

    END

    go

    -- Install standard [permanent] categories (reserved ID range is 0 - 99)

    SET IDENTITY_INSERT msdb.dbo.syscategories ON

    DELETE FROM msdb.dbo.syscategories

    WHERE (category_id < 100)

    -- Core categories

    INSERT INTO msdb.dbo.syscategories (category_id, category_class, category_type, name) VALUES ( 0, 1, 1, N'[Uncategorized (Local)]') -- Local default

    INSERT INTO msdb.dbo.syscategories (category_id, category_class, category_type, name) VALUES ( 1, 1, 1, N'Jobs from MSX') -- All jobs downloaded from the MSX are placed in this category

    INSERT INTO msdb.dbo.syscategories (category_id, category_class, category_type, name) VALUES ( 2, 1, 2, N'[Uncategorized (Multi-Server)]') -- Multi-server default

    INSERT INTO msdb.dbo.syscategories (category_id, category_class, category_type, name) VALUES ( 3, 1, 1, N'Database Maintenance') -- Default for all jobs created by the Maintenance Plan Wizard

    INSERT INTO msdb.dbo.syscategories (category_id, category_class, category_type, name) VALUES ( 4, 1, 1, N'Web Assistant') -- Default for all jobs created by the Web Assistant

    INSERT INTO msdb.dbo.syscategories (category_id, category_class, category_type, name) VALUES ( 5, 1, 1, N'Full-Text') -- Default for all jobs created by the Index Server

    INSERT INTO msdb.dbo.syscategories (category_id, category_class, category_type, name) VALUES (98, 2, 3, N'[Uncategorized]') -- Alert default

    INSERT INTO msdb.dbo.syscategories (category_id, category_class, category_type, name) VALUES (99, 3, 3, N'[Uncategorized]') -- Operator default

    -- Replication categories

    INSERT INTO msdb.dbo.syscategories (category_id, category_class, category_type, name) VALUES (10, 1, 1, N'REPL-Distribution')

    INSERT INTO msdb.dbo.syscategories (category_id, category_class, category_type, name) VALUES (11, 1, 1, N'REPL-Distribution Cleanup')

    INSERT INTO msdb.dbo.syscategories (category_id, category_class, category_type, name) VALUES (12, 1, 1, N'REPL-History Cleanup')

    INSERT INTO msdb.dbo.syscategories (category_id, category_class, category_type, name) VALUES (13, 1, 1, N'REPL-LogReader')

    INSERT INTO msdb.dbo.syscategories (category_id, category_class, category_type, name) VALUES (14, 1, 1, N'REPL-Merge')

    INSERT INTO msdb.dbo.syscategories (category_id, category_class, category_type, name) VALUES (15, 1, 1, N'REPL-Snapshot')

    INSERT INTO msdb.dbo.syscategories (category_id, category_class, category_type, name) VALUES (16, 1, 1, N'REPL-Checkup')

    INSERT INTO msdb.dbo.syscategories (category_id, category_class, category_type, name) VALUES (17, 1, 1, N'REPL-Subscription Cleanup')

    INSERT INTO msdb.dbo.syscategories (category_id, category_class, category_type, name) VALUES (18, 1, 1, N'REPL-Alert Response')

    INSERT INTO msdb.dbo.syscategories (category_id, category_class, category_type, name) VALUES (19, 1, 1, N'REPL-QueueReader')

    INSERT INTO msdb.dbo.syscategories (category_id, category_class, category_type, name) VALUES (20, 2, 3, N'Replication')

    SET IDENTITY_INSERT msdb.dbo.syscategories OFF

    go

    /**************************************************************/

    /* SYSTARGETSERVERS */

    /**************************************************************/

    IF (NOT EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = N'systargetservers')

    AND (type = 'U')))

    BEGIN

    PRINT ''

    PRINT 'Creating table systargetservers...'

    CREATE TABLE systargetservers

    (

    server_id INT IDENTITY NOT NULL,

    server_name NVARCHAR(30) NOT NULL,

    location NVARCHAR(200) NULL,

    time_zone_adjustment INT NOT NULL, -- The offset from GMT in minutes (set by sp_msx_enlist)

    enlist_date DATETIME NOT NULL,

    last_poll_date DATETIME NOT NULL,

    status INT NOT NULL, -- 1 = Normal, 2 = Offline, 4 = Blocked

    local_time_at_last_poll DATETIME NOT NULL, -- The local time at the target server as-of the last time it polled the MSX

    enlisted_by_nt_user NVARCHAR(100) NOT NULL,

    poll_interval INT NOT NULL -- The MSX polling interval (in seconds)

    )

    EXECUTE sp_bindefault default_current_date, N'systargetservers.enlist_date'

    EXECUTE sp_bindefault default_current_date, N'systargetservers.last_poll_date'

    EXECUTE sp_bindefault default_one, N'systargetservers.status'

    CREATE UNIQUE CLUSTERED INDEX clust ON systargetservers(server_id)

    CREATE UNIQUE NONCLUSTERED INDEX nc1 ON systargetservers(server_name)

    END

    go

    /**************************************************************/

    /* SYSTARGETSERVERS_VIEW */

    /**************************************************************/

    PRINT ''

    PRINT 'Creating view systargetservers_view...'

    go

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = N'systargetservers_view')

    AND (type = 'V')))

    DROP VIEW systargetservers_view

    go

    CREATE VIEW systargetservers_view

    AS

    SELECT server_id,

    server_name,

    enlist_date,

    last_poll_date

    FROM msdb.dbo.systargetservers

    UNION

    SELECT 0,

    CONVERT(NVARCHAR(30), SERVERPROPERTY('ServerName')),

    CONVERT(DATETIME, N'19981113', 112),

    CONVERT(DATETIME, N'19981113', 112)

    go

    /**************************************************************/

    /* SYSTARGETSERVERGROUPS */

    /**************************************************************/

    IF (NOT EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = N'systargetservergroups')

    AND (type = 'U')))

    BEGIN

    PRINT ''

    PRINT 'Creating table systargetservergroups...'

    CREATE TABLE systargetservergroups

    (

    servergroup_id INT IDENTITY NOT NULL,

    name sysname NOT NULL

    )

    CREATE UNIQUE CLUSTERED INDEX clust ON systargetservergroups(name)

    END

    go

    /**************************************************************/

    /* SYSTARGETSERVERGROUPMEMBERS */

    /**************************************************************/

    IF (NOT EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = N'systargetservergroupmembers')

    AND (type = 'U')))

    BEGIN

    PRINT ''

    PRINT 'Creating table systargetservergroupmembers...'

    CREATE TABLE systargetservergroupmembers

    (

    servergroup_id INT NOT NULL,

    server_id INT NOT NULL

    )

    CREATE UNIQUE CLUSTERED INDEX clust ON systargetservergroupmembers(servergroup_id, server_id)

    CREATE NONCLUSTERED INDEX nc1 ON systargetservergroupmembers(server_id)

    END

    go

    /**************************************************************/

    /* SYSALERTS */

    /**************************************************************/

    IF (NOT EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = N'sysalerts')

    AND (type = 'U')))

    BEGIN

    PRINT ''

    PRINT 'Creating table sysalerts...'

    CREATE TABLE sysalerts

    (

    id INT IDENTITY NOT NULL,

    name sysname NOT NULL, -- Was length 60 in 6.x

    event_source NVARCHAR(100) NOT NULL,

    event_category_id INT NULL,

    event_id INT NULL,

    message_id INT NOT NULL, -- Was NULL in 6.x

    severity INT NOT NULL, -- Was NULL in 6.x

    enabled TINYINT NOT NULL,

    delay_between_responses INT NOT NULL,

    last_occurrence_date INT NOT NULL, -- Was NULL in 6.x

    last_occurrence_time INT NOT NULL, -- Was NULL in 6.x

    last_response_date INT NOT NULL, -- Was NULL in 6.x

    last_response_time INT NOT NULL, -- Was NULL in 6.x

    notification_message NVARCHAR(512) NULL,

    include_event_description TINYINT NOT NULL,

    database_name sysname NULL,

    event_description_keyword NVARCHAR(100) NULL,

    occurrence_count INT NOT NULL,

    count_reset_date INT NOT NULL, -- Was NULL in 6.x

    count_reset_time INT NOT NULL, -- Was NULL in 6.x

    job_id UNIQUEIDENTIFIER NOT NULL, -- Was NULL in 6.x

    has_notification INT NOT NULL, -- New for 7.0

    flags INT NOT NULL, -- Was NULL in 6.x

    performance_condition NVARCHAR(512) NULL,

    category_id INT NOT NULL -- New for 7.0

    )

    CREATE UNIQUE CLUSTERED INDEX ByName ON sysalerts(name)

    CREATE UNIQUE INDEX ByID ON sysalerts(id)

    END

    go

    /**************************************************************/

    /* SYSOPERATORS */

    /**************************************************************/

    IF (NOT EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = N'sysoperators')

    AND (type = 'U')))

    BEGIN

    PRINT ''

    PRINT 'Creating table sysoperators...'

    CREATE TABLE sysoperators

    (

    id INT IDENTITY NOT NULL,

    name sysname NOT NULL, -- Was length 50 in 6.x

    enabled TINYINT NOT NULL,

    email_address NVARCHAR(100) NULL,

    last_email_date INT NOT NULL, -- Was NULL in 6.x

    last_email_time INT NOT NULL, -- Was NULL in 6.x

    pager_address NVARCHAR(100) NULL,

    last_pager_date INT NOT NULL, -- Was NULL in 6.x

    last_pager_time INT NOT NULL, -- Was NULL in 6.x

    weekday_pager_start_time INT NOT NULL,

    weekday_pager_end_time INT NOT NULL,

    saturday_pager_start_time INT NOT NULL,

    saturday_pager_end_time INT NOT NULL,

    sunday_pager_start_time INT NOT NULL,

    sunday_pager_end_time INT NOT NULL,

    pager_days TINYINT NOT NULL,

    netsend_address NVARCHAR(100) NULL, -- New for 7.0

    last_netsend_date INT NOT NULL, -- New for 7.0

    last_netsend_time INT NOT NULL, -- New for 7.0

    category_id INT NOT NULL -- New for 7.0

    )

    CREATE UNIQUE CLUSTERED INDEX ByName ON sysoperators(name)

    CREATE UNIQUE INDEX ByID ON sysoperators(id)

    END

    go

    /**************************************************************/

    /* SYSNOTIFICATIONS */

    /**************************************************************/

    IF (NOT EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = N'sysnotifications')

    AND (type = 'U')))

    BEGIN

    PRINT ''

    PRINT 'Creating table sysnotifications...'

    CREATE TABLE sysnotifications

    (

    alert_id INT NOT NULL,

    operator_id INT NOT NULL,

    notification_method TINYINT NOT NULL

    )

    CREATE UNIQUE CLUSTERED INDEX ByAlertIDAndOperatorID ON sysnotifications(alert_id, operator_id)

    END

    go

    /**************************************************************/

    /* SYSTASKIDS */

    /* */

    /* This table provides a mapping between new GUID job ID's */

    /* and 6.x INT task ID's. */

    /* Entries are made in this table for all existing 6.x tasks */

    /* and for all new tasks added using the 7.0 version of */

    /* sp_addtask. */

    /* Callers of the 7.0 version of sp_helptask will ONLY see */

    /* tasks [jobs] that have a corresponding entry in this table */

    /* [IE. Jobs created with sp_add_job will not be returned]. */

    /**************************************************************/

    IF (NOT EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = N'systaskids')

    AND (type = 'U')))

    BEGIN

    CREATE TABLE systaskids

    (

    task_id INT IDENTITY NOT NULL,

    job_id UNIQUEIDENTIFIER NOT NULL

    )

    CREATE CLUSTERED INDEX clust ON systaskids(job_id)

    END

    go

    /**************************************************************/

    /* SYSCACHEDCREDENTIALS */

    /* */

    /**************************************************************/

    IF (NOT EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = N'syscachedcredentials')

    AND (type = 'U')))

    BEGIN

    CREATE TABLE syscachedcredentials

    (

    login_name sysname COLLATE database_default NOT NULL PRIMARY KEY,

    has_server_access BIT NOT NULL DEFAULT 0,

    is_sysadmin_member BIT NOT NULL DEFAULT 0,

    cachedate DATETIME NOT NULL DEFAULT getdate()

    )

    END

    go

    DUMP TRANSACTION msdb WITH NO_LOG

    go

    CHECKPOINT

    go

    /**************************************************************/

    /* */

    /* C O R E P R O C E D U R E S */

    /* */

    /**************************************************************/

    /**************************************************************/

    /* SP_SQLAGENT_GET_STARTUP_INFO */

    /**************************************************************/

    PRINT ''

    PRINT 'Creating procedure sp_sqlagent_get_startup_info...'

    go

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = 'sp_sqlagent_get_startup_info')

    AND (type = 'P')))

    DROP PROCEDURE sp_sqlagent_get_startup_info

    go

    CREATE PROCEDURE sp_sqlagent_get_startup_info

    AS

    BEGIN

    DECLARE @tbu INT

    SET NOCOUNT ON

    IF (ServerProperty('InstanceName') IS NULL)

    BEGIN

    EXECUTE @tbu = master.dbo.xp_qv '1338198028'

    END

    ELSE

    BEGIN

    DECLARE @instancename NVARCHAR(128)

    SELECT @instancename = CONVERT(NVARCHAR(128), ServerProperty('InstanceName'))

    EXECUTE @tbu = master.dbo.xp_qv '1338198028', @instancename

    END

    IF (@tbu < 0)

    SELECT @tbu = 0

    SELECT 'msdb_70_compatible' = (SELECT CASE WHEN cmptlevel >= 70 THEN 1 ELSE 0 END FROM master.dbo.sysdatabases WHERE (name = 'msdb')),

    'msdb_read_only' = DATABASEPROPERTY('msdb', 'IsReadOnly'),

    'msdb_available' = CASE ISNULL(DATABASEPROPERTY('msdb', 'IsSingleUser'), 0) WHEN 0 THEN 1 ELSE 0 END &

    CASE ISNULL(DATABASEPROPERTY('msdb', 'IsDboOnly'), 0) WHEN 0 THEN 1 ELSE 0 END &

    CASE ISNULL(DATABASEPROPERTY('msdb', 'IsNotRecovered'), 0) WHEN 0 THEN 1 ELSE 0 END &

    CASE ISNULL(DATABASEPROPERTY('msdb', 'IsSuspect'), 0) WHEN 0 THEN 1 ELSE 0 END,

    'case_sensitive_server' = CASE ISNULL((SELECT 1 WHERE 'a' = 'A'), 0)

    WHEN 1 THEN 0

    ELSE 1

    END,

    'max_user_connection' = (SELECT value FROM master.dbo.syscurconfigs WHERE (config = 103)),

    'sql_server_name' = CONVERT(sysname, SERVERPROPERTY('SERVERNAME')),

    'tbu' = ISNULL(@tbu, 0),

    'platform' = PLATFORM(),

    'instance_name' = ISNULL(CONVERT(sysname, SERVERPROPERTY('INSTANCENAME')), 'MSSQLSERVER'),

    'is_clustered' = CONVERT(INT, SERVERPROPERTY('ISCLUSTERED'))

    RETURN(0) -- Success

    END

    go

    /**************************************************************/

    /* SP_SQLAGENT_HAS_SERVER_ACCESS */

    /**************************************************************/

    PRINT ''

    PRINT 'Creating procedure sp_sqlagent_has_server_access...'

    go

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = 'sp_sqlagent_has_server_access')

    AND (type = 'P')))

    DROP PROCEDURE sp_sqlagent_has_server_access

    go

    CREATE PROCEDURE sp_sqlagent_has_server_access

    @login_name sysname = NULL,

    @is_sysadmin_member INT = NULL OUTPUT

    AS

    BEGIN

    DECLARE @has_server_access BIT

    DECLARE @is_sysadmin BIT

    DECLARE @actual_login_name sysname

    DECLARE @cachedate DATETIME

    SET NOCOUNT ON

    SELECT @cachedate = NULL

    -- remove expired entries from the cache

    DELETE msdb.dbo.syscachedcredentials

    WHERE DATEDIFF(MINUTE, cachedate, GETDATE()) >= 29

    -- query the cache

    SELECT @is_sysadmin = is_sysadmin_member,

    @has_server_access = has_server_access,

    @cachedate = cachedate

    FROM msdb.dbo.syscachedcredentials

    WHERE login_name = @login_name

    AND DATEDIFF(MINUTE, cachedate, GETDATE()) < 29

    IF (@cachedate IS NOT NULL)

    BEGIN

    -- no output variable

    IF (@is_sysadmin_member IS NULL)

    BEGIN

    -- Return result row

    SELECT has_server_access = @has_server_access,

    is_sysadmin = @is_sysadmin,

    actual_login_name = @login_name

    RETURN

    END

    ELSE

    BEGIN

    SELECT @is_sysadmin_member = @is_sysadmin

    RETURN

    END

    END -- select from cache

    CREATE TABLE #xp_results

    (

    account_name sysname COLLATE database_default NOT NULL PRIMARY KEY,

    type NVARCHAR(10) COLLATE database_default NOT NULL,

    privilege NVARCHAR(10) COLLATE database_default NOT NULL,

    mapped_login_name sysname COLLATE database_default NOT NULL,

    permission_path sysname COLLATE database_default NULL

    )

    -- Set defaults

    SELECT @has_server_access = 0

    SELECT @is_sysadmin = 0

    SELECT @actual_login_name = FORMATMESSAGE(14205)

    IF (@login_name IS NULL)

    BEGIN

    SELECT has_server_access = 1,

    is_sysadmin = IS_SRVROLEMEMBER(N'sysadmin'),

    actual_login_name = SUSER_SNAME()

    RETURN

    END

    IF (@login_name LIKE '%\%')

    BEGIN

    -- Handle the LocalSystem account ('NT AUTHORITY\SYSTEM') as a special case

    IF (UPPER(@login_name) = N'NT AUTHORITY\SYSTEM')

    BEGIN

    IF (EXISTS (SELECT *

    FROM master.dbo.syslogins

    WHERE (UPPER(loginname) = N'BUILTIN\ADMINISTRATORS')))

    BEGIN

    SELECT @has_server_access = hasaccess,

    @is_sysadmin = sysadmin,

    @actual_login_name = loginname

    FROM master.dbo.syslogins

    WHERE (UPPER(loginname) = N'BUILTIN\ADMINISTRATORS')

    END

    END

    ELSE

    BEGIN

    -- Check if the NT login has been explicitly denied access

    IF (EXISTS (SELECT *

    FROM master.dbo.syslogins

    WHERE (loginname = @login_name)

    AND (denylogin = 1)))

    BEGIN

    SELECT @has_server_access = 0,

    @is_sysadmin = sysadmin,

    @actual_login_name = loginname

    FROM master.dbo.syslogins

    WHERE (loginname = @login_name)

    END

    ELSE

    BEGIN

    -- Call xp_logininfo to determine server access

    INSERT INTO #xp_results

    EXECUTE master.dbo.xp_logininfo @login_name

    SELECT @has_server_access = CASE COUNT(*)

    WHEN 0 THEN 0

    ELSE 1

    END

    FROM #xp_results

    SELECT @actual_login_name = mapped_login_name,

    @is_sysadmin = CASE UPPER(privilege)

    WHEN 'ADMIN' THEN 1

    ELSE 0

    END

    FROM #xp_results

    END

    END

    END

    ELSE

    BEGIN

    -- Standard login

    IF (EXISTS (SELECT *

    FROM master.dbo.syslogins

    WHERE (loginname = @login_name)))

    BEGIN

    SELECT @has_server_access = hasaccess,

    @is_sysadmin = sysadmin,

    @actual_login_name = loginname

    FROM master.dbo.syslogins

    WHERE (loginname = @login_name)

    END

    END

    -- update the cache only if something is found

    IF (UPPER(@actual_login_name) <> '(UNKNOWN)')

    BEGIN

    BEGIN TRAN

    IF EXISTS (SELECT * FROM msdb.dbo.syscachedcredentials WITH (TABLOCKX) WHERE login_name = @login_name)

    BEGIN

    UPDATE msdb.dbo.syscachedcredentials

    SET has_server_access = @has_server_access,

    is_sysadmin_member = @is_sysadmin,

    cachedate = GETDATE()

    WHERE login_name = @login_name

    END

    ELSE

    BEGIN

    INSERT INTO msdb.dbo.syscachedcredentials(login_name, has_server_access, is_sysadmin_member)

    VALUES(@login_name, @has_server_access, @is_sysadmin)

    END

    COMMIT TRAN

    END

    IF (@is_sysadmin_member IS NULL)

    -- Return result row

    SELECT has_server_access = @has_server_access,

    is_sysadmin = @is_sysadmin,

    actual_login_name = @actual_login_name

    ELSE

    -- output variable only

    SELECT @is_sysadmin_member = @is_sysadmin

    END

    go

    /**************************************************************/

    /* SP_SEM_ADD_MESSAGE [used by SEM only] */

    /**************************************************************/

    PRINT ''

    PRINT 'Creating procedure sp_sem_add_message...'

    go

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = 'sp_sem_add_message')

    AND (type = 'P')))

    DROP PROCEDURE sp_sem_add_message

    go

    CREATE PROCEDURE sp_sem_add_message

    @msgnum INT = NULL,

    @severity SMALLINT = NULL,

    @msgtext NVARCHAR(255) = NULL,

    @lang sysname = NULL, -- Message language name

    @with_log VARCHAR(5) = 'FALSE',

    @replace VARCHAR(7) = NULL

    AS

    BEGIN

    DECLARE @retval INT

    DECLARE @language_name sysname

    SET NOCOUNT ON

    SET ROWCOUNT 1

    SELECT @language_name = name

    FROM master.dbo.syslanguages

    WHERE msglangid = (SELECT number

    FROM master.dbo.spt_values

    WHERE (type = 'LNG')

    AND (name = @lang))

    SET ROWCOUNT 0

    SELECT @language_name = ISNULL(@language_name, 'us_english')

    EXECUTE @retval = master.dbo.sp_addmessage @msgnum, @severity, @msgtext, @language_name, @with_log, @replace

    RETURN(@retval)

    END

    go

    /**************************************************************/

    /* SP_SEM_DROP_MESSAGE [used by SEM only] */

    /**************************************************************/

    PRINT ''

    PRINT 'Creating procedure sp_sem_drop_message...'

    go

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = 'sp_sem_drop_message')

    AND (type = 'P')))

    DROP PROCEDURE sp_sem_drop_message

    go

    CREATE PROCEDURE sp_sem_drop_message

    @msgnum int = NULL,

    @lang sysname = NULL -- Message language name

    AS

    BEGIN

    DECLARE @retval INT

    DECLARE @language_name sysname

    SET NOCOUNT ON

    SET ROWCOUNT 1

    SELECT @language_name = name

    FROM master.dbo.syslanguages

    WHERE msglangid = (SELECT number

    FROM master.dbo.spt_values

    WHERE (type = 'LNG')

    AND (name = @lang))

    SET ROWCOUNT 0

    SELECT @language_name = ISNULL(@language_name, 'us_english')

    EXECUTE @retval = master.dbo.sp_dropmessage @msgnum, @language_name

    RETURN(@retval)

    END

    go

    /**************************************************************/

    /* SP_GET_MESSAGE_DESCRIPTION [used by SEM only] */

    /**************************************************************/

    PRINT ''

    PRINT 'Creating procedure sp_get_message_description...'

    go

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = 'sp_get_message_description')

    AND (type = 'P')))

    DROP PROCEDURE sp_get_message_description

    go

    CREATE PROCEDURE sp_get_message_description

    @error INT

    AS

    BEGIN

    IF EXISTS (SELECT * FROM master.dbo.sysmessages WHERE (error = @error) AND (msglangid = (SELECT msglangid FROM master.dbo.syslanguages WHERE (langid = @@langid))))

    SELECT description FROM master.dbo.sysmessages WHERE (error = @error) AND (msglangid = (SELECT msglangid FROM master.dbo.syslanguages WHERE (langid = @@langid)))

    ELSE

    SELECT description FROM master.dbo.sysmessages WHERE (error = @error) AND (msglangid = 1033)

    END

    go

    /**************************************************************/

    /* SP_SQLAGENT_GET_PERF_COUNTERS */

    /**************************************************************/

    PRINT ''

    PRINT 'Creating procedure sp_sqlagent_get_perf_counters...'

    go

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = N'sp_sqlagent_get_perf_counters')

    AND (type = 'P')))

    DROP PROCEDURE sp_sqlagent_get_perf_counters

    go

    CREATE PROCEDURE sp_sqlagent_get_perf_counters

    @all_counters BIT = 0

    AS

    BEGIN

    SET NOCOUNT ON

    CREATE TABLE #temp

    (

    performance_condition NVARCHAR(1024) COLLATE database_default NOT NULL

    )

    INSERT INTO #temp VALUES (N'dummy')

    IF (@all_counters = 0)

    BEGIN

    INSERT INTO #temp

    SELECT DISTINCT SUBSTRING(performance_condition, 1, CHARINDEX('|', performance_condition, PATINDEX('%_|_%', performance_condition) + 2) - 1)

    FROM msdb.dbo.sysalerts

    WHERE (performance_condition IS NOT NULL)

    AND (enabled = 1)

    END

    SELECT 'object_name' = RTRIM(SUBSTRING(spi1.object_name, 1, 50)),

    'counter_name' = RTRIM(SUBSTRING(spi1.counter_name, 1, 50)),

    'instance_name' = CASE spi1.instance_name

    WHEN N'' THEN NULL

    ELSE RTRIM(spi1.instance_name)

    END,

    'value' = CASE

    WHEN (spi1.cntr_type = 537003008) -- A ratio

    THEN CONVERT(FLOAT, spi1.cntr_value) / (SELECT CASE spi2.cntr_value WHEN 0 THEN 1 ELSE spi2.cntr_value END

    FROM master.dbo.sysperfinfo spi2

    WHERE (spi1.counter_name + ' ' = SUBSTRING(spi2.counter_name, 1, PATINDEX('% Base%', spi2.counter_name)))

    AND (spi1.instance_name = spi2.instance_name)

    AND (spi2.cntr_type = 1073939459))

    WHEN (spi1.cntr_value < 0)

    THEN CONVERT(FLOAT, CONVERT(bigint, spi1.cntr_value) + convert(bigint, 0x100000000))

    ELSE spi1.cntr_value

    END,

    'type' = spi1.cntr_type

    FROM master.dbo.sysperfinfo spi1,

    #temp tmp

    WHERE (spi1.cntr_type <> 1073939459) -- Divisors

    AND ((@all_counters = 1) OR

    (tmp.performance_condition = RTRIM(spi1.object_name) + '|' + RTRIM(spi1.counter_name)))

    END

    go

    /**************************************************************/

    /* SP_SQLAGENT_NOTIFY */

    /* */

    /* NOTE: We define this procedure here instead of in the */

    /* 'Support procedures' section because of the many */

    /* other procedures that reference it. */

    /**************************************************************/

    PRINT ''

    PRINT 'Creating procedure sp_sqlagent_notify...'

    go

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = N'sp_sqlagent_notify')

    AND (type = 'P')))

    DROP PROCEDURE sp_sqlagent_notify

    go

    CREATE PROCEDURE sp_sqlagent_notify

    @op_type NCHAR(1), -- One of: J (Job action [refresh or start/stop]),

    -- S (Schedule action [refresh only])

    -- A (Alert action [refresh only]),

    -- G (Re-cache all registry settings),

    -- D (Dump job [or job schedule] cache to errorlog)

    -- P (Force an immediate poll of the MSX)

    @job_id UNIQUEIDENTIFIER = NULL, -- JobID (for OpTypes 'J', 'S' and 'D')

    @schedule_id INT = NULL, -- ScheduleID (for OpType 'S')

    @alert_id INT = NULL, -- AlertID (for OpType 'A')

    @action_type NCHAR(1) = NULL, -- For 'J' one of: R (Run - no service check),

    -- S (Start - with service check),

    -- I (Insert),

    -- U (Update),

    -- D (Delete),

    -- C (Stop [Cancel])

    -- For 'S' or 'A' one of: I (Insert),

    -- U (Update),

    -- D (Delete)

    @error_flag INT = 1 -- Set to 0 to suppress the error from xp_sqlagent_notify if SQLServer agent is not running

    AS

    BEGIN

    DECLARE @retval INT

    DECLARE @id_as_char VARCHAR(10)

    DECLARE @job_id_as_char VARCHAR(36)

    DECLARE @nt_user_name NVARCHAR(100)

    SET NOCOUNT ON

    SELECT @retval = 0 -- Success

    -- Make sure that we're dealing only with uppercase characters

    SELECT @op_type = UPPER(@op_type)

    SELECT @action_type = UPPER(@action_type)

    -- Verify operation code

    IF (CHARINDEX(@op_type, N'JSAGDP') = 0)

    BEGIN

    RAISERROR(14266, -1, -1, '@op_type', 'J, S, A, G, D, P')

    RETURN(1) -- Failure

    END

    -- Check the job id for those who use it

    IF (CHARINDEX(@op_type, N'JSD') <> 0)

    BEGIN

    IF (NOT ((@op_type = N'D') AND (@job_id IS NULL))) -- For 'D', job_id is optional

    BEGIN

    IF ((@job_id IS NULL) OR

    ((@action_type <> N'D') AND NOT EXISTS (SELECT *

    FROM msdb.dbo.sysjobs_view

    WHERE (job_id = @job_id))))

    BEGIN

    SELECT @job_id_as_char = CONVERT(VARCHAR(36), @job_id)

    RAISERROR(14262, -1, -1, '@job_id', @job_id_as_char)

    RETURN(1) -- Failure

    END

    END

    END

    -- Verify 'job' action parameters

    IF (@op_type = N'J')

    BEGIN

    SELECT @alert_id = 0

    IF (@schedule_id IS NULL) SELECT @schedule_id = 0

    -- The schedule_id (if specified) is the start step

    IF ((CHARINDEX(@action_type, N'RS') <> 0) AND (@schedule_id <> 0))

    BEGIN

    IF (NOT EXISTS (SELECT *

    FROM msdb.dbo.sysjobsteps

    WHERE (job_id = @job_id)

    AND (step_id = @schedule_id)))

    BEGIN

    SELECT @id_as_char = ISNULL(CONVERT(VARCHAR, @schedule_id), '(null)')

    RAISERROR(14262, -1, -1, '@schedule_id', @id_as_char)

    RETURN(1) -- Failure

    END

    END

    ELSE

    SELECT @schedule_id = 0

    IF (CHARINDEX(@action_type, N'RSIUDC') = 0)

    BEGIN

    RAISERROR(14266, -1, -1, '@action_type', 'R, S, I, U, D, C')

    RETURN(1) -- Failure

    END

    END

    -- Verify 'schedule' action parameters

    IF (@op_type = N'S')

    BEGIN

    SELECT @alert_id = 0

    IF (CHARINDEX(@action_type, N'IUD') = 0)

    BEGIN

    RAISERROR(14266, -1, -1, '@action_type', 'I, U, D')

    RETURN(1) -- Failure

    END

    IF ((@schedule_id IS NULL) OR

    ((@action_type <> N'D') AND NOT EXISTS (SELECT *

    FROM msdb.dbo.sysjobschedules

    WHERE (schedule_id = @schedule_id))))

    BEGIN

    SELECT @id_as_char = ISNULL(CONVERT(VARCHAR, @schedule_id), '(null)')

    RAISERROR(14262, -1, -1, '@schedule_id', @id_as_char)

    RETURN(1) -- Failure

    END

    END

    -- Verify 'alert' action parameters

    IF (@op_type = N'A')

    BEGIN

    SELECT @job_id = 0x00

    SELECT @schedule_id = 0

    IF (CHARINDEX(@action_type, N'IUD') = 0)

    BEGIN

    RAISERROR(14266, -1, -1, '@action_type', 'I, U, D')

    RETURN(1) -- Failure

    END

    IF ((@alert_id IS NULL) OR

    ((@action_type <> N'D') AND NOT EXISTS (SELECT *

    FROM msdb.dbo.sysalerts

    WHERE (id = @alert_id))))

    BEGIN

    SELECT @id_as_char = ISNULL(CONVERT(VARCHAR, @alert_id), '(null)')

    RAISERROR(14262, -1, -1, '@alert_id', @id_as_char)

    RETURN(1) -- Failure

    END

    END

    -- Verify 'registry', 'job dump' and 'force MSX poll' action parameters

    IF (CHARINDEX(@op_type, N'GDP') <> 0)

    BEGIN

    IF (@op_type <> N'D')

    SELECT @job_id = 0x00

    SELECT @alert_id = 0

    SELECT @schedule_id = 0

    SELECT @action_type = NULL

    END

    -- Parameters are valid, so now check execution permissions...

    -- For anything except a job (or schedule) action the caller must be SysAdmin, DBO, or DB_Owner

    IF (@op_type NOT IN (N'J', N'S'))

    BEGIN

    IF NOT ((ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) = 1) OR

    (ISNULL(IS_MEMBER(N'db_owner'), 0) = 1) OR

    (UPPER(USER_NAME()) = N'DBO'))

    BEGIN

    RAISERROR(14260, -1, -1)

    RETURN(1) -- Failure

    END

    END

    -- For a Job Action the caller must be SysAdmin, DBO, DB_Owner, or the job owner

    IF (@op_type = N'J')

    BEGIN

    IF NOT ((ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) = 1) OR

    (ISNULL(IS_MEMBER(N'db_owner'), 0) = 1) OR

    (UPPER(USER_NAME()) = N'DBO') OR

    (EXISTS (SELECT *

    FROM msdb.dbo.sysjobs_view

    WHERE (job_id = @job_id))))

    BEGIN

    RAISERROR(14252, -1, -1)

    RETURN(1) -- Failure

    END

    END

    -- Ok, let's do it...

    SELECT @nt_user_name = ISNULL(NT_CLIENT(), ISNULL(SUSER_SNAME(), FORMATMESSAGE(14205)))

    EXECUTE @retval = master.dbo.xp_sqlagent_notify @op_type, @job_id, @schedule_id, @alert_id, @action_type, @nt_user_name, @error_flag, @@trancount

    RETURN(@retval)

    END

    go

    /**************************************************************/

    /* SP_IS_SQLAGENT_STARTING */

    /**************************************************************/

    PRINT ''

    PRINT 'Creating procedure sp_is_sqlagent_starting...'

    go

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = N'sp_is_sqlagent_starting')

    AND (type = 'P')))

    DROP PROCEDURE sp_is_sqlagent_starting

    go

    CREATE PROCEDURE sp_is_sqlagent_starting

    AS

    BEGIN

    DECLARE @retval INT

    SELECT @retval = 0

    EXECUTE master.dbo.xp_sqlagent_is_starting @retval OUTPUT

    IF (@retval = 1)

    RAISERROR(14258, -1, -1)

    RETURN(@retval)

    END

    go

    /**************************************************************/

    /* SP_VERIFY_JOB_IDENTIFIERS */

    /* */

    /* NOTE: We define this procedure here instead of in the */

    /* 'Support procedures' section because of the many */

    /* other procedures that reference it. */

    /**************************************************************/

    PRINT ''

    PRINT 'Creating procedure sp_verify_job_identifiers...'

    go

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = N'sp_verify_job_identifiers')

    AND (type = 'P')))

    DROP PROCEDURE sp_verify_job_identifiers

    go

    CREATE PROCEDURE sp_verify_job_identifiers

    @name_of_name_parameter VARCHAR(60), -- Eg. '@job_name'

    @name_of_id_parameter VARCHAR(60), -- Eg. '@job_id'

    @job_name sysname OUTPUT, -- Eg. 'My Job'

    @job_id UNIQUEIDENTIFIER OUTPUT,

    @sqlagent_starting_test VARCHAR(7) = 'TEST' -- By default we DO want to test if SQLServerAgent is running (caller should specify 'NO_TEST' if not desired)

    AS

    BEGIN

    DECLARE @retval INT

    DECLARE @job_id_as_char VARCHAR(36)

    SET NOCOUNT ON

    -- Remove any leading/trailing spaces from parameters

    SELECT @name_of_name_parameter = LTRIM(RTRIM(@name_of_name_parameter))

    SELECT @name_of_id_parameter = LTRIM(RTRIM(@name_of_id_parameter))

    SELECT @job_name = LTRIM(RTRIM(@job_name))

    IF (@job_name = N'') SELECT @job_name = NULL

    IF ((@job_name IS NULL) AND (@job_id IS NULL)) OR

    ((@job_name IS NOT NULL) AND (@job_id IS NOT NULL))

    BEGIN

    RAISERROR(14294, -1, -1, @name_of_id_parameter, @name_of_name_parameter)

    RETURN(1) -- Failure

    END

    -- Check job id

    IF (@job_id IS NOT NULL)

    BEGIN

    SELECT @job_name = name,

    @job_id = job_id

    FROM msdb.dbo.sysjobs_view

    WHERE (job_id = @job_id)

    IF (@job_name IS NULL)

    BEGIN

    SELECT @job_id_as_char = CONVERT(VARCHAR(36), @job_id)

    RAISERROR(14262, -1, -1, '@job_id', @job_id_as_char)

    RETURN(1) -- Failure

    END

    END

    ELSE

    -- Check job name

    IF (@job_name IS NOT NULL)

    BEGIN

    -- Check if the job name is ambiguous

    IF ((SELECT COUNT(*)

    FROM msdb.dbo.sysjobs_view

    WHERE (name = @job_name)) > 1)

    BEGIN

    RAISERROR(14293, -1, -1, @job_name, @name_of_id_parameter, @name_of_name_parameter)

    RETURN(1) -- Failure

    END

    -- The name is not ambiguous, so get the corresponding job_id (if the job exists)

    SELECT @job_id = job_id

    FROM msdb.dbo.sysjobs_view

    WHERE (name = @job_name)

    IF (@job_id IS NULL)

    BEGIN

    RAISERROR(14262, -1, -1, '@job_name', @job_name)

    RETURN(1) -- Failure

    END

    END

    IF (@sqlagent_starting_test = 'TEST')

    BEGIN

    -- Finally, check if SQLServerAgent is in the process of starting and if so prevent the

    -- calling SP from running

    EXECUTE @retval = msdb.dbo.sp_is_sqlagent_starting

    IF (@retval <> 0)

    RETURN(1) -- Failure

    END

    RETURN(0) -- Success

    END

    go

    /**************************************************************/

    /* SP_VERIFY_JOBPROC_CALLER */

    /* */

    /* NOTE: We define this procedure here instead of in the */

    /* 'Support procedures' section because of the many */

    /* other procedures that reference it. */

    /**************************************************************/

    PRINT ''

    PRINT 'Creating procedure sp_verify_jobproc_caller...'

    go

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = N'sp_verify_jobproc_caller')

    AND (type = 'P')))

    DROP PROCEDURE sp_verify_jobproc_caller

    go

    CREATE PROCEDURE sp_verify_jobproc_caller

    @job_id UNIQUEIDENTIFIER,

    @program_name sysname

    AS

    BEGIN

    SET NOCOUNT ON

    -- Remove any leading/trailing spaces from parameters

    SELECT @program_name = LTRIM(RTRIM(@program_name))

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysjobs_view

    WHERE (job_id = @job_id)

    AND (UPPER(originating_server) <> UPPER(CONVERT(NVARCHAR(30), SERVERPROPERTY('ServerName'))))))

    AND (PROGRAM_NAME() NOT LIKE @program_name)

    BEGIN

    RAISERROR(14274, -1, -1)

    RETURN(1) -- Failure

    END

    RETURN(0)

    END

    go

    /**************************************************************/

    /* SP_DOWNLOADED_ROW_LIMITER */

    /**************************************************************/

    PRINT ''

    PRINT 'Creating procedure sp_downloaded_row_limiter...'

    go

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = N'sp_downloaded_row_limiter')

    AND (type = 'P')))

    DROP PROCEDURE dbo.sp_downloaded_row_limiter

    go

    CREATE PROCEDURE sp_downloaded_row_limiter

    @server_name NVARCHAR(30) -- Target server name

    AS

    BEGIN

    -- This trigger controls how many downloaded (status = 1) sysdownloadlist rows exist

    -- for any given server. It does NOT control the absolute number of rows in the table.

    DECLARE @current_rows_per_server INT

    DECLARE @max_rows_per_server INT -- This value comes from the resgistry (DownloadedMaxRows)

    DECLARE @rows_to_delete INT

    DECLARE @rows_to_delete_as_char VARCHAR(10)

    SET NOCOUNT ON

    -- Remove any leading/trailing spaces from parameters

    SELECT @server_name = LTRIM(RTRIM(@server_name))

    -- Check the server name (if it's bad we fail silently)

    IF (@server_name IS NULL) OR

    (NOT EXISTS (SELECT *

    FROM msdb.dbo.sysdownloadlist

    WHERE (target_server = @server_name)))

    RETURN(1) -- Failure

    SELECT @max_rows_per_server = 0

    -- Get the max-rows-per-server from the registry

    EXECUTE master.dbo.xp_instance_regread N'HKEY_LOCAL_MACHINE',

    N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',

    N'DownloadedMaxRows',

    @max_rows_per_server OUTPUT,

    N'no_output'

    -- Check if we are limiting sysdownloadlist rows

    IF (ISNULL(@max_rows_per_server, -1) = -1)

    RETURN

    -- Check that max_rows_per_server is >= 0

    IF (@max_rows_per_server < -1)

    BEGIN

    -- It isn't, so default to 100 rows

    SELECT @max_rows_per_server = 100

    EXECUTE master.dbo.xp_instance_regwrite N'HKEY_LOCAL_MACHINE',

    N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',

    N'DownloadedMaxRows',

    N'REG_DWORD',

    @max_rows_per_server

    END

    -- Get the number of downloaded rows in sysdownloadlist for the target server in question

    -- NOTE: Determining this [quickly] requires a [non-clustered] index on target_server

    SELECT @current_rows_per_server = COUNT(*)

    FROM msdb.dbo.sysdownloadlist

    WHERE (target_server = @server_name)

    AND (status = 1)

    -- Delete the oldest downloaded row(s) for the target server in question if the new row has

    -- pushed us over the per-server row limit

    SELECT @rows_to_delete = @current_rows_per_server - @max_rows_per_server

    SELECT @rows_to_delete_as_char = CONVERT(VARCHAR, @rows_to_delete)

    IF (@rows_to_delete > 0)

    BEGIN

    EXECUTE ('DECLARE @new_oldest_id INT

    SET NOCOUNT ON

    SET ROWCOUNT ' + @rows_to_delete_as_char +

    'SELECT @new_oldest_id = instance_id

    FROM msdb.dbo.sysdownloadlist

    WHERE (target_server = N''' + @server_name + ''')' +

    ' AND (status = 1)

    ORDER BY instance_id

    SET ROWCOUNT 0

    DELETE FROM msdb.dbo.sysdownloadlist

    WHERE (target_server = N''' + @server_name + ''')' +

    ' AND (instance_id <= @new_oldest_id)

    AND (status = 1)')

    END

    END

    go

    /**************************************************************/

    /* SP_POST_MSX_OPERATION */

    /* */

    /* NOTE: We define this procedure here instead of in the */

    /* 'Support procedures' section because of the many */

    /* other procedures that reference it. */

    /**************************************************************/

    PRINT ''

    PRINT 'Creating procedure sp_post_msx_operation...'

    go

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = 'sp_post_msx_operation')

    AND (type = 'P')))

    DROP PROCEDURE sp_post_msx_operation

    go

    CREATE PROCEDURE sp_post_msx_operation

    @operation VARCHAR(64),

    @object_type VARCHAR(64) = 'JOB',

    @job_id UNIQUEIDENTIFIER = NULL, -- NOTE: 0x00 means 'ALL'

    @specific_target_server NVARCHAR(30) = NULL,

    @value INT = NULL -- For polling interval value

    AS

    BEGIN

    DECLARE @operation_code INT

    DECLARE @specific_target_server_id INT

    DECLARE @instructions_posted INT

    DECLARE @job_id_as_char VARCHAR(36)

    DECLARE @msx_time_zone_adjustment INT

    DECLARE @local_machine_name NVARCHAR(30)

    DECLARE @retval INT

    SET NOCOUNT ON

    -- Remove any leading/trailing spaces from parameters

    SELECT @operation = LTRIM(RTRIM(@operation))

    SELECT @object_type = LTRIM(RTRIM(@object_type))

    SELECT @specific_target_server = LTRIM(RTRIM(@specific_target_server))

    -- Turn [nullable] empty string parameters into NULLs

    IF (@specific_target_server = N'') SELECT @specific_target_server = NULL

    -- Only a sysadmin can do this, but fail silently for a non-sysadmin

    IF (ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) <> 1)

    RETURN(0) -- Success (or more accurately a no-op)

    -- Check operation

    SELECT @operation = UPPER(@operation)

    SELECT @operation_code = CASE @operation

    WHEN 'INSERT' THEN 1

    WHEN 'UPDATE' THEN 2

    WHEN 'DELETE' THEN 3

    WHEN 'START' THEN 4

    WHEN 'STOP' THEN 5

    WHEN 'RE-ENLIST' THEN 6

    WHEN 'DEFECT' THEN 7

    WHEN 'SYNC-TIME' THEN 8

    WHEN 'SET-POLL' THEN 9

    ELSE 0

    END

    IF (@operation_code = 0)

    BEGIN

    RAISERROR(14266, -1, -1, '@operation_code', 'INSERT, UPDATE, DELETE, START, STOP, RE-ENLIST, DEFECT, SYNC-TIME, SET-POLL')

    RETURN(1) -- Failure

    END

    -- Check object type (in 7.0 only 'JOB' or 'SERVER' are valid)

    IF ((@object_type <> 'JOB') AND (@object_type <> 'SERVER'))

    BEGIN

    RAISERROR(14266, -1, -1, '@object_type', 'JOB, SERVER')

    RETURN(1) -- Failure

    END

    -- Check that for a object type of JOB a job_id has been supplied

    IF ((@object_type = 'JOB') AND (@job_id IS NULL))

    BEGIN

    RAISERROR(14233, -1, -1)

    RETURN(1) -- Failure

    END

    -- Check polling interval value

    IF (@operation_code = 9) AND ((ISNULL(@value, 0) 28800))

    BEGIN

    RAISERROR(14266, -1, -1, '@value', '10..28800')

    RETURN(1) -- Failure

    END

    -- Check specific target server

    IF (@specific_target_server IS NOT NULL)

    BEGIN

    -- Check if the local server is being targeted

    IF (UPPER(@specific_target_server) = UPPER(CONVERT(NVARCHAR(30), SERVERPROPERTY('ServerName'))))

    BEGIN

    RETURN(0)

    END

    ELSE

    BEGIN

    SELECT @specific_target_server_id = server_id

    FROM msdb.dbo.systargetservers

    WHERE (server_name = @specific_target_server)

    IF (@specific_target_server_id IS NULL)

    BEGIN

    RAISERROR(14262, -1, -1, '@specific_target_server', @specific_target_server)

    RETURN(1) -- Failure

    END

    END

    END

    -- Check that this server is an MSX server

    IF ((SELECT COUNT(*)

    FROM msdb.dbo.systargetservers) = 0)

    BEGIN

    RETURN(0)

    END

    -- Get local machine name

    EXECUTE @retval = master.dbo.xp_getnetname @local_machine_name OUTPUT

    IF (@retval <> 0) OR (@local_machine_name IS NULL)

    BEGIN

    RAISERROR(14225, -1, -1)

    RETURN(1)

    END

    CREATE TABLE #target_servers (server_name sysname COLLATE database_default NOT NULL)

    -- Optimization: Simply update the date-posted if the operation has already been posted (but

    -- not yet downloaded) and the target server is not currently polling...

    IF ((@object_type = 'JOB') AND (ISNULL(@job_id, 0x00) <> CONVERT(UNIQUEIDENTIFIER, 0x00)) AND (@operation_code IN (1, 2, 3, 4, 5))) OR -- Any JOB operation

    ((@object_type = 'SERVER') AND (@operation_code IN (6, 7))) -- RE-ENLIST or DEFECT operations

    BEGIN

    -- Populate the list of target servers to post to

    IF (@specific_target_server IS NOT NULL)

    INSERT INTO #target_servers VALUES (@specific_target_server)

    ELSE

    BEGIN

    IF (@object_type = 'SERVER')

    INSERT INTO #target_servers

    SELECT server_name

    FROM msdb.dbo.systargetservers

    IF (@object_type = 'JOB')

    INSERT INTO #target_servers

    SELECT sts.server_name

    FROM msdb.dbo.sysjobs_view sjv,

    msdb.dbo.sysjobservers sjs,

    msdb.dbo.systargetservers sts

    WHERE (sjv.job_id = @job_id)

    AND (sjv.job_id = sjs.job_id)

    AND (sjs.server_id = sts.server_id)

    AND (sjs.server_id <> 0)

    END

    END

    -- Job-specific processing...

    IF (@object_type = 'JOB')

    BEGIN

    -- Validate the job (if supplied)

    IF (@job_id <> CONVERT(UNIQUEIDENTIFIER, 0x00))

    BEGIN

    SELECT @job_id_as_char = CONVERT(VARCHAR(36), @job_id)

    -- Check if the job exists

    IF (NOT EXISTS (SELECT *

    FROM msdb.dbo.sysjobs_view

    WHERE (job_id = @job_id)))

    BEGIN

    RAISERROR(14262, -1, -1, '@job_id', @job_id_as_char)

    RETURN(1) -- Failure

    END

    -- If this is a local job then there's nothing for us to do

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysjobservers

    WHERE (job_id = @job_id)

    AND (server_id = 0))) -- 0 means local server

    OR (NOT EXISTS (SELECT *

    FROM msdb.dbo.sysjobservers

    WHERE (job_id = @job_id)))

    BEGIN

    RETURN(0)

    END

    END

    -- Generate the sysdownloadlist row(s)...

    IF (@operation_code = 1) OR -- Insert

    (@operation_code = 2) OR -- Update

    (@operation_code = 3) OR -- Delete

    (@operation_code = 4) OR -- Start

    (@operation_code = 5) -- Stop

    BEGIN

    IF (@job_id = CONVERT(UNIQUEIDENTIFIER, 0x00)) -- IE. 'ALL'

    BEGIN

    -- All jobs

    -- Handle DELETE as a special case (rather than posting 1 instruction per job we just

    -- post a single instruction that means 'delete all jobs from the MSX')

    IF (@operation_code = 3)

    BEGIN

    INSERT INTO msdb.dbo.sysdownloadlist

    (source_server,

    operation_code,

    object_type,

    object_id,

    target_server)

    SELECT @local_machine_name,

    @operation_code,

    1, -- 1 means 'JOB'

    CONVERT(UNIQUEIDENTIFIER, 0x00),

    sts.server_name

    FROM systargetservers sts

    WHERE ((@specific_target_server_id IS NULL) OR (sts.server_id = @specific_target_server_id))

    AND ((SELECT COUNT(*)

    FROM msdb.dbo.sysjobservers

    WHERE (server_id = sts.server_id)) > 0)

    SELECT @instructions_posted = @@rowcount

    END

    ELSE

    BEGIN

    INSERT INTO msdb.dbo.sysdownloadlist

    (source_server,

    operation_code,

    object_type,

    object_id,

    target_server)

    SELECT @local_machine_name,

    @operation_code,

    1, -- 1 means 'JOB'

    sjv.job_id,

    sts.server_name

    FROM sysjobs_view sjv,

    sysjobservers sjs,

    systargetservers sts

    WHERE (sjv.job_id = sjs.job_id)

    AND (sjs.server_id = sts.server_id)

    AND (sjs.server_id <> 0) -- We want to exclude local jobs

    AND ((@specific_target_server_id IS NULL) OR (sjs.server_id = @specific_target_server_id))

    SELECT @instructions_posted = @@rowcount

    END

    END

    ELSE

    BEGIN

    -- Specific job (ie. @job_id is not 0x00)

    INSERT INTO msdb.dbo.sysdownloadlist

    (source_server,

    operation_code,

    object_type,

    object_id,

    target_server,

    deleted_object_name)

    SELECT @local_machine_name,

    @operation_code,

    1, -- 1 means 'JOB'

    sjv.job_id,

    sts.server_name,

    CASE @operation_code WHEN 3 -- Delete

    THEN sjv.name

    ELSE NULL

    END

    FROM sysjobs_view sjv,

    sysjobservers sjs,

    systargetservers sts

    WHERE (sjv.job_id = @job_id)

    AND (sjv.job_id = sjs.job_id)

    AND (sjs.server_id = sts.server_id)

    AND (sjs.server_id <> 0) -- We want to exclude local jobs

    AND ((@specific_target_server_id IS NULL) OR (sjs.server_id = @specific_target_server_id))

    SELECT @instructions_posted = @@rowcount

    END

    END

    ELSE

    BEGIN

    RAISERROR(14266, -1, -1, '@operation_code', 'INSERT, UPDATE, DELETE, START, STOP')

    RETURN(1) -- Failure

    END

    END

    -- Server-specific processing...

    IF (@object_type = 'SERVER')

    BEGIN

    -- Generate the sysdownloadlist row(s)...

    IF (@operation_code = 6) OR -- ReEnlist

    (@operation_code = 7) OR -- Defect

    (@operation_code = 8) OR -- Synchronize time (with MSX)

    (@operation_code = 9) -- Set MSX polling interval (in seconds)

    BEGIN

    IF (@operation_code = 8)

    BEGIN

    EXECUTE master.dbo.xp_regread N'HKEY_LOCAL_MACHINE',

    N'SYSTEM\CurrentControlSet\Control\TimeZoneInformation',

    N'Bias',

    @msx_time_zone_adjustment OUTPUT,

    N'no_output'

    SELECT @msx_time_zone_adjustment = -ISNULL(@msx_time_zone_adjustment, 0)

    END

    INSERT INTO msdb.dbo.sysdownloadlist

    (source_server,

    operation_code,

    object_type,

    object_id,

    target_server)

    SELECT @local_machine_name,

    @operation_code,

    2, -- 2 means 'SERVER'

    CASE @operation_code

    WHEN 8 THEN CONVERT(UNIQUEIDENTIFIER, CONVERT(BINARY(16), -(@msx_time_zone_adjustment - sts.time_zone_adjustment)))

    WHEN 9 THEN CONVERT(UNIQUEIDENTIFIER, CONVERT(BINARY(16), @value))

    ELSE CONVERT(UNIQUEIDENTIFIER, 0x00)

    END,

    sts.server_name

    FROM systargetservers sts

    WHERE ((@specific_target_server_id IS NULL) OR (sts.server_id = @specific_target_server_id))

    SELECT @instructions_posted = @@rowcount

    END

    ELSE

    BEGIN

    RAISERROR(14266, -1, -1, '@operation_code', 'RE-ENLIST, DEFECT, SYNC-TIME, SET-POLL')

    RETURN(1) -- Failure

    END

    END

    -- Report number of rows inserted

    IF (@object_type = 'JOB') AND

    (@job_id = CONVERT(UNIQUEIDENTIFIER, 0x00)) AND

    (@instructions_posted = 0) AND

    (@specific_target_server_id IS NOT NULL)

    RAISERROR(14231, 0, 1, '@specific_target_server', @specific_target_server)

    ELSE

    RAISERROR(14230, 0, 1, @instructions_posted, @operation)

    -- Delete any [downloaded] instructions that are over the registry-defined limit

    IF (@specific_target_server IS NOT NULL)

    EXECUTE msdb.dbo.sp_downloaded_row_limiter @specific_target_server

    RETURN(0) -- 0 means success

    END

    go

    /**************************************************************/

    /* SP_DELETE_JOB_REFERENCES */

    /**************************************************************/

    PRINT ''

    PRINT 'Creating procedure sp_delete_job_references...'

    go

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = N'sp_delete_job_references')

    AND (type = 'P')))

    DROP PROCEDURE sp_delete_job_references

    go

    CREATE PROCEDURE sp_delete_job_references

    AS

    BEGIN

    DECLARE @deleted_job_id UNIQUEIDENTIFIER

    DECLARE @task_id_as_char VARCHAR(10)

    DECLARE @job_is_cached INT

    DECLARE @alert_name sysname

    -- Keep SQLServerAgent's cache in-sync and cleanup any 'webtask' cross-references to the deleted job(s)

    -- NOTE: The caller must have created a table called #temp_jobs_to_delete of the format

    -- (job_id UNIQUEIDENTIFIER NOT NULL, job_is_cached INT NOT NULL).

    DECLARE sqlagent_notify CURSOR LOCAL

    FOR

    SELECT job_id, job_is_cached

    FROM #temp_jobs_to_delete

    OPEN sqlagent_notify

    FETCH NEXT FROM sqlagent_notify INTO @deleted_job_id, @job_is_cached

    WHILE (@@fetch_status = 0)

    BEGIN

    -- NOTE: We only notify SQLServerAgent if we know the job has been cached

    IF(@job_is_cached = 1)

    EXECUTE msdb.dbo.sp_sqlagent_notify @op_type = N'J',

    @job_id = @deleted_job_id,

    @action_type = N'D'

    IF (EXISTS (SELECT *

    FROM master.dbo.sysobjects

    WHERE (name = N'sp_cleanupwebtask')

    AND (type = 'P')))

    BEGIN

    SELECT @task_id_as_char = CONVERT(VARCHAR(10), task_id)

    FROM msdb.dbo.systaskids

    WHERE (job_id = @deleted_job_id)

    IF (@task_id_as_char IS NOT NULL)

    EXECUTE ('master.dbo.sp_cleanupwebtask @taskid = ' + @task_id_as_char)

    END

    FETCH NEXT FROM sqlagent_notify INTO @deleted_job_id, @job_is_cached

    END

    DEALLOCATE sqlagent_notify

    -- Remove systaskid references (must do this AFTER sp_cleanupwebtask stuff)

    DELETE FROM msdb.dbo.systaskids

    WHERE job_id IN (SELECT job_id FROM #temp_jobs_to_delete)

    -- Remove sysdbmaintplan_jobs references

    DELETE FROM msdb.dbo.sysdbmaintplan_jobs

    WHERE job_id IN (SELECT job_id FROM #temp_jobs_to_delete)

    -- Finally, clean up any dangling references in sysalerts to the deleted job(s)

    DECLARE sysalerts_cleanup CURSOR LOCAL

    FOR

    SELECT name

    FROM msdb.dbo.sysalerts

    WHERE (job_id IN (SELECT job_id FROM #temp_jobs_to_delete))

    OPEN sysalerts_cleanup

    FETCH NEXT FROM sysalerts_cleanup INTO @alert_name

    WHILE (@@fetch_status = 0)

    BEGIN

    EXECUTE msdb.dbo.sp_update_alert @name = @alert_name,

    @job_id = 0x00

    FETCH NEXT FROM sysalerts_cleanup INTO @alert_name

    END

    DEALLOCATE sysalerts_cleanup

    END

    go

    /**************************************************************/

    /* SP_DELETE_ALL_MSX_JOBS */

    /* */

    /* NOTE: This is a separate procedure because SQLServerAgent */

    /* needs to call it, as does sp_msx_defect and */

    /* sp_delete_job. */

    /**************************************************************/

    PRINT ''

    PRINT 'Creating procedure sp_delete_all_msx_jobs...'

    go

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = N'sp_delete_all_msx_jobs')

    AND (type = 'P')))

    DROP PROCEDURE sp_delete_all_msx_jobs

    go

    CREATE PROCEDURE sp_delete_all_msx_jobs

    @msx_server NVARCHAR(30),

    @jobs_deleted INT = NULL OUTPUT

    AS

    BEGIN

    SET NOCOUNT ON

    -- Change server name to always reflect real servername or servername\instancename

    IF (UPPER(@msx_server) = '(LOCAL)')

    SELECT @msx_server = UPPER(CONVERT(NVARCHAR(30), SERVERPROPERTY('ServerName')))

    -- Delete all the jobs that originated from the MSX

    CREATE TABLE #temp_jobs_to_delete (job_id UNIQUEIDENTIFIER NOT NULL, job_is_cached INT NOT NULL)

    -- NOTE: The left outer-join here is to handle the [unlikely] case of missing sysjobservers rows

    INSERT INTO #temp_jobs_to_delete

    SELECT sjv.job_id, CASE sjs.server_id WHEN 0 THEN 1 ELSE 0 END

    FROM msdb.dbo.sysjobs_view sjv

    LEFT OUTER JOIN msdb.dbo.sysjobservers sjs ON (sjv.job_id = sjs.job_id)

    WHERE (ISNULL(sjs.server_id, 0) = 0)

    AND (sjv.originating_server = @msx_server)

    -- Must do this before deleting the job itself since sp_sqlagent_notify does a lookup on sysjobs_view

    EXECUTE msdb.dbo.sp_delete_job_references

    BEGIN TRANSACTION

    DELETE FROM msdb.dbo.sysjobs_view

    WHERE job_id IN (SELECT job_id FROM #temp_jobs_to_delete)

    DELETE FROM msdb.dbo.sysjobservers

    WHERE job_id IN (SELECT job_id FROM #temp_jobs_to_delete)

    DELETE FROM msdb.dbo.sysjobsteps

    WHERE job_id IN (SELECT job_id FROM #temp_jobs_to_delete)

    DELETE FROM msdb.dbo.sysjobschedules

    WHERE job_id IN (SELECT job_id FROM #temp_jobs_to_delete)

    DELETE FROM msdb.dbo.sysjobhistory

    WHERE job_id IN (SELECT job_id FROM #temp_jobs_to_delete)

    COMMIT TRANSACTION

    SELECT @jobs_deleted = COUNT(*)

    FROM #temp_jobs_to_delete

    DROP TABLE #temp_jobs_to_delete

    END

    go

    /**************************************************************/

    /* SP_GENERATE_TARGET_SERVER_JOB_ASSIGNMENT_SQL */

    /**************************************************************/

    PRINT ''

    PRINT 'Creating procedure sp_generate_target_server_job_assignment_sql...'

    go

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = N'sp_generate_target_server_job_assignment_sql')

    AND (type = 'P')))

    DROP PROCEDURE sp_generate_target_server_job_assignment_sql

    go

    CREATE PROCEDURE sp_generate_target_server_job_assignment_sql

    @server_name NVARCHAR(30) = NULL,

    @new_server_name NVARCHAR(30) = NULL -- Use this if the target server computer has been renamed

    AS

    BEGIN

    SET NOCOUNT ON

    -- Change server name to always reflect real servername or servername\instancename

    IF (@server_name IS NULL) OR (UPPER(@server_name) = '(LOCAL)')

    SELECT @server_name = UPPER(CONVERT(NVARCHAR(30), SERVERPROPERTY('ServerName')))

    -- Verify the server name

    IF (UPPER(@server_name) <> UPPER(CONVERT(NVARCHAR(30), SERVERPROPERTY('ServerName')))) AND

    (NOT EXISTS (SELECT *

    FROM msdb.dbo.systargetservers

    WHERE (server_name = @server_name)))

    BEGIN

    RAISERROR(14262, 16, 1, '@server_name', @server_name)

    RETURN(1) -- Failure

    END

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysjobservers sjs,

    msdb.dbo.systargetservers sts

    WHERE (sjs.server_id = sts.server_id)

    AND (sts.server_name = @server_name)))

    BEGIN

    -- Generate the SQL

    SELECT 'Execute this SQL to re-assign jobs to the target server' =

    'EXECUTE msdb.dbo.sp_add_jobserver @job_id = ''' + CONVERT(VARCHAR(36), sjs.job_id) +

    ''', @server_name = ''' + ISNULL(@new_server_name, sts.server_name) + ''''

    FROM msdb.dbo.sysjobservers sjs,

    msdb.dbo.systargetservers sts

    WHERE (sjs.server_id = sts.server_id)

    AND (sts.server_name = @server_name)

    END

    ELSE

    RAISERROR(14548, 10, 1, @server_name)

    RETURN(0) -- Success

    END

    go

    /**************************************************************/

    /* SP_GENERATE_SERVER_DESCRIPTION */

    /**************************************************************/

    PRINT ''

    PRINT 'Creating procedure sp_generate_server_description...'

    go

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = N'sp_generate_server_description')

    AND (type = 'P')))

    DROP PROCEDURE sp_generate_server_description

    go

    CREATE PROCEDURE sp_generate_server_description

    @description NVARCHAR(100) = NULL OUTPUT,

    @result_set BIT = 0

    AS

    BEGIN

    SET NOCOUNT ON

    CREATE TABLE #xp_results

    (

    id INT NOT NULL,

    name NVARCHAR(30) COLLATE database_default NOT NULL,

    internal_value INT NULL,

    character_value NVARCHAR(212) COLLATE database_default NULL

    )

    INSERT INTO #xp_results

    EXECUTE master.dbo.xp_msver

    UPDATE #xp_results

    SET character_value = FORMATMESSAGE(14205)

    WHERE (character_value IS NULL)

    SELECT @description = (SELECT character_value FROM #xp_results WHERE (id = 1)) + N' ' +

    (SELECT character_value FROM #xp_results WHERE (id = 2)) + N' / Windows ' +

    (SELECT character_value FROM #xp_results WHERE (id = 15)) + N' / ' +

    (SELECT character_value FROM #xp_results WHERE (id = 16)) + N' ' +

    (SELECT CASE character_value

    WHEN N'PROCESSOR_INTEL_386' THEN N'386'

    WHEN N'PROCESSOR_INTEL_486' THEN N'486'

    WHEN N'PROCESSOR_INTEL_PENTIUM' THEN N'Pentium'

    WHEN N'PROCESSOR_MIPS_R4000' THEN N'MIPS'

    WHEN N'PROCESSOR_ALPHA_21064' THEN N'Alpha'

    ELSE character_value

    END

    FROM #xp_results WHERE (id = 18)) + N' CPU(s) / ' +

    (SELECT CONVERT(NVARCHAR, internal_value) FROM #xp_results WHERE (id = 19)) + N' MB RAM.'

    DROP TABLE #xp_results

    IF (@result_set = 1)

    SELECT @description

    END

    go

    /**************************************************************/

    /* SP_MSX_ENLIST */

    /**************************************************************/

    PRINT ''

    PRINT 'Creating procedure sp_msx_enlist...'

    go

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = 'sp_msx_enlist')

    AND (type = 'P')))

    DROP PROCEDURE sp_msx_enlist

    go

    CREATE PROCEDURE sp_msx_enlist

    @msx_server_name NVARCHAR(30),

    @location NVARCHAR(100) = NULL, -- The procedure will supply a default

    @ping_server BIT = 1 -- Set to 0 to skip the MSX ping test

    AS

    BEGIN

    DECLARE @current_msx_server NVARCHAR(30)

    DECLARE @local_machine_name NVARCHAR(30)

    DECLARE @retval INT

    DECLARE @time_zone_adjustment INT

    DECLARE @local_time NVARCHAR(100)

    DECLARE @nt_user NVARCHAR(100)

    DECLARE @poll_interval INT

    SET NOCOUNT ON

    -- Only a sysadmin can do this

    IF (ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) <> 1)

    BEGIN

    RAISERROR(15003, 16, 1, N'sysadmin')

    RETURN(1) -- Failure

    END

    -- Only an NT server can be enlisted

    IF ((PLATFORM() & 0x1) <> 0x1) -- NT

    BEGIN

    RAISERROR(14540, -1, 1)

    RETURN(1) -- Failure

    END

    -- Only SBS, Standard, or Enterprise editions of SQL Server can be enlisted

    IF ((PLATFORM() & 0x100) = 0x100) -- Desktop package

    BEGIN

    RAISERROR(14539, -1, -1)

    RETURN(1) -- Failure

    END

    -- Remove any leading/trailing spaces from parameters

    SELECT @msx_server_name = LTRIM(RTRIM(@msx_server_name))

    SELECT @location = LTRIM(RTRIM(@location))

    -- Turn [nullable] empty string parameters into NULLs

    IF (@location = N'') SELECT @location = NULL

    -- Change to MSX server name to upper-case since it's a machine name

    -- SELECT @msx_server_name = UPPER(@msx_server_name)

    SELECT @retval = 0

    -- Get the values that we'll need for the [re]enlistment operation (except the local time

    -- which we get right before we call xp_msx_enlist to that it's as accurate as possible)

    SELECT @nt_user = ISNULL(NT_CLIENT(), ISNULL(SUSER_SNAME(), FORMATMESSAGE(14205)))

    EXECUTE master.dbo.xp_regread N'HKEY_LOCAL_MACHINE',

    N'SYSTEM\CurrentControlSet\Control\TimeZoneInformation',

    N'Bias',

    @time_zone_adjustment OUTPUT,

    N'no_output'

    IF ((PLATFORM() & 0x1) = 0x1) -- NT

    SELECT @time_zone_adjustment = -ISNULL(@time_zone_adjustment, 0)

    ELSE

    SELECT @time_zone_adjustment = -CONVERT(INT, CONVERT(BINARY(2), ISNULL(@time_zone_adjustment, 0)))

    EXECUTE master.dbo.xp_instance_regread N'HKEY_LOCAL_MACHINE',

    N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',

    N'MSXPollInterval',

    @poll_interval OUTPUT,

    N'no_output'

    SELECT @poll_interval = ISNULL(@poll_interval, 60) -- This should be the same as DEF_REG_MSX_POLL_INTERVAL

    EXECUTE master.dbo.xp_instance_regread N'HKEY_LOCAL_MACHINE',

    N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',

    N'MSXServerName',

    @current_msx_server OUTPUT,

    N'no_output'

    SELECT @current_msx_server = LTRIM(RTRIM(@current_msx_server))

    -- Check if this machine is an MSX (and therefore cannot be enlisted into another MSX)

    IF (EXISTS (SELECT *

    FROM msdb.dbo.systargetservers))

    BEGIN

    --Get local server/instance name

    SELECT @local_machine_name = UPPER(CONVERT(NVARCHAR(30), SERVERPROPERTY('ServerName')))

    RAISERROR(14299, -1, -1, @local_machine_name)

    RETURN(1) -- Failure

    END

    -- Check if the MSX supplied is the same as the local machine (this is not allowed)

    /* IF (UPPER(@local_machine_name) = UPPER(@msx_server_name))

    BEGIN

    RAISERROR(14297, -1, -1)

    RETURN(1) -- Failure

    END*/

    -- Check if MSDB has be re-installed since we enlisted

    IF (@current_msx_server IS NOT NULL) AND

    (NOT EXISTS (SELECT *

    FROM msdb.dbo.sqlagent_info

    WHERE (attribute = 'DateEnlisted')))

    BEGIN

    -- User is tring to [re]enlist after a re-install, so we have to forcefully defect before

    -- we can fully enlist again

    EXECUTE msdb.dbo.sp_msx_defect @forced_defection = 1

    SELECT @current_msx_server = NULL

    END

    -- Check if we are already enlisted, in which case we re-enlist

    IF ((@current_msx_server IS NOT NULL) AND (@current_msx_server <> N''))

    BEGIN

    IF (UPPER(@current_msx_server) = UPPER(@msx_server_name))

    BEGIN

    -- Update the [existing] enlistment

    SELECT @local_time = CONVERT(NVARCHAR, GETDATE(), 112) + N' ' + CONVERT(NVARCHAR, GETDATE(), 108)

    EXECUTE @retval = master.dbo.xp_msx_enlist 2, @msx_server_name, @nt_user, @location, @time_zone_adjustment, @local_time, @poll_interval

    RETURN(@retval) -- 0 means success

    END

    ELSE

    BEGIN

    RAISERROR(14296, -1, -1, @current_msx_server)

    RETURN(1) -- Failure

    END

    END

    -- If we get this far then we're dealing with a new enlistment...

    -- Check if the MSX supplied exists on the network

    IF (@ping_server = 1)

    BEGIN

    DECLARE @msx_machine_name NVARCHAR (30)

    DECLARE @char_index INT

    SELECT @char_index = CHARINDEX (N'\', @msx_server_name)

    IF (@char_index > 0)

    BEGIN

    SELECT @msx_machine_name = LEFT (@msx_server_name, @char_index - 1)

    END

    ELSE

    BEGIN

    SELECT @msx_machine_name = @msx_server_name

    END

    IF ((PLATFORM() & 0x2) = 0x2) -- Win9x

    BEGIN

    EXECUTE(N'CREATE TABLE #output (output NVARCHAR(1024) COLLATE database_default)

    SET NOCOUNT ON

    INSERT INTO #output

    EXECUTE master.dbo.xp_cmdshell N''net view \\' + @msx_machine_name + N'''

    IF (EXISTS (SELECT *

    FROM #output

    WHERE (output LIKE N''% 53%'')))

    RAISERROR(14262, -1, -1, N''@msx_server_name'', N''' + @msx_machine_name + N''') WITH SETERROR')

    IF (@@error <> 0)

    RETURN(1) -- Failure

    END

    ELSE

    BEGIN

    EXECUTE(N'DECLARE @retval INT

    SET NOCOUNT ON

    EXECUTE @retval = master.dbo.xp_cmdshell N''net view \\' + @msx_machine_name + N' > nul'', no_output

    IF (@retval <> 0)

    RAISERROR(14262, -1, -1, N''@msx_server_name'', N''' + @msx_machine_name + N''') WITH SETERROR')

    IF (@@error <> 0)

    RETURN(1) -- Failure

    END

    END

    -- If no location is supplied, generate one (such as we can)

    IF (@location IS NULL)

    EXECUTE msdb.dbo.sp_generate_server_description @location OUTPUT

    SELECT @local_time = CONVERT(NVARCHAR, GETDATE(), 112) + ' ' + CONVERT(NVARCHAR, GETDATE(), 108)

    EXECUTE @retval = master.dbo.xp_msx_enlist 0, @msx_server_name, @nt_user, @location, @time_zone_adjustment, @local_time, @poll_interval

    IF (@retval = 0)

    BEGIN

    EXECUTE master.dbo.xp_instance_regwrite N'HKEY_LOCAL_MACHINE',

    N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',

    N'MSXServerName',

    N'REG_SZ',

    @msx_server_name

    IF (@current_msx_server IS NOT NULL)

    RAISERROR(14228, 0, 1, @current_msx_server, @msx_server_name)

    ELSE

    RAISERROR(14229, 0, 1, @msx_server_name)

    -- Add entry to sqlagent_info

    INSERT INTO msdb.dbo.sqlagent_info (attribute, value) VALUES ('DateEnlisted', CONVERT(VARCHAR(10), GETDATE(), 112))

    END

    RETURN(@retval) -- 0 means success

    END

    go

    /**************************************************************/

    /* SP_MSX_DEFECT */

    /**************************************************************/

    PRINT ''

    PRINT 'Creating procedure sp_msx_defect...'

    go

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = N'sp_msx_defect')

    AND (type = 'P')))

    DROP PROCEDURE sp_msx_defect

    go

    CREATE PROCEDURE sp_msx_defect

    @forced_defection BIT = 0

    AS

    BEGIN

    DECLARE @current_msx_server NVARCHAR(30)

    DECLARE @retval INT

    DECLARE @jobs_deleted INT

    DECLARE @polling_interval INT

    DECLARE @nt_user NVARCHAR(100)

    SET NOCOUNT ON

    -- Only a sysadmin can do this

    IF (ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) <> 1)

    BEGIN

    RAISERROR(15003, 16, 1, N'sysadmin')

    RETURN(1) -- Failure

    END

    SELECT @retval = 0

    SELECT @jobs_deleted = 0

    -- Get the current MSX server name from the registry

    EXECUTE master.dbo.xp_instance_regread N'HKEY_LOCAL_MACHINE',

    N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',

    N'MSXServerName',

    @current_msx_server OUTPUT,

    N'no_output'

    SELECT @current_msx_server = LTRIM(RTRIM(@current_msx_server))

    IF ((@current_msx_server IS NULL) OR (@current_msx_server = N''))

    BEGIN

    RAISERROR(14298, -1, -1)

    RETURN(1) -- Failure

    END

    SELECT @nt_user = ISNULL(NT_CLIENT(), ISNULL(SUSER_SNAME(), FORMATMESSAGE(14205)))

    EXECUTE @retval = master.dbo.xp_msx_enlist 1, @current_msx_server, @nt_user

    IF (@retval <> 0) AND (@forced_defection = 0)

    RETURN(1) -- Failure

    -- Clear the MSXServerName registry entry

    EXECUTE master.dbo.xp_instance_regwrite N'HKEY_LOCAL_MACHINE',

    N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',

    N'MSXServerName',

    N'REG_SZ',

    N''

    -- Delete the MSXPollingInterval registry entry

    EXECUTE master.dbo.xp_instance_regread N'HKEY_LOCAL_MACHINE',

    N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',

    N'MSXPollInterval',

    @polling_interval OUTPUT,

    N'no_output'

    IF (@polling_interval IS NOT NULL)

    EXECUTE master.dbo.xp_instance_regdeletevalue N'HKEY_LOCAL_MACHINE',

    N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',

    N'MSXPollInterval'

    -- Remove the entry from sqlagent_info

    DELETE FROM msdb.dbo.sqlagent_info

    WHERE (attribute = N'DateEnlisted')

    -- Delete all the jobs that originated from the MSX

    -- NOTE: We can't use sp_delete_job here since sp_delete_job checks if the caller is

    -- SQLServerAgent (only SQLServerAgent can delete non-local jobs).

    EXECUTE msdb.dbo.sp_delete_all_msx_jobs @current_msx_server, @jobs_deleted OUTPUT

    RAISERROR(14227, 0, 1, @current_msx_server, @jobs_deleted)

    -- If a forced defection was performed, attempt to notify the MSXOperator

    IF (@forced_defection = 1)

    BEGIN

    DECLARE @network_address NVARCHAR(100)

    DECLARE @command NVARCHAR(512)

    DECLARE @local_machine_name NVARCHAR(30)

    DECLARE @res_warning NVARCHAR(300)

    SELECT @network_address = netsend_address

    FROM msdb.dbo.sysoperators

    WHERE (name = N'MSXOperator')

    IF (@network_address IS NOT NULL)

    BEGIN

    EXECUTE @retval = master.dbo.xp_getnetname @local_machine_name OUTPUT

    IF (@retval <> 0)

    RETURN(1) -- Failure

    SELECT @res_warning = FORMATMESSAGE(14217)

    SELECT @command = N'NET SEND ' + @network_address + N' ' + @res_warning

    SELECT @command = STUFF(@command, PATINDEX(N'%[%%]s%', @command), 2, NT_CLIENT())

    SELECT @command = STUFF(@command, PATINDEX(N'%[%%]s%', @command), 2, @local_machine_name)

    EXECUTE master.dbo.xp_cmdshell @command, no_output

    END

    END

    -- Delete the 'MSXOperator' (must do this last)

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysoperators

    WHERE (name = N'MSXOperator')))

    EXECUTE msdb.dbo.sp_delete_operator @name = N'MSXOperator'

    RETURN(0) -- 0 means success

    END

    go

    /**************************************************************/

    /* SP_ENLIST_TSX */

    /**************************************************************/

    PRINT ''

    PRINT 'Creating procedure sp_enlist_tsx'

    go

    IF EXISTS (SELECT name FROM sysobjects

    WHERE name = 'sp_enlist_tsx' AND type = 'P')

    DROP PROCEDURE sp_enlist_tsx

    GO

    print N'Creating stored procedure sp_enlist_tsx'

    go

    create proc sp_enlist_tsx

    @Action int,-- 0 - enlist; 1 - defect; 2 - update

    @ServerName nvarchar(30),-- tsx server name

    @Location nvarchar(200),-- tsx server location

    @TimeZoneAdjustment int,-- tsx server time zone adjustment

    @LocalTime datetime,-- tsx server local time

    @NTUserName nvarchar(100),-- name of the user performing the enlistment

    @PollInterval int-- polling interval

    as

    begin

    SET NOCOUNT ON

    /* check permissions */

    IF ((ISNULL(IS_MEMBER(N'TargetServersRole'), 0) = 0) AND

    (ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) = 0))

    begin

    raiserror(15003,-1,-1, N'TargetServersRole')

    return 1

    end

    /* check input parameters */

    if @ServerName is null

    begin

    raiserror(14043, -1, -1, '@ServerName')

    return 2

    end

    select @ServerName = LTRIM(@ServerName)

    select @ServerName = RTRIM(@ServerName)

    if @ServerName = ''

    begin

    raiserror(21263, -1, -1, '@ServerName')

    return 3

    end

    if @Action <> 1 And @Action <> 2

    begin

    /* default action is to enlist */

    select @Action = 0

    end

    if @Action = 0 /* enlisting */

    begin

    /* check input parameters */

    if @NTUserName is null

    begin

    raiserror(14043, -1, -1, '@NTUserName')

    return 4

    end

    select @NTUserName = LTRIM(@NTUserName)

    select @NTUserName = RTRIM(@NTUserName)

    if @NTUserName = ''

    begin

    raiserror(21263, -1, -1, '@NTUserName')

    return 5

    end

    /* check if local server is already configured as TSX machine */

    declare @msx_server_name NVARCHAR(128)

    select @msx_server_name = N''

    execute master.dbo.xp_instance_regread

    N'HKEY_LOCAL_MACHINE',

    N'Software\Microsoft\MSSQLServer\SQLServerAgent',

    N'MSXServerName',

    @msx_server_name OUTPUT

    select @msx_server_name = LTRIM(@msx_server_name)

    select @msx_server_name = RTRIM(@msx_server_name)

    if @msx_server_name <> N''

    begin

    raiserror(14360, -1, -1, @@SERVERNAME)

    return 6

    end

    /*

    * check that local server is not running a desktop SKU,

    * i.e. Win9x, Office, or MSDE

    */

    if( PLATFORM() & 0x100 = 0x100 )

    begin

    raiserror(14362, -1, -1)

    return 8

    end

    /* check if we have any MSXOperators defined */

    if not exists (SELECT * FROM msdb.dbo.sysoperators WHERE name = N'MSXOperator')

    begin

    raiserror(14363, -1, -1)

    return 9

    end

    /* all checks have passed, insert new row into systargetservers table */

    INSERT INTO msdb.dbo.systargetservers

    (

    server_name,

    location,

    time_zone_adjustment,

    enlist_date,

    last_poll_date,

    status,

    local_time_at_last_poll,

    enlisted_by_nt_user,

    poll_interval

    )

    VALUES

    (

    @ServerName,

    @Location,

    @TimeZoneAdjustment,

    GETDATE(),

    GETDATE(),

    1,

    @LocalTime,

    @NTUserName,

    @PollInterval

    )

    /* delete hanging rows from sysdownloadlist */

    DELETE FROM msdb.dbo.sysdownloadlist

    WHERE target_server = @ServerName

    end

    if @Action = 2 /* updating existing enlistment */

    begin

    /* check if we have any MSXOperators defined */

    if not exists (SELECT * FROM msdb.dbo.sysoperators WHERE name = N'MSXOperator')

    begin

    raiserror(14363, -1, -1)

    return 10

    end

    /* check if TSX machine is already enlisted */

    If not exists (SELECT * FROM msdb.dbo.systargetservers WHERE server_name =@ServerName)

    begin

    raiserror(14364, -1, -1)

    return 11

    end

    if @Location is null /* don't update the location if it is not supplied */

    begin

    UPDATE msdb.dbo.systargetservers SET

    time_zone_adjustment = @TimeZoneAdjustment,

    poll_interval = @PollInterval

    WHERE (server_name = @ServerName)

    end

    else

    begin

    UPDATE msdb.dbo.systargetservers SET

    location = @Location,

    time_zone_adjustment = @TimeZoneAdjustment,

    poll_interval = @PollInterval

    WHERE (server_name = @ServerName)

    end

    end

    if @Action = 1 /* defecting */

    begin

    if (exists (SELECT * FROM msdb.dbo.systargetservers WHERE server_name = @ServerName))

    begin

    execute msdb.dbo.sp_delete_targetserver

    @server_name = @ServerName,

    @post_defection = 0

    end

    else

    begin

    DELETE FROM msdb.dbo.sysdownloadlist

    WHERE (target_server = @ServerName)

    end

    end

    if @Action = 0 Or @Action = 2 /* enlisting or updating existing enlistment */

    begin

    /* select resultset to return to the caller */

    SELECT

    id,

    name,

    enabled,

    email_address,

    pager_address,

    netsend_address,

    weekday_pager_start_time,

    weekday_pager_end_time,

    saturday_pager_start_time,

    saturday_pager_end_time,

    sunday_pager_start_time,

    sunday_pager_end_time,

    pager_days

    FROM

    msdb.dbo.sysoperators WHERE (name = N'MSXOperator')

    end

    end

    go

    grant execute on sp_enlist_tsx to public

    go

    /**************************************************************/

    /* SP_GET_SQLAGENT_PROPERTIES */

    /**************************************************************/

    PRINT ''

    PRINT 'Creating procedure sp_get_sqlagent_properties...'

    go

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = N'sp_get_sqlagent_properties')

    AND (type = 'P')))

    DROP PROCEDURE sp_get_sqlagent_properties

    go

    CREATE PROCEDURE sp_get_sqlagent_properties

    AS

    BEGIN

    DECLARE @auto_start INT

    DECLARE @startup_account NVARCHAR(100)

    DECLARE @msx_server_name NVARCHAR(30)

    -- Non-SQLDMO exposed properties

    DECLARE @sqlserver_restart INT

    DECLARE @jobhistory_max_rows INT

    DECLARE @jobhistory_max_rows_per_job INT

    DECLARE @errorlog_file NVARCHAR(255)

    DECLARE @errorlogging_level INT

    DECLARE @error_recipient NVARCHAR(30)

    DECLARE @monitor_autostart INT

    DECLARE @local_host_server NVARCHAR(30)

    DECLARE @job_shutdown_timeout INT

    DECLARE @cmdexec_account VARBINARY(64)

    DECLARE @regular_connections INT

    DECLARE @host_login_name sysname

    DECLARE @host_login_password VARBINARY(512)

    DECLARE @login_timeout INT

    DECLARE @idle_cpu_percent INT

    DECLARE @idle_cpu_duration INT

    DECLARE @oem_errorlog INT

    DECLARE @sysadmin_only INT

    DECLARE @email_profile NVARCHAR(64)

    DECLARE @email_save_in_sent_folder INT

    DECLARE @cpu_poller_enabled INT

    SET NOCOUNT ON

    -- NOTE: We return all SQLServerAgent properties at one go for performance reasons

    -- Read the values from the registry

    IF ((PLATFORM() & 0x1) = 0x1) -- NT

    BEGIN

    DECLARE @key NVARCHAR(200)

    SELECT @key = N'SYSTEM\CurrentControlSet\Services\'

    IF (SERVERPROPERTY('INSTANCENAME') IS NOT NULL)

    SELECT @key = @key + N'SQLAgent$' + CONVERT (sysname, SERVERPROPERTY('INSTANCENAME'))

    ELSE

    SELECT @key = @key + N'SQLServerAgent'

    EXECUTE master.dbo.xp_regread N'HKEY_LOCAL_MACHINE',

    @key,

    N'Start',

    @auto_start OUTPUT,

    N'no_output'

    EXECUTE master.dbo.xp_regread N'HKEY_LOCAL_MACHINE',

    @key,

    N'ObjectName',

    @startup_account OUTPUT,

    N'no_output'

    END

    ELSE

    BEGIN

    SELECT @auto_start = 3 -- Manual start

    SELECT @startup_account = NULL

    END

    EXECUTE master.dbo.xp_instance_regread N'HKEY_LOCAL_MACHINE',

    N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',

    N'MSXServerName',

    @msx_server_name OUTPUT,

    N'no_output'

    -- Non-SQLDMO exposed properties

    EXECUTE master.dbo.xp_instance_regread N'HKEY_LOCAL_MACHINE',

    N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',

    N'RestartSQLServer',

    @sqlserver_restart OUTPUT,

    N'no_output'

    EXECUTE master.dbo.xp_instance_regread N'HKEY_LOCAL_MACHINE',

    N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',

    N'JobHistoryMaxRows',

    @jobhistory_max_rows OUTPUT,

    N'no_output'

    EXECUTE master.dbo.xp_instance_regread N'HKEY_LOCAL_MACHINE',

    N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',

    N'JobHistoryMaxRowsPerJob',

    @jobhistory_max_rows_per_job OUTPUT,

    N'no_output'

    EXECUTE master.dbo.xp_instance_regread N'HKEY_LOCAL_MACHINE',

    N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',

    N'ErrorLogFile',

    @errorlog_file OUTPUT,

    N'no_output'

    EXECUTE master.dbo.xp_instance_regread N'HKEY_LOCAL_MACHINE',

    N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',

    N'ErrorLoggingLevel',

    @errorlogging_level OUTPUT,

    N'no_output'

    EXECUTE master.dbo.xp_instance_regread N'HKEY_LOCAL_MACHINE',

    N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',

    N'ErrorMonitor',

    @error_recipient OUTPUT,

    N'no_output'

    EXECUTE master.dbo.xp_instance_regread N'HKEY_LOCAL_MACHINE',

    N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',

    N'MonitorAutoStart',

    @monitor_autostart OUTPUT,

    N'no_output'

    EXECUTE master.dbo.xp_instance_regread N'HKEY_LOCAL_MACHINE',

    N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',

    N'ServerHost',

    @local_host_server OUTPUT,

    N'no_output'

    EXECUTE master.dbo.xp_instance_regread N'HKEY_LOCAL_MACHINE',

    N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',

    N'JobShutdownTimeout',

    @job_shutdown_timeout OUTPUT,

    N'no_output'

    EXECUTE master.dbo.xp_instance_regread N'HKEY_LOCAL_MACHINE',

    N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',

    N'CmdExecAccount',

    @cmdexec_account OUTPUT,

    N'no_output'

    EXECUTE master.dbo.xp_instance_regread N'HKEY_LOCAL_MACHINE',

    N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',

    N'RegularConnections',

    @regular_connections OUTPUT,

    N'no_output'

    DECLARE @os int

    EXECUTE master.dbo.xp_MSplatform @os OUTPUT

    IF (@OS = 2)

    EXECUTE master.dbo.xp_instance_regread N'HKEY_LOCAL_MACHINE',

    N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',

    N'HostLoginID',

    @host_login_name OUTPUT,

    N'no_output'

    ELSE

    EXECUTE master.dbo.xp_sqlagent_param 0,

    N'HostLoginID',

    @host_login_name OUTPUT

    --check permissions

    IF (is_srvrolemember(N'sysadmin') = 1)

    begin

    IF (@OS = 2)

    EXECUTE master.dbo.xp_instance_regread N'HKEY_LOCAL_MACHINE',

    N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',

    N'HostPassword',

    @host_login_password OUTPUT,

    N'no_output'

    ELSE

    EXECUTE master.dbo.xp_sqlagent_param 0,

    N'HostPassword',

    @host_login_password OUTPUT

    end

    ELSE

    SELECT @host_login_password = 0

    EXECUTE master.dbo.xp_instance_regread N'HKEY_LOCAL_MACHINE',

    N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',

    N'LoginTimeout',

    @login_timeout OUTPUT,

    N'no_output'

    EXECUTE master.dbo.xp_instance_regread N'HKEY_LOCAL_MACHINE',

    N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',

    N'IdleCPUPercent',

    @idle_cpu_percent OUTPUT,

    N'no_output'

    EXECUTE master.dbo.xp_instance_regread N'HKEY_LOCAL_MACHINE',

    N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',

    N'IdleCPUDuration',

    @idle_cpu_duration OUTPUT,

    N'no_output'

    EXECUTE master.dbo.xp_instance_regread N'HKEY_LOCAL_MACHINE',

    N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',

    N'OemErrorLog',

    @oem_errorlog OUTPUT,

    N'no_output'

    EXECUTE master.dbo.xp_instance_regread N'HKEY_LOCAL_MACHINE',

    N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',

    N'SysAdminOnly',

    @sysadmin_only OUTPUT,

    N'no_output'

    EXECUTE master.dbo.xp_instance_regread N'HKEY_LOCAL_MACHINE',

    N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',

    N'EmailProfile',

    @email_profile OUTPUT,

    N'no_output'

    EXECUTE master.dbo.xp_instance_regread N'HKEY_LOCAL_MACHINE',

    N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',

    N'EmailSaveSent',

    @email_save_in_sent_folder OUTPUT,

    N'no_output'

    EXECUTE master.dbo.xp_instance_regread N'HKEY_LOCAL_MACHINE',

    N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',

    N'CoreEngineMask',

    @cpu_poller_enabled OUTPUT,

    N'no_output'

    IF (@cpu_poller_enabled IS NOT NULL)

    SELECT @cpu_poller_enabled = CASE WHEN (@cpu_poller_enabled & 32) = 32 THEN 0 ELSE 1 END

    -- Return the values to the client

    SELECT auto_start = CASE @auto_start

    WHEN 2 THEN 1 -- 2 means auto-start

    WHEN 3 THEN 0 -- 3 means don't auto-start

    ELSE 0 -- Safety net

    END,

    msx_server_name = @msx_server_name,

    sqlagent_type = (SELECT CASE

    WHEN (COUNT(*) = 0) AND (ISNULL(DATALENGTH(@msx_server_name), 0) = 0) THEN 1 -- Standalone

    WHEN (COUNT(*) = 0) AND (ISNULL(DATALENGTH(@msx_server_name), 0) > 0) THEN 2 -- TSX

    WHEN (COUNT(*) > 0) AND (ISNULL(DATALENGTH(@msx_server_name), 0) = 0) THEN 3 -- MSX

    WHEN (COUNT(*) > 0) AND (ISNULL(DATALENGTH(@msx_server_name), 0) > 0) THEN 0 -- Multi-Level MSX (currently invalid)

    ELSE 0 -- Invalid

    END

    FROM msdb.dbo.systargetservers),

    startup_account = @startup_account,

    -- Non-SQLDMO exposed properties

    sqlserver_restart = @sqlserver_restart,

    jobhistory_max_rows = @jobhistory_max_rows,

    jobhistory_max_rows_per_job = @jobhistory_max_rows_per_job,

    errorlog_file = @errorlog_file,

    errorlogging_level = ISNULL(@errorlogging_level, 7),

    error_recipient = @error_recipient,

    monitor_autostart = ISNULL(@monitor_autostart, 0),

    local_host_server = @local_host_server,

    job_shutdown_timeout = ISNULL(@job_shutdown_timeout, 15),

    cmdexec_account = @cmdexec_account,

    regular_connections = ISNULL(@regular_connections, 0),

    host_login_name = @host_login_name,

    host_login_password = @host_login_password,

    login_timeout = ISNULL(@login_timeout, 30),

    idle_cpu_percent = ISNULL(@idle_cpu_percent, 10),

    idle_cpu_duration = ISNULL(@idle_cpu_duration, 600),

    oem_errorlog = ISNULL(@oem_errorlog, 0),

    sysadmin_only = ISNULL(@sysadmin_only, 0),

    email_profile = @email_profile,

    email_save_in_sent_folder = ISNULL(@email_save_in_sent_folder, 0),

    cpu_poller_enabled = ISNULL(@cpu_poller_enabled, 0)

    END

    go

    /**************************************************************/

    /* SP_SET_SQLAGENT_PROPERTIES */

    /**************************************************************/

    IF EXISTS (SELECT * FROM msdb.dbo.sysobjects WHERE name = N'sp_set_sqlagent_properties' AND type = 'P')

    BEGIN

    DROP PROCEDURE dbo.sp_set_sqlagent_properties

    END

    go

    PRINT ''

    PRINT 'Create procedure sp_set_sqlagent_properties...'

    go

    CREATE PROCEDURE dbo.sp_set_sqlagent_properties

    @auto_start INT = NULL, -- 1 or 0

    -- Non-SQLDMO exposed properties

    @sqlserver_restart INT = NULL, -- 1 or 0

    @jobhistory_max_rows INT = NULL, -- No maximum = -1, otherwise must be > 1

    @jobhistory_max_rows_per_job INT = NULL, -- 1 to @jobhistory_max_rows

    @errorlog_file NVARCHAR(255) = NULL, -- Full drive\pathame of errorlog file

    @errorlogging_level INT = NULL, -- 1 = error, 2 = warning, 4 = information

    @error_recipient NVARCHAR(30) = NULL, -- Network address of error popup recipient

    @monitor_autostart INT = NULL, -- 1 or 0

    @local_host_server NVARCHAR(30) = NULL, -- Alias of local host server

    @job_shutdown_timeout INT = NULL, -- 5 to 600 seconds

    @cmdexec_account VARBINARY(64) = NULL, -- CmdExec account information

    @regular_connections INT = NULL, -- 1 or 0

    @host_login_name sysname = NULL, -- Login name (if regular_connections = 1)

    @host_login_password VARBINARY(512) = NULL, -- Login password (if regular_connections = 1)

    @login_timeout INT = NULL, -- 5 to 45 (seconds)

    @idle_cpu_percent INT = NULL, -- 1 to 100

    @idle_cpu_duration INT = NULL, -- 20 to 86400 seconds

    @oem_errorlog INT = NULL, -- 1 or 0

    @sysadmin_only INT = NULL, -- 1 or 0

    @email_profile NVARCHAR(64) = NULL, -- Email profile name

    @email_save_in_sent_folder INT = NULL, -- 1 or 0

    @cpu_poller_enabled INT = NULL -- 1 or 0

    AS

    BEGIN

    -- NOTE: We set all SQLServerAgent properties at one go for performance reasons.

    -- NOTE: You cannot set the value of the properties msx_server_name, is_msx or

    -- startup_account - they are all read only.

    DECLARE @res_valid_range NVARCHAR(100)

    DECLARE @existing_core_engine_mask INT

    SET NOCOUNT ON

    -- Remove any leading/trailing spaces from parameters

    SELECT @errorlog_file = LTRIM(RTRIM(@errorlog_file))

    SELECT @error_recipient = LTRIM(RTRIM(@error_recipient))

    SELECT @local_host_server = LTRIM(RTRIM(@local_host_server))

    SELECT @host_login_name = LTRIM(RTRIM(@host_login_name))

    SELECT @email_profile = LTRIM(RTRIM(@email_profile))

    -- Make sure values (if supplied) are good

    IF (@auto_start IS NOT NULL)

    BEGIN

    -- NOTE: When setting the the services start value, 2 == auto-start, 3 == Don't auto-start

    SELECT @auto_start = CASE @auto_start

    WHEN 0 THEN 3

    WHEN 1 THEN 2

    ELSE 3 -- Assume non auto-start if passed a junk value

    END

    END

    -- Non-SQLDMO exposed properties

    IF ((@sqlserver_restart IS NOT NULL) AND (@sqlserver_restart <> 0))

    SELECT @sqlserver_restart = 1

    IF (@jobhistory_max_rows IS NOT NULL)

    BEGIN

    SELECT @res_valid_range = FORMATMESSAGE(14207)

    IF ((@jobhistory_max_rows < -1) OR (@jobhistory_max_rows = 0))

    BEGIN

    RAISERROR(14266, -1, -1, '@jobhistory_max_rows', @res_valid_range)

    RETURN(1) -- Failure

    END

    END

    ELSE

    BEGIN

    EXECUTE master.dbo.xp_instance_regread N'HKEY_LOCAL_MACHINE',

    N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',

    N'JobHistoryMaxRows',

    @jobhistory_max_rows OUTPUT,

    N'no_output'

    SELECT @jobhistory_max_rows = ISNULL(@jobhistory_max_rows, -1)

    END

    IF (@jobhistory_max_rows_per_job IS NOT NULL)

    BEGIN

    IF (@jobhistory_max_rows = -1)

    SELECT @jobhistory_max_rows_per_job = 0

    ELSE

    BEGIN

    IF ((@jobhistory_max_rows_per_job @jobhistory_max_rows))

    BEGIN

    SELECT @res_valid_range = N'1..' + CONVERT(NVARCHAR, @jobhistory_max_rows)

    RAISERROR(14266, -1, -1, '@jobhistory_max_rows', @res_valid_range)

    RETURN(1) -- Failure

    END

    END

    END

    IF (@errorlogging_level IS NOT NULL) AND ((@errorlogging_level 7))

    BEGIN

    RAISERROR(14266, -1, -1, '@errorlogging_level', '1..7')

    RETURN(1) -- Failure

    END

    IF (@monitor_autostart IS NOT NULL) AND ((@monitor_autostart 1))

    BEGIN

    RAISERROR(14266, -1, -1, '@monitor_autostart', '0, 1')

    RETURN(1) -- Failure

    END

    IF (@job_shutdown_timeout IS NOT NULL) AND ((@job_shutdown_timeout 600))

    BEGIN

    RAISERROR(14266, -1, -1, '@job_shutdown_timeout', '5..600')

    RETURN(1) -- Failure

    END

    IF (@regular_connections IS NOT NULL) AND ((@regular_connections 1))

    BEGIN

    RAISERROR(14266, -1, -1, '@regular_connections', '0, 1')

    RETURN(1) -- Failure

    END

    IF (@login_timeout IS NOT NULL) AND ((@login_timeout 45))

    BEGIN

    RAISERROR(14266, -1, -1, '@login_timeout', '5..45')

    RETURN(1) -- Failure

    END

    IF ((@idle_cpu_percent IS NOT NULL) AND ((@idle_cpu_percent 100)))

    BEGIN

    RAISERROR(14266, -1, -1, '@idle_cpu_percent', '10..100')

    RETURN(1) -- Failure

    END

    IF ((@idle_cpu_duration IS NOT NULL) AND ((@idle_cpu_duration 86400)))

    BEGIN

    RAISERROR(14266, -1, -1, '@idle_cpu_duration', '20..86400')

    RETURN(1) -- Failure

    END

    IF (@oem_errorlog IS NOT NULL) AND ((@oem_errorlog 1))

    BEGIN

    RAISERROR(14266, -1, -1, '@oem_errorlog', '0, 1')

    RETURN(1) -- Failure

    END

    IF (@sysadmin_only IS NOT NULL) AND ((@sysadmin_only 1))

    BEGIN

    RAISERROR(14266, -1, -1, '@sysadmin_only', '0, 1')

    RETURN(1) -- Failure

    END

    IF (@email_save_in_sent_folder IS NOT NULL) AND ((@email_save_in_sent_folder 1))

    BEGIN

    RAISERROR(14266, -1, -1, 'email_save_in_sent_folder', '0, 1')

    RETURN(1) -- Failure

    END

    IF (@cpu_poller_enabled IS NOT NULL) AND ((@cpu_poller_enabled 1))

    BEGIN

    RAISERROR(14266, -1, -1, 'cpu_poller_enabled', '0, 1')

    RETURN(1) -- Failure

    END

    -- Write out the values

    IF (@auto_start IS NOT NULL)

    BEGIN

    IF ((PLATFORM() & 0x1) = 0x1) -- NT

    BEGIN

    DECLARE @key NVARCHAR(200)

    SELECT @key = N'SYSTEM\CurrentControlSet\Services\'

    IF (SERVERPROPERTY('INSTANCENAME') IS NOT NULL)

    SELECT @key = @key + N'SQLAgent$' + CONVERT (sysname, SERVERPROPERTY('INSTANCENAME'))

    ELSE

    SELECT @key = @key + N'SQLServerAgent'

    EXECUTE master.dbo.xp_regwrite N'HKEY_LOCAL_MACHINE',

    @key,

    N'Start',

    N'REG_DWORD',

    @auto_start

    END

    ELSE

    RAISERROR(14546, 16, 1, '@auto_start')

    END

    -- Non-SQLDMO exposed properties

    IF (@sqlserver_restart IS NOT NULL)

    EXECUTE master.dbo.xp_instance_regwrite N'HKEY_LOCAL_MACHINE',

    N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',

    N'RestartSQLServer',

    N'REG_DWORD',

    @sqlserver_restart

    IF (@jobhistory_max_rows IS NOT NULL)

    EXECUTE master.dbo.xp_instance_regwrite N'HKEY_LOCAL_MACHINE',

    N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',

    N'JobHistoryMaxRows',

    N'REG_DWORD',

    @jobhistory_max_rows

    IF (@jobhistory_max_rows_per_job IS NOT NULL)

    EXECUTE master.dbo.xp_instance_regwrite N'HKEY_LOCAL_MACHINE',

    N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',

    N'JobHistoryMaxRowsPerJob',

    N'REG_DWORD',

    @jobhistory_max_rows_per_job

    IF (@errorlog_file IS NOT NULL)

    EXECUTE master.dbo.xp_instance_regwrite N'HKEY_LOCAL_MACHINE',

    N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',

    N'ErrorLogFile',

    N'REG_SZ',

    @errorlog_file

    IF (@errorlogging_level IS NOT NULL)

    EXECUTE master.dbo.xp_instance_regwrite N'HKEY_LOCAL_MACHINE',

    N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',

    N'ErrorLoggingLevel',

    N'REG_DWORD',

    @errorlogging_level

    IF (@error_recipient IS NOT NULL)

    EXECUTE master.dbo.xp_instance_regwrite N'HKEY_LOCAL_MACHINE',

    N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',

    N'ErrorMonitor',

    N'REG_SZ',

    @error_recipient

    IF (@monitor_autostart IS NOT NULL)

    EXECUTE master.dbo.xp_instance_regwrite N'HKEY_LOCAL_MACHINE',

    N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',

    N'MonitorAutoStart',

    N'REG_DWORD',

    @monitor_autostart

    IF (@local_host_server IS NOT NULL)

    EXECUTE master.dbo.xp_instance_regwrite N'HKEY_LOCAL_MACHINE',

    N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',

    N'ServerHost',

    N'REG_SZ',

    @local_host_server

    IF (@job_shutdown_timeout IS NOT NULL)

    EXECUTE master.dbo.xp_instance_regwrite N'HKEY_LOCAL_MACHINE',

    N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',

    N'JobShutdownTimeout',

    N'REG_DWORD',

    @job_shutdown_timeout

    IF (@cmdexec_account IS NOT NULL)

    EXECUTE master.dbo.xp_instance_regwrite N'HKEY_LOCAL_MACHINE',

    N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',

    N'CmdExecAccount',

    N'REG_BINARY',

    @cmdexec_account

    IF (@regular_connections IS NOT NULL)

    EXECUTE master.dbo.xp_instance_regwrite N'HKEY_LOCAL_MACHINE',

    N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',

    N'RegularConnections',

    N'REG_DWORD',

    @regular_connections

    DECLARE @os int

    EXECUTE master.dbo.xp_MSplatform @os OUTPUT

    IF (@regular_connections = 0)

    BEGIN

    IF (@OS = 2)

    BEGIN

    EXECUTE master.dbo.xp_instance_regdeletevalue N'HKEY_LOCAL_MACHINE', N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent', N'HostLoginID'

    EXECUTE master.dbo.xp_instance_regdeletevalue N'HKEY_LOCAL_MACHINE', N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent', N'HostPassword'

    END

    ELSE

    BEGIN

    EXECUTE master.dbo.xp_sqlagent_param 2, N'HostLoginID'

    EXECUTE master.dbo.xp_sqlagent_param 2, N'HostPassword'

    END

    END

    IF (@host_login_name IS NOT NULL)

    BEGIN

    IF (@OS = 2)

    EXECUTE master.dbo.xp_instance_regwrite N'HKEY_LOCAL_MACHINE',

    N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',

    N'HostLoginID',

    N'REG_SZ',

    @host_login_name

    ELSE

    EXECUTE master.dbo.xp_sqlagent_param 1,

    N'HostLoginID',

    @host_login_name

    END

    IF (@host_login_password IS NOT NULL)

    BEGIN

    IF (@OS = 2)

    EXECUTE master.dbo.xp_instance_regwrite N'HKEY_LOCAL_MACHINE',

    N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',

    N'HostPassword',

    N'REG_BINARY',

    @host_login_password

    ELSE

    EXECUTE master.dbo.xp_sqlagent_param 1,

    N'HostPassword',

    @host_login_password

    END

    IF (@login_timeout IS NOT NULL)

    EXECUTE master.dbo.xp_instance_regwrite N'HKEY_LOCAL_MACHINE',

    N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',

    N'LoginTimeout',

    N'REG_DWORD',

    @login_timeout

    IF (@idle_cpu_percent IS NOT NULL)

    EXECUTE master.dbo.xp_instance_regwrite N'HKEY_LOCAL_MACHINE',

    N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',

    N'IdleCPUPercent',

    N'REG_DWORD',

    @idle_cpu_percent

    IF (@idle_cpu_duration IS NOT NULL)

    EXECUTE master.dbo.xp_instance_regwrite N'HKEY_LOCAL_MACHINE',

    N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',

    N'IdleCPUDuration',

    N'REG_DWORD',

    @idle_cpu_duration

    IF (@oem_errorlog IS NOT NULL)

    EXECUTE master.dbo.xp_instance_regwrite N'HKEY_LOCAL_MACHINE',

    N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',

    N'OemErrorLog',

    N'REG_DWORD',

    @oem_errorlog

    IF (@sysadmin_only IS NOT NULL)

    BEGIN

    IF (@sysadmin_only = 1)

    BEGIN

    EXECUTE master.dbo.xp_sqlagent_proxy_account N'DEL'

    END

    EXECUTE master.dbo.xp_instance_regwrite N'HKEY_LOCAL_MACHINE',

    N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',

    N'SysAdminOnly',

    N'REG_DWORD',

    @sysadmin_only

    END

    IF (@email_profile IS NOT NULL)

    EXECUTE master.dbo.xp_instance_regwrite N'HKEY_LOCAL_MACHINE',

    N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',

    N'EmailProfile',

    N'REG_SZ',

    @email_profile

    IF (@email_save_in_sent_folder IS NOT NULL)

    EXECUTE master.dbo.xp_instance_regwrite N'HKEY_LOCAL_MACHINE',

    N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',

    N'EmailSaveSent',

    N'REG_DWORD',

    @email_save_in_sent_folder

    IF (@cpu_poller_enabled IS NOT NULL)

    BEGIN

    EXECUTE master.dbo.xp_instance_regread N'HKEY_LOCAL_MACHINE',

    N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',

    N'CoreEngineMask',

    @existing_core_engine_mask OUTPUT,

    N'no_output'

    IF ((@existing_core_engine_mask IS NOT NULL) OR (@cpu_poller_enabled = 1))

    BEGIN

    IF (@cpu_poller_enabled = 1)

    SELECT @cpu_poller_enabled = (ISNULL(@existing_core_engine_mask, 0) & ~32)

    ELSE

    SELECT @cpu_poller_enabled = (ISNULL(@existing_core_engine_mask, 0) | 32)

    IF ((@existing_core_engine_mask IS NOT NULL) AND (@cpu_poller_enabled = 32))

    EXECUTE master.dbo.xp_instance_regdeletevalue N'HKEY_LOCAL_MACHINE',

    N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',

    N'CoreEngineMask'

    ELSE

    EXECUTE master.dbo.xp_instance_regwrite N'HKEY_LOCAL_MACHINE',

    N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',

    N'CoreEngineMask',

    N'REG_DWORD',

    @cpu_poller_enabled

    END

    END

    RETURN(0) -- Success

    END

    go

    /**************************************************************/

    /* SP_ADD_TARGETSERVERGROUP */

    /**************************************************************/

    PRINT ''

    PRINT 'Creating procedure sp_add_targetservergroup...'

    go

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = N'sp_add_targetservergroup')

    AND (type = 'P')))

    DROP PROCEDURE sp_add_targetservergroup

    go

    CREATE PROCEDURE sp_add_targetservergroup

    @name sysname

    AS

    BEGIN

    SET NOCOUNT ON

    -- Only a sysadmin can do this

    IF (ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) <> 1)

    BEGIN

    RAISERROR(15003, 16, 1, N'sysadmin')

    RETURN(1) -- Failure

    END

    -- Remove any leading/trailing spaces from parameters

    SELECT @name = LTRIM(RTRIM(@name))

    -- Check if the group already exists

    IF (EXISTS (SELECT *

    FROM msdb.dbo.systargetservergroups

    WHERE name = @name))

    BEGIN

    RAISERROR(14261, -1, -1, '@name', @name)

    RETURN(1) -- Failure

    END

    -- Disallow names with commas in them (since sp_apply_job_to_targets parses a comma-separated list of group names)

    IF (@name LIKE N'%,%')

    BEGIN

    RAISERROR(14289, -1, -1, '@name', ',')

    RETURN(1) -- Failure

    END

    INSERT INTO msdb.dbo.systargetservergroups (name)

    VALUES (@name)

    RETURN(@@error) -- 0 means success

    END

    go

    /**************************************************************/

    /* SP_UPDATE_TARGETSERVERGROUP */

    /**************************************************************/

    PRINT ''

    PRINT 'Creating procedure sp_update_targetservergroup...'

    go

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = N'sp_update_targetservergroup')

    AND (type = 'P')))

    DROP PROCEDURE sp_update_targetservergroup

    go

    CREATE PROCEDURE sp_update_targetservergroup

    @name sysname,

    @new_name sysname

    AS

    BEGIN

    SET NOCOUNT ON

    -- Only a sysadmin can do this

    IF (ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) <> 1)

    BEGIN

    RAISERROR(15003, 16, 1, N'sysadmin')

    RETURN(1) -- Failure

    END

    -- Remove any leading/trailing spaces from parameters

    SELECT @name = LTRIM(RTRIM(@name))

    SELECT @new_name = LTRIM(RTRIM(@new_name))

    -- Check if the group exists

    IF (NOT EXISTS (SELECT *

    FROM msdb.dbo.systargetservergroups

    WHERE (name = @name)))

    BEGIN

    RAISERROR(14262, -1, -1, '@name', @name)

    RETURN(1) -- Failure

    END

    -- Check if a group with the new name already exists

    IF (EXISTS (SELECT *

    FROM msdb.dbo.systargetservergroups

    WHERE (name = @new_name)))

    BEGIN

    RAISERROR(14261, -1, -1, '@new_name', @new_name)

    RETURN(1) -- Failure

    END

    -- Disallow names with commas in them (since sp_apply_job_to_targets parses a comma-separated list of group names)

    IF (@new_name LIKE N'%,%')

    BEGIN

    RAISERROR(14289, -1, -1, '@new_name', ',')

    RETURN(1) -- Failure

    END

    -- Update the group's name

    UPDATE msdb.dbo.systargetservergroups

    SET name = @new_name

    WHERE (name = @name)

    RETURN(@@error) -- 0 means success

    END

    go

    /**************************************************************/

    /* SP_DELETE_TARGETSERVERGROUP */

    /**************************************************************/

    PRINT ''

    PRINT 'Creating procedure sp_delete_targetservergroup...'

    go

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = N'sp_delete_targetservergroup')

    AND (type = 'P')))

    DROP PROCEDURE sp_delete_targetservergroup

    go

    CREATE PROCEDURE sp_delete_targetservergroup

    @name sysname

    AS

    BEGIN

    DECLARE @servergroup_id INT

    SET NOCOUNT ON

    -- Only a sysadmin can do this

    IF (ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) <> 1)

    BEGIN

    RAISERROR(15003, 16, 1, N'sysadmin')

    RETURN(1) -- Failure

    END

    -- Remove any leading/trailing spaces from parameters

    SELECT @name = LTRIM(RTRIM(@name))

    -- Check if the group exists

    SELECT @servergroup_id = servergroup_id

    FROM msdb.dbo.systargetservergroups

    WHERE (name = @name)

    IF (@servergroup_id IS NULL)

    BEGIN

    RAISERROR(14262, -1, -1, '@name', @name)

    RETURN(1) -- Failure

    END

    -- Remove the group members

    DELETE FROM msdb.dbo.systargetservergroupmembers

    WHERE (servergroup_id = @servergroup_id)

    -- Remove the group

    DELETE FROM msdb.dbo.systargetservergroups

    WHERE (name = @name)

    RETURN(@@error) -- 0 means success

    END

    go

    /**************************************************************/

    /* SP_HELP_TARGETSERVERGROUP */

    /**************************************************************/

    PRINT ''

    PRINT 'Creating procedure sp_help_targetservergroup...'

    go

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = N'sp_help_targetservergroup')

    AND (type = 'P')))

    DROP PROCEDURE sp_help_targetservergroup

    go

    CREATE PROCEDURE sp_help_targetservergroup

    @name sysname = NULL

    AS

    BEGIN

    DECLARE @servergroup_id INT

    SET NOCOUNT ON

    -- Remove any leading/trailing spaces from parameters

    SELECT @name = LTRIM(RTRIM(@name))

    IF (@name IS NULL)

    BEGIN

    -- Show all groups

    SELECT servergroup_id, name

    FROM msdb.dbo.systargetservergroups

    RETURN(@@error) -- 0 means success

    END

    ELSE

    BEGIN

    -- Check if the group exists

    SELECT @servergroup_id = servergroup_id

    FROM msdb.dbo.systargetservergroups

    WHERE (name = @name)

    IF (@servergroup_id IS NULL)

    BEGIN

    RAISERROR(14262, -1, -1, '@name', @name)

    RETURN(1) -- Failure

    END

    -- Return the members of the group

    SELECT sts.server_id,

    sts.server_name

    FROM msdb.dbo.systargetservers sts,

    msdb.dbo.systargetservergroupmembers stsgm

    WHERE (stsgm.servergroup_id = @servergroup_id)

    AND (stsgm.server_id = sts.server_id)

    RETURN(@@error) -- 0 means success

    END

    END

    go

    /**************************************************************/

    /* SP_ADD_TARGETSVRGRP_MEMBER */

    /**************************************************************/

    PRINT ''

    PRINT 'Creating procedure sp_add_targetsvgrp_member...'

    go

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = N'sp_add_targetsvrgrp_member')

    AND (type = 'P')))

    DROP PROCEDURE sp_add_targetsvrgrp_member

    go

    CREATE PROCEDURE sp_add_targetsvrgrp_member

    @group_name sysname,

    @server_name NVARCHAR(30)

    AS

    BEGIN

    DECLARE @servergroup_id INT

    DECLARE @server_id INT

    SET NOCOUNT ON

    -- Remove any leading/trailing spaces from parameters

    SELECT @group_name = LTRIM(RTRIM(@group_name))

    SELECT @server_name = LTRIM(RTRIM(@server_name))

    -- Check if the group exists

    SELECT @servergroup_id = servergroup_id

    FROM msdb.dbo.systargetservergroups

    WHERE (name = @group_name)

    IF (@servergroup_id IS NULL)

    BEGIN

    RAISERROR(14262, -1, -1, '@group_name', @group_name)

    RETURN(1) -- Failure

    END

    -- Check if the server exists

    SELECT @server_id = server_id

    FROM msdb.dbo.systargetservers

    WHERE (server_name = @server_name)

    IF (@server_id IS NULL)

    BEGIN

    RAISERROR(14262, -1, -1, '@server_name', @server_name)

    RETURN(1) -- Failure

    END

    -- Check if the server is already in this group

    IF (EXISTS (SELECT *

    FROM msdb.dbo.systargetservergroupmembers

    WHERE (servergroup_id = @servergroup_id)

    AND (server_id = @server_id)))

    BEGIN

    RAISERROR(14263, -1, -1, @server_name, @group_name)

    RETURN(1) -- Failure

    END

    -- Add the row to systargetservergroupmembers

    INSERT INTO msdb.dbo.systargetservergroupmembers

    VALUES (@servergroup_id, @server_id)

    RETURN(@@error) -- 0 means success

    END

    go

    /**************************************************************/

    /* SP_DELETE_TARGETSVRGRP_MEMBER */

    /**************************************************************/

    PRINT ''

    PRINT 'Creating procedure sp_delete_targetsvrgrp_member...'

    go

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = N'sp_delete_targetsvrgrp_member')

    AND (type = 'P')))

    DROP PROCEDURE sp_delete_targetsvrgrp_member

    go

    CREATE PROCEDURE sp_delete_targetsvrgrp_member

    @group_name sysname,

    @server_name NVARCHAR(30)

    AS

    BEGIN

    DECLARE @servergroup_id INT

    DECLARE @server_id INT

    SET NOCOUNT ON

    -- Remove any leading/trailing spaces from parameters

    SELECT @group_name = LTRIM(RTRIM(@group_name))

    SELECT @server_name = LTRIM(RTRIM(@server_name))

    -- Check if the group exists

    SELECT @servergroup_id = servergroup_id

    FROM msdb.dbo.systargetservergroups

    WHERE (name = @group_name)

    IF (@servergroup_id IS NULL)

    BEGIN

    RAISERROR(14262, -1, -1, '@group_name', @group_name)

    RETURN(1) -- Failure

    END

    -- Check if the server exists

    SELECT @server_id = server_id

    FROM msdb.dbo.systargetservers

    WHERE (server_name = @server_name)

    IF (@server_id IS NULL)

    BEGIN

    RAISERROR(14262, -1, -1, '@server_name', @server_name)

    RETURN(1) -- Failure

    END

    -- Check if the server is in the group

    IF (NOT EXISTS (SELECT *

    FROM msdb.dbo.systargetservergroupmembers

    WHERE (servergroup_id = @servergroup_id)

    AND (server_id = @server_id)))

    BEGIN

    RAISERROR(14264, -1, -1, @server_name, @group_name)

    RETURN(1) -- Failure

    END

    -- Delete the row from systargetservergroupmembers

    DELETE FROM msdb.dbo.systargetservergroupmembers

    WHERE (servergroup_id = @servergroup_id)

    AND (server_id = @server_id)

    RETURN(@@error) -- 0 means success

    END

    go

    /**************************************************************/

    /* SP_VERIFY_CATEGORY */

    /**************************************************************/

    PRINT ''

    PRINT 'Creating procedure sp_verify_category...'

    go

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = N'sp_verify_category')

    AND (type = 'P')))

    DROP PROCEDURE sp_verify_category

    go

    CREATE PROCEDURE sp_verify_category

    @class VARCHAR(8),

    @type VARCHAR(12) = NULL, -- Supply NULL only if you don't want it checked

    @name sysname = NULL, -- Supply NULL only if you don't want it checked

    @category_class INT OUTPUT,

    @category_type INT OUTPUT -- Supply NULL only if you don't want the return value

    AS

    BEGIN

    SET NOCOUNT ON

    -- Remove any leading/trailing spaces from parameters

    SELECT @class = LTRIM(RTRIM(@class))

    SELECT @type = LTRIM(RTRIM(@type))

    SELECT @name = LTRIM(RTRIM(@name))

    -- Turn [nullable] empty string parameters into NULLs

    IF (@type = '') SELECT @type = NULL

    IF (@name = N'') SELECT @name = NULL

    -- Check class

    SELECT @class = UPPER(@class)

    SELECT @category_class = CASE @class

    WHEN 'JOB' THEN 1

    WHEN 'ALERT' THEN 2

    WHEN 'OPERATOR' THEN 3

    ELSE 0

    END

    IF (@category_class = 0)

    BEGIN

    RAISERROR(14266, -1, -1, '@class', 'JOB, ALERT, OPERATOR')

    RETURN(1) -- Failure

    END

    -- Check name

    IF ((@name IS NOT NULL) AND (@name = N'[DEFAULT]'))

    BEGIN

    RAISERROR(14200, -1, -1, '@name')

    RETURN(1) -- Failure

    END

    -- Check type [optionally]

    IF (@type IS NOT NULL)

    BEGIN

    IF (@class = 'JOB')

    BEGIN

    SELECT @type = UPPER(@type)

    SELECT @category_type = CASE @type

    WHEN 'LOCAL' THEN 1

    WHEN 'MULTI-SERVER' THEN 2

    ELSE 0

    END

    IF (@category_type = 0)

    BEGIN

    RAISERROR(14266, -1, -1, '@type', 'LOCAL, MULTI-SERVER')

    RETURN(1) -- Failure

    END

    END

    ELSE

    BEGIN

    IF (@type <> 'NONE')

    BEGIN

    RAISERROR(14266, -1, -1, '@type', 'NONE')

    RETURN(1) -- Failure

    END

    ELSE

    SELECT @category_type = 3

    END

    END

    RETURN(0) -- Success

    END

    go

    /**************************************************************/

    /* SP_ADD_CATEGORY */

    /**************************************************************/

    PRINT ''

    PRINT 'Creating procedure sp_add_category...'

    go

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = N'sp_add_category')

    AND (type = 'P')))

    DROP PROCEDURE sp_add_category

    go

    CREATE PROCEDURE sp_add_category

    @class VARCHAR(8) = 'JOB', -- JOB or ALERT or OPERATOR

    @type VARCHAR(12) = 'LOCAL', -- LOCAL or MULTI-SERVER (for JOB) or NONE otherwise

    @name sysname

    AS

    BEGIN

    DECLARE @retval INT

    DECLARE @category_type INT

    DECLARE @category_class INT

    SET NOCOUNT ON

    -- Remove any leading/trailing spaces from parameters

    SELECT @class = LTRIM(RTRIM(@class))

    SELECT @type = LTRIM(RTRIM(@type))

    SELECT @name = LTRIM(RTRIM(@name))

    EXECUTE @retval = sp_verify_category @class,

    @type,

    @name,

    @category_class OUTPUT,

    @category_type OUTPUT

    IF (@retval <> 0)

    RETURN(1) -- Failure

    -- Check name

    IF (EXISTS (SELECT *

    FROM msdb.dbo.syscategories

    WHERE (category_class = @category_class)

    AND (name = @name)))

    BEGIN

    RAISERROR(14261, -1, -1, '@name', @name)

    RETURN(1) -- Failure

    END

    -- Add the row

    INSERT INTO msdb.dbo.syscategories (category_class, category_type, name)

    VALUES (@category_class, @category_type, @name)

    RETURN(@@error) -- 0 means success

    END

    go

    /**************************************************************/

    /* SP_UPDATE_CATEGORY */

    /**************************************************************/

    PRINT ''

    PRINT 'Creating procedure sp_update_category...'

    go

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = N'sp_update_category')

    AND (type = 'P')))

    DROP PROCEDURE sp_update_category

    go

    CREATE PROCEDURE sp_update_category

    @class VARCHAR(8), -- JOB or ALERT or OPERATOR

    @name sysname,

    @new_name sysname

    AS

    BEGIN

    DECLARE @retval INT

    DECLARE @category_id INT

    DECLARE @category_class INT

    SET NOCOUNT ON

    -- Remove any leading/trailing spaces from parameters

    SELECT @class = LTRIM(RTRIM(@class))

    SELECT @name = LTRIM(RTRIM(@name))

    SELECT @new_name = LTRIM(RTRIM(@new_name))

    EXECUTE @retval = sp_verify_category @class,

    NULL,

    @new_name,

    @category_class OUTPUT,

    NULL

    IF (@retval <> 0)

    RETURN(1) -- Failure

    -- Check name

    SELECT @category_id = category_id

    FROM msdb.dbo.syscategories

    WHERE (category_class = @category_class)

    AND (name = @new_name)

    IF (@category_id IS NOT NULL)

    BEGIN

    RAISERROR(14261, -1, -1, '@new_name', @new_name)

    RETURN(1) -- Failure

    END

    -- Make sure that we're not updating one of the permanent categories (id's 0 - 99)

    IF (@category_id < 100)

    BEGIN

    RAISERROR(14276, -1, -1, @name, @class)

    RETURN(1) -- Failure

    END

    -- Update the category name

    UPDATE msdb.dbo.syscategories

    SET name = @new_name

    WHERE (category_class = @category_class)

    AND (name = @name)

    RETURN(@@error) -- 0 means success

    END

    go

    /**************************************************************/

    /* SP_DELETE_CATEGORY */

    /**************************************************************/

    PRINT ''

    PRINT 'Creating procedure sp_delete_category...'

    go

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = N'sp_delete_category')

    AND (type = 'P')))

    DROP PROCEDURE sp_delete_category

    go

    CREATE PROCEDURE sp_delete_category

    @class VARCHAR(8), -- JOB or ALERT or OPERATOR

    @name sysname

    AS

    BEGIN

    DECLARE @retval INT

    DECLARE @category_id INT

    DECLARE @category_class INT

    DECLARE @category_type INT

    SET NOCOUNT ON

    -- Remove any leading/trailing spaces from parameters

    SELECT @class = LTRIM(RTRIM(@class))

    SELECT @name = LTRIM(RTRIM(@name))

    EXECUTE @retval = sp_verify_category @class,

    NULL,

    NULL,

    @category_class OUTPUT,

    NULL

    IF (@retval <> 0)

    RETURN(1) -- Failure

    -- Check name

    SELECT @category_id = category_id,

    @category_type = category_type

    FROM msdb.dbo.syscategories

    WHERE (category_class = @category_class)

    AND (name = @name)

    IF (@category_id IS NULL)

    BEGIN

    RAISERROR(14262, -1, -1, '@name', @name)

    RETURN(1) -- Failure

    END

    -- Make sure that we're not deleting one of the permanent categories (id's 0 - 99)

    IF (@category_id < 100)

    BEGIN

    RAISERROR(14276, -1, -1, @name, @class)

    RETURN(1) -- Failure

    END

    BEGIN TRANSACTION

    -- Clean-up any Jobs that reference the deleted category

    UPDATE msdb.dbo.sysjobs

    SET category_id = CASE @category_type

    WHEN 1 THEN 0 -- [Uncategorized (Local)]

    WHEN 2 THEN 2 -- [Uncategorized (Multi-Server)]

    END

    WHERE (category_id = @category_id)

    -- Clean-up any Alerts that reference the deleted category

    UPDATE msdb.dbo.sysalerts

    SET category_id = 98

    WHERE (category_id = @category_id)

    -- Clean-up any Operators that reference the deleted category

    UPDATE msdb.dbo.sysoperators

    SET category_id = 99

    WHERE (category_id = @category_id)

    -- Finally, delete the category itself

    DELETE FROM msdb.dbo.syscategories

    WHERE (category_id = @category_id)

    COMMIT TRANSACTION

    RETURN(0) -- Success

    END

    go

    /**************************************************************/

    /* SP_HELP_CATEGORY */

    /**************************************************************/

    PRINT ''

    PRINT 'Creating procedure sp_help_category...'

    go

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = N'sp_help_category')

    AND (type = 'P')))

    DROP PROCEDURE sp_help_category

    go

    CREATE PROCEDURE sp_help_category

    @class VARCHAR(8) = 'JOB', -- JOB, ALERT or OPERATOR

    @type VARCHAR(12) = NULL, -- LOCAL, MULTI-SERVER, or NONE

    @name sysname = NULL,

    @suffix BIT = 0 -- 0 = no suffix, 1 = add suffix

    AS

    BEGIN

    DECLARE @retval INT

    DECLARE @type_in VARCHAR(12)

    DECLARE @category_type INT

    DECLARE @category_class INT

    DECLARE @where_clause NVARCHAR(255)

    DECLARE @cmd NVARCHAR(255)

    SET NOCOUNT ON

    -- Both name and type can be NULL (this is valid, indeed it is how SQLDMO populates

    -- the JobCategory collection)

    -- Remove any leading/trailing spaces from parameters

    SELECT @class = LTRIM(RTRIM(@class))

    SELECT @type = LTRIM(RTRIM(@type))

    SELECT @name = LTRIM(RTRIM(@name))

    -- Turn [nullable] empty string parameters into NULLs

    IF (@type = '') SELECT @type = NULL

    IF (@name = N'') SELECT @name = NULL

    -- Double up any single quotes in @name

    IF (@name IS NOT NULL)

    SELECT @name = REPLACE(@name, N'''', N'''''')

    -- Check the type and class

    IF (@class = 'JOB') AND (@type IS NULL)

    SELECT @type_in = 'LOCAL' -- This prevents sp_verify_category from failing

    ELSE

    IF (@class <> 'JOB') AND (@type IS NULL)

    SELECT @type_in = 'NONE'

    ELSE

    SELECT @type_in = @type

    EXECUTE @retval = sp_verify_category @class,

    @type_in,

    NULL,

    @category_class OUTPUT,

    @category_type OUTPUT

    IF (@retval <> 0)

    RETURN(1) -- Failure

    -- Make sure that 'suffix' is either 0 or 1

    IF (@suffix <> 0)

    SELECT @suffix = 1

    -- Build the WHERE qualifier

    SELECT @where_clause = N'WHERE (category_class = ' + CONVERT(NVARCHAR, @category_class) + N') '

    IF (@name IS NOT NULL)

    SELECT @where_clause = @where_clause + N'AND (name = N''' + @name + N''') '

    IF (@type IS NOT NULL)

    SELECT @where_clause = @where_clause + N'AND (category_type = ' + CONVERT(NVARCHAR, @category_type) + N') '

    -- Construct the query

    SELECT @cmd = N'SELECT category_id, '

    IF (@suffix = 1)

    BEGIN

    SELECT @cmd = @cmd + N'''category_type'' = '

    SELECT @cmd = @cmd + N'CASE category_type '

    SELECT @cmd = @cmd + N'WHEN 0 THEN ''NONE'' '

    SELECT @cmd = @cmd + N'WHEN 1 THEN ''LOCAL'' '

    SELECT @cmd = @cmd + N'WHEN 2 THEN ''MULTI-SERVER'' '

    SELECT @cmd = @cmd + N'ELSE FORMATMESSAGE(14205) '

    SELECT @cmd = @cmd + N'END, '

    END

    ELSE

    BEGIN

    SELECT @cmd = @cmd + N'category_type, '

    END

    SELECT @cmd = @cmd + N'name '

    SELECT @cmd = @cmd + N'FROM msdb.dbo.syscategories '

    -- Execute the query

    EXECUTE (@cmd + @where_clause + N'ORDER BY category_type, name')

    RETURN(@@error) -- 0 means success

    END

    go

    /**************************************************************/

    /* SP_DELETE_TARGETSERVER */

    /**************************************************************/

    PRINT ''

    PRINT 'Creating procedure sp_delete_targetserver...'

    go

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = N'sp_delete_targetserver')

    AND (type = 'P')))

    DROP PROCEDURE sp_delete_targetserver

    go

    CREATE PROCEDURE sp_delete_targetserver

    @server_name NVARCHAR(30),

    @clear_downloadlist BIT = 1,

    @post_defection BIT = 1

    AS

    BEGIN

    DECLARE @server_id INT

    DECLARE @tsx_probe NVARCHAR(50)

    SET NOCOUNT ON

    -- Remove any leading/trailing spaces from parameters

    SELECT @server_name = LTRIM(RTRIM(@server_name))

    -- Check server name

    SELECT @server_id = server_id

    FROM msdb.dbo.systargetservers

    WHERE (server_name = @server_name)

    IF (@server_id IS NULL)

    BEGIN

    RAISERROR(14262, -1, -1, '@server_name', @server_name)

    RETURN(1) -- Failure

    END

    BEGIN TRANSACTION

    IF (@clear_downloadlist = 1)

    BEGIN

    DELETE FROM msdb.dbo.sysdownloadlist

    WHERE (target_server = @server_name)

    END

    IF (@post_defection = 1)

    BEGIN

    -- Post a defect instruction to the server

    -- NOTE: We must do this BEFORE deleting the systargetservers row

    EXECUTE msdb.dbo.sp_post_msx_operation 'DEFECT', 'SERVER', 0x00, @server_name

    END

    DELETE FROM msdb.dbo.systargetservers

    WHERE (server_id = @server_id)

    DELETE FROM msdb.dbo.systargetservergroupmembers

    WHERE (server_id = @server_id)

    DELETE FROM msdb.dbo.sysjobservers

    WHERE (server_id = @server_id)

    COMMIT TRANSACTION

    RETURN(@@error) -- 0 means success

    END

    go

    /**************************************************************/

    /* SP_HELP_TARGETSERVER */

    /**************************************************************/

    PRINT ''

    PRINT 'Creating procedure sp_help_targetserver...'

    go

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = N'sp_help_targetserver')

    AND (type = 'P')))

    DROP PROCEDURE sp_help_targetserver

    go

    CREATE PROCEDURE sp_help_targetserver

    @server_name NVARCHAR(30) = NULL

    AS

    BEGIN

    SET NOCOUNT ON

    -- Remove any leading/trailing spaces from parameters

    SELECT @server_name = LTRIM(RTRIM(@server_name))

    IF (@server_name IS NOT NULL)

    BEGIN

    IF (NOT EXISTS (SELECT *

    FROM msdb.dbo.systargetservers

    WHERE (server_name = @server_name)))

    BEGIN

    RAISERROR(14262, -1, -1, '@server_name', @server_name)

    RETURN(1) -- Failure

    END

    END

    CREATE TABLE #unread_instructions

    (

    target_server NVARCHAR(30) COLLATE database_default,

    unread_instructions INT

    )

    INSERT INTO #unread_instructions

    SELECT target_server, COUNT(*)

    FROM msdb.dbo.sysdownloadlist

    WHERE (status = 0)

    GROUP BY target_server

    SELECT sts.server_id,

    sts.server_name,

    sts.location,

    sts.time_zone_adjustment,

    sts.enlist_date,

    sts.last_poll_date,

    'status' = sts.status |

    CASE WHEN DATEDIFF(ss, sts.last_poll_date, GETDATE()) > (3 * sts.poll_interval) THEN 0x2 ELSE 0 END |

    CASE WHEN ((SELECT COUNT(*)

    FROM msdb.dbo.sysdownloadlist sdl

    WHERE (sdl.target_server = sts.server_name)

    AND (sdl.error_message IS NOT NULL)) > 0) THEN 0x4 ELSE 0 END,

    'unread_instructions' = ISNULL(ui.unread_instructions, 0),

    'local_time' = DATEADD(SS, DATEDIFF(SS, sts.last_poll_date, GETDATE()), sts.local_time_at_last_poll),

    sts.enlisted_by_nt_user,

    sts.poll_interval

    FROM msdb.dbo.systargetservers sts LEFT OUTER JOIN

    #unread_instructions ui ON (sts.server_name = ui.target_server)

    WHERE ((@server_name IS NULL) OR (sts.server_name = @server_name))

    ORDER BY server_name

    RETURN(@@error) -- 0 means success

    END

    go

    /**************************************************************/

    /* SP_RESYNC_TARGETSERVER */

    /**************************************************************/

    PRINT ''

    PRINT 'Creating procedure sp_resync_targetserver...'

    go

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = N'sp_resync_targetserver')

    AND (type = 'P')))

    DROP PROCEDURE sp_resync_targetserver

    go

    CREATE PROCEDURE sp_resync_targetserver

    @server_name NVARCHAR(30)

    AS

    BEGIN

    SET NOCOUNT ON

    -- Only a sysadmin can do this

    IF (ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) <> 1)

    BEGIN

    RAISERROR(15003, 16, 1, N'sysadmin')

    RETURN(1) -- Failure

    END

    -- Remove any leading/trailing spaces from parameters

    SELECT @server_name = LTRIM(RTRIM(@server_name))

    IF (@server_name <> N'ALL')

    BEGIN

    IF (NOT EXISTS (SELECT *

    FROM msdb.dbo.systargetservers

    WHERE (server_name = @server_name)))

    BEGIN

    RAISERROR(14262, -1, -1, '@server_name', @server_name)

    RETURN(1) -- Failure

    END

    -- We want the target server to:

    -- a) delete all their current MSX jobs, and

    -- b) download all their jobs again.

    -- So we delete all the current instructions and post a new set

    DELETE FROM msdb.dbo.sysdownloadlist

    WHERE (target_server = @server_name)

    EXECUTE msdb.dbo.sp_post_msx_operation 'DELETE', 'JOB', 0x00, @server_name

    EXECUTE msdb.dbo.sp_post_msx_operation 'INSERT', 'JOB', 0x00, @server_name

    END

    ELSE

    BEGIN

    -- We want ALL target servers to:

    -- a) delete all their current MSX jobs, and

    -- b) download all their jobs again.

    -- So we delete all the current instructions and post a new set

    TRUNCATE TABLE msdb.dbo.sysdownloadlist

    EXECUTE msdb.dbo.sp_post_msx_operation 'DELETE', 'JOB', 0x00, NULL

    EXECUTE msdb.dbo.sp_post_msx_operation 'INSERT', 'JOB', 0x00, NULL

    END

    RETURN(@@error) -- 0 means success

    END

    go

    DUMP TRANSACTION msdb WITH NO_LOG

    go

    CHECKPOINT

    go

    /**************************************************************/

    /* SP_PURGE_JOBHISTORY */

    /**************************************************************/

    PRINT ''

    PRINT 'Creating procedure sp_purge_jobhistory...'

    go

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = N'sp_purge_jobhistory')

    AND (type = 'P')))

    DROP PROCEDURE sp_purge_jobhistory

    go

    CREATE PROCEDURE sp_purge_jobhistory

    @job_name sysname = NULL,

    @job_id UNIQUEIDENTIFIER = NULL

    AS

    BEGIN

    DECLARE @rows_affected INT

    DECLARE @total_rows INT

    DECLARE @retval INT

    DECLARE @category_id INT

    SET NOCOUNT ON

    IF ((@job_name IS NOT NULL) OR (@job_id IS NOT NULL))

    BEGIN

    EXECUTE @retval = sp_verify_job_identifiers '@job_name',

    '@job_id',

    @job_name OUTPUT,

    @job_id OUTPUT

    IF (@retval <> 0)

    RETURN(1) -- Failure

    -- Get category to see if it is a misc. replication agent. @category_id will be

    -- NULL if there is no @job_id.

    select @category_id = category_id from msdb.dbo.sysjobs where job_id = @job_id

    -- Delete the histories for this job

    DELETE FROM msdb.dbo.sysjobhistory

    WHERE (job_id = @job_id)

    SELECT @rows_affected = @@rowcount

    -- If misc. replication job, then update global replication status table

    IF (@category_id IN (11, 12, 16, 17, 18))

    BEGIN

    -- Nothing can be done if this fails, so don't worry about the return code

    EXECUTE master.dbo.sp_MSupdate_replication_status

    @publisher = '',

    @publisher_db = '',

    @publication = '',

    @publication_type = -1,

    @agent_type = 5,

    @agent_name = @job_name,

    @status = -1 -- Delete

    END

    END

    ELSE

    BEGIN

    -- Only a sysadmin can do this

    IF (ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) <> 1)

    BEGIN

    RAISERROR(15003, 16, 1, N'sysadmin')

    RETURN(1) -- Failure

    END

    SELECT @total_rows = COUNT(*)

    FROM msdb.dbo.sysjobhistory

    SELECT @rows_affected = @total_rows

    TRUNCATE TABLE msdb.dbo.sysjobhistory

    -- Remove all misc. replication jobs from global replication status table

    -- Nothing can be done if this fails, so don't worry about the return code

    EXECUTE master.dbo.sp_MSupdate_replication_status

    @publisher = '',

    @publisher_db = '',

    @publication = '',

    @publication_type = -1,

    @agent_type = 5,

    @agent_name = '%',

    @status = -1 -- Delete

    END

    RAISERROR(14226, 0, 1, @rows_affected)

    RETURN(0) -- Success

    END

    go

    /**************************************************************/

    /* SP_VERIFY_JOB_DATE */

    /**************************************************************/

    PRINT ''

    PRINT 'Creating procedure sp_verify_job_date...'

    go

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = N'sp_verify_job_date')

    AND (type = 'P')))

    DROP PROCEDURE sp_verify_job_date

    go

    CREATE PROCEDURE sp_verify_job_date

    @date INT,

    @date_name VARCHAR(60) = 'date',

    @error_severity INT = -1

    AS

    BEGIN

    SET NOCOUNT ON

    -- Remove any leading/trailing spaces from parameters

    SELECT @date_name = LTRIM(RTRIM(@date_name))

    IF ((ISDATE(CONVERT(VARCHAR, @date)) = 0) OR (@date 99991231))

    BEGIN

    RAISERROR(14266, @error_severity, -1, @date_name, '19900101..99991231')

    RETURN(1) -- Failure

    END

    RETURN(0) -- Success

    END

    go

    /**************************************************************/

    /* SP_VERIFY_JOB_TIME */

    /**************************************************************/

    PRINT ''

    PRINT 'Creating procedure sp_verify_job_time...'

    go

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = N'sp_verify_job_time')

    AND (type = 'P')))

    DROP PROCEDURE sp_verify_job_time

    go

    CREATE PROCEDURE sp_verify_job_time

    @time INT,

    @time_name VARCHAR(60) = 'time',

    @error_severity INT = -1

    AS

    BEGIN

    DECLARE @hour INT

    DECLARE @minute INT

    DECLARE @second INT

    DECLARE @part_name NVARCHAR(50)

    SET NOCOUNT ON

    -- Remove any leading/trailing spaces from parameters

    SELECT @time_name = LTRIM(RTRIM(@time_name))

    IF ((@time 235959))

    BEGIN

    RAISERROR(14266, @error_severity, -1, @time_name, '000000..235959')

    RETURN(1) -- Failure

    END

    SELECT @hour = (@time / 10000)

    SELECT @minute = (@time % 10000) / 100

    SELECT @second = (@time % 100)

    -- Check hour range

    IF (@hour > 23)

    BEGIN

    SELECT @part_name = FORMATMESSAGE(14218)

    RAISERROR(14287, @error_severity, -1, @time_name, @part_name)

    RETURN(1) -- Failure

    END

    -- Check minute range

    IF (@minute > 59)

    BEGIN

    SELECT @part_name = FORMATMESSAGE(14219)

    RAISERROR(14287, @error_severity, -1, @time_name, @part_name)

    RETURN(1) -- Failure

    END

    -- Check second range

    IF (@second > 59)

    BEGIN

    SELECT @part_name = FORMATMESSAGE(14220)

    RAISERROR(14287, @error_severity, -1, @time_name, @part_name)

    RETURN(1) -- Failure

    END

    RETURN(0) -- Success

    END

    go

    /**************************************************************/

    /* SP_HELP_JOBHISTORY */

    /**************************************************************/

    PRINT ''

    PRINT 'Creating procedure sp_help_jobhistory...'

    go

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = N'sp_help_jobhistory')

    AND (type = 'P')))

    DROP PROCEDURE sp_help_jobhistory

    go

    CREATE PROCEDURE sp_help_jobhistory

    @job_id UNIQUEIDENTIFIER = NULL,

    @job_name sysname = NULL,

    @step_id INT = NULL,

    @sql_message_id INT = NULL,

    @sql_severity INT = NULL,

    @start_run_date INT = NULL, -- YYYYMMDD

    @end_run_date INT = NULL, -- YYYYMMDD

    @start_run_time INT = NULL, -- HHMMSS

    @end_run_time INT = NULL, -- HHMMSS

    @minimum_run_duration INT = NULL, -- HHMMSS

    @run_status INT = NULL, -- SQLAGENT_EXEC_X code

    @minimum_retries INT = NULL,

    @oldest_first INT = 0, -- Or 1

    @server NVARCHAR(30) = NULL,

    @mode VARCHAR(7) = 'SUMMARY' -- Or 'FULL' or 'SEM'

    AS

    BEGIN

    DECLARE @retval INT

    DECLARE @order_by INT -- Must be INT since it can be -1

    SET NOCOUNT ON

    -- Remove any leading/trailing spaces from parameters

    SELECT @server = LTRIM(RTRIM(@server))

    SELECT @mode = LTRIM(RTRIM(@mode))

    -- Turn [nullable] empty string parameters into NULLs

    IF (@server = N'') SELECT @server = NULL

    -- Check job id/name (if supplied)

    IF ((@job_id IS NOT NULL) OR (@job_name IS NOT NULL))

    BEGIN

    EXECUTE @retval = sp_verify_job_identifiers '@job_name',

    '@job_id',

    @job_name OUTPUT,

    @job_id OUTPUT

    IF (@retval <> 0)

    RETURN(1) -- Failure

    END

    -- Check @start_run_date

    IF (@start_run_date IS NOT NULL)

    BEGIN

    EXECUTE @retval = sp_verify_job_date @start_run_date, '@start_run_date'

    IF (@retval <> 0)

    RETURN(1) -- Failure

    END

    -- Check @end_run_date

    IF (@end_run_date IS NOT NULL)

    BEGIN

    EXECUTE @retval = sp_verify_job_date @end_run_date, '@end_run_date'

    IF (@retval <> 0)

    RETURN(1) -- Failure

    END

    -- Check @start_run_time

    EXECUTE @retval = sp_verify_job_time @start_run_time, '@start_run_time'

    IF (@retval <> 0)

    RETURN(1) -- Failure

    -- Check @end_run_time

    EXECUTE @retval = sp_verify_job_time @end_run_time, '@end_run_time'

    IF (@retval <> 0)

    RETURN(1) -- Failure

    -- Check @run_status

    IF ((@run_status 5))

    BEGIN

    RAISERROR(13266, -1, -1, '@run_status', '0..5')

    RETURN(1) -- Failure

    END

    -- Check mode

    SELECT @mode = UPPER(@mode)

    IF (@mode NOT IN ('SUMMARY', 'FULL', 'SEM'))

    BEGIN

    RAISERROR(14266, -1, -1, '@mode', 'SUMMARY, FULL, SEM')

    RETURN(1) -- Failure

    END

    SELECT @order_by = -1

    IF (@oldest_first = 1)

    SELECT @order_by = 1

    -- Return history information filtered by the supplied parameters.

    -- NOTE: SQLDMO relies on the 'FULL' format; ** DO NOT CHANGE IT **

    IF (@mode = 'FULL')

    BEGIN

    SELECT sjh.instance_id, -- This is included just for ordering purposes

    sj.job_id,

    job_name = sj.name,

    sjh.step_id,

    sjh.step_name,

    sjh.sql_message_id,

    sjh.sql_severity,

    sjh.message,

    sjh.run_status,

    sjh.run_date,

    sjh.run_time,

    sjh.run_duration,

    operator_emailed = so1.name,

    operator_netsent = so2.name,

    operator_paged = so3.name,

    sjh.retries_attempted,

    sjh.server

    FROM msdb.dbo.sysjobhistory sjh

    LEFT OUTER JOIN msdb.dbo.sysoperators so1 ON (sjh.operator_id_emailed = so1.id)

    LEFT OUTER JOIN msdb.dbo.sysoperators so2 ON (sjh.operator_id_netsent = so2.id)

    LEFT OUTER JOIN msdb.dbo.sysoperators so3 ON (sjh.operator_id_paged = so3.id),

    msdb.dbo.sysjobs_view sj

    WHERE (sj.job_id = sjh.job_id)

    AND ((@job_id IS NULL) OR (@job_id = sjh.job_id))

    AND ((@step_id IS NULL) OR (@step_id = sjh.step_id))

    AND ((@sql_message_id IS NULL) OR (@sql_message_id = sjh.sql_message_id))

    AND ((@sql_severity IS NULL) OR (@sql_severity = sjh.sql_severity))

    AND ((@start_run_date IS NULL) OR (sjh.run_date >= @start_run_date))

    AND ((@end_run_date IS NULL) OR (sjh.run_date <= @end_run_date))

    AND ((@start_run_time IS NULL) OR (sjh.run_time >= @start_run_time))

    AND ((@end_run_time IS NULL) OR (sjh.run_time <= @end_run_time))

    AND ((@minimum_run_duration IS NULL) OR (sjh.run_duration >= @minimum_run_duration))

    AND ((@run_status IS NULL) OR (@run_status = sjh.run_status))

    AND ((@minimum_retries IS NULL) OR (sjh.retries_attempted >= @minimum_retries))

    AND ((@server IS NULL) OR (sjh.server = @server))

    ORDER BY (sjh.instance_id * @order_by)

    END

    ELSE

    IF (@mode = 'SUMMARY')

    BEGIN

    -- Summary format: same WHERE clause just a different SELECT list

    SELECT sj.job_id,

    job_name = sj.name,

    sjh.run_status,

    sjh.run_date,

    sjh.run_time,

    sjh.run_duration,

    operator_emailed = substring(so1.name, 1, 20),

    operator_netsent = substring(so2.name, 1, 20),

    operator_paged = substring(so3.name, 1, 20),

    sjh.retries_attempted,

    sjh.server

    FROM msdb.dbo.sysjobhistory sjh

    LEFT OUTER JOIN msdb.dbo.sysoperators so1 ON (sjh.operator_id_emailed = so1.id)

    LEFT OUTER JOIN msdb.dbo.sysoperators so2 ON (sjh.operator_id_netsent = so2.id)

    LEFT OUTER JOIN msdb.dbo.sysoperators so3 ON (sjh.operator_id_paged = so3.id),

    msdb.dbo.sysjobs_view sj

    WHERE (sj.job_id = sjh.job_id)

    AND ((@job_id IS NULL) OR (@job_id = sjh.job_id))

    AND ((@step_id IS NULL) OR (@step_id = sjh.step_id))

    AND ((@sql_message_id IS NULL) OR (@sql_message_id = sjh.sql_message_id))

    AND ((@sql_severity IS NULL) OR (@sql_severity = sjh.sql_severity))

    AND ((@start_run_date IS NULL) OR (sjh.run_date >= @start_run_date))

    AND ((@end_run_date IS NULL) OR (sjh.run_date <= @end_run_date))

    AND ((@start_run_time IS NULL) OR (sjh.run_time >= @start_run_time))

    AND ((@end_run_time IS NULL) OR (sjh.run_time <= @end_run_time))

    AND ((@minimum_run_duration IS NULL) OR (sjh.run_duration >= @minimum_run_duration))

    AND ((@run_status IS NULL) OR (@run_status = sjh.run_status))

    AND ((@minimum_retries IS NULL) OR (sjh.retries_attempted >= @minimum_retries))

    AND ((@server IS NULL) OR (sjh.server = @server))

    ORDER BY (sjh.instance_id * @order_by)

    END

    ELSE

    IF (@mode = 'SEM')

    BEGIN

    -- SQL Enterprise Manager format

    SELECT sjh.step_id,

    sjh.step_name,

    sjh.message,

    sjh.run_status,

    sjh.run_date,

    sjh.run_time,

    sjh.run_duration,

    operator_emailed = so1.name,

    operator_netsent = so2.name,

    operator_paged = so3.name

    FROM msdb.dbo.sysjobhistory sjh

    LEFT OUTER JOIN msdb.dbo.sysoperators so1 ON (sjh.operator_id_emailed = so1.id)

    LEFT OUTER JOIN msdb.dbo.sysoperators so2 ON (sjh.operator_id_netsent = so2.id)

    LEFT OUTER JOIN msdb.dbo.sysoperators so3 ON (sjh.operator_id_paged = so3.id),

    msdb.dbo.sysjobs_view sj

    WHERE (sj.job_id = sjh.job_id)

    AND (@job_id = sjh.job_id)

    ORDER BY (sjh.instance_id * @order_by)

    END

    RETURN(0) -- Success

    END

    go

    /**************************************************************/

    /* SP_ADD_JOBSERVER */

    /**************************************************************/

    PRINT ''

    PRINT 'Creating procedure sp_add_jobserver...'

    go

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = N'sp_add_jobserver')

    AND (type = 'P')))

    DROP PROCEDURE sp_add_jobserver

    go

    CREATE PROCEDURE sp_add_jobserver

    @job_id UNIQUEIDENTIFIER = NULL, -- Must provide either this or job_name

    @job_name sysname = NULL, -- Must provide either this or job_id

    @server_name NVARCHAR(30) = NULL, -- if NULL will default to serverproperty('ServerName')

    @automatic_post BIT = 1 -- Flag for SEM use only

    AS

    BEGIN

    DECLARE @retval INT

    DECLARE @server_id INT

    DECLARE @job_type VARCHAR(12)

    DECLARE @current_job_category_type VARCHAR(12)

    DECLARE @msx_operator_id INT

    DECLARE @local_server_name NVARCHAR(30)

    DECLARE @is_sysadmin INT

    DECLARE @job_owner sysname

    SET NOCOUNT ON

    IF (@server_name IS NULL) OR (UPPER(@server_name) = N'(LOCAL)')

    SELECT @server_name = CONVERT(NVARCHAR(30), SERVERPROPERTY('ServerName'))

    -- Remove any leading/trailing spaces from parameters

    SELECT @server_name = LTRIM(RTRIM(@server_name))

    EXECUTE @retval = sp_verify_job_identifiers '@job_name',

    '@job_id',

    @job_name OUTPUT,

    @job_id OUTPUT

    IF (@retval <> 0)

    RETURN(1) -- Failure

    -- First, check if the server is the local server

    SELECT @local_server_name = CONVERT(NVARCHAR,SERVERPROPERTY ('SERVERNAME'))

    IF (UPPER(@server_name) = UPPER(@local_server_name))

    SELECT @server_name = UPPER(CONVERT(NVARCHAR(30), SERVERPROPERTY('ServerName')))

    -- Only the SA can add a multi-server job

    IF (UPPER(@server_name) <> UPPER(CONVERT(NVARCHAR(30), SERVERPROPERTY('ServerName')))) AND

    (ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) = 0)

    BEGIN

    RAISERROR(15003, 16, 1, N'sysadmin')

    RETURN(1) -- Failure

    END

    -- For a multi-server job...

    IF (UPPER(@server_name) <> UPPER(CONVERT(NVARCHAR(30), SERVERPROPERTY('ServerName'))))

    BEGIN

    -- 1) Check if the job owner is a sysadmin

    SELECT @job_owner = SUSER_SNAME(owner_sid)

    FROM msdb.dbo.sysjobs

    WHERE (job_id = @job_id)

    SELECT @is_sysadmin = 0

    EXECUTE msdb.dbo.sp_sqlagent_has_server_access @login_name = @job_owner, @is_sysadmin_member = @is_sysadmin OUTPUT

    IF (@is_sysadmin = 0)

    BEGIN

    RAISERROR(14544, -1, -1, @job_owner, N'sysadmin')

    RETURN(1) -- Failure

    END

    -- 2) Check if any of the TSQL steps have a non-null database_user_name

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysjobsteps

    WHERE (job_id = @job_id)

    AND (subsystem = N'TSQL')

    AND (database_user_name IS NOT NULL)))

    BEGIN

    RAISERROR(14542, -1, -1, N'database_user_name')

    RETURN(1) -- Failure

    END

    END

    -- Check server name

    IF (UPPER(@server_name) <> UPPER(CONVERT(NVARCHAR(30), SERVERPROPERTY('ServerName'))))

    BEGIN

    SELECT @server_id = server_id

    FROM msdb.dbo.systargetservers

    WHERE (server_name = @server_name)

    IF (@server_id IS NULL)

    BEGIN

    RAISERROR(14262, -1, -1, '@server_name', @server_name)

    RETURN(1) -- Failure

    END

    END

    ELSE

    SELECT @server_id = 0

    -- Check that this job has not already been targeted at this server

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysjobservers

    WHERE (job_id = @job_id)

    AND (server_id = @server_id)))

    BEGIN

    RAISERROR(14269, -1, -1, @job_name, @server_name)

    RETURN(1) -- Failure

    END

    -- Prevent the job from being targeted at both the local AND remote servers

    SELECT @job_type = 'UNKNOWN'

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysjobservers

    WHERE (job_id = @job_id)

    AND (server_id = 0)))

    SELECT @job_type = 'LOCAL'

    ELSE

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysjobservers

    WHERE (job_id = @job_id)

    AND (server_id <> 0)))

    SELECT @job_type = 'MULTI-SERVER'

    IF ((@server_id = 0) AND (@job_type = 'MULTI-SERVER'))

    BEGIN

    RAISERROR(14290, -1, -1)

    RETURN(1) -- Failure

    END

    IF ((@server_id <> 0) AND (@job_type = 'LOCAL'))

    BEGIN

    RAISERROR(14291, -1, -1)

    RETURN(1) -- Failure

    END

    -- For a multi-server job, check that any notifications are to the MSXOperator

    IF (@job_type = 'MULTI-SERVER')

    BEGIN

    SELECT @msx_operator_id = id

    FROM msdb.dbo.sysoperators

    WHERE (name = N'MSXOperator')

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysjobs

    WHERE (job_id = @job_id)

    AND (((notify_email_operator_id <> 0) AND (notify_email_operator_id <> @msx_operator_id)) OR

    ((notify_page_operator_id <> 0) AND (notify_page_operator_id <> @msx_operator_id)) OR

    ((notify_netsend_operator_id <> 0) AND (notify_netsend_operator_id <> @msx_operator_id)))))

    BEGIN

    RAISERROR(14221, -1, -1, 'MSXOperator')

    RETURN(1) -- Failure

    END

    END

    -- Insert the sysjobservers row

    INSERT INTO msdb.dbo.sysjobservers

    (job_id,

    server_id,

    last_run_outcome,

    last_outcome_message,

    last_run_date,

    last_run_time,

    last_run_duration)

    VALUES (@job_id,

    @server_id,

    5, -- ie. SQLAGENT_EXEC_UNKNOWN (can't use 0 since this is SQLAGENT_EXEC_FAIL)

    NULL,

    0,

    0,

    0)

    -- Re-categorize the job (if necessary)

    SELECT @current_job_category_type = CASE category_type

    WHEN 1 THEN 'LOCAL'

    WHEN 2 THEN 'MULTI-SERVER'

    END

    FROM msdb.dbo.sysjobs_view sjv,

    msdb.dbo.syscategories sc

    WHERE (sjv.category_id = sc.category_id)

    AND (sjv.job_id = @job_id)

    IF (@server_id = 0) AND (@current_job_category_type = 'MULTI-SERVER')

    BEGIN

    UPDATE msdb.dbo.sysjobs

    SET category_id = 0 -- [Uncategorized (Local)]

    WHERE (job_id = @job_id)

    END

    IF (@server_id <> 0) AND (@current_job_category_type = 'LOCAL')

    BEGIN

    UPDATE msdb.dbo.sysjobs

    SET category_id = 2 -- [Uncategorized (Multi-Server)]

    WHERE (job_id = @job_id)

    END

    -- Instruct the new server to pick up the job

    IF (@automatic_post = 1)

    EXECUTE @retval = sp_post_msx_operation 'INSERT', 'JOB', @job_id, @server_name

    -- If the job is local, make sure that SQLServerAgent caches it

    IF (@server_id = 0)

    BEGIN

    EXECUTE msdb.dbo.sp_sqlagent_notify @op_type = N'J',

    @job_id = @job_id,

    @action_type = N'I'

    END

    RETURN(@retval) -- 0 means success

    END

    go

    /**************************************************************/

    /* SP_DELETE_JOBSERVER */

    /**************************************************************/

    PRINT ''

    PRINT 'Creating procedure sp_delete_jobserver...'

    go

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = N'sp_delete_jobserver')

    AND (type = 'P')))

    DROP PROCEDURE sp_delete_jobserver

    go

    CREATE PROCEDURE sp_delete_jobserver

    @job_id UNIQUEIDENTIFIER = NULL, -- Must provide either this or job_name

    @job_name sysname = NULL, -- Must provide either this or job_id

    @server_name NVARCHAR(30)

    AS

    BEGIN

    DECLARE @retval INT

    DECLARE @server_id INT

    DECLARE @local_machine_name NVARCHAR(30)

    SET NOCOUNT ON

    -- Remove any leading/trailing spaces from parameters

    SELECT @server_name = LTRIM(RTRIM(@server_name))

    IF (UPPER(@server_name) = '(LOCAL)')

    SELECT @server_name = UPPER(CONVERT(NVARCHAR(30), SERVERPROPERTY('ServerName')))

    EXECUTE @retval = sp_verify_job_identifiers '@job_name',

    '@job_id',

    @job_name OUTPUT,

    @job_id OUTPUT

    IF (@retval <> 0)

    RETURN(1) -- Failure

    -- First, check if the server is the local server

    EXECUTE @retval = master.dbo.xp_getnetname @local_machine_name OUTPUT

    IF (@retval <> 0)

    RETURN(1) -- Failure

    IF (@local_machine_name IS NOT NULL) AND (UPPER(@server_name) = UPPER(@local_machine_name))

    SELECT @server_name = UPPER(CONVERT(NVARCHAR(30), SERVERPROPERTY('ServerName')))

    -- Check server name

    IF (UPPER(@server_name) <> UPPER(CONVERT(NVARCHAR(30), SERVERPROPERTY('ServerName'))))

    BEGIN

    SELECT @server_id = server_id

    FROM msdb.dbo.systargetservers

    WHERE (server_name = @server_name)

    IF (@server_id IS NULL)

    BEGIN

    RAISERROR(14262, -1, -1, '@server_name', @server_name)

    RETURN(1) -- Failure

    END

    END

    ELSE

    SELECT @server_id = 0

    -- Check that the job is indeed targeted at the server

    IF (NOT EXISTS (SELECT *

    FROM msdb.dbo.sysjobservers

    WHERE (job_id = @job_id)

    AND (server_id = @server_id)))

    BEGIN

    RAISERROR(14270, -1, -1, @job_name, @server_name)

    RETURN(1) -- Failure

    END

    -- Instruct the deleted server to purge the job

    -- NOTE: We must do this BEFORE we delete the sysjobservers row

    EXECUTE @retval = sp_post_msx_operation 'DELETE', 'JOB', @job_id, @server_name

    -- Delete the sysjobservers row

    DELETE FROM msdb.dbo.sysjobservers

    WHERE (job_id = @job_id)

    AND (server_id = @server_id)

    -- If we deleted the last jobserver then re-categorize the job to the sp_add_job default

    IF (NOT EXISTS (SELECT *

    FROM msdb.dbo.sysjobservers

    WHERE (job_id = @job_id)))

    BEGIN

    UPDATE msdb.dbo.sysjobs

    SET category_id = 0 -- [Uncategorized (Local)]

    WHERE (job_id = @job_id)

    END

    -- If the job is local, make sure that SQLServerAgent removes it from cache

    IF (@server_id = 0)

    BEGIN

    EXECUTE msdb.dbo.sp_sqlagent_notify @op_type = N'J',

    @job_id = @job_id,

    @action_type = N'D'

    END

    RETURN(@retval) -- 0 means success

    END

    go

    /**************************************************************/

    /* SP_HELP_JOBSERVER */

    /**************************************************************/

    PRINT ''

    PRINT 'Creating procedure sp_help_jobserver...'

    go

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = N'sp_help_jobserver')

    AND (type = 'P')))

    DROP PROCEDURE sp_help_jobserver

    go

    CREATE PROCEDURE sp_help_jobserver

    @job_id UNIQUEIDENTIFIER = NULL, -- Must provide either this or job_name

    @job_name sysname = NULL, -- Must provide either this or job_id

    @show_last_run_details TINYINT = 0 -- Controls if last-run execution information is part of the result set (1 = yes, 0 = no)

    AS

    BEGIN

    DECLARE @retval INT

    SET NOCOUNT ON

    EXECUTE @retval = sp_verify_job_identifiers '@job_name',

    '@job_id',

    @job_name OUTPUT,

    @job_id OUTPUT

    IF (@retval <> 0)

    RETURN(1) -- Failure

    -- The show-last-run-details flag must be either 1 or 0

    IF (@show_last_run_details <> 0)

    SELECT @show_last_run_details = 1

    IF (@show_last_run_details = 1)

    BEGIN

    -- List the servers that @job_name has been targeted at (INCLUDING last-run details)

    SELECT stsv.server_id,

    stsv.server_name,

    stsv.enlist_date,

    stsv.last_poll_date,

    sjs.last_run_date,

    sjs.last_run_time,

    sjs.last_run_duration,

    sjs.last_run_outcome, -- Same as JOB_OUTCOME_CODE (SQLAGENT_EXEC_x)

    sjs.last_outcome_message

    FROM msdb.dbo.sysjobservers sjs LEFT OUTER JOIN

    msdb.dbo.systargetservers_view stsv ON (sjs.server_id = stsv.server_id)

    WHERE (sjs.job_id = @job_id)

    END

    ELSE

    BEGIN

    -- List the servers that @job_name has been targeted at (EXCLUDING last-run details)

    SELECT stsv.server_id,

    stsv.server_name,

    stsv.enlist_date,

    stsv.last_poll_date

    FROM msdb.dbo.sysjobservers sjs LEFT OUTER JOIN

    msdb.dbo.systargetservers_view stsv ON (sjs.server_id = stsv.server_id)

    WHERE (sjs.job_id = @job_id)

    END

    RETURN(@@error) -- 0 means success

    END

    go

    /**************************************************************/

    /* SP_HELP_DOWNLOADLIST */

    /**************************************************************/

    PRINT ''

    PRINT 'Creating procedure sp_help_downloadlist...'

    go

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = N'sp_help_downloadlist')

    AND (type = 'P')))

    DROP PROCEDURE sp_help_downloadlist

    go

    CREATE PROCEDURE sp_help_downloadlist

    @job_id UNIQUEIDENTIFIER = NULL, -- If provided must NOT also provide job_name

    @job_name sysname = NULL, -- If provided must NOT also provide job_id

    @operation VARCHAR(64) = NULL,

    @object_type VARCHAR(64) = NULL, -- Only 'JOB' or 'SERVER' are valid in 7.0

    @object_name sysname = NULL,

    @target_server NVARCHAR(30) = NULL,

    @has_error TINYINT = NULL, -- NULL or 1

    @status TINYINT = NULL,

    @date_posted DATETIME = NULL -- Include all entries made on OR AFTER this date

    AS

    BEGIN

    DECLARE @retval INT

    DECLARE @operation_code INT

    DECLARE @object_type_id TINYINT

    SET NOCOUNT ON

    -- Remove any leading/trailing spaces from parameters

    SELECT @operation = LTRIM(RTRIM(@operation))

    SELECT @object_type = LTRIM(RTRIM(@object_type))

    SELECT @object_name = LTRIM(RTRIM(@object_name))

    SELECT @target_server = LTRIM(RTRIM(@target_server))

    -- Turn [nullable] empty string parameters into NULLs

    IF (@operation = '') SELECT @operation = NULL

    IF (@object_type = '') SELECT @object_type = NULL

    IF (@object_name = N'') SELECT @object_name = NULL

    IF (@target_server = N'') SELECT @target_server = NULL

    IF ((@job_id IS NOT NULL) OR (@job_name IS NOT NULL))

    BEGIN

    EXECUTE @retval = sp_verify_job_identifiers '@job_name',

    '@job_id',

    @job_name OUTPUT,

    @job_id OUTPUT

    IF (@retval <> 0)

    RETURN(1) -- Failure

    END

    -- Check operation

    IF (@operation IS NOT NULL)

    BEGIN

    SELECT @operation = UPPER(@operation)

    SELECT @operation_code = CASE @operation

    WHEN 'INSERT' THEN 1

    WHEN 'UPDATE' THEN 2

    WHEN 'DELETE' THEN 3

    WHEN 'START' THEN 4

    WHEN 'STOP' THEN 5

    WHEN 'RE-ENLIST' THEN 6

    WHEN 'DEFECT' THEN 7

    WHEN 'SYNC-TIME' THEN 8

    WHEN 'SET-POLL' THEN 9

    ELSE 0

    END

    IF (@operation_code = 0)

    BEGIN

    RAISERROR(14266, -1, -1, '@operation_code', 'INSERT, UPDATE, DELETE, START, STOP, RE-ENLIST, DEFECT, SYNC-TIME, SET-POLL')

    RETURN(1) -- Failure

    END

    END

    -- Check object type (in 7.0 only 'JOB' and 'SERVER' are valid)

    IF (@object_type IS NOT NULL)

    BEGIN

    SELECT @object_type = UPPER(@object_type)

    IF ((@object_type <> 'JOB') AND (@object_type <> 'SERVER'))

    BEGIN

    RAISERROR(14266, -1, -1, '@object_type', 'JOB, SERVER')

    RETURN(1) -- Failure

    END

    ELSE

    SELECT @object_type_id = CASE @object_type

    WHEN 'JOB' THEN 1

    WHEN 'SERVER' THEN 2

    ELSE 0

    END

    END

    -- If object-type is supplied then object-name must also be supplied

    IF ((@object_type IS NOT NULL) AND (@object_name IS NULL)) OR

    ((@object_type IS NULL) AND (@object_name IS NOT NULL))

    BEGIN

    RAISERROR(14272, -1, -1)

    RETURN(1) -- Failure

    END

    -- Check target server

    IF (@target_server IS NOT NULL) AND NOT EXISTS (SELECT *

    FROM msdb.dbo.systargetservers

    WHERE server_name = @target_server)

    BEGIN

    RAISERROR(14262, -1, -1, '@target_server', @target_server)

    RETURN(1) -- Failure

    END

    -- Check has-error

    IF (@has_error IS NOT NULL) AND (@has_error <> 1)

    BEGIN

    RAISERROR(14266, -1, -1, '@has_error', '1, NULL')

    RETURN(1) -- Failure

    END

    -- Check status

    IF (@status IS NOT NULL) AND (@status <> 0) AND (@status <> 1)

    BEGIN

    RAISERROR(14266, -1, -1, '@status', '0, 1')

    RETURN(1) -- Failure

    END

    -- Return the result set

    SELECT sdl.instance_id,

    sdl.source_server,

    'operation_code' = CASE sdl.operation_code

    WHEN 1 THEN '1 (INSERT)'

    WHEN 2 THEN '2 (UPDATE)'

    WHEN 3 THEN '3 (DELETE)'

    WHEN 4 THEN '4 (START)'

    WHEN 5 THEN '5 (STOP)'

    WHEN 6 THEN '6 (RE-ENLIST)'

    WHEN 7 THEN '7 (DEFECT)'

    WHEN 8 THEN '8 (SYNC-TIME)'

    WHEN 9 THEN '9 (SET-POLL)'

    ELSE CONVERT(VARCHAR, sdl.operation_code) + ' ' + FORMATMESSAGE(14205)

    END,

    'object_name' = ISNULL(sjv.name, CASE

    WHEN (sdl.operation_code >= 1) AND (sdl.operation_code <= 5) AND (sdl.object_id = CONVERT(UNIQUEIDENTIFIER, 0x00)) THEN FORMATMESSAGE(14212) -- '(all jobs)'

    WHEN (sdl.operation_code = 3) AND (sdl.object_id <> CONVERT(UNIQUEIDENTIFIER, 0x00)) THEN sdl.deleted_object_name -- Special case handling for a deleted job

    WHEN (sdl.operation_code >= 1) AND (sdl.operation_code CONVERT(UNIQUEIDENTIFIER, 0x00)) THEN FORMATMESSAGE(14580) -- 'job' (safety belt: should never appear)

    WHEN (sdl.operation_code >= 6) AND (sdl.operation_code <= 9) THEN sdl.target_server

    ELSE FORMATMESSAGE(14205)

    END),

    'object_id' = ISNULL(sjv.job_id, CASE sdl.object_id

    WHEN CONVERT(UNIQUEIDENTIFIER, 0x00) THEN CONVERT(UNIQUEIDENTIFIER, 0x00)

    ELSE sdl.object_id

    END),

    sdl.target_server,

    sdl.error_message,

    sdl.date_posted,

    sdl.date_downloaded,

    sdl.status

    FROM msdb.dbo.sysdownloadlist sdl LEFT OUTER JOIN

    msdb.dbo.sysjobs_view sjv ON (sdl.object_id = sjv.job_id)

    WHERE ((@operation_code IS NULL) OR (operation_code = @operation_code))

    AND ((@object_type_id IS NULL) OR (object_type = @object_type_id))

    AND ((@job_id IS NULL) OR (object_id = @job_id))

    AND ((@target_server IS NULL) OR (target_server = @target_server))

    AND ((@has_error IS NULL) OR (DATALENGTH(error_message) >= 1 * @has_error))

    AND ((@status IS NULL) OR (status = @status))

    AND ((@date_posted IS NULL) OR (date_posted >= @date_posted))

    ORDER BY sdl.instance_id

    RETURN(@@error) -- 0 means success

    END

    go

    /**************************************************************/

    /* SP_ENUM_SQLAGENT_SUBSYSTEMS */

    /**************************************************************/

    PRINT ''

    PRINT 'Creating procedure sp_enum_sqlagent_subsystems...'

    go

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = N'sp_enum_sqlagent_subsystems')

    AND (type = 'P')))

    DROP PROCEDURE sp_enum_sqlagent_subsystems

    go

    CREATE PROCEDURE sp_enum_sqlagent_subsystems

    AS

    BEGIN

    DECLARE @part NVARCHAR(300)

    DECLARE @fmt NVARCHAR(300)

    DECLARE @subsystem NVARCHAR(40)

    DECLARE @replication_installed INT

    SET NOCOUNT ON

    CREATE TABLE #xp_results (subsystem NVARCHAR(40) COLLATE database_default NOT NULL,

    description NVARCHAR(300) COLLATE database_default NOT NULL)

    CREATE TABLE #sp_enum_ss_temp (subsystem NVARCHAR(40) COLLATE database_default NOT NULL,

    description NVARCHAR(80) COLLATE database_default NOT NULL,

    subsystem_dll NVARCHAR(255) COLLATE database_default NULL,

    agent_exe NVARCHAR(80) COLLATE database_default NULL,

    start_entry_point NVARCHAR(30) COLLATE database_default NULL,

    event_entry_point NVARCHAR(30) COLLATE database_default NULL,

    stop_entry_point NVARCHAR(30) COLLATE database_default NULL,

    max_worker_threads INT NULL)

    -- Check if replication is installed

    EXECUTE master.dbo.xp_instance_regread N'HKEY_LOCAL_MACHINE',

    N'SOFTWARE\Microsoft\MSSQLServer\Replication',

    N'IsInstalled',

    @replication_installed OUTPUT,

    N'no_output'

    SELECT @replication_installed = ISNULL(@replication_installed, 0)

    INSERT INTO #xp_results

    EXECUTE master.dbo.xp_instance_regenumvalues N'HKEY_LOCAL_MACHINE', N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent\SubSystems'

    IF (@replication_installed = 0)

    BEGIN

    DELETE FROM #xp_results

    WHERE (subsystem IN (N'Distribution', N'LogReader', N'Merge', N'Snapshot', N'QueueReader'))

    END

    DECLARE all_subsystems CURSOR LOCAL

    FOR

    SELECT subsystem, description

    FROM #xp_results

    OPEN all_subsystems

    FETCH NEXT FROM all_subsystems INTO @subsystem, @part

    WHILE (@@fetch_status = 0)

    BEGIN

    IF (@subsystem = N'TSQL')

    INSERT INTO #sp_enum_ss_temp VALUES (N'TSQL', FORMATMESSAGE(14556), FORMATMESSAGE(14557), FORMATMESSAGE(14557), FORMATMESSAGE(14557), FORMATMESSAGE(14557), FORMATMESSAGE(14557), CONVERT(INT, @part))

    ELSE

    BEGIN

    SELECT @fmt = N''

    WHILE (CHARINDEX(N',', @part) > 0)

    BEGIN

    SELECT @fmt = @fmt + 'N''' + SUBSTRING(@part, 1, CHARINDEX(N',', @part) - 1) + ''', '

    SELECT @part = RIGHT(@part, (DATALENGTH(@part) / 2) - CHARINDEX(N',', @part))

    END

    SELECT @fmt = @fmt + @part

    IF (DATALENGTH(@fmt) > 0)

    INSERT INTO #sp_enum_ss_temp

    EXECUTE(N'SELECT ''' + @subsystem + N''', N'''', ' + @fmt)

    END

    FETCH NEXT FROM all_subsystems INTO @subsystem, @part

    END

    DEALLOCATE all_subsystems

    UPDATE #sp_enum_ss_temp SET description = FORMATMESSAGE(14550)

    WHERE (subsystem = N'CmdExec')

    UPDATE #sp_enum_ss_temp SET description = FORMATMESSAGE(14551)

    WHERE (subsystem = N'Snapshot')

    UPDATE #sp_enum_ss_temp SET description = FORMATMESSAGE(14552)

    WHERE (subsystem = N'LogReader')

    UPDATE #sp_enum_ss_temp SET description = FORMATMESSAGE(14553)

    WHERE (subsystem = N'Distribution')

    UPDATE #sp_enum_ss_temp SET description = FORMATMESSAGE(14554)

    WHERE (subsystem = N'Merge')

    UPDATE #sp_enum_ss_temp SET description = FORMATMESSAGE(14555)

    WHERE (subsystem = N'ActiveScripting')

    UPDATE #sp_enum_ss_temp SET description = FORMATMESSAGE(14581)

    WHERE (subsystem = N'QueueReader')

    -- 'TSQL' is always available (since it's a built-in subsystem), so we explicity add it

    -- to the result set

    IF (NOT EXISTS (SELECT *

    FROM #sp_enum_ss_temp

    WHERE (subsystem = N'TSQL')))

    INSERT INTO #sp_enum_ss_temp VALUES (N'TSQL', FORMATMESSAGE(14556), FORMATMESSAGE(14557), FORMATMESSAGE(14557), FORMATMESSAGE(14557), FORMATMESSAGE(14557), FORMATMESSAGE(14557), CASE (PLATFORM() & 0x2) WHEN 0x2 THEN 10 ELSE 20 END) -- Worker thread rule should match DEF_REG_MAX_TSQL_WORKER_THREADS

    SELECT subsystem,

    description,

    subsystem_dll,

    agent_exe,

    start_entry_point,

    event_entry_point,

    stop_entry_point,

    max_worker_threads

    FROM #sp_enum_ss_temp

    ORDER BY subsystem

    END

    go

    /**************************************************************/

    /* SP_VERIFY_SUBSYSTEM */

    /**************************************************************/

    PRINT ''

    PRINT 'Creating procedure sp_verify_subsystem...'

    go

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = N'sp_verify_subsystem')

    AND (type = 'P')))

    DROP PROCEDURE sp_verify_subsystem

    go

    CREATE PROCEDURE sp_verify_subsystem

    @subsystem NVARCHAR(40)

    AS

    BEGIN

    SET NOCOUNT ON

    -- Remove any leading/trailing spaces from parameters

    SELECT @subsystem = LTRIM(RTRIM(@subsystem))

    -- NOTE: We don't use the results of sp_enum_sqlagent_subsystems for performance reasons

    IF (UPPER(@subsystem collate SQL_Latin1_General_CP1_CS_AS) IN

    (N'ACTIVESCRIPTING',

    N'CMDEXEC',

    N'DISTRIBUTION',

    N'SNAPSHOT',

    N'LOGREADER',

    N'MERGE',

    N'TSQL',

    N'QUEUEREADER'))

    RETURN(0) -- Success

    ELSE

    BEGIN

    RAISERROR(14234, -1, -1, '@subsystem', 'sp_enum_sqlagent_subsystems')

    RETURN(1) -- Failure

    END

    END

    go

    /**************************************************************/

    /* SP_GET_JOBSTEP_DB_USERNAME */

    /* */

    /* NOTE: For NT login names this procedure can take several */

    /* seconds to return as it hits the PDC/BDC. */

    /* SQLServerAgent calls this at runtime. */

    /**************************************************************/

    PRINT ''

    PRINT 'Creating procedure sp_get_jobstep_db_username...'

    go

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = N'sp_get_jobstep_db_username ')

    AND (type = 'P')))

    DROP PROCEDURE sp_get_jobstep_db_username

    go

    CREATE PROCEDURE sp_get_jobstep_db_username

    @database_name sysname,

    @login_name sysname = NULL,

    @username_in_targetdb sysname OUTPUT

    AS

    BEGIN

    DECLARE @suser_sid_clause NVARCHAR(200)

    CREATE TABLE #temp_username (user_name sysname COLLATE database_default NOT NULL, is_aliased BIT)

    -- Check the database name

    IF (DB_ID(@database_name) IS NULL)

    BEGIN

    RAISERROR(14262, 16, 1, 'database', @database_name)

    RETURN(1) -- Failure

    END

    -- Initialize return value

    SELECT @username_in_targetdb = NULL

    -- Make sure login name is never NULL

    IF (@login_name IS NULL)

    SELECT @login_name = SUSER_SNAME()

    IF (@login_name IS NULL)

    RETURN(1) -- Failure

    -- Handle an NT login name

    IF (@login_name LIKE N'%\%')

    BEGIN

    -- Special case...

    IF (UPPER(@login_name) = N'NT AUTHORITY\SYSTEM')

    SELECT @username_in_targetdb = N'dbo'

    ELSE

    SELECT @username_in_targetdb = @login_name

    RETURN(0) -- Success

    END

    -- Handle a SQL login name

    SELECT @suser_sid_clause = N'SUSER_SID(N''' + @login_name + N''')'

    IF (SUSER_SID(@login_name) IS NULL)

    RETURN(1) -- Failure

    -- 1) Look for the user name of the current login in the target database

    INSERT INTO #temp_username

    EXECUTE (N'SET NOCOUNT ON

    SELECT name, isaliased

    FROM '+ @database_name + N'.dbo.sysusers

    WHERE (sid = ' + @suser_sid_clause + N')

    AND (hasdbaccess = 1)')

    -- 2) Look for the alias user name of the current login in the target database

    IF (EXISTS (SELECT *

    FROM #temp_username

    WHERE (is_aliased = 1)))

    BEGIN

    TRUNCATE TABLE #temp_username

    INSERT INTO #temp_username

    EXECUTE (N'SET NOCOUNT ON

    SELECT name, 0

    FROM '+ @database_name + N'.dbo.sysusers

    WHERE uid = (SELECT altuid

    FROM ' + @database_name + N'.dbo.sysusers

    WHERE (sid = ' + @suser_sid_clause + N'))

    AND (hasdbaccess = 1)')

    END

    -- 3) Look for the guest user name in the target database

    IF (NOT EXISTS (SELECT *

    FROM #temp_username))

    INSERT INTO #temp_username

    EXECUTE (N'SET NOCOUNT ON

    SELECT name, 0

    FROM '+ @database_name + N'.dbo.sysusers

    WHERE (name = N''guest'')

    AND (hasdbaccess = 1)')

    SELECT @username_in_targetdb = user_name

    FROM #temp_username

    RETURN(0) -- Success

    END

    go

    /**************************************************************/

    /* SP_VERIFY_JOBSTEP */

    /**************************************************************/

    PRINT ''

    PRINT 'Creating procedure sp_verify_jobstep...'

    go

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = N'sp_verify_jobstep')

    AND (type = 'P')))

    DROP PROCEDURE sp_verify_jobstep

    go

    CREATE PROCEDURE sp_verify_jobstep

    @job_id UNIQUEIDENTIFIER,

    @step_id INT,

    @step_name sysname,

    @subsystem NVARCHAR(40),

    @command NVARCHAR(3201),

    @server NVARCHAR(30),

    @on_success_action TINYINT,

    @on_success_step_id INT,

    @on_fail_action TINYINT,

    @on_fail_step_id INT,

    @os_run_priority INT,

    @database_name sysname OUTPUT,

    @database_user_name sysname OUTPUT,

    @flags INT,

    @output_file_name NVARCHAR(200)

    AS

    BEGIN

    DECLARE @max_step_id INT

    DECLARE @retval INT

    DECLARE @valid_values VARCHAR(50)

    DECLARE @owner_login_name sysname

    DECLARE @database_name_temp sysname

    DECLARE @database_user_name_temp sysname

    DECLARE @temp_command NVARCHAR(3200)

    DECLARE @iPos INT

    DECLARE @create_count INT

    DECLARE @destroy_count INT

    SET NOCOUNT ON

    -- Remove any leading/trailing spaces from parameters

    SELECT @subsystem = LTRIM(RTRIM(@subsystem))

    SELECT @server = LTRIM(RTRIM(@server))

    SELECT @output_file_name = LTRIM(RTRIM(@output_file_name))

    -- Get current maximum step id

    SELECT @max_step_id = ISNULL(MAX(step_id), 0)

    FROM msdb.dbo.sysjobsteps

    WHERE (job_id = @job_id)

    -- Check step id

    IF (@step_id @max_step_id + 1)

    BEGIN

    SELECT @valid_values = '1..' + CONVERT(VARCHAR, @max_step_id + 1)

    RAISERROR(14266, -1, -1, '@step_id', @valid_values)

    RETURN(1) -- Failure

    END

    -- Check subsystem

    EXECUTE @retval = sp_verify_subsystem @subsystem

    IF (@retval <> 0)

    RETURN(1) -- Failure

    -- Check command length

    IF ((DATALENGTH(@command) / 2) > 3200)

    BEGIN

    RAISERROR(14250, 16, 1, '@command', 3200)

    RETURN(1) -- Failure

    END

    -- For a VBScript command, check that object creations are paired with object destructions

    IF ((UPPER(@subsystem) = N'ACTIVESCRIPTING') AND (@database_name = N'VBScript'))

    BEGIN

    SELECT @temp_command = @command

    SELECT @create_count = 0

    SELECT @iPos = PATINDEX('%[Cc]reate[Oo]bject[ (]%', @temp_command)

    WHILE(@iPos > 0)

    BEGIN

    SELECT @temp_command = SUBSTRING(@temp_command, @iPos + 1, DATALENGTH(@temp_command) / 2)

    SELECT @iPos = PATINDEX('%[Cc]reate[Oo]bject[ (]%', @temp_command)

    SELECT @create_count = @create_count + 1

    END

    SELECT @destroy_count = 0

    SELECT @iPos = PATINDEX('%[Ss]et %=%[Nn]othing%', @temp_command)

    WHILE(@iPos > 0)

    BEGIN

    SELECT @temp_command = SUBSTRING(@temp_command, @iPos + 1, DATALENGTH(@temp_command) / 2)

    SELECT @iPos = PATINDEX('%[Ss]et %=%[Nn]othing%', @temp_command)

    SELECT @destroy_count = @destroy_count + 1

    END

    IF(@create_count > @destroy_count)

    BEGIN

    RAISERROR(14277, -1, -1)

    RETURN(1) -- Failure

    END

    END

    -- Check step name

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysjobsteps

    WHERE (job_id = @job_id)

    AND (step_name = @step_name)))

    BEGIN

    RAISERROR(14261, -1, -1, '@step_name', @step_name)

    RETURN(1) -- Failure

    END

    -- Check on-success action/step

    IF (@on_success_action <> 1) AND -- Quit Qith Success

    (@on_success_action <> 2) AND -- Quit Qith Failure

    (@on_success_action <> 3) AND -- Goto Next Step

    (@on_success_action <> 4) -- Goto Step

    BEGIN

    RAISERROR(14266, -1, -1, '@on_success_action', '1, 2, 3, 4')

    RETURN(1) -- Failure

    END

    IF (@on_success_action = 4) AND

    ((@on_success_step_id < 1) OR (@on_success_step_id = @step_id))

    BEGIN

    -- NOTE: We allow forward references to non-existant steps to prevent the user from

    -- having to make a second update pass to fix up the flow

    RAISERROR(14235, -1, -1, '@on_success_step', @step_id)

    RETURN(1) -- Failure

    END

    -- Check on-fail action/step

    IF (@on_fail_action <> 1) AND -- Quit Qith Success

    (@on_fail_action <> 2) AND -- Quit Qith Failure

    (@on_fail_action <> 3) AND -- Goto Next Step

    (@on_fail_action <> 4) -- Goto Step

    BEGIN

    RAISERROR(14266, -1, -1, '@on_failure_action', '1, 2, 3, 4')

    RETURN(1) -- Failure

    END

    IF (@on_fail_action = 4) AND

    ((@on_fail_step_id < 1) OR (@on_fail_step_id = @step_id))

    BEGIN

    -- NOTE: We allow forward references to non-existant steps to prevent the user from

    -- having to make a second update pass to fix up the flow

    RAISERROR(14235, -1, -1, '@on_failure_step', @step_id)

    RETURN(1) -- Failure

    END

    -- Warn the user about forward references

    IF ((@on_success_action = 4) AND (@on_success_step_id > @max_step_id))

    RAISERROR(14236, 0, 1, '@on_success_step_id')

    IF ((@on_fail_action = 4) AND (@on_fail_step_id > @max_step_id))

    RAISERROR(14236, 0, 1, '@on_fail_step_id')

    -- Check server (this is the replication server, NOT the job-target server)

    IF (@server IS NOT NULL) AND (NOT EXISTS (SELECT *

    FROM master.dbo.sysservers

    WHERE (UPPER(srvname) = UPPER(@server))))

    BEGIN

    RAISERROR(14234, -1, -1, '@server', 'sp_helpserver')

    RETURN(1) -- Failure

    END

    -- Check run priority: must be a valid value to pass to SetThreadPriority:

    -- [-15 = IDLE, -1 = BELOW_NORMAL, 0 = NORMAL, 1 = ABOVE_NORMAL, 15 = TIME_CRITICAL]

    IF (@os_run_priority NOT IN (-15, -1, 0, 1, 15))

    BEGIN

    RAISERROR(14266, -1, -1, '@os_run_priority', '-15, -1, 0, 1, 15')

    RETURN(1) -- Failure

    END

    -- Check flags

    IF ((@flags 7))

    BEGIN

    RAISERROR(14266, -1, -1, '@flags', '0..7')

    RETURN(1) -- Failure

    END

    -- Check output file

    IF (@output_file_name IS NOT NULL) AND (UPPER(@subsystem) NOT IN ('TSQL', 'CMDEXEC'))

    BEGIN

    RAISERROR(14545, -1, -1, '@output_file_name', @subsystem)

    RETURN(1) -- Failure

    END

    -- For CmdExec steps database-name and database-user-name should both be null

    IF (UPPER(@subsystem) = N'CMDEXEC')

    SELECT @database_name = NULL,

    @database_user_name = NULL

    -- For non-TSQL steps, database-user-name should be null

    IF (UPPER(@subsystem) <> 'TSQL')

    SELECT @database_user_name = NULL

    -- For a TSQL step, get (and check) the username of the caller in the target database.

    IF (UPPER(@subsystem) = 'TSQL')

    BEGIN

    SET NOCOUNT ON

    -- But first check if remote server name has been supplied

    IF (@server IS NOT NULL)

    SELECT @server = NULL

    -- Default database to 'master' if not supplied

    IF (LTRIM(RTRIM(@database_name)) IS NULL)

    SELECT @database_name = N'master'

    -- Check the database (although this is no guarantee that @database_user_name can access it)

    IF (DB_ID(@database_name) IS NULL)

    BEGIN

    RAISERROR(14262, -1, -1, '@database_name', @database_name)

    RETURN(1) -- Failure

    END

    SELECT @owner_login_name = SUSER_SNAME(owner_sid)

    FROM msdb.dbo.sysjobs

    WHERE (job_id = @job_id)

    SELECT @database_user_name = LTRIM(RTRIM(@database_user_name))

    -- Only if a SysAdmin is creating the job can the database user name be non-NULL [since only

    -- SysAdmin's can call SETUSER].

    -- NOTE: In this case we don't try to validate the user name (it's too costly to do so)

    -- so if it's bad we'll get a runtime error when the job executes.

    IF (ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) = 1)

    BEGIN

    -- Special case handling if the username is 'sa'

    IF (UPPER(@database_user_name) = N'SA')

    SELECT @database_user_name = NULL

    -- If this is a multi-server job then @database_user_name must be null

    IF (@database_user_name IS NOT NULL)

    BEGIN

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysjobs sj,

    msdb.dbo.sysjobservers sjs

    WHERE (sj.job_id = sjs.job_id)

    AND (sj.job_id = @job_id)

    AND (sjs.server_id <> 0)))

    BEGIN

    RAISERROR(14542, -1, -1, N'database_user_name')

    RETURN(1) -- Failure

    END

    END

    -- For a SQL-user, check if it exists

    IF (@database_user_name NOT LIKE N'%\%')

    BEGIN

    SELECT @database_user_name_temp = REPLACE(@database_user_name, N'''', N'''''')

    SELECT @database_name_temp = REPLACE(@database_name, N'''', N'''''')

    EXECUTE(N'DECLARE @ret INT

    SELECT @ret = COUNT(*)

    FROM ' + @database_name_temp + N'.dbo.sysusers

    WHERE (name = N''' + @database_user_name_temp + N''')

    HAVING (COUNT(*) > 0)')

    IF (@@ROWCOUNT = 0)

    BEGIN

    RAISERROR(14262, -1, -1, '@database_user_name', @database_user_name)

    RETURN(1) -- Failure

    END

    END

    END

    ELSE

    SELECT @database_user_name = NULL

    END -- End of TSQL property verification

    RETURN(0) -- Success

    END

    go

    /**************************************************************/

    /* SP_ADD_JOBSTEP_INTERNAL */

    /**************************************************************/

    PRINT ''

    PRINT 'Creating procedure sp_add_jobstep_internal...'

    go

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = N'sp_add_jobstep_internal')

    AND (type = 'P')))

    DROP PROCEDURE dbo.sp_add_jobstep_internal

    go

    CREATE PROCEDURE dbo.sp_add_jobstep_internal

    @job_id UNIQUEIDENTIFIER = NULL, -- Must provide either this or job_name

    @job_name sysname = NULL, -- Must provide either this or job_id

    @step_id INT = NULL, -- The proc assigns a default

    @step_name sysname,

    @subsystem NVARCHAR(40) = N'TSQL',

    @command NVARCHAR(3201) = NULL, -- We declare this as NVARCHAR(3201) not NVARCHAR(3200) so that we can catch 'silent truncation' of commands

    @additional_parameters NTEXT = NULL,

    @cmdexec_success_code INT = 0,

    @on_success_action TINYINT = 1, -- 1 = Quit With Success, 2 = Quit With Failure, 3 = Goto Next Step, 4 = Goto Step

    @on_success_step_id INT = 0,

    @on_fail_action TINYINT = 2, -- 1 = Quit With Success, 2 = Quit With Failure, 3 = Goto Next Step, 4 = Goto Step

    @on_fail_step_id INT = 0,

    @server NVARCHAR(30) = NULL,

    @database_name sysname = NULL,

    @database_user_name sysname = NULL,

    @retry_attempts INT = 0, -- No retries

    @retry_interval INT = 0, -- 0 minute interval

    @os_run_priority INT = 0, -- -15 = Idle, -1 = Below Normal, 0 = Normal, 1 = Above Normal, 15 = Time Critical)

    @output_file_name NVARCHAR(200) = NULL,

    @flags INT = 0 -- 0 = Normal, 1 = Encrypted command (read only), 2 = Append output files (if any), 4 = Write TSQL step output to step history

    AS

    BEGIN

    DECLARE @retval INT

    DECLARE @max_step_id INT

    SET NOCOUNT ON

    -- Remove any leading/trailing spaces from parameters

    SELECT @step_name = LTRIM(RTRIM(@step_name))

    SELECT @subsystem = LTRIM(RTRIM(@subsystem))

    SELECT @server = LTRIM(RTRIM(@server))

    SELECT @database_name = LTRIM(RTRIM(@database_name))

    SELECT @database_user_name = LTRIM(RTRIM(@database_user_name))

    SELECT @output_file_name = LTRIM(RTRIM(@output_file_name))

    -- Turn [nullable] empty string parameters into NULLs

    IF (@server = N'') SELECT @server = NULL

    IF (@database_name = N'') SELECT @database_name = NULL

    IF (@database_user_name = N'') SELECT @database_user_name = NULL

    IF (@output_file_name = N'') SELECT @output_file_name = NULL

    -- Check authority (only SQLServerAgent can add a step to a non-local job)

    EXECUTE @retval = sp_verify_jobproc_caller @job_id = @job_id, @program_name = N'SQLAgent%'

    IF (@retval <> 0)

    RETURN(@retval)

    EXECUTE @retval = sp_verify_job_identifiers '@job_name',

    '@job_id',

    @job_name OUTPUT,

    @job_id OUTPUT

    IF (@retval <> 0)

    RETURN(1) -- Failure

    -- Default step id (if not supplied)

    IF (@step_id IS NULL)

    BEGIN

    SELECT @step_id = ISNULL(MAX(step_id), 0) + 1

    FROM msdb.dbo.sysjobsteps

    WHERE (job_id = @job_id)

    END

    -- Check parameters

    EXECUTE @retval = sp_verify_jobstep @job_id,

    @step_id,

    @step_name,

    @subsystem,

    @command,

    @server,

    @on_success_action,

    @on_success_step_id,

    @on_fail_action,

    @on_fail_step_id,

    @os_run_priority,

    @database_name OUTPUT,

    @database_user_name OUTPUT,

    @flags,

    @output_file_name

    IF (@retval <> 0)

    RETURN(1) -- Failure

    -- Get current maximum step id

    SELECT @max_step_id = ISNULL(MAX(step_id), 0)

    FROM msdb.dbo.sysjobsteps

    WHERE (job_id = @job_id)

    BEGIN TRANSACTION

    -- Update the job's version/last-modified information

    UPDATE msdb.dbo.sysjobs

    SET version_number = version_number + 1,

    date_modified = GETDATE()

    WHERE (job_id = @job_id)

    -- Adjust step id's (unless the new step is being inserted at the 'end')

    -- NOTE: We MUST do this before inserting the step.

    IF (@step_id <= @max_step_id)

    BEGIN

    UPDATE msdb.dbo.sysjobsteps

    SET step_id = step_id + 1

    WHERE (step_id >= @step_id)

    AND (job_id = @job_id)

    -- Clean up OnSuccess/OnFail references

    UPDATE msdb.dbo.sysjobsteps

    SET on_success_step_id = on_success_step_id + 1

    WHERE (on_success_step_id >= @step_id)

    AND (job_id = @job_id)

    UPDATE msdb.dbo.sysjobsteps

    SET on_fail_step_id = on_fail_step_id + 1

    WHERE (on_fail_step_id >= @step_id)

    AND (job_id = @job_id)

    UPDATE msdb.dbo.sysjobsteps

    SET on_success_step_id = 0,

    on_success_action = 1 -- Quit With Success

    WHERE (on_success_step_id = @step_id)

    AND (job_id = @job_id)

    UPDATE msdb.dbo.sysjobsteps

    SET on_fail_step_id = 0,

    on_fail_action = 2 -- Quit With Failure

    WHERE (on_fail_step_id = @step_id)

    AND (job_id = @job_id)

    END

    -- Insert the step

    INSERT INTO msdb.dbo.sysjobsteps

    (job_id,

    step_id,

    step_name,

    subsystem,

    command,

    flags,

    additional_parameters,

    cmdexec_success_code,

    on_success_action,

    on_success_step_id,

    on_fail_action,

    on_fail_step_id,

    server,

    database_name,

    database_user_name,

    retry_attempts,

    retry_interval,

    os_run_priority,

    output_file_name,

    last_run_outcome,

    last_run_duration,

    last_run_retries,

    last_run_date,

    last_run_time)

    VALUES (@job_id,

    @step_id,

    @step_name,

    @subsystem,

    @command,

    @flags,

    @additional_parameters,

    @cmdexec_success_code,

    @on_success_action,

    @on_success_step_id,

    @on_fail_action,

    @on_fail_step_id,

    @server,

    @database_name,

    @database_user_name,

    @retry_attempts,

    @retry_interval,

    @os_run_priority,

    @output_file_name,

    0,

    0,

    0,

    0,

    0)

    COMMIT TRANSACTION

    -- Make sure that SQLServerAgent refreshes the job if the 'Has Steps' property has changed

    IF ((SELECT COUNT(*)

    FROM msdb.dbo.sysjobsteps

    WHERE (job_id = @job_id)) = 1)

    BEGIN

    -- NOTE: We only notify SQLServerAgent if we know the job has been cached

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysjobservers

    WHERE (job_id = @job_id)

    AND (server_id = 0)))

    EXECUTE msdb.dbo.sp_sqlagent_notify @op_type = N'J',

    @job_id = @job_id,

    @action_type = N'U'

    END

    -- For a multi-server job, remind the user that they need to call sp_post_msx_operation

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysjobservers

    WHERE (job_id = @job_id)

    AND (server_id <> 0)))

    RAISERROR(14547, 0, 1, N'INSERT', N'sp_post_msx_operation')

    RETURN(0) -- Success

    END

    go

    /**************************************************************/

    /* SP_ADD_JOBSTEP */

    /**************************************************************/

    PRINT ''

    PRINT 'Creating procedure sp_add_jobstep...'

    go

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = N'sp_add_jobstep')

    AND (type = 'P')))

    DROP PROCEDURE dbo.sp_add_jobstep

    go

    CREATE PROCEDURE dbo.sp_add_jobstep

    @job_id UNIQUEIDENTIFIER = NULL, -- Must provide either this or job_name

    @job_name sysname = NULL, -- Must provide either this or job_id

    @step_id INT = NULL, -- The proc assigns a default

    @step_name sysname,

    @subsystem NVARCHAR(40) = N'TSQL',

    @command NVARCHAR(3201) = NULL, -- We declare this as NVARCHAR(3201) not NVARCHAR(3200) so that we can catch 'silent truncation' of commands

    @additional_parameters NTEXT = NULL,

    @cmdexec_success_code INT = 0,

    @on_success_action TINYINT = 1, -- 1 = Quit With Success, 2 = Quit With Failure, 3 = Goto Next Step, 4 = Goto Step

    @on_success_step_id INT = 0,

    @on_fail_action TINYINT = 2, -- 1 = Quit With Success, 2 = Quit With Failure, 3 = Goto Next Step, 4 = Goto Step

    @on_fail_step_id INT = 0,

    @server NVARCHAR(30) = NULL,

    @database_name sysname = NULL,

    @database_user_name sysname = NULL,

    @retry_attempts INT = 0, -- No retries

    @retry_interval INT = 0, -- 0 minute interval

    @os_run_priority INT = 0, -- -15 = Idle, -1 = Below Normal, 0 = Normal, 1 = Above Normal, 15 = Time Critical)

    @output_file_name NVARCHAR(200) = NULL,

    @flags INT = 0 -- 0 = Normal, 1 = Encrypted command (read only), 2 = Append output files (if any), 4 = Write TSQL step output to step history

    AS

    BEGIN

    DECLARE @retval INT

    SET NOCOUNT ON

    -- Only sysadmin's or db_owner's of msdb can add replication job steps directly

    IF (UPPER(@subsystem collate SQL_Latin1_General_CP1_CS_AS) IN

    (N'DISTRIBUTION',

    N'SNAPSHOT',

    N'LOGREADER',

    N'MERGE',

    N'QUEUEREADER'))

    BEGIN

    IF NOT ((ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) = 1) OR

    (ISNULL(IS_MEMBER(N'db_owner'), 0) = 1) OR

    (UPPER(USER_NAME()) = N'DBO'))

    BEGIN

    RAISERROR(14260, -1, -1)

    RETURN(1) -- Failure

    END

    END

    EXECUTE @retval = dbo.sp_add_jobstep_internal @job_id = @job_id,

    @job_name = @job_name,

    @step_id = @step_id,

    @step_name = @step_name,

    @subsystem = @subsystem,

    @command = @command,

    @additional_parameters = @additional_parameters,

    @cmdexec_success_code = @cmdexec_success_code,

    @on_success_action = @on_success_action,

    @on_success_step_id = @on_success_step_id,

    @on_fail_action = @on_fail_action,

    @on_fail_step_id = @on_fail_step_id,

    @server = @server,

    @database_name = @database_name,

    @database_user_name = @database_user_name,

    @retry_attempts = @retry_attempts,

    @retry_interval = @retry_interval,

    @os_run_priority = @os_run_priority,

    @output_file_name = @output_file_name,

    @flags = @flags

    RETURN(@retval)

    END

    GO

    /**************************************************************/

    /* SP_UPDATE_JOBSTEP */

    /**************************************************************/

    PRINT ''

    PRINT 'Creating procedure sp_update_jobstep...'

    go

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = N'sp_update_jobstep')

    AND (type = 'P')))

    DROP PROCEDURE sp_update_jobstep

    go

    CREATE PROCEDURE sp_update_jobstep

    @job_id UNIQUEIDENTIFIER = NULL, -- Must provide either this or job_name

    @job_name sysname = NULL, -- Not updatable (provided for identification purposes only)

    @step_id INT, -- Not updatable (provided for identification purposes only)

    @step_name sysname = NULL,

    @subsystem NVARCHAR(40) = NULL,

    @command NVARCHAR(3201) = NULL, -- We declare this as NVARCHAR(3201) not NVARCHAR(3200) so that we can catch 'silent truncation' of commands

    @additional_parameters NTEXT = NULL,

    @cmdexec_success_code INT = NULL,

    @on_success_action TINYINT = NULL,

    @on_success_step_id INT = NULL,

    @on_fail_action TINYINT = NULL,

    @on_fail_step_id INT = NULL,

    @server NVARCHAR(30) = NULL,

    @database_name sysname = NULL,

    @database_user_name sysname = NULL,

    @retry_attempts INT = NULL,

    @retry_interval INT = NULL,

    @os_run_priority INT = NULL,

    @output_file_name NVARCHAR(200) = NULL,

    @flags INT = NULL

    AS

    BEGIN

    DECLARE @retval INT

    DECLARE @os_run_priority_code INT

    DECLARE @step_id_as_char VARCHAR(10)

    DECLARE @new_step_name sysname

    DECLARE @x_step_name sysname

    DECLARE @x_subsystem NVARCHAR(40)

    DECLARE @x_command NVARCHAR(3200)

    DECLARE @x_flags INT

    DECLARE @x_cmdexec_success_code INT

    DECLARE @x_on_success_action TINYINT

    DECLARE @x_on_success_step_id INT

    DECLARE @x_on_fail_action TINYINT

    DECLARE @x_on_fail_step_id INT

    DECLARE @x_server NVARCHAR(30)

    DECLARE @x_database_name sysname

    DECLARE @x_database_user_name sysname

    DECLARE @x_retry_attempts INT

    DECLARE @x_retry_interval INT

    DECLARE @x_os_run_priority INT

    DECLARE @x_output_file_name NVARCHAR(200)

    DECLARE @x_last_run_outcome TINYINT -- Not updatable (but may be in future)

    DECLARE @x_last_run_duration INT -- Not updatable (but may be in future)

    DECLARE @x_last_run_retries INT -- Not updatable (but may be in future)

    DECLARE @x_last_run_date INT -- Not updatable (but may be in future)

    DECLARE @x_last_run_time INT -- Not updatable (but may be in future)

    SET NOCOUNT ON

    -- Remove any leading/trailing spaces from parameters

    SELECT @step_name = LTRIM(RTRIM(@step_name))

    SELECT @subsystem = LTRIM(RTRIM(@subsystem))

    SELECT @command = LTRIM(RTRIM(@command))

    SELECT @server = LTRIM(RTRIM(@server))

    SELECT @database_name = LTRIM(RTRIM(@database_name))

    SELECT @database_user_name = LTRIM(RTRIM(@database_user_name))

    SELECT @output_file_name = LTRIM(RTRIM(@output_file_name))

    -- Only sysadmin's or db_owner's of msdb can directly change

    -- an existing job step to use one of the replication

    -- subsystems

    IF (UPPER(@subsystem collate SQL_Latin1_General_CP1_CS_AS) IN

    (N'DISTRIBUTION',

    N'SNAPSHOT',

    N'LOGREADER',

    N'MERGE',

    N'QUEUEREADER'))

    BEGIN

    IF NOT ((ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) = 1) OR

    (ISNULL(IS_MEMBER(N'db_owner'), 0) = 1) OR

    (UPPER(USER_NAME()) = N'DBO'))

    BEGIN

    RAISERROR(14260, -1, -1)

    RETURN(1) -- Failure

    END

    END

    EXECUTE @retval = sp_verify_job_identifiers '@job_name',

    '@job_id',

    @job_name OUTPUT,

    @job_id OUTPUT

    IF (@retval <> 0)

    RETURN(1) -- Failure

    -- Check that the step exists

    IF (NOT EXISTS (SELECT *

    FROM msdb.dbo.sysjobsteps

    WHERE (job_id = @job_id)

    AND (step_id = @step_id)))

    BEGIN

    SELECT @step_id_as_char = CONVERT(VARCHAR(10), @step_id)

    RAISERROR(14262, -1, -1, '@step_id', @step_id_as_char)

    RETURN(1) -- Failure

    END

    -- Check authority (only SQLServerAgent can modify a step of a non-local job)

    EXECUTE @retval = sp_verify_jobproc_caller @job_id = @job_id, @program_name = N'SQLAgent%'

    IF (@retval <> 0)

    RETURN(@retval)

    -- Set the x_ (existing) variables

    SELECT @x_step_name = step_name,

    @x_subsystem = subsystem,

    @x_command = command,

    @x_flags = flags,

    @x_cmdexec_success_code = cmdexec_success_code,

    @x_on_success_action = on_success_action,

    @x_on_success_step_id = on_success_step_id,

    @x_on_fail_action = on_fail_action,

    @x_on_fail_step_id = on_fail_step_id,

    @x_server = server,

    @x_database_name = database_name,

    @x_database_user_name = database_user_name,

    @x_retry_attempts = retry_attempts,

    @x_retry_interval = retry_interval,

    @x_os_run_priority = os_run_priority,

    @x_output_file_name = output_file_name,

    @x_last_run_outcome = last_run_outcome,

    @x_last_run_duration = last_run_duration,

    @x_last_run_retries = last_run_retries,

    @x_last_run_date = last_run_date,

    @x_last_run_time = last_run_time

    FROM msdb.dbo.sysjobsteps

    WHERE (job_id = @job_id)

    AND (step_id = @step_id)

    IF ((@step_name IS NOT NULL) AND (@step_name <> @x_step_name))

    SELECT @new_step_name = @step_name

    -- Fill out the values for all non-supplied parameters from the existing values

    IF (@step_name IS NULL) SELECT @step_name = @x_step_name

    IF (@subsystem IS NULL) SELECT @subsystem = @x_subsystem

    IF (@command IS NULL) SELECT @command = @x_command

    IF (@flags IS NULL) SELECT @flags = @x_flags

    IF (@cmdexec_success_code IS NULL) SELECT @cmdexec_success_code = @x_cmdexec_success_code

    IF (@on_success_action IS NULL) SELECT @on_success_action = @x_on_success_action

    IF (@on_success_step_id IS NULL) SELECT @on_success_step_id = @x_on_success_step_id

    IF (@on_fail_action IS NULL) SELECT @on_fail_action = @x_on_fail_action

    IF (@on_fail_step_id IS NULL) SELECT @on_fail_step_id = @x_on_fail_step_id

    IF (@server IS NULL) SELECT @server = @x_server

    IF (@database_name IS NULL) SELECT @database_name = @x_database_name

    IF (@database_user_name IS NULL) SELECT @database_user_name = @x_database_user_name

    IF (@retry_attempts IS NULL) SELECT @retry_attempts = @x_retry_attempts

    IF (@retry_interval IS NULL) SELECT @retry_interval = @x_retry_interval

    IF (@os_run_priority IS NULL) SELECT @os_run_priority = @x_os_run_priority

    IF (@output_file_name IS NULL) SELECT @output_file_name = @x_output_file_name

    -- Turn [nullable] empty string parameters into NULLs

    IF (@command = N'') SELECT @command = NULL

    IF (@server = N'') SELECT @server = NULL

    IF (@database_name = N'') SELECT @database_name = NULL

    IF (@database_user_name = N'') SELECT @database_user_name = NULL

    IF (@output_file_name = N'') SELECT @output_file_name = NULL

    -- Check new values

    EXECUTE @retval = sp_verify_jobstep @job_id,

    @step_id,

    @new_step_name,

    @subsystem,

    @command,

    @server,

    @on_success_action,

    @on_success_step_id,

    @on_fail_action,

    @on_fail_step_id,

    @os_run_priority,

    @database_name OUTPUT,

    @database_user_name OUTPUT,

    @flags,

    @output_file_name

    IF (@retval <> 0)

    RETURN(1) -- Failure

    BEGIN TRANSACTION

    -- Update the job's version/last-modified information

    UPDATE msdb.dbo.sysjobs

    SET version_number = version_number + 1,

    date_modified = GETDATE()

    WHERE (job_id = @job_id)

    -- Update the step

    UPDATE msdb.dbo.sysjobsteps

    SET step_name = @step_name,

    subsystem = @subsystem,

    command = @command,

    flags = @flags,

    cmdexec_success_code = @cmdexec_success_code,

    on_success_action = @on_success_action,

    on_success_step_id = @on_success_step_id,

    on_fail_action = @on_fail_action,

    on_fail_step_id = @on_fail_step_id,

    server = @server,

    database_name = @database_name,

    database_user_name = @database_user_name,

    retry_attempts = @retry_attempts,

    retry_interval = @retry_interval,

    os_run_priority = @os_run_priority,

    output_file_name = @output_file_name,

    last_run_outcome = @x_last_run_outcome,

    last_run_duration = @x_last_run_duration,

    last_run_retries = @x_last_run_retries,

    last_run_date = @x_last_run_date,

    last_run_time = @x_last_run_time

    WHERE (job_id = @job_id)

    AND (step_id = @step_id)

    -- Since we can't declare TEXT parameters (and therefore use the @x_ technique) we handle

    -- @additional_parameters as a special case...

    IF (@additional_parameters IS NOT NULL)

    BEGIN

    UPDATE msdb.dbo.sysjobsteps

    SET additional_parameters = @additional_parameters

    WHERE (job_id = @job_id)

    AND (step_id = @step_id)

    END

    COMMIT TRANSACTION

    -- For a multi-server job, remind the user that they need to call sp_post_msx_operation

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysjobservers

    WHERE (job_id = @job_id)

    AND (server_id <> 0)))

    RAISERROR(14547, 0, 1, N'INSERT', N'sp_post_msx_operation')

    RETURN(0) -- Success

    END

    go

    /**************************************************************/

    /* SP_DELETE_JOBSTEP */

    /**************************************************************/

    PRINT ''

    PRINT 'Creating procedure sp_delete_jobstep...'

    go

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = N'sp_delete_jobstep')

    AND (type = 'P')))

    DROP PROCEDURE sp_delete_jobstep

    go

    CREATE PROCEDURE sp_delete_jobstep

    @job_id UNIQUEIDENTIFIER = NULL, -- Must provide either this or job_name

    @job_name sysname = NULL, -- Must provide either this or job_id

    @step_id INT

    AS

    BEGIN

    DECLARE @retval INT

    DECLARE @max_step_id INT

    DECLARE @valid_range VARCHAR(50)

    SET NOCOUNT ON

    EXECUTE @retval = sp_verify_job_identifiers '@job_name',

    '@job_id',

    @job_name OUTPUT,

    @job_id OUTPUT

    IF (@retval <> 0)

    RETURN(1) -- Failure

    -- Check authority (only SQLServerAgent can delete a step of a non-local job)

    EXECUTE @retval = sp_verify_jobproc_caller @job_id = @job_id, @program_name = 'SQLAgent%'

    IF (@retval <> 0)

    RETURN(@retval)

    -- Get current maximum step id

    SELECT @max_step_id = ISNULL(MAX(step_id), 0)

    FROM msdb.dbo.sysjobsteps

    WHERE (job_id = @job_id)

    -- Check step id

    IF (@step_id @max_step_id)

    BEGIN

    SELECT @valid_range = FORMATMESSAGE(14201) + CONVERT(VARCHAR, @max_step_id)

    RAISERROR(14266, -1, -1, '@step_id', @valid_range)

    RETURN(1) -- Failure

    END

    BEGIN TRANSACTION

    -- Delete either the specified step or ALL the steps (if step id is 0)

    IF (@step_id = 0)

    DELETE FROM msdb.dbo.sysjobsteps

    WHERE (job_id = @job_id)

    ELSE

    DELETE FROM msdb.dbo.sysjobsteps

    WHERE (job_id = @job_id)

    AND (step_id = @step_id)

    IF (@step_id <> 0)

    BEGIN

    -- Adjust step id's

    UPDATE msdb.dbo.sysjobsteps

    SET step_id = step_id - 1

    WHERE (step_id > @step_id)

    AND (job_id = @job_id)

    -- Clean up OnSuccess/OnFail references

    UPDATE msdb.dbo.sysjobsteps

    SET on_success_step_id = on_success_step_id - 1

    WHERE (on_success_step_id > @step_id)

    AND (job_id = @job_id)

    UPDATE msdb.dbo.sysjobsteps

    SET on_fail_step_id = on_fail_step_id - 1

    WHERE (on_fail_step_id > @step_id)

    AND (job_id = @job_id)

    UPDATE msdb.dbo.sysjobsteps

    SET on_success_step_id = 0,

    on_success_action = 1 -- Quit With Success

    WHERE (on_success_step_id = @step_id)

    AND (job_id = @job_id)

    UPDATE msdb.dbo.sysjobsteps

    SET on_fail_step_id = 0,

    on_fail_action = 2 -- Quit With Failure

    WHERE (on_fail_step_id = @step_id)

    AND (job_id = @job_id)

    END

    -- Update the job's version/last-modified information

    UPDATE msdb.dbo.sysjobs

    SET version_number = version_number + 1,

    date_modified = GETDATE()

    WHERE (job_id = @job_id)

    COMMIT TRANSACTION

    -- Make sure that SQLServerAgent refreshes the job if the 'Has Steps' property has changed

    IF ((SELECT COUNT(*)

    FROM msdb.dbo.sysjobsteps

    WHERE (job_id = @job_id)) = 0)

    BEGIN

    -- NOTE: We only notify SQLServerAgent if we know the job has been cached

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysjobservers

    WHERE (job_id = @job_id)

    AND (server_id = 0)))

    EXECUTE msdb.dbo.sp_sqlagent_notify @op_type = N'J',

    @job_id = @job_id,

    @action_type = N'U'

    END

    -- For a multi-server job, remind the user that they need to call sp_post_msx_operation

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysjobservers

    WHERE (job_id = @job_id)

    AND (server_id <> 0)))

    RAISERROR(14547, 0, 1, N'INSERT', N'sp_post_msx_operation')

    RETURN(0) -- Success

    END

    go

    /**************************************************************/

    /* SP_HELP_JOBSTEP */

    /**************************************************************/

    PRINT ''

    PRINT 'Creating procedure sp_help_jobstep...'

    go

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = N'sp_help_jobstep')

    AND (type = 'P')))

    DROP PROCEDURE sp_help_jobstep

    go

    CREATE PROCEDURE sp_help_jobstep

    @job_id UNIQUEIDENTIFIER = NULL, -- Must provide either this or job_name

    @job_name sysname = NULL, -- Must provide either this or job_id

    @step_id INT = NULL,

    @step_name sysname = NULL,

    @suffix BIT = 0 -- A flag to control how the result set is formatted

    AS

    BEGIN

    DECLARE @retval INT

    DECLARE @max_step_id INT

    DECLARE @valid_range VARCHAR(50)

    SET NOCOUNT ON

    EXECUTE @retval = sp_verify_job_identifiers '@job_name',

    '@job_id',

    @job_name OUTPUT,

    @job_id OUTPUT,

    'NO_TEST'

    IF (@retval <> 0)

    RETURN(1) -- Failure

    -- The suffix flag must be either 0 (ie. no suffix) or 1 (ie. add suffix). 0 is the default.

    IF (@suffix <> 0)

    SELECT @suffix = 1

    -- Check step id (if supplied)

    IF (@step_id IS NOT NULL)

    BEGIN

    -- Get current maximum step id

    SELECT @max_step_id = ISNULL(MAX(step_id), 0)

    FROM msdb.dbo.sysjobsteps

    WHERE job_id = @job_id

    IF (@step_id @max_step_id)

    BEGIN

    SELECT @valid_range = '1..' + CONVERT(VARCHAR, @max_step_id)

    RAISERROR(14266, -1, -1, '@step_id', @valid_range)

    RETURN(1) -- Failure

    END

    END

    -- Check step name (if supplied)

    -- NOTE: A supplied step id overrides a supplied step name

    IF ((@step_id IS NULL) AND (@step_name IS NOT NULL))

    BEGIN

    SELECT @step_id = step_id

    FROM msdb.dbo.sysjobsteps

    WHERE (step_name = @step_name)

    AND (job_id = @job_id)

    IF (@step_id IS NULL)

    BEGIN

    RAISERROR(14262, -1, -1, '@step_name', @step_name)

    RETURN(1) -- Failure

    END

    END

    -- Return the job steps for this job (or just return the specific step)

    IF (@suffix = 0)

    BEGIN

    SELECT step_id,

    step_name,

    subsystem,

    command,

    flags,

    cmdexec_success_code,

    on_success_action,

    on_success_step_id,

    on_fail_action,

    on_fail_step_id,

    server,

    database_name,

    database_user_name,

    retry_attempts,

    retry_interval,

    os_run_priority,

    output_file_name,

    last_run_outcome,

    last_run_duration,

    last_run_retries,

    last_run_date,

    last_run_time

    FROM msdb.dbo.sysjobsteps

    WHERE (job_id = @job_id)

    AND ((@step_id IS NULL) OR (step_id = @step_id))

    END

    ELSE

    BEGIN

    SELECT step_id,

    step_name,

    subsystem,

    command,

    'flags' = CONVERT(NVARCHAR, flags) + N' (' +

    ISNULL(CASE WHEN (flags = 0) THEN FORMATMESSAGE(14561) END, '') +

    ISNULL(CASE WHEN (flags & 1) = 1 THEN FORMATMESSAGE(14558) + ISNULL(CASE WHEN (flags > 1) THEN N', ' END, '') END, '') +

    ISNULL(CASE WHEN (flags & 2) = 2 THEN FORMATMESSAGE(14559) + ISNULL(CASE WHEN (flags > 3) THEN N', ' END, '') END, '') +

    ISNULL(CASE WHEN (flags & 4) = 4 THEN FORMATMESSAGE(14560) END, '') + N')',

    cmdexec_success_code,

    'on_success_action' = CASE on_success_action

    WHEN 1 THEN CONVERT(NVARCHAR, on_success_action) + N' ' + FORMATMESSAGE(14562)

    WHEN 2 THEN CONVERT(NVARCHAR, on_success_action) + N' ' + FORMATMESSAGE(14563)

    WHEN 3 THEN CONVERT(NVARCHAR, on_success_action) + N' ' + FORMATMESSAGE(14564)

    WHEN 4 THEN CONVERT(NVARCHAR, on_success_action) + N' ' + FORMATMESSAGE(14565)

    ELSE CONVERT(NVARCHAR, on_success_action) + N' ' + FORMATMESSAGE(14205)

    END,

    on_success_step_id,

    'on_fail_action' = CASE on_fail_action

    WHEN 1 THEN CONVERT(NVARCHAR, on_fail_action) + N' ' + FORMATMESSAGE(14562)

    WHEN 2 THEN CONVERT(NVARCHAR, on_fail_action) + N' ' + FORMATMESSAGE(14563)

    WHEN 3 THEN CONVERT(NVARCHAR, on_fail_action) + N' ' + FORMATMESSAGE(14564)

    WHEN 4 THEN CONVERT(NVARCHAR, on_fail_action) + N' ' + FORMATMESSAGE(14565)

    ELSE CONVERT(NVARCHAR, on_fail_action) + N' ' + FORMATMESSAGE(14205)

    END,

    on_fail_step_id,

    server,

    database_name,

    database_user_name,

    retry_attempts,

    retry_interval,

    'os_run_priority' = CASE os_run_priority

    WHEN -15 THEN CONVERT(NVARCHAR, os_run_priority) + N' ' + FORMATMESSAGE(14566)

    WHEN -1 THEN CONVERT(NVARCHAR, os_run_priority) + N' ' + FORMATMESSAGE(14567)

    WHEN 0 THEN CONVERT(NVARCHAR, os_run_priority) + N' ' + FORMATMESSAGE(14561)

    WHEN 1 THEN CONVERT(NVARCHAR, os_run_priority) + N' ' + FORMATMESSAGE(14568)

    WHEN 15 THEN CONVERT(NVARCHAR, os_run_priority) + N' ' + FORMATMESSAGE(14569)

    ELSE CONVERT(NVARCHAR, os_run_priority) + N' ' + FORMATMESSAGE(14205)

    END,

    output_file_name,

    last_run_outcome,

    last_run_duration,

    last_run_retries,

    last_run_date,

    last_run_time

    FROM msdb.dbo.sysjobsteps

    WHERE (job_id = @job_id)

    AND ((@step_id IS NULL) OR (step_id = @step_id))

    END

    RETURN(@@error) -- 0 means success

    END

    go

    /**************************************************************/

    /* SP_GET_SCHEDULE_DESCRIPTION */

    /* */

    /* NOTE: This SP only returns an English description of the */

    /* schedule due to the piecemeal nature of the */

    /* description's construction. */

    /**************************************************************/

    PRINT ''

    PRINT 'Creating procedure sp_get_schedule_description...'

    go

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = N'sp_get_schedule_description')

    AND (type = 'P')))

    DROP PROCEDURE sp_get_schedule_description

    go

    CREATE PROCEDURE sp_get_schedule_description

    @freq_type INT = NULL,

    @freq_interval INT = NULL,

    @freq_subday_type INT = NULL,

    @freq_subday_interval INT = NULL,

    @freq_relative_interval INT = NULL,

    @freq_recurrence_factor INT = NULL,

    @active_start_date INT = NULL,

    @active_end_date INT = NULL,

    @active_start_time INT = NULL,

    @active_end_time INT = NULL,

    @schedule_description NVARCHAR(255) OUTPUT

    AS

    BEGIN

    DECLARE @loop INT

    DECLARE @idle_cpu_percent INT

    DECLARE @idle_cpu_duration INT

    SET NOCOUNT ON

    IF (@freq_type = 0x1) -- OneTime

    BEGIN

    SELECT @schedule_description = N'Once on ' + CONVERT(NVARCHAR, @active_start_date) + N' at ' + CONVERT(NVARCHAR, @active_start_time)

    RETURN

    END

    IF (@freq_type = 0x4) -- Daily

    BEGIN

    SELECT @schedule_description = N'Every day '

    END

    IF (@freq_type = 0x8) -- Weekly

    BEGIN

    SELECT @schedule_description = N'Every ' + CONVERT(NVARCHAR, @freq_recurrence_factor) + N' week(s) on '

    SELECT @loop = 1

    WHILE (@loop <= 7)

    BEGIN

    IF (@freq_interval & POWER(2, @loop - 1) = POWER(2, @loop - 1))

    SELECT @schedule_description = @schedule_description + DATENAME(dw, N'1996120' + CONVERT(NVARCHAR, @loop)) + N', '

    SELECT @loop = @loop + 1

    END

    IF (RIGHT(@schedule_description, 2) = N', ')

    SELECT @schedule_description = SUBSTRING(@schedule_description, 1, (DATALENGTH(@schedule_description) / 2) - 2) + N' '

    END

    IF (@freq_type = 0x10) -- Monthly

    BEGIN

    SELECT @schedule_description = N'Every ' + CONVERT(NVARCHAR, @freq_recurrence_factor) + N' months(s) on day ' + CONVERT(NVARCHAR, @freq_interval) + N' of that month '

    END

    IF (@freq_type = 0x20) -- Monthly Relative

    BEGIN

    SELECT @schedule_description = N'Every ' + CONVERT(NVARCHAR, @freq_recurrence_factor) + N' months(s) on the '

    SELECT @schedule_description = @schedule_description +

    CASE @freq_relative_interval

    WHEN 0x01 THEN N'first '

    WHEN 0x02 THEN N'second '

    WHEN 0x04 THEN N'third '

    WHEN 0x08 THEN N'fourth '

    WHEN 0x10 THEN N'last '

    END +

    CASE

    WHEN (@freq_interval > 00)

    AND (@freq_interval < 08) THEN DATENAME(dw, N'1996120' + CONVERT(NVARCHAR, @freq_interval))

    WHEN (@freq_interval = 08) THEN N'day'

    WHEN (@freq_interval = 09) THEN N'week day'

    WHEN (@freq_interval = 10) THEN N'weekend day'

    END + N' of that month '

    END

    IF (@freq_type = 0x40) -- AutoStart

    BEGIN

    SELECT @schedule_description = FORMATMESSAGE(14579)

    RETURN

    END

    IF (@freq_type = 0x80) -- OnIdle

    BEGIN

    EXECUTE master.dbo.xp_instance_regread N'HKEY_LOCAL_MACHINE',

    N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',

    N'IdleCPUPercent',

    @idle_cpu_percent OUTPUT,

    N'no_output'

    EXECUTE master.dbo.xp_instance_regread N'HKEY_LOCAL_MACHINE',

    N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',

    N'IdleCPUDuration',

    @idle_cpu_duration OUTPUT,

    N'no_output'

    SELECT @schedule_description = FORMATMESSAGE(14578, ISNULL(@idle_cpu_percent, 10), ISNULL(@idle_cpu_duration, 600))

    RETURN

    END

    -- Subday stuff

    SELECT @schedule_description = @schedule_description +

    CASE @freq_subday_type

    WHEN 0x1 THEN N'at ' + CONVERT(NVARCHAR, @active_start_time)

    WHEN 0x2 THEN N'every ' + CONVERT(NVARCHAR, @freq_subday_interval) + N' second(s)'

    WHEN 0x4 THEN N'every ' + CONVERT(NVARCHAR, @freq_subday_interval) + N' minute(s)'

    WHEN 0x8 THEN N'every ' + CONVERT(NVARCHAR, @freq_subday_interval) + N' hour(s)'

    END

    IF (@freq_subday_type IN (0x2, 0x4, 0x8))

    SELECT @schedule_description = @schedule_description + N' between ' +

    CONVERT(NVARCHAR, @active_start_time) + N' and ' + CONVERT(NVARCHAR, @active_end_time)

    END

    go

    DUMP TRANSACTION msdb WITH NO_LOG

    go

    CHECKPOINT

    go

    /**************************************************************/

    /* SP_VERIFY_JOBSCHEDULE */

    /**************************************************************/

    PRINT ''

    PRINT 'Creating procedure sp_verify_jobschedule...'

    go

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = N'sp_verify_jobschedule')

    AND (type = 'P')))

    DROP PROCEDURE sp_verify_jobschedule

    go

    CREATE PROCEDURE sp_verify_jobschedule

    @name sysname,

    @enabled TINYINT,

    @freq_type INT,

    @freq_interval INT OUTPUT, -- Output because we may set it to 0 if Frequency Type is one-time or auto-start

    @freq_subday_type INT OUTPUT, -- As above

    @freq_subday_interval INT OUTPUT, -- As above

    @freq_relative_interval INT OUTPUT, -- As above

    @freq_recurrence_factor INT OUTPUT, -- As above

    @active_start_date INT OUTPUT,

    @active_start_time INT OUTPUT,

    @active_end_date INT OUTPUT,

    @active_end_time INT OUTPUT,

    @job_id UNIQUEIDENTIFIER,

    @schedule_id INT -- Will only be provided by sp_update_jobschedule

    AS

    BEGIN

    DECLARE @return_code INT

    DECLARE @duplicate_schedule_id INT

    DECLARE @duplicate_schedule_name sysname

    DECLARE @res_valid_range NVARCHAR(100)

    DECLARE @reason NVARCHAR(200)

    SET NOCOUNT ON

    -- Remove any leading/trailing spaces from parameters

    SELECT @name = LTRIM(RTRIM(@name))

    -- Make sure that NULL input/output parameters - if NULL - are initialized to 0

    SELECT @freq_interval = ISNULL(@freq_interval, 0)

    SELECT @freq_subday_type = ISNULL(@freq_subday_type, 0)

    SELECT @freq_subday_interval = ISNULL(@freq_subday_interval, 0)

    SELECT @freq_relative_interval = ISNULL(@freq_relative_interval, 0)

    SELECT @freq_recurrence_factor = ISNULL(@freq_recurrence_factor, 0)

    SELECT @active_start_date = ISNULL(@active_start_date, 0)

    SELECT @active_start_time = ISNULL(@active_start_time, 0)

    SELECT @active_end_date = ISNULL(@active_end_date, 0)

    SELECT @active_end_time = ISNULL(@active_end_time, 0)

    -- Verify name (we disallow schedules called 'ALL' since this has special meaning in sp_delete_jobschedules)

    IF (UPPER(@name) = N'ALL')

    BEGIN

    RAISERROR(14200, -1, -1, '@name')

    RETURN(1) -- Failure

    END

    -- Verify enabled state

    IF (@enabled <> 0) AND (@enabled <> 1)

    BEGIN

    RAISERROR(14266, -1, -1, '@enabled', '0, 1')

    RETURN(1) -- Failure

    END

    -- Verify frequency type

    IF (@freq_type = 0x2) -- OnDemand is no longer supported

    BEGIN

    RAISERROR(14295, -1, -1)

    RETURN(1) -- Failure

    END

    IF (@freq_type NOT IN (0x1, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80))

    BEGIN

    RAISERROR(14266, -1, -1, '@freq_type', '0x1, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80')

    RETURN(1) -- Failure

    END

    -- Verify frequency sub-day type

    IF (@freq_subday_type <> 0) AND (@freq_subday_type NOT IN (0x1, 0x2, 0x4, 0x8))

    BEGIN

    RAISERROR(14266, -1, -1, '@freq_subday_type', '0x1, 0x2, 0x4, 0x8')

    RETURN(1) -- Failure

    END

    -- Default active start/end date/times (if not supplied, or supplied as NULLs or 0)

    IF (@active_start_date = 0)

    SELECT @active_start_date = DATEPART(yy, GETDATE()) * 10000 +

    DATEPART(mm, GETDATE()) * 100 +

    DATEPART(dd, GETDATE())

    IF (@active_end_date = 0)

    SELECT @active_end_date = 99991231 -- December 31st 9999

    IF (@active_start_time = 0)

    SELECT @active_start_time = 000000 -- 12:00:00 am

    IF (@active_end_time = 0)

    SELECT @active_end_time = 235959 -- 11:59:59 pm

    -- Verify active start/end dates

    IF (@active_end_date = 0)

    SELECT @active_end_date = 99991231

    EXECUTE @return_code = sp_verify_job_date @active_end_date, '@active_end_date'

    IF (@return_code <> 0)

    RETURN(1) -- Failure

    EXECUTE @return_code = sp_verify_job_date @active_start_date, '@active_start_date'

    IF (@return_code <> 0)

    RETURN(1) -- Failure

    IF (@active_end_date < @active_start_date)

    BEGIN

    RAISERROR(14288, -1, -1, '@active_end_date', '@active_start_date')

    RETURN(1) -- Failure

    END

    -- Verify active start/end times

    IF (@active_end_time = 0)

    SELECT @active_end_time = 235959

    EXECUTE @return_code = sp_verify_job_time @active_end_time, '@active_end_time'

    IF (@return_code <> 0)

    RETURN(1) -- Failure

    EXECUTE @return_code = sp_verify_job_time @active_start_time, '@active_start_time'

    IF (@return_code <> 0)

    RETURN(1) -- Failure

    -- NOTE: It's valid for active_end_time to be less than active_start_time since in this

    -- case we assume that the user wants the active time zone to span midnight.

    -- But it's not valid for active_start_date and active_end_date to be the same...

    IF (@active_start_time = @active_end_time)

    BEGIN

    SELECT @res_valid_range = FORMATMESSAGE(14202)

    RAISERROR(14266, -1, -1, '@active_end_time', @res_valid_range)

    RETURN(1) -- Failure

    END

    -- NOTE: The rest of this procedure is a SQL implementation of VerifySchedule in job.c

    IF ((@freq_type = 0x1) OR -- FREQTYPE_ONETIME

    (@freq_type = 0x40) OR -- FREQTYPE_AUTOSTART

    (@freq_type = 0x80)) -- FREQTYPE_ONIDLE

    BEGIN

    -- Set standard defaults for non-required parameters

    SELECT @freq_interval = 0

    SELECT @freq_subday_type = 0

    SELECT @freq_subday_interval = 0

    SELECT @freq_relative_interval = 0

    SELECT @freq_recurrence_factor = 0

    /*

    -- Check that a one-time schedule isn't already in the past

    IF (@freq_type = 0x1) -- FREQTYPE_ONETIME

    BEGIN

    DECLARE @current_date INT

    DECLARE @current_time INT

    SELECT @current_date = CONVERT(INT, CONVERT(VARCHAR, GETDATE(), 112))

    SELECT @current_time = (DATEPART(hh, GETDATE()) * 10000) + (DATEPART(mi, GETDATE()) * 100) + DATEPART(ss, GETDATE())

    IF (@active_start_date < @current_date) OR ((@active_start_date = @current_date) AND (@active_start_time <= @current_time))

    BEGIN

    SELECT @res_valid_range = '> ' + CONVERT(VARCHAR, @current_date) + ' / ' + CONVERT(VARCHAR, @current_time)

    RAISERROR(14266, -1, -1, '@active_start_date'' / ''@active_start_time', @res_valid_range)

    RETURN(1) -- Failure

    END

    END

    */

    GOTO CheckForDuplicate

    END

    -- Safety net: If the sub-day-type is 0 (and we know that the schedule is not a one-time or

    -- auto-start) then set it to 1 (FREQSUBTYPE_ONCE). If the user wanted something

    -- other than ONCE then they should have explicitly set @freq_subday_type.

    IF (@freq_subday_type = 0)

    SELECT @freq_subday_type = 0x1 -- FREQSUBTYPE_ONCE

    IF ((@freq_subday_type <> 0x1) AND -- FREQSUBTYPE_ONCE (see qsched.h)

    (@freq_subday_type <> 0x2) AND -- FREQSUBTYPE_SECOND (see qsched.h)

    (@freq_subday_type <> 0x4) AND -- FREQSUBTYPE_MINUTE (see qsched.h)

    (@freq_subday_type <> 0x8)) -- FREQSUBTYPE_HOUR (see qsched.h)

    BEGIN

    SELECT @reason = FORMATMESSAGE(14266, '@freq_subday_type', '0x1, 0x2, 0x4, 0x8')

    RAISERROR(14278, -1, -1, @reason)

    RETURN(1) -- Failure

    END

    IF ((@freq_subday_type <> 0x1) AND (@freq_subday_interval < 1))

    OR

    ((@freq_subday_type = 0x2) AND (@freq_subday_interval < 10))

    BEGIN

    SELECT @reason = FORMATMESSAGE(14200, '@freq_subday_interval')

    RAISERROR(14278, -1, -1, @reason)

    RETURN(1) -- Failure

    END

    IF (@freq_type = 0x4) -- FREQTYPE_DAILY

    BEGIN

    SELECT @freq_recurrence_factor = 0

    IF (@freq_interval < 1)

    BEGIN

    SELECT @reason = FORMATMESSAGE(14572)

    RAISERROR(14278, -1, -1, @reason)

    RETURN(1) -- Failure

    END

    END

    IF (@freq_type = 0x8) -- FREQTYPE_WEEKLY

    BEGIN

    IF (@freq_interval < 1) OR

    (@freq_interval > 127) -- (2^7)-1 [freq_interval is a bitmap (Sun=1..Sat=64)]

    BEGIN

    SELECT @reason = FORMATMESSAGE(14573)

    RAISERROR(14278, -1, -1, @reason)

    RETURN(1) -- Failure

    END

    END

    IF (@freq_type = 0x10) -- FREQTYPE_MONTHLY

    BEGIN

    IF (@freq_interval < 1) OR

    (@freq_interval > 31)

    BEGIN

    SELECT @reason = FORMATMESSAGE(14574)

    RAISERROR(14278, -1, -1, @reason)

    RETURN(1) -- Failure

    END

    END

    IF (@freq_type = 0x20) -- FREQTYPE_MONTHLYRELATIVE

    BEGIN

    IF (@freq_relative_interval <> 0x01) AND -- RELINT_1ST

    (@freq_relative_interval <> 0x02) AND -- RELINT_2ND

    (@freq_relative_interval <> 0x04) AND -- RELINT_3RD

    (@freq_relative_interval <> 0x08) AND -- RELINT_4TH

    (@freq_relative_interval <> 0x10) -- RELINT_LAST

    BEGIN

    SELECT @reason = FORMATMESSAGE(14575)

    RAISERROR(14278, -1, -1, @reason)

    RETURN(1) -- Failure

    END

    END

    IF (@freq_type = 0x20) -- FREQTYPE_MONTHLYRELATIVE

    BEGIN

    IF (@freq_interval <> 01) AND -- RELATIVE_SUN

    (@freq_interval <> 02) AND -- RELATIVE_MON

    (@freq_interval <> 03) AND -- RELATIVE_TUE

    (@freq_interval <> 04) AND -- RELATIVE_WED

    (@freq_interval <> 05) AND -- RELATIVE_THU

    (@freq_interval <> 06) AND -- RELATIVE_FRI

    (@freq_interval <> 07) AND -- RELATIVE_SAT

    (@freq_interval <> 08) AND -- RELATIVE_DAY

    (@freq_interval <> 09) AND -- RELATIVE_WEEKDAY

    (@freq_interval <> 10) -- RELATIVE_WEEKENDDAY

    BEGIN

    SELECT @reason = FORMATMESSAGE(14576)

    RAISERROR(14278, -1, -1, @reason)

    RETURN(1) -- Failure

    END

    END

    IF ((@freq_type = 0x08) OR -- FREQTYPE_WEEKLY

    (@freq_type = 0x10) OR -- FREQTYPE_MONTHLY

    (@freq_type = 0x20)) AND -- FREQTYPE_MONTHLYRELATIVE

    (@freq_recurrence_factor < 1)

    BEGIN

    SELECT @reason = FORMATMESSAGE(14577)

    RAISERROR(14278, -1, -1, @reason)

    RETURN(1) -- Failure

    END

    CheckForDuplicate:

    -- Check that the schedule is not a duplicate

    SELECT @duplicate_schedule_id = NULL

    SELECT @duplicate_schedule_id = schedule_id,

    @duplicate_schedule_name = name

    FROM msdb.dbo.sysjobschedules

    WHERE (job_id = @job_id)

    AND (freq_type = @freq_type)

    AND (freq_interval = @freq_interval)

    AND (freq_subday_type = @freq_subday_type)

    AND (freq_subday_interval = @freq_subday_interval)

    AND (freq_relative_interval = @freq_relative_interval)

    AND (freq_recurrence_factor = @freq_recurrence_factor)

    AND (active_start_date = @active_start_date)

    AND (active_start_time = @active_start_time)

    IF ((@duplicate_schedule_id IS NOT NULL) AND (@duplicate_schedule_id <> @schedule_id))

    BEGIN

    RAISERROR(14259, -1, -1, @duplicate_schedule_id, @duplicate_schedule_name)

    RETURN(1) -- Failure

    END

    -- If we made it this far the schedule is good

    RETURN(0) -- Success

    END

    go

    /**************************************************************/

    /* SP_ADD_JOBSCHEDULE */

    /**************************************************************/

    PRINT ''

    PRINT 'Creating procedure sp_add_jobschedule...'

    go

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = N'sp_add_jobschedule')

    AND (type = 'P')))

    DROP PROCEDURE sp_add_jobschedule

    go

    CREATE PROCEDURE sp_add_jobschedule

    @job_id UNIQUEIDENTIFIER = NULL,

    @job_name sysname = NULL,

    @name sysname,

    @enabled TINYINT = 1,

    @freq_type INT = 0,

    @freq_interval INT = 0,

    @freq_subday_type INT = 0,

    @freq_subday_interval INT = 0,

    @freq_relative_interval INT = 0,

    @freq_recurrence_factor INT = 0,

    @active_start_date INT = NULL, -- sp_verify_jobschedule assigns a default

    @active_end_date INT = 99991231, -- December 31st 9999

    @active_start_time INT = 000000, -- 12:00:00 am

    @active_end_time INT = 235959 -- 11:59:59 pm

    AS

    BEGIN

    DECLARE @retval INT

    DECLARE @schedule_id INT

    SET NOCOUNT ON

    -- Remove any leading/trailing spaces from parameters

    SELECT @name = LTRIM(RTRIM(@name))

    SELECT @schedule_id = 0

    -- Check authority (only SQLServerAgent can add a schedule to a non-local job)

    EXECUTE @retval = sp_verify_jobproc_caller @job_id = @job_id, @program_name = N'SQLAgent%'

    IF (@retval <> 0)

    RETURN(@retval)

    -- Check that we can uniquely identify the job

    EXECUTE @retval = sp_verify_job_identifiers '@job_name',

    '@job_id',

    @job_name OUTPUT,

    @job_id OUTPUT

    IF (@retval <> 0)

    RETURN(1) -- Failure

    -- Check that the schedule name doesn't already exist

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysjobschedules

    WHERE (job_id = @job_id)

    AND (name = @name)))

    BEGIN

    RAISERROR(14261, -1, -1, '@name', @name)

    RETURN(1) -- Failure

    END

    -- Check schedule (frequency) parameters

    EXECUTE @retval = sp_verify_jobschedule @name,

    @enabled,

    @freq_type,

    @freq_interval OUTPUT,

    @freq_subday_type OUTPUT,

    @freq_subday_interval OUTPUT,

    @freq_relative_interval OUTPUT,

    @freq_recurrence_factor OUTPUT,

    @active_start_date OUTPUT,

    @active_start_time OUTPUT,

    @active_end_date OUTPUT,

    @active_end_time OUTPUT,

    @job_id,

    NULL

    IF (@retval <> 0)

    RETURN(1) -- Failure

    INSERT INTO msdb.dbo.sysjobschedules

    (job_id,

    name,

    enabled,

    freq_type,

    freq_interval,

    freq_subday_type,

    freq_subday_interval,

    freq_relative_interval,

    freq_recurrence_factor,

    active_start_date,

    active_end_date,

    active_start_time,

    active_end_time,

    next_run_date,

    next_run_time)

    VALUES (@job_id,

    @name,

    @enabled,

    @freq_type,

    @freq_interval,

    @freq_subday_type,

    @freq_subday_interval,

    @freq_relative_interval,

    @freq_recurrence_factor,

    @active_start_date,

    @active_end_date,

    @active_start_time,

    @active_end_time,

    0,

    0)

    SELECT @retval = @@error

    -- Update the job's version/last-modified information

    UPDATE msdb.dbo.sysjobs

    SET version_number = version_number + 1,

    date_modified = GETDATE()

    WHERE (job_id = @job_id)

    SELECT @schedule_id = schedule_id

    FROM msdb.dbo.sysjobschedules

    WHERE (job_id = @job_id)

    AND (name = @name)

    -- Notify SQLServerAgent of the change, but only if we know the job has been cached

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysjobservers

    WHERE (job_id = @job_id)

    AND (server_id = 0)))

    BEGIN

    EXECUTE msdb.dbo.sp_sqlagent_notify @op_type = N'S',

    @job_id = @job_id,

    @schedule_id = @schedule_id,

    @action_type = N'I'

    END

    -- For a multi-server job, remind the user that they need to call sp_post_msx_operation

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysjobservers

    WHERE (job_id = @job_id)

    AND (server_id <> 0)))

    RAISERROR(14547, 0, 1, N'INSERT', N'sp_post_msx_operation')

    RETURN(@retval) -- 0 means success

    END

    go

    /**************************************************************/

    /* SP_UPDATE_REPLICATION_JOB_PARAMETER */

    /**************************************************************/

    PRINT ''

    PRINT 'Creating procedure sp_update_replication_job_parameter...'

    go

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = 'sp_update_replication_job_parameter')

    AND (type = 'P')))

    DROP PROCEDURE sp_update_replication_job_parameter

    go

    CREATE PROCEDURE sp_update_replication_job_parameter

    @job_id UNIQUEIDENTIFIER,

    @old_freq_type INT,

    @new_freq_type INT

    AS

    BEGIN

    DECLARE @category_id INT

    DECLARE @pattern NVARCHAR(50)

    DECLARE @patternidx INT

    DECLARE @cmdline NVARCHAR(3200)

    DECLARE @step_id INT

    SET NOCOUNT ON

    SELECT @pattern = N'%[-/][Cc][Oo][Nn][Tt][Ii][Nn][Uu][Oo][Uu][Ss]%'

    -- Make sure that we are dealing with relevant replication jobs

    SELECT @category_id = category_id

    FROM msdb.dbo.sysjobs

    WHERE (@job_id = job_id)

    -- @category_id = 10 (REPL-Distribution), 13 (REPL-LogReader), 14 (REPL-Merge),

    -- 19 (REPL-QueueReader)

    IF @category_id IN (10, 13, 14, 19)

    BEGIN

    -- Adding the -Continuous parameter (non auto-start to auto-start)

    IF ((@old_freq_type <> 0x40) AND (@new_freq_type = 0x40))

    BEGIN

    -- Use a cursor to handle multiple replication agent job steps

    DECLARE step_cursor CURSOR LOCAL FOR

    SELECT command, step_id

    FROM msdb.dbo.sysjobsteps

    WHERE (@job_id = job_id)

    AND (UPPER(subsystem) IN (N'MERGE', N'LOGREADER', N'DISTRIBUTION', N'QUEUEREADER'))

    OPEN step_cursor

    FETCH step_cursor INTO @cmdline, @step_id

    WHILE (@@FETCH_STATUS <> -1)

    BEGIN

    SELECT @patternidx = PATINDEX(@pattern, @cmdline)

    -- Make sure that the -Continuous parameter has not been specified already

    IF (@patternidx = 0)

    BEGIN

    SELECT @cmdline = @cmdline + N' -Continuous'

    UPDATE msdb.dbo.sysjobsteps

    SET command = @cmdline

    WHERE (@job_id = job_id)

    AND (@step_id = step_id)

    END -- IF (@patternidx = 0)

    FETCH NEXT FROM step_cursor into @cmdline, @step_id

    END -- WHILE (@@FETCH_STATUS <> -1)

    CLOSE step_cursor

    DEALLOCATE step_cursor

    END -- IF ((@old_freq_type...

    -- Removing the -Continuous parameter (auto-start to non auto-start)

    ELSE

    IF ((@old_freq_type = 0x40) AND (@new_freq_type <> 0x40))

    BEGIN

    DECLARE step_cursor CURSOR LOCAL FOR

    SELECT command, step_id

    FROM msdb.dbo.sysjobsteps

    WHERE (@job_id = job_id)

    AND (UPPER(subsystem) IN (N'MERGE', N'LOGREADER', N'DISTRIBUTION', N'QUEUEREADER'))

    OPEN step_cursor

    FETCH step_cursor INTO @cmdline, @step_id

    WHILE (@@FETCH_STATUS <> -1)

    BEGIN

    SELECT @patternidx = PATINDEX(@pattern, @cmdline)

    IF (@patternidx <> 0)

    BEGIN

    -- Handle multiple instances of -Continuous in the commandline

    WHILE (@patternidx <> 0)

    BEGIN

    SELECT @cmdline = STUFF(@cmdline, @patternidx, 11, N'')

    IF (@patternidx > 1)

    BEGIN

    -- Remove the preceding space if -Continuous does not start at the beginning of the commandline

    SELECT @cmdline = stuff(@cmdline, @patternidx - 1, 1, N'')

    END

    SELECT @patternidx = PATINDEX(@pattern, @cmdline)

    END -- WHILE (@patternidx <> 0)

    UPDATE msdb.dbo.sysjobsteps

    SET command = @cmdline

    WHERE (@job_id = job_id)

    AND (@step_id = step_id)

    END -- IF (@patternidx <> -1)

    FETCH NEXT FROM step_cursor INTO @cmdline, @step_id

    END -- WHILE (@@FETCH_STATUS <> -1)

    CLOSE step_cursor

    DEALLOCATE step_cursor

    END -- ELSE IF ((@old_freq_type = 0x40)...

    END -- IF @category_id IN (10, 13, 14)

    RETURN 0

    END

    go

    /**************************************************************/

    /* SP_UPDATE_JOBSCHEDULE */

    /**************************************************************/

    PRINT ''

    PRINT 'Creating procedure sp_update_jobschedule...'

    go

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = N'sp_update_jobschedule')

    AND (type = 'P')))

    DROP PROCEDURE sp_update_jobschedule

    go

    CREATE PROCEDURE sp_update_jobschedule

    @job_id UNIQUEIDENTIFIER = NULL,

    @job_name sysname = NULL,

    @name sysname,

    @new_name sysname = NULL,

    @enabled TINYINT = NULL,

    @freq_type INT = NULL,

    @freq_interval INT = NULL,

    @freq_subday_type INT = NULL,

    @freq_subday_interval INT = NULL,

    @freq_relative_interval INT = NULL,

    @freq_recurrence_factor INT = NULL,

    @active_start_date INT = NULL,

    @active_end_date INT = NULL,

    @active_start_time INT = NULL,

    @active_end_time INT = NULL

    AS

    BEGIN

    DECLARE @retval INT

    DECLARE @schedule_id INT

    DECLARE @x_name sysname

    DECLARE @x_enabled TINYINT

    DECLARE @x_freq_type INT

    DECLARE @x_freq_interval INT

    DECLARE @x_freq_subday_type INT

    DECLARE @x_freq_subday_interval INT

    DECLARE @x_freq_relative_interval INT

    DECLARE @x_freq_recurrence_factor INT

    DECLARE @x_active_start_date INT

    DECLARE @x_active_end_date INT

    DECLARE @x_active_start_time INT

    DECLARE @x_active_end_time INT

    SET NOCOUNT ON

    -- Remove any leading/trailing spaces from parameters

    SELECT @name = LTRIM(RTRIM(@name))

    SELECT @new_name = LTRIM(RTRIM(@new_name))

    -- Turn [nullable] empty string parameters into NULLs

    IF (@new_name = N'') SELECT @new_name = NULL

    -- Check authority (only SQLServerAgent can modify a schedule of a non-local job)

    EXECUTE @retval = sp_verify_jobproc_caller @job_id = @job_id, @program_name = 'SQLAgent%'

    IF (@retval <> 0)

    RETURN(@retval)

    -- Check that we can uniquely identify the job

    EXECUTE @retval = sp_verify_job_identifiers '@job_name',

    '@job_id',

    @job_name OUTPUT,

    @job_id OUTPUT

    IF (@retval <> 0)

    RETURN(1) -- Failure

    -- Check that the schedule exists

    SELECT @schedule_id = schedule_id

    FROM msdb.dbo.sysjobschedules

    WHERE (job_id = @job_id)

    AND (name = @name)

    IF (@schedule_id IS NULL)

    BEGIN

    RAISERROR(14262, -1, -1, 'Schedule Name', @name)

    RETURN(1) -- Failure

    END

    -- Set the x_ (existing) variables

    SELECT @x_name = name,

    @x_enabled = enabled,

    @x_freq_type = freq_type,

    @x_freq_interval = freq_interval,

    @x_freq_subday_type = freq_subday_type,

    @x_freq_subday_interval = freq_subday_interval,

    @x_freq_relative_interval = freq_relative_interval,

    @x_freq_recurrence_factor = freq_recurrence_factor,

    @x_active_start_date = active_start_date,

    @x_active_end_date = active_end_date,

    @x_active_start_time = active_start_time,

    @x_active_end_time = active_end_time

    FROM msdb.dbo.sysjobschedules

    WHERE (job_id = @job_id)

    AND (name = @name)

    -- Check that the new name (if any) doesn't already exist for this job

    IF (@new_name IS NOT NULL)

    BEGIN

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysjobschedules

    WHERE (job_id = @job_id)

    AND (name = @new_name)

    AND (@name <> @new_name)))

    BEGIN

    RAISERROR(14261, -1, -1, '@new_name', @new_name)

    RETURN(1) -- Failure

    END

    END

    -- Fill out the values for all non-supplied parameters from the existing values

    IF (@new_name IS NULL) SELECT @new_name = @x_name

    IF (@enabled IS NULL) SELECT @enabled = @x_enabled

    IF (@freq_type IS NULL) SELECT @freq_type = @x_freq_type

    IF (@freq_interval IS NULL) SELECT @freq_interval = @x_freq_interval

    IF (@freq_subday_type IS NULL) SELECT @freq_subday_type = @x_freq_subday_type

    IF (@freq_subday_interval IS NULL) SELECT @freq_subday_interval = @x_freq_subday_interval

    IF (@freq_relative_interval IS NULL) SELECT @freq_relative_interval = @x_freq_relative_interval

    IF (@freq_recurrence_factor IS NULL) SELECT @freq_recurrence_factor = @x_freq_recurrence_factor

    IF (@active_start_date IS NULL) SELECT @active_start_date = @x_active_start_date

    IF (@active_end_date IS NULL) SELECT @active_end_date = @x_active_end_date

    IF (@active_start_time IS NULL) SELECT @active_start_time = @x_active_start_time

    IF (@active_end_time IS NULL) SELECT @active_end_time = @x_active_end_time

    -- Check schedule (frequency) parameters

    EXECUTE @retval = sp_verify_jobschedule @new_name,

    @enabled,

    @freq_type,

    @freq_interval OUTPUT,

    @freq_subday_type OUTPUT,

    @freq_subday_interval OUTPUT,

    @freq_relative_interval OUTPUT,

    @freq_recurrence_factor OUTPUT,

    @active_start_date OUTPUT,

    @active_start_time OUTPUT,

    @active_end_date OUTPUT,

    @active_end_time OUTPUT,

    @job_id,

    @schedule_id

    IF (@retval <> 0)

    RETURN(1) -- Failure

    -- Update the JobSchedule

    UPDATE msdb.dbo.sysjobschedules

    SET name = @new_name,

    enabled = @enabled,

    freq_type = @freq_type,

    freq_interval = @freq_interval,

    freq_subday_type = @freq_subday_type,

    freq_subday_interval = @freq_subday_interval,

    freq_relative_interval = @freq_relative_interval,

    freq_recurrence_factor = @freq_recurrence_factor,

    active_start_date = @active_start_date,

    active_end_date = @active_end_date,

    active_start_time = @active_start_time,

    active_end_time = @active_end_time,

    next_run_date = 0, -- Since SQLServerAgent needs to recalculate it

    next_run_time = 0 -- Since SQLServerAgent needs to recalculate it

    WHERE (job_id = @job_id)

    AND (name = @name)

    SELECT @retval = @@error

    -- Update the job's version/last-modified information

    UPDATE msdb.dbo.sysjobs

    SET version_number = version_number + 1,

    date_modified = GETDATE()

    WHERE (job_id = @job_id)

    -- Notify SQLServerAgent of the change, but only if we know the job has been cached

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysjobservers

    WHERE (job_id = @job_id)

    AND (server_id = 0)))

    BEGIN

    EXECUTE msdb.dbo.sp_sqlagent_notify @op_type = N'S',

    @job_id = @job_id,

    @schedule_id = @schedule_id,

    @action_type = N'U'

    END

    -- For a multi-server job, remind the user that they need to call sp_post_msx_operation

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysjobservers

    WHERE (job_id = @job_id)

    AND (server_id <> 0)))

    RAISERROR(14547, 0, 1, N'INSERT', N'sp_post_msx_operation')

    -- Automatic addition and removal of -Continous parameter for replication agent

    EXECUTE sp_update_replication_job_parameter @job_id = @job_id,

    @old_freq_type = @x_freq_type,

    @new_freq_type = @freq_type

    RETURN(@retval) -- 0 means success

    END

    go

    /**************************************************************/

    /* SP_DELETE_JOBSCHEDULE */

    /**************************************************************/

    PRINT ''

    PRINT 'Creating procedure sp_delete_jobschedule...'

    go

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = 'sp_delete_jobschedule')

    AND (type = 'P')))

    DROP PROCEDURE sp_delete_jobschedule

    go

    CREATE PROCEDURE sp_delete_jobschedule

    @job_id UNIQUEIDENTIFIER = NULL,

    @job_name sysname = NULL,

    @name sysname

    AS

    BEGIN

    DECLARE @retval INT

    DECLARE @schedule_id INT

    SET NOCOUNT ON

    -- Remove any leading/trailing spaces from parameters

    SELECT @name = LTRIM(RTRIM(@name))

    -- Check authority (only SQLServerAgent can delete a schedule of a non-local job)

    EXECUTE @retval = sp_verify_jobproc_caller @job_id = @job_id, @program_name = N'SQLAgent%'

    IF (@retval <> 0)

    RETURN(@retval)

    -- Check that we can uniquely identify the job

    EXECUTE @retval = sp_verify_job_identifiers '@job_name',

    '@job_id',

    @job_name OUTPUT,

    @job_id OUTPUT

    IF (@retval <> 0)

    RETURN(1) -- Failure

    IF (UPPER(@name) = N'ALL')

    BEGIN

    SELECT @schedule_id = -1 -- We use this in the call to sp_sqlagent_notify

    DELETE FROM msdb.dbo.sysjobschedules

    WHERE (job_id = @job_id)

    END

    ELSE

    BEGIN

    -- Check that the schedule exists

    SELECT @schedule_id = schedule_id

    FROM msdb.dbo.sysjobschedules

    WHERE (job_id = @job_id)

    AND (name = @name)

    IF (@schedule_id IS NULL)

    BEGIN

    RAISERROR(14262, -1, -1, '@name', @name)

    RETURN(1) -- Failure

    END

    DELETE FROM msdb.dbo.sysjobschedules

    WHERE (job_id = @job_id)

    AND (schedule_id = @schedule_id)

    END

    SELECT @retval = @@error

    -- Update the job's version/last-modified information

    UPDATE msdb.dbo.sysjobs

    SET version_number = version_number + 1,

    date_modified = GETDATE()

    WHERE (job_id = @job_id)

    -- Notify SQLServerAgent of the change, but only if we know the job has been cached

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysjobservers

    WHERE (job_id = @job_id)

    AND (server_id = 0)))

    BEGIN

    EXECUTE msdb.dbo.sp_sqlagent_notify @op_type = N'S',

    @job_id = @job_id,

    @schedule_id = @schedule_id,

    @action_type = N'D'

    END

    -- For a multi-server job, remind the user that they need to call sp_post_msx_operation

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysjobservers

    WHERE (job_id = @job_id)

    AND (server_id <> 0)))

    RAISERROR(14547, 0, 1, N'INSERT', N'sp_post_msx_operation')

    RETURN(@retval) -- 0 means success

    END

    go

    /**************************************************************/

    /* SP_HELP_JOBSCHEDULE */

    /**************************************************************/

    PRINT ''

    PRINT 'Creating procedure sp_help_jobschedule...'

    go

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = N'sp_help_jobschedule')

    AND (type = 'P')))

    DROP PROCEDURE sp_help_jobschedule

    go

    CREATE PROCEDURE sp_help_jobschedule

    @job_id UNIQUEIDENTIFIER = NULL,

    @job_name sysname = NULL,

    @schedule_name sysname = NULL,

    @schedule_id INT = NULL,

    @include_description BIT = 0 -- 1 if a schedule description is required (NOTE: It's expensive to generate the description)

    AS

    BEGIN

    DECLARE @retval INT

    DECLARE @schedule_description NVARCHAR(255)

    DECLARE @name sysname

    DECLARE @freq_type INT

    DECLARE @freq_interval INT

    DECLARE @freq_subday_type INT

    DECLARE @freq_subday_interval INT

    DECLARE @freq_relative_interval INT

    DECLARE @freq_recurrence_factor INT

    DECLARE @active_start_date INT

    DECLARE @active_end_date INT

    DECLARE @active_start_time INT

    DECLARE @active_end_time INT

    DECLARE @schedule_id_as_char VARCHAR(10)

    SET NOCOUNT ON

    -- Remove any leading/trailing spaces from parameters

    SELECT @schedule_name = LTRIM(RTRIM(@schedule_name))

    -- Turn [nullable] empty string parameters into NULLs

    IF (@schedule_name = N'') SELECT @schedule_name = NULL

    -- The user must provide either:

    -- 1) job_id (or job_name) and (optionally) a schedule name

    -- or...

    -- 2) just schedule_id

    IF (@schedule_id IS NULL) AND

    (@job_id IS NULL) AND

    (@job_name IS NULL)

    BEGIN

    RAISERROR(14273, -1, -1)

    RETURN(1) -- Failure

    END

    IF (@schedule_id IS NOT NULL) AND ((@job_id IS NOT NULL) OR

    (@job_name IS NOT NULL) OR

    (@schedule_name IS NOT NULL))

    BEGIN

    RAISERROR(14273, -1, -1)

    RETURN(1) -- Failure

    END

    -- Check that the schedule (by ID) exists

    IF (@schedule_id IS NOT NULL)

    BEGIN

    SELECT @job_id = job_id

    FROM msdb.dbo.sysjobschedules

    WHERE (schedule_id = @schedule_id)

    IF (@job_id IS NULL)

    BEGIN

    SELECT @schedule_id_as_char = CONVERT(VARCHAR, @schedule_id)

    RAISERROR(14262, -1, -1, '@schedule_id', @schedule_id_as_char)

    RETURN(1) -- Failure

    END

    END

    -- Check that we can uniquely identify the job

    IF (@job_id IS NOT NULL) OR (@job_name IS NOT NULL)

    BEGIN

    EXECUTE @retval = sp_verify_job_identifiers '@job_name',

    '@job_id',

    @job_name OUTPUT,

    @job_id OUTPUT,

    'NO_TEST'

    IF (@retval <> 0)

    RETURN(1) -- Failure

    END

    -- Check that the schedule (by name) exists

    IF (@schedule_name IS NOT NULL)

    BEGIN

    IF (NOT EXISTS (SELECT *

    FROM msdb.dbo.sysjobschedules

    WHERE (job_id = @job_id)

    AND (name = @schedule_name)))

    BEGIN

    RAISERROR(14262, -1, -1, '@schedule_name', @schedule_name)

    RETURN(1) -- Failure

    END

    END

    -- Get the schedule(s) into a temporary table

    SELECT schedule_id,

    'schedule_name' = name,

    enabled,

    freq_type,

    freq_interval,

    freq_subday_type,

    freq_subday_interval,

    freq_relative_interval,

    freq_recurrence_factor,

    active_start_date,

    active_end_date,

    active_start_time,

    active_end_time,

    date_created,

    'schedule_description' = FORMATMESSAGE(14549),

    next_run_date,

    next_run_time

    INTO #temp_jobschedule

    FROM msdb.dbo.sysjobschedules

    WHERE ((@job_id IS NULL) OR (job_id = @job_id))

    AND ((@schedule_name IS NULL) OR (name = @schedule_name))

    AND ((@schedule_id IS NULL) OR (schedule_id = @schedule_id))

    IF (@include_description = 1)

    BEGIN

    -- For each schedule, generate the textual schedule description and update the temporary

    -- table with it

    IF (EXISTS (SELECT *

    FROM #temp_jobschedule))

    BEGIN

    WHILE (EXISTS (SELECT *

    FROM #temp_jobschedule

    WHERE schedule_description = FORMATMESSAGE(14549)))

    BEGIN

    SET ROWCOUNT 1

    SELECT @name = schedule_name,

    @freq_type = freq_type,

    @freq_interval = freq_interval,

    @freq_subday_type = freq_subday_type,

    @freq_subday_interval = freq_subday_interval,

    @freq_relative_interval = freq_relative_interval,

    @freq_recurrence_factor = freq_recurrence_factor,

    @active_start_date = active_start_date,

    @active_end_date = active_end_date,

    @active_start_time = active_start_time,

    @active_end_time = active_end_time

    FROM #temp_jobschedule

    WHERE (schedule_description = FORMATMESSAGE(14549))

    SET ROWCOUNT 0

    EXECUTE sp_get_schedule_description

    @freq_type,

    @freq_interval,

    @freq_subday_type,

    @freq_subday_interval,

    @freq_relative_interval,

    @freq_recurrence_factor,

    @active_start_date,

    @active_end_date,

    @active_start_time,

    @active_end_time,

    @schedule_description OUTPUT

    UPDATE #temp_jobschedule

    SET schedule_description = ISNULL(LTRIM(RTRIM(@schedule_description)), FORMATMESSAGE(14205))

    WHERE (schedule_name = @name)

    END -- While

    END

    END

    -- Return the result set

    SELECT *

    FROM #temp_jobschedule

    ORDER BY schedule_id

    RETURN(@@error) -- 0 means success

    END

    go

    DUMP TRANSACTION msdb WITH NO_LOG

    go

    CHECKPOINT

    go

    /**************************************************************/

    /* SP_VERIFY_JOB */

    /**************************************************************/

    PRINT ''

    PRINT 'Creating procedure sp_verify_job...'

    go

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = N'sp_verify_job')

    AND (type = 'P')))

    DROP PROCEDURE sp_verify_job

    go

    CREATE PROCEDURE sp_verify_job

    @job_id UNIQUEIDENTIFIER,

    @name sysname,

    @enabled TINYINT,

    @start_step_id INT,

    @category_name sysname,

    @owner_sid VARBINARY(85) OUTPUT, -- Output since we may modify it

    @notify_level_eventlog INT,

    @notify_level_email INT OUTPUT, -- Output since we may reset it to 0

    @notify_level_netsend INT OUTPUT, -- Output since we may reset it to 0

    @notify_level_page INT OUTPUT, -- Output since we may reset it to 0

    @notify_email_operator_name sysname,

    @notify_netsend_operator_name sysname,

    @notify_page_operator_name sysname,

    @delete_level INT,

    @category_id INT OUTPUT, -- The ID corresponding to the name

    @notify_email_operator_id INT OUTPUT, -- The ID corresponding to the name

    @notify_netsend_operator_id INT OUTPUT, -- The ID corresponding to the name

    @notify_page_operator_id INT OUTPUT, -- The ID corresponding to the name

    @originating_server NVARCHAR(30) OUTPUT -- Output since we may modify it

    AS

    BEGIN

    DECLARE @job_type INT

    DECLARE @retval INT

    DECLARE @current_date INT

    DECLARE @local_machine_name NVARCHAR(30)

    DECLARE @res_valid_range NVARCHAR(200)

    SET NOCOUNT ON

    -- Remove any leading/trailing spaces from parameters

    SELECT @name = LTRIM(RTRIM(@name))

    SELECT @category_name = LTRIM(RTRIM(@category_name))

    SELECT @originating_server = LTRIM(RTRIM(@originating_server))

    -- Make sure that input/output strings - if NULL - are initialized to NOT null

    EXECUTE @retval = master.dbo.xp_getnetname @local_machine_name OUTPUT

    IF (@retval <> 0)

    RETURN(1) -- Failure

    SELECT @originating_server = ISNULL(@originating_server, ISNULL(@local_machine_name, UPPER(CONVERT(NVARCHAR(30), SERVERPROPERTY('ServerName')))))

    -- Replace the local server name with local server name

    IF (UPPER(@originating_server) = UPPER(@local_machine_name))

    SELECT @originating_server = UPPER(CONVERT(NVARCHAR(30), SERVERPROPERTY('ServerName')))

    -- Check originating server (only the SQLServerAgent can add jobs that originate from a remote server)

    IF (UPPER(@originating_server) <> UPPER(CONVERT(NVARCHAR(30), SERVERPROPERTY('ServerName')))) AND

    (PROGRAM_NAME() NOT LIKE N'SQLAgent%')

    BEGIN

    RAISERROR(14275, -1, -1, @local_machine_name)

    RETURN(1) -- Failure

    END

    -- Make sure that the local server is always referred to as local server name (ie. lower-case)

    IF (UPPER(@originating_server) = UPPER(CONVERT(NVARCHAR(30), SERVERPROPERTY('ServerName'))))

    SELECT @originating_server = LOWER(@originating_server)

    -- NOTE: We allow jobs with the same name (since job_id is always unique) but only if

    -- they originate from different servers. Thus jobs can flow from an MSX to a TSX

    -- without having to worry about naming conflicts.

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysjobs

    WHERE (name = @name)

    AND (originating_server = @originating_server)

    AND (job_id <> ISNULL(@job_id, 0x911)))) -- When adding a new job @job_id is NULL

    BEGIN

    RAISERROR(14261, -1, -1, '@name', @name)

    RETURN(1) -- Failure

    END

    -- Check enabled state

    IF (@enabled <> 0) AND (@enabled <> 1)

    BEGIN

    RAISERROR(14266, -1, -1, '@enabled', '0, 1')

    RETURN(1) -- Failure

    END

    -- Check start step

    IF (@job_id IS NULL)

    BEGIN

    -- New job

    -- NOTE: For [new] MSX jobs we allow the start step to be other than 1 since

    -- the start step was validated when the job was created at the MSX

    IF (@start_step_id <> 1) AND (UPPER(@originating_server) = UPPER(CONVERT(NVARCHAR(30), SERVERPROPERTY('ServerName'))))

    BEGIN

    RAISERROR(14266, -1, -1, '@start_step_id', '1')

    RETURN(1) -- Failure

    END

    END

    ELSE

    BEGIN

    -- Existing job

    DECLARE @max_step_id INT

    DECLARE @valid_range VARCHAR(50)

    -- Get current maximum step id

    SELECT @max_step_id = ISNULL(MAX(step_id), 0)

    FROM msdb.dbo.sysjobsteps

    WHERE (job_id = @job_id)

    IF (@start_step_id @max_step_id + 1)

    BEGIN

    SELECT @valid_range = '1..' + CONVERT(VARCHAR, @max_step_id + 1)

    RAISERROR(14266, -1, -1, '@start_step_id', @valid_range)

    RETURN(1) -- Failure

    END

    END

    -- Check category

    SELECT @job_type = NULL

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysjobservers

    WHERE (job_id = @job_id)

    AND (server_id = 0)))

    SELECT @job_type = 1 -- LOCAL

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysjobservers

    WHERE (job_id = @job_id)

    AND (server_id <> 0)))

    SELECT @job_type = 2 -- MULTI-SERVER

    -- A local job cannot be added to a multi-server job_category

    IF (@job_type = 1) AND (EXISTS (SELECT *

    FROM msdb.dbo.syscategories

    WHERE (category_class = 1) -- Job

    AND (category_type = 2) -- Multi-Server

    AND (name = @category_name)))

    BEGIN

    RAISERROR(14285, -1, -1)

    RETURN(1) -- Failure

    END

    -- A multi-server job cannot be added to a local job_category

    IF (@job_type = 2) AND (EXISTS (SELECT *

    FROM msdb.dbo.syscategories

    WHERE (category_class = 1) -- Job

    AND (category_type = 1) -- Local

    AND (name = @category_name)))

    BEGIN

    RAISERROR(14286, -1, -1)

    RETURN(1) -- Failure

    END

    -- Get the category_id, handling any special-cases as appropriate

    SELECT @category_id = NULL

    IF (@category_name = N'[DEFAULT]') -- User wants to revert to the default job category

    BEGIN

    SELECT @category_id = CASE ISNULL(@job_type, 1)

    WHEN 1 THEN 0 -- [Uncategorized (Local)]

    WHEN 2 THEN 2 -- [Uncategorized (Multi-Server)]

    END

    END

    ELSE

    IF (@category_name IS NULL) -- The sp_add_job default

    BEGIN

    SELECT @category_id = 0

    END

    ELSE

    BEGIN

    SELECT @category_id = category_id

    FROM msdb.dbo.syscategories

    WHERE (category_class = 1) -- Job

    AND (name = @category_name)

    END

    IF (@category_id IS NULL)

    BEGIN

    RAISERROR(14234, -1, -1, '@category_name', 'sp_help_category')

    RETURN(1) -- Failure

    END

    -- Only SQLServerAgent may add jobs to the 'Jobs From MSX' category

    IF (@category_id = 1) AND

    (PROGRAM_NAME() NOT LIKE N'SQLAgent%')

    BEGIN

    RAISERROR(14267, -1, -1, @category_name)

    RETURN(1) -- Failure

    END

    -- Check owner

    -- If a non-sa is [illegally] trying to create a job for another user then default the owner

    -- to be the calling user.

    IF ((ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) = 0) AND (@owner_sid <> SUSER_SID()))

    SELECT @owner_sid = SUSER_SID()

    -- Now just check that the login id is valid (ie. it exists and isn't an NT group)

    IF ((@owner_sid <> 0x010100000000000512000000) AND

    (@owner_sid <> 0x010100000000000514000000))

    BEGIN

    IF (@owner_sid IS NULL) OR (EXISTS (SELECT *

    FROM master.dbo.syslogins

    WHERE (sid = @owner_sid)

    AND (isntgroup <> 0)))

    BEGIN

    -- NOTE: In the following message we quote @owner_login_name instead of @owner_sid

    -- since this is the parameter the user passed to the calling SP (ie. either

    -- sp_add_job or sp_update_job)

    SELECT @res_valid_range = FORMATMESSAGE(14203)

    RAISERROR(14234, -1, -1, '@owner_login_name', @res_valid_range)

    RETURN(1) -- Failure

    END

    END

    -- Check notification levels (must be 0, 1, 2 or 3)

    IF (@notify_level_eventlog & 0x3 <> @notify_level_eventlog)

    BEGIN

    RAISERROR(14266, -1, -1, '@notify_level_eventlog', '0, 1, 2, 3')

    RETURN(1) -- Failure

    END

    IF (@notify_level_email & 0x3 <> @notify_level_email)

    BEGIN

    RAISERROR(14266, -1, -1, '@notify_level_email', '0, 1, 2, 3')

    RETURN(1) -- Failure

    END

    IF (@notify_level_netsend & 0x3 <> @notify_level_netsend)

    BEGIN

    RAISERROR(14266, -1, -1, '@notify_level_netsend', '0, 1, 2, 3')

    RETURN(1) -- Failure

    END

    IF (@notify_level_page & 0x3 <> @notify_level_page)

    BEGIN

    RAISERROR(14266, -1, -1, '@notify_level_page', '0, 1, 2, 3')

    RETURN(1) -- Failure

    END

    -- If we're at a TSX, only SQLServerAgent may add jobs that notify 'MSXOperator'

    IF (NOT EXISTS (SELECT *

    FROM msdb.dbo.systargetservers)) AND

    ((@notify_email_operator_name = N'MSXOperator') OR

    (@notify_page_operator_name = N'MSXOperator') OR

    (@notify_netsend_operator_name = N'MSXOperator')) AND

    (PROGRAM_NAME() NOT LIKE N'SQLAgent%')

    BEGIN

    RAISERROR(14251, -1, -1, 'MSXOperator')

    RETURN(1) -- Failure

    END

    -- Check operator to notify (via email)

    IF (@notify_email_operator_name IS NOT NULL)

    BEGIN

    SELECT @notify_email_operator_id = id

    FROM msdb.dbo.sysoperators

    WHERE (name = @notify_email_operator_name)

    IF (@notify_email_operator_id IS NULL)

    BEGIN

    RAISERROR(14234, -1, -1, '@notify_email_operator_name', 'sp_help_operator')

    RETURN(1) -- Failure

    END

    -- If a valid operator is specified the level must be non-zero

    IF (@notify_level_email = 0)

    BEGIN

    RAISERROR(14266, -1, -1, '@notify_level_email', '1, 2, 3')

    RETURN(1) -- Failure

    END

    END

    ELSE

    BEGIN

    SELECT @notify_email_operator_id = 0

    SELECT @notify_level_email = 0

    END

    -- Check operator to notify (via netsend)

    IF (@notify_netsend_operator_name IS NOT NULL)

    BEGIN

    SELECT @notify_netsend_operator_id = id

    FROM msdb.dbo.sysoperators

    WHERE (name = @notify_netsend_operator_name)

    IF (@notify_netsend_operator_id IS NULL)

    BEGIN

    RAISERROR(14234, -1, -1, '@notify_netsend_operator_name', 'sp_help_operator')

    RETURN(1) -- Failure

    END

    -- If a valid operator is specified the level must be non-zero

    IF (@notify_level_netsend = 0)

    BEGIN

    RAISERROR(14266, -1, -1, '@notify_level_netsend', '1, 2, 3')

    RETURN(1) -- Failure

    END

    END

    ELSE

    BEGIN

    SELECT @notify_netsend_operator_id = 0

    SELECT @notify_level_netsend = 0

    END

    -- Check operator to notify (via page)

    IF (@notify_page_operator_name IS NOT NULL)

    BEGIN

    SELECT @notify_page_operator_id = id

    FROM msdb.dbo.sysoperators

    WHERE (name = @notify_page_operator_name)

    IF (@notify_page_operator_id IS NULL)

    BEGIN

    RAISERROR(14234, -1, -1, '@notify_page_operator_name', 'sp_help_operator')

    RETURN(1) -- Failure

    END

    -- If a valid operator is specified the level must be non-zero

    IF (@notify_level_page = 0)

    BEGIN

    RAISERROR(14266, -1, -1, '@notify_level_page', '1, 2, 3')

    RETURN(1) -- Failure

    END

    END

    ELSE

    BEGIN

    SELECT @notify_page_operator_id = 0

    SELECT @notify_level_page = 0

    END

    -- Check delete level (must be 0, 1, 2 or 3)

    IF (@delete_level & 0x3 <> @delete_level)

    BEGIN

    RAISERROR(14266, -1, -1, '@delete_level', '0, 1, 2, 3')

    RETURN(1) -- Failure

    END

    RETURN(0) -- Success

    END

    go

    /**************************************************************/

    /* SP_ADD_JOB */

    /**************************************************************/

    PRINT ''

    PRINT 'Creating procedure sp_add_job...'

    go

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = N'sp_add_job')

    AND (type = 'P')))

    DROP PROCEDURE sp_add_job

    go

    CREATE PROCEDURE sp_add_job

    @job_name sysname,

    @enabled TINYINT = 1, -- 0 = Disabled, 1 = Enabled

    @description NVARCHAR(512) = NULL,

    @start_step_id INT = 1,

    @category_name sysname = NULL,

    @category_id INT = NULL, -- A language-independent way to specify which category to use

    @owner_login_name sysname = NULL, -- The procedure assigns a default

    @notify_level_eventlog INT = 2, -- 0 = Never, 1 = On Success, 2 = On Failure, 3 = Always

    @notify_level_email INT = 0, -- 0 = Never, 1 = On Success, 2 = On Failure, 3 = Always

    @notify_level_netsend INT = 0, -- 0 = Never, 1 = On Success, 2 = On Failure, 3 = Always

    @notify_level_page INT = 0, -- 0 = Never, 1 = On Success, 2 = On Failure, 3 = Always

    @notify_email_operator_name sysname = NULL,

    @notify_netsend_operator_name sysname = NULL,

    @notify_page_operator_name sysname = NULL,

    @delete_level INT = 0, -- 0 = Never, 1 = On Success, 2 = On Failure, 3 = Always

    @job_id UNIQUEIDENTIFIER = NULL OUTPUT,

    @originating_server NVARCHAR(30) = NULL

    AS

    BEGIN

    DECLARE @retval INT

    DECLARE @notify_email_operator_id INT

    DECLARE @notify_netsend_operator_id INT

    DECLARE @notify_page_operator_id INT

    DECLARE @owner_sid VARBINARY(85)

    SET NOCOUNT ON

    IF (@originating_server IS NULL) OR (UPPER(@originating_server) = '(LOCAL)')

    SELECT @originating_server= UPPER(CONVERT(NVARCHAR(30), SERVERPROPERTY('ServerName')))

    -- Remove any leading/trailing spaces from parameters (except @owner_login_name)

    SELECT @originating_server = LTRIM(RTRIM(@originating_server))

    SELECT @job_name = LTRIM(RTRIM(@job_name))

    SELECT @description = LTRIM(RTRIM(@description))

    SELECT @category_name = LTRIM(RTRIM(@category_name))

    SELECT @notify_email_operator_name = LTRIM(RTRIM(@notify_email_operator_name))

    SELECT @notify_netsend_operator_name = LTRIM(RTRIM(@notify_netsend_operator_name))

    SELECT @notify_page_operator_name = LTRIM(RTRIM(@notify_page_operator_name))

    -- Turn [nullable] empty string parameters into NULLs

    IF (@description = N'') SELECT @description = NULL

    IF (@category_name = N'') SELECT @category_name = NULL

    IF (@notify_email_operator_name = N'') SELECT @notify_email_operator_name = NULL

    IF (@notify_netsend_operator_name = N'') SELECT @notify_netsend_operator_name = NULL

    IF (@notify_page_operator_name = N'') SELECT @notify_page_operator_name = NULL

    -- Default the owner (if not supplied or if a non-sa is [illegally] trying to create a job for another user)

    IF (@owner_login_name IS NULL) OR ((ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) = 0) AND (@owner_login_name <> SUSER_SNAME()))

    SELECT @owner_sid = SUSER_SID()

    ELSE

    SELECT @owner_sid = SUSER_SID(@owner_login_name) -- If @owner_login_name is invalid then SUSER_SID() will return NULL

    -- Default the description (if not supplied)

    IF (@description IS NULL)

    SELECT @description = FORMATMESSAGE(14571)

    -- If a category ID is provided this overrides any supplied category name

    IF (@category_id IS NOT NULL)

    BEGIN

    SELECT @category_name = name

    FROM msdb.dbo.syscategories

    WHERE (category_id = @category_id)

    SELECT @category_name = ISNULL(@category_name, FORMATMESSAGE(14205))

    END

    -- Check parameters

    EXECUTE @retval = sp_verify_job NULL, -- The job id is null since this is a new job

    @job_name,

    @enabled,

    @start_step_id,

    @category_name,

    @owner_sid OUTPUT,

    @notify_level_eventlog,

    @notify_level_email OUTPUT,

    @notify_level_netsend OUTPUT,

    @notify_level_page OUTPUT,

    @notify_email_operator_name,

    @notify_netsend_operator_name,

    @notify_page_operator_name,

    @delete_level,

    @category_id OUTPUT,

    @notify_email_operator_id OUTPUT,

    @notify_netsend_operator_id OUTPUT,

    @notify_page_operator_id OUTPUT,

    @originating_server OUTPUT

    IF (@retval <> 0)

    RETURN(1) -- Failure

    IF (@job_id IS NULL)

    BEGIN

    -- Assign the GUID

    SELECT @job_id = NEWID()

    END

    ELSE

    BEGIN

    -- A job ID has been provided, so check that the caller is SQLServerAgent (inserting an MSX job)

    IF (PROGRAM_NAME() NOT LIKE N'SQLAgent%')

    BEGIN

    RAISERROR(14284, -1, -1)

    RETURN(1) -- Failure

    END

    END

    INSERT INTO msdb.dbo.sysjobs

    (job_id,

    originating_server,

    name,

    enabled,

    description,

    start_step_id,

    category_id,

    owner_sid,

    notify_level_eventlog,

    notify_level_email,

    notify_level_netsend,

    notify_level_page,

    notify_email_operator_id,

    notify_netsend_operator_id,

    notify_page_operator_id,

    delete_level,

    date_created,

    date_modified,

    version_number)

    VALUES (@job_id,

    @originating_server,

    @job_name,

    @enabled,

    @description,

    @start_step_id,

    @category_id,

    @owner_sid,

    @notify_level_eventlog,

    @notify_level_email,

    @notify_level_netsend,

    @notify_level_page,

    @notify_email_operator_id,

    @notify_netsend_operator_id,

    @notify_page_operator_id,

    @delete_level,

    GETDATE(),

    GETDATE(),

    1) -- Version number 1

    SELECT @retval = @@error

    -- If misc. replication job, then update global replication status table

    IF (@category_id IN (11, 12, 16, 17, 18))

    BEGIN

    -- Nothing can be done if this fails, so don't worry about the return code

    EXECUTE master.dbo.sp_MSupdate_replication_status

    @publisher = '',

    @publisher_db = '',

    @publication = '',

    @publication_type = -1,

    @agent_type = 5,

    @agent_name = @job_name,

    @status = NULL -- Never run

    END

    -- NOTE: We don't notify SQLServerAgent to update it's cache (we'll do this in sp_add_jobserver)

    RETURN(@retval) -- 0 means success

    END

    go

    /**************************************************************/

    /* SP_UPDATE_JOB */

    /**************************************************************/

    PRINT ''

    PRINT 'Creating procedure sp_update_job...'

    go

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = N'sp_update_job')

    AND (type = 'P')))

    DROP PROCEDURE sp_update_job

    go

    CREATE PROCEDURE sp_update_job

    @job_id UNIQUEIDENTIFIER = NULL, -- Must provide this or current_name

    @job_name sysname = NULL, -- Must provide this or job_id

    @new_name sysname = NULL,

    @enabled TINYINT = NULL,

    @description NVARCHAR(512) = NULL,

    @start_step_id INT = NULL,

    @category_name sysname = NULL,

    @owner_login_name sysname = NULL,

    @notify_level_eventlog INT = NULL,

    @notify_level_email INT = NULL,

    @notify_level_netsend INT = NULL,

    @notify_level_page INT = NULL,

    @notify_email_operator_name sysname = NULL,

    @notify_netsend_operator_name sysname = NULL,

    @notify_page_operator_name sysname = NULL,

    @delete_level INT = NULL,

    @automatic_post BIT = 1 -- Flag for SEM use only

    AS

    BEGIN

    DECLARE @retval INT

    DECLARE @category_id INT

    DECLARE @notify_email_operator_id INT

    DECLARE @notify_netsend_operator_id INT

    DECLARE @notify_page_operator_id INT

    DECLARE @owner_sid VARBINARY(85)

    DECLARE @alert_id INT

    DECLARE @cached_attribute_modified INT

    DECLARE @is_sysadmin INT

    DECLARE @current_owner sysname

    DECLARE @x_new_name sysname

    DECLARE @x_enabled TINYINT

    DECLARE @x_description NVARCHAR(512)

    DECLARE @x_start_step_id INT

    DECLARE @x_category_name sysname

    DECLARE @x_category_id INT

    DECLARE @x_owner_sid VARBINARY(85)

    DECLARE @x_notify_level_eventlog INT

    DECLARE @x_notify_level_email INT

    DECLARE @x_notify_level_netsend INT

    DECLARE @x_notify_level_page INT

    DECLARE @x_notify_email_operator_name sysname

    DECLARE @x_notify_netsnd_operator_name sysname

    DECLARE @x_notify_page_operator_name sysname

    DECLARE @x_delete_level INT

    DECLARE @x_originating_server NVARCHAR(30) -- Not updatable

    -- Remove any leading/trailing spaces from parameters (except @owner_login_name)

    SELECT @job_name = LTRIM(RTRIM(@job_name))

    SELECT @new_name = LTRIM(RTRIM(@new_name))

    SELECT @description = LTRIM(RTRIM(@description))

    SELECT @category_name = LTRIM(RTRIM(@category_name))

    SELECT @notify_email_operator_name = LTRIM(RTRIM(@notify_email_operator_name))

    SELECT @notify_netsend_operator_name = LTRIM(RTRIM(@notify_netsend_operator_name))

    SELECT @notify_page_operator_name = LTRIM(RTRIM(@notify_page_operator_name))

    SET NOCOUNT ON

    EXECUTE @retval = sp_verify_job_identifiers '@job_name',

    '@job_id',

    @job_name OUTPUT,

    @job_id OUTPUT

    IF (@retval <> 0)

    RETURN(1) -- Failure

    -- Are we modifying an attribute which SQLServerAgent caches?

    IF ((@new_name IS NOT NULL) OR

    (@enabled IS NOT NULL) OR

    (@start_step_id IS NOT NULL) OR

    (@owner_login_name IS NOT NULL) OR

    (@notify_level_eventlog IS NOT NULL) OR

    (@notify_level_email IS NOT NULL) OR

    (@notify_level_netsend IS NOT NULL) OR

    (@notify_level_page IS NOT NULL) OR

    (@notify_email_operator_name IS NOT NULL) OR

    (@notify_netsend_operator_name IS NOT NULL) OR

    (@notify_page_operator_name IS NOT NULL) OR

    (@delete_level IS NOT NULL))

    SELECT @cached_attribute_modified = 1

    ELSE

    SELECT @cached_attribute_modified = 0

    -- Set the x_ (existing) variables

    SELECT @x_new_name = sjv.name,

    @x_enabled = sjv.enabled,

    @x_description = sjv.description,

    @x_start_step_id = sjv.start_step_id,

    @x_category_name = sc.name, -- From syscategories

    @x_category_id = sc.category_id, -- From syscategories

    @x_owner_sid = sjv.owner_sid,

    @x_notify_level_eventlog = sjv.notify_level_eventlog,

    @x_notify_level_email = sjv.notify_level_email,

    @x_notify_level_netsend = sjv.notify_level_netsend,

    @x_notify_level_page = sjv.notify_level_page,

    @x_notify_email_operator_name = so1.name, -- From sysoperators

    @x_notify_netsnd_operator_name = so2.name, -- From sysoperators

    @x_notify_page_operator_name = so3.name, -- From sysoperators

    @x_delete_level = sjv.delete_level,

    @x_originating_server = sjv.originating_server

    FROM msdb.dbo.sysjobs_view sjv

    LEFT OUTER JOIN msdb.dbo.sysoperators so1 ON (sjv.notify_email_operator_id = so1.id)

    LEFT OUTER JOIN msdb.dbo.sysoperators so2 ON (sjv.notify_netsend_operator_id = so2.id)

    LEFT OUTER JOIN msdb.dbo.sysoperators so3 ON (sjv.notify_page_operator_id = so3.id),

    msdb.dbo.syscategories sc

    WHERE (sjv.job_id = @job_id)

    AND (sjv.category_id = sc.category_id)

    -- Check authority (only SQLServerAgent can modify a non-local job)

    IF (UPPER(@x_originating_server) <> UPPER(CONVERT(NVARCHAR(30), SERVERPROPERTY('ServerName')))) AND

    (PROGRAM_NAME() NOT LIKE N'SQLAgent%')

    BEGIN

    RAISERROR(14274, -1, -1)

    RETURN(1) -- Failure

    END

    IF (@new_name = N'') SELECT @new_name = NULL

    -- Fill out the values for all non-supplied parameters from the existing values

    IF (@new_name IS NULL) SELECT @new_name = @x_new_name

    IF (@enabled IS NULL) SELECT @enabled = @x_enabled

    IF (@description IS NULL) SELECT @description = @x_description

    IF (@start_step_id IS NULL) SELECT @start_step_id = @x_start_step_id

    IF (@category_name IS NULL) SELECT @category_name = @x_category_name

    IF (@owner_sid IS NULL) SELECT @owner_sid = @x_owner_sid

    IF (@notify_level_eventlog IS NULL) SELECT @notify_level_eventlog = @x_notify_level_eventlog

    IF (@notify_level_email IS NULL) SELECT @notify_level_email = @x_notify_level_email

    IF (@notify_level_netsend IS NULL) SELECT @notify_level_netsend = @x_notify_level_netsend

    IF (@notify_level_page IS NULL) SELECT @notify_level_page = @x_notify_level_page

    IF (@notify_email_operator_name IS NULL) SELECT @notify_email_operator_name = @x_notify_email_operator_name

    IF (@notify_netsend_operator_name IS NULL) SELECT @notify_netsend_operator_name = @x_notify_netsnd_operator_name

    IF (@notify_page_operator_name IS NULL) SELECT @notify_page_operator_name = @x_notify_page_operator_name

    IF (@delete_level IS NULL) SELECT @delete_level = @x_delete_level

    -- If the SA is attempting to assign ownership of the job to someone else, then convert

    -- the login name to an ID

    IF ((ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) = 1) AND (@owner_login_name IS NOT NULL))

    SELECT @owner_sid = SUSER_SID(@owner_login_name) -- If @owner_login_name is invalid then SUSER_SID() will return NULL

    -- Only the SA can re-assign jobs

    IF ((ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) <> 1) AND (@owner_login_name IS NOT NULL))

    RAISERROR(14242, -1, -1)

    -- Ownership of a multi-server job cannot be assigned to a non-sysadmin

    IF (@owner_login_name IS NOT NULL) AND

    (EXISTS (SELECT *

    FROM msdb.dbo.sysjobs sj,

    msdb.dbo.sysjobservers sjs

    WHERE (sj.job_id = sjs.job_id)

    AND (sj.job_id = @job_id)

    AND (sjs.server_id <> 0)))

    BEGIN

    SELECT @is_sysadmin = 0

    EXECUTE msdb.dbo.sp_sqlagent_has_server_access @login_name = @owner_login_name, @is_sysadmin_member = @is_sysadmin OUTPUT

    IF (@is_sysadmin = 0)

    BEGIN

    SELECT @current_owner = SUSER_SNAME(@x_owner_sid)

    RAISERROR(14543, -1, -1, @current_owner, N'sysadmin')

    RETURN(1) -- Failure

    END

    END

    -- Turn [nullable] empty string parameters into NULLs

    IF (@description = N'') SELECT @description = NULL

    IF (@category_name = N'') SELECT @category_name = NULL

    IF (@notify_email_operator_name = N'') SELECT @notify_email_operator_name = NULL

    IF (@notify_netsend_operator_name = N'') SELECT @notify_netsend_operator_name = NULL

    IF (@notify_page_operator_name = N'') SELECT @notify_page_operator_name = NULL

    -- Check new values

    EXECUTE @retval = sp_verify_job @job_id,

    @new_name,

    @enabled,

    @start_step_id,

    @category_name,

    @owner_sid OUTPUT,

    @notify_level_eventlog,

    @notify_level_email OUTPUT,

    @notify_level_netsend OUTPUT,

    @notify_level_page OUTPUT,

    @notify_email_operator_name,

    @notify_netsend_operator_name,

    @notify_page_operator_name,

    @delete_level,

    @category_id OUTPUT,

    @notify_email_operator_id OUTPUT,

    @notify_netsend_operator_id OUTPUT,

    @notify_page_operator_id OUTPUT,

    @x_originating_server OUTPUT -- We ignore the return value

    IF (@retval <> 0)

    RETURN(1) -- Failure

    BEGIN TRANSACTION

    -- If the job is being re-assigned, modify sysjobsteps.database_user_name as necessary

    IF (@owner_login_name IS NOT NULL)

    BEGIN

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysjobsteps

    WHERE (job_id = @job_id)

    AND (subsystem = N'TSQL')))

    BEGIN

    IF (EXISTS (SELECT *

    FROM master.dbo.syslogins

    WHERE (sid = @owner_sid)

    AND (sysadmin <> 1)))

    BEGIN

    -- The job is being re-assigned to an non-SA

    UPDATE msdb.dbo.sysjobsteps

    SET database_user_name = NULL

    WHERE (job_id = @job_id)

    AND (subsystem = N'TSQL')

    END

    END

    END

    UPDATE msdb.dbo.sysjobs

    SET name = @new_name,

    enabled = @enabled,

    description = @description,

    start_step_id = @start_step_id,

    category_id = @category_id, -- Returned from sp_verify_job

    owner_sid = @owner_sid,

    notify_level_eventlog = @notify_level_eventlog,

    notify_level_email = @notify_level_email,

    notify_level_netsend = @notify_level_netsend,

    notify_level_page = @notify_level_page,

    notify_email_operator_id = @notify_email_operator_id, -- Returned from sp_verify_job

    notify_netsend_operator_id = @notify_netsend_operator_id, -- Returned from sp_verify_job

    notify_page_operator_id = @notify_page_operator_id, -- Returned from sp_verify_job

    delete_level = @delete_level,

    version_number = version_number + 1, -- Update the job's version

    date_modified = GETDATE() -- Update the job's last-modified information

    WHERE (job_id = @job_id)

    SELECT @retval = @@error

    COMMIT TRANSACTION

    -- If change to or from a misc. replication job, then update global replication status table

    IF ((@category_name != @x_category_name) AND

    (@x_category_id IN (11, 12, 16, 17, 18) OR @category_id IN (11, 12,16, 17, 18)))

    BEGIN

    -- Delete entry if change misc. replication job to other

    IF (@x_category_name IS NOT NULL)

    BEGIN

    -- Nothing can be done if this fails, so don't worry about the return code

    EXECUTE master.dbo.sp_MSupdate_replication_status

    @publisher = '',

    @publisher_db = '',

    @publication = '',

    @publication_type = -1,

    @agent_type = 5,

    @agent_name = @job_name,

    @status = -1 -- Delete

    END

    -- Add entry if updated to misc. replication job

    IF (@x_category_name IS NOT NULL)

    BEGIN

    -- Nothing can be done if this fails, so don't worry about the return code

    EXECUTE master.dbo.sp_MSupdate_replication_status

    @publisher = '',

    @publisher_db = '',

    @publication = '',

    @publication_type = -1,

    @agent_type = 5,

    @agent_name = @job_name,

    @status = NULL -- Never run

    END

    END

    -- Always re-post the job if it's an auto-delete job (or if we're updating an auto-delete job

    -- to be non-auto-delete)

    IF (((SELECT delete_level

    FROM msdb.dbo.sysjobs

    WHERE (job_id = @job_id)) <> 0) OR

    ((@x_delete_level = 1) AND (@delete_level = 0)))

    EXECUTE msdb.dbo.sp_post_msx_operation 'INSERT', 'JOB', @job_id

    ELSE

    BEGIN

    -- Post the update to target servers

    IF (@automatic_post = 1)

    EXECUTE msdb.dbo.sp_post_msx_operation 'UPDATE', 'JOB', @job_id

    END

    -- Keep SQLServerAgent's cache in-sync

    -- NOTE: We only notify SQLServerAgent if we know the job has been cached and if

    -- attributes other than description or category have been changed (since

    -- SQLServerAgent doesn't cache these two)

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysjobservers

    WHERE (job_id = @job_id)

    AND (server_id = 0)

    AND (@cached_attribute_modified = 1)))

    EXECUTE msdb.dbo.sp_sqlagent_notify @op_type = N'J',

    @job_id = @job_id,

    @action_type = N'U'

    -- If the name was changed, make SQLServerAgent re-cache any alerts that reference the job

    -- since the alert cache contains the job name

    IF ((@job_name <> @new_name) AND (EXISTS (SELECT *

    FROM msdb.dbo.sysalerts

    WHERE (job_id = @job_id))))

    BEGIN

    DECLARE sysalerts_cache_update CURSOR LOCAL

    FOR

    SELECT id

    FROM msdb.dbo.sysalerts

    WHERE (job_id = @job_id)

    OPEN sysalerts_cache_update

    FETCH NEXT FROM sysalerts_cache_update INTO @alert_id

    WHILE (@@fetch_status = 0)

    BEGIN

    EXECUTE msdb.dbo.sp_sqlagent_notify @op_type = N'A',

    @alert_id = @alert_id,

    @action_type = N'U'

    FETCH NEXT FROM sysalerts_cache_update INTO @alert_id

    END

    DEALLOCATE sysalerts_cache_update

    END

    RETURN(@retval) -- 0 means success

    END

    go

    /**************************************************************/

    /* SP_DELETE_JOB */

    /**************************************************************/

    PRINT ''

    PRINT 'Creating procedure sp_delete_job...'

    go

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = N'sp_delete_job')

    AND (type = 'P')))

    DROP PROCEDURE sp_delete_job

    go

    CREATE PROCEDURE sp_delete_job

    @job_id UNIQUEIDENTIFIER = NULL, -- If provided should NOT also provide job_name

    @job_name sysname = NULL, -- If provided should NOT also provide job_id

    @originating_server NVARCHAR(30) = NULL, -- Reserved (used by SQLAgent)

    @delete_history BIT = 1 -- Reserved (used by SQLAgent)

    AS

    BEGIN

    DECLARE @current_msx_server NVARCHAR(30)

    DECLARE @bMSX_job BIT

    DECLARE @retval INT

    DECLARE @local_machine_name NVARCHAR(30)

    DECLARE @category_id INT

    SET NOCOUNT ON

    -- Remove any leading/trailing spaces from parameters

    SELECT @originating_server = LTRIM(RTRIM(@originating_server))

    -- Change server name to always reflect real servername or servername\instancename

    IF (UPPER(@originating_server) = '(LOCAL)')

    SELECT @originating_server = UPPER(CONVERT(NVARCHAR(30), SERVERPROPERTY('ServerName')))

    -- Turn [nullable] empty string parameters into NULLs

    IF (@originating_server = N'')

    SELECT @originating_server = NULL

    IF ((@job_id IS NOT NULL) OR (@job_name IS NOT NULL))

    BEGIN

    EXECUTE @retval = sp_verify_job_identifiers '@job_name',

    '@job_id',

    @job_name OUTPUT,

    @job_id OUTPUT

    IF (@retval <> 0)

    RETURN(1) -- Failure

    END

    -- We need either a job name or a server name, not both

    IF ((@job_name IS NULL) AND (@originating_server IS NULL)) OR

    ((@job_name IS NOT NULL) AND (@originating_server IS NOT NULL))

    BEGIN

    RAISERROR(14279, -1, -1)

    RETURN(1) -- Failure

    END

    -- Get category to see if it is a misc. replication agent. @category_id will be

    -- NULL if there is no @job_id.

    select @category_id = category_id from msdb.dbo.sysjobs where job_id = @job_id

    -- If job name was given, determine if the job is from an MSX

    IF (@job_id IS NOT NULL)

    BEGIN

    SELECT @bMSX_job = CASE UPPER(originating_server)

    WHEN UPPER(CONVERT(NVARCHAR(30), SERVERPROPERTY('ServerName'))) THEN 0

    ELSE 1

    END

    FROM msdb.dbo.sysjobs_view

    WHERE (job_id = @job_id)

    END

    -- If server name was given, warn user if different from current MSX

    IF (@originating_server IS NOT NULL)

    BEGIN

    EXECUTE @retval = master.dbo.xp_getnetname @local_machine_name OUTPUT

    IF (@retval <> 0)

    RETURN(1) -- Failure

    IF ((UPPER(@originating_server) = UPPER(CONVERT(NVARCHAR(30), SERVERPROPERTY('ServerName')))) OR (UPPER(@originating_server) = UPPER(@local_machine_name)))

    SELECT @originating_server = UPPER(CONVERT(NVARCHAR(30), SERVERPROPERTY('ServerName')))

    EXECUTE master.dbo.xp_instance_regread N'HKEY_LOCAL_MACHINE',

    N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',

    N'MSXServerName',

    @current_msx_server OUTPUT,

    N'no_output'

    -- If server name was given but it's not the current MSX, print a warning

    SELECT @current_msx_server = LTRIM(RTRIM(@current_msx_server))

    IF ((@current_msx_server IS NOT NULL) AND (@current_msx_server <> N'') AND (@originating_server <> @current_msx_server))

    RAISERROR(14224, 0, 1, @current_msx_server)

    END

    -- Check authority (only SQLServerAgent can delete a non-local job)

    IF (((@originating_server IS NOT NULL) AND (@originating_server <> UPPER(CONVERT(NVARCHAR(30), SERVERPROPERTY('ServerName'))))) OR (@bMSX_job = 1)) AND

    (PROGRAM_NAME() NOT LIKE N'SQLAgent%')

    BEGIN

    RAISERROR(14274, -1, -1)

    RETURN(1) -- Failure

    END

    CREATE TABLE #temp_jobs_to_delete (job_id UNIQUEIDENTIFIER NOT NULL, job_is_cached INT NOT NULL)

    -- Do the delete (for a specific job)

    IF (@job_id IS NOT NULL)

    BEGIN

    INSERT INTO #temp_jobs_to_delete

    SELECT job_id, (SELECT COUNT(*)

    FROM msdb.dbo.sysjobservers

    WHERE (job_id = @job_id)

    AND (server_id = 0))

    FROM msdb.dbo.sysjobs_view

    WHERE (job_id = @job_id)

    -- Check if we have any work to do

    IF (NOT EXISTS (SELECT *

    FROM #temp_jobs_to_delete))

    RETURN(0) -- Success

    -- Post the delete to any target servers (need to do this BEFORE deleting the job itself,

    -- but AFTER clearing all all pending download instructions). Note that if the job is

    -- NOT a multi-server job then sp_post_msx_operation will catch this and will do nothing.

    DELETE FROM msdb.dbo.sysdownloadlist

    WHERE (object_id = @job_id)

    EXECUTE msdb.dbo.sp_post_msx_operation 'DELETE', 'JOB', @job_id

    -- Must do this before deleting the job itself since sp_sqlagent_notify does a lookup on sysjobs_view

    EXECUTE msdb.dbo.sp_delete_job_references

    -- Delete all traces of the job

    BEGIN TRANSACTION

    DELETE FROM msdb.dbo.sysjobs

    WHERE job_id IN (SELECT job_id FROM #temp_jobs_to_delete)

    DELETE FROM msdb.dbo.sysjobservers

    WHERE job_id IN (SELECT job_id FROM #temp_jobs_to_delete)

    DELETE FROM msdb.dbo.sysjobsteps

    WHERE job_id IN (SELECT job_id FROM #temp_jobs_to_delete)

    DELETE FROM msdb.dbo.sysjobschedules

    WHERE job_id IN (SELECT job_id FROM #temp_jobs_to_delete)

    IF (@delete_history = 1)

    DELETE FROM msdb.dbo.sysjobhistory

    WHERE job_id IN (SELECT job_id FROM #temp_jobs_to_delete)

    COMMIT TRANSACTION

    END

    ELSE

    -- Do the delete (for all jobs originating from the specific server)

    IF (@originating_server IS NOT NULL)

    BEGIN

    EXECUTE msdb.dbo.sp_delete_all_msx_jobs @msx_server = @originating_server

    -- NOTE: In this case there is no need to propagate the delete via sp_post_msx_operation

    -- since this type of delete is only ever performed on a TSX.

    END

    DROP TABLE #temp_jobs_to_delete

    -- If misc. replication job, then update global replication status table.

    -- @category_id will have a value ONLY if @job_name or @job_id is provided.

    IF (@category_id IS NOT NULL AND @category_id IN (11, 12, 16, 17, 18))

    BEGIN

    -- Nothing can be done if this fails, so don't worry about the return code

    EXECUTE master.dbo.sp_MSupdate_replication_status

    @publisher = '',

    @publisher_db = '',

    @publication = '',

    @publication_type = -1,

    @agent_type = 5,

    @agent_name = @job_name,

    @status = -1 -- Delete

    END

    RETURN(0) -- 0 means success

    END

    go

    /**************************************************************/

    /* SP_GET_COMPOSITE_JOB_INFO */

    /**************************************************************/

    PRINT ''

    PRINT 'Creating procedure sp_get_composite_job_info...'

    go

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = N'sp_get_composite_job_info')

    AND (type = 'P')))

    DROP PROCEDURE sp_get_composite_job_info

    go

    CREATE PROCEDURE sp_get_composite_job_info

    @job_id UNIQUEIDENTIFIER = NULL,

    @job_type VARCHAR(12) = NULL, -- LOCAL or MULTI-SERVER

    @owner_login_name sysname = NULL,

    @subsystem NVARCHAR(40) = NULL,

    @category_id INT = NULL,

    @enabled TINYINT = NULL,

    @execution_status INT = NULL, -- 0 = Not idle or suspended, 1 = Executing, 2 = Waiting For Thread, 3 = Between Retries, 4 = Idle, 5 = Suspended, [6 = WaitingForStepToFinish], 7 = PerformingCompletionActions

    @date_comparator CHAR(1) = NULL, -- >, < or =

    @date_created DATETIME = NULL,

    @date_last_modified DATETIME = NULL,

    @description NVARCHAR(512) = NULL -- We do a LIKE on this so it can include wildcards

    AS

    BEGIN

    DECLARE @is_sysadmin INT

    DECLARE @job_owner sysname

    SET NOCOUNT ON

    -- By 'composite' we mean a combination of sysjobs and xp_sqlagent_enum_jobs data.

    -- This proc should only ever be called by sp_help_job, so we don't verify the

    -- parameters (sp_help_job has already done this).

    -- Step 1: Create intermediate work tables

    CREATE TABLE #job_execution_state (job_id UNIQUEIDENTIFIER NOT NULL,

    date_started INT NOT NULL,

    time_started INT NOT NULL,

    execution_job_status INT NOT NULL,

    execution_step_id INT NULL,

    execution_step_name sysname COLLATE database_default NULL,

    execution_retry_attempt INT NOT NULL,

    next_run_date INT NOT NULL,

    next_run_time INT NOT NULL,

    next_run_schedule_id INT NOT NULL)

    CREATE TABLE #filtered_jobs (job_id UNIQUEIDENTIFIER NOT NULL,

    date_created DATETIME NOT NULL,

    date_last_modified DATETIME NOT NULL,

    current_execution_status INT NULL,

    current_execution_step sysname COLLATE database_default NULL,

    current_retry_attempt INT NULL,

    last_run_date INT NOT NULL,

    last_run_time INT NOT NULL,

    last_run_outcome INT NOT NULL,

    next_run_date INT NULL,

    next_run_time INT NULL,

    next_run_schedule_id INT NULL,

    type INT NOT NULL)

    CREATE TABLE #xp_results (job_id UNIQUEIDENTIFIER NOT NULL,

    last_run_date INT NOT NULL,

    last_run_time INT NOT NULL,

    next_run_date INT NOT NULL,

    next_run_time INT NOT NULL,

    next_run_schedule_id INT NOT NULL,

    requested_to_run INT NOT NULL, -- BOOL

    request_source INT NOT NULL,

    request_source_id sysname COLLATE database_default NULL,

    running INT NOT NULL, -- BOOL

    current_step INT NOT NULL,

    current_retry_attempt INT NOT NULL,

    job_state INT NOT NULL)

    -- Step 2: Capture job execution information (for local jobs only since that's all SQLServerAgent caches)

    SELECT @is_sysadmin = ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0)

    SELECT @job_owner = SUSER_SNAME()

    IF ((@@microsoftversion / 0x01000000) >= 8) -- SQL Server 8.0 or greater

    INSERT INTO #xp_results

    EXECUTE master.dbo.xp_sqlagent_enum_jobs @is_sysadmin, @job_owner, @job_id

    ELSE

    INSERT INTO #xp_results

    EXECUTE master.dbo.xp_sqlagent_enum_jobs @is_sysadmin, @job_owner

    INSERT INTO #job_execution_state

    SELECT xpr.job_id,

    xpr.last_run_date,

    xpr.last_run_time,

    xpr.job_state,

    sjs.step_id,

    sjs.step_name,

    xpr.current_retry_attempt,

    xpr.next_run_date,

    xpr.next_run_time,

    xpr.next_run_schedule_id

    FROM #xp_results xpr

    LEFT OUTER JOIN msdb.dbo.sysjobsteps sjs ON ((xpr.job_id = sjs.job_id) AND (xpr.current_step = sjs.step_id)),

    msdb.dbo.sysjobs_view sjv

    WHERE (sjv.job_id = xpr.job_id)

    -- Step 3: Filter on everything but dates and job_type

    IF ((@subsystem IS NULL) AND

    (@owner_login_name IS NULL) AND

    (@enabled IS NULL) AND

    (@category_id IS NULL) AND

    (@execution_status IS NULL) AND

    (@description IS NULL) AND

    (@job_id IS NULL))

    BEGIN

    -- Optimize for the frequently used case...

    INSERT INTO #filtered_jobs

    SELECT sjv.job_id,

    sjv.date_created,

    sjv.date_modified,

    ISNULL(jes.execution_job_status, 4), -- Will be NULL if the job is non-local or is not in #job_execution_state (NOTE: 4 = STATE_IDLE)

    CASE ISNULL(jes.execution_step_id, 0)

    WHEN 0 THEN NULL -- Will be NULL if the job is non-local or is not in #job_execution_state

    ELSE CONVERT(NVARCHAR, jes.execution_step_id) + N' (' + jes.execution_step_name + N')'

    END,

    jes.execution_retry_attempt, -- Will be NULL if the job is non-local or is not in #job_execution_state

    0, -- last_run_date placeholder (we'll fix it up in step 3.3)

    0, -- last_run_time placeholder (we'll fix it up in step 3.3)

    5, -- last_run_outcome placeholder (we'll fix it up in step 3.3 - NOTE: We use 5 just in case there are no jobservers for the job)

    jes.next_run_date, -- Will be NULL if the job is non-local or is not in #job_execution_state

    jes.next_run_time, -- Will be NULL if the job is non-local or is not in #job_execution_state

    jes.next_run_schedule_id, -- Will be NULL if the job is non-local or is not in #job_execution_state

    0 -- type placeholder (we'll fix it up in step 3.4)

    FROM msdb.dbo.sysjobs_view sjv

    LEFT OUTER JOIN #job_execution_state jes ON (sjv.job_id = jes.job_id)

    END

    ELSE

    BEGIN

    INSERT INTO #filtered_jobs

    SELECT DISTINCT

    sjv.job_id,

    sjv.date_created,

    sjv.date_modified,

    ISNULL(jes.execution_job_status, 4), -- Will be NULL if the job is non-local or is not in #job_execution_state (NOTE: 4 = STATE_IDLE)

    CASE ISNULL(jes.execution_step_id, 0)

    WHEN 0 THEN NULL -- Will be NULL if the job is non-local or is not in #job_execution_state

    ELSE CONVERT(NVARCHAR, jes.execution_step_id) + N' (' + jes.execution_step_name + N')'

    END,

    jes.execution_retry_attempt, -- Will be NULL if the job is non-local or is not in #job_execution_state

    0, -- last_run_date placeholder (we'll fix it up in step 3.3)

    0, -- last_run_time placeholder (we'll fix it up in step 3.3)

    5, -- last_run_outcome placeholder (we'll fix it up in step 3.3 - NOTE: We use 5 just in case there are no jobservers for the job)

    jes.next_run_date, -- Will be NULL if the job is non-local or is not in #job_execution_state

    jes.next_run_time, -- Will be NULL if the job is non-local or is not in #job_execution_state

    jes.next_run_schedule_id, -- Will be NULL if the job is non-local or is not in #job_execution_state

    0 -- type placeholder (we'll fix it up in step 3.4)

    FROM msdb.dbo.sysjobs_view sjv

    LEFT OUTER JOIN #job_execution_state jes ON (sjv.job_id = jes.job_id)

    LEFT OUTER JOIN msdb.dbo.sysjobsteps sjs ON (sjv.job_id = sjs.job_id)

    WHERE ((@subsystem IS NULL) OR (sjs.subsystem = @subsystem))

    AND ((@owner_login_name IS NULL) OR (sjv.owner_sid = SUSER_SID(@owner_login_name)))

    AND ((@enabled IS NULL) OR (sjv.enabled = @enabled))

    AND ((@category_id IS NULL) OR (sjv.category_id = @category_id))

    AND ((@execution_status IS NULL) OR ((@execution_status > 0) AND (jes.execution_job_status = @execution_status))

    OR ((@execution_status = 0) AND (jes.execution_job_status <> 4) AND (jes.execution_job_status <> 5)))

    AND ((@description IS NULL) OR (sjv.description LIKE @description))

    AND ((@job_id IS NULL) OR (sjv.job_id = @job_id))

    END

    -- Step 3.1: Change the execution status of non-local jobs from 'Idle' to 'Unknown'

    UPDATE #filtered_jobs

    SET current_execution_status = NULL

    WHERE (current_execution_status = 4)

    AND (job_id IN (SELECT job_id

    FROM msdb.dbo.sysjobservers

    WHERE (server_id <> 0)))

    -- Step 3.2: Check that if the user asked to see idle jobs that we still have some.

    -- If we don't have any then the query should return no rows.

    IF (@execution_status = 4) AND

    (NOT EXISTS (SELECT *

    FROM #filtered_jobs

    WHERE (current_execution_status = 4)))

    BEGIN

    TRUNCATE TABLE #filtered_jobs

    END

    -- Step 3.3: Populate the last run date/time/outcome [this is a little tricky since for

    -- multi-server jobs there are multiple last run details in sysjobservers, so

    -- we simply choose the most recent].

    IF (EXISTS (SELECT *

    FROM msdb.dbo.systargetservers))

    BEGIN

    UPDATE #filtered_jobs

    SET last_run_date = sjs.last_run_date,

    last_run_time = sjs.last_run_time,

    last_run_outcome = sjs.last_run_outcome

    FROM #filtered_jobs fj,

    msdb.dbo.sysjobservers sjs

    WHERE (CONVERT(FLOAT, sjs.last_run_date) * 1000000) + sjs.last_run_time =

    (SELECT MAX((CONVERT(FLOAT, last_run_date) * 1000000) + last_run_time)

    FROM msdb.dbo.sysjobservers

    WHERE (job_id = sjs.job_id))

    AND (fj.job_id = sjs.job_id)

    END

    ELSE

    BEGIN

    UPDATE #filtered_jobs

    SET last_run_date = sjs.last_run_date,

    last_run_time = sjs.last_run_time,

    last_run_outcome = sjs.last_run_outcome

    FROM #filtered_jobs fj,

    msdb.dbo.sysjobservers sjs

    WHERE (fj.job_id = sjs.job_id)

    END

    -- Step 3.4 : Set the type of the job to local (1) or multi-server (2)

    -- NOTE: If the job has no jobservers then it wil have a type of 0 meaning

    -- unknown. This is marginally inconsistent with the behaviour of

    -- defaulting the category of a new job to [Uncategorized (Local)], but

    -- prevents incompletely defined jobs from erroneously showing up as valid

    -- local jobs.

    UPDATE #filtered_jobs

    SET type = 1 -- LOCAL

    FROM #filtered_jobs fj,

    msdb.dbo.sysjobservers sjs

    WHERE (fj.job_id = sjs.job_id)

    AND (server_id = 0)

    UPDATE #filtered_jobs

    SET type = 2 -- MULTI-SERVER

    FROM #filtered_jobs fj,

    msdb.dbo.sysjobservers sjs

    WHERE (fj.job_id = sjs.job_id)

    AND (server_id <> 0)

    -- Step 4: Filter on job_type

    IF (@job_type IS NOT NULL)

    BEGIN

    IF (UPPER(@job_type) = 'LOCAL')

    DELETE FROM #filtered_jobs

    WHERE (type <> 1) -- IE. Delete all the non-local jobs

    IF (UPPER(@job_type) = 'MULTI-SERVER')

    DELETE FROM #filtered_jobs

    WHERE (type <> 2) -- IE. Delete all the non-multi-server jobs

    END

    -- Step 5: Filter on dates

    IF (@date_comparator IS NOT NULL)

    BEGIN

    IF (@date_created IS NOT NULL)

    BEGIN

    IF (@date_comparator = '=')

    DELETE FROM #filtered_jobs WHERE (date_created <> @date_created)

    IF (@date_comparator = '>')

    DELETE FROM #filtered_jobs WHERE (date_created <= @date_created)

    IF (@date_comparator = '<')

    DELETE FROM #filtered_jobs WHERE (date_created >= @date_created)

    END

    IF (@date_last_modified IS NOT NULL)

    BEGIN

    IF (@date_comparator = '=')

    DELETE FROM #filtered_jobs WHERE (date_last_modified <> @date_last_modified)

    IF (@date_comparator = '>')

    DELETE FROM #filtered_jobs WHERE (date_last_modified <= @date_last_modified)

    IF (@date_comparator = '<')

    DELETE FROM #filtered_jobs WHERE (date_last_modified >= @date_last_modified)

    END

    END

    -- Return the result set (NOTE: No filtering occurs here)

    SELECT sjv.job_id,

    sjv.originating_server,

    sjv.name,

    sjv.enabled,

    sjv.description,

    sjv.start_step_id,

    category = ISNULL(sc.name, FORMATMESSAGE(14205)),

    owner = SUSER_SNAME(sjv.owner_sid),

    sjv.notify_level_eventlog,

    sjv.notify_level_email,

    sjv.notify_level_netsend,

    sjv.notify_level_page,

    notify_email_operator = ISNULL(so1.name, FORMATMESSAGE(14205)),

    notify_netsend_operator = ISNULL(so2.name, FORMATMESSAGE(14205)),

    notify_page_operator = ISNULL(so3.name, FORMATMESSAGE(14205)),

    sjv.delete_level,

    sjv.date_created,

    sjv.date_modified,

    sjv.version_number,

    fj.last_run_date,

    fj.last_run_time,

    fj.last_run_outcome,

    next_run_date = ISNULL(fj.next_run_date, 0), -- This column will be NULL if the job is non-local

    next_run_time = ISNULL(fj.next_run_time, 0), -- This column will be NULL if the job is non-local

    next_run_schedule_id = ISNULL(fj.next_run_schedule_id, 0), -- This column will be NULL if the job is non-local

    current_execution_status = ISNULL(fj.current_execution_status, 0), -- This column will be NULL if the job is non-local

    current_execution_step = ISNULL(fj.current_execution_step, N'0 ' + FORMATMESSAGE(14205)), -- This column will be NULL if the job is non-local

    current_retry_attempt = ISNULL(fj.current_retry_attempt, 0), -- This column will be NULL if the job is non-local

    has_step = (SELECT COUNT(*)

    FROM msdb.dbo.sysjobsteps sjst

    WHERE (sjst.job_id = sjv.job_id)),

    has_schedule = (SELECT COUNT(*)

    FROM msdb.dbo.sysjobschedules sjsch

    WHERE (sjsch.job_id = sjv.job_id)),

    has_target = (SELECT COUNT(*)

    FROM msdb.dbo.sysjobservers sjs

    WHERE (sjs.job_id = sjv.job_id)),

    type = fj.type

    FROM #filtered_jobs fj

    LEFT OUTER JOIN msdb.dbo.sysjobs_view sjv ON (fj.job_id = sjv.job_id)

    LEFT OUTER JOIN msdb.dbo.sysoperators so1 ON (sjv.notify_email_operator_id = so1.id)

    LEFT OUTER JOIN msdb.dbo.sysoperators so2 ON (sjv.notify_netsend_operator_id = so2.id)

    LEFT OUTER JOIN msdb.dbo.sysoperators so3 ON (sjv.notify_page_operator_id = so3.id)

    LEFT OUTER JOIN msdb.dbo.syscategories sc ON (sjv.category_id = sc.category_id)

    ORDER BY sjv.job_id

    -- Clean up

    DROP TABLE #job_execution_state

    DROP TABLE #filtered_jobs

    DROP TABLE #xp_results

    END

    go

    /**************************************************************/

    /* SP_HELP_JOB */

    /**************************************************************/

    PRINT ''

    PRINT 'Creating procedure sp_help_job...'

    go

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = N'sp_help_job')

    AND (type = 'P')))

    DROP PROCEDURE sp_help_job

    go

    CREATE PROCEDURE sp_help_job

    -- Individual job parameters

    @job_id UNIQUEIDENTIFIER = NULL, -- If provided should NOT also provide job_name

    @job_name sysname = NULL, -- If provided should NOT also provide job_id

    @job_aspect VARCHAR(9) = NULL, -- JOB, STEPS, SCEDULES, TARGETS or ALL

    -- Job set parameters

    @job_type VARCHAR(12) = NULL, -- LOCAL or MULTI-SERVER

    @owner_login_name sysname = NULL,

    @subsystem NVARCHAR(40) = NULL,

    @category_name sysname = NULL,

    @enabled TINYINT = NULL,

    @execution_status INT = NULL, -- 1 = Executing, 2 = Waiting For Thread, 3 = Between Retries, 4 = Idle, 5 = Suspended, 6 = [obsolete], 7 = PerformingCompletionActions

    @date_comparator CHAR(1) = NULL, -- >, < or =

    @date_created DATETIME = NULL,

    @date_last_modified DATETIME = NULL,

    @description NVARCHAR(512) = NULL -- We do a LIKE on this so it can include wildcards

    AS

    BEGIN

    DECLARE @retval INT

    DECLARE @category_id INT

    DECLARE @job_id_as_char VARCHAR(36)

    DECLARE @res_valid_range NVARCHAR(200)

    SET NOCOUNT ON

    -- Remove any leading/trailing spaces from parameters (except @owner_login_name)

    SELECT @job_name = LTRIM(RTRIM(@job_name))

    SELECT @job_aspect = LTRIM(RTRIM(@job_aspect))

    SELECT @job_type = LTRIM(RTRIM(@job_type))

    SELECT @subsystem = LTRIM(RTRIM(@subsystem))

    SELECT @category_name = LTRIM(RTRIM(@category_name))

    SELECT @description = LTRIM(RTRIM(@description))

    -- Turn [nullable] empty string parameters into NULLs

    IF (@job_name = N'') SELECT @job_name = NULL

    IF (@job_aspect = '') SELECT @job_aspect = NULL

    IF (@job_type = '') SELECT @job_type = NULL

    IF (@owner_login_name = N'') SELECT @owner_login_name = NULL

    IF (@subsystem = N'') SELECT @subsystem = NULL

    IF (@category_name = N'') SELECT @category_name = NULL

    IF (@description = N'') SELECT @description = NULL

    IF ((@job_id IS NOT NULL) OR (@job_name IS NOT NULL))

    BEGIN

    EXECUTE @retval = sp_verify_job_identifiers '@job_name',

    '@job_id',

    @job_name OUTPUT,

    @job_id OUTPUT

    IF (@retval <> 0)

    RETURN(1) -- Failure

    END

    SELECT @job_id_as_char = CONVERT(VARCHAR(36), @job_id)

    -- If the user provided a job name or id but no aspect, default to ALL

    IF ((@job_name IS NOT NULL) OR (@job_id IS NOT NULL)) AND (@job_aspect IS NULL)

    SELECT @job_aspect = 'ALL'

    -- The caller must supply EITHER job name (or job id) and aspect OR one-or-more of the set

    -- parameters OR no parameters at all

    IF (((@job_name IS NOT NULL) OR (@job_id IS NOT NULL))

    AND ((@job_aspect IS NULL) OR

    (@job_type IS NOT NULL) OR

    (@owner_login_name IS NOT NULL) OR

    (@subsystem IS NOT NULL) OR

    (@category_name IS NOT NULL) OR

    (@enabled IS NOT NULL) OR

    (@date_comparator IS NOT NULL) OR

    (@date_created IS NOT NULL) OR

    (@date_last_modified IS NOT NULL)))

    OR

    ((@job_name IS NULL) AND (@job_id IS NULL) AND (@job_aspect IS NOT NULL))

    BEGIN

    RAISERROR(14280, -1, -1)

    RETURN(1) -- Failure

    END

    IF (@job_id IS NOT NULL)

    BEGIN

    -- Individual job...

    -- Check job aspect

    SELECT @job_aspect = UPPER(@job_aspect)

    IF (@job_aspect NOT IN ('JOB', 'STEPS', 'SCHEDULES', 'TARGETS', 'ALL'))

    BEGIN

    RAISERROR(14266, -1, -1, '@job_aspect', 'JOB, STEPS, SCHEDULES, TARGETS, ALL')

    RETURN(1) -- Failure

    END

    -- Generate results set...

    IF (@job_aspect IN ('JOB', 'ALL'))

    BEGIN

    IF (@job_aspect = 'ALL')

    BEGIN

    RAISERROR(14213, 0, 1)

    PRINT REPLICATE('=', DATALENGTH(FORMATMESSAGE(14213)) / 2)

    END

    EXECUTE sp_get_composite_job_info @job_id,

    @job_type,

    @owner_login_name,

    @subsystem,

    @category_id,

    @enabled,

    @execution_status,

    @date_comparator,

    @date_created,

    @date_last_modified,

    @description

    END

    IF (@job_aspect IN ('STEPS', 'ALL'))

    BEGIN

    IF (@job_aspect = 'ALL')

    BEGIN

    PRINT ''

    RAISERROR(14214, 0, 1)

    PRINT REPLICATE('=', DATALENGTH(FORMATMESSAGE(14214)) / 2)

    END

    EXECUTE ('EXECUTE sp_help_jobstep @job_id = ''' + @job_id_as_char + ''', @suffix = 1')

    END

    IF (@job_aspect IN ('SCHEDULES', 'ALL'))

    BEGIN

    IF (@job_aspect = 'ALL')

    BEGIN

    PRINT ''

    RAISERROR(14215, 0, 1)

    PRINT REPLICATE('=', DATALENGTH(FORMATMESSAGE(14215)) / 2)

    END

    EXECUTE ('EXECUTE sp_help_jobschedule @job_id = ''' + @job_id_as_char + '''')

    END

    IF (@job_aspect IN ('TARGETS', 'ALL'))

    BEGIN

    IF (@job_aspect = 'ALL')

    BEGIN

    PRINT ''

    RAISERROR(14216, 0, 1)

    PRINT REPLICATE('=', DATALENGTH(FORMATMESSAGE(14216)) / 2)

    END

    EXECUTE ('EXECUTE sp_help_jobserver @job_id = ''' + @job_id_as_char + ''', @show_last_run_details = 1')

    END

    END

    ELSE

    BEGIN

    -- Set of jobs...

    -- Check job type

    IF (@job_type IS NOT NULL)

    BEGIN

    SELECT @job_type = UPPER(@job_type)

    IF (@job_type NOT IN ('LOCAL', 'MULTI-SERVER'))

    BEGIN

    RAISERROR(14266, -1, -1, '@job_type', 'LOCAL, MULTI-SERVER')

    RETURN(1) -- Failure

    END

    END

    -- Check owner

    IF (@owner_login_name IS NOT NULL)

    BEGIN

    IF (SUSER_SID(@owner_login_name) IS NULL)

    BEGIN

    RAISERROR(14262, -1, -1, '@owner_login_name', @owner_login_name)

    RETURN(1) -- Failure

    END

    END

    -- Check subsystem

    IF (@subsystem IS NOT NULL)

    BEGIN

    EXECUTE @retval = sp_verify_subsystem @subsystem

    IF (@retval <> 0)

    RETURN(1) -- Failure

    END

    -- Check job category

    IF (@category_name IS NOT NULL)

    BEGIN

    SELECT @category_id = category_id

    FROM msdb.dbo.syscategories

    WHERE (category_class = 1) -- Job

    AND (name = @category_name)

    IF (@category_id IS NULL)

    BEGIN

    RAISERROR(14262, -1, -1, '@category_name', @category_name)

    RETURN(1) -- Failure

    END

    END

    -- Check enabled state

    IF (@enabled IS NOT NULL) AND (@enabled NOT IN (0, 1))

    BEGIN

    RAISERROR(14266, -1, -1, '@enabled', '0, 1')

    RETURN(1) -- Failure

    END

    -- Check current execution status

    IF (@execution_status IS NOT NULL)

    BEGIN

    IF (@execution_status NOT IN (0, 1, 2, 3, 4, 5, 7))

    BEGIN

    SELECT @res_valid_range = FORMATMESSAGE(14204)

    RAISERROR(14266, -1, -1, '@execution_status', @res_valid_range)

    RETURN(1) -- Failure

    END

    END

    -- If a date comparator is supplied, we must have either a date-created or date-last-modified

    IF ((@date_comparator IS NOT NULL) AND (@date_created IS NOT NULL) AND (@date_last_modified IS NOT NULL)) OR

    ((@date_comparator IS NULL) AND ((@date_created IS NOT NULL) OR (@date_last_modified IS NOT NULL)))

    BEGIN

    RAISERROR(14282, -1, -1)

    RETURN(1) -- Failure

    END

    -- Check dates / comparator

    IF (@date_comparator IS NOT NULL) AND (@date_comparator NOT IN ('=', ' '))

    BEGIN

    RAISERROR(14266, -1, -1, '@date_comparator', '=, >, <')

    RETURN(1) -- Failure

    END

    IF (@date_created IS NOT NULL) AND

    ((@date_created '31 Dec 9999 11:59:59pm'))

    BEGIN

    RAISERROR(14266, -1, -1, '@date_created', '1/1/1990 12:00am .. 12/31/9999 11:59pm')

    RETURN(1) -- Failure

    END

    IF (@date_last_modified IS NOT NULL) AND

    ((@date_last_modified 'Dec 31 9999 11:59:59pm'))

    BEGIN

    RAISERROR(14266, -1, -1, '@date_last_modified', '1/1/1990 12:00am .. 12/31/9999 11:59pm')

    RETURN(1) -- Failure

    END

    -- Generate results set...

    EXECUTE sp_get_composite_job_info @job_id,

    @job_type,

    @owner_login_name,

    @subsystem,

    @category_id,

    @enabled,

    @execution_status,

    @date_comparator,

    @date_created,

    @date_last_modified,

    @description

    END

    RETURN(0) -- Success

    END

    go

    DUMP TRANSACTION msdb WITH NO_LOG

    go

    CHECKPOINT

    go

    /**************************************************************/

    /* SP_MANAGE_JOBS_BY_LOGIN */

    /**************************************************************/

    PRINT ''

    PRINT 'Creating procedure sp_manage_jobs_by_login...'

    go

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = N'sp_manage_jobs_by_login')

    AND (type = 'P')))

    DROP PROCEDURE sp_manage_jobs_by_login

    go

    CREATE PROCEDURE sp_manage_jobs_by_login

    @action VARCHAR(10), -- DELETE or REASSIGN

    @current_owner_login_name sysname,

    @new_owner_login_name sysname = NULL

    AS

    BEGIN

    DECLARE @current_sid VARBINARY(85)

    DECLARE @new_sid VARBINARY(85)

    DECLARE @job_id UNIQUEIDENTIFIER

    DECLARE @rows_affected INT

    DECLARE @is_sysadmin INT

    SET NOCOUNT ON

    -- Remove any leading/trailing spaces from parameters

    SELECT @action = LTRIM(RTRIM(@action))

    SELECT @current_owner_login_name = LTRIM(RTRIM(@current_owner_login_name))

    SELECT @new_owner_login_name = LTRIM(RTRIM(@new_owner_login_name))

    -- Turn [nullable] empty string parameters into NULLs

    IF (@new_owner_login_name = N'') SELECT @new_owner_login_name = NULL

    -- Only a sysadmin can do this

    IF (ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) <> 1)

    BEGIN

    RAISERROR(15003, 16, 1, N'sysadmin')

    RETURN(1) -- Failure

    END

    -- Check action

    IF (@action NOT IN ('DELETE', 'REASSIGN'))

    BEGIN

    RAISERROR(14266, -1, -1, '@action', 'DELETE, REASSIGN')

    RETURN(1) -- Failure

    END

    -- Check parameter combinations

    IF ((@action = 'DELETE') AND (@new_owner_login_name IS NOT NULL))

    RAISERROR(14281, 0, 1)

    IF ((@action = 'REASSIGN') AND (@new_owner_login_name IS NULL))

    BEGIN

    RAISERROR(14237, -1, -1)

    RETURN(1) -- Failure

    END

    -- Check current login

    SELECT @current_sid = SUSER_SID(@current_owner_login_name)

    IF (@current_sid IS NULL)

    BEGIN

    RAISERROR(14262, -1, -1, '@current_owner_login_name', @current_owner_login_name)

    RETURN(1) -- Failure

    END

    -- Check new login (if supplied)

    IF (@new_owner_login_name IS NOT NULL)

    BEGIN

    SELECT @new_sid = SUSER_SID(@new_owner_login_name)

    IF (@new_sid IS NULL)

    BEGIN

    RAISERROR(14262, -1, -1, '@new_owner_login_name', @new_owner_login_name)

    RETURN(1) -- Failure

    END

    END

    IF (@action = 'DELETE')

    BEGIN

    DECLARE jobs_to_delete CURSOR LOCAL

    FOR

    SELECT job_id

    FROM msdb.dbo.sysjobs

    WHERE (owner_sid = @current_sid)

    OPEN jobs_to_delete

    FETCH NEXT FROM jobs_to_delete INTO @job_id

    SELECT @rows_affected = 0

    WHILE (@@fetch_status = 0)

    BEGIN

    EXECUTE sp_delete_job @job_id = @job_id

    SELECT @rows_affected = @rows_affected + 1

    FETCH NEXT FROM jobs_to_delete INTO @job_id

    END

    DEALLOCATE jobs_to_delete

    RAISERROR(14238, 0, 1, @rows_affected)

    END

    ELSE

    IF (@action = 'REASSIGN')

    BEGIN

    -- Check if the current owner owns any multi-server jobs.

    -- If they do, then the new owner must be member of the sysadmin role.

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysjobs sj,

    msdb.dbo.sysjobservers sjs

    WHERE (sj.job_id = sjs.job_id)

    AND (sj.owner_sid = @current_sid)

    AND (sjs.server_id <> 0)))

    BEGIN

    SELECT @is_sysadmin = 0

    EXECUTE msdb.dbo.sp_sqlagent_has_server_access @login_name = @new_owner_login_name, @is_sysadmin_member = @is_sysadmin OUTPUT

    IF (@is_sysadmin = 0)

    BEGIN

    RAISERROR(14543, -1, -1, @current_owner_login_name, N'sysadmin')

    RETURN(1) -- Failure

    END

    END

    UPDATE msdb.dbo.sysjobs

    SET owner_sid = @new_sid

    WHERE (owner_sid = @current_sid)

    RAISERROR(14239, 0, 1, @@rowcount, @new_owner_login_name)

    END

    RETURN(0) -- Success

    END

    go

    /**************************************************************/

    /* SP_APPLY_JOB_TO_TARGETS */

    /**************************************************************/

    PRINT ''

    PRINT 'Creating procedure sp_apply_job_to_targets...'

    go

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = N'sp_apply_job_to_targets')

    AND (type = 'P')))

    DROP PROCEDURE sp_apply_job_to_targets

    go

    CREATE PROCEDURE sp_apply_job_to_targets

    @job_id UNIQUEIDENTIFIER = NULL, -- Must provide either this or job_name

    @job_name sysname = NULL, -- Must provide either this or job_id

    @target_server_groups NVARCHAR(2048) = NULL, -- A comma-separated list of target server groups

    @target_servers NVARCHAR(2048) = NULL, -- An comma-separated list of target servers

    @operation VARCHAR(7) = 'APPLY' -- Or 'REMOVE'

    AS

    BEGIN

    DECLARE @retval INT

    DECLARE @rows_affected INT

    DECLARE @server_name NVARCHAR(30)

    DECLARE @groups NVARCHAR(2048)

    DECLARE @group sysname

    DECLARE @servers NVARCHAR(2048)

    DECLARE @server NVARCHAR(30)

    DECLARE @pos_of_comma INT

    SET NOCOUNT ON

    -- Only a sysadmin can do this

    IF (ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) <> 1)

    BEGIN

    RAISERROR(15003, 16, 1, N'sysadmin')

    RETURN(1) -- Failure

    END

    -- Remove any leading/trailing spaces from parameters

    SELECT @target_server_groups = LTRIM(RTRIM(@target_server_groups))

    SELECT @target_servers = LTRIM(RTRIM(@target_servers))

    SELECT @operation = LTRIM(RTRIM(@operation))

    -- Turn [nullable] empty string parameters into NULLs

    IF (@target_server_groups = NULL) SELECT @target_server_groups = NULL

    IF (@target_servers = NULL) SELECT @target_servers = NULL

    IF (@operation = NULL) SELECT @operation = NULL

    EXECUTE @retval = sp_verify_job_identifiers '@job_name',

    '@job_id',

    @job_name OUTPUT,

    @job_id OUTPUT

    IF (@retval <> 0)

    RETURN(1) -- Failure

    -- Check operation type

    IF ((@operation <> 'APPLY') AND (@operation <> 'REMOVE'))

    BEGIN

    RAISERROR(14266, -1, -1, '@operation', 'APPLY, REMOVE')

    RETURN(1) -- Failure

    END

    CREATE TABLE #temp_groups (group_name sysname COLLATE database_default NOT NULL)

    CREATE TABLE #temp_server_name (server_name NVARCHAR(30) COLLATE database_default NOT NULL)

    -- Check that we have a target server group list and/or a target server list

    IF ((@target_server_groups IS NULL) AND (@target_servers IS NULL))

    BEGIN

    RAISERROR(14283, -1, -1)

    RETURN(1) -- Failure

    END

    -- Parse the Target Server comma-separated list (if supplied)

    IF (@target_servers IS NOT NULL)

    BEGIN

    SELECT @servers = @target_servers

    SELECT @pos_of_comma = CHARINDEX(N',', @servers)

    WHILE (@pos_of_comma <> 0)

    BEGIN

    SELECT @server = SUBSTRING(@servers, 1, @pos_of_comma - 1)

    INSERT INTO #temp_server_name (server_name) VALUES (LTRIM(RTRIM(@server)))

    SELECT @servers = RIGHT(@servers, (DATALENGTH(@servers) / 2) - @pos_of_comma)

    SELECT @pos_of_comma = CHARINDEX(N',', @servers)

    END

    INSERT INTO #temp_server_name (server_name) VALUES (LTRIM(RTRIM(@servers)))

    END

    -- Parse the Target Server Groups comma-separated list

    IF (@target_server_groups IS NOT NULL)

    BEGIN

    SELECT @groups = @target_server_groups

    SELECT @pos_of_comma = CHARINDEX(N',', @groups)

    WHILE (@pos_of_comma <> 0)

    BEGIN

    SELECT @group = SUBSTRING(@groups, 1, @pos_of_comma - 1)

    INSERT INTO #temp_groups (group_name) VALUES (LTRIM(RTRIM(@group)))

    SELECT @groups = RIGHT(@groups, (DATALENGTH(@groups) / 2) - @pos_of_comma)

    SELECT @pos_of_comma = CHARINDEX(N',', @groups)

    END

    INSERT INTO #temp_groups (group_name) VALUES (LTRIM(RTRIM(@groups)))

    END

    -- Check server groups

    SET ROWCOUNT 1 -- We do this so that we catch the FIRST invalid group

    SELECT @group = NULL

    SELECT @group = group_name

    FROM #temp_groups

    WHERE group_name NOT IN (SELECT name

    FROM msdb.dbo.systargetservergroups)

    IF (@group IS NOT NULL)

    BEGIN

    RAISERROR(14262, -1, -1, '@target_server_groups', @group)

    RETURN(1) -- Failure

    END

    SET ROWCOUNT 0

    -- Find the distinct list of servers being targeted

    INSERT INTO #temp_server_name (server_name)

    SELECT DISTINCT sts.server_name

    FROM msdb.dbo.systargetservergroups stsg,

    msdb.dbo.systargetservergroupmembers stsgm,

    msdb.dbo.systargetservers sts

    WHERE (stsg.name IN (SELECT group_name FROM #temp_groups))

    AND (stsg.servergroup_id = stsgm.servergroup_id)

    AND (stsgm.server_id = sts.server_id)

    AND (sts.server_name NOT IN (SELECT server_name

    FROM #temp_server_name))

    IF (@operation = 'APPLY')

    BEGIN

    -- Remove those servers to which the job has already been applied

    DELETE FROM #temp_server_name

    WHERE server_name IN (SELECT sts.server_name

    FROM msdb.dbo.sysjobservers sjs,

    msdb.dbo.systargetservers sts

    WHERE (sjs.job_id = @job_id)

    AND (sjs.server_id = sts.server_id))

    END

    IF (@operation = 'REMOVE')

    BEGIN

    -- Remove those servers to which the job is not currently applied

    DELETE FROM #temp_server_name

    WHERE server_name NOT IN (SELECT sts.server_name

    FROM msdb.dbo.sysjobservers sjs,

    msdb.dbo.systargetservers sts

    WHERE (sjs.job_id = @job_id)

    AND (sjs.server_id = sts.server_id))

    END

    SELECT @rows_affected = COUNT(*)

    FROM #temp_server_name

    SET ROWCOUNT 1

    WHILE (EXISTS (SELECT *

    FROM #temp_server_name))

    BEGIN

    SELECT @server_name = server_name

    FROM #temp_server_name

    IF (@operation = 'APPLY')

    EXECUTE sp_add_jobserver @job_id = @job_id, @server_name = @server_name

    ELSE

    IF (@operation = 'REMOVE')

    EXECUTE sp_delete_jobserver @job_id = @job_id, @server_name = @server_name

    DELETE FROM #temp_server_name

    WHERE (server_name = @server_name)

    END

    SET ROWCOUNT 0

    IF (@operation = 'APPLY')

    RAISERROR(14240, 0, 1, @rows_affected)

    IF (@operation = 'REMOVE')

    RAISERROR(14241, 0, 1, @rows_affected)

    RETURN(0) -- Success

    END

    go

    /**************************************************************/

    /* SP_REMOVE_JOB_FROM_TARGETS */

    /**************************************************************/

    PRINT ''

    PRINT 'Creating procedure sp_remove_job_from_targets...'

    go

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = N'sp_remove_job_from_targets')

    AND (type = 'P')))

    DROP PROCEDURE sp_remove_job_from_targets

    go

    CREATE PROCEDURE sp_remove_job_from_targets

    @job_id UNIQUEIDENTIFIER = NULL, -- Must provide either this or job_name

    @job_name sysname = NULL, -- Must provide either this or job_id

    @target_server_groups NVARCHAR(1024) = NULL, -- A comma-separated list of target server groups

    @target_servers NVARCHAR(1024) = NULL -- A comma-separated list of target servers

    AS

    BEGIN

    DECLARE @retval INT

    SET NOCOUNT ON

    EXECUTE @retval = sp_apply_job_to_targets @job_id,

    @job_name,

    @target_server_groups,

    @target_servers,

    'REMOVE'

    RETURN(@retval) -- 0 means success

    END

    go

    /**************************************************************/

    /* SP_GET_JOB_ALERTS */

    /**************************************************************/

    PRINT ''

    PRINT 'Creating procedure sp_get_job_alerts...'

    go

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = N'sp_get_job_alerts')

    AND (type = 'P')))

    DROP PROCEDURE sp_get_job_alerts

    go

    CREATE PROCEDURE sp_get_job_alerts

    @job_id UNIQUEIDENTIFIER = NULL,

    @job_name sysname = NULL

    AS

    BEGIN

    DECLARE @retval INT

    EXECUTE @retval = sp_verify_job_identifiers '@job_name',

    '@job_id',

    @job_name OUTPUT,

    @job_id OUTPUT

    IF (@retval <> 0)

    RETURN(1) -- Failure

    SELECT id,

    name,

    enabled,

    type = CASE ISNULL(performance_condition, N'!')

    WHEN N'!' THEN

    CASE event_source

    WHEN N'MSSQLSERVER' THEN 1 -- SQL Server event alert

    ELSE 3 -- Non SQL Server event alert

    END

    ELSE 2 -- SQL Server performance condition alert

    END

    FROM msdb.dbo.sysalerts

    WHERE (job_id = @job_id)

    RETURN(0) -- Success

    END

    go

    /**************************************************************/

    /* */

    /* S U P P O R T P R O C E D U R E S */

    /* */

    /**************************************************************/

    /**************************************************************/

    /* SP_CONVERT_JOBID_TO_CHAR [used by SEM only] */

    /**************************************************************/

    PRINT ''

    PRINT 'Creating procedure sp_convert_jobid_to_char...'

    go

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = N'sp_convert_jobid_to_char')

    AND (type = 'P')))

    DROP PROCEDURE sp_convert_jobid_to_char

    go

    CREATE PROCEDURE sp_convert_jobid_to_char

    @job_id UNIQUEIDENTIFIER,

    @job_id_as_char NVARCHAR(34) OUTPUT -- 34 because of the leading '0x'

    AS

    BEGIN

    DECLARE @job_id_as_binary BINARY(16)

    DECLARE @temp NCHAR(8)

    DECLARE @counter INT

    DECLARE @byte_value INT

    DECLARE @high_word INT

    DECLARE @low_word INT

    DECLARE @high_high_nybble INT

    DECLARE @high_low_nybble INT

    DECLARE @low_high_nybble INT

    DECLARE @low_low_nybble INT

    SET NOCOUNT ON

    SELECT @job_id_as_binary = CONVERT(BINARY(16), @job_id)

    SELECT @temp = CONVERT(NCHAR(8), @job_id_as_binary)

    SELECT @job_id_as_char = N''

    SELECT @counter = 1

    WHILE (@counter <= (DATALENGTH(@temp) / 2))

    BEGIN

    SELECT @byte_value = CONVERT(INT, CONVERT(BINARY(2), SUBSTRING(@temp, @counter, 1)))

    SELECT @high_word = (@byte_value & 0xff00) / 0x100

    SELECT @low_word = (@byte_value & 0x00ff)

    SELECT @high_high_nybble = (@high_word & 0xff) / 16

    SELECT @high_low_nybble = (@high_word & 0xff) % 16

    SELECT @low_high_nybble = (@low_word & 0xff) / 16

    SELECT @low_low_nybble = (@low_word & 0xff) % 16

    IF (@high_high_nybble < 10)

    SELECT @job_id_as_char = @job_id_as_char + NCHAR(ASCII('0') + @high_high_nybble)

    ELSE

    SELECT @job_id_as_char = @job_id_as_char + NCHAR(ASCII('A') + (@high_high_nybble - 10))

    IF (@high_low_nybble < 10)

    SELECT @job_id_as_char = @job_id_as_char + NCHAR(ASCII('0') + @high_low_nybble)

    ELSE

    SELECT @job_id_as_char = @job_id_as_char + NCHAR(ASCII('A') + (@high_low_nybble - 10))

    IF (@low_high_nybble < 10)

    SELECT @job_id_as_char = @job_id_as_char + NCHAR(ASCII('0') + @low_high_nybble)

    ELSE

    SELECT @job_id_as_char = @job_id_as_char + NCHAR(ASCII('A') + (@low_high_nybble - 10))

    IF (@low_low_nybble < 10)

    SELECT @job_id_as_char = @job_id_as_char + NCHAR(ASCII('0') + @low_low_nybble)

    ELSE

    SELECT @job_id_as_char = @job_id_as_char + NCHAR(ASCII('A') + (@low_low_nybble - 10))

    SELECT @counter = @counter + 1

    END

    SELECT @job_id_as_char = N'0x' + LOWER(@job_id_as_char)

    END

    go

    /**************************************************************/

    /* SP_START_JOB */

    /**************************************************************/

    PRINT ''

    PRINT 'Creating procedure sp_start_job...'

    go

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = N'sp_start_job')

    AND (type = 'P')))

    DROP PROCEDURE sp_start_job

    go

    CREATE PROCEDURE sp_start_job

    @job_name sysname = NULL,

    @job_id UNIQUEIDENTIFIER = NULL,

    @error_flag INT = 1, -- Set to 0 to suppress the error from sp_sqlagent_notify if SQLServerAgent is not running

    @server_name NVARCHAR(30) = NULL, -- The specific target server to start the [multi-server] job on

    @step_name sysname = NULL, -- The name of the job step to start execution with [for use with a local job only]

    @output_flag INT = 1 -- Set to 0 to suppress the success message

    AS

    BEGIN

    DECLARE @job_id_as_char VARCHAR(36)

    DECLARE @retval INT

    DECLARE @step_id INT

    SET NOCOUNT ON

    -- Remove any leading/trailing spaces from parameters

    SELECT @job_name = LTRIM(RTRIM(@job_name))

    SELECT @server_name = LTRIM(RTRIM(@server_name))

    SELECT @step_name = LTRIM(RTRIM(@step_name))

    -- Turn [nullable] empty string parameters into NULLs

    IF (@job_name = N'') SELECT @job_name = NULL

    IF (@server_name = N'') SELECT @server_name = NULL

    IF (@step_name = N'') SELECT @step_name = NULL

    EXECUTE @retval = sp_verify_job_identifiers '@job_name',

    '@job_id',

    @job_name OUTPUT,

    @job_id OUTPUT

    IF (@retval <> 0)

    RETURN(1) -- Failure

    IF (NOT EXISTS (SELECT *

    FROM msdb.dbo.sysjobservers

    WHERE (job_id = @job_id)))

    BEGIN

    SELECT @job_id_as_char = CONVERT(VARCHAR(36), @job_id)

    RAISERROR(14256, -1, -1, @job_name, @job_id_as_char)

    RETURN(1) -- Failure

    END

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysjobservers

    WHERE (job_id = @job_id)

    AND (server_id = 0)))

    BEGIN

    -- The job is local, so start (run) the job locally

    -- Check the step name (if supplied)

    IF (@step_name IS NOT NULL)

    BEGIN

    SELECT @step_id = step_id

    FROM msdb.dbo.sysjobsteps

    WHERE (step_name = @step_name)

    AND (job_id = @job_id)

    IF (@step_id IS NULL)

    BEGIN

    RAISERROR(14262, -1, -1, '@step_name', @step_name)

    RETURN(1) -- Failure

    END

    END

    EXECUTE @retval = msdb.dbo.sp_sqlagent_notify @op_type = N'J',

    @job_id = @job_id,

    @schedule_id = @step_id, -- This is the start step

    @action_type = N'S',

    @error_flag = @error_flag

    IF ((@retval = 0) AND (@output_flag = 1))

    RAISERROR(14243, 0, 1, @job_name)

    END

    ELSE

    BEGIN

    -- The job is a multi-server job

    -- Check target server name (if any)

    IF (@server_name IS NOT NULL)

    BEGIN

    IF (NOT EXISTS (SELECT *

    FROM msdb.dbo.systargetservers

    WHERE (server_name = @server_name)))

    BEGIN

    RAISERROR(14262, -1, -1, '@server_name', @server_name)

    RETURN(1) -- Failure

    END

    END

    -- Re-post the job if it's an auto-delete job

    IF ((SELECT delete_level

    FROM msdb.dbo.sysjobs

    WHERE (job_id = @job_id)) <> 0)

    EXECUTE @retval = msdb.dbo.sp_post_msx_operation 'INSERT', 'JOB', @job_id, @server_name

    -- Post start instruction(s)

    EXECUTE @retval = msdb.dbo.sp_post_msx_operation 'START', 'JOB', @job_id, @server_name

    END

    RETURN(@retval) -- 0 means success

    END

    go

    /**************************************************************/

    /* SP_STOP_JOB */

    /**************************************************************/

    PRINT ''

    PRINT 'Creating procedure sp_stop_job...'

    go

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = N'sp_stop_job')

    AND (type = 'P')))

    DROP PROCEDURE sp_stop_job

    go

    CREATE PROCEDURE sp_stop_job

    @job_name sysname = NULL,

    @job_id UNIQUEIDENTIFIER = NULL,

    @originating_server NVARCHAR(30) = NULL, -- So that we can stop ALL jobs that came from the given server

    @server_name NVARCHAR(30) = NULL -- The specific target server to stop the [multi-server] job on

    AS

    BEGIN

    DECLARE @job_id_as_char VARCHAR(36)

    DECLARE @retval INT

    DECLARE @num_parameters INT

    SET NOCOUNT ON

    -- Remove any leading/trailing spaces from parameters

    SELECT @job_name = LTRIM(RTRIM(@job_name))

    SELECT @originating_server = LTRIM(RTRIM(@originating_server))

    SELECT @server_name = LTRIM(RTRIM(@server_name))

    -- Turn [nullable] empty string parameters into NULLs

    IF (@job_name = N'') SELECT @job_name = NULL

    IF (@originating_server = N'') SELECT @originating_server = NULL

    IF (@server_name = N'') SELECT @server_name = NULL

    -- We must have EITHER a job id OR a job name OR an originating server

    SELECT @num_parameters = 0

    IF (@job_id IS NOT NULL)

    SELECT @num_parameters = @num_parameters + 1

    IF (@job_name IS NOT NULL)

    SELECT @num_parameters = @num_parameters + 1

    IF (@originating_server IS NOT NULL)

    SELECT @num_parameters = @num_parameters + 1

    IF (@num_parameters <> 1)

    BEGIN

    RAISERROR(14232, -1, -1)

    RETURN(1) -- Failure

    END

    IF (@originating_server IS NOT NULL)

    BEGIN

    -- Stop (cancel) ALL local jobs that originated from the specified server

    IF (NOT EXISTS (SELECT *

    FROM msdb.dbo.sysjobs_view

    WHERE (originating_server = @originating_server)))

    BEGIN

    RAISERROR(14268, -1, -1, @originating_server)

    RETURN(1) -- Failure

    END

    DECLARE @total_counter INT

    DECLARE @success_counter INT

    DECLARE stop_jobs CURSOR LOCAL

    FOR

    SELECT job_id

    FROM msdb.dbo.sysjobs_view

    WHERE (originating_server = @originating_server)

    SELECT @total_counter = 0, @success_counter = 0

    OPEN stop_jobs

    FETCH NEXT FROM stop_jobs INTO @job_id

    WHILE (@@fetch_status = 0)

    BEGIN

    SELECT @total_counter + @total_counter + 1

    EXECUTE @retval = msdb.dbo.sp_sqlagent_notify @op_type = N'J',

    @job_id = @job_id,

    @action_type = N'C'

    IF (@retval = 0)

    SELECT @success_counter = @success_counter + 1

    FETCH NEXT FROM stop_jobs INTO @job_id

    END

    RAISERROR(14253, 0, 1, @success_counter, @total_counter)

    DEALLOCATE stop_jobs

    RETURN(0) -- 0 means success

    END

    ELSE

    BEGIN

    -- Stop ONLY the specified job

    EXECUTE @retval = sp_verify_job_identifiers '@job_name',

    '@job_id',

    @job_name OUTPUT,

    @job_id OUTPUT

    IF (@retval <> 0)

    RETURN(1) -- Failure

    IF (NOT EXISTS (SELECT *

    FROM msdb.dbo.sysjobservers

    WHERE (job_id = @job_id)))

    BEGIN

    SELECT @job_id_as_char = CONVERT(VARCHAR(36), @job_id)

    RAISERROR(14257, -1, -1, @job_name, @job_id_as_char)

    RETURN(1) -- Failure

    END

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysjobservers

    WHERE (job_id = @job_id)

    AND (server_id = 0)))

    BEGIN

    -- The job is local, so stop (cancel) the job locally

    EXECUTE @retval = msdb.dbo.sp_sqlagent_notify @op_type = N'J',

    @job_id = @job_id,

    @action_type = N'C'

    IF (@retval = 0)

    RAISERROR(14254, 0, 1, @job_name)

    END

    ELSE

    BEGIN

    -- The job is a multi-server job

    -- Check target server name (if any)

    IF (@server_name IS NOT NULL)

    BEGIN

    IF (NOT EXISTS (SELECT *

    FROM msdb.dbo.systargetservers

    WHERE (server_name = @server_name)))

    BEGIN

    RAISERROR(14262, -1, -1, '@server_name', @server_name)

    RETURN(1) -- Failure

    END

    END

    -- Post the stop instruction(s)

    EXECUTE @retval = sp_post_msx_operation 'STOP', 'JOB', @job_id, @server_name

    END

    RETURN(@retval) -- 0 means success

    END

    END

    go

    /**************************************************************/

    /* SP_GET_CHUNKED_JOBSTEP_PARAMS */

    /**************************************************************/

    PRINT ''

    PRINT 'Creating procedure sp_get_chunked_jobstep_params...'

    go

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = N'sp_get_chunked_jobstep_params')

    AND (type = 'P')))

    DROP PROCEDURE sp_get_chunked_jobstep_params

    go

    CREATE PROCEDURE sp_get_chunked_jobstep_params

    @job_name sysname,

    @step_id INT = 1

    AS

    BEGIN

    DECLARE @job_id UNIQUEIDENTIFIER

    DECLARE @step_id_as_char VARCHAR(10)

    DECLARE @text_pointer VARBINARY(16)

    DECLARE @remaining_length INT

    DECLARE @offset INT

    DECLARE @chunk INT

    DECLARE @retval INT

    SET NOCOUNT ON

    -- Check that the job exists

    EXECUTE @retval = sp_verify_job_identifiers '@job_name',

    '@job_id',

    @job_name OUTPUT,

    @job_id OUTPUT

    IF (@retval <> 0)

    RETURN(1) -- Failure

    -- Check that the step exists

    IF (NOT EXISTS (SELECT *

    FROM msdb.dbo.sysjobsteps

    WHERE (job_id = @job_id)

    AND (step_id = @step_id)))

    BEGIN

    SELECT @step_id_as_char = CONVERT(VARCHAR(10), @step_id)

    RAISERROR(14262, -1, -1, '@step_id', @step_id_as_char)

    RETURN(1) -- Failure

    END

    -- Return the sysjobsteps.additional_parameters TEXT column as multiple readtexts of

    -- length 2048

    SELECT @text_pointer = TEXTPTR(additional_parameters),

    @remaining_length = (DATALENGTH(additional_parameters) / 2)

    FROM msdb.dbo.sysjobsteps

    WHERE (job_id = @job_id)

    AND (step_id = @step_id)

    SELECT @offset = 0, @chunk = 100

    -- Get all the chunks of @chunk size

    WHILE (@remaining_length > @chunk)

    BEGIN

    READTEXT msdb.dbo.sysjobsteps.additional_parameters @text_pointer @offset @chunk

    SELECT @offset = @offset + @chunk

    SELECT @remaining_length = @remaining_length - @chunk

    END

    -- Get the last chunk

    IF (@remaining_length > 0)

    READTEXT msdb.dbo.sysjobsteps.additional_parameters @text_pointer @offset @remaining_length

    RETURN(@@error) -- 0 means success

    END

    go

    /**************************************************************/

    /* SP_CHECK_FOR_OWNED_JOBS */

    /**************************************************************/

    PRINT ''

    PRINT 'Creating procedure sp_check_for_owned_jobs...'

    go

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = N'sp_check_for_owned_jobs')

    AND (type = 'P')))

    DROP PROCEDURE sp_check_for_owned_jobs

    go

    CREATE PROCEDURE sp_check_for_owned_jobs

    @login_name sysname,

    @table_name sysname

    AS

    BEGIN

    SET NOCOUNT ON

    -- This procedure is called by sp_droplogin to check if the login being dropped

    -- still owns jobs. The return value (the number of jobs owned) is passed back

    -- via the supplied table name [this cumbersome approach is necessary because

    -- sp_check_for_owned_jobs is invoked via an EXEC() and because we always want

    -- sp_droplogin to work, even if msdb and/or sysjobs does not exist].

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = N'sysjobs')

    AND (type = 'U')))

    BEGIN

    DECLARE @sql NVARCHAR(1024)

    SET @sql = N'INSERT INTO ' + QUOTENAME(@table_name, N'[') + N' SELECT COUNT(*) FROM msdb.dbo.sysjobs WHERE (owner_sid = SUSER_SID(N' + QUOTENAME(@login_name, '''') + '))'

    EXEC sp_executesql @statement = @sql

    END

    END

    go

    /**************************************************************/

    /* SP_CHECK_FOR_OWNED_JOBSTEPS */

    /**************************************************************/

    PRINT ''

    PRINT 'Creating procedure sp_check_for_owned_jobsteps...'

    go

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = N'sp_check_for_owned_jobsteps')

    AND (type = 'P')))

    DROP PROCEDURE sp_check_for_owned_jobsteps

    go

    CREATE PROCEDURE sp_check_for_owned_jobsteps

    @login_name sysname = NULL, -- Supply this OR the database_X parameters, but not both

    @database_name sysname = NULL,

    @database_user_name sysname = NULL

    AS

    BEGIN

    DECLARE @db_name NVARCHAR(255)

    DECLARE @escaped_db_name NVARCHAR(255)

    SET NOCOUNT ON

    CREATE TABLE #work_table

    (

    database_name sysname COLLATE database_default,

    database_user_name sysname COLLATE database_default

    )

    IF ((@login_name IS NOT NULL) AND (@database_name IS NULL) AND (@database_user_name IS NULL))

    BEGIN

    IF (SUSER_SID(@login_name) IS NULL)

    BEGIN

    RAISERROR(14262, -1, -1, '@login_name', @login_name)

    RETURN(1) -- Failure

    END

    DECLARE all_databases CURSOR LOCAL

    FOR

    SELECT name

    FROM master.dbo.sysdatabases

    OPEN all_databases

    FETCH NEXT FROM all_databases INTO @db_name

    -- Double up any single quotes in @login_name

    SELECT @login_name = REPLACE(@login_name, N'''', N'''''')

    WHILE (@@fetch_status = 0)

    BEGIN

    SELECT @escaped_db_name = QUOTENAME(@db_name, N'[')

    SELECT @db_name = REPLACE(@db_name, '''', '''''')

    EXECUTE(N'INSERT INTO #work_table

    SELECT N''' + @db_name + N''', name

    FROM ' + @escaped_db_name + N'.dbo.sysusers

    WHERE (sid = SUSER_SID(N''' + @login_name + N'''))')

    FETCH NEXT FROM all_databases INTO @db_name

    END

    DEALLOCATE all_databases

    -- If the login is an NT login, check for steps run as the login directly (as is the case with transient NT logins)

    IF (@login_name LIKE '%\%')

    BEGIN

    INSERT INTO #work_table

    SELECT database_name, database_user_name

    FROM msdb.dbo.sysjobsteps

    WHERE (database_user_name = @login_name)

    END

    END

    IF ((@login_name IS NULL) AND (@database_name IS NOT NULL) AND (@database_user_name IS NOT NULL))

    BEGIN

    INSERT INTO #work_table

    SELECT @database_name, @database_user_name

    END

    IF (EXISTS (SELECT *

    FROM #work_table wt,

    msdb.dbo.sysjobsteps sjs

    WHERE (wt.database_name = sjs.database_name)

    AND (wt.database_user_name = sjs.database_user_name)))

    BEGIN

    SELECT sjv.job_id,

    sjv.name,

    sjs.step_id,

    sjs.step_name

    FROM #work_table wt,

    msdb.dbo.sysjobsteps sjs,

    msdb.dbo.sysjobs_view sjv

    WHERE (wt.database_name = sjs.database_name)

    AND (wt.database_user_name = sjs.database_user_name)

    AND (sjv.job_id = sjs.job_id)

    ORDER BY sjs.job_id

    END

    RETURN(0) -- 0 means success

    END

    go

    /**************************************************************/

    /* SP_SQLAGENT_REFRESH_JOB */

    /**************************************************************/

    PRINT ''

    PRINT 'Creating procedure sp_sqlagent_refresh_job...'

    go

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = N'sp_sqlagent_refresh_job')

    AND (type = 'P')))

    DROP PROCEDURE sp_sqlagent_refresh_job

    go

    CREATE PROCEDURE sp_sqlagent_refresh_job

    @job_id UNIQUEIDENTIFIER = NULL,

    @server_name NVARCHAR(30) = NULL -- This parameter allows a TSX to use this SP when updating a job

    AS

    BEGIN

    DECLARE @server_id INT

    SET NOCOUNT ON

    IF (@server_name IS NULL) OR (UPPER(@server_name) = '(LOCAL)')

    SELECT @server_name = UPPER(CONVERT(NVARCHAR(30), SERVERPROPERTY('ServerName')))

    SELECT @server_id = server_id

    FROM msdb.dbo.systargetservers_view

    WHERE (server_name = ISNULL(@server_name, UPPER(CONVERT(NVARCHAR(30), SERVERPROPERTY('ServerName')))))

    SELECT @server_id = ISNULL(@server_id, 0)

    SELECT sjv.job_id,

    sjv.name,

    sjv.enabled,

    sjv.start_step_id,

    owner = SUSER_SNAME(sjv.owner_sid),

    sjv.notify_level_eventlog,

    sjv.notify_level_email,

    sjv.notify_level_netsend,

    sjv.notify_level_page,

    sjv.notify_email_operator_id,

    sjv.notify_netsend_operator_id,

    sjv.notify_page_operator_id,

    sjv.delete_level,

    has_step = (SELECT COUNT(*)

    FROM msdb.dbo.sysjobsteps sjst

    WHERE (sjst.job_id = sjv.job_id)),

    sjv.version_number,

    last_run_date = ISNULL(sjs.last_run_date, 0),

    last_run_time = ISNULL(sjs.last_run_time, 0),

    sjv.originating_server,

    sjv.description

    FROM msdb.dbo.sysjobs_view sjv,

    msdb.dbo.sysjobservers sjs

    WHERE ((@job_id IS NULL) OR (@job_id = sjv.job_id))

    AND (sjv.job_id = sjs.job_id)

    AND (sjs.server_id = @server_id)

    ORDER BY sjv.job_id

    RETURN(@@error) -- 0 means success

    END

    go

    /**************************************************************/

    /* SP_JOBHISTORY_ROW_LIMITER */

    /**************************************************************/

    PRINT ''

    PRINT 'Creating procedure sp_jobhistory_row_limiter...'

    go

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = N'sp_jobhistory_row_limiter')

    AND (type = 'P')))

    DROP PROCEDURE dbo.sp_jobhistory_row_limiter

    go

    CREATE PROCEDURE sp_jobhistory_row_limiter

    @job_id UNIQUEIDENTIFIER

    AS

    BEGIN

    DECLARE @max_total_rows INT -- This value comes from the registry (MaxJobHistoryTableRows)

    DECLARE @max_rows_per_job INT -- This value comes from the registry (MaxJobHistoryRows)

    DECLARE @rows_to_delete INT

    DECLARE @rows_to_delete_as_char VARCHAR(10)

    DECLARE @current_rows INT

    DECLARE @current_rows_per_job INT

    DECLARE @job_id_as_char VARCHAR(36)

    SET NOCOUNT ON

    SELECT @job_id_as_char = CONVERT(VARCHAR(36), @job_id)

    -- Get max-job-history-rows from the registry

    EXECUTE master.dbo.xp_instance_regread N'HKEY_LOCAL_MACHINE',

    N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',

    N'JobHistoryMaxRows',

    @max_total_rows OUTPUT,

    N'no_output'

    -- Check if we are limiting sysjobhistory rows

    IF (ISNULL(@max_total_rows, -1) = -1)

    RETURN(0)

    -- Check that max_total_rows is more than 1

    IF (ISNULL(@max_total_rows, 0) < 2)

    BEGIN

    -- It isn't, so set the default to 1000 rows

    SELECT @max_total_rows = 1000

    EXECUTE master.dbo.xp_instance_regwrite N'HKEY_LOCAL_MACHINE',

    N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',

    N'JobHistoryMaxRows',

    N'REG_DWORD',

    @max_total_rows

    END

    -- Get the per-job maximum number of rows to keep

    SELECT @max_rows_per_job = 0

    EXECUTE master.dbo.xp_instance_regread N'HKEY_LOCAL_MACHINE',

    N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',

    N'JobHistoryMaxRowsPerJob',

    @max_rows_per_job OUTPUT,

    N'no_output'

    -- Check that max_rows_per_job is <= max_total_rows

    IF ((@max_rows_per_job > @max_total_rows) OR (@max_rows_per_job < 1))

    BEGIN

    -- It isn't, so default the rows_per_job to max_total_rows

    SELECT @max_rows_per_job = @max_total_rows

    EXECUTE master.dbo.xp_instance_regwrite N'HKEY_LOCAL_MACHINE',

    N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',

    N'JobHistoryMaxRowsPerJob',

    N'REG_DWORD',

    @max_rows_per_job

    END

    BEGIN TRANSACTION

    SELECT @current_rows_per_job = COUNT(*)

    FROM msdb.dbo.sysjobhistory (TABLOCKX)

    WHERE (job_id = @job_id)

    -- Delete the oldest history row(s) for the job being inserted if the new row has

    -- pushed us over the per-job row limit (MaxJobHistoryRows)

    SELECT @rows_to_delete = @current_rows_per_job - @max_rows_per_job

    SELECT @rows_to_delete_as_char = CONVERT(VARCHAR, @rows_to_delete)

    IF (@rows_to_delete > 0)

    BEGIN

    EXECUTE ('DECLARE @new_oldest_id INT

    SET NOCOUNT ON

    SET ROWCOUNT ' + @rows_to_delete_as_char +

    'SELECT @new_oldest_id = instance_id

    FROM msdb.dbo.sysjobhistory

    WHERE (job_id = ''' + @job_id_as_char + ''') ' +

    'ORDER BY instance_id

    SET ROWCOUNT 0

    DELETE FROM msdb.dbo.sysjobhistory

    WHERE (job_id = ''' + @job_id_as_char + ''')' +

    ' AND (instance_id <= @new_oldest_id)')

    END

    -- Delete the oldest history row(s) if inserting the new row has pushed us over the

    -- global MaxJobHistoryTableRows limit.

    SELECT @current_rows = COUNT(*)

    FROM msdb.dbo.sysjobhistory

    SELECT @rows_to_delete = @current_rows - @max_total_rows

    SELECT @rows_to_delete_as_char = CONVERT(VARCHAR, @rows_to_delete)

    IF (@rows_to_delete > 0)

    BEGIN

    EXECUTE ('DECLARE @new_oldest_id INT

    SET NOCOUNT ON

    SET ROWCOUNT ' + @rows_to_delete_as_char +

    'SELECT @new_oldest_id = instance_id

    FROM msdb.dbo.sysjobhistory

    ORDER BY instance_id

    SET ROWCOUNT 0

    DELETE FROM msdb.dbo.sysjobhistory

    WHERE (instance_id <= @new_oldest_id)')

    END

    IF (@@trancount > 0)

    COMMIT TRANSACTION

    RETURN(0) -- Success

    END

    go

    /**************************************************************/

    /* SP_SQLAGENT_LOG_JOBHISTORY */

    /**************************************************************/

    PRINT ''

    PRINT 'Creating procedure sp_sqlagent_log_jobhistory...'

    go

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = N'sp_sqlagent_log_jobhistory')

    AND (type = 'P')))

    DROP PROCEDURE sp_sqlagent_log_jobhistory

    go

    CREATE PROCEDURE sp_sqlagent_log_jobhistory

    @job_id UNIQUEIDENTIFIER,

    @step_id INT,

    @sql_message_id INT = 0,

    @sql_severity INT = 0,

    @message NVARCHAR(1024) = NULL,

    @run_status INT, -- SQLAGENT_EXEC_X code

    @run_date INT,

    @run_time INT,

    @run_duration INT,

    @operator_id_emailed INT = 0,

    @operator_id_netsent INT = 0,

    @operator_id_paged INT = 0,

    @retries_attempted INT,

    @server NVARCHAR(30) = NULL

    AS

    BEGIN

    DECLARE @retval INT

    DECLARE @job_id_as_char VARCHAR(36)

    DECLARE @step_id_as_char VARCHAR(10)

    DECLARE @operator_id_as_char VARCHAR(10)

    DECLARE @step_name sysname

    DECLARE @error_severity INT

    SET NOCOUNT ON

    IF (@server IS NULL) OR (UPPER(@server) = '(LOCAL)')

    SELECT @server = UPPER(CONVERT(NVARCHAR(30), SERVERPROPERTY('ServerName')))

    -- Check authority (only SQLServerAgent can add a history entry for a job)

    EXECUTE @retval = sp_verify_jobproc_caller @job_id = @job_id, @program_name = N'SQLAgent%'

    IF (@retval <> 0)

    RETURN(@retval)

    -- NOTE: We raise all errors as informational (sev 0) to prevent SQLServerAgent from caching

    -- the operation (if it fails) since if the operation will never run successfully we

    -- don't want it to hang around in the operation cache.

    SELECT @error_severity = 0

    -- Check job_id

    IF (NOT EXISTS (SELECT *

    FROM msdb.dbo.sysjobs_view

    WHERE (job_id = @job_id)))

    BEGIN

    SELECT @job_id_as_char = CONVERT(VARCHAR(36), @job_id)

    RAISERROR(14262, @error_severity, -1, 'Job', @job_id_as_char)

    RETURN(1) -- Failure

    END

    -- Check step id

    IF (@step_id <> 0) -- 0 means 'for the whole job'

    BEGIN

    SELECT @step_name = step_name

    FROM msdb.dbo.sysjobsteps

    WHERE (job_id = @job_id)

    AND (step_id = @step_id)

    IF (@step_name IS NULL)

    BEGIN

    SELECT @step_id_as_char = CONVERT(VARCHAR, @step_id)

    RAISERROR(14262, @error_severity, -1, '@step_id', @step_id_as_char)

    RETURN(1) -- Failure

    END

    END

    ELSE

    SELECT @step_name = FORMATMESSAGE(14570)

    -- Check run_status

    IF (@run_status NOT IN (0, 1, 2, 3, 4, 5)) -- SQLAGENT_EXEC_X code

    BEGIN

    RAISERROR(14266, @error_severity, -1, '@run_status', '0, 1, 2, 3, 4, 5')

    RETURN(1) -- Failure

    END

    -- Check run_date

    EXECUTE @retval = sp_verify_job_date @run_date, '@run_date', 10

    IF (@retval <> 0)

    RETURN(1) -- Failure

    -- Check run_time

    EXECUTE @retval = sp_verify_job_time @run_time, '@run_time', 10

    IF (@retval <> 0)

    RETURN(1) -- Failure

    -- Check operator_id_emailed

    IF (@operator_id_emailed <> 0)

    BEGIN

    IF (NOT EXISTS (SELECT *

    FROM msdb.dbo.sysoperators

    WHERE (id = @operator_id_emailed)))

    BEGIN

    SELECT @operator_id_as_char = CONVERT(VARCHAR, @operator_id_emailed)

    RAISERROR(14262, @error_severity, -1, '@operator_id_emailed', @operator_id_as_char)

    RETURN(1) -- Failure

    END

    END

    -- Check operator_id_netsent

    IF (@operator_id_netsent <> 0)

    BEGIN

    IF (NOT EXISTS (SELECT *

    FROM msdb.dbo.sysoperators

    WHERE (id = @operator_id_netsent)))

    BEGIN

    SELECT @operator_id_as_char = CONVERT(VARCHAR, @operator_id_netsent)

    RAISERROR(14262, @error_severity, -1, '@operator_id_netsent', @operator_id_as_char)

    RETURN(1) -- Failure

    END

    END

    -- Check operator_id_paged

    IF (@operator_id_paged <> 0)

    BEGIN

    IF (NOT EXISTS (SELECT *

    FROM msdb.dbo.sysoperators

    WHERE (id = @operator_id_paged)))

    BEGIN

    SELECT @operator_id_as_char = CONVERT(VARCHAR, @operator_id_paged)

    RAISERROR(14262, @error_severity, -1, '@operator_id_paged', @operator_id_as_char)

    RETURN(1) -- Failure

    END

    END

    -- Insert the history row

    INSERT INTO msdb.dbo.sysjobhistory

    (job_id,

    step_id,

    step_name,

    sql_message_id,

    sql_severity,

    message,

    run_status,

    run_date,

    run_time,

    run_duration,

    operator_id_emailed,

    operator_id_netsent,

    operator_id_paged,

    retries_attempted,

    server)

    VALUES (@job_id,

    @step_id,

    @step_name,

    @sql_message_id,

    @sql_severity,

    @message,

    @run_status,

    @run_date,

    @run_time,

    @run_duration,

    @operator_id_emailed,

    @operator_id_netsent,

    @operator_id_paged,

    @retries_attempted,

    @server)

    -- Special handling of replication jobs

    DECLARE @job_name sysname

    DECLARE @category_id int

    SELECT @job_name = name, @category_id = category_id from msdb.dbo.sysjobs

    where job_id = @job_id

    -- If misc. replication job, then update global replication status table

    IF @category_id IN (11, 12, 16, 17, 18)

    BEGIN

    -- Nothing can be done if this fails, so don't worry about the return code

    EXECUTE master.dbo.sp_MSupdate_replication_status

    @publisher = '',

    @publisher_db = '',

    @publication = '',

    @publication_type = -1,

    @agent_type = 5,

    @agent_name = @job_name,

    @status = @run_status

    END

    -- If replicatio agents (snapshot, logreader, distribution, merge, and queuereader

    -- and the step has been canceled and if we are at the distributor.

    IF @category_id in (10,13,14,15,19) and @run_status = 3 and

    object_id('MSdistributiondbs') is not null

    BEGIN

    -- Get the database

    DECLARE @database sysname

    SELECT @database = database_name from sysjobsteps where job_id = @job_id and

    lower(subsystem) in (N'distribution', N'logreader','snapshot',N'merge',

    N'queuereader')

    -- If the database is a distribution database

    IF EXISTS (select * from MSdistributiondbs where name = @database)

    BEGIN

    DECLARE @proc nvarchar(500)

    SELECT @proc = quotename(@database) + N'.dbo.sp_MSlog_agent_cancel'

    EXEC @proc @job_id = @job_id, @category_id = @category_id,

    @message = @message

    END

    END

    -- Delete any history rows that are over the registry-defined limits

    EXECUTE msdb.dbo.sp_jobhistory_row_limiter @job_id

    RETURN(@@error) -- 0 means success

    END

    go

    /**************************************************************/

    /* SP_SQLAGENT_CHECK_MSX_VERSION */

    /**************************************************************/

    PRINT ''

    PRINT 'Creating procedure sp_sqlagent_check_msx_version...'

    go

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = N'sp_sqlagent_check_msx_version')

    AND (type = 'P')))

    DROP PROCEDURE sp_sqlagent_check_msx_version

    go

    CREATE PROCEDURE sp_sqlagent_check_msx_version

    @required_microsoft_version INT = NULL

    AS

    BEGIN

    SET NOCOUNT ON

    DECLARE @msx_version NVARCHAR(16)

    DECLARE @required_msx_version NVARCHAR(16)

    IF (@required_microsoft_version IS NULL)

    SELECT @required_microsoft_version = 0x07000252 -- 7.0.594

    IF (@@microsoftversion < @required_microsoft_version)

    BEGIN

    SELECT @msx_version = CONVERT( NVARCHAR(2), CONVERT( INT, CONVERT( BINARY(1), @@microsoftversion / 0x1000000 ) ) )

    + N'.'

    + CONVERT( NVARCHAR(2), CONVERT( INT, CONVERT( BINARY(1), CONVERT( BINARY(2), ((@@microsoftversion / 0x10000) % 0x100) ) ) ) )

    + N'.'

    + CONVERT( NVARCHAR(4), @@microsoftversion % 0x10000 )

    SELECT @required_msx_version = CONVERT( NVARCHAR(2), CONVERT( INT, CONVERT( BINARY(1), @required_microsoft_version / 0x1000000 ) ) )

    + N'.'

    + CONVERT( NVARCHAR(2), CONVERT( INT, CONVERT( BINARY(1), CONVERT( BINARY(2), ((@required_microsoft_version / 0x10000) % 0x100) ) ) ) )

    + N'.'

    + CONVERT( NVARCHAR(4), @required_microsoft_version % 0x10000 )

    RAISERROR(14541, -1, -1, @msx_version, @required_msx_version)

    RETURN(1) -- Failure

    END

    RETURN(0) -- Success

    END

    go

    /**************************************************************/

    /* SP_SQLAGENT_PROBE_MSX */

    /**************************************************************/

    PRINT ''

    PRINT 'Creating procedure sp_sqlagent_probe_msx...'

    go

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = N'sp_sqlagent_probe_msx')

    AND (type = 'P')))

    DROP PROCEDURE sp_sqlagent_probe_msx

    go

    CREATE PROCEDURE sp_sqlagent_probe_msx

    @server_name NVARCHAR(30), -- The name of the target server probing the MSX

    @local_time NVARCHAR(100), -- The local time at the target server in the format YYYY/MM/DD HH:MM:SS

    @poll_interval INT, -- The frequency (in seconds) with which the target polls the MSX

    @time_zone_adjustment INT = NULL -- The offset from GMT in minutes (may be NULL if unknown)

    AS

    BEGIN

    DECLARE @bad_enlistment BIT

    DECLARE @blocking_instructions INT

    DECLARE @pending_instructions INT

    SET NOCOUNT ON

    SELECT @bad_enlistment = 0, @blocking_instructions = 0, @pending_instructions = 0

    UPDATE msdb.dbo.systargetservers

    SET last_poll_date = GETDATE(),

    local_time_at_last_poll = CONVERT(DATETIME, @local_time, 111),

    poll_interval = @poll_interval,

    time_zone_adjustment = ISNULL(@time_zone_adjustment, time_zone_adjustment)

    WHERE (server_name = @server_name)

    -- If the systargetservers entry is missing (and no DEFECT instruction has been posted)

    -- then the enlistment is bad

    IF (NOT EXISTS (SELECT 1

    FROM msdb.dbo.systargetservers

    WHERE (server_name = @server_name))) AND

    (NOT EXISTS (SELECT 1

    FROM msdb.dbo.sysdownloadlist

    WHERE (target_server = @server_name)

    AND (operation_code = 7)

    AND (object_type = 2)))

    SELECT @bad_enlistment = 1

    SELECT @blocking_instructions = COUNT(*)

    FROM msdb.dbo.sysdownloadlist

    WHERE (target_server = @server_name)

    AND (error_message IS NOT NULL)

    SELECT @pending_instructions = COUNT(*)

    FROM msdb.dbo.sysdownloadlist

    WHERE (target_server = @server_name)

    AND (error_message IS NULL)

    AND (status = 0)

    SELECT @bad_enlistment, @blocking_instructions, @pending_instructions

    END

    go

    /**************************************************************/

    /* SP_SET_LOCAL_TIME */

    /**************************************************************/

    PRINT ''

    PRINT 'Creating procedure sp_set_local_time...'

    go

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = N'sp_set_local_time')

    AND (type = 'P')))

    DROP PROCEDURE sp_set_local_time

    go

    CREATE PROCEDURE sp_set_local_time

    @server_name NVARCHAR(30) = NULL,

    @adjustment_in_minutes INT = 0 -- Only needed for Win9x

    AS

    BEGIN

    DECLARE @ret INT

    DECLARE @local_time INT

    DECLARE @local_date INT

    DECLARE @current_datetime DATETIME

    DECLARE @local_time_sz VARCHAR(30)

    DECLARE @cmd NVARCHAR(200)

    DECLARE @date_format NVARCHAR(64)

    DECLARE @year_sz NVARCHAR(16)

    DECLARE @month_sz NVARCHAR(16)

    DECLARE @day_sz NVARCHAR(16)

    -- Synchronize the clock with the remote server (if supplied)

    -- NOTE: NT takes timezones into account, whereas Win9x does not

    IF (@server_name IS NOT NULL)

    BEGIN

    SELECT @cmd = N'net time \\' + @server_name + N' /set /y'

    EXECUTE @ret = master.dbo.xp_cmdshell @cmd, no_output

    IF (@ret <> 0)

    RETURN(1) -- Failure

    END

    -- Since NET TIME on Win9x does not take time zones into account we need to manually adjust

    -- for this using @adjustment_in_minutes which will be the difference between the MSX GMT

    -- offset and the target server GMT offset

    IF ((PLATFORM() & 0x2) = 0x2) -- Win9x

    BEGIN

    -- Get the date format from the registry (so that we can construct our DATE command-line command)

    EXECUTE master.dbo.xp_regread N'HKEY_CURRENT_USER',

    N'Control Panel\International',

    N'sShortDate',

    @date_format OUTPUT,

    N'no_output'

    SELECT @date_format = LOWER(@date_format)

    IF (@adjustment_in_minutes <> 0)

    BEGIN

    -- Wait for SQLServer to re-cache the OS time

    WAITFOR DELAY '00:01:00'

    SELECT @current_datetime = DATEADD(mi, @adjustment_in_minutes, GETDATE())

    SELECT @local_time_sz = SUBSTRING(CONVERT(VARCHAR, @current_datetime, 8), 1, 5)

    SELECT @local_time = CONVERT(INT, LTRIM(SUBSTRING(@local_time_sz, 1, PATINDEX('%:%', @local_time_sz) - 1) + SUBSTRING(@local_time_sz, PATINDEX('%:%', @local_time_sz) + 1, 2)))

    SELECT @local_date = CONVERT(INT, CONVERT(VARCHAR, @current_datetime, 112))

    -- Set the date

    SELECT @year_sz = CONVERT(NVARCHAR, @local_date / 10000)

    SELECT @month_sz = CONVERT(NVARCHAR, (@local_date % 10000) / 100)

    SELECT @day_sz = CONVERT(NVARCHAR, @local_date % 100)

    IF (@date_format LIKE N'y%m%d')

    SELECT @cmd = N'DATE ' + @year_sz + N'-' + @month_sz + N'-' + @day_sz

    IF (@date_format LIKE N'y%d%m')

    SELECT @cmd = N'DATE ' + @year_sz + N'-' + @day_sz + N'-' + @month_sz

    IF (@date_format LIKE N'm%d%y')

    SELECT @cmd = N'DATE ' + @month_sz + N'-' + @day_sz + N'-' + @year_sz

    IF (@date_format LIKE N'd%m%y')

    SELECT @cmd = N'DATE ' + @day_sz + N'-' + @month_sz + N'-' + @year_sz

    EXECUTE @ret = master.dbo.xp_cmdshell @cmd, no_output

    IF (@ret <> 0)

    RETURN 1 -- Failure

    -- Set the time (NOTE: We can't set the millisecond part of the time, so we may be up to .999 sec off)

    SELECT @cmd = N'TIME ' + CONVERT(NVARCHAR, @local_time / 100) + N':' + CONVERT(NVARCHAR, @local_time % 100) + ':' + CONVERT(NVARCHAR(2), DATEPART(SS, GETDATE()))

    EXECUTE @ret = master.dbo.xp_cmdshell @cmd, no_output

    IF (@ret <> 0)

    RETURN 1 -- Failure

    END

    END

    RETURN(0) -- Success

    END

    go

    /**************************************************************/

    /* SP_MULTI_SERVER_JOB_SUMMARY [used by SEM only] */

    /**************************************************************/

    PRINT ''

    PRINT 'Creating procedure sp_multi_server_job_summary...'

    go

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = N'sp_multi_server_job_summary')

    AND (type = 'P')))

    DROP PROCEDURE sp_multi_server_job_summary

    go

    CREATE PROCEDURE sp_multi_server_job_summary

    @job_id UNIQUEIDENTIFIER = NULL,

    @job_name sysname = NULL

    AS

    BEGIN

    DECLARE @retval INT

    SET NOCOUNT ON

    IF ((@job_id IS NOT NULL) OR (@job_name IS NOT NULL))

    BEGIN

    EXECUTE @retval = sp_verify_job_identifiers '@job_name',

    '@job_id',

    @job_name OUTPUT,

    @job_id OUTPUT

    IF (@retval <> 0)

    RETURN(1) -- Failure

    END

    -- NOTE: We join with syscategories - not sysjobservers - since we want to include jobs

    -- which are of type multi-server but which don't currently have any servers

    SELECT 'job_id' = sj.job_id,

    'job_name' = sj.name,

    'enabled' = sj.enabled,

    'category_name' = sc.name,

    'target_servers' = (SELECT COUNT(*)

    FROM msdb.dbo.sysjobservers sjs

    WHERE (sjs.job_id = sj.job_id)),

    'pending_download_instructions' = (SELECT COUNT(*)

    FROM msdb.dbo.sysdownloadlist sdl

    WHERE (sdl.object_id = sj.job_id)

    AND (status = 0)),

    'download_errors' = (SELECT COUNT(*)

    FROM msdb.dbo.sysdownloadlist sdl

    WHERE (sdl.object_id = sj.job_id)

    AND (sdl.error_message IS NOT NULL)),

    'execution_failures' = (SELECT COUNT(*)

    FROM msdb.dbo.sysjobservers sjs

    WHERE (sjs.job_id = sj.job_id)

    AND (sjs.last_run_date <> 0)

    AND (sjs.last_run_outcome <> 1)) -- 1 is success

    FROM msdb.dbo.sysjobs sj,

    msdb.dbo.syscategories sc

    WHERE (sj.category_id = sc.category_id)

    AND (sc.category_class = 1) -- JOB

    AND (sc.category_type = 2) -- Multi-Server

    AND ((@job_id IS NULL) OR (sj.job_id = @job_id))

    AND ((@job_name IS NULL) OR (sj.name = @job_name))

    RETURN(0) -- Success

    END

    go

    /**************************************************************/

    /* SP_TARGET_SERVER_SUMMARY [used by SEM only] */

    /**************************************************************/

    PRINT ''

    PRINT 'Creating procedure sp_target_server_summary...'

    go

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = N'sp_target_server_summary')

    AND (type = 'P')))

    DROP PROCEDURE sp_target_server_summary

    go

    CREATE PROCEDURE sp_target_server_summary

    @target_server NVARCHAR(30) = NULL

    AS

    BEGIN

    SET NOCOUNT ON

    SELECT server_id,

    server_name,

    'local_time' = DATEADD(SS, DATEDIFF(SS, last_poll_date, GETDATE()), local_time_at_last_poll),

    last_poll_date,

    'unread_instructions' = (SELECT COUNT(*)

    FROM msdb.dbo.sysdownloadlist sdl

    WHERE (sdl.target_server = sts.server_name)

    AND (sdl.status = 0)),

    'blocked' = (SELECT COUNT(*)

    FROM msdb.dbo.sysdownloadlist sdl

    WHERE (sdl.target_server = sts.server_name)

    AND (sdl.error_message IS NOT NULL)),

    poll_interval

    FROM msdb.dbo.systargetservers sts

    WHERE ((@target_server IS NULL) OR (@target_server = sts.server_name))

    END

    go

    DUMP TRANSACTION msdb WITH NO_LOG

    go

    CHECKPOINT

    go

    /**************************************************************/

    /* */

    /* 6 . X P R O C E D U R E S */

    /* */

    /* These procedures are provided for backwards compatability */

    /* with 6.x scripts and 6.x replication. The re-implemented */

    /* procedures are as follows: */

    /* */

    /* - sp_uniquetaskname (SQLDMO) */

    /* - systasks_view (INSTDIST.SQL) */

    /* - sp_addtask (INSTREPL.SQL, INSTDIST.SQL, SQLDMO) */

    /* - sp_updatetask (INSTDIST.SQL) */

    /* - sp_droptask (INSTREPL.SQL, INSTDIST.SQL, SQLDMO) */

    /* - sp_helptask (INSTREPL.SQL, SQLDMO) */

    /* - sp_verifytaskid (INSTREPL.SQL) */

    /* - sp_reassigntask (INSTDIST.SQL) */

    /* - sp_helphistory (For completeness only) */

    /* - sp_purgehistory (For completeness only) */

    /* - systasks (For completeness only) */

    /**************************************************************/

    /**************************************************************/

    /* SYSTASKS (a view to simulate the 6.x systasks table) */

    /**************************************************************/

    PRINT ''

    PRINT 'Creating [legacy] table systasks [as a view]...'

    go

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = N'systasks')

    AND (type = 'U')))

    DROP TABLE systasks -- Just a precaution in case the systasks table is somehow still lingering around

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = N'systasks')

    AND (type = 'V')))

    DROP VIEW systasks

    go

    CREATE VIEW systasks

    AS

    SELECT 'id' = sti.task_id,

    'name' = sj.name,

    'subsystem' = sjst.subsystem,

    'server' = sjst.server,

    'username' = sjst.database_user_name,

    'ownerloginid' = 1, -- Always default to SA since suid is no longer available

    'databasename' = sjst.database_name,

    'enabled' = sj.enabled,

    'freqtype' = ISNULL(sjsch.freq_type, 2), -- On Demand

    'freqinterval' = ISNULL(sjsch.freq_interval, 0),

    'freqsubtype' = ISNULL(sjsch.freq_subday_type, 0),

    'freqsubinterval' = ISNULL(sjsch.freq_subday_interval, 0),

    'freqrelativeinterval' = ISNULL(sjsch.freq_relative_interval, 0),

    'freqrecurrencefactor' = ISNULL(sjsch.freq_recurrence_factor, 0),

    'activestartdate' = ISNULL(sjsch.active_start_date, 19900101),

    'activeenddate' = ISNULL(sjsch.active_end_date, 99991231),

    'activestarttimeofday' = ISNULL(sjsch.active_start_time, 0),

    'activeendtimeofday' = ISNULL(sjsch.active_end_time, 235959),

    'lastrundate' = sjs.last_run_date,

    'lastruntime' = sjs.last_run_time,

    'nextrundate' = ISNULL(sjsch.next_run_date, 0),

    'nextruntime' = ISNULL(sjsch.next_run_time, 0),

    'runpriority' = sjst.os_run_priority,

    'emailoperatorid' = sj.notify_email_operator_id,

    'retryattempts' = sjst.retry_attempts,

    'retrydelay' = sjst.retry_interval,

    'datecreated' = sj.date_created,

    'datemodified' = sj.date_modified,

    'command' = sjst.command,

    'lastruncompletionlevel' = sjs.last_run_outcome,

    'lastrunduration' = sjst.last_run_duration,

    'lastrunretries' = sjst.last_run_retries,

    'loghistcompletionlevel' = sj.notify_level_eventlog,

    'emailcompletionlevel' = sj.notify_level_email,

    'description' = sj.description,

    'tagadditionalinfo' = 0,

    'tagobjectid' = 0,

    'tagobjecttype' = 0,

    'parameters' = CONVERT(TEXT, sjst.additional_parameters),

    'cmdexecsuccesscode' = sjst.cmdexec_success_code

    FROM msdb.dbo.sysjobs sj

    LEFT OUTER JOIN msdb.dbo.sysjobschedules sjsch ON (sj.job_id = sjsch.job_id),

    msdb.dbo.systaskids sti,

    msdb.dbo.sysjobsteps sjst,

    msdb.dbo.sysjobservers sjs

    WHERE (sj.job_id = sti.job_id)

    AND (sj.job_id = sjst.job_id)

    AND (sjst.step_id = 1)

    AND (sj.job_id = sjs.job_id)

    AND (sjs.server_id = 0)

    AND ((sjsch.name = N'6.x schedule') OR (sjsch.name IS NULL)) -- NULL handles the case of the job not having a schedule

    UNION ALL -- NOTE: We do this just to make the view non-updatable

    SELECT 0, '', '', '', '', 0, '', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, GETDATE(), GETDATE(), '', 0, 0, 0, 0, 0, '', 0, 0, 0, '', 0

    WHERE (1 = 2)

    go

    /**************************************************************/

    /* SYSTASKS_VIEW */

    /**************************************************************/

    PRINT ''

    PRINT 'Creating [legacy] view systasks_view...'

    go

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = N'systasks_view')

    AND (type = 'V')))

    DROP VIEW systasks_view

    go

    CREATE VIEW systasks_view

    AS

    SELECT 'id' = sti.task_id,

    'name' = sjv.name,

    'subsystem' = sjst.subsystem,

    'server' = sjst.server,

    'username' = sjst.database_user_name,

    'ownerloginid' = 1, -- Always default to SA since suid is no longer available

    'databasename' = sjst.database_name,

    'enabled' = sjv.enabled,

    'freqtype' = ISNULL(sjsch.freq_type, 2), -- On Demand

    'freqinterval' = ISNULL(sjsch.freq_interval, 0),

    'freqsubtype' = ISNULL(sjsch.freq_subday_type, 0),

    'freqsubinterval' = ISNULL(sjsch.freq_subday_interval, 0),

    'freqrelativeinterval' = ISNULL(sjsch.freq_relative_interval, 0),

    'freqrecurrencefactor' = ISNULL(sjsch.freq_recurrence_factor, 0),

    'activestartdate' = ISNULL(sjsch.active_start_date, 19900101),

    'activeenddate' = ISNULL(sjsch.active_end_date, 99991231),

    'activestarttimeofday' = ISNULL(sjsch.active_start_time, 0),

    'activeendtimeofday' = ISNULL(sjsch.active_end_time, 235959),

    'lastrundate' = sjs.last_run_date,

    'lastruntime' = sjs.last_run_time,

    'nextrundate' = ISNULL(sjsch.next_run_date, 0),

    'nextruntime' = ISNULL(sjsch.next_run_time, 0),

    'runpriority' = sjst.os_run_priority,

    'emailoperatorid' = sjv.notify_email_operator_id,

    'retryattempts' = sjst.retry_attempts,

    'retrydelay' = sjst.retry_interval,

    'datecreated' = sjv.date_created,

    'datemodified' = sjv.date_modified,

    'command' = sjst.command,

    'lastruncompletionlevel' = sjs.last_run_outcome,

    'lastrunduration' = sjst.last_run_duration,

    'lastrunretries' = sjst.last_run_retries,

    'loghistcompletionlevel' = sjv.notify_level_eventlog,

    'emailcompletionlevel' = sjv.notify_level_email,

    'description' = sjv.description,

    'tagadditionalinfo' = 0,

    'tagobjectid' = 0,

    'tagobjecttype' = 0,

    'parameters' = CONVERT(TEXT, sjst.additional_parameters),

    'cmdexecsuccesscode' = sjst.cmdexec_success_code

    FROM msdb.dbo.sysjobs_view sjv

    LEFT OUTER JOIN msdb.dbo.sysjobschedules sjsch ON (sjv.job_id = sjsch.job_id),

    msdb.dbo.systaskids sti,

    msdb.dbo.sysjobsteps sjst,

    msdb.dbo.sysjobservers sjs

    WHERE (sjv.job_id = sti.job_id)

    AND (sjv.job_id = sjst.job_id)

    AND (sjst.step_id = 1)

    AND (sjv.job_id = sjs.job_id)

    AND (sjs.server_id = 0)

    AND ((sjsch.name = N'6.x schedule') OR (sjsch.name IS NULL)) -- NULL handles the case of the job not having a schedule

    UNION ALL -- NOTE: We do this just to make the view non-updatable

    SELECT 0, '', '', '', '', 0, '', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, GETDATE(), GETDATE(), '', 0, 0, 0, 0, 0, '', 0, 0, 0, '', 0

    WHERE (1 = 2)

    go

    /**************************************************************/

    /* SP_UNIQUETASKNAME */

    /**************************************************************/

    PRINT ''

    PRINT 'Creating [legacy] procedure sp_uniquetaskname...'

    go

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = N'sp_uniquetaskname')

    AND (type = 'P')))

    DROP PROCEDURE sp_uniquetaskname

    go

    CREATE PROCEDURE sp_uniquetaskname

    @seed NVARCHAR(92)

    AS

    BEGIN

    DECLARE @newest_suffix INT

    SET NOCOUNT ON

    -- We're going to add a suffix of 8 characters so make sure the seed is at most 84 characters

    SELECT @seed = LTRIM(RTRIM(@seed))

    IF (DATALENGTH(@seed) > 0)

    SELECT @seed = SUBSTRING(@seed, 1, 84)

    -- Find the newest (highest) suffix so far

    SELECT @newest_suffix = MAX(CONVERT(INT, RIGHT(name, 8)))

    FROM msdb.dbo.sysjobs -- DON'T use sysjobs_view here!

    WHERE (name LIKE N'%[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]')

    -- Generate the task name by appending the 'newest suffix' value (plus one) to the seed

    IF (@newest_suffix IS NOT NULL)

    BEGIN

    SELECT @newest_suffix = @newest_suffix + 1

    SELECT 'TaskName' = CONVERT(NVARCHAR(92), @seed + REPLICATE(N'0', 8 - (DATALENGTH(CONVERT(NVARCHAR, @newest_suffix)) / 2)) + CONVERT(NVARCHAR, @newest_suffix))

    END

    ELSE

    SELECT 'TaskName' = CONVERT(NVARCHAR(92), @seed + N'00000001')

    END

    go

    /**************************************************************/

    /* SP_ADDTASK */

    /**************************************************************/

    PRINT ''

    PRINT 'Creating [legacy] procedure sp_addtask...'

    go

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = N'sp_addtask')

    AND (type = 'P')))

    DROP PROCEDURE sp_addtask

    go

    CREATE PROCEDURE sp_addtask

    @name sysname, -- Was VARCHAR(100) in 6.x

    @subsystem NVARCHAR(40) = N'TSQL', -- Was VARCHAR(30) in 6.x

    @server NVARCHAR(30) = NULL,

    @username sysname = NULL, -- Was VARCHAR(30) in 6.x

    @databasename sysname = NULL, -- Was VARCHAR(30) in 6.x

    @enabled TINYINT = 0,

    @freqtype INT = 2, -- 2 means OnDemand

    @freqinterval INT = 1,

    @freqsubtype INT = 1,

    @freqsubinterval INT = 1,

    @freqrelativeinterval INT = 1,

    @freqrecurrencefactor INT = 1,

    @activestartdate INT = 0,

    @activeenddate INT = 0,

    @activestarttimeofday INT = 0,

    @activeendtimeofday INT = 0,

    @nextrundate INT = 0,

    @nextruntime INT = 0,

    @runpriority INT = 0,

    @emailoperatorname sysname = NULL, -- Was VARCHAR(50) in 6.x

    @retryattempts INT = 0,

    @retrydelay INT = 10,

    @command NVARCHAR(3200) = NULL, -- Was VARCHAR(255) in 6.x

    @loghistcompletionlevel INT = 2,

    @emailcompletionlevel INT = 0,

    @description NVARCHAR(512) = NULL, -- Was VARCHAR(255) in 6.x

    @tagadditionalinfo VARCHAR(96) = NULL, -- Obsolete in 7.0

    @tagobjectid INT = NULL, -- Obsolete in 7.0

    @tagobjecttype INT = NULL, -- Obsolete in 7.0

    @newid INT = NULL OUTPUT,

    @parameters NTEXT = NULL, -- Was TEXT in 6.x

    @cmdexecsuccesscode INT = 0,

    @category_name sysname = NULL, -- New for 7.0

    @category_id INT = NULL -- New for 7.0

    AS

    BEGIN

    DECLARE @retval INT

    DECLARE @job_id UNIQUEIDENTIFIER

    DECLARE @id INT

    DECLARE @distdb sysname

    DECLARE @proc nvarchar(255)

    SET NOCOUNT ON

    SELECT @retval = 1 -- 0 means success, 1 means failure

    -- Set 7.0 category names for 6.5 replication tasks

    IF (LOWER(@subsystem) = N'sync')

    SELECT @category_id = 15

    ELSE IF (LOWER(@subsystem) = N'logreader')

    SELECT @category_id = 13

    ELSE IF (LOWER(@subsystem) = N'distribution')

    SELECT @category_id = 10

    -- Convert old replication synchronization subsystem name to the 7.0 name

    IF (LOWER(@subsystem) = N'sync')

    SELECT @subsystem = N'Snapshot'

    -- If a category ID is provided this overrides any supplied category name

    IF (@category_id IS NOT NULL)

    BEGIN

    SELECT @category_name = name

    FROM msdb.dbo.syscategories

    WHERE (category_id = @category_id)

    SELECT @category_name = ISNULL(@category_name, FORMATMESSAGE(14205))

    END

    -- In 6.x active start date was not restricted, but it is in 7.0; so to avoid a "noisey"

    -- failure in sp_add_jobschedule we modify the value accordingly

    IF ((@activestartdate <> 0) AND (@activestartdate < 19900101))

    SELECT @activestartdate = 19900101

    BEGIN TRANSACTION

    -- Add the job

    EXECUTE @retval = sp_add_job

    @job_name = @name,

    @enabled = @enabled,

    @start_step_id = 1,

    @description = @description,

    @category_name = @category_name,

    @notify_level_eventlog = @loghistcompletionlevel,

    @notify_level_email = @emailcompletionlevel,

    @notify_email_operator_name = @emailoperatorname,

    @job_id = @job_id OUTPUT

    IF (@retval <> 0)

    BEGIN

    ROLLBACK TRANSACTION

    GOTO Quit

    END

    -- Add an entry to systaskids for the new job (created by a 6.x client)

    INSERT INTO msdb.dbo.systaskids (job_id) VALUES (@job_id)

    -- Get the assigned task id

    SELECT @id = task_id, @newid = task_id

    FROM msdb.dbo.systaskids

    WHERE (job_id = @job_id)

    -- Add the job step

    EXECUTE @retval = sp_add_jobstep

    @job_id = @job_id,

    @step_id = 1,

    @step_name = N'Step 1',

    @subsystem = @subsystem,

    @command = @command,

    @additional_parameters = @parameters,

    @cmdexec_success_code = @cmdexecsuccesscode,

    @server = @server,

    @database_name = @databasename,

    @database_user_name = @username,

    @retry_attempts = @retryattempts,

    @retry_interval = @retrydelay,

    @os_run_priority = @runpriority

    IF (@retval <> 0)

    BEGIN

    ROLLBACK TRANSACTION

    GOTO Quit

    END

    -- Add the job schedule

    IF (@activestartdate = 0)

    SELECT @activestartdate = NULL

    IF (@activeenddate = 0)

    SELECT @activeenddate = NULL

    IF (@activestarttimeofday = 0)

    SELECT @activestarttimeofday = NULL

    IF (@activeendtimeofday = 0)

    SELECT @activeendtimeofday = NULL

    IF (@freqtype <> 0x2) -- OnDemand tasks simply have no schedule in 7.0

    BEGIN

    EXECUTE @retval = sp_add_jobschedule

    @job_id = @job_id,

    @name = N'6.x schedule',

    @enabled = 1,

    @freq_type = @freqtype,

    @freq_interval = @freqinterval,

    @freq_subday_type = @freqsubtype,

    @freq_subday_interval = @freqsubinterval,

    @freq_relative_interval = @freqrelativeinterval,

    @freq_recurrence_factor = @freqrecurrencefactor,

    @active_start_date = @activestartdate,

    @active_end_date = @activeenddate,

    @active_start_time = @activestarttimeofday,

    @active_end_time = @activeendtimeofday

    IF (@retval <> 0)

    BEGIN

    ROLLBACK TRANSACTION

    GOTO Quit

    END

    END

    -- And finally, add the job server

    EXECUTE @retval = sp_add_jobserver @job_id = @job_id, @server_name = NULL

    IF (@retval <> 0)

    BEGIN

    ROLLBACK TRANSACTION

    GOTO Quit

    END

    -- Add the replication agent for monitoring

    IF (@category_id = 13) -- Logreader

    BEGIN

    SELECT @distdb = distribution_db from MSdistpublishers where name = @server

    SELECT @proc = @distdb + '.dbo.sp_MSadd_logreader_agent'

    EXECUTE @retval = @proc

    @name = @name,

    @publisher = @server,

    @publisher_db = @databasename,

    @publication = '',

    @local_job = 1,

    @job_existing = 1,

    @job_id = @job_id

    IF (@retval <> 0)

    BEGIN

    ROLLBACK TRANSACTION

    GOTO Quit

    END

    END

    ELSE

    IF (@category_id = 15) -- Snapshot

    BEGIN

    DECLARE @publication sysname

    EXECUTE @retval = master.dbo.sp_MSget_publication_from_taskname

    @taskname = @name,

    @publisher = @server,

    @publisherdb = @databasename,

    @publication = @publication OUTPUT

    IF (@publication IS NOT NULL)

    BEGIN

    SELECT @distdb = distribution_db from MSdistpublishers where name = @server

    SELECT @proc = @distdb + '.dbo.sp_MSadd_snapshot_agent'

    EXECUTE @retval = @proc

    @name = @name,

    @publisher = @server,

    @publisher_db = @databasename,

    @publication = @publication,

    @local_job = 1,

    @job_existing = 1,

    @snapshot_jobid = @job_id

    IF (@retval <> 0)

    BEGIN

    ROLLBACK TRANSACTION

    GOTO Quit

    END

    SELECT @proc = @distdb + '.dbo.sp_MSadd_publication'

    EXECUTE @retval = @proc

    @publisher = @server,

    @publisher_db = @databasename,

    @publication = @publication,

    @publication_type = 0 -- Transactional

    IF (@retval <> 0)

    BEGIN

    ROLLBACK TRANSACTION

    GOTO Quit

    END

    END

    END

    COMMIT TRANSACTION

    -- If this is an autostart LogReader or Distribution job, add the [new] '-Continuous' paramter to the command

    IF (@freqtype = 0x40) AND ((UPPER(@subsystem) = N'LOGREADER') OR (UPPER(@subsystem) = N'DISTRIBUTION'))

    BEGIN

    UPDATE msdb.dbo.sysjobsteps

    SET command = command + N' -Continuous'

    WHERE (job_id = @job_id)

    AND (step_id = 1)

    END

    -- If this is an autostart job, start it now (for backwards compatibility with 6.x SQLExecutive behaviour)

    IF (@freqtype = 0x40)

    EXECUTE msdb.dbo.sp_start_job @job_id = @job_id, @error_flag = 0, @output_flag = 0

    Quit:

    RETURN(@retval) -- 0 means success

    END

    go

    /**************************************************************/

    /* SP_UPDATETASK */

    /**************************************************************/

    PRINT ''

    PRINT 'Creating [legacy] procedure sp_updatetask...'

    go

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = N'sp_updatetask')

    AND (type = 'P')))

    DROP PROCEDURE sp_updatetask

    go

    CREATE PROCEDURE sp_updatetask

    @currentname sysname = NULL, -- Was VARCHAR(100) in 6.x

    @id INT = NULL,

    @name sysname = NULL, -- Was VARCHAR(100) in 6.x

    @subsystem NVARCHAR(40) = NULL, -- Was VARCHAR(30) in 6.x

    @server NVARCHAR(30) = NULL, -- Was VARCHAR(30) in 6.x

    @username sysname = NULL, -- Was VARCHAR(30) in 6.x

    @databasename sysname = NULL, -- Was VARCHAR(30) in 6.x

    @enabled TINYINT = NULL,

    @freqtype INT = NULL,

    @freqinterval INT = NULL,

    @freqsubtype INT = NULL,

    @freqsubinterval INT = NULL,

    @freqrelativeinterval INT = NULL,

    @freqrecurrencefactor INT = NULL,

    @activestartdate INT = NULL,

    @activeenddate INT = NULL,

    @activestarttimeofday INT = NULL,

    @activeendtimeofday INT = NULL,

    @nextrundate INT = NULL,

    @nextruntime INT = NULL,

    @runpriority INT = NULL,

    @emailoperatorname sysname = NULL, -- Was VARCHAR(50) in 6.x

    @retryattempts INT = NULL,

    @retrydelay INT = NULL,

    @command NVARCHAR(3200) = NULL,

    @loghistcompletionlevel INT = NULL,

    @emailcompletionlevel INT = NULL,

    @description VARCHAR(512) = NULL,

    @tagadditionalinfo VARCHAR(96) = NULL, -- Obsolete in 7.0

    @tagobjectid INT = NULL, -- Obsolete in 7.0

    @tagobjecttype INT = NULL, -- Obsolete in 7.0

    @parameters TEXT = NULL,

    @cmdexecsuccesscode INT = NULL

    AS

    BEGIN

    DECLARE @retval INT

    DECLARE @job_id UNIQUEIDENTIFIER

    SET NOCOUNT ON

    SELECT @retval = 1 -- 0 means success, 1 means failure

    -- Convert old replication synchronization subsystem name to the 7.0 name

    IF (LOWER(@subsystem) = N'sync')

    SELECT @subsystem = N'Snapshot'

    IF ((@id IS NULL) AND (@currentname IS NULL)) OR

    ((@id IS NOT NULL) AND (@currentname IS NOT NULL))

    BEGIN

    RAISERROR(14246, -1, -1)

    RETURN(1) -- Failure

    END

    -- In 6.x active start date was not restricted, but it is in 7.0; so to avoid a "noisey"

    -- failure in sp_update_jobschedule we modify the value accordingly

    IF ((@activestartdate IS NOT NULL) AND (@activestartdate < 19900101))

    SELECT @activestartdate = 19900101

    -- If the name is supplied, get the job_id directly from sysjobs

    IF (@currentname IS NOT NULL)

    BEGIN

    -- Check if the name is ambiguous

    IF ((SELECT COUNT(*)

    FROM msdb.dbo.sysjobs_view

    WHERE (name = @currentname)) > 1)

    BEGIN

    RAISERROR(14292, -1, -1, @currentname, '@id', '@currentname')

    RETURN(1) -- Failure

    END

    SELECT @job_id = job_id

    FROM msdb.dbo.sysjobs_view

    WHERE (name = @currentname)

    SELECT @id = task_id

    FROM msdb.dbo.systaskids

    WHERE (job_id = @job_id)

    IF (@job_id IS NULL)

    BEGIN

    RAISERROR(14262, -1, -1, '@currentname', @currentname)

    RETURN(1) -- Failure

    END

    END

    -- If the id is supplied lookup the corresponding job_id from systaskids

    IF (@id IS NOT NULL)

    BEGIN

    SELECT @job_id = job_id

    FROM msdb.dbo.systaskids

    WHERE (task_id = @id)

    -- Check that the job still exists

    IF (NOT EXISTS (SELECT *

    FROM msdb.dbo.sysjobs_view

    WHERE (job_id = @job_id)))

    BEGIN

    SELECT @currentname = CONVERT(NVARCHAR, @id)

    RAISERROR(14262, -1, -1, '@id', @currentname)

    RETURN(1) -- Failure

    END

    END

    -- Do the update

    BEGIN TRANSACTION

    -- Update the Job Step

    IF (@subsystem IS NOT NULL) OR

    (@command IS NOT NULL) OR

    (@cmdexecsuccesscode IS NOT NULL) OR

    (@server IS NOT NULL) OR

    (@databasename IS NOT NULL) OR

    (@username IS NOT NULL) OR

    (@retryattempts IS NOT NULL) OR

    (@retrydelay IS NOT NULL) OR

    (@runpriority IS NOT NULL)

    BEGIN

    EXECUTE @retval = sp_update_jobstep

    @job_id = @job_id,

    @step_id = 1,

    @subsystem = @subsystem,

    @command = @command,

    @cmdexec_success_code = @cmdexecsuccesscode,

    @server = @server,

    @database_name = @databasename,

    @database_user_name = @username,

    @retry_attempts = @retryattempts,

    @retry_interval = @retrydelay,

    @os_run_priority = @runpriority

    IF (@retval <> 0)

    BEGIN

    ROLLBACK TRANSACTION

    GOTO Quit

    END

    END

    -- Now update the job itself

    IF (@name IS NOT NULL) OR

    (@enabled IS NOT NULL) OR

    (@description IS NOT NULL) OR

    (@loghistcompletionlevel IS NOT NULL) OR

    (@emailcompletionlevel IS NOT NULL) OR

    (@emailoperatorname IS NOT NULL)

    BEGIN

    EXECUTE @retval = sp_update_job

    @job_id = @job_id,

    @new_name = @name,

    @enabled = @enabled,

    @description = @description,

    @notify_level_eventlog = @loghistcompletionlevel,

    @notify_level_email = @emailcompletionlevel,

    @notify_email_operator_name = @emailoperatorname

    IF (@retval <> 0)

    BEGIN

    ROLLBACK TRANSACTION

    GOTO Quit

    END

    END

    -- Finally, update the job schedule

    IF (@freqtype IS NOT NULL) OR

    (@freqinterval IS NOT NULL) OR

    (@freqsubtype IS NOT NULL) OR

    (@freqsubinterval IS NOT NULL) OR

    (@freqrelativeinterval IS NOT NULL) OR

    (@freqrecurrencefactor IS NOT NULL) OR

    (@activestartdate IS NOT NULL) OR

    (@activeenddate IS NOT NULL) OR

    (@activestarttimeofday IS NOT NULL) OR

    (@activeendtimeofday IS NOT NULL)

    BEGIN

    IF (@freqtype = 0x2)

    BEGIN

    -- OnDemand tasks simply have no schedule in 7.0, so delete the job schedule

    EXECUTE @retval = sp_delete_jobschedule

    @job_id = @job_id,

    @name = N'6.x schedule'

    END

    ELSE

    BEGIN

    IF (NOT EXISTS (SELECT *

    FROM msdb.dbo.sysjobschedules

    WHERE (job_id = @job_id)

    AND (name = N'6.x schedule')))

    EXECUTE @retval = sp_add_jobschedule

    @job_id = @job_id,

    @name = N'6.x schedule',

    @enabled = 1,

    @freq_type = @freqtype,

    @freq_interval = @freqinterval,

    @freq_subday_type = @freqsubtype,

    @freq_subday_interval = @freqsubinterval,

    @freq_relative_interval = @freqrelativeinterval,

    @freq_recurrence_factor = @freqrecurrencefactor,

    @active_start_date = @activestartdate,

    @active_end_date = @activeenddate,

    @active_start_time = @activestarttimeofday,

    @active_end_time = @activeendtimeofday

    ELSE

    EXECUTE @retval = sp_update_jobschedule

    @job_id = @job_id,

    @name = N'6.x schedule',

    @enabled = 1,

    @freq_type = @freqtype,

    @freq_interval = @freqinterval,

    @freq_subday_type = @freqsubtype,

    @freq_subday_interval = @freqsubinterval,

    @freq_relative_interval = @freqrelativeinterval,

    @freq_recurrence_factor = @freqrecurrencefactor,

    @active_start_date = @activestartdate,

    @active_end_date = @activeenddate,

    @active_start_time = @activestarttimeofday,

    @active_end_time = @activeendtimeofday

    END

    IF (@retval <> 0)

    BEGIN

    ROLLBACK TRANSACTION

    GOTO Quit

    END

    END

    COMMIT TRANSACTION

    Quit:

    RETURN(@retval) -- 0 means success

    END

    go

    /**************************************************************/

    /* SP_DROPTASK */

    /**************************************************************/

    PRINT ''

    PRINT 'Creating [legacy] procedure sp_droptask...'

    go

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = N'sp_droptask')

    AND (type = 'P')))

    DROP PROCEDURE sp_droptask

    go

    CREATE PROCEDURE sp_droptask

    @name sysname = NULL, -- Was VARCHAR(100) in 6.x

    @loginname sysname = NULL, -- Was VARCHAR(30) in 6.x

    @id INT = NULL

    AS

    BEGIN

    DECLARE @retval INT

    DECLARE @job_id UNIQUEIDENTIFIER

    DECLARE @category_id int

    SET NOCOUNT ON

    IF ((@name IS NULL) AND (@id IS NULL) AND (@loginname IS NULL)) OR

    ((@name IS NOT NULL) AND ((@id IS NOT NULL) OR (@loginname IS NOT NULL))) OR

    ((@id IS NOT NULL) AND ((@name IS NOT NULL) OR (@loginname IS NOT NULL))) OR

    ((@loginname IS NOT NULL) AND ((@name IS NOT NULL) OR (@id IS NOT NULL)))

    BEGIN

    RAISERROR(14245, -1, -1)

    RETURN(1) -- Failure

    END

    -- If the name is supplied, get the job_id directly from sysjobs

    IF (@name IS NOT NULL)

    BEGIN

    -- Check if the name is ambiguous

    IF ((SELECT COUNT(*)

    FROM msdb.dbo.sysjobs_view

    WHERE (name = @name)) > 1)

    BEGIN

    RAISERROR(14292, -1, -1, @name, '@id', '@name')

    RETURN(1) -- Failure

    END

    SELECT @job_id = job_id, @category_id = category_id

    FROM msdb.dbo.sysjobs_view

    WHERE (name = @name)

    SELECT @id = task_id

    FROM msdb.dbo.systaskids

    WHERE (job_id = @job_id)

    IF (@job_id IS NULL)

    BEGIN

    RAISERROR(14262, -1, -1, '@name', @name)

    RETURN(1) -- Failure

    END

    END

    -- If the id is supplied lookup the corresponding job_id from systaskids

    IF (@id IS NOT NULL)

    BEGIN

    SELECT @job_id = job_id

    FROM msdb.dbo.systaskids

    WHERE (task_id = @id)

    -- Check that the job still exists

    IF (NOT EXISTS (SELECT *

    FROM msdb.dbo.sysjobs_view

    WHERE (job_id = @job_id)))

    BEGIN

    SELECT @name = CONVERT(NVARCHAR, @id)

    RAISERROR(14262, -1, -1, '@id', @name)

    RETURN(1) -- Failure

    END

    -- Get the name of this job

    SELECT @name = name, @category_id = category_id

    FROM msdb.dbo.sysjobs_view

    WHERE (job_id = @job_id)

    END

    -- Delete the specific job

    IF (@name IS NOT NULL)

    BEGIN

    BEGIN TRANSACTION

    DELETE FROM msdb.dbo.systaskids

    WHERE (job_id = @job_id)

    EXECUTE @retval = sp_delete_job @job_id = @job_id

    IF (@retval <> 0)

    BEGIN

    ROLLBACK TRANSACTION

    GOTO Quit

    END

    -- If a Logreader or Snapshot task, delete corresponding replication agent information

    IF @category_id = 13 or @category_id = 15

    BEGIN

    EXECUTE @retval = sp_MSdrop_6x_replication_agent @job_id, @category_id

    IF (@retval <> 0)

    BEGIN

    ROLLBACK TRANSACTION

    GOTO Quit

    END

    END

    COMMIT TRANSACTION

    END

    -- Delete all jobs belonging to the specified login

    IF (@loginname IS NOT NULL)

    BEGIN

    BEGIN TRANSACTION

    DELETE FROM msdb.dbo.systaskids

    WHERE job_id IN (SELECT job_id

    FROM msdb.dbo.sysjobs_view

    WHERE (owner_sid = SUSER_SID(@loginname)))

    EXECUTE @retval = sp_manage_jobs_by_login @action = 'DELETE',

    @current_owner_login_name = @loginname

    IF (@retval <> 0)

    BEGIN

    ROLLBACK TRANSACTION

    GOTO Quit

    END

    COMMIT TRANSACTION

    END

    Quit:

    RETURN(@retval) -- 0 means success

    END

    go

    /**************************************************************/

    /* SP_HELPTASK */

    /**************************************************************/

    PRINT ''

    PRINT 'Creating [legacy] procedure procedure sp_helptask...'

    go

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = N'sp_helptask')

    AND (type = 'P')))

    DROP PROCEDURE sp_helptask

    go

    CREATE PROCEDURE sp_helptask

    @taskname sysname = NULL, -- Was VARCHAR(100) in 6.x

    @taskid INT = NULL,

    @loginname sysname = NULL, -- Was VARCHAR(20) in 6.x

    @operatorname sysname = NULL, -- Was VARCHAR(50) in 6.x

    @subsystem NVARCHAR(40) = NULL, -- Was VARCHAR(30) in 6.x

    @mode VARCHAR(10) = 'QUICK' -- Or 'FULL'

    AS

    BEGIN

    DECLARE @operator_id INT

    DECLARE @owner_sid VARBINARY(85)

    SET NOCOUNT ON

    -- Convert old replication synchronization subsystem name to the 7.0 name

    IF (LOWER(@subsystem) = N'sync')

    SELECT @subsystem = N'Snapshot'

    -- Get the login id for the login name (if supplied)

    IF (@loginname IS NOT NULL)

    BEGIN

    IF (ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) = 0) AND (SUSER_SNAME() <> @loginname)

    BEGIN

    RAISERROR(14247, -1, -1)

    RETURN(1) -- Failure

    END

    SELECT @owner_sid = SUSER_ID(@loginname)

    IF (@owner_sid IS NULL)

    BEGIN

    RAISERROR(14234, -1, -1, '@loginname', 'sp_helplogins')

    RETURN(1) -- Failure

    END

    END

    -- Get the operator id for the operator name (if supplied)

    IF (@operatorname IS NOT NULL)

    BEGIN

    SELECT @operator_id = id

    FROM msdb.dbo.sysoperators

    WHERE (name = @operatorname)

    IF (@operator_id IS NULL)

    BEGIN

    RAISERROR(14262, -1, -1, '@operatorname', @operatorname)

    RETURN(1) -- Failure

    END

    END

    -- Check the mode

    SELECT @mode = UPPER(@mode)

    IF (@mode NOT IN ('FULL', 'QUICK'))

    BEGIN

    RAISERROR(14266, -1, -1, '@mode', 'FULL, QUICK')

    RETURN(1) -- Failure

    END

    -- Return task details...

    -- NOTE: SQLOLE and Starfighter rely on the 'FULL' mode format - do not change it!

    IF (@mode = 'FULL')

    BEGIN

    SELECT name = sjv.name,

    id = sti.task_id,

    subsystem = sjst.subsystem,

    server = sjst.server,

    username = sjst.database_user_name,

    ownerloginname = SUSER_SNAME(sjv.owner_sid),

    databasename = sjst.database_name,

    enabled = sjv.enabled,

    freqtype = ISNULL(sjsch.freq_type, 2), -- On Demand

    freqinterval = ISNULL(sjsch.freq_interval, 0),

    freqsubtype = ISNULL(sjsch.freq_subday_type, 0),

    freqsubinterval = ISNULL(sjsch.freq_subday_interval, 0),

    freqrelativeinterval = ISNULL(sjsch.freq_relative_interval, 0),

    freqrecurrencefactor = ISNULL(sjsch.freq_recurrence_factor, 0),

    activestartdate = ISNULL(sjsch.active_start_date, 19900101),

    activeenddate = ISNULL(sjsch.active_end_date, 99991231),

    activestarttimeofday = ISNULL(sjsch.active_start_time, 0),

    activeendtimeofday = ISNULL(sjsch.active_end_time, 235959),

    lastrundate = sjs.last_run_date,

    lastruntime = sjs.last_run_time,

    nextrundate = ISNULL(sjsch.next_run_date, 0),

    nextruntime = ISNULL(sjsch.next_run_time, 0),

    runpriority = sjst.os_run_priority,

    emailoperatorname = so.name,

    retryattempts = sjst.retry_attempts,

    retrydelay = sjst.retry_interval,

    datecreated = sjv.date_created,

    datemodified = sjv.date_modified,

    command = sjst.command,

    lastruncompletionlevel = sjs.last_run_outcome,

    lastrunduration = sjst.last_run_duration,

    lastrunretries = sjst.last_run_retries,

    loghistcompletionlevel = sjv.notify_level_eventlog,

    emailcompletionlevel = sjv.notify_level_email,

    description = sjv.description,

    tagadditionalinfo = 0,

    tagobjectid = 0,

    tagobjecttype = 0,

    cmdexecsuccesscode = sjst.cmdexec_success_code

    FROM msdb.dbo.sysjobs_view sjv

    LEFT OUTER JOIN msdb.dbo.sysoperators so ON (sjv.notify_email_operator_id = so.id)

    LEFT OUTER JOIN msdb.dbo.systaskids sti ON (sjv.job_id = sti.job_id)

    LEFT OUTER JOIN msdb.dbo.sysjobschedules sjsch ON (sjv.job_id = sjsch.job_id),

    msdb.dbo.sysjobsteps sjst,

    msdb.dbo.sysjobservers sjs

    WHERE (sjv.job_id = sjst.job_id)

    AND (sjst.step_id = 1)

    AND (sjv.job_id = sjs.job_id)

    AND (sjs.server_id = 0)

    AND ((sjsch.name = N'6.x schedule') OR (sjsch.name IS NULL)) -- NULL handles the case of the job not having a schedule

    AND ((@owner_sid IS NULL) OR (sjv.owner_sid = @owner_sid))

    AND ((@subsystem IS NULL) OR (sjst.subsystem = @subsystem))

    AND ((@operator_id IS NULL) OR (sjv.notify_email_operator_id = @operator_id))

    AND ((@taskname IS NULL) OR (sjv.name = @taskname))

    AND ((@taskid IS NULL) OR (sti.task_id = @taskid))

    ORDER BY sj.name

    END

    ELSE

    BEGIN

    SELECT name = SUBSTRING(sjv.name, 1, 20),

    id = sti.task_id,

    subsystem = SUBSTRING(sjst.subsystem, 1, 15),

    server = SUBSTRING(sjst.server, 1, 20),

    username = SUBSTRING(sjst.database_user_name, 1, 20),

    dbname = SUBSTRING(sjst.database_name, 1, 20),

    enabled = sjv.enabled

    FROM msdb.dbo.sysjobs_view sjv

    LEFT OUTER JOIN msdb.dbo.systaskids sti ON (sjv.job_id = sti.job_id),

    msdb.dbo.sysjobsteps sjst

    WHERE (sjv.job_id = sjst.job_id)

    AND (sjst.step_id = 1)

    AND ((@owner_sid IS NULL) OR (sjv.owner_sid = @owner_sid))

    AND ((@subsystem IS NULL) OR (sjst.subsystem = @subsystem))

    AND ((@operator_id IS NULL) OR (sjv.notify_email_operator_id = @operator_id))

    AND ((@taskname IS NULL) OR (sjv.name = @taskname))

    AND ((@taskid IS NULL) OR (sti.task_id = @taskid))

    ORDER BY sjv.name

    END

    END

    go

    DUMP TRANSACTION msdb WITH NO_LOG

    go

    CHECKPOINT

    go

    /**************************************************************/

    /* SP_VERIFYTASKID */

    /**************************************************************/

    PRINT ''

    PRINT 'Creating [legacy] procedure procedure sp_verifytaskid...'

    go

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = N'sp_verifytaskid')

    AND (type = 'P')))

    DROP PROCEDURE sp_verifytaskid

    go

    CREATE PROCEDURE sp_verifytaskid

    @taskid INT,

    @subsystem NVARCHAR(40) = N'%'

    AS

    BEGIN

    SET NOCOUNT ON

    -- Convert old replication synchronization subsystem name to the 7.0 name

    IF (LOWER(@subsystem) = N'sync')

    SELECT @subsystem = N'Snapshot'

    -- Check if the task [job] exists

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysjobs_view sjv,

    msdb.dbo.sysjobsteps sjst,

    msdb.dbo.systaskids sti

    WHERE (sjv.job_id = sjst.job_id)

    AND (sjv.job_id = sti.job_id)

    AND (sti.task_id = @taskid)

    AND (LOWER(sjst.subsystem) LIKE LOWER(@subsystem))))

    RETURN(0) -- Success

    ELSE

    RETURN(1) -- Failure

    END

    go

    /**************************************************************/

    /* SP_REASSIGNTASK */

    /**************************************************************/

    PRINT ''

    PRINT 'Creating [legacy] procedure sp_reassigntask...'

    go

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = N'sp_reassigntask')

    AND (type = 'P')))

    DROP PROCEDURE sp_reassigntask

    go

    CREATE PROCEDURE sp_reassigntask

    @taskname sysname = NULL, -- Was VARCHAR(100) in 6.x

    @newloginname sysname, -- Was VARCHAR(30) in 6.x

    @oldloginname sysname = NULL -- Was VARCHAR(30) in 6.x

    AS

    BEGIN

    DECLARE @retval INT

    SET NOCOUNT ON

    IF (ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) <> 1)

    BEGIN

    RAISERROR(14244, -1, -1)

    RETURN(1) -- Failure

    END

    -- Check that we have either task or old login name (or both, though it's redundant)

    IF ((@taskname IS NULL) AND (@oldloginname IS NULL))

    BEGIN

    RAISERROR(14249, -1, -1)

    RETURN(1) -- Failure

    END

    -- Case [1]: Reassign a specific task [job]...

    IF (@taskname IS NOT NULL)

    BEGIN

    -- Check new login id

    IF (SUSER_ID(@newloginname) IS NULL)

    BEGIN

    RAISERROR(14262, -1, -1, '@newloginname', @newloginname)

    RETURN(1) -- Failure

    END

    -- NOTE: Normally we'd invoke sp_update_job by supplying the job_id, but since this is

    -- a legacy procedure we cannot change the parameter list to have the job_id

    -- supplied to us. Hence we use name and we run the risk of a [handled] error

    -- if the task [job] name is not unique.

    EXECUTE @retval = sp_update_job @job_name = @taskname, @owner_login_name = @newloginname

    RETURN(@retval) -- 0 means success

    END

    -- Case [2]: Reassign all jobs belonging to the specified old login name...

    IF (@oldloginname IS NOT NULL)

    BEGIN

    EXECUTE @retval = sp_manage_jobs_by_login @action = 'REASSIGN',

    @current_owner_login_name = @oldloginname,

    @new_owner_login_name = @newloginname

    RETURN(@retval) -- 0 means success

    END

    END

    go

    /**************************************************************/

    /* SP_HELPHISTORY (Replication doesn't need this - It is here */

    /* for completeness only) */

    /**************************************************************/

    PRINT ''

    PRINT 'Creating [legacy] procedure sp_helphistory...'

    go

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = N'sp_helphistory')

    AND (type = 'P')))

    DROP PROCEDURE sp_helphistory

    go

    CREATE PROCEDURE sp_helphistory

    @taskname sysname = NULL, -- Was VARCHAR(100) in 6.x

    @taskid INT = NULL,

    @eventid INT = NULL,

    @messageid INT = NULL,

    @severity INT = NULL,

    @source VARCHAR(30) = NULL, -- Obsolete in 7.0

    @category VARCHAR(30) = NULL, -- Obsolete in 7.0

    @startdate INT = NULL, -- YYYYMMDD format

    @enddate INT = NULL, -- YYYYMMDD format

    @starttime INT = NULL, -- HHMMSS format

    @endtime INT = NULL, -- HHMMSS format

    @minimumtimesskipped INT = NULL,

    @minimumrunduration INT = NULL, -- HHMMSS format

    @runstatusmask INT = NULL, -- SQLOLE_COMPLETION_STATUS

    @minimumretries INT = NULL,

    @oldestfirst INT = NULL,

    @mode VARCHAR(10) = 'QUICK' -- Or FULL

    AS

    BEGIN

    DECLARE @job_id UNIQUEIDENTIFIER

    DECLARE @order_by INT

    SET NOCOUNT ON

    -- If the name is supplied, get the job_id directly from sysjobs

    IF (@taskname IS NOT NULL)

    BEGIN

    SELECT @job_id = job_id

    FROM msdb.dbo.sysjobs_view

    WHERE (name = @taskname)

    -- Check if the name is ambiguous

    IF (@@rowcount > 1)

    BEGIN

    RAISERROR(14292, -1, -1, @taskname, '@taskid', '@taskname')

    RETURN(1) -- Failure

    END

    IF (@job_id IS NULL)

    BEGIN

    RAISERROR(14262, -1, -1, '@taskname', @taskname)

    RETURN(1) -- Failure

    END

    END

    -- If the id is supplied lookup the corresponding job_id from systaskids

    IF (@taskid IS NOT NULL)

    BEGIN

    SELECT @job_id = job_id

    FROM msdb.dbo.systaskids

    WHERE (task_id = @taskid)

    -- Check that the job still exists

    IF (NOT EXISTS (SELECT *

    FROM msdb.dbo.sysjobs_view

    WHERE (job_id = @job_id)))

    BEGIN

    SELECT @taskname = CONVERT(NVARCHAR, @taskid)

    RAISERROR(14262, -1, -1, '@taskid', @taskname)

    RETURN(1) -- Failure

    END

    END

    SELECT @mode = UPPER(@mode)

    IF (@mode = 'QUICK')

    SELECT @mode = 'SUMMARY'

    CREATE TABLE #task_history_full

    (

    instance_id INT NOT NULL,

    job_id UNIQUEIDENTIFIER NOT NULL,

    job_name sysname COLLATE database_default NOT NULL,

    step_id INT NOT NULL,

    step_name sysname COLLATE database_default NOT NULL,

    sql_message_id INT NOT NULL,

    sql_severity INT NOT NULL,

    message NVARCHAR(1024) COLLATE database_default NULL,

    run_status INT NOT NULL,

    run_date INT NOT NULL,

    run_time INT NOT NULL,

    run_duration INT NOT NULL,

    operator_emailed sysname COLLATE database_default NULL,

    operator_netsent sysname COLLATE database_default NULL,

    operator_paged sysname COLLATE database_default NULL,

    retries_attempted INT NOT NULL,

    server NVARCHAR(30) COLLATE database_default NOT NULL

    )

    CREATE TABLE #task_history_quick

    (

    job_id UNIQUEIDENTIFIER NOT NULL,

    job_name sysname COLLATE database_default NOT NULL,

    run_status INT NOT NULL,

    run_date INT NOT NULL,

    run_time INT NOT NULL,

    run_duration INT NOT NULL,

    operator_emailed sysname COLLATE database_default NULL,

    operator_netsent sysname COLLATE database_default NULL,

    operator_paged sysname COLLATE database_default NULL,

    retries_attempted INT NOT NULL,

    server NVARCHAR(30) COLLATE database_default NOT NULL

    )

    IF (@mode = 'FULL')

    BEGIN

    INSERT INTO #task_history_full

    EXECUTE msdb.dbo.sp_help_jobhistory @job_id = @job_id,

    @sql_message_id = @messageid,

    @sql_severity = @severity,

    @start_run_date = @startdate,

    @end_run_date = @enddate,

    @start_run_time = @starttime,

    @end_run_time = @endtime,

    @minimum_run_duration = @minimumrunduration,

    @run_status = @runstatusmask,

    @minimum_retries = @minimumretries,

    @oldest_first = @oldestfirst,

    @mode = @mode

    END

    ELSE

    BEGIN

    INSERT INTO #task_history_quick

    EXECUTE msdb.dbo.sp_help_jobhistory @job_id = @job_id,

    @sql_message_id = @messageid,

    @sql_severity = @severity,

    @start_run_date = @startdate,

    @end_run_date = @enddate,

    @start_run_time = @starttime,

    @end_run_time = @endtime,

    @minimum_run_duration = @minimumrunduration,

    @run_status = @runstatusmask,

    @minimum_retries = @minimumretries,

    @oldest_first = @oldestfirst,

    @mode = @mode

    END

    IF (@mode = 'FULL')

    BEGIN

    SELECT id = sti.task_id,

    eventid = 0,

    messageid = sql_message_id,

    severity = sql_severity,

    taskname = job_name,

    source = '',

    category = '',

    runstatus = run_status,

    rundate = run_date,

    runtime = run_time,

    runduration = run_duration,

    reviewstatus = 0,

    emailoperatorname = operator_emailed,

    retries = retries_attempted,

    comments = message,

    timesskipped = 0

    FROM #task_history_full thf,

    systaskids sti

    WHERE (thf.job_id = sti.job_id)

    END

    ELSE

    BEGIN

    SELECT taskname = job_name,

    source = '',

    runstatus = run_status,

    rundate = run_date,

    runtime = run_time,

    runduration = run_duration,

    emailoperatorname = operator_emailed,

    retries = retries_attempted

    FROM #task_history_quick

    END

    END

    go

    /**************************************************************/

    /* SP_PURGEHISTORY (Replication doesn't need this - It is */

    /* here for completeness only) */

    /**************************************************************/

    PRINT ''

    PRINT 'Creating [legacy] procedure sp_purgehistory...'

    go

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = N'sp_purgehistory')

    AND (type = 'P')))

    DROP PROCEDURE sp_purgehistory

    go

    CREATE PROCEDURE sp_purgehistory

    @taskname sysname = NULL, -- Was VARCHAR(100) in 6.x

    @taskid INT = NULL

    AS

    BEGIN

    DECLARE @job_id UNIQUEIDENTIFIER

    SET NOCOUNT ON

    -- If the name is supplied, get the job_id directly from sysjobs

    IF (@taskname IS NOT NULL)

    BEGIN

    SELECT @job_id = job_id

    FROM msdb.dbo.sysjobs_view

    WHERE (name = @taskname)

    -- Check if the name is ambiguous

    IF (@@rowcount > 1)

    BEGIN

    RAISERROR(14292, -1, -1, @taskname, '@taskid', '@taskname')

    RETURN(1) -- Failure

    END

    IF (@job_id IS NULL)

    BEGIN

    RAISERROR(14262, -1, -1, '@taskname', @taskname)

    RETURN(1) -- Failure

    END

    END

    -- If the id is supplied lookup the corresponding job_id from systaskids

    IF (@taskid IS NOT NULL)

    BEGIN

    SELECT @job_id = job_id

    FROM msdb.dbo.systaskids

    WHERE (task_id = @taskid)

    -- Check that the job still exists

    IF (NOT EXISTS (SELECT *

    FROM msdb.dbo.sysjobs_view

    WHERE (job_id = @job_id)))

    BEGIN

    SELECT @taskname = CONVERT(NVARCHAR, @taskid)

    RAISERROR(14262, -1, -1, '@taskid', @taskname)

    RETURN(1) -- Failure

    END

    END

    EXECUTE sp_purge_jobhistory @job_id = @job_id

    END

    go

    /**************************************************************/

    /* */

    /* E R R O R M E S S A G E S */

    /* */

    /* These are now created by MESSAGES.SQL. */

    /* */

    /* NOTE: 14255 and 14265 are called by dynamic SQL generated */

    /* by SQLServerAgent. */

    /**************************************************************/

    /**************************************************************/

    /* */

    /* T R I G G E R S */

    /* */

    /**************************************************************/

    /**************************************************************/

    /* TRIG_TARGETSERVER_INSERT */

    /**************************************************************/

    PRINT ''

    PRINT 'Creating trigger trig_targetserver_insert...'

    go

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = N'trig_targetserver_insert')

    AND (type = 'TR')))

    DROP TRIGGER dbo.trig_targetserver_insert

    go

    CREATE TRIGGER trig_targetserver_insert

    ON msdb.dbo.systargetservers

    FOR INSERT, DELETE

    AS

    BEGIN

    SET NOCOUNT ON

    -- Disallow the insert if the server is called 'ALL'

    -- NOTE: We have to do this check here in the trigger since there is no sp_add_targetserver

    -- (target servers insert a row for themselves when they 'enlist' in an MSX)

    IF (EXISTS (SELECT *

    FROM inserted

    WHERE (server_name = N'ALL')))

    BEGIN

    DELETE FROM msdb.dbo.systargetservers

    WHERE (server_name = N'ALL')

    RAISERROR(14271, -1, -1, 'ALL')

    RETURN

    END

    -- Set (or delete) the registy flag (so that SETUP can detect if we're an MSX)

    IF ((SELECT COUNT(*)

    FROM msdb.dbo.systargetservers) = 0)

    BEGIN

    DECLARE @val INT

    EXECUTE master.dbo.xp_instance_regread N'HKEY_LOCAL_MACHINE',

    N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',

    N'MSXServer',

    @val OUTPUT,

    N'no_output'

    IF (@val IS NOT NULL)

    EXECUTE master.dbo.xp_instance_regdeletevalue N'HKEY_LOCAL_MACHINE',

    N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',

    N'MSXServer'

    END

    ELSE

    EXECUTE master.dbo.xp_instance_regwrite N'HKEY_LOCAL_MACHINE',

    N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',

    N'MSXServer',

    N'REG_DWORD',

    1

    END

    go

    DUMP TRANSACTION msdb WITH NO_LOG

    go

    CHECKPOINT

    go

    /**************************************************************/

    /** **/

    /** A L E R T S A N D O P E R A T O R S **/

    /** **/

    /**************************************************************/

    /**************************************************************/

    /* */

    /* C O R E P R O C E D U R E S */

    /* */

    /**************************************************************/

    DUMP TRANSACTION msdb WITH NO_LOG

    go

    /**************************************************************/

    /* SP_VERIFY_PERFORMANCE_CONDITION */

    /**************************************************************/

    PRINT ''

    PRINT 'Creating procedure sp_verify_performance_condition...'

    go

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = N'sp_verify_performance_condition')

    AND (type = 'P')))

    DROP PROCEDURE sp_verify_performance_condition

    go

    CREATE PROCEDURE sp_verify_performance_condition

    @performance_condition NVARCHAR(512)

    AS

    BEGIN

    DECLARE @delimiter_count INT

    DECLARE @temp_str NVARCHAR(512)

    DECLARE @object_name sysname

    DECLARE @counter_name sysname

    DECLARE @instance_name sysname

    DECLARE @pos INT

    SET NOCOUNT ON

    -- The performance condition must have the format 'object|counter|instance|comparator|value'

    -- NOTE: 'instance' may be empty.

    IF (PATINDEX(N'%_|%_|%|[><=]|[0-9]%', @performance_condition) = 0)

    BEGIN

    RAISERROR(14507, 16, 1)

    RETURN(1) -- Failure

    END

    -- Parse the performance_condition

    SELECT @delimiter_count = 0

    SELECT @temp_str = @performance_condition

    SELECT @pos = CHARINDEX(N'|', @temp_str)

    WHILE (@pos <> 0)

    BEGIN

    SELECT @delimiter_count = @delimiter_count + 1

    IF (@delimiter_count = 1) SELECT @object_name = SUBSTRING(@temp_str, 1, @pos - 1)

    IF (@delimiter_count = 2) SELECT @counter_name = SUBSTRING(@temp_str, 1, @pos - 1)

    IF (@delimiter_count = 3) SELECT @instance_name = SUBSTRING(@temp_str, 1, @pos - 1)

    SELECT @temp_str = SUBSTRING(@temp_str, @pos + 1, (DATALENGTH(@temp_str) / 2) - @pos)

    SELECT @pos = CHARINDEX(N'|', @temp_str)

    END

    IF (@delimiter_count <> 4)

    BEGIN

    RAISERROR(14507, 16, 1)

    RETURN(1) -- Failure

    END

    -- Check the object_name

    IF (NOT EXISTS (SELECT *

    FROM master.dbo.sysperfinfo

    WHERE (object_name = @object_name)))

    BEGIN

    RAISERROR(14262, 16, 1, 'object_name', @object_name)

    RETURN(1) -- Failure

    END

    -- Check the counter_name

    IF (NOT EXISTS (SELECT *

    FROM master.dbo.sysperfinfo

    WHERE (object_name = @object_name)

    AND (counter_name = @counter_name)))

    BEGIN

    RAISERROR(14262, 16, 1, 'counter_name', @counter_name)

    RETURN(1) -- Failure

    END

    -- Check the instance_name

    IF (@instance_name IS NOT NULL)

    BEGIN

    IF (NOT EXISTS (SELECT *

    FROM master.dbo.sysperfinfo

    WHERE (object_name = @object_name)

    AND (counter_name = @counter_name)

    AND (instance_name = @instance_name)))

    BEGIN

    RAISERROR(14262, 16, 1, 'instance_name', @instance_name)

    RETURN(1) -- Failure

    END

    END

    RETURN(0) -- Success

    END

    go

    /**************************************************************/

    /* SP_VERIFY_ALERT */

    /**************************************************************/

    PRINT ''

    PRINT 'Creating procedure sp_verify_alert...'

    go

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = N'sp_verify_alert')

    AND (type = 'P')))

    DROP PROCEDURE sp_verify_alert

    go

    CREATE PROCEDURE sp_verify_alert

    @name sysname,

    @message_id INT,

    @severity INT,

    @enabled TINYINT,

    @delay_between_responses INT,

    @notification_message NVARCHAR(512),

    @include_event_description_in TINYINT,

    @database_name sysname,

    @event_description_keyword NVARCHAR(100),

    @job_id UNIQUEIDENTIFIER OUTPUT,

    @job_name sysname OUTPUT,

    @occurrence_count INT,

    @raise_snmp_trap TINYINT,

    @performance_condition NVARCHAR(512),

    @category_name sysname,

    @category_id INT OUTPUT,

    @count_reset_date INT,

    @count_reset_time INT

    AS

    BEGIN

    DECLARE @retval INT

    DECLARE @non_alertable_errors VARCHAR(512)

    DECLARE @message_id_as_string VARCHAR(10)

    DECLARE @res_valid_range NVARCHAR(100)

    SET NOCOUNT ON

    -- Remove any leading/trailing spaces from parameters

    SELECT @name = LTRIM(RTRIM(@name))

    SELECT @notification_message = LTRIM(RTRIM(@notification_message))

    SELECT @database_name = LTRIM(RTRIM(@database_name))

    SELECT @event_description_keyword = LTRIM(RTRIM(@event_description_keyword))

    SELECT @job_name = LTRIM(RTRIM(@job_name))

    SELECT @performance_condition = LTRIM(RTRIM(@performance_condition))

    SELECT @category_name = LTRIM(RTRIM(@category_name))

    -- Only a sysadmin can do this

    IF (ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) <> 1)

    BEGIN

    RAISERROR(15003, 16, 1, N'sysadmin')

    RETURN(1) -- Failure

    END

    -- Check if the NewName is unique

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysalerts

    WHERE (name = @name)))

    BEGIN

    RAISERROR(14261, 16, 1, '@name', @name)

    RETURN(1) -- Failure

    END

    -- Check if the user has supplied MessageID OR Severity OR Performance-Condition

    IF ((@performance_condition IS NULL) AND ((@message_id = 0) AND (@severity = 0)) OR ((@message_id <> 0) AND (@severity <> 0))) OR

    ((@performance_condition IS NOT NULL) AND ((@message_id <> 0) OR (@severity <> 0)))

    BEGIN

    RAISERROR(14500, 16, 1)

    RETURN(1) -- Failure

    END

    -- Check the Severity

    IF ((@severity 25))

    BEGIN

    RAISERROR(14266, 16, 1, '@severity', '0..25')

    RETURN(1) -- Failure

    END

    -- Check the MessageID

    IF (@message_id <> 0) AND

    (NOT EXISTS (SELECT error

    FROM master.dbo.sysmessages

    WHERE (error = @message_id)))

    BEGIN

    SELECT @message_id_as_string = CONVERT(VARCHAR, @message_id)

    RAISERROR(14262, 16, 1, '@message_id', @message_id_as_string)

    RETURN(1) -- Failure

    END

    -- Check if it is legal to set an alert on this MessageID

    CREATE TABLE #TempRetVal (RetVal INT)

    EXECUTE master.dbo.xp_instance_regread N'HKEY_LOCAL_MACHINE',

    N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',

    N'NonAlertableErrors',

    @non_alertable_errors OUTPUT,

    N'no_output'

    IF (ISNULL(@non_alertable_errors, N'NULL') <> N'NULL')

    BEGIN

    DECLARE @message_id_as_char VARCHAR(10)

    SELECT @message_id_as_char = CONVERT(VARCHAR(10), @message_id)

    INSERT INTO #TempRetVal

    EXECUTE ('IF (' + @message_id_as_char + ' IN (' + @non_alertable_errors + ')) SELECT 1')

    END

    IF (EXISTS (SELECT *

    FROM #TempRetVal))

    BEGIN

    RAISERROR(14506, 16, 1, @message_id)

    RETURN(1) -- Failure

    END

    DROP TABLE #TempRetVal

    -- Enabled must be 0 or 1

    IF (@enabled NOT IN (0, 1))

    BEGIN

    RAISERROR(14266, 16, 1, '@enabled', '0, 1')

    RETURN(1) -- Failure

    END

    -- DelayBetweenResponses must be > 0

    IF (@delay_between_responses < 0)

    BEGIN

    SELECT @res_valid_range = FORMATMESSAGE(14206)

    RAISERROR(14266, 16, 1, '@delay_between_responses', @res_valid_range)

    RETURN(1) -- Failure

    END

    -- NOTE: We don't check the notification message

    -- Check IncludeEventDescriptionIn

    IF ((@include_event_description_in 7))

    BEGIN

    SELECT @res_valid_range = FORMATMESSAGE(14208)

    RAISERROR(14266, 16, 1, '@include_event_description_in', @res_valid_range)

    RETURN(1) -- Failure

    END

    -- Check the database name

    IF (@database_name IS NOT NULL) AND (DB_ID(@database_name) IS NULL)

    BEGIN

    RAISERROR(15010, 16, 1, @database_name)

    RETURN(1) -- Failure

    END

    -- NOTE: We don't check the event description keyword

    -- Check JobName/ID

    IF ((@job_id IS NOT NULL) OR (@job_name IS NOT NULL))

    BEGIN

    -- We use '' as a special value which means 'no job' (we cannot use NULL since this forces

    -- sp_update_alert to use the existing value)

    IF (@job_name = N'')

    SELECT @job_id = 0x00

    ELSE

    BEGIN

    EXECUTE @retval = sp_verify_job_identifiers '@job_name',

    '@job_id',

    @job_name OUTPUT,

    @job_id OUTPUT

    IF (@retval <> 0)

    RETURN(1) -- Failure

    -- Check that the job is a local job

    IF (NOT EXISTS (SELECT *

    FROM msdb.dbo.sysjobservers

    WHERE (job_id = @job_id)

    AND (server_id = 0)))

    BEGIN

    RAISERROR(14234, -1, -1, '@job_id', 'sp_help_job @job_type = ''LOCAL''')

    RETURN(1) -- Failure

    END

    END

    END

    -- OccurrenceCount must be > 0

    IF (@occurrence_count < 0)

    BEGIN

    RAISERROR(14266, 16, 1, '@occurrence_count', '0..n')

    RETURN(1) -- Failure

    END

    -- RaiseSNMPTrap must be 0 or 1

    IF (@raise_snmp_trap NOT IN (0, 1))

    BEGIN

    RAISERROR(14266, 16, 1, '@raise_snmp_trap', '0, 1')

    RETURN(1) -- Failure

    END

    -- Check the performance condition (including invalid parameter combinations)

    IF (@performance_condition IS NOT NULL)

    BEGIN

    IF (@database_name IS NOT NULL)

    BEGIN

    RAISERROR(14505, 16, 1, 'database_name')

    RETURN(1) -- Failure

    END

    IF (@event_description_keyword IS NOT NULL)

    BEGIN

    RAISERROR(14505, 16, 1, 'event_description_keyword')

    RETURN(1) -- Failure

    END

    -- Verify the performance condition

    EXECUTE @retval = msdb.dbo.sp_verify_performance_condition @performance_condition

    IF (@retval <> 0)

    RETURN(1) -- Failure

    END

    -- Check category name

    IF (@category_name = N'[DEFAULT]')

    SELECT @category_id = 98

    ELSE

    BEGIN

    SELECT @category_id = category_id

    FROM msdb.dbo.syscategories

    WHERE (category_class = 2) -- Alerts

    AND (category_type = 3) -- None

    AND (name = @category_name)

    END

    IF (@category_id IS NULL)

    BEGIN

    RAISERROR(14262, -1, -1, '@category_name', @category_name)

    RETURN(1) -- Failure

    END

    -- Check count reset date

    IF (@count_reset_date <> 0)

    BEGIN

    EXECUTE @retval = msdb.dbo.sp_verify_job_date @count_reset_date, '@count_reset_date'

    IF (@retval <> 0)

    RETURN(1) -- Failure

    END

    -- Check count reset time

    IF (@count_reset_time <> 0)

    BEGIN

    EXECUTE @retval = msdb.dbo.sp_verify_job_time @count_reset_time, '@count_reset_time'

    IF (@retval <> 0)

    RETURN(1) -- Failure

    END

    RETURN(0) -- Success

    END

    go

    /**************************************************************/

    /* SP_ADD_ALERT */

    /**************************************************************/

    PRINT ''

    PRINT 'Creating procedure sp_add_alert...'

    go

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = N'sp_add_alert')

    AND (type = 'P')))

    DROP PROCEDURE sp_add_alert

    go

    CREATE PROCEDURE sp_add_alert

    @name sysname,

    @message_id INT = 0,

    @severity INT = 0,

    @enabled TINYINT = 1,

    @delay_between_responses INT = 0,

    @notification_message NVARCHAR(512) = NULL,

    @include_event_description_in TINYINT = 5, -- 0 = None, 1 = Email, 2 = Pager, 4 = NetSend, 7 = All

    @database_name sysname = NULL,

    @event_description_keyword NVARCHAR(100) = NULL,

    @job_id UNIQUEIDENTIFIER = NULL, -- If provided must NOT also provide job_name

    @job_name sysname = NULL, -- If provided must NOT also provide job_id

    @raise_snmp_trap TINYINT = 0,

    @performance_condition NVARCHAR(512) = NULL, -- New for 7.0

    @category_name sysname = NULL -- New for 7.0

    AS

    BEGIN

    DECLARE @event_source NVARCHAR(100)

    DECLARE @event_category_id INT

    DECLARE @event_id INT

    DECLARE @last_occurrence_date INT

    DECLARE @last_occurrence_time INT

    DECLARE @last_notification_date INT

    DECLARE @last_notification_time INT

    DECLARE @occurrence_count INT

    DECLARE @count_reset_date INT

    DECLARE @count_reset_time INT

    DECLARE @has_notification INT

    DECLARE @return_code INT

    DECLARE @duplicate_name sysname

    DECLARE @category_id INT

    DECLARE @alert_id INT

    SET NOCOUNT ON

    -- Remove any leading/trailing spaces from parameters

    SELECT @name = LTRIM(RTRIM(@name))

    SELECT @notification_message = LTRIM(RTRIM(@notification_message))

    SELECT @database_name = LTRIM(RTRIM(@database_name))

    SELECT @event_description_keyword = LTRIM(RTRIM(@event_description_keyword))

    SELECT @job_name = LTRIM(RTRIM(@job_name))

    SELECT @performance_condition = LTRIM(RTRIM(@performance_condition))

    SELECT @category_name = LTRIM(RTRIM(@category_name))

    -- Turn [nullable] empty string parameters into NULLs

    IF (@notification_message = N'') SELECT @notification_message = NULL

    IF (@database_name = N'') SELECT @database_name = NULL

    IF (@event_description_keyword = N'') SELECT @event_description_keyword = NULL

    IF (@job_name = N'') SELECT @job_name = NULL

    IF (@performance_condition = N'') SELECT @performance_condition = NULL

    IF (@category_name = N'') SELECT @category_name = NULL

    SELECT @message_id = ISNULL(@message_id, 0)

    SELECT @severity = ISNULL(@severity, 0)

    -- Only a sysadmin can do this

    IF (ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) <> 1)

    BEGIN

    RAISERROR(15003, 16, 1, N'sysadmin')

    RETURN(1) -- Failure

    END

    -- Check if SQLServerAgent is in the process of starting

    EXECUTE @return_code = msdb.dbo.sp_is_sqlagent_starting

    IF (@return_code <> 0)

    RETURN(1) -- Failure

    -- Hard-code the new Alert defaults

    -- event source needs to be instance aware

    DECLARE @instance_name sysname

    SELECT @instance_name = CONVERT (sysname, SERVERPROPERTY ('InstanceName'))

    IF (@instance_name IS NULL OR @instance_name = N'MSSQLSERVER')

    SELECT @event_source = N'MSSQLSERVER'

    ELSE

    SELECT @event_source = N'MSSQL$' + @instance_name

    SELECT @event_category_id = NULL

    SELECT @event_id = NULL

    SELECT @last_occurrence_date = 0

    SELECT @last_occurrence_time = 0

    SELECT @last_notification_date = 0

    SELECT @last_notification_time = 0

    SELECT @occurrence_count = 0

    SELECT @count_reset_date = 0

    SELECT @count_reset_time = 0

    SELECT @has_notification = 0

    IF (@category_name IS NULL)

    BEGIN

    SELECT @category_name = name

    FROM msdb.dbo.syscategories

    WHERE (category_id = 98)

    END

    -- Map a job_id of 0 to the real value we use to mean 'no job'

    IF (@job_id = CONVERT(UNIQUEIDENTIFIER, 0x00)) AND (@job_name IS NULL)

    SELECT @job_name = N''

    -- Verify the Alert

    IF (@job_id = CONVERT(UNIQUEIDENTIFIER, 0x00))

    SELECT @job_id = NULL

    EXECUTE @return_code = sp_verify_alert @name,

    @message_id,

    @severity,

    @enabled,

    @delay_between_responses,

    @notification_message,

    @include_event_description_in,

    @database_name,

    @event_description_keyword,

    @job_id OUTPUT,

    @job_name OUTPUT,

    @occurrence_count,

    @raise_snmp_trap,

    @performance_condition,

    @category_name,

    @category_id OUTPUT,

    @count_reset_date,

    @count_reset_time

    IF (@return_code <> 0)

    RETURN(1) -- Failure

    -- Check if this Alert already exists

    SELECT @duplicate_name = FORMATMESSAGE(14205)

    SELECT @duplicate_name = name

    FROM msdb.dbo.sysalerts

    WHERE (ISNULL(performance_condition, N'apples') = ISNULL(@performance_condition, N'oranges'))

    OR ((performance_condition IS NULL) AND

    (message_id = @message_id) AND

    (severity = @severity) AND

    (ISNULL(database_name, N'') = ISNULL(@database_name, N'')) AND

    (ISNULL(event_description_keyword, N'') = ISNULL(@event_description_keyword, N'')))

    IF (@duplicate_name <> FORMATMESSAGE(14205))

    BEGIN

    RAISERROR(14501, 16, 1, @duplicate_name)

    RETURN(1) -- Failure

    END

    -- Finally, do the actual INSERT

    INSERT INTO msdb.dbo.sysalerts

    (name,

    event_source,

    event_category_id,

    event_id,

    message_id,

    severity,

    enabled,

    delay_between_responses,

    last_occurrence_date,

    last_occurrence_time,

    last_response_date,

    last_response_time,

    notification_message,

    include_event_description,

    database_name,

    event_description_keyword,

    occurrence_count,

    count_reset_date,

    count_reset_time,

    job_id,

    has_notification,

    flags,

    performance_condition,

    category_id)

    VALUES (@name,

    @event_source,

    @event_category_id,

    @event_id,

    @message_id,

    @severity,

    @enabled,

    @delay_between_responses,

    @last_occurrence_date,

    @last_occurrence_time,

    @last_notification_date,

    @last_notification_time,

    @notification_message,

    @include_event_description_in,

    @database_name,

    @event_description_keyword,

    @occurrence_count,

    @count_reset_date,

    @count_reset_time,

    ISNULL(@job_id, CONVERT(UNIQUEIDENTIFIER, 0x00)),

    @has_notification,

    @raise_snmp_trap,

    @performance_condition,

    @category_id)

    -- Notify SQLServerAgent of the change

    SELECT @alert_id = id

    FROM msdb.dbo.sysalerts

    WHERE (name = @name)

    EXECUTE msdb.dbo.sp_sqlagent_notify @op_type = N'A',

    @alert_id = @alert_id,

    @action_type = N'I'

    RETURN(0) -- Success

    END

    go

    /**************************************************************/

    /* SP_UPDATE_ALERT */

    /**************************************************************/

    PRINT ''

    PRINT 'Creating procedure sp_update_alert...'

    go

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = N'sp_update_alert')

    AND (type = 'P')))

    DROP PROCEDURE sp_update_alert

    go

    CREATE PROCEDURE sp_update_alert

    @name sysname,

    @new_name sysname = NULL,

    @enabled TINYINT = NULL,

    @message_id INT = NULL,

    @severity INT = NULL,

    @delay_between_responses INT = NULL,

    @notification_message NVARCHAR(512) = NULL,

    @include_event_description_in TINYINT = NULL, -- 0 = None, 1 = Email, 2 = Pager. 4 = NetSend, 7 = All

    @database_name sysname = NULL,

    @event_description_keyword NVARCHAR(100) = NULL,

    @job_id UNIQUEIDENTIFIER = NULL, -- If provided must NOT also provide job_name

    @job_name sysname = NULL, -- If provided must NOT also provide job_id

    @occurrence_count INT = NULL, -- Can only be set to 0

    @count_reset_date INT = NULL,

    @count_reset_time INT = NULL,

    @last_occurrence_date INT = NULL, -- Can only be set to 0

    @last_occurrence_time INT = NULL, -- Can only be set to 0

    @last_response_date INT = NULL, -- Can only be set to 0

    @last_response_time INT = NULL, -- Can only be set to 0

    @raise_snmp_trap TINYINT = NULL,

    @performance_condition NVARCHAR(512) = NULL, -- New for 7.0

    @category_name sysname = NULL -- New for 7.0

    AS

    BEGIN

    DECLARE @x_enabled TINYINT

    DECLARE @x_message_id INT

    DECLARE @x_severity INT

    DECLARE @x_delay_between_responses INT

    DECLARE @x_notification_message NVARCHAR(512)

    DECLARE @x_include_event_description TINYINT

    DECLARE @x_database_name sysname

    DECLARE @x_event_description_keyword NVARCHAR(100)

    DECLARE @x_occurrence_count INT

    DECLARE @x_count_reset_date INT

    DECLARE @x_count_reset_time INT

    DECLARE @x_last_occurrence_date INT

    DECLARE @x_last_occurrence_time INT

    DECLARE @x_last_response_date INT

    DECLARE @x_last_response_time INT

    DECLARE @x_flags INT

    DECLARE @x_performance_condition NVARCHAR(512)

    DECLARE @x_job_id UNIQUEIDENTIFIER

    DECLARE @x_category_id INT

    DECLARE @include_event_desc_code TINYINT

    DECLARE @return_code INT

    DECLARE @duplicate_name sysname

    DECLARE @category_id INT

    DECLARE @alert_id INT

    DECLARE @cached_attribute_modified INT

    SET NOCOUNT ON

    -- Remove any leading/trailing spaces from parameters

    SELECT @new_name = LTRIM(RTRIM(@new_name))

    SELECT @job_name = LTRIM(RTRIM(@job_name))

    SELECT @notification_message = LTRIM(RTRIM(@notification_message))

    SELECT @database_name = LTRIM(RTRIM(@database_name))

    SELECT @event_description_keyword = LTRIM(RTRIM(@event_description_keyword))

    SELECT @performance_condition = LTRIM(RTRIM(@performance_condition))

    SELECT @category_name = LTRIM(RTRIM(@category_name))

    -- Are we modifying an attribute which SQLServerAgent caches?

    IF ((@new_name IS NOT NULL) OR

    (@enabled IS NOT NULL) OR

    (@message_id IS NOT NULL) OR

    (@severity IS NOT NULL) OR

    (@delay_between_responses IS NOT NULL) OR

    (@notification_message IS NOT NULL) OR

    (@include_event_description_in IS NOT NULL) OR

    (@database_name IS NOT NULL) OR

    (@event_description_keyword IS NOT NULL) OR

    (@job_id IS NOT NULL) OR

    (@job_name IS NOT NULL) OR

    (@last_response_date IS NOT NULL) OR

    (@last_response_time IS NOT NULL) OR

    (@raise_snmp_trap IS NOT NULL) OR

    (@performance_condition IS NOT NULL))

    SELECT @cached_attribute_modified = 1

    ELSE

    SELECT @cached_attribute_modified = 0

    -- Map a job_id of 0 to the real value we use to mean 'no job'

    IF (@job_id = CONVERT(UNIQUEIDENTIFIER, 0x00)) AND (@job_name IS NULL)

    SELECT @job_name = N''

    -- Only a sysadmin can do this

    IF (ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) <> 1)

    BEGIN

    RAISERROR(15003, 16, 1, N'sysadmin')

    RETURN(1)

    END

    -- Check if SQLServerAgent is in the process of starting

    EXECUTE @return_code = msdb.dbo.sp_is_sqlagent_starting

    IF (@return_code <> 0)

    RETURN(1) -- Failure

    -- Check if this Alert exists

    IF (NOT EXISTS (SELECT *

    FROM msdb.dbo.sysalerts

    WHERE (name = @name)))

    BEGIN

    RAISERROR(14262, 16, 1, '@name', @name)

    RETURN(1)

    END

    -- Certain values (if supplied) may only be updated to 0

    IF (@occurrence_count <> 0)

    BEGIN

    RAISERROR(14266, -1, -1, '@occurrence_count', '0')

    RETURN(1) -- Failure

    END

    IF (@last_occurrence_date <> 0)

    BEGIN

    RAISERROR(14266, -1, -1, '@last_occurrence_date', '0')

    RETURN(1) -- Failure

    END

    IF (@last_occurrence_time <> 0)

    BEGIN

    RAISERROR(14266, -1, -1, '@last_occurrence_time', '0')

    RETURN(1) -- Failure

    END

    IF (@last_response_date <> 0)

    BEGIN

    RAISERROR(14266, -1, -1, '@last_response_date', '0')

    RETURN(1) -- Failure

    END

    IF (@last_response_time <> 0)

    BEGIN

    RAISERROR(14266, -1, -1, '@last_response_time', '0')

    RETURN(1) -- Failure

    END

    -- Get existing (@x_) values

    SELECT @alert_id = id,

    @x_enabled = enabled,

    @x_message_id = message_id,

    @x_severity = severity,

    @x_delay_between_responses = delay_between_responses,

    @x_notification_message = notification_message,

    @x_include_event_description = include_event_description,

    @x_database_name = database_name,

    @x_event_description_keyword = event_description_keyword,

    @x_occurrence_count = occurrence_count,

    @x_count_reset_date = count_reset_date,

    @x_count_reset_time = count_reset_time,

    @x_job_id = job_id,

    @x_last_occurrence_date = last_occurrence_date,

    @x_last_occurrence_time = last_occurrence_time,

    @x_last_response_date = last_response_date,

    @x_last_response_time = last_response_time,

    @x_flags = flags,

    @x_performance_condition = performance_condition,

    @x_category_id = category_id

    FROM msdb.dbo.sysalerts

    WHERE (name = @name)

    SELECT @x_job_id = sjv.job_id

    FROM msdb.dbo.sysalerts sa,

    msdb.dbo.sysjobs_view sjv

    WHERE (sa.job_id = sjv.job_id)

    AND (sa.name = @name)

    -- Fill out the values for all non-supplied parameters from the existsing values

    IF (@enabled IS NULL) SELECT @enabled = @x_enabled

    IF (@message_id IS NULL) SELECT @message_id = @x_message_id

    IF (@severity IS NULL) SELECT @severity = @x_severity

    IF (@delay_between_responses IS NULL) SELECT @delay_between_responses = @x_delay_between_responses

    IF (@notification_message IS NULL) SELECT @notification_message = @x_notification_message

    IF (@include_event_description_in IS NULL) SELECT @include_event_description_in = @x_include_event_description

    IF (@database_name IS NULL) SELECT @database_name = @x_database_name

    IF (@event_description_keyword IS NULL) SELECT @event_description_keyword = @x_event_description_keyword

    IF (@job_id IS NULL) AND (@job_name IS NULL) SELECT @job_id = @x_job_id

    IF (@occurrence_count IS NULL) SELECT @occurrence_count = @x_occurrence_count

    IF (@count_reset_date IS NULL) SELECT @count_reset_date = @x_count_reset_date

    IF (@count_reset_time IS NULL) SELECT @count_reset_time = @x_count_reset_time

    IF (@last_occurrence_date IS NULL) SELECT @last_occurrence_date = @x_last_occurrence_date

    IF (@last_occurrence_time IS NULL) SELECT @last_occurrence_time = @x_last_occurrence_time

    IF (@last_response_date IS NULL) SELECT @last_response_date = @x_last_response_date

    IF (@last_response_time IS NULL) SELECT @last_response_time = @x_last_response_time

    IF (@raise_snmp_trap IS NULL) SELECT @raise_snmp_trap = @x_flags & 0x1

    IF (@performance_condition IS NULL) SELECT @performance_condition = @x_performance_condition

    IF (@category_name IS NULL) SELECT @category_name = name FROM msdb.dbo.syscategories WHERE (category_id = @x_category_id)

    IF (@category_name IS NULL)

    BEGIN

    SELECT @category_name = name

    FROM msdb.dbo.syscategories

    WHERE (category_id = 98)

    END

    -- Turn [nullable] empty string parameters into NULLs

    IF (@new_name = N'') SELECT @new_name = NULL

    IF (@notification_message = N'') SELECT @notification_message = NULL

    IF (@database_name = N'') SELECT @database_name = NULL

    IF (@event_description_keyword = N'') SELECT @event_description_keyword = NULL

    IF (@performance_condition = N'') SELECT @performance_condition = NULL

    -- Check if this alert would match an already existing alert

    SELECT @duplicate_name = FORMATMESSAGE(14205)

    SELECT @duplicate_name = name

    FROM msdb.dbo.sysalerts

    WHERE (ISNULL(performance_condition, N'') = ISNULL(@performance_condition, N''))

    AND (message_id = @message_id)

    AND (severity = @severity)

    AND (ISNULL(database_name, N'') = ISNULL(@database_name, N''))

    AND (ISNULL(event_description_keyword, N'') = ISNULL(@event_description_keyword, N''))

    AND (name <> @name)

    IF (@duplicate_name <> FORMATMESSAGE(14205))

    BEGIN

    RAISERROR(14501, 16, 1, @duplicate_name)

    RETURN(1) -- Failure

    END

    -- Verify the Alert

    IF (@job_id = CONVERT(UNIQUEIDENTIFIER, 0x00))

    SELECT @job_id = NULL

    EXECUTE @return_code = sp_verify_alert @new_name,

    @message_id,

    @severity,

    @enabled,

    @delay_between_responses,

    @notification_message,

    @include_event_description_in,

    @database_name,

    @event_description_keyword,

    @job_id OUTPUT,

    @job_name OUTPUT,

    @occurrence_count,

    @raise_snmp_trap,

    @performance_condition,

    @category_name,

    @category_id OUTPUT,

    @count_reset_date,

    @count_reset_time

    IF (@return_code <> 0)

    RETURN(1) -- Failure

    -- If the user didn't supply a NewName, use the old one.

    -- NOTE: This must be done AFTER sp_verify_alert.

    IF (@new_name IS NULL)

    SELECT @new_name = @name

    -- Turn the 1st 'flags' bit on or off accordingly

    IF (@raise_snmp_trap = 0)

    SELECT @x_flags = @x_flags & 0xFFFE

    ELSE

    SELECT @x_flags = @x_flags | 0x0001

    -- Finally, do the actual UPDATE

    UPDATE msdb.dbo.sysalerts

    SET name = @new_name,

    message_id = @message_id,

    severity = @severity,

    enabled = @enabled,

    delay_between_responses = @delay_between_responses,

    notification_message = @notification_message,

    include_event_description = @include_event_description_in,

    database_name = @database_name,

    event_description_keyword = @event_description_keyword,

    job_id = ISNULL(@job_id, CONVERT(UNIQUEIDENTIFIER, 0x00)),

    occurrence_count = @occurrence_count,

    count_reset_date = @count_reset_date,

    count_reset_time = @count_reset_time,

    last_occurrence_date = @last_occurrence_date,

    last_occurrence_time = @last_occurrence_time,

    last_response_date = @last_response_date,

    last_response_time = @last_response_time,

    flags = @x_flags,

    performance_condition = @performance_condition,

    category_id = @category_id

    WHERE (name = @name)

    -- Notify SQLServerAgent of the change

    IF (@cached_attribute_modified = 1)

    EXECUTE msdb.dbo.sp_sqlagent_notify @op_type = N'A',

    @alert_id = @alert_id,

    @action_type = N'U'

    RETURN(0) -- Success

    END

    go

    /**************************************************************/

    /* SP_DELETE_ALERT */

    /**************************************************************/

    PRINT ''

    PRINT 'Creating procedure sp_delete_alert...'

    go

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = N'sp_delete_alert')

    AND (type = 'P')))

    DROP PROCEDURE sp_delete_alert

    go

    CREATE PROCEDURE sp_delete_alert

    @name sysname

    AS

    BEGIN

    DECLARE @alert_id INT

    DECLARE @return_code INT

    SET NOCOUNT ON

    -- Remove any leading/trailing spaces from parameters

    SELECT @name = LTRIM(RTRIM(@name))

    -- Only a sysadmin can do this

    IF (ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) <> 1)

    BEGIN

    RAISERROR(15003, 16, 1, N'sysadmin')

    RETURN(1) -- Failure

    END

    -- Check if SQLServerAgent is in the process of starting

    EXECUTE @return_code = msdb.dbo.sp_is_sqlagent_starting

    IF (@return_code <> 0)

    RETURN(1) -- Failure

    -- Check if this Alert exists

    IF (NOT EXISTS (SELECT *

    FROM msdb.dbo.sysalerts

    WHERE (name = @name)))

    BEGIN

    RAISERROR(14262, 16, 1, '@name', @name)

    RETURN(1) -- Failure

    END

    -- Convert the Name to it's ID

    SELECT @alert_id = id

    FROM msdb.dbo.sysalerts

    WHERE (name = @name)

    BEGIN TRANSACTION

    -- Delete sysnotifications entries

    DELETE FROM msdb.dbo.sysnotifications

    WHERE (alert_id = @alert_id)

    -- Finally, do the actual DELETE

    DELETE FROM msdb.dbo.sysalerts

    WHERE (id = @alert_id)

    COMMIT TRANSACTION

    -- Notify SQLServerAgent of the change

    EXECUTE msdb.dbo.sp_sqlagent_notify @op_type = N'A',

    @alert_id = @alert_id,

    @action_type = N'D'

    RETURN(0) -- Success

    END

    go

    /**************************************************************/

    /* SP_HELP_ALERT */

    /**************************************************************/

    PRINT ''

    PRINT 'Creating procedure sp_help_alert...'

    go

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = N'sp_help_alert')

    AND (type = 'P')))

    DROP PROCEDURE sp_help_alert

    go

    CREATE PROCEDURE sp_help_alert

    @alert_name sysname = NULL,

    @order_by sysname = N'name',

    @alert_id INT = NULL,

    @category_name sysname = NULL

    AS

    BEGIN

    DECLARE @alert_id_as_char NVARCHAR(10)

    SET NOCOUNT ON

    -- Remove any leading/trailing spaces from parameters

    SELECT @alert_name = LTRIM(RTRIM(@alert_name))

    SELECT @order_by = LTRIM(RTRIM(@order_by))

    SELECT @category_name = LTRIM(RTRIM(@category_name))

    -- Turn [nullable] empty string parameters into NULLs

    IF (@category_name = N'') SELECT @category_name = NULL

    IF (@alert_name = N'') SELECT @alert_name = NULL

    -- Check alert name

    IF (@alert_name IS NOT NULL)

    BEGIN

    IF (NOT EXISTS (SELECT *

    FROM msdb.dbo.sysalerts

    WHERE (name = @alert_name)))

    BEGIN

    RAISERROR(14262, -1, -1, '@alert_name', @alert_name)

    RETURN(1) -- Failure

    END

    END

    -- Check alert id

    IF (@alert_id IS NOT NULL)

    BEGIN

    IF (NOT EXISTS (SELECT *

    FROM msdb.dbo.sysalerts

    WHERE (id = @alert_id)))

    BEGIN

    SELECT @alert_id_as_char = CONVERT(VARCHAR, @alert_id)

    RAISERROR(14262, -1, -1, '@alert_id', @alert_id_as_char)

    RETURN(1) -- Failure

    END

    END

    IF (@alert_id IS NOT NULL)

    SELECT @alert_id_as_char = CONVERT(VARCHAR, @alert_id)

    ELSE

    SELECT @alert_id_as_char = N'NULL'

    -- Double up any single quotes in @alert_name

    IF (@alert_name IS NOT NULL)

    SELECT @alert_name = REPLACE(@alert_name, N'''', N'''''')

    -- Double up any single quotes in @category_name

    IF (@category_name IS NOT NULL)

    SELECT @category_name = REPLACE(@category_name, N'''', N'''''')

    -- @order_by parameter validation.

    IF ( (@order_by IS NOT NULL) AND

    (EXISTS(SELECT so.id FROM msdb.dbo.sysobjects so

    JOIN msdb.dbo.syscolumns sc ON (so.id = sc.id)

    WHERE so.xtype='U' AND so.name='sysalerts' AND LOWER(sc.name)=LOWER(@order_by)

    )

    ) )

    BEGIN

    SELECT @order_by = N'sa.' + @order_by

    END

    ELSE

    BEGIN

    IF (LOWER(@order_by) NOT IN (N'job_name', N'category_name', N'type' ) )

    AND --special "order by" clause used only by sqlagent. if you change it you need to change agent too

    (@order_by <> N'severity ASC, message_id ASC, database_name DESC')

    BEGIN

    RAISERROR(18750, -1, -1, 'sp_help_alert', '@order_by')

    RETURN(1) -- Failure

    END

    END

    EXECUTE (N'SELECT sa.id,

    sa.name,

    sa.event_source,

    sa.event_category_id,

    sa.event_id,

    sa.message_id,

    sa.severity,

    sa.enabled,

    sa.delay_between_responses,

    sa.last_occurrence_date,

    sa.last_occurrence_time,

    sa.last_response_date,

    sa.last_response_time,

    sa.notification_message,

    sa.include_event_description,

    sa.database_name,

    sa.event_description_keyword,

    sa.occurrence_count,

    sa.count_reset_date,

    sa.count_reset_time,

    sjv.job_id,

    job_name = sjv.name,

    sa.has_notification,

    sa.flags,

    sa.performance_condition,

    category_name = sc.name,

    type = CASE ISNULL(performance_condition, ''!'')

    WHEN ''!'' THEN

    CASE event_source

    WHEN ''MSSQLSERVER'' THEN 1 -- SQL Server event alert

    ELSE 3 -- Non SQL Server event alert

    END

    ELSE 2 -- SQL Server performance condition alert

    END

    FROM msdb.dbo.sysalerts sa

    LEFT OUTER JOIN msdb.dbo.sysjobs_view sjv ON (sa.job_id = sjv.job_id)

    LEFT OUTER JOIN msdb.dbo.syscategories sc ON (sa.category_id = sc.category_id)

    WHERE ((N''' + @alert_name + N''' = N'''') OR (sa.name = N''' + @alert_name + N'''))

    AND ((' + @alert_id_as_char + N' IS NULL) OR (sa.id = ' + @alert_id_as_char + N'))

    AND ((N''' + @category_name + N''' = N'''') OR (sc.name = N''' + @category_name + N'''))

    ORDER BY ' + @order_by)

    RETURN(@@error) -- 0 means success

    END

    go

    /**************************************************************/

    /* SP_VERIFY_OPERATOR */

    /**************************************************************/

    PRINT ''

    PRINT 'Creating procedure sp_verify_operator...'

    go

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = N'sp_verify_operator')

    AND (type = 'P')))

    DROP PROCEDURE sp_verify_operator

    go

    CREATE PROCEDURE sp_verify_operator

    @name sysname,

    @enabled TINYINT,

    @pager_days TINYINT,

    @weekday_pager_start_time INT,

    @weekday_pager_end_time INT,

    @saturday_pager_start_time INT,

    @saturday_pager_end_time INT,

    @sunday_pager_start_time INT,

    @sunday_pager_end_time INT,

    @category_name sysname,

    @category_id INT OUTPUT

    AS

    BEGIN

    DECLARE @return_code TINYINT

    DECLARE @res_valid_range NVARCHAR(100)

    SET NOCOUNT ON

    SELECT @res_valid_range = FORMATMESSAGE(14209)

    -- Remove any leading/trailing spaces from parameters

    SELECT @name = LTRIM(RTRIM(@name))

    SELECT @category_name = LTRIM(RTRIM(@category_name))

    -- The name must be unique

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysoperators

    WHERE (name = @name)))

    BEGIN

    RAISERROR(14261, 16, 1, '@name', @name)

    RETURN(1) -- Failure

    END

    -- Enabled must be 0 or 1

    IF (@enabled NOT IN (0, 1))

    BEGIN

    RAISERROR(14266, 16, 1, '@enabled', '0, 1')

    RETURN(1) -- Failure

    END

    -- Check PagerDays

    IF (@pager_days 127)

    BEGIN

    RAISERROR(14266, 16, 1, '@pager_days', @res_valid_range)

    RETURN(1) -- Failure

    END

    -- Check Start/End Times

    EXECUTE @return_code = sp_verify_job_time @weekday_pager_start_time, '@weekday_pager_start_time'

    IF (@return_code <> 0)

    RETURN(1)

    EXECUTE @return_code = sp_verify_job_time @weekday_pager_end_time, '@weekday_pager_end_time'

    IF (@return_code <> 0)

    RETURN(1)

    EXECUTE @return_code = sp_verify_job_time @saturday_pager_start_time, '@saturday_pager_start_time'

    IF (@return_code <> 0)

    RETURN(1)

    EXECUTE @return_code = sp_verify_job_time @saturday_pager_end_time, '@saturday_pager_end_time'

    IF (@return_code <> 0)

    RETURN(1)

    EXECUTE @return_code = sp_verify_job_time @sunday_pager_start_time, '@sunday_pager_start_time'

    IF (@return_code <> 0)

    RETURN(1)

    EXECUTE @return_code = sp_verify_job_time @sunday_pager_end_time, '@sunday_pager_end_time'

    IF (@return_code <> 0)

    RETURN(1)

    -- Check category name

    IF (@category_name = N'[DEFAULT]')

    SELECT @category_id = 99

    ELSE

    BEGIN

    SELECT @category_id = category_id

    FROM msdb.dbo.syscategories

    WHERE (category_class = 3) -- Operators

    AND (category_type = 3) -- None

    AND (name = @category_name)

    END

    IF (@category_id IS NULL)

    BEGIN

    RAISERROR(14262, -1, -1, '@category_name', @category_name)

    RETURN(1) -- Failure

    END

    RETURN(0)

    END

    go

    /**************************************************************/

    /* SP_ADD_OPERATOR */

    /**************************************************************/

    PRINT ''

    PRINT 'Creating procedure sp_add_operator...'

    go

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = N'sp_add_operator')

    AND (type = 'P')))

    DROP PROCEDURE sp_add_operator

    go

    CREATE PROCEDURE sp_add_operator

    @name sysname,

    @enabled TINYINT = 1,

    @email_address NVARCHAR(100) = NULL,

    @pager_address NVARCHAR(100) = NULL,

    @weekday_pager_start_time INT = 090000, -- HHMMSS using 24 hour clock

    @weekday_pager_end_time INT = 180000, -- As above

    @saturday_pager_start_time INT = 090000, -- As above

    @saturday_pager_end_time INT = 180000, -- As above

    @sunday_pager_start_time INT = 090000, -- As above

    @sunday_pager_end_time INT = 180000, -- As above

    @pager_days TINYINT = 0, -- 1 = Sunday .. 64 = Saturday

    @netsend_address NVARCHAR(100) = NULL, -- New for 7.0

    @category_name sysname = NULL -- New for 7.0

    AS

    BEGIN

    DECLARE @return_code TINYINT

    DECLARE @category_id INT

    SET NOCOUNT ON

    -- Remove any leading/trailing spaces from parameters

    SELECT @name = LTRIM(RTRIM(@name))

    SELECT @email_address = LTRIM(RTRIM(@email_address))

    SELECT @pager_address = LTRIM(RTRIM(@pager_address))

    SELECT @netsend_address = LTRIM(RTRIM(@netsend_address))

    SELECT @category_name = LTRIM(RTRIM(@category_name))

    -- Turn [nullable] empty string parameters into NULLs

    IF (@email_address = N'') SELECT @email_address = NULL

    IF (@pager_address = N'') SELECT @pager_address = NULL

    IF (@netsend_address = N'') SELECT @netsend_address = NULL

    IF (@category_name = N'') SELECT @category_name = NULL

    -- Only a sysadmin can do this

    IF (ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) <> 1)

    BEGIN

    RAISERROR(15003, 16, 1, N'sysadmin')

    RETURN(1) -- Failure

    END

    IF (@category_name IS NULL)

    BEGIN

    SELECT @category_name = name

    FROM msdb.dbo.syscategories

    WHERE (category_id = 99)

    END

    -- Verify the operator

    EXECUTE @return_code = sp_verify_operator @name,

    @enabled,

    @pager_days,

    @weekday_pager_start_time,

    @weekday_pager_end_time,

    @saturday_pager_start_time,

    @saturday_pager_end_time,

    @sunday_pager_start_time,

    @sunday_pager_end_time,

    @category_name,

    @category_id OUTPUT

    IF (@return_code <> 0)

    RETURN(1) -- Failure

    -- Finally, do the INSERT

    INSERT INTO msdb.dbo.sysoperators

    (name,

    enabled,

    email_address,

    last_email_date,

    last_email_time,

    pager_address,

    last_pager_date,

    last_pager_time,

    weekday_pager_start_time,

    weekday_pager_end_time,

    saturday_pager_start_time,

    saturday_pager_end_time,

    sunday_pager_start_time,

    sunday_pager_end_time,

    pager_days,

    netsend_address,

    last_netsend_date,

    last_netsend_time,

    category_id)

    VALUES (@name,

    @enabled,

    @email_address,

    0,

    0,

    @pager_address,

    0,

    0,

    @weekday_pager_start_time,

    @weekday_pager_end_time,

    @saturday_pager_start_time,

    @saturday_pager_end_time,

    @sunday_pager_start_time,

    @sunday_pager_end_time,

    @pager_days,

    @netsend_address,

    0,

    0,

    @category_id)

    RETURN(@@error) -- 0 means success

    END

    go

    /**************************************************************/

    /* SP_UPDATE_OPERATOR */

    /**************************************************************/

    PRINT ''

    PRINT 'Creating procedure sp_update_operator...'

    go

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = N'sp_update_operator')

    AND (type = 'P')))

    DROP PROCEDURE sp_update_operator

    go

    CREATE PROCEDURE sp_update_operator

    @name sysname,

    @new_name sysname = NULL,

    @enabled TINYINT = NULL,

    @email_address NVARCHAR(100) = NULL,

    @pager_address NVARCHAR(100) = NULL,

    @weekday_pager_start_time INT = NULL, -- HHMMSS using 24 hour clock

    @weekday_pager_end_time INT = NULL, -- As above

    @saturday_pager_start_time INT = NULL, -- As above

    @saturday_pager_end_time INT = NULL, -- As above

    @sunday_pager_start_time INT = NULL, -- As above

    @sunday_pager_end_time INT = NULL, -- As above

    @pager_days TINYINT = NULL,

    @netsend_address NVARCHAR(100) = NULL, -- New for 7.0

    @category_name sysname = NULL -- New for 7.0

    AS

    BEGIN

    DECLARE @x_enabled TINYINT

    DECLARE @x_email_address NVARCHAR(100)

    DECLARE @x_pager_address NVARCHAR(100)

    DECLARE @x_weekday_pager_start_time INT

    DECLARE @x_weekday_pager_end_time INT

    DECLARE @x_saturday_pager_start_time INT

    DECLARE @x_saturday_pager_end_time INT

    DECLARE @x_sunday_pager_start_time INT

    DECLARE @x_sunday_pager_end_time INT

    DECLARE @x_pager_days TINYINT

    DECLARE @x_netsend_address NVARCHAR(100)

    DECLARE @x_category_id INT

    DECLARE @return_code INT

    DECLARE @notification_method INT

    DECLARE @alert_fail_safe_operator sysname

    DECLARE @current_msx_server NVARCHAR(30)

    DECLARE @category_id INT

    SET NOCOUNT ON

    -- Remove any leading/trailing spaces from parameters

    SELECT @name = LTRIM(RTRIM(@name))

    SELECT @new_name = LTRIM(RTRIM(@new_name))

    SELECT @email_address = LTRIM(RTRIM(@email_address))

    SELECT @pager_address = LTRIM(RTRIM(@pager_address))

    SELECT @netsend_address = LTRIM(RTRIM(@netsend_address))

    SELECT @category_name = LTRIM(RTRIM(@category_name))

    -- Only a sysadmin can do this

    IF (ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) <> 1)

    BEGIN

    RAISERROR(15003, 16, 1, N'sysadmin')

    RETURN(1) -- Failure

    END

    -- Check if this Operator exists

    IF (NOT EXISTS (SELECT *

    FROM msdb.dbo.sysoperators

    WHERE (name = @name)))

    BEGIN

    RAISERROR(14262, 16, 1, '@name', @name)

    RETURN(1) -- Failure

    END

    -- Check if this operator is 'MSXOperator'

    IF (@name = N'MSXOperator')

    BEGIN

    -- Disallow the update operation if we're at a TSX for all callers other than xp_msx_enlist

    EXECUTE master.dbo.xp_instance_regread N'HKEY_LOCAL_MACHINE',

    N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',

    N'MSXServerName',

    @current_msx_server OUTPUT,

    N'no_output'

    IF ((@current_msx_server IS NOT NULL) AND (PROGRAM_NAME() <> N'xp_msx_enlist'))

    BEGIN

    RAISERROR(14223, 16, 1, 'MSXOperator', 'TSX')

    RETURN(1) -- Failure

    END

    END

    -- Get existing (@x_) operator property values

    SELECT @x_enabled = enabled,

    @x_email_address = email_address,

    @x_pager_address = pager_address,

    @x_weekday_pager_start_time = weekday_pager_start_time,

    @x_weekday_pager_end_time = weekday_pager_end_time,

    @x_saturday_pager_start_time = saturday_pager_start_time,

    @x_saturday_pager_end_time = saturday_pager_end_time,

    @x_sunday_pager_start_time = sunday_pager_start_time,

    @x_sunday_pager_end_time = sunday_pager_end_time,

    @x_pager_days = pager_days,

    @x_netsend_address = netsend_address,

    @x_category_id = category_id

    FROM msdb.dbo.sysoperators

    WHERE (name = @name)

    -- Fill out the values for all non-supplied parameters from the existsing values

    IF (@enabled IS NULL) SELECT @enabled = @x_enabled

    IF (@email_address IS NULL) SELECT @email_address = @x_email_address

    IF (@pager_address IS NULL) SELECT @pager_address = @x_pager_address

    IF (@weekday_pager_start_time IS NULL) SELECT @weekday_pager_start_time = @x_weekday_pager_start_time

    IF (@weekday_pager_end_time IS NULL) SELECT @weekday_pager_end_time = @x_weekday_pager_end_time

    IF (@saturday_pager_start_time IS NULL) SELECT @saturday_pager_start_time = @x_saturday_pager_start_time

    IF (@saturday_pager_end_time IS NULL) SELECT @saturday_pager_end_time = @x_saturday_pager_end_time

    IF (@sunday_pager_start_time IS NULL) SELECT @sunday_pager_start_time = @x_sunday_pager_start_time

    IF (@sunday_pager_end_time IS NULL) SELECT @sunday_pager_end_time = @x_sunday_pager_end_time

    IF (@pager_days IS NULL) SELECT @pager_days = @x_pager_days

    IF (@netsend_address IS NULL) SELECT @netsend_address = @x_netsend_address

    IF (@category_name IS NULL) SELECT @category_name = name FROM msdb.dbo.syscategories WHERE (category_id = @x_category_id)

    IF (@category_name IS NULL)

    BEGIN

    SELECT @category_name = name

    FROM msdb.dbo.syscategories

    WHERE (category_id = 99)

    END

    -- Turn [nullable] empty string parameters into NULLs

    IF (@email_address = N'') SELECT @email_address = NULL

    IF (@pager_address = N'') SELECT @pager_address = NULL

    IF (@netsend_address = N'') SELECT @netsend_address = NULL

    IF (@category_name = N'') SELECT @category_name = NULL

    -- Verify the operator

    EXECUTE @return_code = sp_verify_operator @new_name,

    @enabled,

    @pager_days,

    @weekday_pager_start_time,

    @weekday_pager_end_time,

    @saturday_pager_start_time,

    @saturday_pager_end_time,

    @sunday_pager_start_time,

    @sunday_pager_end_time,

    @category_name,

    @category_id OUTPUT

    IF (@return_code <> 0)

    RETURN(1) -- Failure

    -- If no new name is supplied, use the old one

    -- NOTE: We must do this AFTER calling sp_verify_operator.

    IF (@new_name IS NULL)

    SELECT @new_name = @name

    ELSE

    BEGIN

    -- You can't rename the MSXOperator

    IF (@name = N'MSXOperator')

    BEGIN

    RAISERROR(14222, 16, 1, 'MSXOperator')

    RETURN(1) -- Failure

    END

    END

    -- Do the UPDATE

    UPDATE msdb.dbo.sysoperators

    SET name = @new_name,

    enabled = @enabled,

    email_address = @email_address,

    pager_address = @pager_address,

    weekday_pager_start_time = @weekday_pager_start_time,

    weekday_pager_end_time = @weekday_pager_end_time,

    saturday_pager_start_time = @saturday_pager_start_time,

    saturday_pager_end_time = @saturday_pager_end_time,

    sunday_pager_start_time = @sunday_pager_start_time,

    sunday_pager_end_time = @sunday_pager_end_time,

    pager_days = @pager_days,

    netsend_address = @netsend_address,

    category_id = @category_id

    WHERE (name = @name)

    -- Check if the operator is 'MSXOperator', in which case we need to re-enlist all the targets

    -- so that they will download the new MSXOperator details

    IF ((@name = N'MSXOperator') AND ((SELECT COUNT(*) FROM msdb.dbo.systargetservers) > 0))

    EXECUTE msdb.dbo.sp_post_msx_operation 'RE-ENLIST', 'SERVER', 0x00

    -- Check if this operator is the FailSafe Operator

    EXECUTE master.dbo.xp_instance_regread N'HKEY_LOCAL_MACHINE',

    N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',

    N'AlertFailSafeOperator',

    @alert_fail_safe_operator OUTPUT,

    N'no_output'

    -- If it is, we update the 4 'AlertFailSafe...' registry entries and AlertNotificationMethod

    IF (LTRIM(RTRIM(@alert_fail_safe_operator)) = @name)

    BEGIN

    -- Update AlertFailSafeX values

    EXECUTE master.dbo.xp_instance_regwrite N'HKEY_LOCAL_MACHINE',

    N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',

    N'AlertFailSafeOperator',

    N'REG_SZ',

    @new_name

    EXECUTE master.dbo.xp_instance_regwrite N'HKEY_LOCAL_MACHINE',

    N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',

    N'AlertFailSafeEmailAddress',

    N'REG_SZ',

    @email_address

    EXECUTE master.dbo.xp_instance_regwrite N'HKEY_LOCAL_MACHINE',

    N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',

    N'AlertFailSafePagerAddress',

    N'REG_SZ',

    @pager_address

    EXECUTE master.dbo.xp_instance_regwrite N'HKEY_LOCAL_MACHINE',

    N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',

    N'AlertFailSafeNetSendAddress',

    N'REG_SZ',

    @netsend_address

    -- Update AlertNotificationMethod values

    EXECUTE master.dbo.xp_instance_regread N'HKEY_LOCAL_MACHINE',

    N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',

    N'AlertNotificationMethod',

    @notification_method OUTPUT,

    N'no_output'

    IF (LTRIM(RTRIM(@email_address)) IS NULL)

    SELECT @notification_method = @notification_method & ~1

    IF (LTRIM(RTRIM(@pager_address)) IS NULL)

    SELECT @notification_method = @notification_method & ~2

    IF (LTRIM(RTRIM(@netsend_address)) IS NULL)

    SELECT @notification_method = @notification_method & ~4

    EXECUTE master.dbo.xp_instance_regwrite N'HKEY_LOCAL_MACHINE',

    N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',

    N'AlertNotificationMethod',

    N'REG_DWORD',

    @notification_method

    -- And finally, let SQLServerAgent know of the changes

    EXECUTE msdb.dbo.sp_sqlagent_notify @op_type = N'G'

    END

    RETURN(0) -- Success

    END

    go

    /**************************************************************/

    /* SP_DELETE_OPERATOR */

    /**************************************************************/

    PRINT ''

    PRINT 'Creating procedure sp_delete_operator...'

    go

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = N'sp_delete_operator')

    AND (type = 'P')))

    DROP PROCEDURE sp_delete_operator

    go

    CREATE PROCEDURE sp_delete_operator

    @name sysname,

    @reassign_to_operator sysname = NULL

    AS

    BEGIN

    DECLARE @id INT

    DECLARE @alert_fail_safe_operator sysname

    DECLARE @job_id UNIQUEIDENTIFIER

    DECLARE @job_id_as_char VARCHAR(36)

    DECLARE @notify_email_operator_id INT

    DECLARE @notify_netsend_operator_id INT

    DECLARE @notify_page_operator_id INT

    DECLARE @reassign_to_id INT

    DECLARE @cmd NVARCHAR(512)

    DECLARE @current_msx_server NVARCHAR(30)

    SET NOCOUNT ON

    -- Remove any leading/trailing spaces from parameters

    SELECT @name = LTRIM(RTRIM(@name))

    SELECT @reassign_to_operator = LTRIM(RTRIM(@reassign_to_operator))

    -- Turn [nullable] empty string parameters into NULLs

    IF (@reassign_to_operator = N'') SELECT @reassign_to_operator = NULL

    -- Only a sysadmin can do this

    IF (ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) <> 1)

    BEGIN

    RAISERROR(15003, 16, 1, N'sysadmin')

    RETURN(1) -- Failure

    END

    -- Check if this Operator exists

    IF (NOT EXISTS (SELECT *

    FROM msdb.dbo.sysoperators

    WHERE (name = @name)))

    BEGIN

    RAISERROR(14262, 16, 1, '@name', @name)

    RETURN(1) -- Failure

    END

    -- Check if this operator the FailSafe Operator

    EXECUTE master.dbo.xp_instance_regread N'HKEY_LOCAL_MACHINE',

    N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',

    N'AlertFailSafeOperator',

    @alert_fail_safe_operator OUTPUT,

    N'no_output'

    -- If it is, we disallow the delete operation

    IF (LTRIM(RTRIM(@alert_fail_safe_operator)) = @name)

    BEGIN

    RAISERROR(14504, 16, 1, @name, @name)

    RETURN(1) -- Failure

    END

    -- Check if this operator is 'MSXOperator'

    IF (@name = N'MSXOperator')

    BEGIN

    DECLARE @server_type VARCHAR(3)

    -- Disallow the delete operation if we're an MSX or a TSX

    EXECUTE master.dbo.xp_instance_regread N'HKEY_LOCAL_MACHINE',

    N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',

    N'MSXServerName',

    @current_msx_server OUTPUT,

    N'no_output'

    IF (@current_msx_server IS NOT NULL)

    SELECT @server_type = 'TSX'

    IF ((SELECT COUNT(*)

    FROM msdb.dbo.systargetservers) > 0)

    SELECT @server_type = 'MSX'

    IF (@server_type IS NOT NULL)

    BEGIN

    RAISERROR(14223, 16, 1, 'MSXOperator', @server_type)

    RETURN(1) -- Failure

    END

    END

    -- Convert the Name to it's ID

    SELECT @id = id

    FROM msdb.dbo.sysoperators

    WHERE (name = @name)

    IF (@reassign_to_operator IS NOT NULL)

    BEGIN

    -- On a TSX or standalone server, disallow re-assigning to the MSXOperator

    IF (@reassign_to_operator = N'MSXOperator') AND

    (NOT EXISTS (SELECT *

    FROM msdb.dbo.systargetservers))

    BEGIN

    RAISERROR(14251, -1, -1, @reassign_to_operator)

    RETURN(1) -- Failure

    END

    SELECT @reassign_to_id = id

    FROM msdb.dbo.sysoperators

    WHERE (name = @reassign_to_operator)

    IF (@reassign_to_id IS NULL)

    BEGIN

    RAISERROR(14262, -1, -1, '@reassign_to_operator', @reassign_to_operator)

    RETURN(1) -- Failure

    END

    END

    -- Double up any single quotes in @reassign_to_operator

    IF (@reassign_to_operator IS NOT NULL)

    SELECT @reassign_to_operator = REPLACE(@reassign_to_operator, N'''', N'''''')

    BEGIN TRANSACTION

    -- Reassign (or delete) any sysnotifications rows that reference this operator

    IF (@reassign_to_operator IS NOT NULL)

    BEGIN

    UPDATE msdb.dbo.sysnotifications

    SET operator_id = @reassign_to_id

    WHERE (operator_id = @id)

    AND (NOT EXISTS (SELECT *

    FROM msdb.dbo.sysnotifications sn2

    WHERE (sn2.alert_id = msdb.dbo.sysnotifications.alert_id)

    AND (sn2.operator_id = @reassign_to_id)))

    END

    DELETE FROM msdb.dbo.sysnotifications

    WHERE (operator_id = @id)

    -- Update any jobs that reference this operator

    DECLARE jobs_referencing_this_operator CURSOR LOCAL

    FOR

    SELECT job_id,

    notify_email_operator_id,

    notify_netsend_operator_id,

    notify_page_operator_id

    FROM msdb.dbo.sysjobs

    WHERE (notify_email_operator_id = @id)

    OR (notify_netsend_operator_id = @id)

    OR (notify_page_operator_id = @id)

    OPEN jobs_referencing_this_operator

    FETCH NEXT FROM jobs_referencing_this_operator INTO @job_id,

    @notify_email_operator_id,

    @notify_netsend_operator_id,

    @notify_page_operator_id

    WHILE (@@fetch_status = 0)

    BEGIN

    SELECT @job_id_as_char = CONVERT(VARCHAR(36), @job_id)

    SELECT @cmd = N'msdb.dbo.sp_update_job @job_id = ''' + @job_id_as_char + N''', '

    IF (@notify_email_operator_id = @id)

    IF (@reassign_to_operator IS NOT NULL)

    SELECT @cmd = @cmd + N'@notify_email_operator_name = N''' + @reassign_to_operator + N''', '

    ELSE

    SELECT @cmd = @cmd + N'@notify_email_operator_name = N'''', @notify_level_email = 0, '

    IF (@notify_netsend_operator_id = @id)

    IF (@reassign_to_operator IS NOT NULL)

    SELECT @cmd = @cmd + N'@notify_netsend_operator_name = N''' + @reassign_to_operator + N''', '

    ELSE

    SELECT @cmd = @cmd + N'@notify_netsend_operator_name = N'''', @notify_level_netsend = 0, '

    IF (@notify_page_operator_id = @id)

    IF (@reassign_to_operator IS NOT NULL)

    SELECT @cmd = @cmd + N'@notify_page_operator_name = N''' + @reassign_to_operator + N''', '

    ELSE

    SELECT @cmd = @cmd + N'@notify_page_operator_name = N'''', @notify_level_page = 0, '

    SELECT @cmd = SUBSTRING(@cmd, 1, (DATALENGTH(@cmd) / 2) - 2)

    EXECUTE (N'EXECUTE ' + @cmd)

    FETCH NEXT FROM jobs_referencing_this_operator INTO @job_id,

    @notify_email_operator_id,

    @notify_netsend_operator_id,

    @notify_page_operator_id

    END

    DEALLOCATE jobs_referencing_this_operator

    -- Finally, do the actual DELETE

    DELETE FROM msdb.dbo.sysoperators

    WHERE (id = @id)

    COMMIT TRANSACTION

    RETURN(@@error) -- 0 means success

    END

    go

    /**************************************************************/

    /* SP_HELP_OPERATOR */

    /**************************************************************/

    PRINT ''

    PRINT 'Creating procedure sp_help_operator...'

    go

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = N'sp_help_operator')

    AND (type = 'P')))

    DROP PROCEDURE sp_help_operator

    go

    CREATE PROCEDURE sp_help_operator

    @operator_name sysname = NULL,

    @operator_id INT = NULL

    AS

    BEGIN

    DECLARE @operator_id_as_char VARCHAR(10)

    SET NOCOUNT ON

    -- Remove any leading/trailing spaces from parameters

    SELECT @operator_name = LTRIM(RTRIM(@operator_name))

    IF (@operator_name = '') SELECT @operator_name = NULL

    -- Check operator name

    IF (@operator_name IS NOT NULL)

    BEGIN

    IF (NOT EXISTS (SELECT *

    FROM msdb.dbo.sysoperators

    WHERE (name = @operator_name)))

    BEGIN

    RAISERROR(14262, -1, -1, '@operator_name', @operator_name)

    RETURN(1) -- Failure

    END

    END

    -- Check operator id

    IF (@operator_id IS NOT NULL)

    BEGIN

    IF (NOT EXISTS (SELECT *

    FROM msdb.dbo.sysoperators

    WHERE (id = @operator_id)))

    BEGIN

    SELECT @operator_id_as_char = CONVERT(VARCHAR, @operator_id)

    RAISERROR(14262, -1, -1, '@operator_id', @operator_id_as_char)

    RETURN(1) -- Failure

    END

    END

    SELECT so.id,

    so.name,

    so.enabled,

    so.email_address,

    so.last_email_date,

    so.last_email_time,

    so.pager_address,

    so.last_pager_date,

    so.last_pager_time,

    so.weekday_pager_start_time,

    so.weekday_pager_end_time,

    so.saturday_pager_start_time,

    so.saturday_pager_end_time,

    so.sunday_pager_start_time,

    so.sunday_pager_end_time,

    so.pager_days,

    so.netsend_address,

    so.last_netsend_date,

    so.last_netsend_time,

    category_name = sc.name

    FROM msdb.dbo.sysoperators so

    LEFT OUTER JOIN msdb.dbo.syscategories sc ON (so.category_id = sc.category_id)

    WHERE ((@operator_name IS NULL) OR (so.name = @operator_name))

    AND ((@operator_id IS NULL) OR (so.id = @operator_id))

    ORDER BY so.name

    RETURN(@@error) -- 0 means success

    END

    go

    /**************************************************************/

    /* SP_HELP_OPERATOR_JOBS */

    /**************************************************************/

    PRINT ''

    PRINT 'Creating procedure sp_help_operator_jobs...'

    go

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = 'sp_help_operator_jobs')

    AND (type = 'P')))

    DROP PROCEDURE sp_help_operator_jobs

    go

    CREATE PROCEDURE sp_help_operator_jobs

    @operator_name sysname = NULL

    AS

    BEGIN

    DECLARE @operator_id INT

    SET NOCOUNT ON

    -- Check operator name

    SELECT @operator_id = id

    FROM msdb.dbo.sysoperators

    WHERE (name = @operator_name)

    IF (@operator_id IS NULL)

    BEGIN

    RAISERROR(14262, -1, -1, '@operator_name', @operator_name)

    RETURN(1) -- Failure

    END

    -- Get the job info

    SELECT job_id, name, notify_level_email, notify_level_netsend, notify_level_page

    FROM msdb.dbo.sysjobs_view

    WHERE ((notify_email_operator_id = @operator_id) AND (notify_level_email <> 0))

    OR ((notify_netsend_operator_id = @operator_id) AND (notify_level_netsend <> 0))

    OR ((notify_page_operator_id = @operator_id) AND (notify_level_page <> 0))

    RETURN(0) -- Success

    END

    go

    /**************************************************************/

    /* SP_VERIFY_NOTIFICATION */

    /**************************************************************/

    PRINT ''

    PRINT 'Creating procedure sp_verify_notification...'

    go

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = N'sp_verify_notification')

    AND (type = 'P')))

    DROP PROCEDURE sp_verify_notification

    go

    CREATE PROCEDURE sp_verify_notification

    @alert_name sysname,

    @operator_name sysname,

    @notification_method TINYINT,

    @alert_id INT OUTPUT,

    @operator_id INT OUTPUT

    AS

    BEGIN

    DECLARE @res_valid_range NVARCHAR(100)

    SET NOCOUNT ON

    SELECT @res_valid_range = FORMATMESSAGE(14208)

    -- Remove any leading/trailing spaces from parameters

    SELECT @alert_name = LTRIM(RTRIM(@alert_name))

    SELECT @operator_name = LTRIM(RTRIM(@operator_name))

    -- Check if the AlertName is valid

    SELECT @alert_id = id

    FROM msdb.dbo.sysalerts

    WHERE (name = @alert_name)

    IF (@alert_id IS NULL)

    BEGIN

    RAISERROR(14262, 16, 1, '@alert_name', @alert_name)

    RETURN(1) -- Failure

    END

    -- Check if the OperatorName is valid

    SELECT @operator_id = id

    FROM msdb.dbo.sysoperators

    WHERE (name = @operator_name)

    IF (@operator_id IS NULL)

    BEGIN

    RAISERROR(14262, 16, 1, '@operator_name', @operator_name)

    RETURN(1) -- Failure

    END

    -- If we're at a TSX, we disallow using operator 'MSXOperator'

    IF (NOT EXISTS (SELECT *

    FROM msdb.dbo.systargetservers)) AND

    (@operator_name = N'MSXOperator')

    BEGIN

    RAISERROR(14251, -1, -1, @operator_name)

    RETURN(1) -- Failure

    END

    -- Check if the NotificationMethod is valid

    IF ((@notification_method 7))

    BEGIN

    RAISERROR(14266, 16, 1, '@notification_method', @res_valid_range)

    RETURN(1) -- Failure

    END

    RETURN(0) -- Success

    END

    go

    /**************************************************************/

    /* SP_ADD_NOTIFICATION */

    /**************************************************************/

    PRINT ''

    PRINT 'Creating procedure sp_add_notification...'

    go

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = N'sp_add_notification')

    AND (type = 'P')))

    DROP PROCEDURE sp_add_notification

    go

    CREATE PROCEDURE sp_add_notification

    @alert_name sysname,

    @operator_name sysname,

    @notification_method TINYINT -- 1 = Email, 2 = Pager, 4 = NetSend, 7 = All

    AS

    BEGIN

    DECLARE @alert_id INT

    DECLARE @operator_id INT

    DECLARE @notification NVARCHAR(512)

    DECLARE @retval INT

    DECLARE @old_has_notification INT

    DECLARE @new_has_notification INT

    DECLARE @res_notification NVARCHAR(100)

    SET NOCOUNT ON

    SELECT @res_notification = FORMATMESSAGE(14210)

    -- Remove any leading/trailing spaces from parameters

    SELECT @alert_name = LTRIM(RTRIM(@alert_name))

    SELECT @operator_name = LTRIM(RTRIM(@operator_name))

    -- Only a sysadmin can do this

    IF (ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) <> 1)

    BEGIN

    RAISERROR(15003, 16, 1, N'sysadmin')

    RETURN(1) -- Failure

    END

    -- Check if the Notification is valid

    EXECUTE @retval = msdb.dbo.sp_verify_notification @alert_name,

    @operator_name,

    @notification_method,

    @alert_id OUTPUT,

    @operator_id OUTPUT

    IF (@retval <> 0)

    RETURN(1) -- Failure

    -- Check if this notification already exists

    -- NOTE: The unique index would catch this, but testing for the problem here lets us

    -- control the message.

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysnotifications

    WHERE (alert_id = @alert_id)

    AND (operator_id = @operator_id)))

    BEGIN

    SELECT @notification = @alert_name + N' / ' + @operator_name + N' / ' + CONVERT(NVARCHAR, @notification_method)

    RAISERROR(14261, 16, 1, @res_notification, @notification)

    RETURN(1) -- Failure

    END

    SELECT @old_has_notification = has_notification

    FROM msdb.dbo.sysalerts

    WHERE (id = @alert_id)

    -- Do the INSERT

    INSERT INTO msdb.dbo.sysnotifications

    (alert_id,

    operator_id,

    notification_method)

    VALUES (@alert_id,

    @operator_id,

    @notification_method)

    SELECT @retval = @@error

    SELECT @new_has_notification = has_notification

    FROM msdb.dbo.sysalerts

    WHERE (id = @alert_id)

    -- Notify SQLServerAgent of the change - if any - to has_notifications

    IF (@old_has_notification <> @new_has_notification)

    EXECUTE msdb.dbo.sp_sqlagent_notify @op_type = N'A',

    @alert_id = @alert_id,

    @action_type = N'U'

    RETURN(@retval) -- 0 means success

    END

    go

    /**************************************************************/

    /* SP_UPDATE_NOTIFICATION */

    /**************************************************************/

    PRINT ''

    PRINT 'Creating procedure sp_update_notification...'

    go

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = N'sp_update_notification')

    AND (type = 'P')))

    DROP PROCEDURE sp_update_notification

    go

    CREATE PROCEDURE sp_update_notification

    @alert_name sysname,

    @operator_name sysname,

    @notification_method TINYINT -- 1 = Email, 2 = Pager, 4 = NetSend, 7 = All

    AS

    BEGIN

    DECLARE @alert_id INT

    DECLARE @operator_id INT

    DECLARE @notification NVARCHAR(512)

    DECLARE @retval INT

    DECLARE @old_has_notification INT

    DECLARE @new_has_notification INT

    DECLARE @res_notification NVARCHAR(100)

    SET NOCOUNT ON

    SELECT @res_notification = FORMATMESSAGE(14210)

    -- Remove any leading/trailing spaces from parameters

    SELECT @alert_name = LTRIM(RTRIM(@alert_name))

    SELECT @operator_name = LTRIM(RTRIM(@operator_name))

    -- Only a sysadmin can do this

    IF (ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) <> 1)

    BEGIN

    RAISERROR(15003, 16, 1, N'sysadmin')

    RETURN(1) -- Failure

    END

    -- Check if the Notification is valid

    EXECUTE sp_verify_notification @alert_name,

    @operator_name,

    @notification_method,

    @alert_id OUTPUT,

    @operator_id OUTPUT

    -- Check if this notification exists

    IF (NOT EXISTS (SELECT *

    FROM msdb.dbo.sysnotifications

    WHERE (alert_id = @alert_id)

    AND (operator_id = @operator_id)))

    BEGIN

    SELECT @notification = @alert_name + N' / ' + @operator_name

    RAISERROR(14262, 16, 1, @res_notification, @notification)

    RETURN(1) -- Failure

    END

    SELECT @old_has_notification = has_notification

    FROM msdb.dbo.sysalerts

    WHERE (id = @alert_id)

    -- Do the UPDATE

    UPDATE msdb.dbo.sysnotifications

    SET notification_method = @notification_method

    WHERE (alert_id = @alert_id)

    AND (operator_id = @operator_id)

    SELECT @retval = @@error

    SELECT @new_has_notification = has_notification

    FROM msdb.dbo.sysalerts

    WHERE (id = @alert_id)

    -- Notify SQLServerAgent of the change - if any - to has_notifications

    IF (@old_has_notification <> @new_has_notification)

    EXECUTE msdb.dbo.sp_sqlagent_notify @op_type = N'A',

    @alert_id = @alert_id,

    @action_type = N'U'

    RETURN(@retval) -- 0 means success

    END

    go

    /**************************************************************/

    /* SP_DELETE_NOTIFICATION */

    /**************************************************************/

    PRINT ''

    PRINT 'Creating procedure sp_delete_notification...'

    go

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = N'sp_delete_notification')

    AND (type = 'P')))

    DROP PROCEDURE sp_delete_notification

    go

    CREATE PROCEDURE sp_delete_notification

    @alert_name sysname,

    @operator_name sysname

    AS

    BEGIN

    DECLARE @alert_id INT

    DECLARE @operator_id INT

    DECLARE @ignored TINYINT

    DECLARE @notification NVARCHAR(512)

    DECLARE @retval INT

    DECLARE @old_has_notification INT

    DECLARE @new_has_notification INT

    DECLARE @res_notification NVARCHAR(100)

    SET NOCOUNT ON

    SELECT @res_notification = FORMATMESSAGE(14210)

    -- Remove any leading/trailing spaces from parameters

    SELECT @alert_name = LTRIM(RTRIM(@alert_name))

    SELECT @operator_name = LTRIM(RTRIM(@operator_name))

    -- Only a sysadmin can do this

    IF (ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) <> 1)

    BEGIN

    RAISERROR(15003, 16, 1, N'sysadmin')

    RETURN(1) -- Failure

    END

    -- Get the alert and operator ID's

    EXECUTE sp_verify_notification @alert_name,

    @operator_name,

    7, -- A dummy (but valid) value

    @alert_id OUTPUT,

    @operator_id OUTPUT

    -- Check if this notification exists

    IF (NOT EXISTS (SELECT *

    FROM msdb.dbo.sysnotifications

    WHERE (alert_id = @alert_id)

    AND (operator_id = @operator_id)))

    BEGIN

    SELECT @notification = @alert_name + N' / ' + @operator_name

    RAISERROR(14262, 16, 1, @res_notification, @notification)

    RETURN(1) -- Failure

    END

    SELECT @old_has_notification = has_notification

    FROM msdb.dbo.sysalerts

    WHERE (id = @alert_id)

    -- Do the Delete

    DELETE FROM msdb.dbo.sysnotifications

    WHERE (alert_id = @alert_id)

    AND (operator_id = @operator_id)

    SELECT @retval = @@error

    SELECT @new_has_notification = has_notification

    FROM msdb.dbo.sysalerts

    WHERE (id = @alert_id)

    -- Notify SQLServerAgent of the change - if any - to has_notifications

    IF (@old_has_notification <> @new_has_notification)

    EXECUTE msdb.dbo.sp_sqlagent_notify @op_type = N'A',

    @alert_id = @alert_id,

    @action_type = N'U'

    RETURN(@retval) -- 0 means success

    END

    go

    /**************************************************************/

    /* SP_HELP_NOTIFICATION */

    /**************************************************************/

    PRINT ''

    PRINT 'Creating procedure sp_help_notification...'

    go

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = N'sp_help_notification')

    AND (type = 'P')))

    DROP PROCEDURE sp_help_notification

    go

    CREATE PROCEDURE sp_help_notification

    @object_type CHAR(9), -- Either 'ALERTS' (enumerates Alerts for given Operator)

    -- or 'OPERATORS' (enumerates Operators for given Alert)

    @name sysname, -- Either an Operator Name (if @object_type is 'ALERTS')

    -- or an Alert Name (if @object_type is 'OPERATORS')

    @enum_type CHAR(10), -- Either 'ALL' (enumerate all objects [eg. all alerts irrespective of whether 'Fred' receives a notification for them])

    -- or 'ACTUAL' (enumerate only the associated objects [eg. only the alerts which 'Fred' receives a notification for])

    -- or 'TARGET' (enumerate only the objects matching @target_name [eg. a single row showing how 'Fred' is notfied for alert 'Test'])

    @notification_method TINYINT, -- Either 1 (Email) - Modifies the result set to only show use_email column

    -- or 2 (Pager) - Modifies the result set to only show use_pager column

    -- or 4 (NetSend) - Modifies the result set to only show use_netsend column

    -- or 7 (All) - Modifies the result set to show all the use_xxx columns

    @target_name sysname = NULL -- Either an Alert Name (if @object_type is 'ALERTS')

    -- or an Operator Name (if @object_type is 'OPERATORS')

    -- NOTE: This parameter is only required if @enum_type is 'TARGET')

    AS

    BEGIN

    DECLARE @id INT -- We use this to store the decode of @name

    DECLARE @target_id INT -- We use this to store the decode of @target_name

    DECLARE @select_clause NVARCHAR(1024)

    DECLARE @from_clause NVARCHAR(512)

    DECLARE @where_clause NVARCHAR(512)

    DECLARE @res_valid_range NVARCHAR(100)

    SET NOCOUNT ON

    SELECT @res_valid_range = FORMATMESSAGE(14208)

    -- Remove any leading/trailing spaces from parameters

    SELECT @object_type = UPPER(LTRIM(RTRIM(@object_type)))

    SELECT @name = LTRIM(RTRIM(@name))

    SELECT @enum_type = UPPER(LTRIM(RTRIM(@enum_type)))

    SELECT @target_name = LTRIM(RTRIM(@target_name))

    -- Turn [nullable] empty string parameters into NULLs

    IF (@target_name = N'') SELECT @target_name = NULL

    -- Check ObjectType

    IF (@object_type NOT IN ('ALERTS', 'OPERATORS'))

    BEGIN

    RAISERROR(14266, 16, 1, '@object_type', 'ALERTS, OPERATORS')

    RETURN(1) -- Failure

    END

    -- Check AlertName

    IF (@object_type = 'OPERATORS') AND

    (NOT EXISTS (SELECT *

    FROM msdb.dbo.sysalerts

    WHERE (name = @name)))

    BEGIN

    RAISERROR(14262, 16, 1, '@name', @name)

    RETURN(1) -- Failure

    END

    -- Check OperatorName

    IF (@object_type = 'ALERTS') AND

    (NOT EXISTS (SELECT *

    FROM msdb.dbo.sysoperators

    WHERE (name = @name)))

    BEGIN

    RAISERROR(14262, 16, 1, '@name', @name)

    RETURN(1) -- Failure

    END

    -- Check EnumType

    IF (@enum_type NOT IN ('ALL', 'ACTUAL', 'TARGET'))

    BEGIN

    RAISERROR(14266, 16, 1, '@enum_type', 'ALL, ACTUAL, TARGET')

    RETURN(1) -- Failure

    END

    -- Check Notification Method

    IF ((@notification_method 7))

    BEGIN

    RAISERROR(14266, 16, 1, '@notification_method', @res_valid_range)

    RETURN(1) -- Failure

    END

    -- If EnumType is 'TARGET', check if we have a @TargetName parameter

    IF (@enum_type = 'TARGET') AND (@target_name IS NULL)

    BEGIN

    RAISERROR(14502, 16, 1)

    RETURN(1) -- Failure

    END

    -- If EnumType isn't 'TARGET', we shouldn't have an @target_name parameter

    IF (@enum_type <> 'TARGET') AND (@target_name IS NOT NULL)

    BEGIN

    RAISERROR(14503, 16, 1)

    RETURN(1) -- Failure

    END

    -- Translate the Name into an ID

    IF (@object_type = 'ALERTS')

    BEGIN

    SELECT @id = id

    FROM msdb.dbo.sysoperators

    WHERE (name = @name)

    END

    IF (@object_type = 'OPERATORS')

    BEGIN

    SELECT @id = id

    FROM msdb.dbo.sysalerts

    WHERE (name = @name)

    END

    -- Translate the TargetName into a TargetID

    IF (@target_name IS NOT NULL)

    BEGIN

    IF (@object_type = 'OPERATORS')

    BEGIN

    SELECT @target_id = id

    FROM msdb.dbo.sysoperators

    WHERE (name = @target_name )

    END

    IF (@object_type = 'ALERTS')

    BEGIN

    SELECT @target_id = id

    FROM msdb.dbo.sysalerts

    WHERE (name = @target_name)

    END

    IF (@target_id IS NULL) -- IE. the Target Name is invalid

    BEGIN

    RAISERROR(14262, 16, 1, @object_type, @target_name)

    RETURN(1) -- Failure

    END

    END

    -- Ok, the parameters look good so generate the SQL then EXECUTE() it...

    -- Generate the 'stub' SELECT clause and the FROM clause

    IF (@object_type = 'OPERATORS') -- So we want a list of Operators for the supplied AlertID

    BEGIN

    SELECT @select_clause = N'SELECT operator_id = o.id, operator_name = o.name, '

    IF (@enum_type = 'ALL')

    SELECT @from_clause = N'FROM msdb.dbo.sysoperators o LEFT OUTER JOIN msdb.dbo.sysnotifications sn ON (o.id = sn.operator_id) '

    ELSE

    SELECT @from_clause = N'FROM msdb.dbo.sysoperators o, msdb.dbo.sysnotifications sn '

    END

    IF (@object_type = 'ALERTS') -- So we want a list of Alerts for the supplied OperatorID

    BEGIN

    SELECT @select_clause = N'SELECT alert_id = a.id, alert_name = a.name, '

    IF (@enum_type = 'ALL')

    SELECT @from_clause = N'FROM msdb.dbo.sysalerts a LEFT OUTER JOIN msdb.dbo.sysnotifications sn ON (a.id = sn.alert_id) '

    ELSE

    SELECT @from_clause = N'FROM msdb.dbo.sysalerts a, msdb.dbo.sysnotifications sn '

    END

    -- Add the required use_xxx columns to the SELECT clause

    IF (@notification_method & 1 = 1)

    SELECT @select_clause = @select_clause + N'use_email = ISNULL((sn.notification_method & 1) / POWER(2, 0), 0), '

    IF (@notification_method & 2 = 2)

    SELECT @select_clause = @select_clause + N'use_pager = ISNULL((sn.notification_method & 2) / POWER(2, 1), 0), '

    IF (@notification_method & 4 = 4)

    SELECT @select_clause = @select_clause + N'use_netsend = ISNULL((sn.notification_method & 4) / POWER(2, 2), 0), '

    -- Remove the trailing comma

    SELECT @select_clause = SUBSTRING(@select_clause, 1, (DATALENGTH(@select_clause) / 2) - 2) + N' '

    -- Generate the WHERE clause

    IF (@object_type = 'OPERATORS')

    BEGIN

    IF (@enum_type = 'ALL')

    SELECT @from_clause = @from_clause + N' AND (sn.alert_id = ' + CONVERT(VARCHAR(10), @id) + N')'

    IF (@enum_type = 'ACTUAL')

    SELECT @where_clause = N'WHERE (o.id = sn.operator_id) AND (sn.alert_id = ' + CONVERT(VARCHAR(10), @id) + N') AND (sn.notification_method & ' + CONVERT(VARCHAR, @notification_method) + N' <> 0)'

    IF (@enum_type = 'TARGET')

    SELECT @where_clause = N'WHERE (o.id = sn.operator_id) AND (sn.operator_id = ' + CONVERT(VARCHAR(10), @target_id) + N') AND (sn.alert_id = ' + CONVERT(VARCHAR(10), @id) + N')'

    END

    IF (@object_type = 'ALERTS')

    BEGIN

    IF (@enum_type = 'ALL')

    SELECT @from_clause = @from_clause + N' AND (sn.operator_id = ' + CONVERT(VARCHAR(10), @id) + N')'

    IF (@enum_type = 'ACTUAL')

    SELECT @where_clause = N'WHERE (a.id = sn.alert_id) AND (sn.operator_id = ' + CONVERT(VARCHAR(10), @id) + N') AND (sn.notification_method & ' + CONVERT(VARCHAR, @notification_method) + N' <> 0)'

    IF (@enum_type = 'TARGET')

    SELECT @where_clause = N'WHERE (a.id = sn.alert_id) AND (sn.alert_id = ' + CONVERT(VARCHAR(10), @target_id) + N') AND (sn.operator_id = ' + CONVERT(VARCHAR(10), @id) + N')'

    END

    -- Add the has_email and has_pager columns to the SELECT clause

    IF (@object_type = 'OPERATORS')

    BEGIN

    SELECT @select_clause = @select_clause + N', has_email = PATINDEX(N''%[^ ]%'', ISNULL(o.email_address, N''''))'

    SELECT @select_clause = @select_clause + N', has_pager = PATINDEX(N''%[^ ]%'', ISNULL(o.pager_address, N''''))'

    SELECT @select_clause = @select_clause + N', has_netsend = PATINDEX(N''%[^ ]%'', ISNULL(o.netsend_address, N''''))'

    END

    IF (@object_type = 'ALERTS')

    BEGIN

    -- NOTE: We return counts so that the UI can detect 'unchecking' the last notification

    SELECT @select_clause = @select_clause + N', has_email = (SELECT COUNT(*) FROM sysnotifications WHERE (alert_id = a.id) AND ((notification_method & 1) = 1)) '

    SELECT @select_clause = @select_clause + N', has_pager = (SELECT COUNT(*) FROM sysnotifications WHERE (alert_id = a.id) AND ((notification_method & 2) = 2)) '

    SELECT @select_clause = @select_clause + N', has_netsend = (SELECT COUNT(*) FROM sysnotifications WHERE (alert_id = a.id) AND ((notification_method & 4) = 4)) '

    END

    EXECUTE (@select_clause + @from_clause + @where_clause)

    RETURN(@@error) -- 0 means success

    END

    go

    DUMP TRANSACTION msdb WITH NO_LOG

    go

    /**************************************************************/

    /* */

    /* T R I G G E R S */

    /* */

    /**************************************************************/

    /**************************************************************/

    /* DROP THE OLD 6.x TRIGGERS */

    /* [multiple triggers of the same type are allowed in 7.0] */

    /**************************************************************/

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = N'NewOrChangedNotification')

    AND (type = 'TR')))

    DROP TRIGGER NewOrChangedNotification

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = N'RemovedNotification')

    AND (type = 'TR')))

    DROP TRIGGER RemovedNotification

    go

    /**************************************************************/

    /* TRIG_NOTIFICATION_INS_OR_UPD */

    /**************************************************************/

    PRINT ''

    PRINT 'Creating trigger trig_notification_ins_or_upd...'

    go

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = N'trig_notification_ins_or_upd')

    AND (type = 'TR')))

    DROP TRIGGER trig_notification_ins_or_upd

    go

    CREATE TRIGGER trig_notification_ins_or_upd

    ON msdb.dbo.sysnotifications

    FOR INSERT,

    UPDATE

    AS

    BEGIN

    SET NOCOUNT ON

    -- First, throw out 'non-notification' rows

    DELETE FROM msdb.dbo.sysnotifications

    WHERE (notification_method = 0)

    -- Reset the has_notification flag for the affected alerts

    UPDATE msdb.dbo.sysalerts

    SET has_notification = 0

    FROM inserted i,

    msdb.dbo.sysalerts sa

    WHERE (i.alert_id = sa.id)

    -- Update sysalerts.has_notification (for email)

    UPDATE msdb.dbo.sysalerts

    SET has_notification = has_notification | 1

    FROM msdb.dbo.sysalerts sa,

    msdb.dbo.sysnotifications sn,

    inserted i

    WHERE (sa.id = sn.alert_id)

    AND (sa.id = i.alert_id)

    AND ((sn.notification_method & 1) = 1)

    -- Update sysalerts.has_notification (for pager)

    UPDATE msdb.dbo.sysalerts

    SET has_notification = has_notification | 2

    FROM msdb.dbo.sysalerts sa,

    msdb.dbo.sysnotifications sn,

    inserted i

    WHERE (sa.id = sn.alert_id)

    AND (sa.id = i.alert_id)

    AND ((sn.notification_method & 2) = 2)

    -- Update sysalerts.has_notification (for netsend)

    UPDATE msdb.dbo.sysalerts

    SET has_notification = has_notification | 4

    FROM msdb.dbo.sysalerts sa,

    msdb.dbo.sysnotifications sn,

    inserted i

    WHERE (sa.id = sn.alert_id)

    AND (sa.id = i.alert_id)

    AND ((sn.notification_method & 4) = 4)

    END

    go

    /**************************************************************/

    /* TRIG_NOTIFICATION_DELETE */

    /**************************************************************/

    PRINT ''

    PRINT 'Creating trigger trig_notification_delete...'

    go

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = N'trig_notification_delete')

    AND (type = 'TR')))

    DROP TRIGGER trig_notification_delete

    go

    CREATE TRIGGER trig_notification_delete

    ON msdb.dbo.sysnotifications

    FOR DELETE

    AS

    BEGIN

    SET NOCOUNT ON

    -- Reset the has_notification flag for the affected alerts

    UPDATE msdb.dbo.sysalerts

    SET has_notification = 0

    FROM deleted d,

    msdb.dbo.sysalerts sa

    WHERE (d.alert_id = sa.id)

    -- Update sysalerts.has_notification (for email)

    UPDATE msdb.dbo.sysalerts

    SET has_notification = has_notification | 1

    FROM msdb.dbo.sysalerts sa,

    msdb.dbo.sysnotifications sn,

    deleted d

    WHERE (sa.id = sn.alert_id)

    AND (sa.id = d.alert_id)

    AND ((sn.notification_method & 1) = 1)

    -- Update sysalerts.has_notification (for pager)

    UPDATE msdb.dbo.sysalerts

    SET has_notification = has_notification | 2

    FROM msdb.dbo.sysalerts sa,

    msdb.dbo.sysnotifications sn,

    deleted d

    WHERE (sa.id = sn.alert_id)

    AND (sa.id = d.alert_id)

    AND ((sn.notification_method & 2) = 2)

    -- Update sysalerts.has_notification (for netsend)

    UPDATE msdb.dbo.sysalerts

    SET has_notification = has_notification | 4

    FROM msdb.dbo.sysalerts sa,

    msdb.dbo.sysnotifications sn,

    deleted d

    WHERE (sa.id = sn.alert_id)

    AND (sa.id = d.alert_id)

    AND ((sn.notification_method & 4) = 4)

    END

    go

    DUMP TRANSACTION msdb WITH NO_LOG

    go

    /**************************************************************/

    /* */

    /* D E F A U L T A L E R T S */

    /* */

    /**************************************************************/

    PRINT ''

    PRINT 'Installing default alerts...'

    go

    EXECUTE master.dbo.sp_altermessage 9002, 'WITH_LOG', TRUE

    go

    IF (NOT EXISTS (SELECT *

    FROM msdb.dbo.sysalerts

    WHERE (name = N'Demo: Full msdb log')

    OR ((severity = 0) AND

    (message_id = 9002) AND

    (database_name = N'msdb') AND

    (event_description_keyword IS NULL) AND

    (performance_condition IS NULL))))

    EXECUTE msdb.dbo.sp_add_alert @name = N'Demo: Full msdb log',

    @message_id = 9002,

    @severity = 0,

    @enabled = 1,

    @delay_between_responses = 10,

    @database_name = N'msdb',

    @notification_message = NULL,

    @job_name = NULL,

    @event_description_keyword = NULL,

    @include_event_description_in = 5 -- Email and NetSend

    go

    IF (NOT EXISTS (SELECT *

    FROM msdb.dbo.sysalerts

    WHERE (name = N'Demo: Full tempdb')

    OR ((severity = 0) AND

    (message_id = 9002) AND

    (database_name = N'tempdb') AND

    (event_description_keyword IS NULL) AND

    (performance_condition IS NULL))))

    EXECUTE msdb.dbo.sp_add_alert @name = N'Demo: Full tempdb',

    @message_id = 9002,

    @severity = 0,

    @enabled = 1,

    @delay_between_responses = 10,

    @database_name = N'tempdb',

    @notification_message = NULL,

    @job_name = NULL,

    @event_description_keyword = NULL,

    @include_event_description_in = 5 -- Email and NetSend

    go

    IF (NOT EXISTS (SELECT *

    FROM msdb.dbo.sysalerts

    WHERE (name = N'Demo: Sev. 19 Errors')

    OR ((severity = 19) AND

    (message_id = 0) AND

    (database_name IS NULL) AND

    (event_description_keyword IS NULL) AND

    (performance_condition IS NULL))))

    EXECUTE msdb.dbo.sp_add_alert @name = N'Demo: Sev. 19 Errors',

    @message_id = 0,

    @severity = 19,

    @enabled = 1,

    @delay_between_responses = 10,

    @database_name = NULL,

    @notification_message = NULL,

    @job_name = NULL,

    @event_description_keyword = NULL,

    @include_event_description_in = 5 -- Email and NetSend

    go

    IF (NOT EXISTS (SELECT *

    FROM msdb.dbo.sysalerts

    WHERE (name = N'Demo: Sev. 20 Errors')

    OR ((severity = 20) AND

    (message_id = 0) AND

    (database_name IS NULL) AND

    (event_description_keyword IS NULL) AND

    (performance_condition IS NULL))))

    EXECUTE msdb.dbo.sp_add_alert @name = N'Demo: Sev. 20 Errors',

    @message_id = 0,

    @severity = 20,

    @enabled = 1,

    @delay_between_responses = 10,

    @database_name = NULL,

    @notification_message = NULL,

    @job_name = NULL,

    @event_description_keyword = NULL,

    @include_event_description_in = 5 -- Email and NetSend

    go

    IF (NOT EXISTS (SELECT *

    FROM msdb.dbo.sysalerts

    WHERE (name = N'Demo: Sev. 21 Errors')

    OR ((severity = 21) AND

    (message_id = 0) AND

    (database_name IS NULL) AND

    (event_description_keyword IS NULL) AND

    (performance_condition IS NULL))))

    EXECUTE msdb.dbo.sp_add_alert @name = N'Demo: Sev. 21 Errors',

    @message_id = 0,

    @severity = 21,

    @enabled = 1,

    @delay_between_responses = 10,

    @database_name = NULL,

    @notification_message = NULL,

    @job_name = NULL,

    @event_description_keyword = NULL,

    @include_event_description_in = 5 -- Email and NetSend

    go

    IF (NOT EXISTS (SELECT *

    FROM msdb.dbo.sysalerts

    WHERE (name = N'Demo: Sev. 22 Errors')

    OR ((severity = 22) AND

    (message_id = 0) AND

    (database_name IS NULL) AND

    (event_description_keyword IS NULL) AND

    (performance_condition IS NULL))))

    EXECUTE msdb.dbo.sp_add_alert @name = N'Demo: Sev. 22 Errors',

    @message_id = 0,

    @severity = 22,

    @enabled = 1,

    @delay_between_responses = 10,

    @database_name = NULL,

    @notification_message = NULL,

    @job_name = NULL,

    @event_description_keyword = NULL,

    @include_event_description_in = 5 -- Email and NetSend

    go

    IF (NOT EXISTS (SELECT *

    FROM msdb.dbo.sysalerts

    WHERE name = N'Demo: Sev. 23 Errors'

    OR ((severity = 23) AND

    (message_id = 0) AND

    (database_name IS NULL) AND

    (event_description_keyword IS NULL) AND

    (performance_condition IS NULL))))

    EXECUTE msdb.dbo.sp_add_alert @name = N'Demo: Sev. 23 Errors',

    @message_id = 0,

    @severity = 23,

    @enabled = 1,

    @delay_between_responses = 10,

    @database_name = NULL,

    @notification_message = NULL,

    @job_name = NULL,

    @event_description_keyword = NULL,

    @include_event_description_in = 5 -- Email and NetSend

    go

    IF (NOT EXISTS (SELECT *

    FROM msdb.dbo.sysalerts

    WHERE (name = N'Demo: Sev. 24 Errors')

    OR ((severity = 24) AND

    (message_id = 0) AND

    (database_name IS NULL) AND

    (event_description_keyword IS NULL) AND

    (performance_condition IS NULL))))

    EXECUTE msdb.dbo.sp_add_alert @name = N'Demo: Sev. 24 Errors',

    @message_id = 0,

    @severity = 24,

    @enabled = 1,

    @delay_between_responses = 10,

    @database_name = NULL,

    @notification_message = NULL,

    @job_name = NULL,

    @event_description_keyword = NULL,

    @include_event_description_in = 5 -- Email and NetSend

    go

    IF (NOT EXISTS (SELECT *

    FROM msdb.dbo.sysalerts

    WHERE (name = N'Demo: Sev. 25 Errors')

    OR ((severity = 25) AND

    (message_id = 0) AND

    (database_name IS NULL) AND

    (event_description_keyword IS NULL) AND

    (performance_condition IS NULL))))

    EXECUTE msdb.dbo.sp_add_alert @name = N'Demo: Sev. 25 Errors',

    @message_id = 0,

    @severity = 25,

    @enabled = 1,

    @delay_between_responses = 10,

    @database_name = NULL,

    @notification_message = NULL,

    @job_name = NULL,

    @event_description_keyword = NULL,

    @include_event_description_in = 5 -- Email and NetSend

    go

    /**************************************************************/

    /** **/

    /** B A C K U P H I S T O R Y S U P P O R T **/

    /** **/

    /**************************************************************/

    /**************************************************************/

    /* T A B L E S */

    /**************************************************************/

    /**************************************************************/

    /* BACKUPMEDIASET */

    /**************************************************************/

    IF (NOT EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = 'backupmediaset')))

    BEGIN

    PRINT ''

    PRINT 'Creating table backupmediaset...'

    CREATE TABLE backupmediaset

    (

    media_set_id INT IDENTITY NOT NULL PRIMARY KEY,

    media_uuid UNIQUEIDENTIFIER NULL, -- Null if this media set only one media family

    media_family_count TINYINT NULL, -- Number of media families in the media set

    name NVARCHAR(128) NULL,

    description NVARCHAR(255) NULL,

    software_name NVARCHAR(128) NULL,

    software_vendor_id INT NULL,

    MTF_major_version TINYINT NULL

    )

    CREATE INDEX backupmediasetuuid ON backupmediaset (media_uuid)

    END

    go

    /**************************************************************/

    /* BACKUPMEDIAFAMILY */

    /**************************************************************/

    IF (NOT EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = 'backupmediafamily')))

    BEGIN

    PRINT ''

    PRINT 'Creating table backupmediafamily...'

    CREATE TABLE backupmediafamily

    (

    media_set_id INT NOT NULL REFERENCES backupmediaset(media_set_id),

    family_sequence_number TINYINT NOT NULL, -- Raid sequence number

    media_family_id UNIQUEIDENTIFIER NULL, -- This will be a uuid in MTF 2.0, allow space

    media_count INT NULL, -- Number of media in the family

    logical_device_name NVARCHAR(128) NULL, -- Name from sysdevices, if any

    physical_device_name NVARCHAR(260) NULL, -- To facilitate restores from online media (disk)

    device_type TINYINT NULL, -- Disk, tape, pipe, ...

    physical_block_size INT NULL

    PRIMARY KEY (media_set_id, family_sequence_number)

    )

    CREATE INDEX backupmediafamilyuuid ON backupmediafamily (media_family_id)

    END

    go

    /**************************************************************/

    /* BACKUPSET - One row per backup operation. */

    /**************************************************************/

    IF (NOT EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = 'backupset')))

    BEGIN

    PRINT ''

    PRINT 'Creating table backupset...'

    CREATE TABLE backupset

    (

    backup_set_id INT IDENTITY NOT NULL PRIMARY KEY,

    backup_set_uuid UNIQUEIDENTIFIER NOT NULL,

    media_set_id INT NOT NULL REFERENCES backupmediaset(media_set_id),

    first_family_number TINYINT NULL, -- family number & media number of the media

    first_media_number SMALLINT NULL, -- containing the start of this backup (first SSET)

    last_family_number TINYINT NULL, -- family number & media number of the media

    last_media_number SMALLINT NULL, -- containing the end of this backup (ESET after MBC)

    catalog_family_number TINYINT NULL, -- family number & media number of the media

    catalog_media_number SMALLINT NULL, -- containing the start of the 'directory' data stream

    position INT NULL, -- For FILE=

    expiration_date DATETIME NULL,

    -- From SSET...

    software_vendor_id INT NULL, -- Might want table for sw vendors

    name NVARCHAR(128) NULL,

    description NVARCHAR(255) NULL,

    user_name NVARCHAR(128) NULL,

    software_major_version TINYINT NULL,

    software_minor_version TINYINT NULL,

    software_build_version SMALLINT NULL,

    time_zone SMALLINT NULL,

    mtf_minor_version TINYINT NULL,

    -- From CONFIG_INFO...

    first_lsn NUMERIC(25,0) NULL,

    last_lsn NUMERIC(25,0) NULL,

    checkpoint_lsn NUMERIC(25,0) NULL,

    database_backup_lsn NUMERIC(25,0) NULL,

    database_creation_date DATETIME NULL,

    backup_start_date DATETIME NULL,

    backup_finish_date DATETIME NULL,

    type CHAR(1) NULL,

    sort_order SMALLINT NULL,

    code_page SMALLINT NULL,

    compatibility_level TINYINT NULL,

    database_version INT NULL,

    backup_size NUMERIC(20,0) NULL,

    database_name NVARCHAR(128) NULL,

    server_name NVARCHAR(128) NULL,

    machine_name NVARCHAR(128) NULL,

    flags INT NULL,

    unicode_locale INT NULL,

    unicode_compare_style INT NULL,

    collation_name NVARCHAR(128) NULL

    )

    CREATE INDEX backupsetuuid ON backupset (backup_set_uuid)

    END

    ELSE

    BEGIN

    IF NOT EXISTS (

    select * from msdb.dbo.syscolumns where name='flags' and id =

    (select id from msdb.dbo.sysobjects where name='backupset'))

    ALTER TABLE backupset ADD flags INT NULL

    IF NOT EXISTS (

    select * from msdb.dbo.syscolumns where name='collation_name' and id =

    (select id from msdb.dbo.sysobjects where name='backupset'))

    ALTER TABLE backupset ADD

    unicode_locale INT NULL,

    unicode_compare_style INT NULL,

    collation_name NVARCHAR(128) NULL

    END

    go

    /**************************************************************/

    /* BACKUPFILE - One row per file backed up (data file, log */

    /* file) */

    /**************************************************************/

    IF (NOT EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = 'backupfile')))

    BEGIN

    PRINT ''

    PRINT 'Creating table backupfile...'

    CREATE TABLE backupfile

    (

    backup_set_id INT NOT NULL REFERENCES backupset(backup_set_id),

    first_family_number TINYINT NULL, -- Family number & media number of he first media

    first_media_number SMALLINT NULL, -- containing this file

    filegroup_name NVARCHAR(128) NULL,

    page_size INT NULL,

    file_number NUMERIC(10,0) NOT NULL,

    backed_up_page_count NUMERIC(10,0) NULL,

    file_type CHAR(1) NULL, -- database or log

    source_file_block_size NUMERIC(10,0) NULL,

    file_size NUMERIC(20,0) NULL,

    logical_name NVARCHAR(128) NULL,

    physical_drive VARCHAR(260) NULL, -- Drive or partition name

    physical_name VARCHAR(260) NULL -- Remainder of physical (OS) filename

    PRIMARY KEY (backup_set_id, file_number)

    )

    END

    go

    /**************************************************************/

    /* RESTOREHISTORY - One row per restore operation. */

    /**************************************************************/

    IF (NOT EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = 'restorehistory')))

    BEGIN

    PRINT ''

    PRINT 'Creating table restorehistory...'

    CREATE TABLE restorehistory

    (

    restore_history_id INT NOT NULL IDENTITY PRIMARY KEY,

    restore_date DATETIME NULL,

    destination_database_name NVARCHAR(128) NULL,

    user_name NVARCHAR(128) NULL,

    backup_set_id INT NOT NULL REFERENCES backupset(backup_set_id), -- The backup set restored

    restore_type CHAR(1) NULL, -- Database, file, filegroup, log, verifyonly, ...

    -- Various options...

    replace BIT NULL, -- Replace(1), Noreplace(0)

    recovery BIT NULL, -- Recovery(1), Norecovery(0)

    restart BIT NULL, -- Restart(1), Norestart(0)

    stop_at DATETIME NULL,

    device_count TINYINT NULL, -- Can be less than number of media families

    stop_at_mark_name NVARCHAR(128) NULL,

    stop_before BIT NULL

    )

    CREATE INDEX restorehistorybackupset ON restorehistory (backup_set_id)

    END

    IF (NOT EXISTS (SELECT *

    FROM msdb.dbo.syscolumns

    WHERE (name in ('stop_at_mark_name', 'stop_before'))

    AND (id = (SELECT id

    FROM msdb.dbo.sysobjects

    WHERE (name = 'restorehistory')))))

    BEGIN

    IF NOT EXISTS (

    select * from msdb.dbo.syscolumns where name='stop_before' and id =

    (select id from msdb.dbo.sysobjects where name='restorehistory'))

    BEGIN

    PRINT ''

    PRINT 'Adding columns to table restorehistory...'

    ALTER TABLE restorehistory

    ADD

    stop_at_mark_name NVARCHAR(128) NULL,

    stop_before BIT NULL

    END

    END

    go

    /**************************************************************/

    /* RESTOREFILE - One row per file restored. */

    /**************************************************************/

    IF (NOT EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = 'restorefile')))

    BEGIN

    PRINT ''

    PRINT 'Creating table restorefile...'

    CREATE TABLE restorefile

    (

    restore_history_id INT NOT NULL REFERENCES restorehistory(restore_history_id),

    file_number NUMERIC(10,0) NULL, -- Note: requires database to make unique

    destination_phys_drive VARCHAR(260) NULL,

    destination_phys_name VARCHAR(260) NULL

    )

    END

    go

    /**************************************************************/

    /* RESTOREFILEGROUP - One row per filegroup restored. */

    /**************************************************************/

    IF (NOT EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = 'restorefilegroup')))

    BEGIN

    PRINT ''

    PRINT 'Creating table restorefilegroup...'

    CREATE TABLE restorefilegroup

    (

    restore_history_id INT NOT NULL REFERENCES restorehistory(restore_history_id),

    filegroup_name NVARCHAR(128) NULL

    )

    END

    go

    /**************************************************************/

    /* LOGMARKHISTORY - One row per log mark generated */

    /**************************************************************/

    IF (NOT EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = 'logmarkhistory')))

    BEGIN

    PRINT ''

    PRINT 'Creating table logmarkhistory...'

    CREATE TABLE logmarkhistory

    (

    database_name NVARCHAR(128) NOT NULL,

    mark_name NVARCHAR(128) NOT NULL,

    description NVARCHAR(255) NULL,

    user_name NVARCHAR(128) NOT NULL,

    lsn NUMERIC(25,0) NOT NULL,

    mark_time DATETIME NOT NULL

    )

    CREATE INDEX logmarkhistory1 ON logmarkhistory (database_name, mark_name)

    CREATE INDEX logmarkhistory2 ON logmarkhistory (database_name, lsn)

    END

    go

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = 'trig_backupset_delete')

    AND (OBJECTPROPERTY(id, 'IsTrigger') != 0)))

    BEGIN

    DROP TRIGGER trig_backupset_delete

    END

    go

    CREATE TRIGGER trig_backupset_delete ON msdb.dbo.backupset FOR DELETE AS

    BEGIN

    DELETE FROM msdb.dbo.logmarkhistory from deleted

    WHERE (msdb.dbo.logmarkhistory.database_name = deleted.database_name)

    AND (msdb.dbo.logmarkhistory.lsn >= deleted.first_lsn)

    AND (msdb.dbo.logmarkhistory.lsn < deleted.last_lsn)

    END

    go

    /**************************************************************/

    /** **/

    /** O B J E C T P E R M I S S I O N S **/

    /** **/

    /**************************************************************/

    PRINT ''

    PRINT 'Setting object permissions...'

    go

    -- Permissions a non-SA needs to create/update/delete a job

    GRANT EXECUTE ON sp_get_sqlagent_properties TO PUBLIC

    GRANT EXECUTE ON sp_help_category TO PUBLIC

    GRANT EXECUTE ON sp_enum_sqlagent_subsystems TO PUBLIC

    GRANT EXECUTE ON sp_add_jobserver TO PUBLIC

    GRANT EXECUTE ON sp_delete_jobserver TO PUBLIC

    GRANT SELECT ON syscategories TO PUBLIC

    GRANT EXECUTE ON sp_purge_jobhistory TO PUBLIC

    GRANT EXECUTE ON sp_help_jobhistory TO PUBLIC

    GRANT EXECUTE ON sp_add_jobstep TO PUBLIC

    GRANT EXECUTE ON sp_update_jobstep TO PUBLIC

    GRANT EXECUTE ON sp_delete_jobstep TO PUBLIC

    GRANT EXECUTE ON sp_help_jobstep TO PUBLIC

    GRANT EXECUTE ON sp_add_jobschedule TO PUBLIC

    GRANT EXECUTE ON sp_update_jobschedule TO PUBLIC

    GRANT EXECUTE ON sp_delete_jobschedule TO PUBLIC

    GRANT EXECUTE ON sp_help_jobschedule TO PUBLIC

    GRANT EXECUTE ON sp_add_job TO PUBLIC

    GRANT EXECUTE ON sp_update_job TO PUBLIC

    GRANT EXECUTE ON sp_delete_job TO PUBLIC

    GRANT EXECUTE ON sp_help_job TO PUBLIC

    GRANT EXECUTE ON sp_start_job TO PUBLIC

    GRANT EXECUTE ON sp_stop_job TO PUBLIC

    GRANT EXECUTE ON sp_help_jobserver TO PUBLIC

    GRANT EXECUTE ON sp_check_for_owned_jobs TO PUBLIC

    GRANT EXECUTE ON sp_check_for_owned_jobsteps TO PUBLIC

    GRANT EXECUTE ON sp_get_jobstep_db_username TO PUBLIC

    GRANT EXECUTE ON sp_post_msx_operation TO PUBLIC

    GRANT EXECUTE ON sp_get_job_alerts TO PUBLIC

    GRANT EXECUTE ON sp_uniquetaskname TO PUBLIC

    GRANT EXECUTE ON sp_addtask TO PUBLIC

    GRANT EXECUTE ON sp_updatetask TO PUBLIC

    GRANT EXECUTE ON sp_droptask TO PUBLIC

    GRANT EXECUTE ON sp_helptask TO PUBLIC

    GRANT EXECUTE ON sp_verifytaskid TO PUBLIC

    GRANT EXECUTE ON sp_reassigntask TO PUBLIC

    GRANT EXECUTE ON sp_helphistory TO PUBLIC

    GRANT EXECUTE ON sp_purgehistory TO PUBLIC

    GRANT SELECT ON sysjobs_view TO PUBLIC

    GRANT SELECT ON systasks_view TO PUBLIC

    REVOKE ALL ON systargetservers FROM PUBLIC

    REVOKE ALL ON systargetservers_view FROM PUBLIC

    REVOKE ALL ON systargetservergroups FROM PUBLIC

    REVOKE ALL ON systargetservergroupmembers FROM PUBLIC

    REVOKE INSERT, UPDATE, DELETE ON syscategories FROM PUBLIC

    REVOKE ALL ON sysalerts FROM PUBLIC

    REVOKE ALL ON sysoperators FROM PUBLIC

    REVOKE ALL ON sysnotifications FROM PUBLIC

    GRANT SELECT ON backupfile TO PUBLIC

    GRANT SELECT ON backupmediafamily TO PUBLIC

    GRANT SELECT ON backupmediaset TO PUBLIC

    GRANT SELECT ON backupset TO PUBLIC

    GRANT SELECT ON restorehistory TO PUBLIC

    GRANT SELECT ON restorefile TO PUBLIC

    GRANT SELECT ON restorefilegroup TO PUBLIC

    GRANT SELECT ON logmarkhistory TO PUBLIC

    go

    -- Create the TargetServers role (for use by target servers when downloading jobs / uploading status)

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysusers

    WHERE (name = N'TargetServersRole')

    AND (issqlrole = 1)))

    BEGIN

    -- If there are no members in the role, then drop and re-create it

    IF ((SELECT COUNT(*)

    FROM msdb.dbo.sysusers su,

    msdb.dbo.sysmembers sm

    WHERE (su.uid = sm.groupuid)

    AND (su.name = N'TargetServersRole')

    AND (su.issqlrole = 1)) = 0)

    BEGIN

    EXECUTE msdb.dbo.sp_droprole @rolename = N'TargetServersRole'

    EXECUTE msdb.dbo.sp_addrole @rolename = N'TargetServersRole'

    END

    END

    ELSE

    EXECUTE msdb.dbo.sp_addrole @rolename = N'TargetServersRole'

    GRANT SELECT, UPDATE, DELETE ON sysdownloadlist TO TargetServersRole

    GRANT SELECT, UPDATE ON sysjobservers TO TargetServersRole

    GRANT SELECT, UPDATE ON systargetservers TO TargetServersRole

    GRANT EXECUTE ON sp_downloaded_row_limiter TO TargetServersRole

    GRANT SELECT ON sysjobs TO TargetServersRole

    GRANT EXECUTE ON sp_help_jobstep TO TargetServersRole

    GRANT EXECUTE ON sp_help_jobschedule TO TargetServersRole

    GRANT EXECUTE ON sp_sqlagent_refresh_job TO TargetServersRole

    GRANT EXECUTE ON sp_sqlagent_probe_msx TO TargetServersRole

    GRANT EXECUTE ON sp_sqlagent_check_msx_version TO TargetServersRole

    --revoke TargetServerRole permission that would allow modifying of jobs

    DENY ALL ON sp_add_jobserver TO TargetServersRole

    DENY ALL ON sp_delete_jobserver TO TargetServersRole

    DENY ALL ON sp_add_jobstep TO TargetServersRole

    DENY ALL ON sp_update_jobstep TO TargetServersRole

    DENY ALL ON sp_delete_jobstep TO TargetServersRole

    DENY ALL ON sp_add_jobschedule TO TargetServersRole

    DENY ALL ON sp_update_jobschedule TO TargetServersRole

    DENY ALL ON sp_delete_jobschedule TO TargetServersRole

    DENY ALL ON sp_add_job TO TargetServersRole

    DENY ALL ON sp_update_job TO TargetServersRole

    DENY ALL ON sp_delete_job TO TargetServersRole

    DENY ALL ON sp_start_job TO TargetServersRole

    DENY ALL ON sp_stop_job TO TargetServersRole

    DENY ALL ON sp_post_msx_operation TO TargetServersRole

    DENY ALL ON sp_addtask TO TargetServersRole

    DENY ALL ON sp_updatetask TO TargetServersRole

    DENY ALL ON sp_droptask TO TargetServersRole

    DENY ALL ON sp_reassigntask TO TargetServersRole

    DENY ALL ON sp_purgehistory TO TargetServersRole

    -------------------------------------------------------------------------

    go

    USE msdb

    go

    /**************************************************************/

    /**************************************************************/

    /* BEGIN DTS */

    /**************************************************************/

    /**************************************************************/

    /**************************************************************/

    /* DTS TABLES */

    /* These are never dropped since we dropped MSDB itself if */

    /* this was an upgrade from pre-beta3, and we preserve beta3 */

    /* packages. However, we need to add the owner_sid column */

    /* if it's not there already, defaulting to sa ownership. */

    /**************************************************************/

    /**************************************************************/

    /* SYSDTSCATEGORIES */

    /**************************************************************/

    IF (NOT EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = N'sysdtscategories')))

    BEGIN

    PRINT ''

    PRINT 'Creating table sysdtscategories...'

    CREATE TABLE sysdtscategories

    (

    name sysname NOT NULL,

    description NVARCHAR(1024) NULL,

    id UNIQUEIDENTIFIER NOT NULL,

    parentid UNIQUEIDENTIFIER NOT NULL, --// IID_NULL if a predefined root category

    CONSTRAINT pk_dtscategories PRIMARY KEY (id),

    CONSTRAINT uq_dtscategories_name_parent UNIQUE (name, parentid)

    )

    /**************************************************************/

    /* PREDEFINED DTS CATEGORIES */

    /**************************************************************/

    PRINT ''

    PRINT 'Adding predefined dts categories...'

    --// MUST BE IN SYNC with DTSPkg.h!

    --// These must be INSERTed explicitly as the IID_NULL parent does not exist.

    INSERT sysdtscategories VALUES (N'Local', 'DTS Packages stored on local SQL Server', 'B8C30000-A282-11D1-B7D9-00C04FB6EFD5', '00000000-0000-0000-0000-000000000000')

    INSERT sysdtscategories VALUES (N'Repository', 'DTS Packages stored on Repository', 'B8C30001-A282-11D1-B7D9-00C04FB6EFD5', '00000000-0000-0000-0000-000000000000')

    --// Default location for DTSPackage.SaveToSQLServer

    INSERT sysdtscategories VALUES (N'LocalDefault', 'Default local subcategory for DTS Packages', 'B8C30002-A282-11D1-B7D9-00C04FB6EFD5', 'B8C30000-A282-11D1-B7D9-00C04FB6EFD5')

    END

    GO

    /**************************************************************/

    /* SYSDTSPACKAGES */

    /**************************************************************/

    IF (NOT EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = N'sysdtspackages')))

    BEGIN

    PRINT ''

    PRINT 'Creating table sysdtspackages...'

    CREATE TABLE sysdtspackages

    (

    name sysname NOT NULL, --// May have multiple ids

    id UNIQUEIDENTIFIER NOT NULL, --// May have multiple versionids

    versionid UNIQUEIDENTIFIER NOT NULL UNIQUE,

    description NVARCHAR(1024) NULL,

    categoryid UNIQUEIDENTIFIER NOT NULL REFERENCES sysdtscategories (id),

    createdate DATETIME,

    owner sysname,

    packagedata IMAGE,

    owner_sid VARBINARY(85) NOT NULL DEFAULT SUSER_SID(N'sa'),

    packagetype int NOT NULL DEFAULT 0 --// DTSPkgType_Default

    CONSTRAINT pk_dtspackages PRIMARY KEY (id, versionid)

    )

    END ELSE BEGIN

    IF (NOT EXISTS (SELECT *

    FROM msdb.dbo.syscolumns

    WHERE name = N'owner_sid' AND id = OBJECT_ID(N'sysdtspackages')))

    BEGIN

    PRINT ''

    PRINT 'Altering table sysdtspackages for owner_sid and packagetype...'

    ALTER TABLE sysdtspackages ADD owner_sid VARBINARY(85) NOT NULL DEFAULT SUSER_SID(N'sa'),

    packagetype int NOT NULL DEFAULT 0 --// DTSPkgType_Default

    END

    IF (NOT EXISTS (SELECT *

    FROM msdb.dbo.syscolumns

    WHERE name = N'packagetype' AND id = OBJECT_ID(N'sysdtspackages')))

    BEGIN

    PRINT ''

    PRINT 'Altering table sysdtspackages for packagetype...'

    ALTER TABLE sysdtspackages ADD packagetype int NOT NULL DEFAULT 0 --// DTSPkgType_Default

    END

    END

    GO

    /**************************************************************/

    /* SP_MAKE_DTSPACKAGENAME */

    /**************************************************************/

    PRINT ''

    PRINT 'Creating procedure sp_get_dtsversion...'

    go

    IF OBJECT_ID(N'sp_get_dtsversion') IS NOT NULL

    DROP PROCEDURE sp_get_dtsversion

    go

    CREATE PROCEDURE sp_get_dtsversion

    AS

    /* Values for this are same as @@microsoftversion */

    /* @@microsoftversion format is 0xaaiibbbb (aa = major, ii = minor, bb[bb] = build #) */

    DECLARE @i INT

    select @i = 0x08000000/* Must be in hex! */

    /* Select the numeric value, and a conversion to make it readable */

    select N'Microsoft SQLDTS Scripts' = @i, N'Version' = convert(binary(4), @i)

    GO

    GRANT EXECUTE ON sp_get_dtsversion TO PUBLIC

    GO

    /**************************************************************/

    /* SP_MAKE_DTSPACKAGENAME */

    /**************************************************************/

    PRINT ''

    PRINT 'Creating procedure sp_make_dtspackagename...'

    go

    IF OBJECT_ID(N'sp_make_dtspackagename') IS NOT NULL

    DROP PROCEDURE sp_make_dtspackagename

    go

    CREATE PROCEDURE sp_make_dtspackagename

    @categoryid UNIQUEIDENTIFIER,

    @name sysname OUTPUT,

    @flags int = 0

    AS

    SET NOCOUNT ON

    --// If NULL catid, default to the LocalDefault category.

    IF (@categoryid IS NULL)

    SELECT @categoryid = 'B8C30002-A282-11d1-B7D9-00C04FB6EFD5'

    --// Validate category. We'll generate a unique name within category.

    DECLARE @stringfromclsid NVARCHAR(200)

    IF NOT EXISTS (SELECT * FROM sysdtscategories WHERE id = @categoryid)

    BEGIN

    SELECT @stringfromclsid = CONVERT(NVARCHAR(50), @categoryid)

    RAISERROR(14262, 16, 1, '@categoryid', @stringfromclsid)

    RETURN(1) -- Failure

    END

    --// Autogenerate the next name in our format.

    DECLARE @max-2 sysname, @i INT, @spidchar NVARCHAR(20)

    --// Any logic we use may have collisions so let's get the max and wrap if we have to.

    --// @@spid is necessary for guaranteed uniqueness but makes it ugly so for now, don't use it.

    --// Note: use only 9 characters as it makes the pattern match easier without overflowing.

    SELECT @i = 0, @spidchar = '_' -- + LTRIM(STR(@@spid)) + '_'

    SELECT @max-2 = MAX(name)

    FROM sysdtspackages

    WHERE name like 'DTS_' + @spidchar + '[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]'

    IF @max-2 IS NOT NULL

    SELECT @i = CONVERT(INT, SUBSTRING(@max, (DATALENGTH(N'DTS_' + @spidchar) / 2) + 1, 9))

    --// Wrap if needed. Find a gap in the names.

    IF @i < 999999999

    BEGIN

    SELECT @i = @i + 1

    END ELSE BEGIN

    SELECT @i = 1

    DECLARE @existingname sysname

    DECLARE hC CURSOR LOCAL FOR SELECT name FROM sysdtspackages WHERE categoryid = @categoryid ORDER BY name FOR READ ONLY

    OPEN hC

    FETCH NEXT FROM hC INTO @existingname

    WHILE @@FETCH_STATUS = 0 AND @i < 999999999

    BEGIN

    SELECT @name = 'DTS_' + @spidchar + REPLICATE('0', 9 - DATALENGTH(LTRIM(STR(@i)))) + LTRIM(STR(@i))

    IF @existingname > @name

    BREAK

    SELECT @i = @i + 1

    FETCH NEXT FROM hC INTO @existingname

    END

    CLOSE hC

    DEALLOCATE hC

    END

    --// Set the name.

    SELECT @name = 'DTS_' + @spidchar + REPLICATE('0', 9 - DATALENGTH(LTRIM(STR(@i)))) + LTRIM(STR(@i))

    IF (@flags & 1) <> 0

    SELECT @name

    GO

    GRANT EXECUTE ON sp_make_dtspackagename TO PUBLIC

    GO

    /**************************************************************/

    /* SP_ADD_DTSPACKAGE */

    /**************************************************************/

    PRINT ''

    PRINT 'Creating procedure sp_add_dtspackage...'

    GO

    IF OBJECT_ID(N'sp_add_dtspackage') IS NOT NULL

    DROP PROCEDURE sp_add_dtspackage

    GO

    CREATE PROCEDURE sp_add_dtspackage

    @name sysname,

    @id UNIQUEIDENTIFIER,

    @versionid UNIQUEIDENTIFIER,

    @description NVARCHAR(255),

    @categoryid UNIQUEIDENTIFIER,

    @owner sysname,

    @packagedata IMAGE,

    @packagetype int = 0--// DTSPkgType_Default

    AS

    SET NOCOUNT ON

    --// If NULL catid, default to the LocalDefault category.

    IF (@categoryid IS NULL)

    SELECT @categoryid = 'B8C30002-A282-11d1-B7D9-00C04FB6EFD5'

    --// Autogenerate name if it came in NULL. If it didn't, the below will validate uniqueness.

    IF DATALENGTH(@name) = 0

    SELECT @name = NULL

    IF @name IS NULL

    BEGIN

    --// First see if they specified a new version based on id instead of name.

    if @id IS NOT NULL

    BEGIN

    SELECT @name = name

    FROM sysdtspackages WHERE @id = id

    IF @name IS NOT NULL

    GOTO AddPackage -- OK, add with the existing name

    END

    --// Name not available, autogenerate one.

    exec sp_make_dtspackagename @categoryid, @name OUTPUT

    GOTO AddPackage

    END

    --// Verify name unique within category. Allow a new versionid of the same name though.

    IF EXISTS (SELECT * FROM sysdtspackages WHERE name = @name AND categoryid = @categoryid AND id <> @id)

    BEGIN

    RAISERROR (14590, -1, -1, @name)

    RETURN(1) -- Failure

    END

    --// Verify that the same id is not getting a different name.

    IF EXISTS (SELECT * FROM sysdtspackages WHERE id = @id AND name <> @name)

    BEGIN

    DECLARE @stringfromclsid NVARCHAR(200)

    SELECT @stringfromclsid = CONVERT(NVARCHAR(50), @id)

    RAISERROR (14597, -1, -1, @stringfromclsid)

    RETURN(1) -- Failure

    END

    --// Verify all versions of a package go in the same category.

    IF EXISTS (SELECT * FROM sysdtspackages WHERE id = @id AND categoryid <> @categoryid)

    BEGIN

    RAISERROR (14596, -1, -1, @name)

    RETURN(1) -- Failure

    END

    --// The real information is in the IMAGE; the rest is "documentary".

    --// Therefore, there is no need to verify anything.

    --// The REFERENCE in sysdtspackages will validate @categoryid.

    AddPackage:

    --// We will use the original owner_sid for all new versions - all must have the same owner.

    --// New packages will get the current login's SID as owner_sid.

    DECLARE @owner_sid VARBINARY(85)

    SELECT @owner_sid = MIN(owner_sid) FROM sysdtspackages WHERE id = @id

    IF @@rowcount = 0 OR @owner_sid IS NULL

    BEGIN

    SELECT @owner_sid = SUSER_SID()

    END ELSE BEGIN

    --// Only the owner of DTS Package ''%s'' or a member of the sysadmin role may create new versions of it.

    IF (@owner_sid <> SUSER_SID() AND (ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) <> 1))

    BEGIN

    RAISERROR (14586, -1, -1, @name)

    RETURN(1) -- Failure

    END

    END

    --// Everything checks out, add the package or its new version.

    INSERT sysdtspackages (

    name,

    id,

    versionid,

    description,

    categoryid,

    createdate,

    owner,

    packagedata,

    owner_sid,

    packagetype

    ) VALUES (

    @name,

    @id,

    @versionid,

    @description,

    @categoryid,

    GETDATE(),

    @owner,

    @packagedata,

    @owner_sid,

    @packagetype

    )

    RETURN 0 -- SUCCESS

    GO

    GRANT EXECUTE ON sp_add_dtspackage TO PUBLIC

    GO

    /**************************************************************/

    /* SP_DROP_DTSPACKAGE */

    /**************************************************************/

    PRINT ''

    PRINT 'Creating procedure sp_drop_dtspackage...'

    go

    IF OBJECT_ID(N'sp_drop_dtspackage') IS NOT NULL

    DROP PROCEDURE sp_drop_dtspackage

    go

    CREATE PROCEDURE sp_drop_dtspackage

    @name sysname,

    @id UNIQUEIDENTIFIER,

    @versionid UNIQUEIDENTIFIER

    AS

    SET NOCOUNT ON

    --// Does the specified package (uniquely) exist? Referencing by name only may not be unique.

    --// We do a bit of a hack here as SQL can't handle a DISTINCT clause with UNIQUEIDENTIFIER.

    --// @id will get the first id returned; if only name specified, see if there are more.

    DECLARE @findid UNIQUEIDENTIFIER

    SELECT @findid = id FROM sysdtspackages

    WHERE (@name IS NOT NULL OR @id IS NOT NULL OR @versionid IS NOT NULL)

    AND (@name IS NULL OR @name = name)

    AND (@id IS NULL OR @id = id)

    AND (@versionid IS NULL or @versionid = versionid)

    IF @@rowcount = 0

    BEGIN

    DECLARE @pkgnotfound NVARCHAR(200)

    DECLARE @dts_package_res NVARCHAR(100)

    SELECT @pkgnotfound = FORMATMESSAGE(14599) + ' = ''' + ISNULL(@name, FORMATMESSAGE(14589)) + '''; ' + FORMATMESSAGE(14588) + ' {'

    SELECT @pkgnotfound = @pkgnotfound + CASE WHEN @id IS NULL THEN FORMATMESSAGE(14589) ELSE CONVERT(NVARCHAR(50), @id) END + '}.{'

    SELECT @pkgnotfound = @pkgnotfound + CASE WHEN @versionid IS NULL THEN FORMATMESSAGE(14589) ELSE CONVERT(NVARCHAR(50), @versionid) END + '}'

    SELECT @dts_package_res = FORMATMESSAGE(14594)

    RAISERROR(14262, 16, 1, @dts_package_res, @pkgnotfound)

    RETURN(1) -- Failure

    END ELSE IF @name IS NOT NULL AND @id IS NULL AND @versionid IS NULL AND

    EXISTS (SELECT * FROM sysdtspackages WHERE name = @name AND id <> @findid)

    BEGIN

    RAISERROR(14595, -1, -1, @name)

    RETURN(1) -- Failure

    END

    SELECT @id = @findid

    --// Only the owner of DTS Package ''%s'' or a member of the sysadmin role may drop it or any of its versions.

    --// sp_add_dtspackage ensures that all versions have the same owner_sid.

    IF (ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) <> 1)

    BEGIN

    IF (NOT EXISTS (SELECT * FROM sysdtspackages WHERE id = @id AND owner_sid = SUSER_SID()))

    BEGIN

    SELECT @name = name FROM sysdtspackages WHERE id = @id

    RAISERROR (14587, -1, -1, @name)

    RETURN(1) -- Failure

    END

    END

    --// If @versionid is NULL, drop all versions of name, else only the @versionid version.

    DELETE sysdtspackages

    WHERE id = @id

    AND (@versionid IS NULL OR @versionid = versionid)

    RETURN 0 -- SUCCESS

    go

    GRANT EXECUTE ON sp_drop_dtspackage TO PUBLIC

    go

    /**************************************************************/

    /* SP_REASSIGN_DTSPACKAGEOWNER */

    /**************************************************************/

    PRINT ''

    PRINT 'Creating procedure sp_reassign_dtspackageowner...'

    go

    IF OBJECT_ID(N'sp_reassign_dtspackageowner') IS NOT NULL

    DROP PROCEDURE sp_reassign_dtspackageowner

    go

    CREATE PROCEDURE sp_reassign_dtspackageowner

    @name sysname,

    @id UNIQUEIDENTIFIER,

    @newloginname sysname

    AS

    SET NOCOUNT ON

    --// First, is this a valid login?

    IF SUSER_SID(@newloginname) IS NULL

    BEGIN

    RAISERROR(14262, -1, -1, '@newloginname', @newloginname)

    RETURN(1) -- Failure

    END

    --// Does the specified package (uniquely) exist? Referencing by name only may not be unique.

    --// We do a bit of a hack here as SQL can't handle a DISTINCT clause with UNIQUEIDENTIFIER.

    --// @id will get the first id returned; if only name specified, see if there are more.

    DECLARE @findid UNIQUEIDENTIFIER

    SELECT @findid = id FROM sysdtspackages

    WHERE (@name IS NOT NULL OR @id IS NOT NULL)

    AND (@name IS NULL OR @name = name)

    AND (@id IS NULL OR @id = id)

    IF @@rowcount = 0

    BEGIN

    DECLARE @pkgnotfound NVARCHAR(200)

    DECLARE @dts_package_res NVARCHAR(100)

    SELECT @pkgnotfound = FORMATMESSAGE(14599) + ' = ''' + ISNULL(@name, FORMATMESSAGE(14589)) + '''; ' + FORMATMESSAGE(14588) + ' {'

    SELECT @pkgnotfound = @pkgnotfound + CASE WHEN @id IS NULL THEN FORMATMESSAGE(14589) ELSE CONVERT(NVARCHAR(50), @id) END + '}.{'

    SELECT @pkgnotfound = @pkgnotfound + FORMATMESSAGE(14589) + '}'

    SELECT @dts_package_res = FORMATMESSAGE(14594)

    RAISERROR(14262, 16, 1, @dts_package_res, @pkgnotfound)

    RETURN(1) -- Failure

    END ELSE IF @name IS NOT NULL AND @id IS NULL AND

    EXISTS (SELECT * FROM sysdtspackages WHERE name = @name AND id <> @findid)

    BEGIN

    RAISERROR(14595, -1, -1, @name)

    RETURN(1) -- Failure

    END

    SELECT @id = @findid

    --// Only the owner of DTS Package ''%s'' or a member of the sysadmin role may reassign its ownership.

    --// sp_add_dtspackage ensures that all versions have the same owner_sid.

    IF (ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) <> 1)

    BEGIN

    IF (NOT EXISTS (SELECT * FROM sysdtspackages WHERE id = @id AND owner_sid = SUSER_SID()))

    BEGIN

    SELECT @name = name FROM sysdtspackages WHERE id = @id

    RAISERROR (14585, -1, -1, @name)

    RETURN(1) -- Failure

    END

    END

    --// Everything checks out, so reassign the owner.

    --// Note that @newloginname may be a sql server login rather than a network user,

    --// which is not quite the same as when a package is created.

    UPDATE sysdtspackages

    SET owner_sid = SUSER_SID(@newloginname),

    owner = @newloginname

    WHERE id = @id

    RETURN 0 -- SUCCESS

    GO

    GRANT EXECUTE ON sp_reassign_dtspackageowner TO PUBLIC

    GO

    /**************************************************************/

    /* SP_GET_DTSPACKAGE */

    /**************************************************************/

    PRINT ''

    PRINT 'Creating procedure sp_get_dtspackage...'

    go

    IF OBJECT_ID(N'sp_get_dtspackage') IS NOT NULL

    DROP PROCEDURE sp_get_dtspackage

    go

    CREATE PROCEDURE sp_get_dtspackage

    @name sysname,

    @id UNIQUEIDENTIFIER,

    @versionid UNIQUEIDENTIFIER

    AS

    SET NOCOUNT ON

    --// Does the specified package (uniquely) exist? Dropping by name only may not be unique.

    --// We do a bit of a hack here as SQL can't handle a DISTINCT clause with UNIQUEIDENTIFIER.

    --// @id will get the first id returned; if only name specified, see if there are more.

    DECLARE @findid UNIQUEIDENTIFIER

    SELECT @findid = id FROM sysdtspackages

    WHERE (@name IS NOT NULL OR @id IS NOT NULL OR @versionid IS NOT NULL)

    AND (@name IS NULL OR @name = name)

    AND (@id IS NULL OR @id = id)

    AND (@versionid IS NULL or @versionid = versionid)

    IF @@rowcount = 0

    BEGIN

    DECLARE @pkgnotfound NVARCHAR(200)

    DECLARE @dts_package_res NVARCHAR(100)

    SELECT @pkgnotfound = FORMATMESSAGE(14599) + ' = ''' + ISNULL(@name, FORMATMESSAGE(14589)) + '''; ' + FORMATMESSAGE(14588) + ' {'

    SELECT @pkgnotfound = @pkgnotfound + CASE WHEN @id IS NULL THEN FORMATMESSAGE(14589) ELSE CONVERT(NVARCHAR(50), @id) END + '}.{'

    SELECT @pkgnotfound = @pkgnotfound + CASE WHEN @versionid IS NULL THEN FORMATMESSAGE(14589) ELSE CONVERT(NVARCHAR(50), @versionid) END + '}'

    SELECT @dts_package_res = FORMATMESSAGE(14594)

    RAISERROR(14262, 16, 1, @dts_package_res, @pkgnotfound)

    RETURN(1) -- Failure

    END ELSE IF @name IS NOT NULL AND @id IS NULL AND @versionid IS NULL AND

    EXISTS (SELECT * FROM sysdtspackages WHERE name = @name AND id <> @findid)

    BEGIN

    RAISERROR(14595, -1, -1, @name)

    RETURN(1) -- Failure

    END

    SELECT @id = @findid

    --// If @versionid is NULL, select all versions of name, else only the @versionid version.

    --// This must return the IMAGE as the rightmost column.

    SELECT

    name,

    id,

    versionid,

    description,

    createdate,

    owner,

    pkgsize = datalength(packagedata),

    packagedata,

    isowner = CASE WHEN (ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) = 1 OR owner_sid = SUSER_SID()) THEN 1 ELSE 0 END,

    packagetype

    FROM sysdtspackages

    WHERE id = @id

    AND (@versionid IS NULL OR @versionid = versionid)

    ORDER BY name, createdate DESC

    RETURN 0 -- SUCCESS

    go

    GRANT EXECUTE ON sp_get_dtspackage TO PUBLIC

    go

    /**************************************************************/

    /* SP_REASSIGN_DTSPACKAGECATEGORY */

    /**************************************************************/

    PRINT ''

    PRINT 'Creating procedure sp_reassign_dtspackagecategory...'

    go

    IF OBJECT_ID(N'sp_reassign_dtspackagecategory') IS NOT NULL

    DROP PROCEDURE sp_reassign_dtspackagecategory

    go

    CREATE PROCEDURE sp_reassign_dtspackagecategory

    @packageid UNIQUEIDENTIFIER,

    @categoryid UNIQUEIDENTIFIER

    AS

    SET NOCOUNT ON

    --// Does the package exist?

    DECLARE @stringfromclsid NVARCHAR(200)

    IF NOT EXISTS (SELECT * from sysdtspackages WHERE id = @packageid)

    BEGIN

    SELECT @stringfromclsid = CONVERT(NVARCHAR(50), @packageid)

    RAISERROR(14262, 16, 1, '@packageid', @stringfromclsid)

    RETURN(1) -- Failure

    END

    --// Does the category exist?

    IF NOT EXISTS (SELECT * FROM sysdtscategories WHERE id = @categoryid)

    BEGIN

    SELECT @stringfromclsid = CONVERT(NVARCHAR(50), @categoryid)

    RAISERROR(14262, 16, 1, '@categoryid', @stringfromclsid)

    RETURN(1) -- Failure

    END

    UPDATE sysdtspackages SET categoryid = @categoryid WHERE id = @packageid

    go

    /**************************************************************/

    /* SP_ENUM_DTSPACKAGES */

    /**************************************************************/

    PRINT ''

    PRINT 'Creating procedure sp_enum_dtspackages...'

    go

    IF OBJECT_ID(N'sp_enum_dtspackages') IS NOT NULL

    DROP PROCEDURE sp_enum_dtspackages

    go

    CREATE PROCEDURE sp_enum_dtspackages

    @name_like sysname = '%',

    @description_like NVARCHAR(255) = '%',

    @categoryid UNIQUEIDENTIFIER = NULL,

    @flags INT = 0, --// Bitmask: 0x01 == return image data

    --// 0x02 == recursive (packagenames and categorynames only)

    --// 0x04 == all versions (default == only most-recent-versions)

    --// 0x08 == all prior versions versions (not most-recent; requires @id)

    @id UNIQUEIDENTIFIER = NULL, --// If non-NULL, enum versions of this package.

    @wanttype int = NULL --// If non-NULL, enum only packages of the given type

    AS

    IF (@flags & 0x02) <> 0

    GOTO DO_RECURSE

    --// Just return the non-IMAGE stuff - sp_get_dtspackage will return the

    --// actual dtspackage info.

    DECLARE @latestversiondate datetime

    SELECT @latestversiondate = NULL

    IF (@flags & 0x08 = 0x08)

    BEGIN

    SELECT @latestversiondate = MAX(t.createdate) FROM sysdtspackages t WHERE t.id = @id

    IF @latestversiondate IS NULL

    BEGIN

    DECLARE @pkgnotfound NVARCHAR(200)

    DECLARE @dts_package_res NVARCHAR(100)

    SELECT @pkgnotfound = FORMATMESSAGE(14599) + ' = ' + FORMATMESSAGE(14589) + '; ' + FORMATMESSAGE(14588) + ' {'

    SELECT @pkgnotfound = @pkgnotfound + CASE WHEN @id IS NULL THEN FORMATMESSAGE(14589) ELSE CONVERT(NVARCHAR(50), @id) END + '}.{'

    SELECT @pkgnotfound = @pkgnotfound + FORMATMESSAGE(14589) + '}'

    SELECT @dts_package_res = FORMATMESSAGE(14594)

    RAISERROR(14262, 16, 1, @dts_package_res, @pkgnotfound)

    RETURN(1) -- Failure

    END

    END

    SELECT

    p.name,

    p.id,

    p.versionid,

    p.description,

    p.createdate,

    p.owner,

    size = datalength(p.packagedata),

    packagedata = CASE (@flags & 0x01) WHEN 0 THEN NULL ELSE p.packagedata END,

    isowner = CASE WHEN (ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) = 1 OR p.owner_sid = SUSER_SID()) THEN 1 ELSE 0 END,

    p.packagetype

    FROM sysdtspackages p

    WHERE (@name_like IS NULL OR p.name LIKE @name_like)

    AND (@description_like IS NULL OR p.description LIKE @description_like)

    AND (@categoryid IS NULL OR p.categoryid = @categoryid)

    AND (@id is NULL OR p.id = @id)

    -- These filter by version

    AND ( (@flags & 0x08 = 0x08 AND p.createdate < @latestversiondate)

    OR ( (@flags & 0x04 = 0x04)

    OR (@flags & 0x08 = 0 AND p.createdate = (SELECT MAX(t.createdate) FROM sysdtspackages t WHERE t.id = p.id))

    )

    )

    AND (@wanttype is NULL or p.packagetype = @wanttype)

    ORDER BY id, createdate DESC

    RETURN 0 -- SUCCESS

    DO_RECURSE:

    DECLARE @packagesfound INT

    SELECT @packagesfound = 0

    --// Starting parent category. If null, start at root.

    if (@categoryid IS NULL)

    SELECT @categoryid = '00000000-0000-0000-0000-000000000000'

    IF EXISTS (SELECT *

    FROM sysdtspackages p INNER JOIN sysdtscategories c ON p.categoryid = c.id

    WHERE p.categoryid = @categoryid

    AND (@name_like IS NULL OR p.name LIKE @name_like)

    AND (@description_like IS NULL OR p.description LIKE @description_like)

    )

    SELECT @packagesfound = 1

    IF (@packagesfound <> 0)

    BEGIN

    --// Identify the category and list its Packages.

    SELECT 'Level' = @@nestlevel, 'PackageName' = p.name, 'CategoryName' = c.name

    FROM sysdtspackages p INNER JOIN sysdtscategories c ON p.categoryid = c.id

    WHERE p.categoryid = @categoryid

    AND (@name_like IS NULL OR p.name LIKE @name_like)

    AND (@description_like IS NULL OR p.description LIKE @description_like)

    END

    --// List its subcategories' packages

    DECLARE @childid UNIQUEIDENTIFIER

    DECLARE hC CURSOR LOCAL FOR SELECT id FROM sysdtscategories c WHERE parentid = @categoryid ORDER BY c.name FOR READ ONLY

    OPEN hC

    FETCH NEXT FROM hC INTO @childid

    WHILE @@FETCH_STATUS = 0

    BEGIN

    EXECUTE sp_enum_dtspackages @name_like, @description_like, @childid, @flags

    FETCH NEXT FROM hC INTO @childid

    END

    CLOSE hC

    DEALLOCATE hC

    RETURN 0

    go

    GRANT EXECUTE ON sp_enum_dtspackages TO PUBLIC

    go

    /**************************************************************/

    /* SP_ADD_DTSCATEGORY */

    /**************************************************************/

    PRINT ''

    PRINT 'Creating procedure sp_add_dtscategory...'

    go

    IF OBJECT_ID(N'sp_add_dtscategory') IS NOT NULL

    DROP PROCEDURE sp_add_dtscategory

    go

    CREATE PROCEDURE sp_add_dtscategory

    @name sysname,

    @description NVARCHAR(1024),

    @id UNIQUEIDENTIFIER,

    @parentid UNIQUEIDENTIFIER

    AS

    SET NOCOUNT ON

    --// If parentid is NULL, use 'Local'

    IF @parentid IS NULL

    SELECT @parentid = 'B8C30000-A282-11d1-B7D9-00C04FB6EFD5'

    --// First do some simple validation of "non-assert" cases. UI should validate others and the table

    --// definitions will act as an "assert", but we check here (with a nice message) for user-error stuff

    --// it would be hard for UI to validate.

    IF NOT EXISTS (SELECT * FROM sysdtscategories WHERE id = @parentid)

    BEGIN

    DECLARE @stringfromclsid NVARCHAR(200)

    SELECT @stringfromclsid = CONVERT(NVARCHAR(50), @parentid)

    RAISERROR(14262, 16, 1, '@parentid', @stringfromclsid)

    RETURN(1) -- Failure

    END

    IF EXISTS (SELECT * FROM sysdtscategories WHERE name = @name AND parentid = @parentid)

    BEGIN

    RAISERROR(14591, 16, -1, @name)

    RETURN(1) -- Failure

    END

    --// id uniqueness is ensured by the primary key.

    INSERT sysdtscategories (

    name,

    description,

    id,

    parentid

    ) VALUES (

    @name,

    @description,

    @id,

    @parentid

    )

    RETURN 0 -- SUCCESS

    go

    /**************************************************************/

    /* SP_DROP_DTSCATEGORY */

    /**************************************************************/

    PRINT ''

    PRINT 'Creating procedure sp_drop_dtscategory...'

    go

    IF OBJECT_ID(N'sp_drop_dtscategory') IS NOT NULL

    DROP PROCEDURE sp_drop_dtscategory

    go

    CREATE PROCEDURE sp_drop_dtscategory

    @name_like sysname,

    @id UNIQUEIDENTIFIER = NULL,

    @flags INT = 0 --// Bitmask: 0x01 == recursive (drop all subcategories and packages)

    AS

    SET NOCOUNT ON

    --// Temp table in case recursion is needed.

    CREATE TABLE #recurse(id UNIQUEIDENTIFIER, passcount INT DEFAULT(0))

    IF (@name_like IS NOT NULL)

    BEGIN

    INSERT #recurse (id) SELECT id FROM sysdtscategories WHERE name LIKE @name_like

    IF @@rowcount = 0

    BEGIN

    RAISERROR(14262, 16, 1, '@name_like', @name_like)

    RETURN(1) -- Failure

    END

    IF @@rowcount > 1

    BEGIN

    RAISERROR(14592, 16, -1, @name_like)

    RETURN(1) -- Failure

    END

    SELECT @name_like = name, @id = id FROM sysdtscategories WHERE name LIKE @name_like

    END ELSE BEGIN

    --// Verify the id. @name_like will be NULL if we're here so no need to initialize.

    SELECT @name_like = name FROM sysdtscategories WHERE id = @id

    IF @name_like IS NULL

    BEGIN

    DECLARE @stringfromclsid NVARCHAR(200)

    SELECT @stringfromclsid = CONVERT(NVARCHAR(50), @id)

    RAISERROR(14262, 16, 1, '@id', @stringfromclsid)

    RETURN(1) -- Failure

    END

    INSERT #recurse (id) VALUES (@id)

    END

    --// We now have a unique category.

    --// Cannot drop the predefined categories (or the root, which already failed above as IID_NULL

    --// is not an id in sysdtscategories). These will be at top level.

    IF @id IN (

    'B8C30000-A282-11d1-B7D9-00C04FB6EFD5'

    , 'B8C30001-A282-11d1-B7D9-00C04FB6EFD5'

    , 'B8C30002-A282-11d1-B7D9-00C04FB6EFD5'

    ) BEGIN

    RAISERROR(14598, 16, 1)

    RETURN(1) -- Failure

    END

    --// Check for subcategories or packages.

    IF EXISTS (SELECT * FROM sysdtspackages WHERE categoryid = @id)

    OR EXISTS (SELECT * FROM sysdtscategories WHERE parentid = @id)

    BEGIN

    --// It does. Make sure recursion was requested.

    IF (@flags & 0x01 = 0)

    BEGIN

    RAISERROR(14593, 16, -1, @name_like)

    RETURN(1) -- Failure

    END

    --// Fill up #recurse.

    UPDATE #recurse SET passcount = 0

    WHILE (1 = 1)

    BEGIN

    UPDATE #recurse SET passcount = passcount + 1

    INSERT #recurse (id, passcount)

    SELECT c.id, 0 FROM sysdtscategories c INNER JOIN #recurse r ON c.parentid = r.id

    WHERE passcount = 1

    IF @@rowcount = 0

    BREAK

    END

    END

    DELETE sysdtspackages FROM sysdtspackages INNER JOIN #recurse ON sysdtspackages.categoryid = #recurse.id

    DELETE sysdtscategories FROM sysdtscategories INNER JOIN #recurse ON sysdtscategories.id = #recurse.id

    RETURN(0) -- SUCCESS

    go

    /**************************************************************/

    /* SP_MODIFY_DTSCATEGORY */

    /**************************************************************/

    PRINT ''

    PRINT 'Creating procedure sp_modify_dtscategory...'

    go

    IF OBJECT_ID(N'sp_modify_dtscategory') IS NOT NULL

    DROP PROCEDURE sp_modify_dtscategory

    go

    CREATE PROCEDURE sp_modify_dtscategory

    @id UNIQUEIDENTIFIER,

    @name sysname,

    @description NVARCHAR(1024),

    @parentid UNIQUEIDENTIFIER

    AS

    SET NOCOUNT ON

    --// Validate.

    DECLARE @stringfromclsid NVARCHAR(200)

    IF NOT EXISTS (SELECT * FROM sysdtscategories WHERE id = @id)

    BEGIN

    SELECT @stringfromclsid = CONVERT(NVARCHAR(50), @id)

    RAISERROR(14262, 16, 1, '@id', @stringfromclsid)

    RETURN(1) -- Failure

    END

    IF NOT EXISTS (SELECT * FROM sysdtscategories WHERE id = @parentid)

    BEGIN

    SELECT @stringfromclsid = CONVERT(NVARCHAR(50), @parentid)

    RAISERROR(14262, 16, 1, '@parentid', @stringfromclsid)

    RETURN(1) -- Failure

    END

    --// Check the name uniqueness within parent, but make sure the id is different (we may just be renaming

    --// without reassigning parentage).

    IF EXISTS (SELECT * FROM sysdtscategories WHERE name = @name AND parentid = @parentid and id <> @id)

    BEGIN

    RAISERROR(14591, 16, -1, @name)

    RETURN(1) -- Failure

    END

    UPDATE sysdtscategories SET name = @name, description = @description, parentid = @parentid

    WHERE id = @id

    RETURN(0) -- SUCCESS

    go

    /**************************************************************/

    /* SP_ENUM_DTSCATEGORIES */

    /**************************************************************/

    PRINT ''

    PRINT 'Creating procedure sp_enum_dtscategories...'

    go

    IF OBJECT_ID(N'sp_enum_dtscategories') IS NOT NULL

    DROP PROCEDURE sp_enum_dtscategories

    go

    CREATE PROCEDURE sp_enum_dtscategories

    @parentid UNIQUEIDENTIFIER = NULL,

    @flags INT = 0 --// Bitmask: 0x01 == recursive (enum all subcategories; names only)

    AS

    IF (@flags & 0x01) <> 0

    GOTO DO_RECURSE

    --// Go to the root if no parentid specified

    IF @parentid IS NULL

    SELECT @parentid = '00000000-0000-0000-0000-000000000000'

    --// 'No results' is valid here.

    SELECT name, description, id FROM sysdtscategories WHERE parentid = @parentid

    ORDER BY name

    RETURN 0

    DO_RECURSE:

    --// Identify the category.

    IF @@nestlevel <> 0

    SELECT 'Level' = @@nestlevel, name FROM sysdtscategories WHERE id = @parentid

    --// List its subcategories

    DECLARE @childid UNIQUEIDENTIFIER

    DECLARE hC CURSOR LOCAL FOR SELECT id FROM sysdtscategories c WHERE parentid = @parentid ORDER BY c.name FOR READ ONLY

    OPEN hC

    FETCH NEXT FROM hC INTO @childid

    WHILE @@FETCH_STATUS = 0

    BEGIN

    EXECUTE sp_enum_dtscategories @childid, @flags

    FETCH NEXT FROM hC INTO @childid

    END

    CLOSE hC

    DEALLOCATE hC

    RETURN 0

    go

    /**************************************************************/

    /* Drop Beta1 DTS Logging objects */

    /**************************************************************/

    if OBJECT_ID('sysdtspackagestepslog') IS NOT NULL

    BEGIN

    PRINT ''

    PRINT 'Dropping Beta1 logging tables and stored procedures...'

    DROP TABLE sysdtspackagestepslog

    IF OBJECT_ID('sysdtspackagelog') IS NOT NULL

    DROP TABLE sysdtspackagelog

    IF OBJECT_ID('sp_log_dtspackage') IS NOT NULL

    DROP PROCEDURE sp_log_dtspackage

    IF OBJECT_ID('sp_log_dtspackagesteps') IS NOT NULL

    DROP PROCEDURE sp_log_dtspackagesteps

    END

    /**************************************************************/

    /* SYSDTSPACKAGELOG */

    /**************************************************************/

    if OBJECT_ID('sysdtspackagelog') IS NULL

    BEGIN

    PRINT ''

    PRINT 'Creating table sysdtspackagelog...'

    CREATE TABLE sysdtspackagelog

    (

    namesysnameNOT NULL,

    descriptionNVARCHAR(1000)NULL,

    idUNIQUEIDENTIFIERNOT NULL,

    versionidUNIQUEIDENTIFIERNOT NULL,

    lineagefullUNIQUEIDENTIFIERNOT NULL PRIMARY KEY,

    lineageshortINTNOT NULL,

    starttimeDATETIMENOT NULL,

    endtimeDATETIMENULL,

    elapsedtimedouble precisionNULL,

    computersysnameNOT NULL,

    operatorsysnameNOT NULL,

    logdatedatetimeNOT NULL DEFAULT GETDATE(),

    errorcodeINTNULL,

    errordescriptionNVARCHAR(2000)NULL

    )

    END

    /**************************************************************/

    /* SYSDTSSTEPLOG */

    /**************************************************************/

    if OBJECT_ID('sysdtssteplog') IS NULL

    BEGIN

    PRINT ''

    PRINT 'Creating table sysdtssteplog...'

    CREATE TABLE sysdtssteplog

    (

    stepexecutionidBIGINT IDENTITY (1, 1)NOT NULL PRIMARY KEY,

    lineagefullUNIQUEIDENTIFIERNOT NULL

    REFERENCES sysdtspackagelog(lineagefull)

    ON DELETE CASCADE,

    stepnamesysnameNOT NULL,

    stepexecstatusintNULL,

    stepexecresultintNULL,

    starttimeDATETIMENOT NULL,

    endtimeDATETIMENULL,

    elapsedtimedouble precisionNULL,

    errorcodeINTNULL,

    errordescriptionNVARCHAR(2000)NULL,

    progresscountBIGINTNULL

    )

    END ELSE BEGIN

    IF (NOT EXISTS (SELECT *

    FROM msdb.dbo.syscolumns

    WHERE name = N'stepexecresult' AND id = OBJECT_ID(N'sysdtssteplog')))

    BEGIN

    PRINT ''

    PRINT 'Altering table sysdtssteplog...'

    ALTER TABLE sysdtssteplog ADD stepexecresult INT NULL DEFAULT 0

    END

    END

    /**************************************************************/

    /* SYSDTSTASKLOG */

    /**************************************************************/

    if OBJECT_ID('sysdtstasklog') IS NULL

    BEGIN

    PRINT ''

    PRINT 'Creating table sysdtstasklog...'

    CREATE TABLE sysdtstasklog

    (

    stepexecutionidBIGINTNOT NULL

    REFERENCES sysdtssteplog (stepexecutionid)

    ON DELETE CASCADE,

    sequenceidINTNOT NULL,

    errorcodeINTNOT NULL,

    descriptionNVARCHAR(2000)NULL,

    PRIMARY KEY(stepexecutionid, sequenceid)

    )

    END

    /**************************************************************/

    /* SP_LOG_DTSPACKAGE_BEGIN */

    /**************************************************************/

    PRINT ''

    PRINT 'Creating procedure sp_log_dtspackage_begin...'

    GO

    IF OBJECT_ID(N'sp_log_dtspackage_begin') IS NOT NULL

    DROP PROCEDURE sp_log_dtspackage_begin

    GO

    CREATE PROCEDURE sp_log_dtspackage_begin

    @namesysname,

    @descriptionNVARCHAR(1000),

    @idUNIQUEIDENTIFIER,

    @versionidUNIQUEIDENTIFIER,

    @lineagefullUNIQUEIDENTIFIER,

    @lineageshortINT,

    @starttimeDATETIME,

    @computer-2sysname,

    @operatorsysname

    AS

    SET NOCOUNT ON

    INSERT sysdtspackagelog (

    name,

    description,

    id,

    versionid,

    lineagefull,

    lineageshort,

    starttime,

    computer,

    operator

    ) VALUES (

    @name,

    @description,

    @id,

    @versionid,

    @lineagefull,

    @lineageshort,

    @starttime,

    @computer-2,

    @operator

    )

    RETURN 0 -- SUCCESS

    GO

    GRANT EXECUTE ON sp_log_dtspackage_begin TO PUBLIC

    GO

    /**************************************************************/

    /* SP_LOG_DTSPACKAGE_END */

    /**************************************************************/

    PRINT ''

    PRINT 'Creating procedure sp_log_dtspackage_end...'

    GO

    IF OBJECT_ID(N'sp_log_dtspackage_end') IS NOT NULL

    DROP PROCEDURE sp_log_dtspackage_end

    GO

    CREATE PROCEDURE sp_log_dtspackage_end

    @lineagefullUNIQUEIDENTIFIER,

    @endtimeDATETIME,

    @elapsedtimedouble precision,

    @errorcodeINT,

    @errordescriptionNVARCHAR(2000)

    AS

    SET NOCOUNT ON

    --// Validate lineage.

    DECLARE @stringfromclsid NVARCHAR(200)

    IF NOT EXISTS (SELECT * FROM sysdtspackagelog WHERE lineagefull = @lineagefull)

    BEGIN

    SELECT @stringfromclsid = CONVERT(NVARCHAR(50), @lineagefull)

    RAISERROR(14262, 16, 1, '@lineagefull', @stringfromclsid)

    RETURN(1) -- Failure

    END

    UPDATE sysdtspackagelog

    SET

    endtime = @endtime,

    elapsedtime = @elapsedtime,

    errorcode = @errorcode,

    errordescription = @errordescription

    WHERE lineagefull = @lineagefull

    RETURN 0 -- SUCCESS

    GO

    GRANT EXECUTE ON sp_log_dtspackage_end TO PUBLIC

    GO

    /**************************************************************/

    /* SP_LOG_DTSSTEP_BEGIN */

    /**************************************************************/

    PRINT ''

    PRINT 'Creating procedure sp_log_dtsstep_begin...'

    GO

    IF OBJECT_ID(N'sp_log_dtsstep_begin') IS NOT NULL

    DROP PROCEDURE sp_log_dtsstep_begin

    GO

    CREATE PROCEDURE sp_log_dtsstep_begin

    @lineagefullUNIQUEIDENTIFIER,

    @stepnamesysname,

    @starttimeDATETIME

    AS

    SET NOCOUNT ON

    --// Validate lineage.

    DECLARE @stringfromclsid NVARCHAR(200)

    IF NOT EXISTS (SELECT * FROM sysdtspackagelog WHERE lineagefull = @lineagefull)

    BEGIN

    SELECT @stringfromclsid = CONVERT(NVARCHAR(50), @lineagefull)

    RAISERROR(14262, 16, 1, '@lineagefull', @stringfromclsid)

    RETURN(1) -- Failure

    END

    INSERT sysdtssteplog (

    lineagefull,

    stepname,

    starttime

    ) VALUES (

    @lineagefull,

    @stepname,

    @starttime

    )

    --// Return the @@identity for sp_log_dtstask and sp_logdtsstep_end

    SELECT @@IDENTITY

    RETURN 0 -- SUCCESS

    GO

    GRANT EXECUTE ON sp_log_dtsstep_begin TO PUBLIC

    GO

    /**************************************************************/

    /* SP_LOG_DTSSTEP_END */

    /**************************************************************/

    PRINT ''

    PRINT 'Creating procedure sp_log_dtsstep_end...'

    GO

    IF OBJECT_ID(N'sp_log_dtsstep_end') IS NOT NULL

    DROP PROCEDURE sp_log_dtsstep_end

    GO

    CREATE PROCEDURE sp_log_dtsstep_end

    @stepexecutionidBIGINT,

    @stepexecstatusint,

    @stepexecresultint,

    @endtimeDATETIME,

    @elapsedtimedouble precision,

    @errorcodeINT,

    @errordescriptionNVARCHAR(2000),

    @progresscountBIGINT

    AS

    SET NOCOUNT ON

    --// Validate @stepexecutionid.

    DECLARE @stringfromclsid NVARCHAR(200)

    IF NOT EXISTS (SELECT * FROM sysdtssteplog WHERE stepexecutionid = @stepexecutionid)

    BEGIN

    SELECT @stringfromclsid = CONVERT(NVARCHAR(50), @stepexecutionid)

    RAISERROR(14262, 16, 1, '@stepexecutionid', @stringfromclsid)

    RETURN(1) -- Failure

    END

    UPDATE sysdtssteplog

    SET

    stepexecstatus = @stepexecstatus,

    stepexecresult = @stepexecresult,

    endtime = @endtime,

    elapsedtime = @elapsedtime,

    errorcode = @errorcode,

    errordescription = @errordescription,

    progresscount = @progresscount

    WHERE stepexecutionid = @stepexecutionid

    RETURN 0 -- SUCCESS

    GO

    GRANT EXECUTE ON sp_log_dtsstep_end TO PUBLIC

    GO

    /**************************************************************/

    /* SP_LOG_DTSTASK */

    /**************************************************************/

    PRINT ''

    PRINT 'Creating procedure sp_log_dtstask...'

    GO

    IF OBJECT_ID(N'sp_log_dtstask') IS NOT NULL

    DROP PROCEDURE sp_log_dtstask

    GO

    CREATE PROCEDURE sp_log_dtstask

    @stepexecutionidBIGINT,

    @sequenceidINT,

    @errorcodeINT,

    @descriptionNVARCHAR(2000)

    AS

    SET NOCOUNT ON

    --// Validate @stepexecutionid.

    DECLARE @stringfromclsid NVARCHAR(200)

    IF NOT EXISTS (SELECT * FROM sysdtssteplog WHERE stepexecutionid = @stepexecutionid)

    BEGIN

    SELECT @stringfromclsid = CONVERT(NVARCHAR(50), @stepexecutionid)

    RAISERROR(14262, 16, 1, '@stepexecutionid', @stringfromclsid)

    RETURN(1) -- Failure

    END

    INSERT sysdtstasklog (

    stepexecutionid,

    sequenceid,

    errorcode,

    description

    ) VALUES (

    @stepexecutionid,

    @sequenceid,

    @errorcode,

    @description

    )

    RETURN 0 -- SUCCESS

    GO

    GRANT EXECUTE ON sp_log_dtstask TO PUBLIC

    GO

    /**************************************************************/

    /* SP_ENUM_DTSPACKAGELOG */

    /**************************************************************/

    PRINT ''

    PRINT 'Creating procedure sp_enum_dtspackagelog...'

    GO

    IF OBJECT_ID(N'sp_enum_dtspackagelog') IS NOT NULL

    DROP PROCEDURE sp_enum_dtspackagelog

    GO

    CREATE PROCEDURE sp_enum_dtspackagelog

    @name sysname,

    @flags INT = 0, --// Bitmask: 0x01 == return only latest

    @id UNIQUEIDENTIFIER = NULL,--// If non-NULL, use instead of @name.

    @versionid UNIQUEIDENTIFIER = NULL,--// If non-NULL, use instead of @id or @name

    @lineagefull UNIQUEIDENTIFIER = NULL--// If non-NULL, use instead of @versionid or @id or @name

    AS

    SET NOCOUNT ON

    --// This is used for realtime viewing of package logs, so don't error if no entries

    --// found, simply return an empty result set.

    SELECT

    p.name,

    p.description,

    p.id,

    p.versionid,

    p.lineagefull,

    p.lineageshort,

    p.starttime,

    p.endtime,

    p.elapsedtime,

    p.computer,

    p.operator,

    p.logdate,

    p.errorcode,

    p.errordescription

    FROM sysdtspackagelog p

    WHERE ((@lineagefull IS NULL OR p.lineagefull = @lineagefull)

    AND (@versionid IS NULL OR p.versionid = @versionid)

    AND (@id IS NULL OR p.id = @id)

    AND (@name IS NULL OR p.name = @name))

    AND ((@flags & 0x01) = 0

    OR p.logdate =

    (

    SELECT MAX(logdate)

    FROM sysdtspackagelog d

    WHERE (d.id = p.id)

    )

    )

    ORDER BY logdate

    RETURN 0 -- SUCCESS

    GO

    GRANT EXECUTE ON sp_enum_dtspackagelog TO PUBLIC

    GO

    /**************************************************************/

    /* SP_ENUM_DTSSTEPLOG */

    /**************************************************************/

    PRINT ''

    PRINT 'Creating procedure sp_enum_dtssteplog...'

    GO

    IF OBJECT_ID(N'sp_enum_dtssteplog') IS NOT NULL

    DROP PROCEDURE sp_enum_dtssteplog

    GO

    CREATE PROCEDURE sp_enum_dtssteplog

    @lineagefullUNIQUEIDENTIFIER = NULL,-- all steps in this package execution

    @stepexecutionidBIGINT = NULL

    AS

    SET NOCOUNT ON

    --// This is used for realtime viewing of package logs, so don't error if no entries

    --// found, simply return an empty result set.

    --// This query must be restricted within a single package execution (lineage); it may

    --// be further restricted by stepexecutionid to a single step within that package execution.

    SELECT

    stepexecutionid,

    lineagefull,

    stepname,

    stepexecstatus,

    stepexecresult,

    starttime,

    endtime,

    elapsedtime,

    errorcode,

    errordescription,

    progresscount

    FROM sysdtssteplog

    WHERE (@lineagefull IS NULL OR lineagefull = @lineagefull)

    AND (@stepexecutionid IS NULL OR stepexecutionid = @stepexecutionid)

    ORDER BY stepexecutionid

    RETURN 0 -- SUCCESS

    GO

    GRANT EXECUTE ON sp_enum_dtssteplog TO PUBLIC

    GO

    /**************************************************************/

    /* SP_ENUM_DTSTASKLOG */

    /**************************************************************/

    PRINT ''

    PRINT 'Creating procedure sp_enum_dtstasklog...'

    GO

    IF OBJECT_ID(N'sp_enum_dtstasklog') IS NOT NULL

    DROP PROCEDURE sp_enum_dtstasklog

    GO

    CREATE PROCEDURE sp_enum_dtstasklog

    @stepexecutionidBIGINT,

    @sequenceidINT = NULL

    AS

    SET NOCOUNT ON

    --// This is used for realtime viewing of package logs, so don't error if no entries

    --// found, simply return an empty result set.

    --// This query must be restricted within a single step execution; it may

    --// be further restricted by stepexecutionid to a single record within that step execution.

    SELECT

    -- stepexecutionid, -- this is always passed in so we don't need to return it.

    sequenceid,

    errorcode,

    description

    FROM sysdtstasklog

    WHERE (stepexecutionid IS NULL or stepexecutionid = @stepexecutionid)

    AND (@sequenceid IS NULL OR sequenceid = @sequenceid)

    ORDER BY sequenceid

    RETURN 0 -- SUCCESS

    GO

    GRANT EXECUTE ON sp_enum_dtstasklog TO PUBLIC

    GO

    /**************************************************************/

    /* SP_DUMP_DTSLOG_ALL */

    /**************************************************************/

    PRINT ''

    PRINT 'Creating procedure sp_dump_dtslog_all...'

    GO

    IF OBJECT_ID(N'sp_dump_dtslog_all') IS NOT NULL

    DROP PROCEDURE sp_dump_dtslog_all

    GO

    CREATE PROCEDURE sp_dump_dtslog_all

    AS

    SET NOCOUNT ON

    --// sysadmin only.

    IF (ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) <> 1)

    BEGIN

    RAISERROR(15003, 16, 1, N'sysadmin')

    RETURN(1) -- Failure

    END

    DELETE sysdtspackagelog

    RETURN 0 -- SUCCESS

    GO

    GRANT EXECUTE ON sp_dump_dtslog_all TO PUBLIC

    GO

    /**************************************************************/

    /* SP_DUMP_DTSPACKAGELOG */

    /**************************************************************/

    PRINT ''

    PRINT 'Creating procedure sp_dump_dtspackagelog...'

    GO

    IF OBJECT_ID(N'sp_dump_dtspackagelog') IS NOT NULL

    DROP PROCEDURE sp_dump_dtspackagelog

    GO

    CREATE PROCEDURE sp_dump_dtspackagelog

    @name sysname,

    @flags INT = 0, --// Bitmask: 0x01 == preserve latest

    @id UNIQUEIDENTIFIER = NULL,--// If non-NULL, use instead of @name.

    @versionid UNIQUEIDENTIFIER = NULL,--// If non-NULL, use instead of @id or @name

    @lineagefull UNIQUEIDENTIFIER = NULL--// If non-NULL, use instead of @versionid or @id or @name

    AS

    SET NOCOUNT ON

    --// sysadmin only.

    IF (ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) <> 1)

    BEGIN

    RAISERROR(15003, 16, 1, N'sysadmin')

    RETURN(1) -- Failure

    END

    --// Don't error if no entries found, as the desired result will be met.

    --// DELETE will CASCADE

    DELETE sysdtspackagelog

    FROM sysdtspackagelog p

    WHERE ((@lineagefull IS NULL OR p.lineagefull = @lineagefull)

    AND (@versionid IS NULL OR p.versionid = @versionid)

    AND (@id IS NULL OR p.id = @id)

    AND (@name IS NULL OR p.name = @name))

    AND ((@flags & 0x01) = 0

    OR p.logdate <

    (

    SELECT MAX(logdate)

    FROM sysdtspackagelog d

    WHERE (d.id = p.id)

    )

    )

    RETURN 0 -- SUCCESS

    GO

    GRANT EXECUTE ON sp_dump_dtspackagelog TO PUBLIC

    GO

    /**************************************************************/

    /* SP_DUMP_DTSSTEPLOG */

    /**************************************************************/

    PRINT ''

    PRINT 'Creating procedure sp_dump_dtssteplog...'

    GO

    IF OBJECT_ID(N'sp_dump_dtssteplog') IS NOT NULL

    DROP PROCEDURE sp_dump_dtssteplog

    GO

    CREATE PROCEDURE sp_dump_dtssteplog

    @lineagefullUNIQUEIDENTIFIER = NULL,-- all steps in this package execution

    @stepexecutionidBIGINT = NULL

    AS

    SET NOCOUNT ON

    --// sysadmin only.

    IF (ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) <> 1)

    BEGIN

    RAISERROR(15003, 16, 1, N'sysadmin')

    RETURN(1) -- Failure

    END

    --// Don't error if no entries found, as the desired result will be met.

    --// DELETE will CASCADE

    DELETE sysdtssteplog

    WHERE (@lineagefull IS NULL OR lineagefull = @lineagefull)

    AND (@stepexecutionid IS NULL OR stepexecutionid = @stepexecutionid)

    RETURN 0 -- SUCCESS

    GO

    GRANT EXECUTE ON sp_dump_dtssteplog TO PUBLIC

    GO

    /**************************************************************/

    /* SP_DUMP_DTSTASKLOG */

    /**************************************************************/

    PRINT ''

    PRINT 'Creating procedure sp_dump_dtstasklog...'

    GO

    IF OBJECT_ID(N'sp_dump_dtstasklog') IS NOT NULL

    DROP PROCEDURE sp_dump_dtstasklog

    GO

    CREATE PROCEDURE sp_dump_dtstasklog

    @stepexecutionidBIGINT,

    @sequenceidINT = NULL

    AS

    SET NOCOUNT ON

    --// sysadmin only.

    IF (ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) <> 1)

    BEGIN

    RAISERROR(15003, 16, 1, N'sysadmin')

    RETURN(1) -- Failure

    END

    --// Don't error if no entries found, as the desired result will be met.

    DELETE sysdtstasklog

    WHERE (stepexecutionid IS NULL or stepexecutionid = @stepexecutionid)

    AND (@sequenceid IS NULL OR sequenceid = @sequenceid)

    RETURN 0 -- SUCCESS

    GO

    GRANT EXECUTE ON sp_dump_dtstasklog TO PUBLIC

    GO

    /**************************************************************/

    /* */

    /* D B M A I N T E N A N C E P L A N S */

    /* */

    /**************************************************************/

    /**************************************************************/

    /* SYSDBMAINTPLANS */

    /**************************************************************/

    IF (NOT EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = N'sysdbmaintplans')

    AND (type = 'U')))

    BEGIN

    PRINT ''

    PRINT 'Creating table sysdbmaintplans...'

    CREATE TABLE sysdbmaintplans

    (

    plan_id UNIQUEIDENTIFIER NOT NULL PRIMARY KEY CLUSTERED,

    plan_name sysname NOT NULL,

    date_created DATETIME NOT NULL DEFAULT (GETDATE()),

    owner sysname NOT NULL DEFAULT (ISNULL(NT_CLIENT(), SUSER_SNAME())),

    max_history_rows INT NOT NULL DEFAULT (0),

    remote_history_server sysname NOT NULL DEFAULT (''),

    max_remote_history_rows INT NOT NULL DEFAULT (0),

    user_defined_1 INT NULL,

    user_defined_2 NVARCHAR(100) NULL,

    user_defined_3 DATETIME NULL,

    user_defined_4 UNIQUEIDENTIFIER NULL

    )

    END

    go

    -- Add row for "plan 0"

    IF (NOT EXISTS (SELECT *

    FROM msdb.dbo.sysdbmaintplans

    WHERE (plan_id = CONVERT(UNIQUEIDENTIFIER, 0x00))))

    INSERT INTO sysdbmaintplans(plan_id, plan_name, owner) VALUES (0x00, N'All ad-hoc plans', N'sa')

    go

    /**************************************************************/

    /* SYSDBMAINTPLAN_JOBS */

    /**************************************************************/

    IF (NOT EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = N'sysdbmaintplan_jobs')

    AND (type = 'U')))

    BEGIN

    PRINT ''

    PRINT 'Creating table sysdbmaintplan_jobs...'

    CREATE TABLE sysdbmaintplan_jobs

    (

    plan_id UNIQUEIDENTIFIER NOT NULL UNIQUE CLUSTERED (plan_id, job_id)

    FOREIGN KEY REFERENCES msdb.dbo.sysdbmaintplans (plan_id),

    job_id UNIQUEIDENTIFIER NOT NULL

    )

    END

    go

    /**************************************************************/

    /* SYSDBMAINTPLAN_DATABASES */

    /**************************************************************/

    IF (NOT EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = N'sysdbmaintplan_databases')

    AND (type = 'U')))

    BEGIN

    PRINT ''

    PRINT 'Creating table sysdbmaintplan_databases...'

    CREATE TABLE sysdbmaintplan_databases

    (

    plan_id UNIQUEIDENTIFIER NOT NULL UNIQUE CLUSTERED (plan_id, database_name)

    FOREIGN KEY REFERENCES msdb.dbo.sysdbmaintplans (plan_id),

    database_name sysname NOT NULL

    )

    END

    go

    /**************************************************************/

    /* SYSDBMAINTPLAN_HISTORY */

    /**************************************************************/

    IF (NOT EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = N'sysdbmaintplan_history')

    AND (type = 'U')))

    BEGIN

    PRINT ''

    PRINT 'Creating table sysdbmaintplan_history...'

    CREATE TABLE sysdbmaintplan_history

    (

    sequence_id INT NOT NULL IDENTITY UNIQUE NONCLUSTERED,

    plan_id UNIQUEIDENTIFIER NOT NULL DEFAULT('00000000-0000-0000-0000-000000000000'),

    plan_name sysname NOT NULL DEFAULT('All ad-hoc plans'),

    database_name sysname NULL,

    server_name sysname NOT NULL DEFAULT (CONVERT(sysname, ServerProperty('ServerName'))),

    activity NVARCHAR(128) NULL,

    succeeded BIT NOT NULL DEFAULT (1),

    end_time DATETIME NOT NULL DEFAULT (GETDATE()),

    duration INT NULL DEFAULT (0),

    start_time AS DATEADD (ss, -duration, end_time),

    error_number INT NOT NULL DEFAULT (0),

    message NVARCHAR(512) NULL

    )

    CREATE CLUSTERED INDEX clust ON sysdbmaintplan_history(plan_id)

    END

    -- ALTER TABLE to correct default constraint

    ELSE

    BEGIN

    CREATE TABLE #t

    (

    constraint_type NVARCHAR(146) COLLATE database_default NULL,

    constraint_name sysname COLLATE database_default NULL,

    delete_action NVARCHAR(20) COLLATE database_default NULL,

    update_action NVARCHAR(20) COLLATE database_default NULL,

    status_enabled NVARCHAR(20) COLLATE database_default NULL,

    status_for_replication NVARCHAR(20) COLLATE database_default NULL,

    constraint_keys NVARCHAR(2126) COLLATE database_default NULL

    )

    INSERT INTO #t EXEC sp_helpconstraint N'sysdbmaintplan_history', 'nomsg'

    DECLARE @constraint_name sysname

    DECLARE @sql NVARCHAR(4000)

    SELECT @constraint_name = constraint_name

    FROM #t

    WHERE constraint_type = N'DEFAULT on column server_name'

    AND constraint_keys = N'(@@servername)'

    DROP TABLE #t

    -- default found

    IF (@constraint_name IS NOT NULL)

    BEGIN

    PRINT ''

    PRINT 'Alter sysdbmaintplan_history ...'

    SELECT @sql = N'ALTER TABLE sysdbmaintplan_history DROP CONSTRAINT ' + @constraint_name

    EXEC (@sql)

    ALTER TABLE sysdbmaintplan_history

    ADD CONSTRAINT servername_default DEFAULT (CONVERT(sysname, ServerProperty('ServerName')))

    FOR server_name

    END

    END

    go

    /**************************************************************/

    /* SPs for the maintenance plans */

    /**************************************************************/

    /**************************************************************/

    /* sp_clear_dbmaintplan_by_db */

    /**************************************************************/

    PRINT ''

    PRINT 'Creating procedure sp_clear_dbmaintplan_by_db...'

    GO

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = N'sp_clear_dbmaintplan_by_db') AND (type = 'P')))

    DROP PROCEDURE sp_clear_dbmaintplan_by_db

    GO

    CREATE PROCEDURE sp_clear_dbmaintplan_by_db

    @db_name sysname

    AS

    BEGIN

    DECLARE planid_cursor CURSOR

    FOR

    select plan_id from msdb.dbo.sysdbmaintplan_databases where database_name=@db_name

    OPEN planid_cursor

    declare @planid uniqueidentifier

    FETCH NEXT FROM planid_cursor INTO @planid

    WHILE (@@FETCH_STATUS <> -1)

    BEGIN

    IF (@@FETCH_STATUS <> -2)

    BEGIN

    delete from msdb.dbo.sysdbmaintplan_databases where plan_id=@planid AND database_name=@db_name

    if (NOT EXISTS(select * from msdb.dbo.sysdbmaintplan_databases where plan_id=@planid))

    BEGIN

    --delete the job

    DECLARE jobid_cursor CURSOR

    FOR

    select job_id from msdb.dbo.sysdbmaintplan_jobs where plan_id=@planid

    OPEN jobid_cursor

    DECLARE @jobid uniqueidentifier

    FETCH NEXT FROM jobid_cursor INTO @jobid

    WHILE (@@FETCH_STATUS <> -1)

    BEGIN

    if (@@FETCH_STATUS <> -2)

    BEGIN

    execute msdb.dbo.sp_delete_job @jobid

    END

    FETCH NEXT FROM jobid_cursor into @jobid

    END

    CLOSE jobid_cursor

    DEALLOCATE jobid_cursor

    --delete the history

    delete from msdb.dbo.sysdbmaintplan_history where plan_id=@planid

    --delete the plan

    delete from msdb.dbo.sysdbmaintplans where plan_id=@planid

    END

    END

    FETCH NEXT FROM planid_cursor INTO @planid

    END

    CLOSE planid_cursor

    DEALLOCATE planid_cursor

    END

    GO

    /**************************************************************/

    /* sp_add_maintenance_plan */

    /**************************************************************/

    PRINT ''

    PRINT 'Creating procedure sp_add_maintenance_plan...'

    GO

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = N'sp_add_maintenance_plan') AND (type = 'P')))

    DROP PROCEDURE sp_add_maintenance_plan

    GO

    CREATE PROCEDURE sp_add_maintenance_plan

    @plan_name varchar(128),

    @plan_id UNIQUEIDENTIFIER OUTPUT

    AS

    BEGIN

    IF (NOT EXISTS (SELECT *

    FROM msdb.dbo.sysdbmaintplans

    WHERE plan_name=@plan_name))

    BEGIN

    SELECT @plan_id=NEWID()

    INSERT INTO msdb.dbo.sysdbmaintplans (plan_id, plan_name) VALUES (@plan_id, @plan_name)

    END

    ELSE

    BEGIN

    RAISERROR(14261,-1,-1,'@plan_name',@plan_name)

    RETURN(1) -- failure

    END

    END

    GO

    /**************************************************************/

    /* sp_delete_maintenance_plan */

    /**************************************************************/

    PRINT ''

    PRINT 'Creating procedure sp_delete_maintenance_plan...'

    GO

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = N'sp_delete_maintenance_plan')

    AND (type = 'P')))

    DROP PROCEDURE sp_delete_maintenance_plan

    GO

    CREATE PROCEDURE sp_delete_maintenance_plan

    @plan_id UNIQUEIDENTIFIER

    AS

    BEGIN

    /*check if the plan_id is valid*/

    IF (NOT EXISTS(SELECT *

    FROM sysdbmaintplans

    WHERE plan_id=@plan_id))

    BEGIN

    DECLARE @syserr VARCHAR(100)

    SELECT @syserr=CONVERT(VARCHAR(100),@plan_id)

    RAISERROR(14262,-1,-1,'@plan_id',@syserr)

    RETURN(1)

    END

    /* clean the related records in sysdbmaintplan_database */

    DELETE FROM msdb.dbo.sysdbmaintplan_databases

    WHERE plan_id=@plan_id

    /* clean the related records in sysdbmaintplan_jobs*/

    DELETE FROM msdb.dbo.sysdbmaintplan_jobs

    WHERE plan_id=@plan_id

    /* clean sysdbmaintplans */

    DELETE FROM msdb.dbo.sysdbmaintplans

    WHERE plan_id= @plan_id

    END

    GO

    /**************************************************************/

    /* sp_add_maintenance_plan_db */

    /**************************************************************/

    PRINT ''

    PRINT 'Creating procedure sp_add_maintenance_plan_db...'

    GO

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = N'sp_add_maintenance_plan_db')

    AND (type = 'P')))

    DROP PROCEDURE sp_add_maintenance_plan_db

    GO

    CREATE PROCEDURE sp_add_maintenance_plan_db

    @plan_id UNIQUEIDENTIFIER,

    @db_name sysname

    AS

    BEGIN

    DECLARE @syserr VARCHAR(100)

    /*check if the plan_id is valid */

    IF (NOT EXISTS (SELECT plan_id

    FROM msdb.dbo.sysdbmaintplans

    WHERE plan_id=@plan_id))

    BEGIN

    SELECT @syserr=CONVERT(VARCHAR(100),@plan_id)

    RAISERROR(14262,-1,-1,'@plan_id',@syserr)

    RETURN(1)

    END

    /*check if the database name is valid */

    IF (NOT EXISTS (SELECT name

    FROM master.dbo.sysdatabases

    WHERE name=@db_name))

    BEGIN

    RAISERROR(14262,-1,-1,'@db_name',@db_name)

    RETURN(1)

    END

    /*check if the (plan_id, database) pair already exists*/

    IF (EXISTS (SELECT *

    FROM sysdbmaintplan_databases

    WHERE plan_id=@plan_id AND database_name=@db_name))

    BEGIN

    SELECT @syserr=CONVERT(VARCHAR(100),@plan_id)+' + '+@db_name

    RAISERROR(14261,-1,-1,'@plan_id+@db_name',@syserr)

    RETURN(1)

    END

    INSERT INTO msdb.dbo.sysdbmaintplan_databases (plan_id,database_name) VALUES (@plan_id, @db_name)

    END

    GO

    /**************************************************************/

    /* sp_delete_maintenance_plan_db */

    /**************************************************************/

    PRINT ''

    PRINT 'Creating procedure sp_delete_maintenance_plan_db...'

    go

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = N'sp_delete_maintenance_plan_db')

    AND (type = 'P')))

    DROP PROCEDURE sp_delete_maintenance_plan_db

    go

    CREATE PROCEDURE sp_delete_maintenance_plan_db

    @plan_id uniqueidentifier,

    @db_name sysname

    AS

    BEGIN

    /*check if the (plan_id, db_name) exists in the table*/

    IF (NOT EXISTS(SELECT *

    FROM msdb.dbo.sysdbmaintplan_databases

    WHERE @plan_id=plan_id AND @db_name=database_name))

    BEGIN

    DECLARE @syserr VARCHAR(300)

    SELECT @syserr=CONVERT(VARCHAR(100),@plan_id)+' + '+@db_name

    RAISERROR(14262,-1,-1,'@plan_id+@db_name',@syserr)

    RETURN(1)

    END

    /*delete the pair*/

    DELETE FROM msdb.dbo.sysdbmaintplan_databases

    WHERE plan_id=@plan_id AND database_name=@db_name

    END

    GO

    /**************************************************************/

    /* sp_add_maintenance_plan_job */

    /**************************************************************/

    PRINT ''

    PRINT 'Creating procedure sp_add_maintenance_plan_job...'

    GO

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = N'sp_add_maintenance_plan_job')

    AND (type = 'P')))

    DROP PROCEDURE sp_add_maintenance_plan_job

    GO

    CREATE PROCEDURE sp_add_maintenance_plan_job

    @plan_id UNIQUEIDENTIFIER,

    @job_id UNIQUEIDENTIFIER

    AS

    BEGIN

    DECLARE @syserr varchar(100)

    /*check if the @plan_id is valid*/

    IF (NOT EXISTS(SELECT plan_id

    FROM msdb.dbo.sysdbmaintplans

    WHERE plan_id=@plan_id))

    BEGIN

    SELECT @syserr=CONVERT(VARCHAR(100),@plan_id)

    RAISERROR(14262,-1,-1,'@plan_id',@syserr)

    RETURN(1)

    END

    /*check if the @job_id is valid*/

    IF (NOT EXISTS(SELECT job_id

    FROM msdb.dbo.sysjobs

    WHERE job_id=@job_id))

    BEGIN

    SELECT @syserr=CONVERT(VARCHAR(100),@job_id)

    RAISERROR(14262,-1,-1,'@job_id',@syserr)

    RETURN(1)

    END

    /*check if the job has at least one step calling xp_sqlmaint*/

    DECLARE @maxind INT

    SELECT @maxind=(SELECT MAX(CHARINDEX('xp_sqlmaint', command))

    FROM msdb.dbo.sysjobsteps

    WHERE @job_id=job_id)

    IF (@maxind<=0)

    BEGIN

    /*print N'Warning: The job is not for maitenance plan.' -- will add the new sysmessage here*/

    SELECT @syserr=CONVERT(VARCHAR(100),@job_id)

    RAISERROR(14199,-1,-1,'@job_id',@syserr)

    RETURN(1)

    END

    INSERT INTO msdb.dbo.sysdbmaintplan_jobs(plan_id,job_id) VALUES (@plan_id, @job_id) --don't have to check duplicate here

    END

    GO

    /**************************************************************/

    /* sp_delete_maintenance_plan_job */

    /**************************************************************/

    PRINT ''

    PRINT 'Creating procedure sp_delete_maintenance_plan_job...'

    GO

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = N'sp_delete_maintenance_plan_job')

    AND (type = 'P')))

    DROP PROCEDURE sp_delete_maintenance_plan_job

    GO

    CREATE PROCEDURE sp_delete_maintenance_plan_job

    @plan_id uniqueidentifier,

    @job_id uniqueidentifier

    AS

    BEGIN

    /*check if the (plan_id, job_id) exists*/

    IF (NOT EXISTS(SELECT *

    FROM sysdbmaintplan_jobs

    WHERE @plan_id=plan_id AND @job_id=job_id))

    BEGIN

    DECLARE @syserr VARCHAR(300)

    SELECT @syserr=CONVERT(VARCHAR(100),@plan_id)+' + '+CONVERT(VARCHAR(100),@job_id)

    RAISERROR(14262,-1,-1,'@plan_id+@job_id',@syserr)

    RETURN(1)

    END

    DELETE FROM msdb.dbo.sysdbmaintplan_jobs

    WHERE plan_id=@plan_id AND job_id=@job_id

    END

    GO

    /**************************************************************/

    /* sp_help_maintenance_plan */

    /**************************************************************/

    PRINT ''

    PRINT 'Creating procedure sp_help_maintenance_plan...'

    GO

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = N'sp_help_maintenance_plan')

    AND (type = 'P')))

    DROP PROCEDURE sp_help_maintenance_plan

    GO

    CREATE PROCEDURE sp_help_maintenance_plan

    @plan_id UNIQUEIDENTIFIER = NULL

    AS

    BEGIN

    IF (@plan_id IS NOT NULL)

    BEGIN

    /*return the information about the plan itself*/

    SELECT *

    FROM msdb.dbo.sysdbmaintplans

    WHERE plan_id=@plan_id

    /*return the information about databases this plan defined on*/

    SELECT database_name

    FROM msdb.dbo.sysdbmaintplan_databases

    WHERE plan_id=@plan_id

    /*return the information about the jobs that relating to the plan*/

    SELECT job_id

    FROM msdb.dbo.sysdbmaintplan_jobs

    WHERE plan_id=@plan_id

    END

    ELSE

    BEGIN

    SELECT *

    FROM msdb.dbo.sysdbmaintplans

    END

    END

    GO

    /**************************************************************/

    /* */

    /* B A C K U P H I S T O R Y */

    /* */

    /**************************************************************/

    /**************************************************************/

    /* sp_delete_database_backuphistory */

    /**************************************************************/

    PRINT ''

    PRINT 'Creating procedure sp_delete_database_backuphistory...'

    go

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = N'sp_delete_database_backuphistory')

    AND (type = 'P')))

    DROP PROCEDURE sp_delete_database_backuphistory

    go

    CREATE PROCEDURE sp_delete_database_backuphistory

    @db_nm nvarchar(256)

    AS

    BEGIN

    declare @bsid int

    declare @msid int

    declare @rows int

    declare @errorflag int

    declare @STR nvarchar(64)

    set nocount on

    set @errorflag = 0

    declare oldbackups insensitive cursor for

    select backup_set_id from backupset where database_name=@db_nm

    for read only

    open oldbackups

    fetch next from oldbackups into @bsid

    while(@@fetch_status = 0)

    begin

    begin transaction

    set rowcount 1

    set @rows = (select count(*) from restorehistory where backup_set_id = @bsid)

    set rowcount 0

    if (@rows > 0)

    begin

    delete from restorefile where restore_history_id in (select restore_history_id from restorehistory where backup_set_id = @bsid)

    if (@@error <> 0)

    begin

    rollback transaction

    set @errorflag = 1

    break

    end

    delete from restorefilegroup where restore_history_id in (select restore_history_id from restorehistory where backup_set_id = @bsid)

    if (@@error <> 0)

    begin

    rollback transaction

    set @errorflag = 1

    break

    end

    delete from restorehistory where backup_set_id = @bsid

    if (@@error <> 0)

    begin

    rollback transaction

    set @errorflag = 1

    break

    end

    end

    delete from backupfile where backup_set_id = @bsid

    if (@@error <> 0)

    begin

    rollback transaction

    set @errorflag = 1

    break

    end

    set @msid = (select media_set_id from backupset where backup_set_id = @bsid)

    delete from backupset where backup_set_id = @bsid

    if (@@error <> 0)

    begin

    rollback transaction

    set @errorflag = 1

    break

    end

    set rowcount 1

    set @rows = (select count(*) from backupset where media_set_id = @msid)

    set rowcount 0

    if (@rows = 0)

    begin

    delete from backupmediafamily where media_set_id = @msid

    if (@@error <> 0)

    begin

    rollback transaction

    set @errorflag = 1

    break

    end

    delete from backupmediaset where media_set_id = @msid

    if (@@error <> 0)

    begin

    rollback transaction

    set @errorflag = 1

    break

    end

    end

    commit transaction

    fetch next from oldbackups into @bsid

    end

    deallocate oldbackups

    set nocount off

    if (@errorflag <> 0)

    begin

    set @STR = (select convert( nvarchar(64), @bsid))

    raiserror( 4325, -1, -1, @STR )

    return(1)

    end

    END

    go

    /**************************************************************/

    /* SP_DELETE_BACKUPHISTORY */

    /**************************************************************/

    PRINT ''

    PRINT 'Creating procedure sp_delete_backuphistory...'

    go

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = N'sp_delete_backuphistory')

    AND (type = 'P')))

    DROP PROCEDURE sp_delete_backuphistory

    go

    CREATE PROCEDURE sp_delete_backuphistory

    @oldest_date datetime

    AS

    BEGIN

    declare @bsid int

    declare @msid int

    declare @rows int

    declare @errorflag int

    declare @STR nvarchar(64)

    set nocount on

    set @errorflag = 0

    declare oldbackups insensitive cursor for

    select backup_set_id from backupset where backup_finish_date < @oldest_date

    for read only

    open oldbackups

    fetch next from oldbackups into @bsid

    while(@@fetch_status = 0)

    begin

    begin transaction

    set rowcount 1

    set @rows = (select count(*) from restorehistory where backup_set_id = @bsid)

    set rowcount 0

    if (@rows > 0)

    begin

    delete from restorefile where restore_history_id in (select restore_history_id from restorehistory where backup_set_id = @bsid)

    if (@@error <> 0)

    begin

    rollback transaction

    set @errorflag = 1

    break

    end

    delete from restorefilegroup where restore_history_id in (select restore_history_id from restorehistory where backup_set_id = @bsid)

    if (@@error <> 0)

    begin

    rollback transaction

    set @errorflag = 1

    break

    end

    delete from restorehistory where backup_set_id = @bsid

    if (@@error <> 0)

    begin

    rollback transaction

    set @errorflag = 1

    break

    end

    end

    delete from backupfile where backup_set_id = @bsid

    if (@@error <> 0)

    begin

    rollback transaction

    set @errorflag = 1

    break

    end

    set @msid = (select media_set_id from backupset where backup_set_id = @bsid)

    delete from backupset where backup_set_id = @bsid

    if (@@error <> 0)

    begin

    rollback transaction

    set @errorflag = 1

    break

    end

    set rowcount 1

    set @rows = (select count(*) from backupset where media_set_id = @msid)

    set rowcount 0

    if (@rows = 0)

    begin

    delete from backupmediafamily where media_set_id = @msid

    if (@@error <> 0)

    begin

    rollback transaction

    set @errorflag = 1

    break

    end

    delete from backupmediaset where media_set_id = @msid

    if (@@error <> 0)

    begin

    rollback transaction

    set @errorflag = 1

    break

    end

    end

    commit transaction

    fetch next from oldbackups into @bsid

    end

    deallocate oldbackups

    set nocount off

    if (@errorflag <> 0)

    begin

    set @STR = (select convert( nvarchar(64), @bsid))

    raiserror( 4325, -1, -1, @STR )

    return(1)

    end

    set @STR = (select convert( nvarchar(64), @oldest_date))

    raiserror( 4324, -1, -1, @STR )

    return(0)

    END

    go

    /**************************************************************/

    /* SP_DELETE_BACKUP_AND_RESTORE_HISTORY */

    /**************************************************************/

    PRINT ''

    PRINT 'Creating procedure sp_delete_backup_and_restore_history...'

    go

    IF (EXISTS (SELECT *

    FROM msdb.dbo.sysobjects

    WHERE (name = 'sp_delete_backup_and_restore_history')

    AND (type = 'P')))

    DROP PROCEDURE sp_delete_backup_and_restore_history

    go

    CREATE PROCEDURE sp_delete_backup_and_restore_history

    @database_name sysname

    AS

    BEGIN

    SET NOCOUNT ON

    CREATE TABLE #backup_set_id (backup_set_id INT)

    CREATE TABLE #media_set_id (media_set_id INT)

    CREATE TABLE #restore_history_id (restore_history_id INT)

    INSERT INTO #backup_set_id (backup_set_id)

    SELECT DISTINCT backup_set_id

    FROM msdb.dbo.backupset

    WHERE database_name = @database_name

    INSERT INTO #media_set_id (media_set_id)

    SELECT DISTINCT media_set_id

    FROM msdb.dbo.backupset

    WHERE database_name = @database_name

    INSERT INTO #restore_history_id (restore_history_id)

    SELECT DISTINCT restore_history_id

    FROM msdb.dbo.restorehistory

    WHERE backup_set_id IN (SELECT backup_set_id

    FROM #backup_set_id)

    BEGIN TRANSACTION

    DELETE FROM msdb.dbo.backupfile

    WHERE backup_set_id IN (SELECT backup_set_id

    FROM #backup_set_id)

    IF (@@error > 0)

    GOTO Quit

    DELETE FROM msdb.dbo.restorefile

    WHERE restore_history_id IN (SELECT restore_history_id

    FROM #restore_history_id)

    IF (@@error > 0)

    GOTO Quit

    DELETE FROM msdb.dbo.restorefilegroup

    WHERE restore_history_id IN (SELECT restore_history_id

    FROM #restore_history_id)

    IF (@@error > 0)

    GOTO Quit

    DELETE FROM msdb.dbo.restorehistory

    WHERE restore_history_id IN (SELECT restore_history_id

    FROM #restore_history_id)

    IF (@@error > 0)

    GOTO Quit

    DELETE FROM msdb.dbo.backupset

    WHERE backup_set_id IN (SELECT backup_set_id

    FROM #backup_set_id)

    IF (@@error > 0)

    GOTO Quit

    DELETE msdb.dbo.backupmediafamily

    FROM msdb.dbo.backupmediafamily bmf

    WHERE bmf.media_set_id IN (SELECT media_set_id

    FROM #media_set_id)

    AND ((SELECT COUNT(*)

    FROM msdb.dbo.backupset

    WHERE media_set_id = bmf.media_set_id) = 0)

    IF (@@error > 0)

    GOTO Quit

    DELETE msdb.dbo.backupmediaset

    FROM msdb.dbo.backupmediaset bms

    WHERE bms.media_set_id IN (SELECT media_set_id

    FROM #media_set_id)

    AND ((SELECT COUNT(*)

    FROM msdb.dbo.backupset

    WHERE media_set_id = bms.media_set_id) = 0)

    IF (@@error > 0)

    GOTO Quit

    COMMIT TRANSACTION

    RETURN

    Quit:

    ROLLBACK TRANSACTION

    END

    go

    /**********************************************************************/

    /* TABLE : log_shipping_primaries */

    /* Populated on the monitor server */

    /* */

    /**********************************************************************/

    IF (NOT EXISTS (SELECT *

    FROM INFORMATION_SCHEMA.TABLES

    WHERE (TABLE_NAME = N'log_shipping_primaries')))

    BEGIN

    PRINT ''

    PRINT 'Creating table log_shipping_primaries...'

    CREATE TABLE log_shipping_primaries

    (

    primary_id INT IDENTITY NOT NULL PRIMARY KEY,

    primary_server_name sysname NOT NULL,

    primary_database_name sysname NOT NULL,

    maintenance_plan_id UNIQUEIDENTIFIER NULL,

    backup_threshold INT NOT NULL,

    threshold_alert INT NOT NULL,

    threshold_alert_enabled BIT NOT NULL, /* 1 = enabled, 0 = disabled */

    last_backup_filename NVARCHAR(500) NULL,

    last_updated DATETIME NULL,

    planned_outage_start_time INT NOT NULL,

    planned_outage_end_time INT NOT NULL,

    planned_outage_weekday_mask INT NOT NULL,

    source_directory NVARCHAR(500) NULL

    )

    END

    ELSE

    BEGIN

    IF (NOT EXISTS (SELECT *

    FROM INFORMATION_SCHEMA.COLUMNS

    WHERE (TABLE_NAME = N'log_shipping_primaries')

    AND (COLUMN_NAME = N'source_directory')))

    BEGIN

    PRINT ''

    PRINT 'Adding columns to table log_shipping_primaries...'

    ALTER TABLE log_shipping_primaries

    ADD source_directory NVARCHAR(500) NULL

    END

    END

    go

    /**********************************************************************/

    /* TABLE : log_shipping_secondaries */

    /* Populated on the monitor server */

    /* */

    /**********************************************************************/

    IF (NOT EXISTS (SELECT *

    FROM INFORMATION_SCHEMA.TABLES

    WHERE (TABLE_NAME = N'log_shipping_secondaries')))

    BEGIN

    PRINT ''

    PRINT 'Creating table log_shipping_secondaries...'

    CREATE TABLE log_shipping_secondaries

    (

    primary_id INT FOREIGN KEY REFERENCES log_shipping_primaries (primary_id),

    secondary_server_name sysname,

    secondary_database_name sysname,

    last_copied_filename NVARCHAR(500),

    last_loaded_filename NVARCHAR(500),

    last_copied_last_updated DATETIME,

    last_loaded_last_updated DATETIME,

    secondary_plan_id UNIQUEIDENTIFIER,

    copy_enabled BIT,

    load_enabled BIT, /* 1 = load enabled, 0 = load disabled */

    out_of_sync_threshold INT,

    threshold_alert INT,

    threshold_alert_enabled BIT, /*1 = enabled, 0 = disabled */

    planned_outage_start_time INT,

    planned_outage_end_time INT,

    planned_outage_weekday_mask INT,

    allow_role_change BIT DEFAULT (0)

    )

    END

    ELSE

    BEGIN

    IF (NOT EXISTS (SELECT *

    FROM INFORMATION_SCHEMA.COLUMNS

    WHERE (TABLE_NAME = N'log_shipping_secondaries')

    AND (COLUMN_NAME = N'allow_role_change')))

    BEGIN

    PRINT ''

    PRINT 'Adding columns to table log_shipping_secondaries...'

    ALTER TABLE log_shipping_secondaries

    ADD allow_role_change BIT DEFAULT (0)

    END

    END

    go

    /**************************************************************/

    /* sp_add_log_shipping_monitor_jobs */

    /**************************************************************/

    PRINT ''

    PRINT 'Creating procedure sp_add_log_shipping_monitor_jobs...'

    go

    IF (EXISTS (SELECT * from msdb.dbo.sysobjects WHERE name = N'sp_add_log_shipping_monitor_jobs' AND type = N'P') )

    drop procedure sp_add_log_shipping_monitor_jobs

    go

    CREATE PROCEDURE sp_add_log_shipping_monitor_jobs AS

    BEGIN

    SET NOCOUNT ON

    BEGIN TRANSACTION

    DECLARE @rv INT

    DECLARE @backup_job_name sysname

    SET @backup_job_name = N'Log Shipping Alert Job - Backup'

    IF (NOT EXISTS (SELECT * FROM msdb.dbo.sysjobs WHERE name = @backup_job_name))

    BEGIN

    EXECUTE @rv = msdb.dbo.sp_add_job @job_name = N'Log Shipping Alert Job - Backup'

    IF (@@error <> 0 OR @rv <> 0) GOTO rollback_quit -- error

    EXECUTE @rv = msdb.dbo.sp_add_jobstep

    @job_name = N'Log Shipping Alert Job - Backup',

    @step_id = 1,

    @step_name = N'Log Shipping Alert - Backup',

    @command = N'EXECUTE msdb.dbo.sp_log_shipping_monitor_backup',

    @on_fail_action = 2,

    @flags = 4,

    @subsystem = N'TSQL',

    @on_success_step_id = 0,

    @on_success_action = 1,

    @on_fail_step_id = 0

    IF (@@error <> 0 OR @rv <> 0) GOTO rollback_quit -- error

    EXECUTE @rv = msdb.dbo.sp_add_jobschedule

    @job_name = @backup_job_name,

    @freq_type = 4,

    @freq_interval = 1,

    @freq_subday_type = 0x4,

    @freq_subday_interval = 1, -- run every minute

    @freq_relative_interval = 0,

    @name = @backup_job_name

    IF (@@error <> 0 OR @rv <> 0) GOTO rollback_quit -- error

    EXECUTE @rv = msdb.dbo.sp_add_jobserver @job_name = @backup_job_name, @server_name = NULL

    IF (@@error <> 0 OR @rv <> 0) GOTO rollback_quit -- error

    END

    DECLARE @restore_job_name sysname

    SET @restore_job_name = 'Log Shipping Alert Job - Restore'

    IF (NOT EXISTS (SELECT * FROM msdb.dbo.sysjobs WHERE name = @restore_job_name))

    BEGIN

    EXECUTE @rv = msdb.dbo.sp_add_job @job_name = @restore_job_name

    IF (@@error <> 0 OR @rv <> 0) GOTO rollback_quit -- error

    EXECUTE @rv = msdb.dbo.sp_add_jobstep

    @job_name = @restore_job_name,

    @step_id = 1,

    @step_name = @restore_job_name,

    @command = N'EXECUTE msdb.dbo.sp_log_shipping_monitor_restore',

    @on_fail_action = 2,

    @flags = 4,

    @subsystem = N'TSQL',

    @on_success_step_id = 0,

    @on_success_action = 1,

    @on_fail_step_id = 0

    IF (@@error <> 0 OR @rv <> 0) GOTO rollback_quit -- error

    EXECUTE @rv = msdb.dbo.sp_add_jobschedule

    @job_name = @restore_job_name,

    @freq_type = 4,

    @freq_interval = 1,

    @freq_subday_type = 0x4,

    @freq_subday_interval = 1, -- run every minute

    @freq_relative_interval = 0,

    @name = @restore_job_name

    IF (@@error <> 0 OR @rv <> 0) GOTO rollback_quit -- error

    EXECUTE @rv = msdb.dbo.sp_add_jobserver @job_name = @restore_job_name, @server_name = NULL

    IF (@@error <> 0 OR @rv <> 0) GOTO rollback_quit -- error

    END

    COMMIT TRANSACTION

    RETURN

    rollback_quit:

    ROLLBACK TRANSACTION

    END

    go

    /**************************************************************/

    /* sp_add_log_shipping_primary */

    /**************************************************************/

    PRINT ''

    PRINT 'Creating procedure sp_add_log_shipping_primary...'

    go

    IF (EXISTS (SELECT * from msdb.dbo.sysobjects WHERE name = N'sp_add_log_shipping_primary' AND type = N'P'))

    drop procedure sp_add_log_shipping_primary

    go

    CREATE PROCEDURE sp_add_log_shipping_primary

    @primary_server_name sysname,

    @primary_database_name sysname,

    @maintenance_plan_id UNIQUEIDENTIFIER = NULL,

    @backup_threshold INT = 60,

    @threshold_alert INT = 14420,

    @threshold_alert_enabled BIT = 1,

    @planned_outage_start_time INT = 0,

    @planned_outage_end_time INT = 0,

    @planned_outage_weekday_mask INT = 0,

    @primary_id INT = NULL OUTPUT

    AS

    BEGIN

    SET NOCOUNT ON

    IF EXISTS (SELECT * FROM msdb.dbo.log_shipping_primaries WHERE primary_server_name = @primary_server_name AND primary_database_name = @primary_database_name)

    BEGIN

    DECLARE @pair_name NVARCHAR

    SELECT @pair_name = @primary_server_name + N'.' + @primary_database_name

    RAISERROR (14261,16,1, N'primary_server_name.primary_database_name', @pair_name)

    RETURN (1) -- error

    END

    INSERT INTO msdb.dbo.log_shipping_primaries (

    primary_server_name,

    primary_database_name,

    maintenance_plan_id,

    backup_threshold,

    threshold_alert,

    threshold_alert_enabled,

    last_backup_filename,

    last_updated,

    planned_outage_start_time,

    planned_outage_end_time,

    planned_outage_weekday_mask,

    source_directory)

    VALUES (@primary_server_name,

    @primary_database_name,

    @maintenance_plan_id,

    @backup_threshold,

    @threshold_alert,

    @threshold_alert_enabled,

    N'first_file_000000000000.trn',

    GETDATE (),

    @planned_outage_start_time,

    @planned_outage_end_time,

    @planned_outage_weekday_mask,

    NULL)

    SELECT @primary_id = @@IDENTITY

    EXECUTE msdb.dbo.sp_add_log_shipping_monitor_jobs

    END

    go

    /**************************************************************/

    /* sp_add_log_shipping_secondary */

    /**************************************************************/

    PRINT ''

    PRINT 'Creating procedure sp_add_log_shipping_secondary...'

    go

    IF (EXISTS (SELECT * from msdb.dbo.sysobjects WHERE name = N'sp_add_log_shipping_secondary' AND type = N'P'))

    drop procedure sp_add_log_shipping_secondary

    go

    CREATE PROCEDURE sp_add_log_shipping_secondary

    @primary_id INT,

    @secondary_server_name sysname,

    @secondary_database_name sysname,

    @secondary_plan_id UNIQUEIDENTIFIER,

    @copy_enabled BIT = 1,

    @load_enabled BIT = 1,

    @out_of_sync_threshold INT = 60,

    @threshold_alert INT = 14421,

    @threshold_alert_enabled BIT = 1,

    @planned_outage_start_time INT = 0,

    @planned_outage_end_time INT = 0,

    @planned_outage_weekday_mask INT = 0,

    @allow_role_change BIT = 0

    AS

    BEGIN

    SET NOCOUNT ON

    IF NOT EXISTS (SELECT * FROM msdb.dbo.log_shipping_primaries where primary_id = @primary_id)

    BEGIN

    RAISERROR (14262, 16, 1, N'primary_id', N'msdb.dbo.log_shipping_primaries')

    RETURN(1)

    END

    INSERT INTO msdb.dbo.log_shipping_secondaries (

    primary_id,

    secondary_server_name,

    secondary_database_name,

    last_copied_filename,

    last_loaded_filename,

    last_copied_last_updated,

    last_loaded_last_updated,

    secondary_plan_id,

    copy_enabled,

    load_enabled,

    out_of_sync_threshold,

    threshold_alert,

    threshold_alert_enabled,

    planned_outage_start_time,

    planned_outage_end_time,

    planned_outage_weekday_mask,

    allow_role_change)

    VALUES (@primary_id,

    @secondary_server_name,

    @secondary_database_name,

    N'first_file_000000000000.trn',

    N'first_file_000000000000.trn',

    GETDATE (),

    GETDATE (),

    @secondary_plan_id,

    @copy_enabled,

    @load_enabled,

    @out_of_sync_threshold,

    @threshold_alert,

    @threshold_alert_enabled,

    @planned_outage_start_time,

    @planned_outage_end_time,

    @planned_outage_weekday_mask,

    @allow_role_change)

    END

    go

    /**************************************************************/

    /* sp_delete_log_shipping_monitor_jobs */

    /**************************************************************/

    PRINT ''

    PRINT 'Creating procedure sp_delete_log_shipping_monitor_jobs...'

    go

    IF (EXISTS (SELECT * from msdb.dbo.sysobjects WHERE name = N'sp_delete_log_shipping_monitor_jobs' AND type = N'P') )

    drop procedure sp_delete_log_shipping_monitor_jobs

    go

    CREATE PROCEDURE sp_delete_log_shipping_monitor_jobs AS

    BEGIN

    DECLARE @backup_job_name sysname

    SET NOCOUNT ON

    SET @backup_job_name = N'Log Shipping Alert Job - Backup'

    IF (EXISTS (SELECT * FROM msdb.dbo.sysjobs WHERE name = @backup_job_name))

    EXECUTE msdb.dbo.sp_delete_job @job_name = N'Log Shipping Alert Job - Backup'

    DECLARE @restore_job_name sysname

    SET @restore_job_name = 'Log Shipping Alert Job - Restore'

    IF (EXISTS (SELECT * FROM msdb.dbo.sysjobs WHERE name = @restore_job_name))

    EXECUTE msdb.dbo.sp_delete_job @job_name = N'Log Shipping Alert Job - Restore'

    END

    go

    /**************************************************************/

    /* sp_delete_log_shipping_primary */

    /**************************************************************/

    PRINT ''

    PRINT 'Creating procedure sp_delete_log_shipping_primary...'

    go

    IF (EXISTS (SELECT * from msdb.dbo.sysobjects WHERE name = N'sp_delete_log_shipping_primary' AND type = N'P') )

    drop procedure sp_delete_log_shipping_primary

    go

    CREATE PROCEDURE sp_delete_log_shipping_primary

    @primary_server_name sysname,

    @primary_database_name sysname,

    @delete_secondaries BIT = 0

    AS BEGIN

    DECLARE @primary_id INT

    SET NOCOUNT ON

    SELECT @primary_id = primary_id

    FROM msdb.dbo.log_shipping_primaries

    WHERE primary_server_name = @primary_server_name AND primary_database_name = @primary_database_name

    IF (@primary_id IS NULL)

    RETURN (0)

    BEGIN TRANSACTION

    IF (EXISTS (SELECT * FROM msdb.dbo.log_shipping_secondaries WHERE primary_id = @primary_id))

    BEGIN

    IF (@delete_secondaries = 0)

    BEGIN

    RAISERROR (14429,-1,-1)

    goto rollback_quit

    END

    DELETE FROM msdb.dbo.log_shipping_secondaries WHERE primary_id = @primary_id

    IF (@@ERROR <> 0)

    GOTO rollback_quit

    END

    DELETE FROM msdb.dbo.log_shipping_primaries WHERE primary_id = @primary_id

    IF (@@ERROR <> 0)

    GOTO rollback_quit

    COMMIT TRANSACTION

    DECLARE @i INT

    SELECT @i = COUNT(*) FROM msdb.dbo.log_shipping_primaries

    IF (@i=0)

    EXECUTE msdb.dbo.sp_delete_log_shipping_monitor_jobs

    RETURN (0)

    rollback_quit:

    ROLLBACK TRANSACTION

    RETURN(1) -- error

    END

    go

    /**************************************************************/

    /* sp_delete_log_shipping_secondary */

    /**************************************************************/

    PRINT ''

    PRINT 'Creating sp_delete_log_shipping_secondary...'

    go

    IF (EXISTS (SELECT * from msdb.dbo.sysobjects WHERE name = N'sp_delete_log_shipping_secondary' AND type = N'P') )

    drop procedure sp_delete_log_shipping_secondary

    go

    CREATE PROCEDURE sp_delete_log_shipping_secondary

    @secondary_server_name sysname,

    @secondary_database_name sysname

    AS BEGIN

    SET NOCOUNT ON

    DELETE FROM msdb.dbo.log_shipping_secondaries WHERE

    secondary_server_name = @secondary_server_name AND

    secondary_database_name = @secondary_database_name

    END

    go

    /**************************************************************/

    /* sp_log_shipping_in_sync */

    /**************************************************************/

    PRINT ''

    PRINT 'Creating procedure sp_log_shipping_in_sync...'

    go

    IF (EXISTS (SELECT * from msdb.dbo.sysobjects WHERE name = N'sp_log_shipping_in_sync' AND type = N'P') )

    drop procedure sp_log_shipping_in_sync

    go

    CREATE PROCEDURE sp_log_shipping_in_sync

    @last_updated DATETIME,

    @compare_with DATETIME,

    @threshold INT,

    @outage_start_time INT,

    @outage_end_time INT,

    @outage_weekday_mask INT,

    @enabled BIT = 1,

    @delta INT = NULL OUTPUT

    AS BEGIN

    SET NOCOUNT ON

    DECLARE @cur_time INT

    SELECT @delta = DATEDIFF (mi, @last_updated, @compare_with)

    -- in sync

    IF (@delta <= @threshold)

    RETURN (0) -- in sync

    IF (@enabled = 0)

    RETURN(0) -- in sync

    DECLARE @daybitmask int

    DECLARE @normalized_datefirst int

    SELECT @normalized_datefirst = (@@DATEFIRST + DATEPART(dw, GETDATE ())) % 7

    SELECT @daybitmask = POWER (2, @normalized_datefirst-1)

    IF ((@outage_weekday_mask & @daybitmask) > 0) -- in outage window

    BEGIN

    SELECT @cur_time = DATEPART (hh, GETDATE()) * 10000 +

    DATEPART (mi, GETDATE()) * 100 +

    DATEPART (ss, GETDATE())

    -- outage doesn't span midnight

    IF (@outage_start_time < @outage_end_time)

    BEGIN

    IF (@cur_time >= @outage_start_time AND @cur_time < @outage_end_time)

    RETURN(1) -- in outage

    END

    -- outage does span midnight

    ELSE IF (@outage_start_time > @outage_end_time)

    BEGIN

    IF (@cur_time >= @outage_start_time OR @cur_time < @outage_end_time)

    RETURN(1) -- in outage

    END

    END

    RETURN(-1 ) -- not in outage, not in sync

    END

    go

    /**************************************************************/

    /* sp_log_shipping_get_date_from_file */

    /**************************************************************/

    PRINT ''

    PRINT 'Creating procedure sp_log_shipping_get_date_from_file...'

    go

    IF (EXISTS (SELECT * from msdb.dbo.sysobjects WHERE name = N'sp_log_shipping_get_date_from_file' AND type = N'P') )

    drop procedure sp_log_shipping_get_date_from_file

    go

    CREATE PROCEDURE sp_log_shipping_get_date_from_file

    @db_name sysname,

    @filename NVARCHAR (500),

    @file_date DATETIME OUTPUT

    AS

    BEGIN

    SET NOCOUNT ON

    DECLARE @tempname NVARCHAR (500)

    IF (LEN (@filename) - (LEN(@db_name) + LEN ('_tlog_')) <= 0)

    RETURN(1) -- filename string isn't long enough

    SELECT @tempname = RIGHT (@filename, LEN (@filename) - (LEN(@db_name) + LEN ('_tlog_')))

    IF (CHARINDEX ('.',@tempname,0) > 0)

    SELECT @tempname = LEFT (@tempname, CHARINDEX ('.',@tempname,0) - 1)

    IF (LEN (@tempname) <> 8 AND LEN (@tempname) <> 12)

    RETURN (1) -- error must be yyyymmddhhmm or yyyymmdd

    IF (ISNUMERIC (@tempname) = 0 OR CHARINDEX ('.',@tempname,0) <> 0 OR CONVERT (FLOAT,SUBSTRING (@tempname, 1,8)) < 1 )

    RETURN (1) -- must be numeric, can't contain any '.' etc

    SELECT @file_date = CONVERT (DATETIME,SUBSTRING (@tempname, 1,8),112)

    IF (LEN (@tempname) = 12)

    BEGIN

    SELECT @file_date = DATEADD (hh, CONVERT (INT, SUBSTRING (@tempname,9,2)),@file_date)

    SELECT @file_date = DATEADD (mi, CONVERT (INT, SUBSTRING (@tempname,11,2)),@file_date)

    END

    RETURN (0) -- success

    END

    go

    /**************************************************************/

    /* sp_get_log_shipping_monitor_info */

    /**************************************************************/

    PRINT ''

    PRINT 'Creating procedure sp_get_log_shipping_monitor_info...'

    go

    IF (EXISTS (SELECT * from msdb.dbo.sysobjects WHERE name = N'sp_get_log_shipping_monitor_info' AND type = N'P') )

    drop procedure sp_get_log_shipping_monitor_info

    go

    CREATE PROCEDURE sp_get_log_shipping_monitor_info

    @primary_server_name sysname = N'%',

    @primary_database_name sysname = N'%',

    @secondary_server_name sysname = N'%',

    @secondary_database_name sysname = N'%'

    AS BEGIN

    SET NOCOUNT ON

    CREATE TABLE #lsp (

    primary_server_name sysname COLLATE database_default NOT NULL,

    primary_database_name sysname COLLATE database_default NOT NULL,

    secondary_server_name sysname COLLATE database_default NOT NULL,

    secondary_database_name sysname COLLATE database_default NOT NULL,

    backup_threshold INT NOT NULL,

    backup_threshold_alert INT NOT NULL,

    backup_threshold_alert_enabled BIT NOT NULL,

    last_backup_filename NVARCHAR(500) COLLATE database_default NOT NULL,

    last_backup_last_updated DATETIME NOT NULL,

    backup_outage_start_time INT NOT NULL,

    backup_outage_end_time INT NOT NULL,

    backup_outage_weekday_mask INT NOT NULL,

    backup_in_sync INT NULL, -- 0 = in sync, -1 = out of sync, 1 = in outage window

    backup_delta INT NULL,

    last_copied_filename NVARCHAR(500) COLLATE database_default NOT NULL,

    last_copied_last_updated DATETIME NOT NULL,

    last_loaded_filename NVARCHAR(500) COLLATE database_default NOT NULL,

    last_loaded_last_updated DATETIME NOT NULL,

    copy_delta INT NULL,

    copy_enabled BIT NOT NULL,

    load_enabled BIT NOT NULL,

    out_of_sync_threshold INT NOT NULL,

    load_threshold_alert INT NOT NULL,

    load_threshold_alert_enabled BIT NOT NULL,

    load_outage_start_time INT NOT NULL,

    load_outage_end_time INT NOT NULL,

    load_outage_weekday_mask INT NOT NULL,

    load_in_sync INT NULL, -- 0 = in sync, -1 = out of sync, 1 = in outage window

    load_delta INT NULL,

    maintenance_plan_id UNIQUEIDENTIFIER NULL,

    secondary_plan_id UNIQUEIDENTIFIER NOT NULL)

    INSERT INTO #lsp

    SELECT

    primary_server_name,

    primary_database_name,

    secondary_server_name,

    secondary_database_name,

    backup_threshold,

    p.threshold_alert,

    p.threshold_alert_enabled,

    last_backup_filename,

    p.last_updated,

    p.planned_outage_start_time,

    p.planned_outage_end_time,

    p.planned_outage_weekday_mask,

    NULL,

    NULL,

    last_copied_filename,

    last_copied_last_updated,

    last_loaded_filename,

    last_loaded_last_updated,

    NULL,

    copy_enabled,

    load_enabled,

    out_of_sync_threshold,

    s.threshold_alert,

    s.threshold_alert_enabled,

    s.planned_outage_start_time,

    s.planned_outage_end_time,

    s.planned_outage_weekday_mask,

    NULL,

    NULL,

    maintenance_plan_id,

    secondary_plan_id

    FROM msdb.dbo.log_shipping_primaries p, msdb.dbo.log_shipping_secondaries s

    WHERE

    p.primary_id = s.primary_id AND

    primary_server_name LIKE @primary_server_name AND

    primary_database_name LIKE @primary_database_name AND

    secondary_server_name LIKE @secondary_server_name AND

    secondary_database_name LIKE @secondary_database_name

    DECLARE @load_in_sync INT

    DECLARE @backup_in_sync INT

    DECLARE @_primary_server_name sysname

    DECLARE @_primary_database_name sysname

    DECLARE @_secondary_server_name sysname

    DECLARE @_secondary_database_name sysname

    DECLARE @last_loaded_last_updated DATETIME

    DECLARE @last_loaded_filename NVARCHAR (500)

    DECLARE @last_copied_filename NVARCHAR (500)

    DECLARE @last_backup_last_updated DATETIME

    DECLARE @last_backup_filename NVARCHAR (500)

    DECLARE @backup_outage_start_time INT

    DECLARE @backup_outage_end_time INT

    DECLARE @backup_outage_weekday_mask INT

    DECLARE @backup_threshold INT

    DECLARE @backup_threshold_alert_enabled BIT

    DECLARE @load_outage_start_time INT

    DECLARE @load_outage_end_time INT

    DECLARE @load_outage_weekday_mask INT

    DECLARE @load_threshold INT

    DECLARE @load_threshold_alert_enabled BIT

    DECLARE @backupdt DATETIME

    DECLARE @restoredt DATETIME

    DECLARE @copydt DATETIME

    DECLARE @rv INT

    DECLARE @dt DATETIME

    DECLARE @copy_delta INT

    DECLARE @load_delta INT

    DECLARE @backup_delta INT

    DECLARE @last_copied_last_updated DATETIME

    SELECT @dt = GETDATE ()

    DECLARE sync_update CURSOR FOR

    SELECT

    primary_server_name,

    primary_database_name,

    secondary_server_name,

    secondary_database_name,

    last_backup_filename,

    last_backup_last_updated,

    last_loaded_filename,

    last_loaded_last_updated,

    backup_outage_start_time,

    backup_outage_end_time,

    backup_outage_weekday_mask,

    backup_threshold,

    backup_threshold_alert_enabled,

    load_outage_start_time,

    load_outage_end_time,

    out_of_sync_threshold,

    load_outage_weekday_mask,

    load_threshold_alert_enabled,

    last_copied_filename,

    last_copied_last_updated

    FROM #lsp

    FOR READ ONLY

    OPEN sync_update

    loop:

    FETCH NEXT FROM sync_update INTO

    @_primary_server_name,

    @_primary_database_name,

    @_secondary_server_name,

    @_secondary_database_name,

    @last_backup_filename,

    @last_backup_last_updated,

    @last_loaded_filename,

    @last_loaded_last_updated,

    @backup_outage_start_time,

    @backup_outage_end_time,

    @backup_outage_weekday_mask,

    @backup_threshold,

    @backup_threshold_alert_enabled,

    @load_outage_start_time,

    @load_outage_end_time,

    @load_threshold,

    @load_outage_weekday_mask,

    @load_threshold_alert_enabled,

    @last_copied_filename,

    @last_copied_last_updated

    IF @@fetch_status <> 0

    GOTO _loop

    EXECUTE @rv = sp_log_shipping_get_date_from_file @_primary_database_name, @last_backup_filename, @backupdt OUTPUT

    IF (@rv <> 0)

    SElECT @backupdt = @last_backup_last_updated

    EXECUTE @rv = sp_log_shipping_get_date_from_file @_primary_database_name, @last_loaded_filename, @restoredt OUTPUT

    IF (@rv <> 0)

    SElECT @restoredt = @last_loaded_last_updated

    EXECUTE @rv = sp_log_shipping_get_date_from_file @_primary_database_name, @last_copied_filename, @copydt OUTPUT

    IF (@rv <> 0)

    SElECT @copydt = @last_copied_last_updated

    EXECUTE @load_in_sync = msdb.dbo.sp_log_shipping_in_sync

    @restoredt,

    @backupdt,

    @load_threshold,

    @load_outage_start_time,

    @load_outage_end_time,

    @load_outage_weekday_mask,

    @load_threshold_alert_enabled,

    @load_delta OUTPUT

    EXECUTE @backup_in_sync = msdb.dbo.sp_log_shipping_in_sync

    @last_backup_last_updated,

    @dt,

    @backup_threshold,

    @backup_outage_start_time,

    @backup_outage_end_time,

    @backup_outage_weekday_mask,

    @backup_threshold_alert_enabled,

    @backup_delta OUTPUT

    EXECUTE msdb.dbo.sp_log_shipping_in_sync

    @copydt,

    @backupdt,

    1,0,0,0,0,

    @copy_delta OUTPUT

    UPDATE #lsp

    SET backup_in_sync = @backup_in_sync, load_in_sync = @load_in_sync,

    copy_delta = @copy_delta, load_delta = @load_delta, backup_delta = @backup_delta

    WHERE primary_server_name = @_primary_server_name AND

    secondary_server_name = @_secondary_server_name AND

    primary_database_name = @_primary_database_name AND

    secondary_database_name = @_secondary_database_name

    GOTO loop

    _loop:

    CLOSE sync_update

    DEALLOCATE sync_update

    SELECT * FROM #lsp

    END

    go

    /**************************************************************/

    /* sp_update_log_shipping_monitor_info */

    /**************************************************************/

    PRINT ''

    PRINT 'Creating procedure sp_update_log_shipping_monitor_info...'

    go

    IF (EXISTS (SELECT * from msdb.dbo.sysobjects WHERE name = N'sp_update_log_shipping_monitor_info' AND type = N'P') )

    DROP PROCEDURE sp_update_log_shipping_monitor_info

    go

    CREATE PROCEDURE sp_update_log_shipping_monitor_info

    @primary_server_name sysname,

    @primary_database_name sysname,

    @secondary_server_name sysname,

    @secondary_database_name sysname,

    @backup_threshold INT = NULL,

    @backup_threshold_alert INT = NULL,

    @backup_threshold_alert_enabled BIT = NULL,

    @backup_outage_start_time INT = NULL,

    @backup_outage_end_time INT = NULL,

    @backup_outage_weekday_mask INT = NULL,

    @copy_enabled BIT = NULL,

    @load_enabled BIT = NULL,

    @out_of_sync_threshold INT = NULL,

    @out_of_sync_threshold_alert INT = NULL,

    @out_of_sync_threshold_alert_enabled BIT = NULL,

    @out_of_sync_outage_start_time INT = NULL,

    @out_of_sync_outage_end_time INT = NULL,

    @out_of_sync_outage_weekday_mask INT = NULL

    AS BEGIN

    SET NOCOUNT ON

    DECLARE @_backup_threshold INT

    DECLARE @_backup_threshold_alert INT

    DECLARE @_backup_threshold_alert_enabled BIT

    DECLARE @_backup_outage_start_time INT

    DECLARE @_backup_outage_end_time INT

    DECLARE @_backup_outage_weekday_mask INT

    DECLARE @_copy_enabled BIT

    DECLARE @_load_enabled BIT

    DECLARE @_out_of_sync_threshold INT

    DECLARE @_out_of_sync_threshold_alert INT

    DECLARE @_out_of_sync_threshold_alert_enabled BIT

    DECLARE @_out_of_sync_outage_start_time INT

    DECLARE @_out_of_sync_outage_end_time INT

    DECLARE @_out_of_sync_outage_weekday_mask INT

    -- check that the primary exists

    IF (NOT EXISTS (SELECT * FROM msdb.dbo.log_shipping_primaries WHERE primary_server_name = @primary_server_name AND primary_database_name = @primary_database_name))

    BEGIN

    DECLARE @pp sysname

    SELECT @pp = @primary_server_name + N'.' + @primary_database_name

    RAISERROR (14262, 16, 1, N'primary_server_name.primary_database_name', @pp)

    RETURN (1) -- error

    END

    -- check that the secondary exists

    IF (NOT EXISTS (SELECT * FROM msdb.dbo.log_shipping_secondaries WHERE secondary_server_name = @secondary_server_name AND secondary_database_name = @secondary_database_name))

    BEGIN

    DECLARE @sp-2 sysname

    SELECT @sp-2 = @secondary_server_name + N'.' + @secondary_database_name

    RAISERROR (14262, 16, 1, N'secondary_server_name.secondary_database_name', @sp-2)

    RETURN (1) -- error

    END

    -- load the original variables

    SELECT

    @_backup_threshold = backup_threshold,

    @_backup_threshold_alert = p.threshold_alert,

    @_backup_threshold_alert_enabled = p.threshold_alert_enabled,

    @_backup_outage_start_time = p.planned_outage_start_time,

    @_backup_outage_end_time = p.planned_outage_end_time,

    @_backup_outage_weekday_mask = p.planned_outage_weekday_mask,

    @_copy_enabled = copy_enabled,

    @_load_enabled = load_enabled,

    @_out_of_sync_threshold = out_of_sync_threshold,

    @_out_of_sync_threshold_alert = s.threshold_alert,

    @_out_of_sync_threshold_alert_enabled = s.threshold_alert_enabled,

    @_out_of_sync_outage_start_time = s.planned_outage_start_time,

    @_out_of_sync_outage_weekday_mask = s.planned_outage_weekday_mask,

    @_out_of_sync_outage_end_time = s.planned_outage_end_time

    FROM msdb.dbo.log_shipping_primaries p, msdb.dbo.log_shipping_secondaries s

    WHERE

    p.primary_id = s.primary_id AND

    primary_server_name = @primary_server_name AND

    primary_database_name = @primary_database_name AND

    secondary_server_name = @secondary_server_name AND

    secondary_database_name = @secondary_database_name

    SELECT @_backup_threshold = ISNULL (@backup_threshold, @_backup_threshold)

    SELECT @_backup_threshold_alert = ISNULL (@backup_threshold_alert, @_backup_threshold_alert)

    SELECT @_backup_threshold_alert_enabled = ISNULL (@backup_threshold_alert_enabled, @_backup_threshold_alert_enabled)

    SELECT @_backup_outage_start_time = ISNULL (@backup_outage_start_time, @_backup_outage_start_time)

    SELECT @_backup_outage_end_time = ISNULL (@backup_outage_end_time, @_backup_outage_end_time)

    SELECT @_backup_outage_weekday_mask = ISNULL (@backup_outage_weekday_mask, @_backup_outage_weekday_mask)

    SELECT @_copy_enabled = ISNULL (@copy_enabled, @_copy_enabled)

    SELECT @_load_enabled = ISNULL (@load_enabled, @_load_enabled)

    SELECT @_out_of_sync_threshold = ISNULL (@out_of_sync_threshold, @_out_of_sync_threshold)

    SELECT @_out_of_sync_threshold_alert = ISNULL (@out_of_sync_threshold_alert, @_out_of_sync_threshold_alert)

    SELECT @_out_of_sync_threshold_alert_enabled = ISNULL (@out_of_sync_threshold_alert_enabled, @_out_of_sync_threshold_alert_enabled)

    SELECT @_out_of_sync_outage_start_time = ISNULL (@out_of_sync_outage_start_time, @_out_of_sync_outage_start_time)

    SELECT @_out_of_sync_outage_end_time = ISNULL (@out_of_sync_outage_end_time, @_out_of_sync_outage_end_time)

    SELECT @_out_of_sync_outage_weekday_mask = ISNULL (@out_of_sync_outage_weekday_mask, @_out_of_sync_outage_weekday_mask)

    -- updates

    UPDATE msdb.dbo.log_shipping_primaries SET

    backup_threshold = @_backup_threshold,

    threshold_alert = @_backup_threshold_alert,

    threshold_alert_enabled = @_backup_threshold_alert_enabled,

    planned_outage_start_time = @_backup_outage_start_time,

    planned_outage_end_time = @_backup_outage_end_time,

    planned_outage_weekday_mask = @_backup_outage_weekday_mask

    WHERE primary_server_name = @primary_server_name AND primary_database_name = @primary_database_name

    UPDATE msdb.dbo.log_shipping_secondaries SET

    copy_enabled = @_copy_enabled,

    load_enabled = @_load_enabled,

    out_of_sync_threshold = @_out_of_sync_threshold,

    threshold_alert = @_out_of_sync_threshold_alert,

    threshold_alert_enabled = @_out_of_sync_threshold_alert_enabled,

    planned_outage_start_time = @_out_of_sync_outage_start_time,

    planned_outage_end_time = @_out_of_sync_outage_end_time,

    planned_outage_weekday_mask = @_out_of_sync_outage_weekday_mask

    WHERE secondary_server_name = @secondary_server_name AND secondary_database_name = @secondary_database_name

    RETURN(0)

    END

    go

    /**************************************************************/

    /* sp_delete_log_shipping_monitor_info */

    /**************************************************************/

    PRINT ''

    PRINT 'Creating procedure sp_delete_log_shipping_monitor_info...'

    go

    IF (EXISTS (SELECT * from msdb.dbo.sysobjects WHERE name = N'sp_delete_log_shipping_monitor_info' AND type = N'P') )

    DROP PROCEDURE sp_delete_log_shipping_monitor_info

    go

    CREATE PROCEDURE sp_delete_log_shipping_monitor_info

    @primary_server_name sysname,

    @primary_database_name sysname,

    @secondary_server_name sysname,

    @secondary_database_name sysname

    AS BEGIN

    -- check that the primary exists

    IF (NOT EXISTS (SELECT * FROM msdb.dbo.log_shipping_primaries WHERE primary_server_name = @primary_server_name AND primary_database_name = @primary_database_name))

    BEGIN

    DECLARE @pp sysname

    SELECT @pp = @primary_server_name + N'.' + @primary_database_name

    RAISERROR (14262, 16, 1, N'primary_server_name.primary_database_name', @pp)

    RETURN (1) -- error

    END

    -- check that the secondary exists

    IF (NOT EXISTS (SELECT * FROM msdb.dbo.log_shipping_secondaries WHERE secondary_server_name = @secondary_server_name AND secondary_database_name = @secondary_database_name))

    BEGIN

    DECLARE @sp-2 sysname

    SELECT @sp-2 = @secondary_server_name + N'.' + @secondary_database_name

    RAISERROR (14262, 16, 1, N'secondary_server_name.secondary_database_name', @sp-2)

    RETURN (1) -- error

    END

    BEGIN TRANSACTION

    -- delete the secondary

    DELETE FROM msdb.dbo.log_shipping_secondaries WHERE secondary_server_name = @secondary_server_name AND secondary_database_name = @secondary_database_name

    IF (@@error <> 0)

    goto rollback_quit

    -- if there are no more secondaries for this primary then delete it

    IF (NOT EXISTS (SELECT * FROM msdb.dbo.log_shipping_primaries p, msdb.dbo.log_shipping_secondaries s WHERE p.primary_id = s.primary_id AND primary_server_name = @primary_server_name AND primary_database_name = @primary_database_name))

    BEGIN

    DELETE FROM msdb.dbo.log_shipping_primaries WHERE primary_server_name = @primary_server_name AND primary_database_name = @primary_database_name

    IF (@@error <> 0)

    goto rollback_quit

    END

    COMMIT TRANSACTION

    RETURN (0)

    rollback_quit:

    ROLLBACK TRANSACTION

    RETURN(1) -- Failure

    END

    go

    /**************************************************************/

    /* sp_remove_log_shipping_monitor_account */

    /**************************************************************/

    PRINT ''

    PRINT 'Creating procedure sp_remove_log_shipping_monitor_account...'

    go

    IF (EXISTS (SELECT * from msdb.dbo.sysobjects WHERE name = N'sp_remove_log_shipping_monitor_account' AND type = N'P') )

    DROP PROCEDURE sp_remove_log_shipping_monitor_account

    go

    CREATE PROCEDURE sp_remove_log_shipping_monitor_account

    AS

    BEGIN

    SET NOCOUNT ON

    EXECUTE sp_dropuser N'log_shipping_monitor_probe'

    EXECUTE sp_droplogin N'log_shipping_monitor_probe'

    END

    go

    /**************************************************************/

    /* sp_log_shipping_monitor_backup */

    /**************************************************************/

    PRINT ''

    PRINT 'Creating procedure sp_log_shipping_monitor_backup...'

    go

    IF (EXISTS (SELECT * from msdb.dbo.sysobjects WHERE name = N'sp_log_shipping_monitor_backup' AND type = N'P') )

    drop procedure sp_log_shipping_monitor_backup

    go

    CREATE PROCEDURE sp_log_shipping_monitor_backup AS

    BEGIN

    DECLARE @primary_id sysname

    DECLARE @primary_server_name sysname

    DECLARE @primary_database_name sysname

    DECLARE @maintenance_plan_id UNIQUEIDENTIFIER

    DECLARE @backup_threshold INT

    DECLARE @threshold_alert INT

    DECLARE @threshold_alert_enabled BIT

    DECLARE @last_backup_filename sysname

    DECLARE @last_updated DATETIME

    DECLARE @planned_outage_start_time INT

    DECLARE @planned_outage_end_time INT

    DECLARE @planned_outage_weekday_mask INT

    DECLARE @sync_status INT

    DECLARE @backup_delta INT

    DECLARE @delta_string NVARCHAR (10)

    DECLARE @dt DATETIME

    SELECT @dt = GETDATE ()

    SET NOCOUNT ON

    DECLARE bmlsp_cur CURSOR FOR

    SELECT primary_id,

    primary_server_name,

    primary_database_name,

    maintenance_plan_id,

    backup_threshold,

    threshold_alert,

    threshold_alert_enabled,

    last_backup_filename,

    last_updated,

    planned_outage_start_time,

    planned_outage_end_time,

    planned_outage_weekday_mask

    FROM msdb.dbo.log_shipping_primaries

    FOR READ ONLY

    OPEN bmlsp_cur

    loop:

    FETCH NEXT FROM bmlsp_cur

    INTO @primary_id,

    @primary_server_name,

    @primary_database_name,

    @maintenance_plan_id,

    @backup_threshold,

    @threshold_alert,

    @threshold_alert_enabled,

    @last_backup_filename,

    @last_updated,

    @planned_outage_start_time,

    @planned_outage_end_time,

    @planned_outage_weekday_mask

    IF @@FETCH_STATUS <> 0 -- nothing more to fetch, finish the loop

    GOTO _loop

    EXECUTE @sync_status = sp_log_shipping_in_sync

    @last_updated,

    @dt,

    @backup_threshold,

    @planned_outage_start_time,

    @planned_outage_end_time,

    @planned_outage_weekday_mask,

    @threshold_alert_enabled,

    @backup_delta OUTPUT

    IF (@sync_status < 0)

    BEGIN

    SELECT @delta_string = CONVERT (NVARCHAR(10), @backup_delta)

    RAISERROR (@threshold_alert, 16, 1, @primary_server_name, @primary_database_name, @delta_string)

    END

    GOTO loop

    _loop:

    CLOSE bmlsp_cur

    DEALLOCATE bmlsp_cur

    END

    go

    /**************************************************************/

    /* sp_log_shipping_monitor_restore */

    /**************************************************************/

    PRINT ''

    PRINT 'Creating procedure sp_log_shipping_monitor_restore...'

    go

    IF (EXISTS (SELECT * from msdb.dbo.sysobjects WHERE name = N'sp_log_shipping_monitor_restore' AND type = N'P') )

    drop procedure sp_log_shipping_monitor_restore

    go

    CREATE PROCEDURE sp_log_shipping_monitor_restore AS

    BEGIN

    SET NOCOUNT ON

    DECLARE @primary_id INT

    DECLARE @secondary_server_name sysname

    DECLARE @secondary_database_name sysname

    DECLARE @secondary_plan_id UNIQUEIDENTIFIER

    DECLARE @out_of_sync_threshold INT

    DECLARE @threshold_alert INT

    DECLARE @threshold_alert_enabled BIT

    DECLARE @last_loaded_filename NVARCHAR (500)

    DECLARE @last_backup_filename NVARCHAR (500)

    DECLARE @primary_database_name sysname

    DECLARE @last_loaded_last_updated DATETIME

    DECLARE @last_backup_last_updated DATETIME

    DECLARE @planned_outage_start_time INT

    DECLARE @planned_outage_end_time INT

    DECLARE @planned_outage_weekday_mask INT

    DECLARE @sync_status INT

    DECLARE @sync_delta INT

    DECLARE @delta_string NVARCHAR(10)

    SET NOCOUNT ON

    DECLARE @backupdt DATETIME

    DECLARE @restoredt DATETIME

    DECLARE @rv INT

    DECLARE rmlsp_cur CURSOR FOR

    SELECT s.primary_id,

    s.secondary_server_name,

    s.secondary_database_name,

    s.secondary_plan_id,

    s.out_of_sync_threshold,

    s.threshold_alert,

    s.threshold_alert_enabled,

    s.last_loaded_filename,

    s.last_loaded_last_updated,

    p.last_backup_filename,

    p.last_updated,

    p.primary_database_name,

    s.planned_outage_start_time,

    s.planned_outage_end_time,

    s.planned_outage_weekday_mask

    FROM msdb.dbo.log_shipping_secondaries s

    INNER JOIN msdb.dbo.log_shipping_primaries p

    ON s.primary_id = p.primary_id

    FOR READ ONLY

    OPEN rmlsp_cur

    loop:

    FETCH NEXT FROM rmlsp_cur

    INTO @primary_id,

    @secondary_server_name,

    @secondary_database_name,

    @secondary_plan_id,

    @out_of_sync_threshold,

    @threshold_alert,

    @threshold_alert_enabled,

    @last_loaded_filename,

    @last_loaded_last_updated,

    @last_backup_filename,

    @last_backup_last_updated,

    @primary_database_name,

    @planned_outage_start_time,

    @planned_outage_end_time,

    @planned_outage_weekday_mask

    IF @@FETCH_STATUS <> 0 -- nothing more to fetch, finish the loop

    GOTO _loop

    EXECUTE @rv = sp_log_shipping_get_date_from_file @primary_database_name, @last_backup_filename, @backupdt OUTPUT

    IF (@rv <> 0)

    SELECT @backupdt = @last_backup_last_updated

    EXECUTE @rv = sp_log_shipping_get_date_from_file @primary_database_name, @last_loaded_filename, @restoredt OUTPUT

    IF (@rv <> 0)

    SELECT @restoredt = @last_loaded_last_updated

    EXECUTE @sync_status = sp_log_shipping_in_sync

    @restoredt,

    @backupdt,

    @out_of_sync_threshold,

    @planned_outage_start_time,

    @planned_outage_end_time,

    @planned_outage_weekday_mask,

    @threshold_alert_enabled,

    @sync_delta OUTPUT

    IF (@sync_status < 0)

    BEGIN

    SELECT @delta_string = CONVERT (NVARCHAR(10), @sync_delta)

    RAISERROR (@threshold_alert, 16, 1, @secondary_server_name, @secondary_database_name, @delta_string)

    END

    GOTO loop

    _loop:

    CLOSE rmlsp_cur

    DEALLOCATE rmlsp_cur

    END

    go

    /**************************************************************/

    /* sp_change_monitor_role */

    /**************************************************************/

    PRINT ''

    PRINT 'Creating procedure sp_change_monitor_role...'

    go

    IF (EXISTS (SELECT * from msdb.dbo.sysobjects WHERE name = N'sp_change_monitor_role' AND type = N'P') )

    DROP PROCEDURE sp_change_monitor_role

    go

    CREATE PROCEDURE sp_change_monitor_role

    @primary_server sysname,

    @secondary_server sysname,

    @database sysname,

    @new_source NVARCHAR (128)

    AS BEGIN

    SET NOCOUNT ON

    BEGIN TRANSACTION

    -- drop the secondary

    DELETE FROM msdb.dbo.log_shipping_secondaries

    WHERE secondary_server_name = @secondary_server AND secondary_database_name = @database

    IF (@@ROWCOUNT <> 1)

    BEGIN

    ROLLBACK TRANSACTION

    RAISERROR (14442,-1,-1)

    return(1)

    END

    -- let everyone know that we are the new primary

    UPDATE msdb.dbo.log_shipping_primaries

    SET primary_server_name = @secondary_server, primary_database_name = @database, source_directory = @new_source

    WHERE primary_server_name = @primary_server AND primary_database_name = @database

    IF (@@ROWCOUNT <> 1)

    BEGIN

    ROLLBACK TRANSACTION

    RAISERROR (14442,-1,-1)

    return(1)

    END

    COMMIT TRANSACTION

    END

    go

    /**************************************************************/

    /* sp_create_log_shipping_monitor_account */

    /**************************************************************/

    PRINT ''

    PRINT 'Creating procedure sp_create_log_shipping_monitor_account...'

    go

    IF (EXISTS (SELECT * from msdb.dbo.sysobjects WHERE name = N'sp_create_log_shipping_monitor_account' AND type = N'P') )

    drop procedure sp_create_log_shipping_monitor_account

    go

    CREATE PROCEDURE sp_create_log_shipping_monitor_account @password sysname

    AS

    BEGIN

    DECLARE @rv INT

    SET NOCOUNT ON

    -- raise an error if the password already exists

    if exists(select * from master.dbo.syslogins where loginname = N'log_shipping_monitor_probe')

    begin

    raiserror(15025,-1,-1,N'log_shipping_monitor_probe')

    RETURN (1) -- error

    end

    IF (@password = N'')

    BEGIN

    EXECUTE @rv = sp_addlogin N'log_shipping_monitor_probe', @defdb = N'msdb'

    IF @@error <>0 or @rv <> 0

    RETURN (1) -- error

    END

    ELSE

    BEGIN

    EXECUTE @rv = sp_addlogin N'log_shipping_monitor_probe', @password, N'msdb'

    IF @@error <>0 or @rv <> 0

    RETURN (1) -- error

    END

    EXECUTE @rv = sp_grantdbaccess N'log_shipping_monitor_probe', N'log_shipping_monitor_probe'

    IF @@error <>0 or @rv <> 0

    RETURN (1) -- error

    GRANT UPDATE ON log_shipping_primaries TO log_shipping_monitor_probe

    GRANT UPDATE ON log_shipping_secondaries TO log_shipping_monitor_probe

    GRANT SELECT ON log_shipping_primaries TO log_shipping_monitor_probe

    GRANT SELECT ON log_shipping_secondaries TO log_shipping_monitor_probe

    RETURN (0)

    END

    go

    GRANT EXECUTE ON sp_get_log_shipping_monitor_info TO PUBLIC

    /**************************************************************/

    /* Turn 'System Object' marking OFF */

    /**************************************************************/

    PRINT ''

    EXECUTE master.dbo.sp_MS_upd_sysobj_category 2

    go

    EXECUTE master.dbo.sp_configure N'allow updates', 0

    go

    RECONFIGURE WITH OVERRIDE

    go

    PRINT ''

    PRINT '----------------------------------'

    PRINT 'Execution of INSTMSDB.SQL complete'

    PRINT '----------------------------------'

    go

    DUMP TRANSACTION msdb WITH NO_LOG

    go

    CHECKPOINT

    go

Viewing 12 posts - 1 through 11 (of 11 total)

You must be logged in to reply to this topic. Login to reply