home *** CD-ROM | disk | FTP | other *** search
/ Enter 2001 April / EnterCD4.iso / Update / SQL Server SP3 / sql70sp3i.exe / INSTALL / instmsdb.sql < prev    next >
Encoding:
Text File  |  2000-10-04  |  622.7 KB  |  16,860 lines

  1. /**********************************************************************/
  2. /* INSTMSDB.SQL                                                       */
  3. /*                                                                    */
  4. /* Installs the tables, triggers and stored procedures necessary for  */
  5. /* supporting local (and multi-server) jobs, alerts, operators, and   */
  6. /* backup history.  These objects are used by SQLDMO, SQL Enterprise  */
  7. /* Manager, and SQLServerAgent.                                       */
  8. /*                                                                    */
  9. /* Also contains SQL DTS (Data Transformation Services) tables and    */
  10. /* stored procedures for local SQL Server storage of DTS Packages.    */
  11. /*                                                                    */
  12. /* Copyright Microsoft, Inc. 1996 - 1998.                             */
  13. /* All Rights Reserved.                                               */
  14. /*                                                                    */
  15. /* Use, duplication, or disclosure by the United States Government    */
  16. /* is subject to restrictions as set forth in subdivision (c) (1)(ii) */
  17. /* of the Rights in Technical Data and Computer Software clause       */
  18. /* at CFR 252.227-7013.                                               */
  19. /* Microsoft, Inc. One Microsoft Way, Redmond WA. 98052.              */
  20. /**********************************************************************/
  21.  
  22. PRINT '----------------------------------'
  23. PRINT 'Starting execution of INSTMSDB.SQL'
  24. PRINT '----------------------------------'
  25. go
  26.  
  27. /**************************************************************/
  28. /* If upgrading from Beta 2, drop MSDB                        */
  29. /**************************************************************/
  30. DECLARE @prior_version    VARCHAR(100)
  31. DECLARE @old_build_number INT
  32.  
  33. EXECUTE master.dbo.xp_regread N'HKEY_LOCAL_MACHINE',
  34.                               N'SOFTWARE\Microsoft\MSSQLServer\MSSQLServer\CurrentVersion',
  35.                               N'PriorVersion',
  36.                               @prior_version OUTPUT,
  37.                               N'no_output'
  38.  
  39. IF (@prior_version IS NOT NULL)
  40. BEGIN
  41.   SELECT @old_build_number = CONVERT(INT, REVERSE(SUBSTRING(REVERSE(@prior_version), 1, PATINDEX('%.%', REVERSE(@prior_version)) - 1)))
  42.   IF (@old_build_number <= 504) -- The last build that we changed the schema in
  43.   BEGIN
  44.     PRINT ''
  45.     RAISERROR('Dropping pre-beta 3 MSDB database (created by build %ld)...', 0, 1, @old_build_number)
  46.     DROP DATABASE msdb
  47.   END
  48. END
  49. go
  50.  
  51. /**************************************************************/
  52. /* Turn 'System Object' marking ON                            */
  53. /**************************************************************/
  54. EXECUTE master.dbo.sp_MS_upd_sysobj_category 1
  55. go
  56.  
  57. -- Explicitly set the options that the server stores with the object in sysobjects.status
  58. -- so that it doesn't matter if the script is run using a DBLib or ODBC based client.
  59. SET QUOTED_IDENTIFIER OFF -- We don't use quoted identifiers
  60. SET ANSI_NULLS ON         -- We don't want (NULL = NULL) == TRUE
  61. go
  62. SET ANSI_PADDING ON       -- Set so that trailing zeros aren't trimmed off sysjobs.owner_login_sid
  63. go
  64.  
  65. -- Allow updates to system catalogs so that all our SP's inherit full DML capability on
  66. -- system objects and so that we can exercise full DDL control on our system objects
  67. EXECUTE master.dbo.sp_configure N'allow updates', 1
  68. go
  69. RECONFIGURE WITH OVERRIDE
  70. go
  71.  
  72. /**************************************************************/
  73. /*                                                            */
  74. /*      D  A  T  A  B  A  S  E    C  R  E  A  T  I  O  N      */
  75. /*                                                            */
  76. /**************************************************************/
  77.  
  78. IF (NOT EXISTS (SELECT name
  79.                 FROM master.dbo.sysdatabases
  80.                 WHERE (name = N'msdb')))
  81. BEGIN
  82.   PRINT 'Creating the msdb database...'
  83. END
  84. go
  85.  
  86. USE master
  87. go
  88.  
  89. SET NOCOUNT ON
  90.  
  91. -- NOTE: It is important that this script can be re-run WITHOUT causing loss of data, hence
  92. --       we only create the database if it missing (if the database already exists we test
  93. --       that it has enough free space and if not we expand both the device and the database).
  94. DECLARE @model_db_size    INT
  95. DECLARE @msdb_db_size     INT
  96. DECLARE @sz_msdb_db_size  VARCHAR(10)
  97. DECLARE @device_directory NVARCHAR(520)
  98. DECLARE @page_size        INT
  99. DECLARE @size             INT
  100. DECLARE @free_db_space    FLOAT
  101.  
  102. SELECT @page_size = 8
  103.  
  104. IF (NOT EXISTS (SELECT name
  105.                 FROM master.dbo.sysdatabases
  106.                 WHERE (name = N'msdb')))
  107. BEGIN
  108.   -- Make sure that we create [the data portion of] MSDB to be at least as large as
  109.   -- the MODEL database
  110.   SELECT @model_db_size = (SUM(size) * @page_size)
  111.   FROM model.dbo.sysfiles
  112.  
  113.   IF (@model_db_size > 3072) -- 3 is the minimum required size for MSDB (in megabytes)
  114.     SELECT @msdb_db_size = @model_db_size
  115.   ELSE
  116.     SELECT @msdb_db_size = 3072
  117.  
  118.   SELECT @device_directory = SUBSTRING(phyname, 1, CHARINDEX(N'master.mdf', LOWER(phyname)) - 1)
  119.   FROM master.dbo.sysdevices
  120.   WHERE (name = N'master')
  121.  
  122.   -- Drop any existing MSDBData / MSDBLog file(s)
  123.   EXECUTE(N'EXECUTE master.dbo.xp_cmdshell N''DEL ' + @device_directory + N'MSDBData.mdf'', no_output')
  124.   EXECUTE(N'EXECUTE master.dbo.xp_cmdshell N''DEL ' + @device_directory + N'MSDBLog.ldf'', no_output')
  125.  
  126.   -- Create the database
  127.   PRINT ''
  128.   PRINT 'Creating MSDB database...'
  129.   SELECT @sz_msdb_db_size = RTRIM(LTRIM(CONVERT(VARCHAR, @msdb_db_size)))
  130.   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)
  131.                           LOG ON (NAME = N''MSDBLog'',  FILENAME = N''' + @device_directory + N'MSDBLog.ldf'',  SIZE = 512KB, MAXSIZE = UNLIMITED, FILEGROWTH = 256KB)')
  132.   PRINT ''
  133. END
  134. ELSE
  135. BEGIN
  136.   PRINT 'Checking the size of MSDB...'
  137.  
  138.   DBCC UPDATEUSAGE(N'msdb') WITH NO_INFOMSGS
  139.  
  140.   -- Make sure that MSDBLog has unlimited growth
  141.   ALTER DATABASE msdb MODIFY FILE (NAME = N'MSDBLog', MAXSIZE = UNLIMITED)
  142.  
  143.   -- Determine amount of free space in msdb. We need at least 2MB free.
  144.   SELECT @free_db_space = ((((SELECT SUM(size)
  145.                               FROM msdb.dbo.sysfiles
  146.                               WHERE status & 0x8040 = 0) -
  147.                              (SELECT SUM(reserved)
  148.                               FROM msdb.dbo.sysindexes
  149.                               WHERE indid IN (0, 1, 255))) * @page_size) / 1024.0)
  150.  
  151.   IF (@free_db_space < 2)
  152.   BEGIN
  153.     DECLARE @logical_file_name sysname
  154.     DECLARE @os_file_name      NVARCHAR(255)
  155.     DECLARE @size_as_char      VARCHAR(10)
  156.     
  157.     SELECT @logical_file_name = name,
  158.            @os_file_name = phyname,
  159.            @size_as_char = CONVERT(VARCHAR(10), ((high + 1) / 4) + 2048)
  160.     FROM master.dbo.sysdevices
  161.     WHERE (name = N'MSDBData')
  162.  
  163.     PRINT 'Attempting to expand the msdb database...'
  164.     EXECUTE (N'ALTER DATABASE msdb MODIFY FILE (NAME = N''' + @logical_file_name + N''', 
  165.                                                 FILENAME = N''' + @os_file_name + N''', 
  166.                                                 SIZE = @size_as_char)')
  167.     IF (@@error <> 0)
  168.       RAISERROR('Unable to expand the msdb database. INSTMSDB.SQL terminating.', 20, 127) WITH LOG
  169.   END
  170.   PRINT ''
  171. END
  172. go
  173.  
  174. EXECUTE sp_dboption msdb, N'trunc. log on chkpt.', TRUE
  175. go
  176.  
  177. USE msdb
  178. go
  179.  
  180. -- Check that we're in msdb
  181. IF (DB_NAME() <> N'msdb')
  182.   RAISERROR('A problem was encountered accessing msdb. INSTMSDB.SQL terminating.', 20, 127) WITH LOG
  183. go
  184.  
  185. -- Add the guest user
  186. IF (NOT EXISTS (SELECT *
  187.                 FROM msdb.dbo.sysusers
  188.                 WHERE (name = N'guest')
  189.                   AND (hasdbaccess = 1)))
  190. BEGIN
  191.   PRINT ''
  192.   EXECUTE sp_adduser N'guest'
  193. END
  194. go
  195.  
  196. DUMP TRANSACTION msdb WITH NO_LOG
  197. go
  198. CHECKPOINT
  199. go
  200.  
  201. /**************************************************************/
  202. /*                                                            */
  203. /*              T  A  B  L  E     D  R  O  P  S               */
  204. /*                                                            */
  205. /**************************************************************/
  206.  
  207. SET NOCOUNT ON
  208.  
  209. DECLARE @build_number   INT
  210. DECLARE @rebuild_needed TINYINT
  211.  
  212. SELECT @build_number = @@microsoftversion & 0xffff
  213.  
  214. IF (@build_number <= 504) -- The last build that we changed the schema in
  215.   SELECT @rebuild_needed = 1
  216. ELSE
  217.   SELECT @rebuild_needed = 0
  218.  
  219. IF (EXISTS (SELECT *
  220.             FROM msdb.dbo.sysobjects
  221.             WHERE (name = N'sqlagent_info')
  222.               AND (type = 'U')
  223.               AND (@rebuild_needed = 1)))
  224. BEGIN
  225.   PRINT ''
  226.   PRINT 'Dropping table sqlagent_info...'
  227.   DROP TABLE dbo.sqlagent_info
  228. END
  229.  
  230. IF (EXISTS (SELECT *
  231.             FROM msdb.dbo.sysobjects
  232.             WHERE (name = N'sysdownloadlist')
  233.               AND (type = 'U')
  234.               AND (@rebuild_needed = 1)))
  235. BEGIN
  236.   PRINT ''
  237.   PRINT 'Dropping table sysdownloadlist...'
  238.  
  239.   IF (EXISTS (SELECT *
  240.               FROM msdb.dbo.syscolumns
  241.               WHERE (id = OBJECT_ID(N'sysdownloadlist'))
  242.                 AND (name = N'error_message')
  243.                 AND (cdefault <> 0)))
  244.     EXECUTE sp_unbindefault N'sysdownloadlist.error_message'
  245.  
  246.   IF (EXISTS (SELECT *
  247.               FROM msdb.dbo.syscolumns
  248.               WHERE (id = OBJECT_ID(N'sysdownloadlist'))
  249.                 AND (name = N'date_posted')
  250.                 AND (cdefault <> 0)))
  251.     EXECUTE sp_unbindefault N'sysdownloadlist.date_posted'
  252.  
  253.   IF (EXISTS (SELECT *
  254.               FROM msdb.dbo.syscolumns
  255.               WHERE (id = OBJECT_ID(N'sysdownloadlist'))
  256.                 AND (name = N'status')
  257.                 AND (cdefault <> 0)))
  258.     EXECUTE sp_unbindefault N'sysdownloadlist.status'
  259.  
  260.   DROP TABLE dbo.sysdownloadlist
  261. END
  262.  
  263. IF (EXISTS (SELECT *
  264.             FROM msdb.dbo.sysobjects
  265.             WHERE (name = N'sysjobhistory')
  266.               AND (type = 'U')
  267.               AND (@rebuild_needed = 1)))
  268. BEGIN
  269.   PRINT ''
  270.   PRINT 'Dropping table sysjobhistory...'
  271.   DROP TABLE dbo.sysjobhistory
  272. END
  273.  
  274. IF (EXISTS (SELECT *
  275.             FROM msdb.dbo.sysobjects
  276.             WHERE (name = N'sysjobservers')
  277.               AND (type = 'U')
  278.               AND (@rebuild_needed = 1)))
  279. BEGIN
  280.   PRINT ''
  281.   PRINT 'Dropping table sysjobservers...'
  282.   DROP TABLE dbo.sysjobservers
  283. END
  284.  
  285. IF (EXISTS (SELECT *
  286.             FROM msdb.dbo.sysobjects
  287.             WHERE (name = N'sysjobs')
  288.               AND (type = 'U')
  289.               AND (@rebuild_needed = 1)))
  290. BEGIN
  291.   PRINT ''
  292.   PRINT 'Dropping table sysjobs...'
  293.   DROP TABLE dbo.sysjobs
  294. END
  295.  
  296. IF (EXISTS (SELECT *
  297.             FROM msdb.dbo.sysobjects
  298.             WHERE (name = N'sysjobsteps')
  299.               AND (type = 'U')
  300.               AND (@rebuild_needed = 1)))
  301. BEGIN
  302.   PRINT ''
  303.   PRINT 'Dropping table sysjobsteps...'
  304.   DROP TABLE dbo.sysjobsteps
  305. END
  306.  
  307. IF (EXISTS (SELECT *
  308.             FROM msdb.dbo.sysobjects
  309.             WHERE (name = N'sysjobschedules')
  310.               AND (type = 'U')
  311.               AND (@rebuild_needed = 1)))
  312. BEGIN
  313.   PRINT ''
  314.   PRINT 'Dropping table sysjobschedules...'
  315.  
  316.   IF (EXISTS (SELECT *
  317.               FROM msdb.dbo.syscolumns
  318.               WHERE (id = OBJECT_ID(N'sysjobschedules'))
  319.                 AND (name = N'date_created')
  320.                 AND (cdefault <> 0)))
  321.     EXECUTE sp_unbindefault N'sysjobschedules.date_created'
  322.  
  323.   DROP TABLE dbo.sysjobschedules
  324. END
  325.  
  326. IF (EXISTS (SELECT *
  327.             FROM msdb.dbo.sysobjects
  328.             WHERE (name = N'syscategories')
  329.               AND (type = 'U')
  330.               AND (@rebuild_needed = 1)))
  331. BEGIN
  332.   PRINT ''
  333.   PRINT 'Dropping table syscategories...'
  334.   DROP TABLE dbo.syscategories
  335. END
  336.  
  337. IF (EXISTS (SELECT *
  338.             FROM msdb.dbo.sysobjects
  339.             WHERE (name = N'systargetservers')
  340.               AND (type = 'U')
  341.               AND (@rebuild_needed = 1)))
  342. BEGIN
  343.   PRINT ''
  344.   PRINT 'Dropping table systargetservers...'
  345.  
  346.   IF (EXISTS (SELECT *
  347.               FROM msdb.dbo.syscolumns
  348.               WHERE (id = OBJECT_ID(N'systargetservers'))
  349.                 AND (name = N'enlist_date')
  350.                 AND (cdefault <> 0)))
  351.     EXECUTE sp_unbindefault N'systargetservers.enlist_date'
  352.  
  353.   IF (EXISTS (SELECT *
  354.               FROM msdb.dbo.syscolumns
  355.               WHERE (id = OBJECT_ID(N'systargetservers'))
  356.                 AND (name = N'last_poll_date')
  357.                 AND (cdefault <> 0)))
  358.     EXECUTE sp_unbindefault N'systargetservers.last_poll_date'
  359.  
  360.   IF (EXISTS (SELECT *
  361.               FROM msdb.dbo.syscolumns
  362.               WHERE (id = OBJECT_ID(N'systargetservers'))
  363.                 AND (name = N'status')
  364.                 AND (cdefault <> 0)))
  365.     EXECUTE sp_unbindefault N'systargetservers.status'
  366.  
  367.   DROP TABLE dbo.systargetservers
  368. END
  369.  
  370. IF (EXISTS (SELECT *
  371.             FROM msdb.dbo.sysobjects
  372.             WHERE (name = N'systargetservergroups')
  373.               AND (type = 'U')
  374.               AND (@rebuild_needed = 1)))
  375. BEGIN
  376.   PRINT ''
  377.   PRINT 'Dropping table systargetservergroups...'
  378.   DROP TABLE dbo.systargetservergroups
  379. END
  380.  
  381. IF (EXISTS (SELECT *
  382.             FROM msdb.dbo.sysobjects
  383.             WHERE (name = N'systargetservergroupmembers')
  384.               AND (type = 'U')
  385.               AND (@rebuild_needed = 1)))
  386. BEGIN
  387.   PRINT ''
  388.   PRINT 'Dropping table systargetservergroupmembers...'
  389.   DROP TABLE dbo.systargetservergroupmembers
  390. END
  391.  
  392. IF (EXISTS (SELECT *
  393.             FROM msdb.dbo.sysobjects
  394.             WHERE (name = N'systaskids')
  395.               AND (type = 'U')
  396.               AND (@rebuild_needed = 1)))
  397. BEGIN
  398.   PRINT ''
  399.   PRINT 'Dropping table systaskids...'
  400.   DROP TABLE dbo.systaskids
  401. END
  402.  
  403. IF (EXISTS (SELECT *
  404.             FROM msdb.dbo.sysobjects
  405.             WHERE (name = N'sysalerts')
  406.               AND (type = 'U')
  407.               AND (@rebuild_needed = 1)))
  408. BEGIN
  409.   PRINT ''
  410.   PRINT 'Dropping table sysalerts...'
  411.   DROP TABLE dbo.sysalerts
  412. END
  413.  
  414. IF (EXISTS (SELECT *
  415.             FROM msdb.dbo.sysobjects
  416.             WHERE (name = N'sysoperators')
  417.               AND (type = 'U')
  418.               AND (@rebuild_needed = 1)))
  419. BEGIN
  420.   PRINT ''
  421.   PRINT 'Dropping table sysoperators...'
  422.   DROP TABLE dbo.sysoperators
  423. END
  424.  
  425. IF (EXISTS (SELECT *
  426.             FROM msdb.dbo.sysobjects
  427.             WHERE (name = N'sysnotifications')
  428.               AND (type = 'U')
  429.               AND (@rebuild_needed = 1)))
  430. BEGIN
  431.   PRINT ''
  432.   PRINT 'Dropping table sysnotifications...'
  433.   DROP TABLE dbo.sysnotifications
  434. END
  435.  
  436. IF (EXISTS (SELECT *
  437.             FROM msdb.dbo.sysobjects
  438.             WHERE (name = N'sysdbmaintplan_jobs')
  439.               AND (type = 'U')
  440.               AND (@rebuild_needed = 1)))
  441. BEGIN
  442.   PRINT ''
  443.   PRINT 'Dropping table sysdbmaintplan_jobs...'
  444.   DROP TABLE sysdbmaintplan_jobs
  445. END
  446.  
  447. IF (EXISTS (SELECT *
  448.             FROM msdb.dbo.sysobjects
  449.             WHERE (name = N'sysdbmaintplan_databases')
  450.               AND (type = 'U')
  451.               AND (@rebuild_needed = 1)))
  452. BEGIN
  453.   PRINT ''
  454.   PRINT 'Dropping table sysdbmaintplan_databases...'
  455.   DROP TABLE sysdbmaintplan_databases
  456. END
  457.  
  458. IF (EXISTS (SELECT *
  459.             FROM msdb.dbo.sysobjects
  460.             WHERE (name = N'sysdbmaintplan_history')
  461.               AND (type = 'U')
  462.               AND (@rebuild_needed = 1)))
  463. BEGIN
  464.   PRINT ''
  465.   PRINT 'Dropping table sysdbmaintplan_history...'
  466.   DROP TABLE sysdbmaintplan_history
  467. END
  468.  
  469.  
  470. IF (EXISTS (SELECT *
  471.             FROM msdb.dbo.sysobjects
  472.             WHERE (name = N'sysdbmaintplans')
  473.               AND (type = 'U')
  474.               AND (@rebuild_needed = 1)))
  475. BEGIN
  476.   PRINT ''
  477.   PRINT 'Dropping table sysdbmaintplans...'
  478.   DROP TABLE sysdbmaintplans
  479. END
  480.  
  481. IF (EXISTS (SELECT *
  482.             FROM msdb.dbo.sysobjects
  483.             WHERE (name = N'default_sdl_error_message')
  484.               AND (type = 'D')
  485.               AND (@rebuild_needed = 1)))
  486.   DROP DEFAULT default_sdl_error_message
  487.  
  488. IF (EXISTS (SELECT *
  489.             FROM msdb.dbo.sysobjects
  490.             WHERE (name = N'default_current_date')
  491.               AND (type = 'D')
  492.               AND (@rebuild_needed = 1)))
  493.   DROP DEFAULT default_current_date
  494.  
  495. IF (EXISTS (SELECT *
  496.             FROM msdb.dbo.sysobjects
  497.             WHERE (name = N'default_zero')
  498.               AND (type = 'D')
  499.               AND (@rebuild_needed = 1)))
  500.   DROP DEFAULT default_zero
  501.  
  502. IF (EXISTS (SELECT *
  503.             FROM msdb.dbo.sysobjects
  504.             WHERE (name = N'default_one')
  505.               AND (type = 'D')
  506.               AND (@rebuild_needed = 1)))
  507.   DROP DEFAULT default_one
  508. go
  509.  
  510. DUMP TRANSACTION msdb WITH NO_LOG
  511. go
  512. CHECKPOINT
  513. go
  514.  
  515. /**************************************************************/
  516. /*                                                            */
  517. /*                     D  E  F  A  U  L  T  S                 */
  518. /*                                                            */
  519. /**************************************************************/
  520.  
  521. IF (NOT EXISTS (SELECT *
  522.                 FROM msdb.dbo.sysobjects
  523.                 WHERE (name = N'default_sdl_error_message')
  524.                   AND (type = 'D')))
  525.   EXECUTE('CREATE DEFAULT default_sdl_error_message AS NULL')
  526. go
  527. IF (NOT EXISTS (SELECT *
  528.                 FROM msdb.dbo.sysobjects
  529.                 WHERE (name = N'default_current_date')
  530.                   AND (type = 'D')))
  531.   EXECUTE('CREATE DEFAULT default_current_date AS GETDATE()')
  532. go
  533. IF (NOT EXISTS (SELECT *
  534.                 FROM msdb.dbo.sysobjects
  535.                 WHERE (name = N'default_zero')
  536.                   AND (type = 'D')))
  537.   EXECUTE('CREATE DEFAULT default_zero AS 0')
  538. go
  539. IF (NOT EXISTS (SELECT *
  540.                 FROM msdb.dbo.sysobjects
  541.                 WHERE (name = N'default_one')
  542.                   AND (type = 'D')))
  543.   EXECUTE('CREATE DEFAULT default_one AS 1')
  544. go
  545.  
  546. /**************************************************************/
  547. /*                                                            */
  548. /*                       T  A  B  L  E  S                     */
  549. /*                                                            */
  550. /**************************************************************/
  551.  
  552. /**************************************************************/
  553. /* SQLAGENT_INFO                                              */
  554. /**************************************************************/
  555.  
  556. IF (NOT EXISTS (SELECT *
  557.                 FROM msdb.dbo.sysobjects
  558.                 WHERE (name = N'sqlagent_info')
  559.                   AND (type = 'U')))
  560. BEGIN
  561.   PRINT ''
  562.   PRINT 'Creating table sqlagent_info...'
  563.  
  564.   CREATE TABLE sqlagent_info
  565.   (
  566.   attribute sysname       NOT NULL,
  567.   value     NVARCHAR(512) NOT NULL
  568.   )
  569. END
  570. go
  571.  
  572. /**************************************************************/
  573. /* SYSDOWNLOADLIST                                            */
  574. /**************************************************************/
  575.  
  576. IF (NOT EXISTS (SELECT *
  577.                 FROM msdb.dbo.sysobjects
  578.                 WHERE (name = N'sysdownloadlist')
  579.                   AND (type = 'U')))
  580. BEGIN
  581.   PRINT ''
  582.   PRINT 'Creating table sysdownloadlist...'
  583.  
  584.   CREATE TABLE sysdownloadlist
  585.   (
  586.   instance_id         INT IDENTITY     NOT NULL,
  587.   source_server       NVARCHAR(30)     NOT NULL,
  588.   operation_code      TINYINT          NOT NULL,
  589.   object_type         TINYINT          NOT NULL,
  590.   object_id           UNIQUEIDENTIFIER NOT NULL,
  591.   target_server       NVARCHAR(30)     NOT NULL,
  592.   error_message       NVARCHAR(1024)   NULL,
  593.   date_posted         DATETIME         NOT NULL,
  594.   date_downloaded     DATETIME         NULL,
  595.   status              TINYINT          NOT NULL,
  596.   deleted_object_name sysname          NULL
  597.   )
  598.  
  599.   EXECUTE sp_bindefault default_sdl_error_message, N'sysdownloadlist.error_message'
  600.   EXECUTE sp_bindefault default_current_date,      N'sysdownloadlist.date_posted'
  601.   EXECUTE sp_bindefault default_zero,              N'sysdownloadlist.status'
  602.  
  603.   CREATE UNIQUE CLUSTERED INDEX clust ON sysdownloadlist(instance_id)
  604.   CREATE NONCLUSTERED     INDEX nc1   ON sysdownloadlist(target_server)
  605.   CREATE NONCLUSTERED     INDEX nc2   ON sysdownloadlist(object_id)
  606. END
  607. go
  608.  
  609. /**************************************************************/
  610. /* SYSJOBHISTORY                                              */
  611. /**************************************************************/
  612.  
  613. IF (NOT EXISTS (SELECT *
  614.                 FROM msdb.dbo.sysobjects
  615.                 WHERE (name = N'sysjobhistory')
  616.                   AND (type = 'U')))
  617. BEGIN
  618.   PRINT ''
  619.   PRINT 'Creating table sysjobhistory...'
  620.  
  621.   CREATE TABLE sysjobhistory
  622.   (
  623.   instance_id          INT IDENTITY     NOT NULL,
  624.   job_id               UNIQUEIDENTIFIER NOT NULL,
  625.   step_id              INT              NOT NULL,
  626.   step_name            sysname          NOT NULL,
  627.   sql_message_id       INT              NOT NULL,
  628.   sql_severity         INT              NOT NULL,
  629.   message              NVARCHAR(1024)   NULL,
  630.   run_status           INT              NOT NULL,
  631.   run_date             INT              NOT NULL,
  632.   run_time             INT              NOT NULL,
  633.   run_duration         INT              NOT NULL,
  634.   operator_id_emailed  INT              NOT NULL,
  635.   operator_id_netsent  INT              NOT NULL,
  636.   operator_id_paged    INT              NOT NULL,
  637.   retries_attempted    INT              NOT NULL,
  638.   server               NVARCHAR(30)     NOT NULL
  639.   )
  640.  
  641.   CREATE UNIQUE CLUSTERED INDEX clust ON sysjobhistory(instance_id)
  642.   CREATE NONCLUSTERED     INDEX nc1   ON sysjobhistory(job_id)
  643. END
  644. go
  645.  
  646. /**************************************************************/
  647. /* SYSJOBS                                                    */
  648. /**************************************************************/
  649.  
  650. IF (NOT EXISTS (SELECT *
  651.                 FROM msdb.dbo.sysobjects
  652.                 WHERE (name = N'sysjobs')
  653.                   AND (type = 'U')))
  654. BEGIN
  655.   PRINT ''
  656.   PRINT 'Creating table sysjobs...'
  657.  
  658.   CREATE TABLE sysjobs
  659.   (
  660.   job_id                     UNIQUEIDENTIFIER NOT NULL,
  661.   originating_server         NVARCHAR(30)     NOT NULL,
  662.   name                       sysname          NOT NULL,
  663.   enabled                    TINYINT          NOT NULL,
  664.   description                NVARCHAR(512)    NULL,
  665.   start_step_id              INT              NOT NULL,
  666.   category_id                INT              NOT NULL,
  667.   owner_sid                  VARBINARY(85)    NOT NULL,
  668.   notify_level_eventlog      INT              NOT NULL,
  669.   notify_level_email         INT              NOT NULL,
  670.   notify_level_netsend       INT              NOT NULL,
  671.   notify_level_page          INT              NOT NULL,
  672.   notify_email_operator_id   INT              NOT NULL,
  673.   notify_netsend_operator_id INT              NOT NULL,
  674.   notify_page_operator_id    INT              NOT NULL,
  675.   delete_level               INT              NOT NULL,
  676.   date_created               DATETIME         NOT NULL,
  677.   date_modified              DATETIME         NOT NULL,
  678.   version_number             INT              NOT NULL
  679.   )
  680.  
  681.   CREATE UNIQUE CLUSTERED INDEX clust ON sysjobs(job_id)
  682.   CREATE NONCLUSTERED     INDEX nc1   ON sysjobs(name) -- NOTE: This is deliberately non-unique
  683.   CREATE NONCLUSTERED     INDEX nc2   ON sysjobs(originating_server)
  684.   CREATE NONCLUSTERED     INDEX nc3   ON sysjobs(category_id)
  685.   CREATE NONCLUSTERED     INDEX nc4   ON sysjobs(owner_sid)
  686. END
  687. go
  688.  
  689. /**************************************************************/
  690. /* SYSJOBS_VIEW                                               */
  691. /**************************************************************/
  692.  
  693. PRINT ''
  694. PRINT 'Creating view sysjobs_view...'
  695. go
  696. IF (EXISTS (SELECT *
  697.             FROM msdb.dbo.sysobjects
  698.             WHERE (name = N'sysjobs_view')
  699.               AND (type = 'V')))
  700.   DROP VIEW sysjobs_view
  701. go
  702. CREATE VIEW sysjobs_view
  703. AS
  704. SELECT *
  705. FROM msdb.dbo.sysjobs
  706. WHERE (owner_sid = SUSER_SID())
  707.    OR (ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) = 1)
  708.    OR (ISNULL(IS_MEMBER(N'TargetServersRole'), 0) = 1)
  709. go
  710.  
  711. /**************************************************************/
  712. /* SYSJOBSERVERS                                              */
  713. /**************************************************************/
  714.  
  715. IF (NOT EXISTS (SELECT *
  716.                 FROM msdb.dbo.sysobjects
  717.                 WHERE (name = N'sysjobservers')
  718.                   AND (type = 'U')))
  719. BEGIN
  720.   PRINT ''
  721.   PRINT 'Creating table sysjobservers...'
  722.  
  723.   CREATE TABLE sysjobservers
  724.   (
  725.   job_id               UNIQUEIDENTIFIER NOT NULL,
  726.   server_id            INT              NOT NULL,
  727.   last_run_outcome     TINYINT          NOT NULL,
  728.   last_outcome_message NVARCHAR(1024)   NULL,
  729.   last_run_date        INT              NOT NULL,
  730.   last_run_time        INT              NOT NULL,
  731.   last_run_duration    INT              NOT NULL
  732.   )
  733.  
  734.   CREATE CLUSTERED    INDEX clust ON sysjobservers(job_id)
  735.   CREATE NONCLUSTERED INDEX nc1   ON sysjobservers(server_id)
  736. END
  737. go
  738.  
  739. /**************************************************************/
  740. /* SYSJOBSTEPS                                                */
  741. /**************************************************************/
  742.  
  743. IF (NOT EXISTS (SELECT *
  744.                 FROM msdb.dbo.sysobjects
  745.                 WHERE (name = N'sysjobsteps')
  746.                   AND (type = 'U')))
  747. BEGIN
  748.   PRINT ''
  749.   PRINT 'Creating table sysjobsteps...'
  750.  
  751.   CREATE TABLE sysjobsteps
  752.   (
  753.   job_id                UNIQUEIDENTIFIER NOT NULL,
  754.   step_id               INT              NOT NULL,
  755.   step_name             sysname          NOT NULL,
  756.   subsystem             NVARCHAR(40)     NOT NULL,
  757.   command               NVARCHAR(3200)   NULL,      -- NOTE: 3.125K since unicode requires 2x space
  758.   flags                 INT              NOT NULL,
  759.   additional_parameters NTEXT            NULL,
  760.   cmdexec_success_code  INT              NOT NULL,
  761.   on_success_action     TINYINT          NOT NULL,
  762.   on_success_step_id    INT              NOT NULL,
  763.   on_fail_action        TINYINT          NOT NULL,
  764.   on_fail_step_id       INT              NOT NULL,
  765.   server                sysname          NULL,      -- Used only by replication
  766.   database_name         sysname          NULL,
  767.   database_user_name    sysname          NULL,
  768.   retry_attempts        INT              NOT NULL,
  769.   retry_interval        INT              NOT NULL,
  770.   os_run_priority       INT              NOT NULL,  -- NOTE: Cannot use TINYINT because we need a signed number
  771.   output_file_name      NVARCHAR(200)    NULL,
  772.   last_run_outcome      INT              NOT NULL,
  773.   last_run_duration     INT              NOT NULL,
  774.   last_run_retries      INT              NOT NULL,
  775.   last_run_date         INT              NOT NULL,
  776.   last_run_time         INT              NOT NULL
  777.   )
  778.  
  779.   CREATE UNIQUE CLUSTERED INDEX clust ON sysjobsteps(job_id, step_id)
  780.   CREATE UNIQUE NONCLUSTERED INDEX nc1 ON sysjobsteps(job_id, step_name)
  781. END
  782. go
  783.  
  784. /**************************************************************/
  785. /* SYSJOBSCHEDULES                                            */
  786. /**************************************************************/
  787.  
  788. IF (NOT EXISTS (SELECT *
  789.                 FROM msdb.dbo.sysobjects
  790.                 WHERE (name = N'sysjobschedules')
  791.                   AND (type = 'U')))
  792. BEGIN
  793.   PRINT ''
  794.   PRINT 'Creating table sysjobschedules...'
  795.  
  796.   CREATE TABLE sysjobschedules
  797.   (
  798.   schedule_id            INT IDENTITY     NOT NULL,
  799.   job_id                 UNIQUEIDENTIFIER NOT NULL,
  800.   name                   sysname          NOT NULL,
  801.   enabled                INT              NOT NULL,
  802.   freq_type              INT              NOT NULL,
  803.   freq_interval          INT              NOT NULL,
  804.   freq_subday_type       INT              NOT NULL,
  805.   freq_subday_interval   INT              NOT NULL,
  806.   freq_relative_interval INT              NOT NULL,
  807.   freq_recurrence_factor INT              NOT NULL,
  808.   active_start_date      INT              NOT NULL,
  809.   active_end_date        INT              NOT NULL,
  810.   active_start_time      INT              NOT NULL,
  811.   active_end_time        INT              NOT NULL,
  812.   next_run_date          INT              NOT NULL,
  813.   next_run_time          INT              NOT NULL,
  814.   date_created           DATETIME         NOT NULL
  815.   )
  816.  
  817.   EXECUTE sp_bindefault default_current_date, N'sysjobschedules.date_created'
  818.  
  819.   CREATE UNIQUE CLUSTERED INDEX clust ON sysjobschedules(job_id, name)
  820.   CREATE UNIQUE NONCLUSTERED INDEX nc1 ON sysjobschedules(schedule_id)
  821. END
  822. go
  823.  
  824. /**************************************************************/
  825. /* SYSCATEGORIES                                              */
  826. /**************************************************************/
  827.  
  828. IF (NOT EXISTS (SELECT *
  829.                 FROM msdb.dbo.sysobjects
  830.                 WHERE (name = N'syscategories')
  831.                   AND (type = 'U')))
  832. BEGIN
  833.   PRINT ''
  834.   PRINT 'Creating table syscategories...'
  835.  
  836.   CREATE TABLE syscategories
  837.   (
  838.   category_id    INT IDENTITY NOT NULL,
  839.   category_class INT          NOT NULL, -- 1 = Job, 2 = Alert, 3 = Operator
  840.   category_type  TINYINT      NOT NULL, -- 1 = Local, 2 = Multi-Server [Only relevant if class is 1; otherwise, 3 (None)]
  841.   name           sysname      NOT NULL
  842.   )
  843.  
  844.   CREATE UNIQUE CLUSTERED INDEX clust ON syscategories(name, category_class)
  845. END
  846. go
  847.  
  848. -- Install standard [permanent] categories (reserved ID range is 0 - 99)
  849. SET IDENTITY_INSERT msdb.dbo.syscategories ON
  850.  
  851. DELETE FROM msdb.dbo.syscategories 
  852. WHERE (category_id < 100)
  853.  
  854. -- Core categories
  855. INSERT INTO msdb.dbo.syscategories (category_id, category_class, category_type, name) VALUES ( 0, 1, 1, N'[Uncategorized (Local)]')        -- Local default
  856. 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
  857. INSERT INTO msdb.dbo.syscategories (category_id, category_class, category_type, name) VALUES ( 2, 1, 2, N'[Uncategorized (Multi-Server)]') -- Multi-server default
  858. 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
  859. 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
  860. 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
  861. INSERT INTO msdb.dbo.syscategories (category_id, category_class, category_type, name) VALUES (98, 2, 3, N'[Uncategorized]')                -- Alert default
  862. INSERT INTO msdb.dbo.syscategories (category_id, category_class, category_type, name) VALUES (99, 3, 3, N'[Uncategorized]')                -- Operator default
  863.  
  864. -- Replication categories
  865. INSERT INTO msdb.dbo.syscategories (category_id, category_class, category_type, name) VALUES (10, 1, 1, N'REPL-Distribution')
  866. INSERT INTO msdb.dbo.syscategories (category_id, category_class, category_type, name) VALUES (11, 1, 1, N'REPL-Distribution Cleanup')
  867. INSERT INTO msdb.dbo.syscategories (category_id, category_class, category_type, name) VALUES (12, 1, 1, N'REPL-History Cleanup')
  868. INSERT INTO msdb.dbo.syscategories (category_id, category_class, category_type, name) VALUES (13, 1, 1, N'REPL-LogReader')
  869. INSERT INTO msdb.dbo.syscategories (category_id, category_class, category_type, name) VALUES (14, 1, 1, N'REPL-Merge')
  870. INSERT INTO msdb.dbo.syscategories (category_id, category_class, category_type, name) VALUES (15, 1, 1, N'REPL-Snapshot')
  871. INSERT INTO msdb.dbo.syscategories (category_id, category_class, category_type, name) VALUES (16, 1, 1, N'REPL-Checkup')
  872. INSERT INTO msdb.dbo.syscategories (category_id, category_class, category_type, name) VALUES (17, 1, 1, N'REPL-Subscription Cleanup')
  873. INSERT INTO msdb.dbo.syscategories (category_id, category_class, category_type, name) VALUES (18, 1, 1, N'REPL-Alert Response')
  874. INSERT INTO msdb.dbo.syscategories (category_id, category_class, category_type, name) VALUES (20, 2, 3, N'Replication')
  875.  
  876. SET IDENTITY_INSERT msdb.dbo.syscategories OFF
  877. go
  878.  
  879. /**************************************************************/
  880. /* SYSTARGETSERVERS                                           */
  881. /**************************************************************/
  882.  
  883. IF (NOT EXISTS (SELECT *
  884.                 FROM msdb.dbo.sysobjects
  885.                 WHERE (name = N'systargetservers')
  886.                   AND (type = 'U')))
  887. BEGIN
  888.   PRINT ''
  889.   PRINT 'Creating table systargetservers...'
  890.  
  891.   CREATE TABLE systargetservers
  892.   (
  893.   server_id               INT IDENTITY  NOT NULL,
  894.   server_name             NVARCHAR(30)  NOT NULL,
  895.   location                NVARCHAR(200) NULL,
  896.   time_zone_adjustment    INT           NOT NULL,  -- The offset from GMT in minutes (set by sp_msx_enlist)
  897.   enlist_date             DATETIME      NOT NULL,
  898.   last_poll_date          DATETIME      NOT NULL,
  899.   status                  INT           NOT NULL,  -- 1 = Normal, 2 = Offline, 4 = Blocked
  900.   local_time_at_last_poll DATETIME      NOT NULL,  -- The local time at the target server as-of the last time it polled the MSX
  901.   enlisted_by_nt_user     NVARCHAR(100) NOT NULL,
  902.   poll_interval           INT           NOT NULL   -- The MSX polling interval (in seconds)
  903.   )
  904.  
  905.   EXECUTE sp_bindefault default_current_date, N'systargetservers.enlist_date'
  906.   EXECUTE sp_bindefault default_current_date, N'systargetservers.last_poll_date'
  907.   EXECUTE sp_bindefault default_one,          N'systargetservers.status'
  908.  
  909.   CREATE UNIQUE CLUSTERED    INDEX clust ON systargetservers(server_id)
  910.   CREATE UNIQUE NONCLUSTERED INDEX nc1   ON systargetservers(server_name)
  911. END
  912. go
  913.  
  914. /**************************************************************/
  915. /* SYSTARGETSERVERS_VIEW                                      */
  916. /**************************************************************/
  917.  
  918. PRINT ''
  919. PRINT 'Creating view systargetservers_view...'
  920. go
  921. IF (EXISTS (SELECT *
  922.             FROM msdb.dbo.sysobjects
  923.             WHERE (name = N'systargetservers_view')
  924.               AND (type = 'V')))
  925.   DROP VIEW systargetservers_view
  926. go
  927. CREATE VIEW systargetservers_view
  928. AS
  929. SELECT server_id,
  930.        server_name,
  931.        enlist_date,
  932.        last_poll_date
  933. FROM msdb.dbo.systargetservers
  934. UNION
  935. SELECT 0,
  936.        N'(local)',
  937.        CONVERT(DATETIME, N'19981113', 112),
  938.        CONVERT(DATETIME, N'19981113', 112)  
  939. go
  940.  
  941. /**************************************************************/
  942. /* SYSTARGETSERVERGROUPS                                      */
  943. /**************************************************************/
  944.  
  945. IF (NOT EXISTS (SELECT *
  946.                 FROM msdb.dbo.sysobjects
  947.                 WHERE (name = N'systargetservergroups')
  948.                   AND (type = 'U')))
  949. BEGIN
  950.   PRINT ''
  951.   PRINT 'Creating table systargetservergroups...'
  952.  
  953.   CREATE TABLE systargetservergroups
  954.   (
  955.   servergroup_id INT IDENTITY NOT NULL,
  956.   name           sysname      NOT NULL
  957.   )
  958.  
  959.   CREATE UNIQUE CLUSTERED INDEX clust ON systargetservergroups(name)
  960. END
  961. go
  962.  
  963. /**************************************************************/
  964. /* SYSTARGETSERVERGROUPMEMBERS                                */
  965. /**************************************************************/
  966.  
  967. IF (NOT EXISTS (SELECT *
  968.                 FROM msdb.dbo.sysobjects
  969.                 WHERE (name = N'systargetservergroupmembers')
  970.                   AND (type = 'U')))
  971. BEGIN
  972.   PRINT ''
  973.   PRINT 'Creating table systargetservergroupmembers...'
  974.  
  975.   CREATE TABLE systargetservergroupmembers
  976.   (
  977.   servergroup_id INT NOT NULL,
  978.   server_id      INT NOT NULL
  979.   )
  980.  
  981.   CREATE UNIQUE CLUSTERED INDEX clust ON systargetservergroupmembers(servergroup_id, server_id)
  982.   CREATE NONCLUSTERED     INDEX nc1   ON systargetservergroupmembers(server_id)
  983. END
  984. go
  985.  
  986. /**************************************************************/
  987. /* SYSALERTS                                                  */
  988. /**************************************************************/
  989.  
  990. IF (NOT EXISTS (SELECT *
  991.                 FROM msdb.dbo.sysobjects
  992.                 WHERE (name = N'sysalerts')
  993.                   AND (type = 'U')))
  994. BEGIN
  995.   PRINT ''
  996.   PRINT 'Creating table sysalerts...'
  997.  
  998.   CREATE TABLE sysalerts
  999.   (
  1000.   id                        INT IDENTITY     NOT NULL,
  1001.   name                      sysname          NOT NULL, -- Was length 60 in 6.x
  1002.   event_source              NVARCHAR(100)    NOT NULL,
  1003.   event_category_id         INT              NULL,
  1004.   event_id                  INT              NULL,
  1005.   message_id                INT              NOT NULL, -- Was NULL in 6.x
  1006.   severity                  INT              NOT NULL, -- Was NULL in 6.x
  1007.   enabled                   TINYINT          NOT NULL,
  1008.   delay_between_responses   INT              NOT NULL,
  1009.   last_occurrence_date      INT              NOT NULL, -- Was NULL in 6.x
  1010.   last_occurrence_time      INT              NOT NULL, -- Was NULL in 6.x
  1011.   last_response_date        INT              NOT NULL, -- Was NULL in 6.x
  1012.   last_response_time        INT              NOT NULL, -- Was NULL in 6.x
  1013.   notification_message      NVARCHAR(512)    NULL,
  1014.   include_event_description TINYINT          NOT NULL,
  1015.   database_name             sysname          NULL,
  1016.   event_description_keyword NVARCHAR(100)    NULL,
  1017.   occurrence_count          INT              NOT NULL,
  1018.   count_reset_date          INT              NOT NULL, -- Was NULL in 6.x
  1019.   count_reset_time          INT              NOT NULL, -- Was NULL in 6.x
  1020.   job_id                    UNIQUEIDENTIFIER NOT NULL, -- Was NULL in 6.x
  1021.   has_notification          INT              NOT NULL, -- New for 7.0
  1022.   flags                     INT              NOT NULL, -- Was NULL in 6.x
  1023.   performance_condition     NVARCHAR(512)    NULL,
  1024.   category_id               INT              NOT NULL  -- New for 7.0
  1025.   )
  1026.  
  1027.   CREATE UNIQUE CLUSTERED INDEX ByName ON sysalerts(name)
  1028.   CREATE UNIQUE INDEX ByID ON sysalerts(id)
  1029. END
  1030. go
  1031.  
  1032. /**************************************************************/
  1033. /* SYSOPERATORS                                               */
  1034. /**************************************************************/
  1035.  
  1036. IF (NOT EXISTS (SELECT *
  1037.                 FROM msdb.dbo.sysobjects
  1038.                 WHERE (name = N'sysoperators')
  1039.                   AND (type = 'U')))
  1040. BEGIN
  1041.   PRINT ''
  1042.   PRINT 'Creating table sysoperators...'
  1043.  
  1044.   CREATE TABLE sysoperators
  1045.   (
  1046.   id                        INT IDENTITY  NOT NULL,
  1047.   name                      sysname       NOT NULL, -- Was length 50 in 6.x
  1048.   enabled                   TINYINT       NOT NULL,
  1049.   email_address             NVARCHAR(100) NULL,
  1050.   last_email_date           INT           NOT NULL, -- Was NULL in 6.x
  1051.   last_email_time           INT           NOT NULL, -- Was NULL in 6.x
  1052.   pager_address             NVARCHAR(100) NULL,
  1053.   last_pager_date           INT           NOT NULL, -- Was NULL in 6.x
  1054.   last_pager_time           INT           NOT NULL, -- Was NULL in 6.x
  1055.   weekday_pager_start_time  INT           NOT NULL,
  1056.   weekday_pager_end_time    INT           NOT NULL,
  1057.   saturday_pager_start_time INT           NOT NULL,
  1058.   saturday_pager_end_time   INT           NOT NULL,
  1059.   sunday_pager_start_time   INT           NOT NULL,
  1060.   sunday_pager_end_time     INT           NOT NULL,
  1061.   pager_days                TINYINT       NOT NULL,
  1062.   netsend_address           NVARCHAR(100) NULL,     -- New for 7.0
  1063.   last_netsend_date         INT           NOT NULL, -- New for 7.0
  1064.   last_netsend_time         INT           NOT NULL, -- New for 7.0
  1065.   category_id               INT           NOT NULL  -- New for 7.0
  1066.   )
  1067.  
  1068.   CREATE UNIQUE CLUSTERED INDEX ByName ON sysoperators(name)
  1069.   CREATE UNIQUE INDEX ByID ON sysoperators(id)
  1070. END
  1071. go
  1072.  
  1073. /**************************************************************/
  1074. /* SYSNOTIFICATIONS                                           */
  1075. /**************************************************************/
  1076.  
  1077. IF (NOT EXISTS (SELECT *
  1078.                 FROM msdb.dbo.sysobjects
  1079.                 WHERE (name = N'sysnotifications')
  1080.                   AND (type = 'U')))
  1081. BEGIN
  1082.   PRINT ''
  1083.   PRINT 'Creating table sysnotifications...'
  1084.  
  1085.   CREATE TABLE sysnotifications
  1086.   (
  1087.   alert_id             INT      NOT NULL,
  1088.   operator_id          INT      NOT NULL,
  1089.   notification_method  TINYINT  NOT NULL
  1090.   )
  1091.  
  1092.   CREATE UNIQUE CLUSTERED INDEX ByAlertIDAndOperatorID ON sysnotifications(alert_id, operator_id)
  1093. END
  1094. go
  1095.  
  1096. /**************************************************************/
  1097. /* SYSTASKIDS                                                 */
  1098. /*                                                            */
  1099. /* This table provides a mapping between new GUID job ID's    */
  1100. /* and 6.x INT task ID's.                                     */
  1101. /* Entries are made in this table for all existing 6.x tasks  */
  1102. /* and for all new tasks added using the 7.0 version of       */
  1103. /* sp_addtask.                                                */
  1104. /* Callers of the 7.0 version of sp_helptask will ONLY see    */
  1105. /* tasks [jobs] that have a corresponding entry in this table */
  1106. /* [IE. Jobs created with sp_add_job will not be returned].   */
  1107. /**************************************************************/
  1108.  
  1109. IF (NOT EXISTS (SELECT *
  1110.                 FROM msdb.dbo.sysobjects
  1111.                 WHERE (name = N'systaskids')
  1112.                   AND (type = 'U')))
  1113. BEGIN
  1114.   CREATE TABLE systaskids
  1115.   (
  1116.   task_id INT IDENTITY     NOT NULL,
  1117.   job_id  UNIQUEIDENTIFIER NOT NULL
  1118.   )
  1119.  
  1120.   CREATE CLUSTERED INDEX clust ON systaskids(job_id)
  1121. END
  1122. go
  1123.  
  1124. DUMP TRANSACTION msdb WITH NO_LOG
  1125. go
  1126. CHECKPOINT
  1127. go
  1128.  
  1129.  
  1130. /**************************************************************/
  1131. /*                                                            */
  1132. /*        C  O  R  E     P  R  O  C  E  D  U  R  E  S         */
  1133. /*                                                            */
  1134. /**************************************************************/
  1135.  
  1136. /**************************************************************/
  1137. /* SYSCACHEDCREDENTIALS                                       */
  1138. /*                                                            */
  1139. /**************************************************************/
  1140.  
  1141. IF (NOT EXISTS (SELECT *
  1142.                 FROM msdb.dbo.sysobjects
  1143.                 WHERE (name = N'syscachedcredentials')
  1144.                   AND (type = 'U')))
  1145. BEGIN
  1146.   CREATE TABLE syscachedcredentials
  1147.   (
  1148.   login_name          sysname      NOT NULL PRIMARY KEY,
  1149.   has_server_access   BIT          NOT NULL DEFAULT 0,
  1150.   is_sysadmin_member  BIT          NOT NULL DEFAULT 0,
  1151.   cachedate           DATETIME     NOT NULL DEFAULT getdate()
  1152.   )
  1153. END
  1154. go
  1155.  
  1156.  
  1157.  
  1158. /**************************************************************/
  1159. /* SP_SQLAGENT_GET_STARTUP_INFO                               */
  1160. /**************************************************************/
  1161.  
  1162. PRINT ''
  1163. PRINT 'Creating procedure sp_sqlagent_get_startup_info...'
  1164. go
  1165. IF (EXISTS (SELECT *
  1166.             FROM msdb.dbo.sysobjects
  1167.             WHERE (name = 'sp_sqlagent_get_startup_info')
  1168.               AND (type = 'P')))
  1169.   DROP PROCEDURE sp_sqlagent_get_startup_info
  1170. go
  1171. CREATE PROCEDURE sp_sqlagent_get_startup_info
  1172. AS
  1173. BEGIN
  1174.   DECLARE @tbu INT
  1175.  
  1176.   SET NOCOUNT ON
  1177.  
  1178.   EXECUTE @tbu = master.dbo.xp_qv '1338198028'
  1179.   IF (@tbu < 0)
  1180.     SELECT @tbu = 0
  1181.  
  1182.   SELECT 'msdb_70_compatible' = (SELECT CASE WHEN cmptlevel >= 70 THEN 1 ELSE 0 END FROM master.dbo.sysdatabases WHERE (name = 'msdb')),
  1183.          'msdb_read_only' = DATABASEPROPERTY('msdb', 'IsReadOnly'),
  1184.          'msdb_available' = CASE ISNULL(DATABASEPROPERTY('msdb', 'IsSingleUser'), 0) WHEN 0 THEN 1 ELSE 0 END &
  1185.                             CASE ISNULL(DATABASEPROPERTY('msdb', 'IsDboOnly'), 0) WHEN 0 THEN 1 ELSE 0 END &
  1186.                             CASE ISNULL(DATABASEPROPERTY('msdb', 'IsNotRecovered'), 0) WHEN 0 THEN 1 ELSE 0 END & 
  1187.                             CASE ISNULL(DATABASEPROPERTY('msdb', 'IsSuspect'), 0) WHEN 0 THEN 1 ELSE 0 END,
  1188.          'case_sensitive_server' = CASE ISNULL((SELECT 1 WHERE 'a' = 'A'), 0)
  1189.                                      WHEN 1 THEN 0
  1190.                                      ELSE 1
  1191.                                    END,
  1192.          'max_user_connection' = (SELECT value FROM master.dbo.syscurconfigs WHERE (config = 103)),
  1193.          'sql_server_name' = ISNULL(@@servername, N'(no name)'),
  1194.          'tbu' = ISNULL(@tbu, 0),
  1195.          'platform' = PLATFORM()
  1196.  
  1197.   RETURN(0) -- Success
  1198. END
  1199. go
  1200.  
  1201. /**************************************************************/
  1202. /* SP_SQLAGENT_HAS_SERVER_ACCESS                              */
  1203. /**************************************************************/
  1204.  
  1205. PRINT ''
  1206. PRINT 'Creating procedure sp_sqlagent_has_server_access...'
  1207. go
  1208. IF (EXISTS (SELECT *
  1209.             FROM msdb.dbo.sysobjects
  1210.             WHERE (name = 'sp_sqlagent_has_server_access')
  1211.               AND (type = 'P')))
  1212.   DROP PROCEDURE sp_sqlagent_has_server_access
  1213. go
  1214. CREATE PROCEDURE sp_sqlagent_has_server_access
  1215.   @login_name         sysname = NULL,
  1216.   @is_sysadmin_member INT     = NULL OUTPUT
  1217. AS
  1218. BEGIN
  1219.   DECLARE @has_server_access BIT
  1220.   DECLARE @is_sysadmin       BIT
  1221.   DECLARE @actual_login_name sysname
  1222.   DECLARE @cachedate         DATETIME
  1223.  
  1224.   SET NOCOUNT ON
  1225.  
  1226.   SELECT @cachedate = NULL
  1227.  
  1228.   -- remove expired entries from the cache
  1229.   DELETE msdb.dbo.syscachedcredentials
  1230.   WHERE  DATEDIFF(MINUTE, cachedate, GETDATE()) >= 29
  1231.  
  1232.   -- query the cache
  1233.   SELECT  @is_sysadmin = is_sysadmin_member,
  1234.           @has_server_access = has_server_access,
  1235.           @cachedate = cachedate
  1236.   FROM    msdb.dbo.syscachedcredentials
  1237.   WHERE   login_name = @login_name
  1238.   AND     DATEDIFF(MINUTE, cachedate, GETDATE()) < 29
  1239.  
  1240.   IF (@cachedate IS NOT NULL)
  1241.   BEGIN
  1242.     -- no output variable
  1243.     IF (@is_sysadmin_member IS NULL)
  1244.     BEGIN
  1245.       -- Return result row
  1246.       SELECT has_server_access = @has_server_access,
  1247.              is_sysadmin       = @is_sysadmin,
  1248.              actual_login_name = @login_name
  1249.       RETURN
  1250.     END
  1251.     ELSE
  1252.     BEGIN
  1253.       SELECT @is_sysadmin_member = @is_sysadmin
  1254.       RETURN
  1255.     END
  1256.   END -- select from cache
  1257.  
  1258.   CREATE TABLE #xp_results
  1259.   (
  1260.   account_name      sysname      NOT NULL PRIMARY KEY,
  1261.   type              NVARCHAR(10) NOT NULL,
  1262.   privilege         NVARCHAR(10) NOT NULL,
  1263.   mapped_login_name sysname      NOT NULL,
  1264.   permission_path   sysname      NULL
  1265.   )
  1266.  
  1267.   -- Set defaults
  1268.   SELECT @has_server_access = 0
  1269.   SELECT @is_sysadmin = 0
  1270.   SELECT @actual_login_name = FORMATMESSAGE(14205)
  1271.  
  1272.   IF (@login_name IS NULL)
  1273.   BEGIN
  1274.     SELECT has_server_access = 1,
  1275.            is_sysadmin       = IS_SRVROLEMEMBER(N'sysadmin'),
  1276.            actual_login_name = SUSER_SNAME()
  1277.     RETURN
  1278.   END
  1279.  
  1280.   IF (@login_name LIKE '%\%')
  1281.   BEGIN
  1282.     -- Handle the LocalSystem account ('NT AUTHORITY\SYSTEM') as a special case
  1283.     IF (UPPER(@login_name) = N'NT AUTHORITY\SYSTEM')
  1284.     BEGIN
  1285.       IF (EXISTS (SELECT *
  1286.                   FROM master.dbo.syslogins
  1287.                   WHERE (UPPER(loginname) = N'BUILTIN\ADMINISTRATORS')))
  1288.       BEGIN
  1289.         SELECT @has_server_access = hasaccess,
  1290.                @is_sysadmin = sysadmin,
  1291.                @actual_login_name = loginname
  1292.         FROM master.dbo.syslogins
  1293.         WHERE (UPPER(loginname) = N'BUILTIN\ADMINISTRATORS')
  1294.       END
  1295.     END
  1296.     ELSE
  1297.     BEGIN
  1298.       -- Check if the NT login has been explicitly denied access
  1299.       IF (EXISTS (SELECT *
  1300.                   FROM master.dbo.syslogins
  1301.                   WHERE (loginname = @login_name)
  1302.                     AND (denylogin = 1)))
  1303.       BEGIN
  1304.         SELECT @has_server_access = 0,
  1305.                @is_sysadmin = sysadmin,
  1306.                @actual_login_name = loginname
  1307.         FROM master.dbo.syslogins
  1308.         WHERE (loginname = @login_name)
  1309.       END
  1310.       ELSE
  1311.       BEGIN
  1312.         -- Call xp_logininfo to determine server access
  1313.         INSERT INTO #xp_results
  1314.         EXECUTE master.dbo.xp_logininfo @login_name
  1315.  
  1316.         SELECT @has_server_access = CASE COUNT(*)
  1317.                                       WHEN 0 THEN 0
  1318.                                       ELSE 1
  1319.                                     END
  1320.         FROM #xp_results
  1321.         SELECT @actual_login_name = mapped_login_name,
  1322.                @is_sysadmin = CASE UPPER(privilege)
  1323.                                 WHEN 'ADMIN' THEN 1
  1324.                                 ELSE 0
  1325.                              END
  1326.         FROM #xp_results
  1327.       END
  1328.     END
  1329.   END
  1330.   ELSE
  1331.   BEGIN
  1332.     -- Standard login
  1333.     IF (EXISTS (SELECT *
  1334.                 FROM master.dbo.syslogins
  1335.                 WHERE (loginname = @login_name)))
  1336.     BEGIN
  1337.       SELECT @has_server_access = hasaccess,
  1338.              @is_sysadmin = sysadmin,
  1339.              @actual_login_name = loginname
  1340.       FROM master.dbo.syslogins
  1341.       WHERE (loginname = @login_name)
  1342.     END
  1343.   END
  1344.  
  1345.   -- update the cache only if something is found
  1346.   IF  (UPPER(@actual_login_name) <> '(UNKNOWN)')
  1347.   BEGIN
  1348.     IF EXISTS (SELECT * FROM msdb.dbo.syscachedcredentials WHERE login_name = @login_name)
  1349.     BEGIN
  1350.       UPDATE msdb.dbo.syscachedcredentials
  1351.       SET    has_server_access = @has_server_access,
  1352.              is_sysadmin_member = @is_sysadmin,
  1353.              cachedate = GETDATE()
  1354.       WHERE  login_name = @login_name
  1355.     END
  1356.     ELSE
  1357.     BEGIN
  1358.       INSERT INTO msdb.dbo.syscachedcredentials(login_name, has_server_access, is_sysadmin_member) 
  1359.       VALUES(@login_name, @has_server_access, @is_sysadmin)
  1360.     END
  1361.   END
  1362.  
  1363.   IF (@is_sysadmin_member IS NULL)
  1364.     -- Return result row
  1365.     SELECT has_server_access = @has_server_access,
  1366.            is_sysadmin       = @is_sysadmin,
  1367.            actual_login_name = @actual_login_name
  1368.   ELSE
  1369.     -- output variable only
  1370.     SELECT @is_sysadmin_member = @is_sysadmin
  1371. END
  1372. go
  1373.  
  1374.  
  1375. /**************************************************************/
  1376. /* SP_SEM_ADD_MESSAGE [used by SEM only]                      */
  1377. /**************************************************************/
  1378.  
  1379. PRINT ''
  1380. PRINT 'Creating procedure sp_sem_add_message...'
  1381. go
  1382. IF (EXISTS (SELECT *
  1383.             FROM msdb.dbo.sysobjects
  1384.             WHERE (name = 'sp_sem_add_message')
  1385.               AND (type = 'P')))
  1386.   DROP PROCEDURE sp_sem_add_message
  1387. go
  1388. CREATE PROCEDURE sp_sem_add_message
  1389.   @msgnum   INT           = NULL,
  1390.   @severity SMALLINT      = NULL,
  1391.   @msgtext  NVARCHAR(255) = NULL,
  1392.   @lang     sysname       = NULL, -- Message language name
  1393.   @with_log VARCHAR(5)    = 'FALSE',
  1394.   @replace  VARCHAR(7)    = NULL
  1395. AS
  1396. BEGIN
  1397.   DECLARE @retval        INT
  1398.   DECLARE @language_name sysname
  1399.  
  1400.   SET NOCOUNT ON
  1401.  
  1402.   SET ROWCOUNT 1
  1403.   SELECT @language_name = name 
  1404.   FROM master.dbo.syslanguages
  1405.   WHERE msglangid = (SELECT number 
  1406.                      FROM master.dbo.spt_values 
  1407.                      WHERE (type = 'LNG') 
  1408.                        AND (name = @lang))
  1409.   SET ROWCOUNT 0
  1410.  
  1411.   SELECT @language_name = ISNULL(@language_name, 'us_english')
  1412.   EXECUTE @retval = master.dbo.sp_addmessage @msgnum, @severity, @msgtext, @language_name, @with_log, @replace
  1413.   RETURN(@retval)
  1414. END
  1415. go
  1416.  
  1417. /**************************************************************/
  1418. /* SP_SEM_DROP_MESSAGE [used by SEM only]                     */
  1419. /**************************************************************/
  1420.  
  1421. PRINT ''
  1422. PRINT 'Creating procedure sp_sem_drop_message...'
  1423. go
  1424. IF (EXISTS (SELECT *
  1425.             FROM msdb.dbo.sysobjects
  1426.             WHERE (name = 'sp_sem_drop_message')
  1427.               AND (type = 'P')))
  1428.   DROP PROCEDURE sp_sem_drop_message
  1429. go
  1430. CREATE PROCEDURE sp_sem_drop_message
  1431.   @msgnum int     = NULL,
  1432.   @lang   sysname = NULL -- Message language name
  1433. AS
  1434. BEGIN
  1435.   DECLARE @retval        INT
  1436.   DECLARE @language_name sysname
  1437.  
  1438.   SET NOCOUNT ON
  1439.  
  1440.   SET ROWCOUNT 1
  1441.   SELECT @language_name = name 
  1442.   FROM master.dbo.syslanguages
  1443.   WHERE msglangid = (SELECT number 
  1444.                      FROM master.dbo.spt_values 
  1445.                      WHERE (type = 'LNG') 
  1446.                        AND (name = @lang))
  1447.   SET ROWCOUNT 0
  1448.  
  1449.   SELECT @language_name = ISNULL(@language_name, 'us_english')
  1450.   EXECUTE @retval = master.dbo.sp_dropmessage @msgnum, @language_name
  1451.   RETURN(@retval)
  1452. END
  1453. go
  1454.  
  1455. /**************************************************************/
  1456. /* SP_GET_MESSAGE_DESCRIPTION [used by SEM only]              */
  1457. /**************************************************************/
  1458.  
  1459. PRINT ''
  1460. PRINT 'Creating procedure sp_get_message_description...'
  1461. go
  1462. IF (EXISTS (SELECT *
  1463.             FROM msdb.dbo.sysobjects
  1464.             WHERE (name = 'sp_get_message_description')
  1465.               AND (type = 'P')))
  1466.   DROP PROCEDURE sp_get_message_description 
  1467. go
  1468. CREATE PROCEDURE sp_get_message_description 
  1469.   @error INT
  1470. AS
  1471. BEGIN
  1472.   IF EXISTS (SELECT * FROM master.dbo.sysmessages WHERE (error = @error) AND (msglangid = (SELECT msglangid FROM master.dbo.syslanguages WHERE (langid = @@langid)))) 
  1473.     SELECT description FROM master.dbo.sysmessages WHERE (error = @error) AND (msglangid = (SELECT msglangid FROM master.dbo.syslanguages WHERE (langid = @@langid)))
  1474.   ELSE 
  1475.     SELECT description FROM master.dbo.sysmessages WHERE (error = @error) AND (msglangid = 1033)
  1476. END
  1477. go
  1478.  
  1479. /**************************************************************/
  1480. /* SP_SQLAGENT_GET_PERF_COUNTERS                              */
  1481. /**************************************************************/
  1482.  
  1483. PRINT ''
  1484. PRINT 'Creating procedure sp_sqlagent_get_perf_counters...'
  1485. go
  1486. IF (EXISTS (SELECT *
  1487.             FROM msdb.dbo.sysobjects
  1488.             WHERE (name = N'sp_sqlagent_get_perf_counters')
  1489.               AND (type = 'P')))
  1490.   DROP PROCEDURE sp_sqlagent_get_perf_counters
  1491. go
  1492. CREATE PROCEDURE sp_sqlagent_get_perf_counters
  1493.   @all_counters BIT = 0
  1494. AS
  1495. BEGIN
  1496.   SET NOCOUNT ON
  1497.  
  1498.   CREATE TABLE #temp
  1499.   (
  1500.   performance_condition NVARCHAR(1024) NOT NULL
  1501.   )
  1502.  
  1503.   INSERT INTO #temp VALUES (N'dummy')
  1504.  
  1505.   IF (@all_counters = 0)
  1506.   BEGIN
  1507.     INSERT INTO #temp
  1508.     SELECT DISTINCT SUBSTRING(performance_condition, 1, CHARINDEX('|', performance_condition, PATINDEX('%[_|_]%', performance_condition) + 1) - 1)
  1509.     FROM msdb.dbo.sysalerts
  1510.     WHERE (performance_condition IS NOT NULL)
  1511.       AND (enabled = 1)
  1512.   END
  1513.  
  1514.   SELECT 'object_name' = RTRIM(SUBSTRING(spi1.object_name, 1, 50)), 
  1515.          'counter_name' = RTRIM(SUBSTRING(spi1.counter_name, 1, 50)), 
  1516.          'instance_name' = CASE spi1.instance_name 
  1517.                              WHEN N'' THEN NULL 
  1518.                              ELSE RTRIM(spi1.instance_name)
  1519.                            END, 
  1520.          'value' = CASE spi1.cntr_type
  1521.                      WHEN 537003008 -- A ratio
  1522.                        THEN CONVERT(FLOAT, spi1.cntr_value) / (SELECT CASE spi2.cntr_value WHEN 0 THEN 1 ELSE spi2.cntr_value END
  1523.                                                                FROM master.dbo.sysperfinfo spi2
  1524.                                                                WHERE (spi1.counter_name + ' ' = SUBSTRING(spi2.counter_name, 1, PATINDEX('% Base%', spi2.counter_name)))
  1525.                                                                  AND (spi1.instance_name = spi2.instance_name)
  1526.                                                                  AND (spi2.cntr_type = 1073939459))
  1527.                      ELSE spi1.cntr_value
  1528.                    END
  1529.   FROM master.dbo.sysperfinfo spi1, 
  1530.        #temp tmp
  1531.   WHERE (spi1.cntr_type <> 1073939459) -- Divisors
  1532.     AND ((@all_counters = 1) OR
  1533.          (tmp.performance_condition = RTRIM(spi1.object_name) + '|' + RTRIM(spi1.counter_name)))
  1534. END
  1535. go
  1536.  
  1537. /**************************************************************/
  1538. /* SP_SEM_GET_PERF_COUNTER_HELP                               */
  1539. /**************************************************************/
  1540.  
  1541. PRINT ''
  1542. PRINT 'Creating procedure sp_sem_get_perf_counter_help...'
  1543. go
  1544. IF (EXISTS (SELECT *
  1545.             FROM msdb.dbo.sysobjects
  1546.             WHERE (name = 'sp_sem_get_perf_counter_help')
  1547.               AND (type = 'P')))
  1548.   DROP PROCEDURE sp_sem_get_perf_counter_help
  1549. go
  1550. CREATE PROCEDURE sp_sem_get_perf_counter_help
  1551.   @counter_name VARCHAR(200),
  1552.   @nt_langid    NVARCHAR(10) = N'009'
  1553. AS
  1554. BEGIN
  1555.   DECLARE @help_id    INT
  1556.   DECLARE @row_id     INT
  1557.   DECLARE @counter_id INT
  1558.   DECLARE @reg_key    NVARCHAR(200)
  1559.  
  1560.   SET NOCOUNT ON
  1561.  
  1562.   SELECT @reg_key = N'SOFTWARE\Microsoft\Windows NT\CurrentVersion\Perflib\' + @nt_langid
  1563.  
  1564.   -- Check that the desired key exists
  1565.   CREATE TABLE #result(key_exists INT)
  1566.   INSERT INTO #result
  1567.   EXECUTE master.dbo.xp_regread N'HKEY_LOCAL_MACHINE',
  1568.                                 @reg_key
  1569.   IF (NOT EXISTS (SELECT *
  1570.                   FROM #result
  1571.                   WHERE key_exists = 1))
  1572.     RETURN(1) -- Failure
  1573.  
  1574.   CREATE TABLE #help
  1575.   (
  1576.   item NVARCHAR(30),
  1577.   help NVARCHAR(1024)
  1578.   )
  1579.  
  1580.   CREATE TABLE #counters
  1581.   (
  1582.   item    NVARCHAR(30),
  1583.   counter NVARCHAR(1024)
  1584.   )
  1585.  
  1586.   -- Populate temporary tables
  1587.   INSERT INTO #help
  1588.   EXECUTE master.dbo.xp_regread N'HKEY_LOCAL_MACHINE',
  1589.                                 @reg_key,
  1590.                                 N'Help'
  1591.   INSERT INTO #counters
  1592.   EXECUTE master.dbo.xp_regread N'HKEY_LOCAL_MACHINE',
  1593.                                 @reg_key,
  1594.                                 N'Counter'
  1595.  
  1596.   -- Find the row id of the counter
  1597.   SELECT @row_id = CONVERT(INT, SUBSTRING(item, PATINDEX('%#%', item) + 1, 5))
  1598.   FROM #counters
  1599.   WHERE (counter = @counter_name)
  1600.  
  1601.   IF (@row_id IS NOT NULL) AND (@row_id > 0)
  1602.   BEGIN
  1603.     -- From the row id of the counter, backup to get the counter id
  1604.     SELECT @row_id = @row_id - 1
  1605.  
  1606.     SELECT @counter_id = CONVERT(INT, counter) 
  1607.     FROM #counters
  1608.     WHERE (item LIKE '%#' + CONVERT(VARCHAR, @row_id))
  1609.  
  1610.     IF (@counter_id IS NOT NULL) AND (@counter_id > 0)
  1611.     BEGIN
  1612.       SELECT @help_id = @counter_id + 1
  1613.  
  1614.       -- Find the row id of the help
  1615.       SELECT @row_id = CONVERT(INT, SUBSTRING(item, PATINDEX('%#%', item) + 1, 5))
  1616.       FROM #help 
  1617.       WHERE (help = @help_id)
  1618.  
  1619.       IF (@row_id IS NOT NULL) AND (@row_id > 0)
  1620.       BEGIN
  1621.         -- Finally, lookup the help by row id
  1622.         SELECT @row_id = @row_id + 1
  1623.  
  1624.         SELECT help 
  1625.         FROM #help
  1626.         WHERE (item LIKE '%#' + CONVERT(VARCHAR, @row_id))
  1627.  
  1628.         RETURN(0) -- Success
  1629.       END
  1630.     END
  1631.   END
  1632. END
  1633. go
  1634.  
  1635. /**************************************************************/
  1636. /* SP_SQLAGENT_NOTIFY                                         */
  1637. /*                                                            */
  1638. /* NOTE: We define this procedure here instead of in the      */
  1639. /*      'Support procedures' section because of the many      */
  1640. /*       other procedures that reference it.                  */
  1641. /**************************************************************/
  1642.  
  1643. PRINT ''
  1644. PRINT 'Creating procedure sp_sqlagent_notify...'
  1645. go
  1646.  
  1647. IF (EXISTS (SELECT *
  1648.             FROM msdb.dbo.sysobjects
  1649.             WHERE (name = N'sp_sqlagent_notify')
  1650.               AND (type = 'P')))
  1651.   DROP PROCEDURE sp_sqlagent_notify
  1652. go
  1653. CREATE PROCEDURE sp_sqlagent_notify
  1654.   @op_type     NCHAR(1),                -- One of: J (Job action [refresh or start/stop]),
  1655.                                         --         S (Schedule action [refresh only])
  1656.                                         --         A (Alert action [refresh only]),
  1657.                                         --         G (Re-cache all registry settings),
  1658.                                         --         D (Dump job [or job schedule] cache to errorlog)
  1659.                                         --         P (Force an immediate poll of the MSX)
  1660.   @job_id      UNIQUEIDENTIFIER = NULL, -- JobID (for OpTypes 'J', 'S' and 'D')
  1661.   @schedule_id INT              = NULL, -- ScheduleID (for OpType 'S')
  1662.   @alert_id    INT              = NULL, -- AlertID (for OpType 'A')
  1663.   @action_type NCHAR(1)         = NULL, -- For 'J' one of: R (Run - no service check),
  1664.                                         --                 S (Start - with service check),
  1665.                                         --                 I (Insert),
  1666.                                         --                 U (Update),
  1667.                                         --                 D (Delete),
  1668.                                         --                 C (Stop [Cancel])
  1669.                                         -- For 'S' or 'A' one of: I (Insert),
  1670.                                         --                        U (Update),
  1671.                                         --                        D (Delete)
  1672.   @error_flag  INT              = 1     -- Set to 0 to suppress the error from xp_sqlagent_notify if SQLServer agent is not running
  1673. AS
  1674. BEGIN
  1675.   DECLARE @retval         INT
  1676.   DECLARE @id_as_char     VARCHAR(10)
  1677.   DECLARE @job_id_as_char VARCHAR(36)
  1678.   DECLARE @nt_user_name   NVARCHAR(100)
  1679.  
  1680.   SET NOCOUNT ON
  1681.  
  1682.   SELECT @retval = 0 -- Success
  1683.  
  1684.   -- Make sure that we're dealing only with uppercase characters
  1685.   SELECT @op_type     = UPPER(@op_type)
  1686.   SELECT @action_type = UPPER(@action_type)
  1687.  
  1688.   -- Verify operation code
  1689.   IF (CHARINDEX(@op_type, N'JSAGDP') = 0)
  1690.   BEGIN
  1691.     RAISERROR(14266, -1, -1, '@op_type', 'J, S, A, G, D, P')
  1692.     RETURN(1) -- Failure
  1693.   END
  1694.  
  1695.   -- Check the job id for those who use it
  1696.   IF (CHARINDEX(@op_type, N'JSD') <> 0)
  1697.   BEGIN
  1698.     IF (NOT ((@op_type = N'D') AND (@job_id IS NULL))) -- For 'D', job_id is optional
  1699.     BEGIN
  1700.       IF ((@job_id IS NULL) OR
  1701.           ((@action_type <> N'D') AND NOT EXISTS (SELECT *
  1702.                                                   FROM msdb.dbo.sysjobs_view
  1703.                                                   WHERE (job_id = @job_id))))
  1704.       BEGIN
  1705.         SELECT @job_id_as_char = CONVERT(VARCHAR(36), @job_id)
  1706.         RAISERROR(14262, -1, -1, '@job_id', @job_id_as_char)
  1707.         RETURN(1) -- Failure
  1708.       END
  1709.     END
  1710.   END
  1711.  
  1712.   -- Verify 'job' action parameters
  1713.   IF (@op_type = N'J')
  1714.   BEGIN
  1715.     SELECT @alert_id = 0
  1716.     IF (@schedule_id IS NULL) SELECT @schedule_id = 0
  1717.  
  1718.     -- The schedule_id (if specified) is the start step
  1719.     IF ((CHARINDEX(@action_type, N'RS') <> 0) AND (@schedule_id <> 0))
  1720.     BEGIN
  1721.       IF (NOT EXISTS (SELECT *
  1722.                       FROM msdb.dbo.sysjobsteps
  1723.                       WHERE (job_id = @job_id)
  1724.                         AND (step_id = @schedule_id)))
  1725.       BEGIN
  1726.         SELECT @id_as_char = ISNULL(CONVERT(VARCHAR, @schedule_id), '(null)')
  1727.         RAISERROR(14262, -1, -1, '@schedule_id', @id_as_char)
  1728.         RETURN(1) -- Failure
  1729.       END
  1730.     END
  1731.     ELSE
  1732.       SELECT @schedule_id = 0
  1733.  
  1734.     IF (CHARINDEX(@action_type, N'RSIUDC') = 0)
  1735.     BEGIN
  1736.       RAISERROR(14266, -1, -1, '@action_type', 'R, S, I, U, D, C')
  1737.       RETURN(1) -- Failure
  1738.     END
  1739.   END
  1740.  
  1741.   -- Verify 'schedule' action parameters
  1742.   IF (@op_type = N'S')
  1743.   BEGIN
  1744.     SELECT @alert_id = 0
  1745.  
  1746.     IF (CHARINDEX(@action_type, N'IUD') = 0)
  1747.     BEGIN
  1748.       RAISERROR(14266, -1, -1, '@action_type', 'I, U, D')
  1749.       RETURN(1) -- Failure
  1750.     END
  1751.  
  1752.     IF ((@schedule_id IS NULL) OR
  1753.         ((@action_type <> N'D') AND NOT EXISTS (SELECT *
  1754.                                                 FROM msdb.dbo.sysjobschedules
  1755.                                                 WHERE (schedule_id = @schedule_id))))
  1756.     BEGIN
  1757.       SELECT @id_as_char = ISNULL(CONVERT(VARCHAR, @schedule_id), '(null)')
  1758.       RAISERROR(14262, -1, -1, '@schedule_id', @id_as_char)
  1759.       RETURN(1) -- Failure
  1760.     END
  1761.   END
  1762.  
  1763.   -- Verify 'alert' action parameters
  1764.   IF (@op_type = N'A')
  1765.   BEGIN
  1766.     SELECT @job_id = 0x00
  1767.     SELECT @schedule_id = 0
  1768.  
  1769.     IF (CHARINDEX(@action_type, N'IUD') = 0)
  1770.     BEGIN
  1771.       RAISERROR(14266, -1, -1, '@action_type', 'I, U, D')
  1772.       RETURN(1) -- Failure
  1773.     END
  1774.  
  1775.     IF ((@alert_id IS NULL) OR
  1776.         ((@action_type <> N'D') AND NOT EXISTS (SELECT *
  1777.                                                 FROM msdb.dbo.sysalerts
  1778.                                                 WHERE (id = @alert_id))))
  1779.     BEGIN
  1780.       SELECT @id_as_char = ISNULL(CONVERT(VARCHAR, @alert_id), '(null)')
  1781.       RAISERROR(14262, -1, -1, '@alert_id', @id_as_char)
  1782.       RETURN(1) -- Failure
  1783.     END
  1784.   END
  1785.  
  1786.   -- Verify 'registry', 'job dump' and 'force MSX poll' action parameters
  1787.   IF (CHARINDEX(@op_type, N'GDP') <> 0)
  1788.   BEGIN
  1789.     IF (@op_type <> N'D')
  1790.       SELECT @job_id = 0x00
  1791.     SELECT @alert_id = 0
  1792.     SELECT @schedule_id = 0
  1793.     SELECT @action_type = NULL
  1794.   END
  1795.  
  1796.   -- Parameters are valid, so now check execution permissions...
  1797.  
  1798.   -- For anything except a job (or schedule) action the caller must be SysAdmin, DBO, or DB_Owner
  1799.   IF (@op_type NOT IN (N'J', N'S'))
  1800.   BEGIN
  1801.     IF NOT ((ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) = 1) OR
  1802.             (ISNULL(IS_MEMBER(N'db_owner'), 0) = 1) OR
  1803.             (UPPER(USER_NAME()) = N'DBO'))
  1804.     BEGIN
  1805.       RAISERROR(14260, -1, -1)
  1806.       RETURN(1) -- Failure
  1807.     END
  1808.   END
  1809.  
  1810.   -- For a Job Action the caller must be SysAdmin, DBO, DB_Owner, or the job owner
  1811.   IF (@op_type = N'J')
  1812.   BEGIN
  1813.     IF NOT ((ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) = 1) OR
  1814.             (ISNULL(IS_MEMBER(N'db_owner'), 0) = 1) OR
  1815.             (UPPER(USER_NAME()) = N'DBO') OR
  1816.             (EXISTS (SELECT *
  1817.                      FROM msdb.dbo.sysjobs_view
  1818.                      WHERE (job_id = @job_id))))
  1819.     BEGIN
  1820.       RAISERROR(14252, -1, -1)
  1821.       RETURN(1) -- Failure
  1822.     END
  1823.   END
  1824.  
  1825.   -- Ok, let's do it...
  1826.   SELECT @nt_user_name = ISNULL(NT_CLIENT(), ISNULL(SUSER_SNAME(), FORMATMESSAGE(14205)))
  1827.   EXECUTE @retval = master.dbo.xp_sqlagent_notify @op_type, @job_id, @schedule_id, @alert_id, @action_type, @nt_user_name, @error_flag, @@trancount
  1828.  
  1829.   RETURN(@retval)
  1830. END
  1831. go
  1832.  
  1833. /**************************************************************/
  1834. /* SP_IS_SQLAGENT_STARTING                                    */
  1835. /**************************************************************/
  1836.  
  1837. PRINT ''
  1838. PRINT 'Creating procedure sp_is_sqlagent_starting...'
  1839. go
  1840. IF (EXISTS (SELECT *
  1841.             FROM msdb.dbo.sysobjects
  1842.             WHERE (name = N'sp_is_sqlagent_starting')
  1843.               AND (type = 'P')))
  1844.   DROP PROCEDURE sp_is_sqlagent_starting
  1845. go
  1846. CREATE PROCEDURE sp_is_sqlagent_starting
  1847. AS
  1848. BEGIN
  1849.   DECLARE @retval INT
  1850.  
  1851.   SELECT @retval = 0
  1852.   EXECUTE master.dbo.xp_sqlagent_is_starting @retval OUTPUT
  1853.   IF (@retval = 1)
  1854.     RAISERROR(14258, -1, -1)
  1855.  
  1856.   RETURN(@retval)
  1857. END
  1858. go
  1859.  
  1860. /**************************************************************/
  1861. /* SP_VERIFY_JOB_IDENTIFIERS                                  */
  1862. /*                                                            */
  1863. /* NOTE: We define this procedure here instead of in the      */
  1864. /*      'Support procedures' section because of the many      */
  1865. /*       other procedures that reference it.                  */
  1866. /**************************************************************/
  1867.  
  1868. PRINT ''
  1869. PRINT 'Creating procedure sp_verify_job_identifiers...'
  1870. go
  1871. IF (EXISTS (SELECT *
  1872.             FROM msdb.dbo.sysobjects
  1873.             WHERE (name = N'sp_verify_job_identifiers')
  1874.               AND (type = 'P')))
  1875.   DROP PROCEDURE sp_verify_job_identifiers
  1876. go
  1877. CREATE PROCEDURE sp_verify_job_identifiers
  1878.   @name_of_name_parameter  VARCHAR(60),             -- Eg. '@job_name'
  1879.   @name_of_id_parameter    VARCHAR(60),             -- Eg. '@job_id'
  1880.   @job_name                sysname          OUTPUT, -- Eg. 'My Job'
  1881.   @job_id                  UNIQUEIDENTIFIER OUTPUT,
  1882.   @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)
  1883. AS
  1884. BEGIN
  1885.   DECLARE @retval         INT
  1886.   DECLARE @job_id_as_char VARCHAR(36)
  1887.  
  1888.   SET NOCOUNT ON
  1889.  
  1890.   -- Remove any leading/trailing spaces from parameters
  1891.   SELECT @name_of_name_parameter = LTRIM(RTRIM(@name_of_name_parameter))
  1892.   SELECT @name_of_id_parameter   = LTRIM(RTRIM(@name_of_id_parameter))
  1893.   SELECT @job_name               = LTRIM(RTRIM(@job_name))
  1894.  
  1895.   IF (@job_name = N'') SELECT @job_name = NULL
  1896.  
  1897.   IF ((@job_name IS NULL)     AND (@job_id IS NULL)) OR
  1898.      ((@job_name IS NOT NULL) AND (@job_id IS NOT NULL))
  1899.   BEGIN
  1900.     RAISERROR(14294, -1, -1, @name_of_id_parameter, @name_of_name_parameter)
  1901.     RETURN(1) -- Failure
  1902.   END
  1903.  
  1904.   -- Check job id
  1905.   IF (@job_id IS NOT NULL)
  1906.   BEGIN
  1907.     SELECT @job_name = name,
  1908.            @job_id = job_id
  1909.     FROM msdb.dbo.sysjobs_view
  1910.     WHERE (job_id = @job_id)
  1911.     IF (@job_name IS NULL)
  1912.     BEGIN
  1913.       SELECT @job_id_as_char = CONVERT(VARCHAR(36), @job_id)
  1914.       RAISERROR(14262, -1, -1, '@job_id', @job_id_as_char)
  1915.       RETURN(1) -- Failure
  1916.     END
  1917.   END
  1918.   ELSE
  1919.   -- Check job name
  1920.   IF (@job_name IS NOT NULL)
  1921.   BEGIN
  1922.     -- Check if the job name is ambiguous
  1923.     IF ((SELECT COUNT(*)
  1924.          FROM msdb.dbo.sysjobs_view
  1925.          WHERE (name = @job_name)) > 1)
  1926.     BEGIN
  1927.       RAISERROR(14293, -1, -1, @job_name, @name_of_id_parameter, @name_of_name_parameter)
  1928.       RETURN(1) -- Failure
  1929.     END
  1930.  
  1931.     -- The name is not ambiguous, so get the corresponding job_id (if the job exists)
  1932.     SELECT @job_id = job_id
  1933.     FROM msdb.dbo.sysjobs_view
  1934.     WHERE (name = @job_name)
  1935.     IF (@job_id IS NULL)
  1936.     BEGIN
  1937.       RAISERROR(14262, -1, -1, '@job_name', @job_name)
  1938.       RETURN(1) -- Failure
  1939.     END
  1940.   END
  1941.  
  1942.   IF (@sqlagent_starting_test = 'TEST')
  1943.   BEGIN
  1944.     -- Finally, check if SQLServerAgent is in the process of starting and if so prevent the
  1945.     -- calling SP from running
  1946.     EXECUTE @retval = msdb.dbo.sp_is_sqlagent_starting
  1947.     IF (@retval <> 0)
  1948.       RETURN(1) -- Failure
  1949.   END
  1950.  
  1951.   RETURN(0) -- Success
  1952. END
  1953. go
  1954.  
  1955. /**************************************************************/
  1956. /* SP_VERIFY_JOBPROC_CALLER                                   */
  1957. /*                                                            */
  1958. /* NOTE: We define this procedure here instead of in the      */
  1959. /*      'Support procedures' section because of the many      */
  1960. /*       other procedures that reference it.                  */
  1961. /**************************************************************/
  1962.  
  1963. PRINT ''
  1964. PRINT 'Creating procedure sp_verify_jobproc_caller...'
  1965. go
  1966. IF (EXISTS (SELECT *
  1967.             FROM msdb.dbo.sysobjects
  1968.             WHERE (name = N'sp_verify_jobproc_caller')
  1969.               AND (type = 'P')))
  1970.   DROP PROCEDURE sp_verify_jobproc_caller
  1971. go
  1972. CREATE PROCEDURE sp_verify_jobproc_caller
  1973.   @job_id       UNIQUEIDENTIFIER,
  1974.   @program_name sysname
  1975. AS
  1976. BEGIN
  1977.   SET NOCOUNT ON
  1978.  
  1979.   -- Remove any leading/trailing spaces from parameters
  1980.   SELECT @program_name = LTRIM(RTRIM(@program_name))
  1981.  
  1982.   IF (EXISTS (SELECT *
  1983.               FROM msdb.dbo.sysjobs_view
  1984.               WHERE (job_id = @job_id)
  1985.                 AND (UPPER(originating_server) <> N'(LOCAL)'))) AND
  1986.      (PROGRAM_NAME() NOT LIKE @program_name)
  1987.   BEGIN
  1988.     RAISERROR(14274, -1, -1)
  1989.     RETURN(1) -- Failure
  1990.   END
  1991.  
  1992.   RETURN(0)
  1993. END
  1994. go
  1995.  
  1996. /**************************************************************/
  1997. /* SP_DOWNLOADED_ROW_LIMITER                                  */
  1998. /**************************************************************/
  1999.  
  2000. PRINT ''
  2001. PRINT 'Creating procedure sp_downloaded_row_limiter...'
  2002. go
  2003. IF (EXISTS (SELECT *
  2004.             FROM msdb.dbo.sysobjects
  2005.             WHERE (name = N'sp_downloaded_row_limiter')
  2006.               AND (type = 'P')))
  2007.   DROP PROCEDURE dbo.sp_downloaded_row_limiter
  2008. go
  2009. CREATE PROCEDURE sp_downloaded_row_limiter
  2010.   @server_name NVARCHAR(30) -- Target server name
  2011. AS
  2012. BEGIN
  2013.   -- This trigger controls how many downloaded (status = 1) sysdownloadlist rows exist
  2014.   -- for any given server.  It does NOT control the absolute number of rows in the table.
  2015.  
  2016.   DECLARE @current_rows_per_server INT
  2017.   DECLARE @max_rows_per_server     INT -- This value comes from the resgistry (DownloadedMaxRows)
  2018.   DECLARE @rows_to_delete          INT
  2019.   DECLARE @rows_to_delete_as_char  VARCHAR(10)
  2020.  
  2021.   SET NOCOUNT ON
  2022.  
  2023.   -- Remove any leading/trailing spaces from parameters
  2024.   SELECT @server_name = LTRIM(RTRIM(@server_name))
  2025.  
  2026.   -- Check the server name (if it's bad we fail silently)
  2027.   IF (@server_name IS NULL) OR
  2028.      (NOT EXISTS (SELECT *
  2029.                   FROM msdb.dbo.sysdownloadlist
  2030.                   WHERE (target_server = @server_name)))
  2031.     RETURN(1) -- Failure
  2032.  
  2033.   SELECT @max_rows_per_server = 0
  2034.  
  2035.   -- Get the max-rows-per-server from the registry
  2036.   EXECUTE master.dbo.xp_regread N'HKEY_LOCAL_MACHINE',
  2037.                                 N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
  2038.                                 N'DownloadedMaxRows',
  2039.                                  @max_rows_per_server OUTPUT,
  2040.                                 N'no_output'
  2041.  
  2042.   -- Check if we are limiting sysdownloadlist rows
  2043.   IF (ISNULL(@max_rows_per_server, -1) = -1)
  2044.     RETURN
  2045.  
  2046.   -- Check that max_rows_per_server is >= 0
  2047.   IF (@max_rows_per_server < -1)
  2048.   BEGIN
  2049.     -- It isn't, so default to 100 rows
  2050.     SELECT @max_rows_per_server = 100
  2051.     EXECUTE master.dbo.xp_regwrite N'HKEY_LOCAL_MACHINE',
  2052.                                    N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
  2053.                                    N'DownloadedMaxRows',
  2054.                                    N'REG_DWORD',
  2055.                                     @max_rows_per_server
  2056.   END
  2057.  
  2058.   -- Get the number of downloaded rows in sysdownloadlist for the target server in question
  2059.   -- NOTE: Determining this [quickly] requires a [non-clustered] index on target_server
  2060.   SELECT @current_rows_per_server = COUNT(*)
  2061.   FROM msdb.dbo.sysdownloadlist
  2062.   WHERE (target_server = @server_name)
  2063.     AND (status = 1)
  2064.  
  2065.   -- Delete the oldest downloaded row(s) for the target server in question if the new row has
  2066.   -- pushed us over the per-server row limit
  2067.   SELECT @rows_to_delete = @current_rows_per_server - @max_rows_per_server
  2068.   SELECT @rows_to_delete_as_char = CONVERT(VARCHAR, @rows_to_delete)
  2069.  
  2070.   IF (@rows_to_delete > 0)
  2071.   BEGIN
  2072.     EXECUTE ('DECLARE @new_oldest_id INT
  2073.               SET NOCOUNT ON
  2074.               SET ROWCOUNT ' + @rows_to_delete_as_char +
  2075.              'SELECT @new_oldest_id = instance_id
  2076.               FROM msdb.dbo.sysdownloadlist
  2077.               WHERE (target_server = N''' + @server_name + ''')' +
  2078.              '  AND (status = 1)
  2079.               ORDER BY instance_id
  2080.               SET ROWCOUNT 0
  2081.               DELETE FROM msdb.dbo.sysdownloadlist
  2082.               WHERE (target_server = N''' + @server_name + ''')' +
  2083.              '  AND (instance_id <= @new_oldest_id)
  2084.                 AND (status = 1)')
  2085.   END
  2086. END
  2087. go
  2088.  
  2089. /**************************************************************/
  2090. /* SP_POST_MSX_OPERATION                                      */
  2091. /*                                                            */
  2092. /* NOTE: We define this procedure here instead of in the      */
  2093. /*      'Support procedures' section because of the many      */
  2094. /*       other procedures that reference it.                  */
  2095. /**************************************************************/
  2096.  
  2097. PRINT ''
  2098. PRINT 'Creating procedure sp_post_msx_operation...'
  2099. go
  2100. IF (EXISTS (SELECT *
  2101.             FROM msdb.dbo.sysobjects
  2102.             WHERE (name = 'sp_post_msx_operation')
  2103.               AND (type = 'P')))
  2104.   DROP PROCEDURE sp_post_msx_operation
  2105. go
  2106. CREATE PROCEDURE sp_post_msx_operation
  2107.   @operation              VARCHAR(64),
  2108.   @object_type            VARCHAR(64)      = 'JOB',
  2109.   @job_id                 UNIQUEIDENTIFIER = NULL, -- NOTE: 0x00 means 'ALL'
  2110.   @specific_target_server NVARCHAR(30)     = NULL,
  2111.   @value                  INT              = NULL  -- For polling interval value
  2112. AS
  2113. BEGIN
  2114.   DECLARE @operation_code            INT
  2115.   DECLARE @specific_target_server_id INT
  2116.   DECLARE @instructions_posted       INT
  2117.   DECLARE @job_id_as_char            VARCHAR(36)
  2118.   DECLARE @msx_time_zone_adjustment  INT
  2119.   DECLARE @local_machine_name        NVARCHAR(30)
  2120.   DECLARE @retval                    INT
  2121.  
  2122.   SET NOCOUNT ON
  2123.  
  2124.   -- Remove any leading/trailing spaces from parameters
  2125.   SELECT @operation              = LTRIM(RTRIM(@operation))
  2126.   SELECT @object_type            = LTRIM(RTRIM(@object_type))
  2127.   SELECT @specific_target_server = LTRIM(RTRIM(@specific_target_server))
  2128.  
  2129.   -- Turn [nullable] empty string parameters into NULLs
  2130.   IF (@specific_target_server = N'') SELECT @specific_target_server = NULL
  2131.  
  2132.   -- Only a sysadmin can do this, but fail silently for a non-sysadmin
  2133.   IF (ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) <> 1)
  2134.     RETURN(0) -- Success (or more accurately a no-op)
  2135.  
  2136.   -- Check operation
  2137.   SELECT @operation = UPPER(@operation)
  2138.   SELECT @operation_code = CASE @operation
  2139.                              WHEN 'INSERT'    THEN 1
  2140.                              WHEN 'UPDATE'    THEN 2
  2141.                              WHEN 'DELETE'    THEN 3
  2142.                              WHEN 'START'     THEN 4
  2143.                              WHEN 'STOP'      THEN 5
  2144.                              WHEN 'RE-ENLIST' THEN 6
  2145.                              WHEN 'DEFECT'    THEN 7
  2146.                              WHEN 'SYNC-TIME' THEN 8
  2147.                              WHEN 'SET-POLL'  THEN 9
  2148.                              ELSE 0
  2149.                            END
  2150.   IF (@operation_code = 0)
  2151.   BEGIN
  2152.     RAISERROR(14266, -1, -1, '@operation_code', 'INSERT, UPDATE, DELETE, START, STOP, RE-ENLIST, DEFECT, SYNC-TIME, SET-POLL')
  2153.     RETURN(1) -- Failure
  2154.   END
  2155.  
  2156.   -- Check object type (in 7.0 only 'JOB' or 'SERVER' are valid)
  2157.   IF ((@object_type <> 'JOB') AND (@object_type <> 'SERVER'))
  2158.   BEGIN
  2159.     RAISERROR(14266, -1, -1, '@object_type', 'JOB, SERVER')
  2160.     RETURN(1) -- Failure
  2161.   END
  2162.  
  2163.   -- Check that for a object type of JOB a job_id has been supplied
  2164.   IF ((@object_type = 'JOB') AND (@job_id IS NULL))
  2165.   BEGIN
  2166.     RAISERROR(14233, -1, -1)
  2167.     RETURN(1) -- Failure
  2168.   END
  2169.  
  2170.   -- Check polling interval value
  2171.   IF (@operation_code = 9) AND ((ISNULL(@value, 0) < 10) OR (ISNULL(@value, 0) > 28800))
  2172.   BEGIN
  2173.     RAISERROR(14266, -1, -1, '@value', '10..28800')
  2174.     RETURN(1) -- Failure
  2175.   END
  2176.  
  2177.   -- Check specific target server
  2178.   IF (@specific_target_server IS NOT NULL)
  2179.   BEGIN
  2180.     -- Check if the local server is being targeted
  2181.     IF (UPPER(@specific_target_server) = N'(LOCAL)')
  2182.     BEGIN
  2183.       RETURN(0)
  2184.     END
  2185.     ELSE
  2186.     BEGIN
  2187.       SELECT @specific_target_server_id = server_id
  2188.       FROM msdb.dbo.systargetservers
  2189.       WHERE (server_name = @specific_target_server)
  2190.       IF (@specific_target_server_id IS NULL)
  2191.       BEGIN
  2192.         RAISERROR(14262, -1, -1, '@specific_target_server', @specific_target_server)
  2193.         RETURN(1) -- Failure
  2194.       END
  2195.     END
  2196.   END
  2197.  
  2198.   -- Check that this server is an MSX server
  2199.   IF ((SELECT COUNT(*)
  2200.        FROM msdb.dbo.systargetservers) = 0)
  2201.   BEGIN
  2202.     RETURN(0)
  2203.   END
  2204.  
  2205.   -- Get local machine name
  2206.   EXECUTE @retval = master.dbo.xp_getnetname @local_machine_name OUTPUT
  2207.   IF (@retval <> 0) OR (@local_machine_name IS NULL)
  2208.   BEGIN
  2209.     RAISERROR(14225, -1, -1)
  2210.     RETURN(1)
  2211.   END
  2212.  
  2213.   CREATE TABLE #target_servers (server_name sysname NOT NULL)
  2214.  
  2215.   -- Optimization: Simply update the date-posted if the operation has already been posted (but
  2216.   -- not yet downloaded) and the target server is not currently polling...
  2217.   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
  2218.      ((@object_type = 'SERVER') AND (@operation_code IN (6, 7))) -- RE-ENLIST or DEFECT operations
  2219.   BEGIN
  2220.     -- Populate the list of target servers to post to
  2221.     IF (@specific_target_server IS NOT NULL)
  2222.       INSERT INTO #target_servers VALUES (@specific_target_server)
  2223.     ELSE
  2224.     BEGIN
  2225.       IF (@object_type = 'SERVER')
  2226.         INSERT INTO #target_servers
  2227.         SELECT server_name 
  2228.         FROM msdb.dbo.systargetservers
  2229.  
  2230.       IF (@object_type = 'JOB')
  2231.         INSERT INTO #target_servers
  2232.         SELECT sts.server_name
  2233.         FROM msdb.dbo.sysjobs_view     sjv,
  2234.              msdb.dbo.sysjobservers    sjs,
  2235.              msdb.dbo.systargetservers sts
  2236.         WHERE (sjv.job_id = @job_id)
  2237.           AND (sjv.job_id = sjs.job_id)
  2238.           AND (sjs.server_id = sts.server_id)
  2239.           AND (sjs.server_id <> 0)
  2240.     END 
  2241.     
  2242.     IF (EXISTS (SELECT * 
  2243.                 FROM #target_servers))
  2244.     BEGIN
  2245.       DECLARE @target_server sysname
  2246.       DECLARE @optimized     BIT
  2247.  
  2248.       SELECT @optimized = 1
  2249.  
  2250.       DECLARE targets_to_post_to CURSOR LOCAL
  2251.       FOR
  2252.       SELECT server_name 
  2253.       FROM #target_servers
  2254.  
  2255.       OPEN targets_to_post_to
  2256.       FETCH NEXT FROM targets_to_post_to INTO @target_server
  2257.  
  2258.       -- Optimizing is an all-or-nothing thing, so we do the updates inside a transaction so
  2259.       -- that we can rollback if necessary
  2260.       BEGIN TRANSACTION
  2261.       SAVE TRANSACTION start
  2262.       WHILE (@@fetch_status = 0)
  2263.       BEGIN
  2264.         IF (EXISTS (SELECT * 
  2265.                     FROM msdb.dbo.sysdownloadlist
  2266.                     WHERE (target_server = @target_server)
  2267.                       AND (operation_code = @operation_code)
  2268.                       AND (object_id = ISNULL(@job_id, CONVERT(UNIQUEIDENTIFIER, 0x00)))
  2269.                       AND (status = 0))) AND
  2270.            (NOT EXISTS (SELECT * 
  2271.                         FROM master.dbo.sysprocesses 
  2272.                         WHERE (loginame = @target_server + N'_msx_probe')))
  2273.         BEGIN
  2274.           UPDATE msdb.dbo.sysdownloadlist
  2275.           SET date_posted = GETDATE()
  2276.           WHERE (target_server = @target_server)
  2277.             AND (operation_code = @operation_code)
  2278.             AND (object_id = ISNULL(@job_id, CONVERT(UNIQUEIDENTIFIER, 0x00)))
  2279.             AND (status = 0)
  2280.         END
  2281.         ELSE
  2282.         BEGIN
  2283.           SELECT @optimized = 0
  2284.           BREAK          
  2285.         END
  2286.  
  2287.         FETCH NEXT FROM targets_to_post_to INTO @target_server
  2288.       END
  2289.       DEALLOCATE targets_to_post_to
  2290.  
  2291.       IF (@optimized = 1) 
  2292.       BEGIN
  2293.         COMMIT TRANSACTION
  2294.         SELECT @instructions_posted = 0
  2295.         GOTO DoReport
  2296.       END
  2297.       ELSE
  2298.       BEGIN
  2299.         ROLLBACK TRANSACTION start
  2300.         COMMIT TRANSACTION
  2301.       END
  2302.     END
  2303.   END
  2304.  
  2305.   -- Job-specific processing...
  2306.   IF (@object_type = 'JOB')
  2307.   BEGIN
  2308.     -- Validate the job (if supplied)
  2309.     IF (@job_id <> CONVERT(UNIQUEIDENTIFIER, 0x00))
  2310.     BEGIN
  2311.       SELECT @job_id_as_char = CONVERT(VARCHAR(36), @job_id)
  2312.  
  2313.       -- Check if the job exists
  2314.       IF (NOT EXISTS (SELECT *
  2315.                       FROM msdb.dbo.sysjobs_view
  2316.                       WHERE (job_id = @job_id)))
  2317.       BEGIN
  2318.         RAISERROR(14262, -1, -1, '@job_id', @job_id_as_char)
  2319.         RETURN(1) -- Failure
  2320.       END
  2321.  
  2322.       -- If this is a local job then there's nothing for us to do
  2323.       IF (EXISTS (SELECT *
  2324.                   FROM msdb.dbo.sysjobservers
  2325.                   WHERE (job_id = @job_id)
  2326.                     AND (server_id = 0))) -- 0 means local server
  2327.       OR (NOT EXISTS (SELECT * 
  2328.                       FROM msdb.dbo.sysjobservers
  2329.                       WHERE (job_id = @job_id)))
  2330.       BEGIN
  2331.         RETURN(0)
  2332.       END
  2333.     END
  2334.  
  2335.     -- Generate the sysdownloadlist row(s)...
  2336.     IF (@operation_code = 1) OR  -- Insert
  2337.        (@operation_code = 2) OR  -- Update
  2338.        (@operation_code = 3) OR  -- Delete
  2339.        (@operation_code = 4) OR  -- Start
  2340.        (@operation_code = 5)     -- Stop
  2341.     BEGIN
  2342.       IF (@job_id = CONVERT(UNIQUEIDENTIFIER, 0x00)) -- IE. 'ALL'
  2343.       BEGIN
  2344.         -- All jobs
  2345.  
  2346.         -- Handle DELETE as a special case (rather than posting 1 instruction per job we just
  2347.         -- post a single instruction that means 'delete all jobs from the MSX')
  2348.         IF (@operation_code = 3)
  2349.         BEGIN
  2350.           INSERT INTO msdb.dbo.sysdownloadlist
  2351.                 (source_server,
  2352.                  operation_code,
  2353.                  object_type,
  2354.                  object_id,
  2355.                  target_server)
  2356.           SELECT @local_machine_name,
  2357.                  @operation_code,
  2358.                  1,                -- 1 means 'JOB'
  2359.                  CONVERT(UNIQUEIDENTIFIER, 0x00),
  2360.                  sts.server_name
  2361.           FROM systargetservers sts
  2362.           WHERE ((@specific_target_server_id IS NULL) OR (sts.server_id = @specific_target_server_id))
  2363.             AND ((SELECT COUNT(*) 
  2364.                   FROM msdb.dbo.sysjobservers
  2365.                   WHERE (server_id = sts.server_id)) > 0)
  2366.           SELECT @instructions_posted = @@rowcount
  2367.         END
  2368.         ELSE
  2369.         BEGIN
  2370.           INSERT INTO msdb.dbo.sysdownloadlist
  2371.                 (source_server,
  2372.                  operation_code,
  2373.                  object_type,
  2374.                  object_id,
  2375.                  target_server)
  2376.           SELECT @local_machine_name,
  2377.                  @operation_code,
  2378.                  1,                -- 1 means 'JOB'
  2379.                  sjv.job_id,
  2380.                  sts.server_name
  2381.           FROM sysjobs_view     sjv,
  2382.                sysjobservers    sjs,
  2383.                systargetservers sts
  2384.           WHERE (sjv.job_id = sjs.job_id)
  2385.             AND (sjs.server_id = sts.server_id)
  2386.             AND (sjs.server_id <> 0) -- We want to exclude local jobs
  2387.             AND ((@specific_target_server_id IS NULL) OR (sjs.server_id = @specific_target_server_id))
  2388.           SELECT @instructions_posted = @@rowcount
  2389.         END
  2390.       END
  2391.       ELSE
  2392.       BEGIN
  2393.         -- Specific job (ie. @job_id is not 0x00)
  2394.         INSERT INTO msdb.dbo.sysdownloadlist
  2395.               (source_server,
  2396.                operation_code,
  2397.                object_type,
  2398.                object_id,
  2399.                target_server,
  2400.                deleted_object_name)
  2401.         SELECT @local_machine_name,
  2402.                @operation_code,
  2403.                1,                -- 1 means 'JOB'
  2404.                sjv.job_id,
  2405.                sts.server_name,
  2406.                CASE @operation_code WHEN 3 -- Delete
  2407.                                       THEN sjv.name
  2408.                                       ELSE NULL
  2409.                                     END
  2410.         FROM sysjobs_view     sjv,
  2411.              sysjobservers    sjs,
  2412.              systargetservers sts
  2413.         WHERE (sjv.job_id = @job_id)
  2414.           AND (sjv.job_id = sjs.job_id)
  2415.           AND (sjs.server_id = sts.server_id)
  2416.           AND (sjs.server_id <> 0) -- We want to exclude local jobs
  2417.           AND ((@specific_target_server_id IS NULL) OR (sjs.server_id = @specific_target_server_id))
  2418.         SELECT @instructions_posted = @@rowcount
  2419.       END
  2420.     END
  2421.     ELSE
  2422.     BEGIN
  2423.       RAISERROR(14266, -1, -1, '@operation_code', 'INSERT, UPDATE, DELETE, START, STOP')
  2424.       RETURN(1) -- Failure
  2425.     END
  2426.   END
  2427.  
  2428.   -- Server-specific processing...
  2429.   IF (@object_type = 'SERVER')
  2430.   BEGIN
  2431.     -- Generate the sysdownloadlist row(s)...
  2432.     IF (@operation_code = 6) OR  -- ReEnlist
  2433.        (@operation_code = 7) OR  -- Defect
  2434.        (@operation_code = 8) OR  -- Synchronize time (with MSX)
  2435.        (@operation_code = 9)     -- Set MSX polling interval (in seconds)
  2436.     BEGIN
  2437.       IF (@operation_code = 8)
  2438.       BEGIN       
  2439.         EXECUTE master.dbo.xp_regread N'HKEY_LOCAL_MACHINE',
  2440.                                       N'SYSTEM\CurrentControlSet\Control\TimeZoneInformation',
  2441.                                       N'Bias',
  2442.                                        @msx_time_zone_adjustment OUTPUT,
  2443.                                       N'no_output'
  2444.         SELECT @msx_time_zone_adjustment = -ISNULL(@msx_time_zone_adjustment, 0)
  2445.       END
  2446.  
  2447.       INSERT INTO msdb.dbo.sysdownloadlist
  2448.             (source_server,
  2449.              operation_code,
  2450.              object_type,
  2451.              object_id,
  2452.              target_server)
  2453.       SELECT @local_machine_name,
  2454.              @operation_code,
  2455.              2,                  -- 2 means 'SERVER'
  2456.              CASE @operation_code
  2457.                WHEN 8 THEN CONVERT(UNIQUEIDENTIFIER, CONVERT(BINARY(16), -(@msx_time_zone_adjustment - sts.time_zone_adjustment)))
  2458.                WHEN 9 THEN CONVERT(UNIQUEIDENTIFIER, CONVERT(BINARY(16), @value))
  2459.                ELSE CONVERT(UNIQUEIDENTIFIER, 0x00)
  2460.              END,
  2461.              sts.server_name
  2462.       FROM systargetservers sts
  2463.       WHERE ((@specific_target_server_id IS NULL) OR (sts.server_id = @specific_target_server_id))
  2464.       SELECT @instructions_posted = @@rowcount
  2465.     END
  2466.     ELSE
  2467.     BEGIN
  2468.       RAISERROR(14266, -1, -1, '@operation_code', 'RE-ENLIST, DEFECT, SYNC-TIME, SET-POLL')
  2469.       RETURN(1) -- Failure
  2470.     END
  2471.   END
  2472.  
  2473. DoReport:
  2474.  
  2475.   -- Report number of rows inserted
  2476.   IF (@object_type = 'JOB') AND
  2477.      (@job_id = CONVERT(UNIQUEIDENTIFIER, 0x00)) AND
  2478.      (@instructions_posted = 0) AND
  2479.      (@specific_target_server_id IS NOT NULL)
  2480.     RAISERROR(14231, 0, 1, '@specific_target_server', @specific_target_server)
  2481.   ELSE
  2482.     RAISERROR(14230, 0, 1, @instructions_posted, @operation)
  2483.  
  2484.   -- Delete any [downloaded] instructions that are over the registry-defined limit
  2485.   IF (@specific_target_server IS NOT NULL)
  2486.     EXECUTE msdb.dbo.sp_downloaded_row_limiter @specific_target_server
  2487.  
  2488.   RETURN(0) -- 0 means success
  2489. END
  2490. go
  2491.  
  2492. /**************************************************************/
  2493. /* SP_DELETE_JOB_REFERENCES                                   */
  2494. /**************************************************************/
  2495.  
  2496. PRINT ''
  2497. PRINT 'Creating procedure sp_delete_job_references...'
  2498. go
  2499. IF (EXISTS (SELECT *
  2500.             FROM msdb.dbo.sysobjects
  2501.             WHERE (name = N'sp_delete_job_references')
  2502.               AND (type = 'P')))
  2503.   DROP PROCEDURE sp_delete_job_references
  2504. go
  2505. CREATE PROCEDURE sp_delete_job_references
  2506. AS
  2507. BEGIN
  2508.   DECLARE @deleted_job_id  UNIQUEIDENTIFIER
  2509.   DECLARE @task_id_as_char VARCHAR(10)
  2510.   DECLARE @job_is_cached   INT
  2511.   DECLARE @alert_name      sysname
  2512.  
  2513.   -- Keep SQLServerAgent's cache in-sync and cleanup any 'webtask' cross-references to the deleted job(s)
  2514.   -- NOTE: The caller must have created a table called #temp_jobs_to_delete of the format
  2515.   --       (job_id UNIQUEIDENTIFIER NOT NULL, job_is_cached INT NOT NULL).
  2516.  
  2517.   DECLARE sqlagent_notify CURSOR LOCAL
  2518.   FOR
  2519.   SELECT job_id, job_is_cached
  2520.   FROM #temp_jobs_to_delete
  2521.  
  2522.   OPEN sqlagent_notify
  2523.   FETCH NEXT FROM sqlagent_notify INTO @deleted_job_id, @job_is_cached
  2524.  
  2525.   WHILE (@@fetch_status = 0)
  2526.   BEGIN
  2527.     -- NOTE: We only notify SQLServerAgent if we know the job has been cached
  2528.     IF(@job_is_cached = 1)
  2529.       EXECUTE msdb.dbo.sp_sqlagent_notify @op_type     = N'J',
  2530.                                           @job_id      = @deleted_job_id,
  2531.                                           @action_type = N'D'
  2532.  
  2533.     IF (EXISTS (SELECT *
  2534.                 FROM master.dbo.sysobjects
  2535.                 WHERE (name = N'sp_cleanupwebtask')
  2536.                   AND (type = 'P')))
  2537.     BEGIN
  2538.       SELECT @task_id_as_char = CONVERT(VARCHAR(10), task_id)
  2539.       FROM msdb.dbo.systaskids
  2540.       WHERE (job_id = @deleted_job_id)
  2541.       IF (@task_id_as_char IS NOT NULL)
  2542.         EXECUTE ('master.dbo.sp_cleanupwebtask @taskid = ' + @task_id_as_char)
  2543.     END
  2544.  
  2545.     FETCH NEXT FROM sqlagent_notify INTO @deleted_job_id, @job_is_cached
  2546.   END
  2547.   DEALLOCATE sqlagent_notify
  2548.  
  2549.   -- Remove systaskid references (must do this AFTER sp_cleanupwebtask stuff)
  2550.   DELETE FROM msdb.dbo.systaskids
  2551.   WHERE job_id IN (SELECT job_id FROM #temp_jobs_to_delete)
  2552.  
  2553.   -- Remove sysdbmaintplan_jobs references
  2554.   DELETE FROM msdb.dbo.sysdbmaintplan_jobs
  2555.   WHERE job_id IN (SELECT job_id FROM #temp_jobs_to_delete)
  2556.  
  2557.   -- Finally, clean up any dangling references in sysalerts to the deleted job(s)
  2558.   DECLARE sysalerts_cleanup CURSOR LOCAL
  2559.   FOR
  2560.   SELECT name
  2561.   FROM msdb.dbo.sysalerts
  2562.   WHERE (job_id IN (SELECT job_id FROM #temp_jobs_to_delete))
  2563.  
  2564.   OPEN sysalerts_cleanup
  2565.   FETCH NEXT FROM sysalerts_cleanup INTO @alert_name
  2566.   WHILE (@@fetch_status = 0)
  2567.   BEGIN
  2568.     EXECUTE msdb.dbo.sp_update_alert @name   = @alert_name, 
  2569.                                      @job_id = 0x00
  2570.     FETCH NEXT FROM sysalerts_cleanup INTO @alert_name
  2571.   END
  2572.   DEALLOCATE sysalerts_cleanup
  2573. END
  2574. go
  2575.  
  2576. /**************************************************************/
  2577. /* SP_DELETE_ALL_MSX_JOBS                                     */
  2578. /*                                                            */
  2579. /* NOTE: This is a separate procedure because SQLServerAgent  */
  2580. /*       needs to call it, as does sp_msx_defect and          */
  2581. /*       sp_delete_job.                                       */
  2582. /**************************************************************/
  2583.  
  2584. PRINT ''
  2585. PRINT 'Creating procedure sp_delete_all_msx_jobs...'
  2586. go
  2587. IF (EXISTS (SELECT *
  2588.             FROM msdb.dbo.sysobjects
  2589.             WHERE (name = N'sp_delete_all_msx_jobs')
  2590.               AND (type = 'P')))
  2591.   DROP PROCEDURE sp_delete_all_msx_jobs
  2592. go
  2593. CREATE PROCEDURE sp_delete_all_msx_jobs
  2594.   @msx_server   NVARCHAR(30),
  2595.   @jobs_deleted INT = NULL OUTPUT
  2596. AS
  2597. BEGIN
  2598.   SET NOCOUNT ON
  2599.  
  2600.   -- Delete all the jobs that originated from the MSX
  2601.   CREATE TABLE #temp_jobs_to_delete (job_id UNIQUEIDENTIFIER NOT NULL, job_is_cached INT NOT NULL)
  2602.  
  2603.   -- NOTE: The left outer-join here is to handle the [unlikely] case of missing sysjobservers rows
  2604.   INSERT INTO #temp_jobs_to_delete
  2605.   SELECT sjv.job_id, CASE sjs.server_id WHEN 0 THEN 1 ELSE 0 END
  2606.   FROM msdb.dbo.sysjobs_view sjv
  2607.        LEFT OUTER JOIN msdb.dbo.sysjobservers sjs ON (sjv.job_id = sjs.job_id)
  2608.   WHERE (ISNULL(sjs.server_id, 0) = 0)
  2609.     AND (sjv.originating_server = @msx_server)
  2610.  
  2611.   -- Must do this before deleting the job itself since sp_sqlagent_notify does a lookup on sysjobs_view
  2612.   EXECUTE msdb.dbo.sp_delete_job_references
  2613.  
  2614.   BEGIN TRANSACTION
  2615.  
  2616.     DELETE FROM msdb.dbo.sysjobs_view
  2617.     WHERE job_id IN (SELECT job_id FROM #temp_jobs_to_delete)
  2618.  
  2619.     DELETE FROM msdb.dbo.sysjobservers
  2620.     WHERE job_id IN (SELECT job_id FROM #temp_jobs_to_delete)
  2621.  
  2622.     DELETE FROM msdb.dbo.sysjobsteps
  2623.     WHERE job_id IN (SELECT job_id FROM #temp_jobs_to_delete)
  2624.  
  2625.     DELETE FROM msdb.dbo.sysjobschedules
  2626.     WHERE job_id IN (SELECT job_id FROM #temp_jobs_to_delete)
  2627.  
  2628.     DELETE FROM msdb.dbo.sysjobhistory
  2629.     WHERE job_id IN (SELECT job_id FROM #temp_jobs_to_delete)
  2630.  
  2631.   COMMIT TRANSACTION
  2632.  
  2633.   SELECT @jobs_deleted = COUNT(*)
  2634.   FROM #temp_jobs_to_delete
  2635.  
  2636.   DROP TABLE #temp_jobs_to_delete
  2637. END
  2638. go
  2639.  
  2640. /**************************************************************/
  2641. /* SP_GENERATE_TARGET_SERVER_JOB_ASSIGNMENT_SQL               */
  2642. /**************************************************************/
  2643.  
  2644. PRINT ''
  2645. PRINT 'Creating procedure sp_generate_target_server_job_assignment_sql...'
  2646. go
  2647. IF (EXISTS (SELECT *
  2648.             FROM msdb.dbo.sysobjects
  2649.             WHERE (name = N'sp_generate_target_server_job_assignment_sql')
  2650.               AND (type = 'P')))
  2651.   DROP PROCEDURE sp_generate_target_server_job_assignment_sql
  2652. go
  2653. CREATE PROCEDURE sp_generate_target_server_job_assignment_sql
  2654.   @server_name     NVARCHAR(30) = '(local)',
  2655.   @new_server_name NVARCHAR(30) = NULL -- Use this if the target server computer has been renamed
  2656. AS
  2657. BEGIN
  2658.   SET NOCOUNT ON
  2659.  
  2660.   -- Verify the server name
  2661.   IF (UPPER(@server_name) <> '(LOCAL)') AND
  2662.      (NOT EXISTS (SELECT * 
  2663.                   FROM msdb.dbo.systargetservers
  2664.                   WHERE (server_name = @server_name)))
  2665.   BEGIN
  2666.     RAISERROR(14262, 16, 1, '@server_name', @server_name)
  2667.     RETURN(1) -- Failure
  2668.   END
  2669.  
  2670.   IF (EXISTS (SELECT * 
  2671.               FROM msdb.dbo.sysjobservers    sjs,
  2672.                    msdb.dbo.systargetservers sts
  2673.               WHERE (sjs.server_id = sts.server_id)
  2674.                 AND (sts.server_name = @server_name)))
  2675.   BEGIN
  2676.     -- Generate the SQL
  2677.     SELECT 'Execute this SQL to re-assign jobs to the target server' = 
  2678.            'EXECUTE msdb.dbo.sp_add_jobserver @job_id = ''' + CONVERT(VARCHAR(36), sjs.job_id) + 
  2679.            ''', @server_name = ''' +  ISNULL(@new_server_name, sts.server_name) + ''''
  2680.     FROM msdb.dbo.sysjobservers    sjs,
  2681.          msdb.dbo.systargetservers sts
  2682.     WHERE (sjs.server_id = sts.server_id)
  2683.       AND (sts.server_name = @server_name)
  2684.   END
  2685.   ELSE
  2686.     RAISERROR(14548, 10, 1, @server_name)
  2687.  
  2688.   RETURN(0) -- Success
  2689. END
  2690. go
  2691.  
  2692. /**************************************************************/
  2693. /* SP_GENERATE_SERVER_DESCRIPTION                             */
  2694. /**************************************************************/
  2695.  
  2696. PRINT ''
  2697. PRINT 'Creating procedure sp_generate_server_description...'
  2698. go
  2699.  
  2700. IF (EXISTS (SELECT *
  2701.             FROM msdb.dbo.sysobjects
  2702.             WHERE (name = N'sp_generate_server_description')
  2703.               AND (type = 'P')))
  2704.   DROP PROCEDURE sp_generate_server_description
  2705. go
  2706. CREATE PROCEDURE sp_generate_server_description 
  2707.   @description NVARCHAR(100) = NULL OUTPUT,
  2708.   @result_set  BIT = 0
  2709. AS
  2710. BEGIN
  2711.   SET NOCOUNT ON
  2712.  
  2713.   CREATE TABLE #xp_results 
  2714.   (
  2715.   id              INT           NOT NULL, 
  2716.   name            NVARCHAR(30)  NOT NULL,
  2717.   internal_value  INT           NULL,
  2718.   character_value NVARCHAR(212) NULL
  2719.   )
  2720.   INSERT INTO #xp_results
  2721.   EXECUTE master.dbo.xp_msver
  2722.  
  2723.   UPDATE #xp_results
  2724.   SET character_value = FORMATMESSAGE(14205)
  2725.   WHERE (character_value IS NULL)
  2726.  
  2727.   SELECT @description = (SELECT character_value FROM #xp_results WHERE (id = 1)) + N' ' +
  2728.                         (SELECT character_value FROM #xp_results WHERE (id = 2)) + N' / Windows ' +
  2729.                         (SELECT character_value FROM #xp_results WHERE (id = 15)) + N' / ' +
  2730.                         (SELECT character_value FROM #xp_results WHERE (id = 16)) + N' ' +
  2731.                         (SELECT CASE character_value 
  2732.                                   WHEN N'PROCESSOR_INTEL_386'     THEN N'386'
  2733.                                   WHEN N'PROCESSOR_INTEL_486'     THEN N'486'
  2734.                                   WHEN N'PROCESSOR_INTEL_PENTIUM' THEN N'Pentium'
  2735.                                   WHEN N'PROCESSOR_MIPS_R4000'    THEN N'MIPS'
  2736.                                   WHEN N'PROCESSOR_ALPHA_21064'   THEN N'Alpha'
  2737.                                   ELSE character_value
  2738.                                 END
  2739.                          FROM #xp_results WHERE (id = 18)) + N' CPU(s) / ' +
  2740.                         (SELECT CONVERT(NVARCHAR, internal_value) FROM #xp_results WHERE (id = 19)) + N' MB RAM.'
  2741.   DROP TABLE #xp_results
  2742.   IF (@result_set = 1)
  2743.     SELECT @description
  2744. END
  2745. go
  2746.  
  2747. /**************************************************************/
  2748. /* SP_MSX_ENLIST                                              */
  2749. /**************************************************************/
  2750.  
  2751. PRINT ''
  2752. PRINT 'Creating procedure sp_msx_enlist...'
  2753. go
  2754. IF (EXISTS (SELECT *
  2755.             FROM msdb.dbo.sysobjects
  2756.             WHERE (name = 'sp_msx_enlist')
  2757.               AND (type = 'P')))
  2758.   DROP PROCEDURE sp_msx_enlist
  2759. go
  2760. CREATE PROCEDURE sp_msx_enlist
  2761.   @msx_server_name NVARCHAR(30),
  2762.   @location        NVARCHAR(100) = NULL, -- The procedure will supply a default
  2763.   @ping_server     BIT = 1               -- Set to 0 to skip the MSX ping test
  2764. AS
  2765. BEGIN
  2766.   DECLARE @current_msx_server   NVARCHAR(30)
  2767.   DECLARE @local_machine_name   NVARCHAR(30)
  2768.   DECLARE @retval               INT
  2769.   DECLARE @time_zone_adjustment INT
  2770.   DECLARE @local_time           NVARCHAR(100)
  2771.   DECLARE @nt_user              NVARCHAR(100)
  2772.   DECLARE @poll_interval        INT
  2773.  
  2774.   SET NOCOUNT ON
  2775.  
  2776.   -- Only a sysadmin can do this
  2777.   IF (ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) <> 1)
  2778.   BEGIN
  2779.     RAISERROR(15003, 16, 1, N'sysadmin')
  2780.     RETURN(1) -- Failure
  2781.   END
  2782.  
  2783.   -- Only an NT server can be enlisted
  2784.   IF ((PLATFORM() & 0x1) <> 0x1) -- NT
  2785.   BEGIN
  2786.     RAISERROR(14540, -1, 1)
  2787.     RETURN(1) -- Failure
  2788.   END
  2789.  
  2790.   -- Only SBS, Standard, or Enterprise editions of SQL Server can be enlisted
  2791.   IF ((PLATFORM() & 0x100) = 0x100) -- Desktop package
  2792.   BEGIN
  2793.     RAISERROR(14539, -1, -1)
  2794.     RETURN(1) -- Failure
  2795.   END
  2796.  
  2797.   -- Remove any leading/trailing spaces from parameters
  2798.   SELECT @msx_server_name = LTRIM(RTRIM(@msx_server_name))
  2799.   SELECT @location        = LTRIM(RTRIM(@location))
  2800.  
  2801.   -- Turn [nullable] empty string parameters into NULLs
  2802.   IF (@location = N'') SELECT @location = NULL
  2803.  
  2804.   -- Change to MSX server name to upper-case since it's a machine name
  2805.   SELECT @msx_server_name = UPPER(@msx_server_name)
  2806.  
  2807.   SELECT @retval = 0
  2808.  
  2809.   -- Get the values that we'll need for the [re]enlistment operation (except the local time
  2810.   -- which we get right before we call xp_msx_enlist to that it's as accurate as possible)
  2811.   SELECT @nt_user = ISNULL(NT_CLIENT(), ISNULL(SUSER_SNAME(), FORMATMESSAGE(14205)))
  2812.   EXECUTE master.dbo.xp_regread N'HKEY_LOCAL_MACHINE',
  2813.                                 N'SYSTEM\CurrentControlSet\Control\TimeZoneInformation',
  2814.                                 N'Bias',
  2815.                                  @time_zone_adjustment OUTPUT,
  2816.                                 N'no_output'
  2817.   IF ((PLATFORM() & 0x1) = 0x1) -- NT
  2818.     SELECT @time_zone_adjustment = -ISNULL(@time_zone_adjustment, 0)
  2819.   ELSE
  2820.     SELECT @time_zone_adjustment = -CONVERT(INT, CONVERT(BINARY(2), ISNULL(@time_zone_adjustment, 0)))
  2821.   
  2822.   EXECUTE master.dbo.xp_regread N'HKEY_LOCAL_MACHINE',
  2823.                                 N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
  2824.                                 N'MSXPollInterval',
  2825.                                  @poll_interval OUTPUT,
  2826.                                 N'no_output'
  2827.   SELECT @poll_interval = ISNULL(@poll_interval, 60) -- This should be the same as DEF_REG_MSX_POLL_INTERVAL
  2828.   EXECUTE master.dbo.xp_regread N'HKEY_LOCAL_MACHINE',
  2829.                                 N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
  2830.                                 N'MSXServerName',
  2831.                                  @current_msx_server OUTPUT,
  2832.                                 N'no_output'
  2833.   SELECT @current_msx_server = LTRIM(RTRIM(@current_msx_server))
  2834.   EXECUTE @retval = master.dbo.xp_getnetname @local_machine_name OUTPUT
  2835.   IF (@retval <> 0)
  2836.     RETURN(1) -- Failure
  2837.  
  2838.   -- Check if this machine is an MSX (and therefore cannot be enlisted into another MSX)
  2839.   IF (EXISTS (SELECT *
  2840.               FROM msdb.dbo.systargetservers))
  2841.   BEGIN
  2842.     RAISERROR(14299, -1, -1, @local_machine_name)
  2843.     RETURN(1) -- Failure
  2844.   END
  2845.  
  2846.   -- Check if the MSX supplied is the same as the local machine (this is not allowed)
  2847.   IF (UPPER(@local_machine_name) = UPPER(@msx_server_name))
  2848.   BEGIN
  2849.     RAISERROR(14297, -1, -1)
  2850.     RETURN(1) -- Failure
  2851.   END
  2852.  
  2853.   -- Check if MSDB has be re-installed since we enlisted
  2854.   IF (@current_msx_server IS NOT NULL) AND
  2855.      (NOT EXISTS (SELECT *
  2856.                   FROM msdb.dbo.sqlagent_info
  2857.                   WHERE (attribute = 'DateEnlisted')))
  2858.   BEGIN
  2859.     -- User is tring to [re]enlist after a re-install, so we have to forcefully defect before
  2860.     -- we can fully enlist again
  2861.     EXECUTE msdb.dbo.sp_msx_defect @forced_defection = 1
  2862.     SELECT @current_msx_server = NULL
  2863.   END  
  2864.  
  2865.   -- Check if we are already enlisted, in which case we re-enlist
  2866.   IF ((@current_msx_server IS NOT NULL) AND (@current_msx_server <> N''))
  2867.   BEGIN
  2868.     IF (UPPER(@current_msx_server) = UPPER(@msx_server_name))
  2869.     BEGIN
  2870.       -- Update the [existing] enlistment
  2871.       SELECT @local_time = CONVERT(NVARCHAR, GETDATE(), 112) + N' ' + CONVERT(NVARCHAR, GETDATE(), 108)
  2872.       EXECUTE @retval = master.dbo.xp_msx_enlist 2, @msx_server_name, @nt_user, @location, @time_zone_adjustment, @local_time, @poll_interval
  2873.       RETURN(@retval) -- 0 means success
  2874.     END
  2875.     ELSE
  2876.     BEGIN
  2877.       RAISERROR(14296, -1, -1, @current_msx_server)
  2878.       RETURN(1) -- Failure
  2879.     END
  2880.   END
  2881.  
  2882.   -- If we get this far then we're dealing with a new enlistment...
  2883.  
  2884.   -- Check if the MSX supplied exists on the network
  2885.   IF (@ping_server = 1)
  2886.   BEGIN
  2887.     DECLARE @msx_machine_name NVARCHAR (30)
  2888.     DECLARE @char_index       INT
  2889.  
  2890.     SELECT @char_index = CHARINDEX (N'\', @msx_server_name)
  2891.     IF (@char_index > 0)
  2892.     BEGIN
  2893.       SELECT @msx_machine_name = LEFT (@msx_server_name, @char_index - 1)
  2894.     END
  2895.     ELSE
  2896.     BEGIN
  2897.       SELECT @msx_machine_name = @msx_server_name
  2898.     END
  2899.  
  2900.     IF ((PLATFORM() & 0x2) = 0x2) -- Win9x
  2901.     BEGIN
  2902.       EXECUTE(N'CREATE TABLE #output (output NVARCHAR(1024) COLLATE database_default)
  2903.                 SET NOCOUNT ON
  2904.                 INSERT INTO #output
  2905.                 EXECUTE master.dbo.xp_cmdshell N''net view \\' + @msx_machine_name + N'''
  2906.                 IF (EXISTS (SELECT *
  2907.                             FROM #output
  2908.                             WHERE (output LIKE N''% 53%'')))
  2909.                    RAISERROR(14262, -1, -1, N''@msx_server_name'', N''' + @msx_machine_name + N''') WITH SETERROR')
  2910.       IF (@@error <> 0)
  2911.         RETURN(1) -- Failure
  2912.     END
  2913.     ELSE
  2914.     BEGIN
  2915.       EXECUTE(N'DECLARE @retval INT
  2916.                 SET NOCOUNT ON
  2917.                 EXECUTE @retval = master.dbo.xp_cmdshell N''net view \\' + @msx_machine_name + N' > nul'', no_output
  2918.                 IF (@retval <> 0)
  2919.                   RAISERROR(14262, -1, -1, N''@msx_server_name'', N''' + @msx_machine_name + N''') WITH SETERROR')
  2920.       IF (@@error <> 0)
  2921.         RETURN(1) -- Failure
  2922.     END
  2923.   END
  2924.  
  2925.   -- If no location is supplied, generate one (such as we can)
  2926.   IF (@location IS NULL)
  2927.     EXECUTE msdb.dbo.sp_generate_server_description @location OUTPUT
  2928.  
  2929.   SELECT @local_time = CONVERT(NVARCHAR, GETDATE(), 112) + ' ' + CONVERT(NVARCHAR, GETDATE(), 108)
  2930.   EXECUTE @retval = master.dbo.xp_msx_enlist 0, @msx_server_name, @nt_user, @location, @time_zone_adjustment, @local_time, @poll_interval
  2931.  
  2932.   IF (@retval = 0)
  2933.   BEGIN
  2934.     EXECUTE master.dbo.xp_regwrite N'HKEY_LOCAL_MACHINE',
  2935.                                    N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
  2936.                                    N'MSXServerName',
  2937.                                    N'REG_SZ',
  2938.                                     @msx_server_name
  2939.  
  2940.     IF (@current_msx_server IS NOT NULL)
  2941.       RAISERROR(14228, 0, 1, @current_msx_server, @msx_server_name)
  2942.     ELSE
  2943.       RAISERROR(14229, 0, 1, @msx_server_name)
  2944.  
  2945.     -- Add entry to sqlagent_info
  2946.     INSERT INTO msdb.dbo.sqlagent_info (attribute, value) VALUES ('DateEnlisted', CONVERT(VARCHAR(10), GETDATE(), 112))
  2947.   END
  2948.  
  2949.   RETURN(@retval) -- 0 means success
  2950. END
  2951. go
  2952.  
  2953. /**************************************************************/
  2954. /* SP_MSX_DEFECT                                              */
  2955. /**************************************************************/
  2956.  
  2957. PRINT ''
  2958. PRINT 'Creating procedure sp_msx_defect...'
  2959. go
  2960. IF (EXISTS (SELECT *
  2961.             FROM msdb.dbo.sysobjects
  2962.             WHERE (name = N'sp_msx_defect')
  2963.               AND (type = 'P')))
  2964.   DROP PROCEDURE sp_msx_defect
  2965. go
  2966. CREATE PROCEDURE sp_msx_defect
  2967.   @forced_defection BIT = 0
  2968. AS
  2969. BEGIN
  2970.   DECLARE @current_msx_server NVARCHAR(30)
  2971.   DECLARE @retval             INT
  2972.   DECLARE @jobs_deleted       INT
  2973.   DECLARE @polling_interval   INT
  2974.   DECLARE @nt_user            NVARCHAR(100)
  2975.  
  2976.   SET NOCOUNT ON
  2977.  
  2978.   -- Only a sysadmin can do this
  2979.   IF (ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) <> 1)
  2980.   BEGIN
  2981.     RAISERROR(15003, 16, 1, N'sysadmin')
  2982.     RETURN(1) -- Failure
  2983.   END
  2984.  
  2985.   SELECT @retval = 0
  2986.   SELECT @jobs_deleted = 0
  2987.  
  2988.   -- Get the current MSX server name from the registry
  2989.   EXECUTE master.dbo.xp_regread N'HKEY_LOCAL_MACHINE',
  2990.                                 N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
  2991.                                 N'MSXServerName',
  2992.                                  @current_msx_server OUTPUT,
  2993.                                 N'no_output'
  2994.  
  2995.   SELECT @current_msx_server = LTRIM(RTRIM(@current_msx_server))
  2996.   IF ((@current_msx_server IS NULL) OR (@current_msx_server = N''))
  2997.   BEGIN
  2998.     RAISERROR(14298, -1, -1)
  2999.     RETURN(1) -- Failure
  3000.   END
  3001.  
  3002.   SELECT @nt_user = ISNULL(NT_CLIENT(), ISNULL(SUSER_SNAME(), FORMATMESSAGE(14205)))
  3003.  
  3004.   EXECUTE @retval = master.dbo.xp_msx_enlist 1, @current_msx_server, @nt_user
  3005.  
  3006.   IF (@retval <> 0) AND (@forced_defection = 0)
  3007.     RETURN(1) -- Failure
  3008.  
  3009.   -- Clear the MSXServerName registry entry
  3010.   EXECUTE master.dbo.xp_regwrite N'HKEY_LOCAL_MACHINE',
  3011.                                  N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
  3012.                                  N'MSXServerName',
  3013.                                  N'REG_SZ',
  3014.                                  N''
  3015.  
  3016.   -- Delete the MSXPollingInterval registry entry
  3017.   EXECUTE master.dbo.xp_regread N'HKEY_LOCAL_MACHINE', 
  3018.                                 N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent', 
  3019.                                 N'MSXPollInterval',
  3020.                                  @polling_interval OUTPUT,
  3021.                                 N'no_output'
  3022.   IF (@polling_interval IS NOT NULL)
  3023.     EXECUTE master.dbo.xp_regdeletevalue N'HKEY_LOCAL_MACHINE', 
  3024.                                          N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent', 
  3025.                                          N'MSXPollInterval'
  3026.  
  3027.   -- Remove the entry from sqlagent_info 
  3028.   DELETE FROM msdb.dbo.sqlagent_info 
  3029.   WHERE (attribute = N'DateEnlisted')
  3030.  
  3031.   -- Delete all the jobs that originated from the MSX
  3032.   -- NOTE: We can't use sp_delete_job here since sp_delete_job checks if the caller is
  3033.   --       SQLServerAgent (only SQLServerAgent can delete non-local jobs).
  3034.   EXECUTE msdb.dbo.sp_delete_all_msx_jobs @current_msx_server, @jobs_deleted OUTPUT
  3035.   RAISERROR(14227, 0, 1, @current_msx_server, @jobs_deleted)
  3036.  
  3037.   -- If a forced defection was performed, attempt to notify the MSXOperator
  3038.   IF (@forced_defection = 1)
  3039.   BEGIN 
  3040.     DECLARE @network_address    NVARCHAR(100)
  3041.     DECLARE @command            NVARCHAR(512)
  3042.     DECLARE @local_machine_name NVARCHAR(30)
  3043.     DECLARE @res_warning        NVARCHAR(300)
  3044.     
  3045.     SELECT @network_address = netsend_address
  3046.     FROM msdb.dbo.sysoperators
  3047.     WHERE (name = N'MSXOperator')
  3048.  
  3049.     IF (@network_address IS NOT NULL)
  3050.     BEGIN
  3051.       EXECUTE @retval = master.dbo.xp_getnetname @local_machine_name OUTPUT
  3052.       IF (@retval <> 0)
  3053.         RETURN(1) -- Failure
  3054.       SELECT @res_warning = FORMATMESSAGE(14217)
  3055.       SELECT @command = N'NET SEND ' + @network_address + N' ' + @res_warning
  3056.       SELECT @command = STUFF(@command, PATINDEX(N'%[%%]s%', @command), 2, NT_CLIENT())
  3057.       SELECT @command = STUFF(@command, PATINDEX(N'%[%%]s%', @command), 2, @local_machine_name)
  3058.       EXECUTE master.dbo.xp_cmdshell @command, no_output
  3059.     END
  3060.   END
  3061.  
  3062.   -- Delete the 'MSXOperator' (must do this last)
  3063.   IF (EXISTS (SELECT *
  3064.               FROM msdb.dbo.sysoperators
  3065.               WHERE (name = N'MSXOperator')))
  3066.     EXECUTE msdb.dbo.sp_delete_operator @name = N'MSXOperator'
  3067.  
  3068.   RETURN(0) -- 0 means success
  3069. END
  3070. go
  3071.  
  3072. /**************************************************************/
  3073. /* SP_GET_SQLAGENT_PROPERTIES                                 */
  3074. /**************************************************************/
  3075.  
  3076. PRINT ''
  3077. PRINT 'Creating procedure sp_get_sqlagent_properties...'
  3078. go
  3079. IF (EXISTS (SELECT *
  3080.             FROM msdb.dbo.sysobjects
  3081.             WHERE (name = N'sp_get_sqlagent_properties')
  3082.               AND (type = 'P')))
  3083.   DROP PROCEDURE sp_get_sqlagent_properties
  3084. go
  3085. CREATE PROCEDURE sp_get_sqlagent_properties
  3086. AS
  3087. BEGIN
  3088.   DECLARE @auto_start                  INT
  3089.   DECLARE @startup_account             NVARCHAR(100)
  3090.   DECLARE @msx_server_name             NVARCHAR(30)
  3091.  
  3092.   -- Non-SQLDMO exposed properties
  3093.   DECLARE @sqlserver_restart           INT
  3094.   DECLARE @jobhistory_max_rows         INT
  3095.   DECLARE @jobhistory_max_rows_per_job INT
  3096.   DECLARE @errorlog_file               NVARCHAR(255)
  3097.   DECLARE @errorlogging_level          INT
  3098.   DECLARE @error_recipient             NVARCHAR(30)
  3099.   DECLARE @monitor_autostart           INT
  3100.   DECLARE @local_host_server           NVARCHAR(30)
  3101.   DECLARE @job_shutdown_timeout        INT 
  3102.   DECLARE @cmdexec_account             VARBINARY(64)
  3103.   DECLARE @regular_connections         INT
  3104.   DECLARE @host_login_name             sysname
  3105.   DECLARE @host_login_password         VARBINARY(512)
  3106.   DECLARE @login_timeout               INT
  3107.   DECLARE @idle_cpu_percent            INT
  3108.   DECLARE @idle_cpu_duration           INT
  3109.   DECLARE @oem_errorlog                INT
  3110.   DECLARE @sysadmin_only               INT
  3111.   DECLARE @email_profile               NVARCHAR(64)
  3112.   DECLARE @email_save_in_sent_folder   INT
  3113.   DECLARE @cpu_poller_enabled          INT     
  3114.  
  3115.   SET NOCOUNT ON
  3116.  
  3117.   -- NOTE: We return all SQLServerAgent properties at one go for performance reasons
  3118.  
  3119.   -- Read the values from the registry
  3120.   IF ((PLATFORM() & 0x1) = 0x1) -- NT
  3121.   BEGIN
  3122.     EXECUTE master.dbo.xp_regread N'HKEY_LOCAL_MACHINE',
  3123.                                   N'SYSTEM\CurrentControlSet\Services\SQLServerAgent',
  3124.                                   N'Start',
  3125.                                    @auto_start OUTPUT,
  3126.                                   N'no_output'
  3127.     EXECUTE master.dbo.xp_regread N'HKEY_LOCAL_MACHINE',
  3128.                                   N'SYSTEM\CurrentControlSet\Services\SQLServerAgent',
  3129.                                   N'ObjectName',
  3130.                                    @startup_account OUTPUT,
  3131.                                   N'no_output'
  3132.   END
  3133.   ELSE
  3134.   BEGIN
  3135.     SELECT @auto_start = 3 -- Manual start
  3136.     SELECT @startup_account = NULL
  3137.   END
  3138.   EXECUTE master.dbo.xp_regread N'HKEY_LOCAL_MACHINE',
  3139.                                 N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
  3140.                                 N'MSXServerName',
  3141.                                  @msx_server_name OUTPUT,
  3142.                                 N'no_output'
  3143.  
  3144.   -- Non-SQLDMO exposed properties
  3145.   EXECUTE master.dbo.xp_regread N'HKEY_LOCAL_MACHINE',
  3146.                                 N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
  3147.                                 N'RestartSQLServer',
  3148.                                  @sqlserver_restart OUTPUT,
  3149.                                 N'no_output'
  3150.   EXECUTE master.dbo.xp_regread N'HKEY_LOCAL_MACHINE',
  3151.                                 N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
  3152.                                 N'JobHistoryMaxRows',
  3153.                                  @jobhistory_max_rows OUTPUT,
  3154.                                 N'no_output'
  3155.   EXECUTE master.dbo.xp_regread N'HKEY_LOCAL_MACHINE',
  3156.                                 N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
  3157.                                 N'JobHistoryMaxRowsPerJob',
  3158.                                  @jobhistory_max_rows_per_job OUTPUT,
  3159.                                 N'no_output'
  3160.   EXECUTE master.dbo.xp_regread N'HKEY_LOCAL_MACHINE',
  3161.                                 N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
  3162.                                 N'ErrorLogFile',
  3163.                                  @errorlog_file OUTPUT,
  3164.                                 N'no_output'
  3165.   EXECUTE master.dbo.xp_regread N'HKEY_LOCAL_MACHINE',
  3166.                                 N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
  3167.                                 N'ErrorLoggingLevel',
  3168.                                  @errorlogging_level OUTPUT,
  3169.                                 N'no_output'
  3170.   EXECUTE master.dbo.xp_regread N'HKEY_LOCAL_MACHINE',
  3171.                                 N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
  3172.                                 N'ErrorMonitor',
  3173.                                  @error_recipient OUTPUT,
  3174.                                 N'no_output'
  3175.   EXECUTE master.dbo.xp_regread N'HKEY_LOCAL_MACHINE',
  3176.                                 N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
  3177.                                 N'MonitorAutoStart',
  3178.                                  @monitor_autostart OUTPUT,
  3179.                                 N'no_output'
  3180.   EXECUTE master.dbo.xp_regread N'HKEY_LOCAL_MACHINE',
  3181.                                 N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
  3182.                                 N'ServerHost',
  3183.                                  @local_host_server OUTPUT,
  3184.                                 N'no_output'
  3185.   EXECUTE master.dbo.xp_regread N'HKEY_LOCAL_MACHINE',
  3186.                                 N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
  3187.                                 N'JobShutdownTimeout',
  3188.                                  @job_shutdown_timeout OUTPUT,
  3189.                                 N'no_output'
  3190.   EXECUTE master.dbo.xp_regread N'HKEY_LOCAL_MACHINE',
  3191.                                 N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
  3192.                                 N'CmdExecAccount',
  3193.                                  @cmdexec_account OUTPUT,
  3194.                                 N'no_output'
  3195.   EXECUTE master.dbo.xp_regread N'HKEY_LOCAL_MACHINE',
  3196.                                 N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
  3197.                                 N'RegularConnections',
  3198.                                  @regular_connections OUTPUT,
  3199.                                 N'no_output'
  3200.   EXECUTE master.dbo.xp_regread N'HKEY_LOCAL_MACHINE',
  3201.                                 N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
  3202.                                 N'HostLoginID',
  3203.                                  @host_login_name OUTPUT,
  3204.                                 N'no_output'
  3205.   EXECUTE master.dbo.xp_regread N'HKEY_LOCAL_MACHINE',
  3206.                                 N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
  3207.                                 N'HostPassword',
  3208.                                  @host_login_password OUTPUT,
  3209.                                 N'no_output'
  3210.   EXECUTE master.dbo.xp_regread N'HKEY_LOCAL_MACHINE',
  3211.                                 N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
  3212.                                 N'LoginTimeout',
  3213.                                  @login_timeout OUTPUT,
  3214.                                 N'no_output'
  3215.   EXECUTE master.dbo.xp_regread N'HKEY_LOCAL_MACHINE',
  3216.                                 N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
  3217.                                 N'IdleCPUPercent',
  3218.                                  @idle_cpu_percent OUTPUT,
  3219.                                 N'no_output'
  3220.   EXECUTE master.dbo.xp_regread N'HKEY_LOCAL_MACHINE',
  3221.                                 N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
  3222.                                 N'IdleCPUDuration',
  3223.                                  @idle_cpu_duration OUTPUT,
  3224.                                 N'no_output'
  3225.   EXECUTE master.dbo.xp_regread N'HKEY_LOCAL_MACHINE',
  3226.                                 N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
  3227.                                 N'OemErrorLog',
  3228.                                  @oem_errorlog OUTPUT,
  3229.                                 N'no_output'
  3230.   EXECUTE master.dbo.xp_regread N'HKEY_LOCAL_MACHINE',
  3231.                                 N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
  3232.                                 N'SysAdminOnly',
  3233.                                  @sysadmin_only OUTPUT,
  3234.                                 N'no_output'
  3235.   EXECUTE master.dbo.xp_regread N'HKEY_LOCAL_MACHINE',
  3236.                                 N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
  3237.                                 N'EmailProfile',
  3238.                                  @email_profile OUTPUT,
  3239.                                 N'no_output'
  3240.   EXECUTE master.dbo.xp_regread N'HKEY_LOCAL_MACHINE',
  3241.                                 N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
  3242.                                 N'EmailSaveSent',
  3243.                                  @email_save_in_sent_folder OUTPUT,
  3244.                                 N'no_output'
  3245.   EXECUTE master.dbo.xp_regread N'HKEY_LOCAL_MACHINE',
  3246.                                 N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
  3247.                                 N'CoreEngineMask',
  3248.                                  @cpu_poller_enabled OUTPUT,
  3249.                                 N'no_output'
  3250.   IF (@cpu_poller_enabled IS NOT NULL)
  3251.     SELECT @cpu_poller_enabled = CASE WHEN (@cpu_poller_enabled & 32) = 32 THEN 0 ELSE 1 END
  3252.  
  3253.   -- Return the values to the client
  3254.   SELECT auto_start = CASE @auto_start
  3255.                         WHEN 2 THEN 1 -- 2 means auto-start
  3256.                         WHEN 3 THEN 0 -- 3 means don't auto-start
  3257.                         ELSE 0        -- Safety net
  3258.                       END,
  3259.          msx_server_name = @msx_server_name,
  3260.          sqlagent_type = (SELECT CASE
  3261.                                     WHEN (COUNT(*) = 0) AND (ISNULL(DATALENGTH(@msx_server_name), 0) = 0) THEN 1 -- Standalone
  3262.                                     WHEN (COUNT(*) = 0) AND (ISNULL(DATALENGTH(@msx_server_name), 0) > 0) THEN 2 -- TSX
  3263.                                     WHEN (COUNT(*) > 0) AND (ISNULL(DATALENGTH(@msx_server_name), 0) = 0) THEN 3 -- MSX
  3264.                                     WHEN (COUNT(*) > 0) AND (ISNULL(DATALENGTH(@msx_server_name), 0) > 0) THEN 0 -- Multi-Level MSX (currently invalid)
  3265.                                     ELSE 0 -- Invalid
  3266.                                   END
  3267.                            FROM msdb.dbo.systargetservers),
  3268.          startup_account = @startup_account,
  3269.  
  3270.          -- Non-SQLDMO exposed properties
  3271.          sqlserver_restart = @sqlserver_restart,
  3272.          jobhistory_max_rows = @jobhistory_max_rows,
  3273.          jobhistory_max_rows_per_job = @jobhistory_max_rows_per_job,
  3274.          errorlog_file = @errorlog_file,
  3275.          errorlogging_level = ISNULL(@errorlogging_level, 7),
  3276.          error_recipient = @error_recipient,
  3277.          monitor_autostart = ISNULL(@monitor_autostart, 0),
  3278.          local_host_server = @local_host_server,
  3279.          job_shutdown_timeout = ISNULL(@job_shutdown_timeout, 15),
  3280.          cmdexec_account = @cmdexec_account,
  3281.          regular_connections = ISNULL(@regular_connections, 0),
  3282.          host_login_name = @host_login_name,
  3283.          host_login_password = @host_login_password,
  3284.          login_timeout = ISNULL(@login_timeout, 30),
  3285.          idle_cpu_percent = ISNULL(@idle_cpu_percent, 10),
  3286.          idle_cpu_duration = ISNULL(@idle_cpu_duration, 600),
  3287.          oem_errorlog = ISNULL(@oem_errorlog, 0),
  3288.          sysadmin_only = ISNULL(@sysadmin_only, 0),
  3289.          email_profile = @email_profile,
  3290.          email_save_in_sent_folder = ISNULL(@email_save_in_sent_folder, 0),
  3291.          cpu_poller_enabled = ISNULL(@cpu_poller_enabled, 0)
  3292. END
  3293. go
  3294.  
  3295. /**************************************************************/
  3296. /* SP_SET_SQLAGENT_PROPERTIES                                 */
  3297. /**************************************************************/
  3298.  
  3299. PRINT ''
  3300. PRINT 'Creating procedure sp_set_sqlagent_properties...'
  3301. go
  3302. IF (EXISTS (SELECT *
  3303.             FROM msdb.dbo.sysobjects
  3304.             WHERE (name = N'sp_set_sqlagent_properties')
  3305.               AND (type = 'P')))
  3306.   DROP PROCEDURE sp_set_sqlagent_properties
  3307. go
  3308. CREATE PROCEDURE sp_set_sqlagent_properties
  3309.   @auto_start                  INT           = NULL, -- 1 or 0
  3310.  
  3311.   -- Non-SQLDMO exposed properties
  3312.   @sqlserver_restart           INT           = NULL, -- 1 or 0
  3313.   @jobhistory_max_rows         INT           = NULL, -- No maximum = -1, otherwise must be > 1
  3314.   @jobhistory_max_rows_per_job INT           = NULL, -- 1 to @jobhistory_max_rows
  3315.   @errorlog_file               NVARCHAR(255) = NULL, -- Full drive\path\name of errorlog file
  3316.   @errorlogging_level          INT           = NULL, -- 1 = error, 2 = warning, 4 = information
  3317.   @error_recipient             NVARCHAR(30)  = NULL, -- Network address of error popup recipient 
  3318.   @monitor_autostart           INT           = NULL, -- 1 or 0
  3319.   @local_host_server           NVARCHAR(30)  = NULL, -- Alias of local host server
  3320.   @job_shutdown_timeout        INT           = NULL, -- 5 to 600 seconds
  3321.   @cmdexec_account             VARBINARY(64) = NULL, -- CmdExec account information
  3322.   @regular_connections         INT           = NULL, -- 1 or 0
  3323.   @host_login_name             sysname       = NULL, -- Login name (if regular_connections = 1) 
  3324.   @host_login_password         VARBINARY(512)= NULL, -- Login password (if regular_connections = 1) 
  3325.   @login_timeout               INT           = NULL, -- 5 to 45 (seconds)
  3326.   @idle_cpu_percent            INT           = NULL, -- 1 to 100
  3327.   @idle_cpu_duration           INT           = NULL, -- 20 to 86400 seconds
  3328.   @oem_errorlog                INT           = NULL, -- 1 or 0
  3329.   @sysadmin_only               INT           = NULL, -- 1 or 0
  3330.   @email_profile               NVARCHAR(64)  = NULL, -- Email profile name
  3331.   @email_save_in_sent_folder   INT           = NULL, -- 1 or 0
  3332.   @cpu_poller_enabled          INT           = NULL  -- 1 or 0
  3333. AS
  3334. BEGIN
  3335.   -- NOTE: We set all SQLServerAgent properties at one go for performance reasons.
  3336.   -- NOTE: You cannot set the value of the properties msx_server_name, is_msx or
  3337.   --       startup_account - they are all read only.
  3338.  
  3339.   DECLARE @res_valid_range           NVARCHAR(100)
  3340.   DECLARE @existing_core_engine_mask INT
  3341.  
  3342.   SET NOCOUNT ON
  3343.  
  3344.   -- Remove any leading/trailing spaces from parameters
  3345.   SELECT @errorlog_file     = LTRIM(RTRIM(@errorlog_file))
  3346.   SELECT @error_recipient   = LTRIM(RTRIM(@error_recipient))
  3347.   SELECT @local_host_server = LTRIM(RTRIM(@local_host_server))
  3348.   SELECT @host_login_name   = LTRIM(RTRIM(@host_login_name))
  3349.   SELECT @email_profile     = LTRIM(RTRIM(@email_profile))
  3350.  
  3351.   -- Make sure values (if supplied) are good
  3352.   IF (@auto_start IS NOT NULL)
  3353.   BEGIN
  3354.     -- NOTE: When setting the the services start value, 2 == auto-start, 3 == Don't auto-start
  3355.     SELECT @auto_start = CASE @auto_start
  3356.                            WHEN 0 THEN 3
  3357.                            WHEN 1 THEN 2
  3358.                            ELSE 3 -- Assume non auto-start if passed a junk value
  3359.                           END
  3360.   END
  3361.  
  3362.   -- Non-SQLDMO exposed properties
  3363.   IF ((@sqlserver_restart IS NOT NULL) AND (@sqlserver_restart <> 0))
  3364.     SELECT @sqlserver_restart = 1
  3365.  
  3366.   IF (@jobhistory_max_rows IS NOT NULL)
  3367.   BEGIN
  3368.     SELECT @res_valid_range = FORMATMESSAGE(14207)
  3369.     IF ((@jobhistory_max_rows < -1) OR (@jobhistory_max_rows = 0))
  3370.     BEGIN
  3371.       RAISERROR(14266, -1, -1, '@jobhistory_max_rows', @res_valid_range)
  3372.       RETURN(1) -- Failure
  3373.     END
  3374.   END
  3375.   ELSE
  3376.   BEGIN
  3377.     EXECUTE master.dbo.xp_regread N'HKEY_LOCAL_MACHINE',
  3378.                                   N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
  3379.                                   N'JobHistoryMaxRows',
  3380.                                    @jobhistory_max_rows OUTPUT,
  3381.                                   N'no_output'
  3382.     SELECT @jobhistory_max_rows = ISNULL(@jobhistory_max_rows, -1)
  3383.   END
  3384.  
  3385.   IF (@jobhistory_max_rows_per_job IS NOT NULL)
  3386.   BEGIN
  3387.     IF (@jobhistory_max_rows = -1)
  3388.       SELECT @jobhistory_max_rows_per_job = 0
  3389.     ELSE
  3390.     BEGIN
  3391.       IF ((@jobhistory_max_rows_per_job < 1) OR (@jobhistory_max_rows_per_job > @jobhistory_max_rows))
  3392.       BEGIN
  3393.         SELECT @res_valid_range = N'1..' + CONVERT(NVARCHAR, @jobhistory_max_rows)
  3394.         RAISERROR(14266, -1, -1, '@jobhistory_max_rows', @res_valid_range)
  3395.         RETURN(1) -- Failure
  3396.       END
  3397.     END
  3398.   END
  3399.  
  3400.   IF (@errorlogging_level IS NOT NULL) AND ((@errorlogging_level < 1) OR (@errorlogging_level > 7))
  3401.   BEGIN
  3402.     RAISERROR(14266, -1, -1, '@errorlogging_level', '1..7')
  3403.     RETURN(1) -- Failure
  3404.   END
  3405.  
  3406.   IF (@monitor_autostart IS NOT NULL) AND ((@monitor_autostart < 0) OR (@monitor_autostart > 1))
  3407.   BEGIN
  3408.     RAISERROR(14266, -1, -1, '@monitor_autostart', '0, 1')
  3409.     RETURN(1) -- Failure
  3410.   END
  3411.  
  3412.   IF (@job_shutdown_timeout IS NOT NULL) AND ((@job_shutdown_timeout < 5) OR (@job_shutdown_timeout > 600))
  3413.   BEGIN
  3414.     RAISERROR(14266, -1, -1, '@job_shutdown_timeout', '5..600')
  3415.     RETURN(1) -- Failure
  3416.   END
  3417.  
  3418.   IF (@regular_connections IS NOT NULL) AND ((@regular_connections < 0) OR (@regular_connections > 1))
  3419.   BEGIN
  3420.     RAISERROR(14266, -1, -1, '@regular_connections', '0, 1')
  3421.     RETURN(1) -- Failure
  3422.   END
  3423.  
  3424.   IF (@login_timeout IS NOT NULL) AND ((@login_timeout < 5) OR (@login_timeout > 45))
  3425.   BEGIN
  3426.     RAISERROR(14266, -1, -1, '@login_timeout', '5..45')
  3427.     RETURN(1) -- Failure
  3428.   END
  3429.  
  3430.   IF ((@idle_cpu_percent IS NOT NULL) AND ((@idle_cpu_percent < 1) OR (@idle_cpu_percent > 100)))
  3431.   BEGIN
  3432.     RAISERROR(14266, -1, -1, '@idle_cpu_percent', '10..100')
  3433.     RETURN(1) -- Failure
  3434.   END
  3435.  
  3436.   IF ((@idle_cpu_duration IS NOT NULL) AND ((@idle_cpu_duration < 20) OR (@idle_cpu_duration > 86400)))
  3437.   BEGIN
  3438.     RAISERROR(14266, -1, -1, '@idle_cpu_duration', '20..86400')
  3439.     RETURN(1) -- Failure
  3440.   END
  3441.  
  3442.   IF (@oem_errorlog IS NOT NULL) AND ((@oem_errorlog < 0) OR (@oem_errorlog > 1))
  3443.   BEGIN
  3444.     RAISERROR(14266, -1, -1, '@oem_errorlog', '0, 1')
  3445.     RETURN(1) -- Failure
  3446.   END
  3447.  
  3448.   IF (@sysadmin_only IS NOT NULL) AND ((@sysadmin_only < 0) OR (@sysadmin_only > 1))
  3449.   BEGIN
  3450.     RAISERROR(14266, -1, -1, '@sysadmin_only', '0, 1')
  3451.     RETURN(1) -- Failure
  3452.   END
  3453.  
  3454.   IF (@email_save_in_sent_folder IS NOT NULL) AND ((@email_save_in_sent_folder < 0) OR (@email_save_in_sent_folder > 1))
  3455.   BEGIN
  3456.     RAISERROR(14266, -1, -1, 'email_save_in_sent_folder', '0, 1')
  3457.     RETURN(1) -- Failure
  3458.   END
  3459.  
  3460.   IF (@cpu_poller_enabled IS NOT NULL) AND ((@cpu_poller_enabled < 0) OR (@cpu_poller_enabled > 1))
  3461.   BEGIN
  3462.     RAISERROR(14266, -1, -1, 'cpu_poller_enabled', '0, 1')
  3463.     RETURN(1) -- Failure
  3464.   END
  3465.  
  3466.   -- Write out the values
  3467.   IF (@auto_start IS NOT NULL)
  3468.   BEGIN
  3469.     IF ((PLATFORM() & 0x1) = 0x1) -- NT
  3470.       EXECUTE master.dbo.xp_regwrite N'HKEY_LOCAL_MACHINE',
  3471.                                      N'SYSTEM\CurrentControlSet\Services\SQLServerAgent',
  3472.                                      N'Start',
  3473.                                      N'REG_DWORD',
  3474.                                       @auto_start
  3475.     ELSE
  3476.       RAISERROR(14546, 16, 1, '@auto_start')
  3477.   END
  3478.  
  3479.   -- Non-SQLDMO exposed properties
  3480.   IF (@sqlserver_restart IS NOT NULL)
  3481.     EXECUTE master.dbo.xp_regwrite N'HKEY_LOCAL_MACHINE',
  3482.                                    N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
  3483.                                    N'RestartSQLServer',
  3484.                                    N'REG_DWORD',
  3485.                                     @sqlserver_restart
  3486.   IF (@jobhistory_max_rows IS NOT NULL)
  3487.     EXECUTE master.dbo.xp_regwrite N'HKEY_LOCAL_MACHINE',
  3488.                                    N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
  3489.                                    N'JobHistoryMaxRows',
  3490.                                    N'REG_DWORD',
  3491.                                     @jobhistory_max_rows
  3492.   IF (@jobhistory_max_rows_per_job IS NOT NULL)
  3493.     EXECUTE master.dbo.xp_regwrite N'HKEY_LOCAL_MACHINE',
  3494.                                    N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
  3495.                                    N'JobHistoryMaxRowsPerJob',
  3496.                                    N'REG_DWORD',
  3497.                                     @jobhistory_max_rows_per_job
  3498.   IF (@errorlog_file IS NOT NULL)
  3499.     EXECUTE master.dbo.xp_regwrite N'HKEY_LOCAL_MACHINE',
  3500.                                    N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
  3501.                                    N'ErrorLogFile',
  3502.                                    N'REG_SZ',
  3503.                                     @errorlog_file
  3504.   IF (@errorlogging_level IS NOT NULL)
  3505.     EXECUTE master.dbo.xp_regwrite N'HKEY_LOCAL_MACHINE',
  3506.                                    N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
  3507.                                    N'ErrorLoggingLevel',
  3508.                                    N'REG_DWORD',
  3509.                                     @errorlogging_level
  3510.   IF (@error_recipient IS NOT NULL)
  3511.     EXECUTE master.dbo.xp_regwrite N'HKEY_LOCAL_MACHINE',
  3512.                                    N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
  3513.                                    N'ErrorMonitor',
  3514.                                    N'REG_SZ',
  3515.                                     @error_recipient
  3516.   IF (@monitor_autostart IS NOT NULL)
  3517.     EXECUTE master.dbo.xp_regwrite N'HKEY_LOCAL_MACHINE',
  3518.                                    N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
  3519.                                    N'MonitorAutoStart',
  3520.                                    N'REG_DWORD',
  3521.                                     @monitor_autostart
  3522.   IF (@local_host_server IS NOT NULL)
  3523.     EXECUTE master.dbo.xp_regwrite N'HKEY_LOCAL_MACHINE',
  3524.                                    N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
  3525.                                    N'ServerHost',
  3526.                                    N'REG_SZ',
  3527.                                     @local_host_server
  3528.   IF (@job_shutdown_timeout IS NOT NULL)
  3529.     EXECUTE master.dbo.xp_regwrite N'HKEY_LOCAL_MACHINE',
  3530.                                    N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
  3531.                                    N'JobShutdownTimeout',
  3532.                                    N'REG_DWORD',
  3533.                                     @job_shutdown_timeout
  3534.   IF (@cmdexec_account IS NOT NULL)
  3535.     EXECUTE master.dbo.xp_regwrite N'HKEY_LOCAL_MACHINE',
  3536.                                    N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
  3537.                                    N'CmdExecAccount',
  3538.                                    N'REG_BINARY',
  3539.                                     @cmdexec_account
  3540.   IF (@regular_connections IS NOT NULL)
  3541.     EXECUTE master.dbo.xp_regwrite N'HKEY_LOCAL_MACHINE',
  3542.                                    N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
  3543.                                    N'RegularConnections',
  3544.                                    N'REG_DWORD',
  3545.                                     @regular_connections
  3546.   IF (@host_login_name IS NOT NULL)
  3547.     EXECUTE master.dbo.xp_regwrite N'HKEY_LOCAL_MACHINE',
  3548.                                    N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
  3549.                                    N'HostLoginID',
  3550.                                    N'REG_SZ',
  3551.                                     @host_login_name
  3552.   IF (@host_login_password IS NOT NULL)
  3553.     EXECUTE master.dbo.xp_regwrite N'HKEY_LOCAL_MACHINE',
  3554.                                    N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
  3555.                                    N'HostPassword',
  3556.                                    N'REG_BINARY',
  3557.                                     @host_login_password
  3558.   IF (@login_timeout IS NOT NULL)
  3559.     EXECUTE master.dbo.xp_regwrite N'HKEY_LOCAL_MACHINE',
  3560.                                    N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
  3561.                                    N'LoginTimeout',
  3562.                                    N'REG_DWORD',
  3563.                                     @login_timeout
  3564.   IF (@idle_cpu_percent IS NOT NULL)
  3565.     EXECUTE master.dbo.xp_regwrite N'HKEY_LOCAL_MACHINE',
  3566.                                    N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
  3567.                                    N'IdleCPUPercent',
  3568.                                    N'REG_DWORD',
  3569.                                     @idle_cpu_percent
  3570.   IF (@idle_cpu_duration IS NOT NULL)
  3571.     EXECUTE master.dbo.xp_regwrite N'HKEY_LOCAL_MACHINE',
  3572.                                    N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
  3573.                                    N'IdleCPUDuration',
  3574.                                    N'REG_DWORD',
  3575.                                     @idle_cpu_duration
  3576.   IF (@oem_errorlog IS NOT NULL)
  3577.     EXECUTE master.dbo.xp_regwrite N'HKEY_LOCAL_MACHINE',
  3578.                                    N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
  3579.                                    N'OemErrorLog',
  3580.                                    N'REG_DWORD',
  3581.                                     @oem_errorlog
  3582.   IF (@sysadmin_only IS NOT NULL)
  3583.     EXECUTE master.dbo.xp_regwrite N'HKEY_LOCAL_MACHINE',
  3584.                                    N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
  3585.                                    N'SysAdminOnly',
  3586.                                    N'REG_DWORD',
  3587.                                     @sysadmin_only
  3588.   IF (@email_profile IS NOT NULL)
  3589.     EXECUTE master.dbo.xp_regwrite N'HKEY_LOCAL_MACHINE',
  3590.                                    N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
  3591.                                    N'EmailProfile',
  3592.                                    N'REG_SZ',
  3593.                                     @email_profile
  3594.   IF (@email_save_in_sent_folder IS NOT NULL)
  3595.     EXECUTE master.dbo.xp_regwrite N'HKEY_LOCAL_MACHINE',
  3596.                                    N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
  3597.                                    N'EmailSaveSent',
  3598.                                    N'REG_DWORD',
  3599.                                     @email_save_in_sent_folder
  3600.   IF (@cpu_poller_enabled IS NOT NULL)
  3601.   BEGIN
  3602.     EXECUTE master.dbo.xp_regread N'HKEY_LOCAL_MACHINE',
  3603.                                   N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
  3604.                                   N'CoreEngineMask',
  3605.                                    @existing_core_engine_mask OUTPUT,
  3606.                                   N'no_output'
  3607.     IF ((@existing_core_engine_mask IS NOT NULL) OR (@cpu_poller_enabled = 1))
  3608.     BEGIN
  3609.       IF (@cpu_poller_enabled = 1)
  3610.         SELECT @cpu_poller_enabled = (ISNULL(@existing_core_engine_mask, 0) & ~32)
  3611.       ELSE
  3612.         SELECT @cpu_poller_enabled = (ISNULL(@existing_core_engine_mask, 0) | 32)
  3613.  
  3614.       IF ((@existing_core_engine_mask IS NOT NULL) AND (@cpu_poller_enabled = 32))
  3615.         EXECUTE master.dbo.xp_regdeletevalue N'HKEY_LOCAL_MACHINE',
  3616.                                              N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
  3617.                                              N'CoreEngineMask'
  3618.       ELSE
  3619.         EXECUTE master.dbo.xp_regwrite N'HKEY_LOCAL_MACHINE',
  3620.                                        N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
  3621.                                        N'CoreEngineMask',
  3622.                                        N'REG_DWORD',
  3623.                                         @cpu_poller_enabled
  3624.     END
  3625.   END
  3626.  
  3627.   RETURN(0) -- Success
  3628. END
  3629. go
  3630.  
  3631. /**************************************************************/
  3632. /* SP_ADD_TARGETSERVERGROUP                                   */
  3633. /**************************************************************/
  3634.  
  3635. PRINT ''
  3636. PRINT 'Creating procedure sp_add_targetservergroup...'
  3637. go
  3638. IF (EXISTS (SELECT *
  3639.             FROM msdb.dbo.sysobjects
  3640.             WHERE (name = N'sp_add_targetservergroup')
  3641.               AND (type = 'P')))
  3642.   DROP PROCEDURE sp_add_targetservergroup
  3643. go
  3644. CREATE PROCEDURE sp_add_targetservergroup
  3645.   @name sysname
  3646. AS
  3647. BEGIN
  3648.   SET NOCOUNT ON
  3649.  
  3650.   -- Only a sysadmin can do this
  3651.   IF (ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) <> 1)
  3652.   BEGIN
  3653.     RAISERROR(15003, 16, 1, N'sysadmin')
  3654.     RETURN(1) -- Failure
  3655.   END
  3656.  
  3657.   -- Remove any leading/trailing spaces from parameters
  3658.   SELECT @name = LTRIM(RTRIM(@name))
  3659.  
  3660.   -- Check if the group already exists
  3661.   IF (EXISTS (SELECT *
  3662.               FROM msdb.dbo.systargetservergroups
  3663.               WHERE name = @name))
  3664.   BEGIN
  3665.     RAISERROR(14261, -1, -1, '@name', @name)
  3666.     RETURN(1) -- Failure
  3667.   END
  3668.  
  3669.   -- Disallow names with commas in them (since sp_apply_job_to_targets parses a comma-separated list of group names)
  3670.   IF (@name LIKE N'%,%')
  3671.   BEGIN
  3672.     RAISERROR(14289, -1, -1, '@name', ',')
  3673.     RETURN(1) -- Failure
  3674.   END
  3675.  
  3676.   INSERT INTO msdb.dbo.systargetservergroups (name)
  3677.   VALUES (@name)
  3678.  
  3679.   RETURN(@@error) -- 0 means success
  3680. END
  3681. go
  3682.  
  3683. /**************************************************************/
  3684. /* SP_UPDATE_TARGETSERVERGROUP                                */
  3685. /**************************************************************/
  3686.  
  3687. PRINT ''
  3688. PRINT 'Creating procedure sp_update_targetservergroup...'
  3689. go
  3690. IF (EXISTS (SELECT *
  3691.             FROM msdb.dbo.sysobjects
  3692.             WHERE (name = N'sp_update_targetservergroup')
  3693.               AND (type = 'P')))
  3694.   DROP PROCEDURE sp_update_targetservergroup
  3695. go
  3696. CREATE PROCEDURE sp_update_targetservergroup
  3697.   @name     sysname,
  3698.   @new_name sysname
  3699. AS
  3700. BEGIN
  3701.   SET NOCOUNT ON
  3702.  
  3703.   -- Only a sysadmin can do this
  3704.   IF (ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) <> 1)
  3705.   BEGIN
  3706.     RAISERROR(15003, 16, 1, N'sysadmin')
  3707.     RETURN(1) -- Failure
  3708.   END
  3709.  
  3710.   -- Remove any leading/trailing spaces from parameters
  3711.   SELECT @name     = LTRIM(RTRIM(@name))
  3712.   SELECT @new_name = LTRIM(RTRIM(@new_name))
  3713.  
  3714.   -- Check if the group exists
  3715.   IF (NOT EXISTS (SELECT *
  3716.                   FROM msdb.dbo.systargetservergroups
  3717.                   WHERE (name = @name)))
  3718.   BEGIN
  3719.     RAISERROR(14262, -1, -1, '@name', @name)
  3720.     RETURN(1) -- Failure
  3721.   END
  3722.  
  3723.   -- Check if a group with the new name already exists
  3724.   IF (EXISTS (SELECT *
  3725.               FROM msdb.dbo.systargetservergroups
  3726.               WHERE (name = @new_name)))
  3727.   BEGIN
  3728.     RAISERROR(14261, -1, -1, '@new_name', @new_name)
  3729.     RETURN(1) -- Failure
  3730.   END
  3731.  
  3732.   -- Disallow names with commas in them (since sp_apply_job_to_targets parses a comma-separated list of group names)
  3733.   IF (@new_name LIKE N'%,%')
  3734.   BEGIN
  3735.     RAISERROR(14289, -1, -1, '@new_name', ',')
  3736.     RETURN(1) -- Failure
  3737.   END
  3738.  
  3739.   -- Update the group's name
  3740.   UPDATE msdb.dbo.systargetservergroups
  3741.   SET name = @new_name
  3742.   WHERE (name = @name)
  3743.  
  3744.   RETURN(@@error) -- 0 means success
  3745. END
  3746. go
  3747.  
  3748. /**************************************************************/
  3749. /* SP_DELETE_TARGETSERVERGROUP                                */
  3750. /**************************************************************/
  3751.  
  3752. PRINT ''
  3753. PRINT 'Creating procedure sp_delete_targetservergroup...'
  3754. go
  3755. IF (EXISTS (SELECT *
  3756.             FROM msdb.dbo.sysobjects
  3757.             WHERE (name = N'sp_delete_targetservergroup')
  3758.               AND (type = 'P')))
  3759.   DROP PROCEDURE sp_delete_targetservergroup
  3760. go
  3761. CREATE PROCEDURE sp_delete_targetservergroup
  3762.   @name sysname
  3763. AS
  3764. BEGIN
  3765.   DECLARE @servergroup_id INT
  3766.  
  3767.   SET NOCOUNT ON
  3768.  
  3769.   -- Only a sysadmin can do this
  3770.   IF (ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) <> 1)
  3771.   BEGIN
  3772.     RAISERROR(15003, 16, 1, N'sysadmin')
  3773.     RETURN(1) -- Failure
  3774.   END
  3775.  
  3776.   -- Remove any leading/trailing spaces from parameters
  3777.   SELECT @name = LTRIM(RTRIM(@name))
  3778.  
  3779.   -- Check if the group exists
  3780.   SELECT @servergroup_id = servergroup_id
  3781.   FROM msdb.dbo.systargetservergroups
  3782.   WHERE (name = @name)
  3783.  
  3784.   IF (@servergroup_id IS NULL)
  3785.   BEGIN
  3786.     RAISERROR(14262, -1, -1, '@name', @name)
  3787.     RETURN(1) -- Failure
  3788.   END
  3789.  
  3790.   -- Remove the group members
  3791.   DELETE FROM msdb.dbo.systargetservergroupmembers
  3792.   WHERE (servergroup_id = @servergroup_id)
  3793.  
  3794.   -- Remove the group
  3795.   DELETE FROM msdb.dbo.systargetservergroups
  3796.   WHERE (name = @name)
  3797.  
  3798.   RETURN(@@error) -- 0 means success
  3799. END
  3800. go
  3801.  
  3802. /**************************************************************/
  3803. /* SP_HELP_TARGETSERVERGROUP                                  */
  3804. /**************************************************************/
  3805.  
  3806. PRINT ''
  3807. PRINT 'Creating procedure sp_help_targetservergroup...'
  3808. go
  3809. IF (EXISTS (SELECT *
  3810.             FROM msdb.dbo.sysobjects
  3811.             WHERE (name = N'sp_help_targetservergroup')
  3812.               AND (type = 'P')))
  3813.   DROP PROCEDURE sp_help_targetservergroup
  3814. go
  3815. CREATE PROCEDURE sp_help_targetservergroup
  3816.   @name sysname = NULL
  3817. AS
  3818. BEGIN
  3819.   DECLARE @servergroup_id INT
  3820.  
  3821.   SET NOCOUNT ON
  3822.  
  3823.   -- Remove any leading/trailing spaces from parameters
  3824.   SELECT @name = LTRIM(RTRIM(@name))
  3825.  
  3826.   IF (@name IS NULL)
  3827.   BEGIN
  3828.     -- Show all groups
  3829.     SELECT servergroup_id, name
  3830.     FROM msdb.dbo.systargetservergroups
  3831.     RETURN(@@error) -- 0 means success
  3832.   END
  3833.   ELSE
  3834.   BEGIN
  3835.     -- Check if the group exists
  3836.     SELECT @servergroup_id = servergroup_id
  3837.     FROM msdb.dbo.systargetservergroups
  3838.     WHERE (name = @name)
  3839.  
  3840.     IF (@servergroup_id IS NULL)
  3841.     BEGIN
  3842.       RAISERROR(14262, -1, -1, '@name', @name)
  3843.       RETURN(1) -- Failure
  3844.     END
  3845.  
  3846.     -- Return the members of the group
  3847.     SELECT sts.server_id,
  3848.            sts.server_name
  3849.     FROM msdb.dbo.systargetservers sts,
  3850.          msdb.dbo.systargetservergroupmembers stsgm
  3851.     WHERE (stsgm.servergroup_id = @servergroup_id)
  3852.       AND (stsgm.server_id = sts.server_id)
  3853.  
  3854.     RETURN(@@error) -- 0 means success
  3855.   END
  3856. END
  3857. go
  3858.  
  3859. /**************************************************************/
  3860. /* SP_ADD_TARGETSVRGRP_MEMBER                                 */
  3861. /**************************************************************/
  3862.  
  3863. PRINT ''
  3864. PRINT 'Creating procedure sp_add_targetsvgrp_member...'
  3865. go
  3866. IF (EXISTS (SELECT *
  3867.             FROM msdb.dbo.sysobjects
  3868.             WHERE (name = N'sp_add_targetsvrgrp_member')
  3869.               AND (type = 'P')))
  3870.   DROP PROCEDURE sp_add_targetsvrgrp_member
  3871. go
  3872. CREATE PROCEDURE sp_add_targetsvrgrp_member
  3873.   @group_name  sysname,
  3874.   @server_name NVARCHAR(30)
  3875. AS
  3876. BEGIN
  3877.   DECLARE @servergroup_id INT
  3878.   DECLARE @server_id      INT
  3879.  
  3880.   SET NOCOUNT ON
  3881.  
  3882.   -- Remove any leading/trailing spaces from parameters
  3883.   SELECT @group_name = LTRIM(RTRIM(@group_name))
  3884.   SELECT @server_name = LTRIM(RTRIM(@server_name))
  3885.  
  3886.   -- Check if the group exists
  3887.   SELECT @servergroup_id = servergroup_id
  3888.   FROM msdb.dbo.systargetservergroups
  3889.   WHERE (name = @group_name)
  3890.  
  3891.   IF (@servergroup_id IS NULL)
  3892.   BEGIN
  3893.     RAISERROR(14262, -1, -1, '@group_name', @group_name)
  3894.     RETURN(1) -- Failure
  3895.   END
  3896.  
  3897.   -- Check if the server exists
  3898.   SELECT @server_id = server_id
  3899.   FROM msdb.dbo.systargetservers
  3900.   WHERE (server_name = @server_name)
  3901.  
  3902.   IF (@server_id IS NULL)
  3903.   BEGIN
  3904.     RAISERROR(14262, -1, -1, '@server_name', @server_name)
  3905.     RETURN(1) -- Failure
  3906.   END
  3907.  
  3908.   -- Check if the server is already in this group
  3909.   IF (EXISTS (SELECT *
  3910.               FROM msdb.dbo.systargetservergroupmembers
  3911.               WHERE (servergroup_id = @servergroup_id)
  3912.                 AND (server_id = @server_id)))
  3913.   BEGIN
  3914.     RAISERROR(14263, -1, -1, @server_name, @group_name)
  3915.     RETURN(1) -- Failure
  3916.   END
  3917.  
  3918.   -- Add the row to systargetservergroupmembers
  3919.   INSERT INTO msdb.dbo.systargetservergroupmembers
  3920.   VALUES (@servergroup_id, @server_id)
  3921.  
  3922.   RETURN(@@error) -- 0 means success
  3923. END
  3924. go
  3925.  
  3926. /**************************************************************/
  3927. /* SP_DELETE_TARGETSVRGRP_MEMBER                              */
  3928. /**************************************************************/
  3929.  
  3930. PRINT ''
  3931. PRINT 'Creating procedure sp_delete_targetsvrgrp_member...'
  3932. go
  3933. IF (EXISTS (SELECT *
  3934.             FROM msdb.dbo.sysobjects
  3935.             WHERE (name = N'sp_delete_targetsvrgrp_member')
  3936.               AND (type = 'P')))
  3937.   DROP PROCEDURE sp_delete_targetsvrgrp_member
  3938. go
  3939. CREATE PROCEDURE sp_delete_targetsvrgrp_member
  3940.   @group_name  sysname,
  3941.   @server_name NVARCHAR(30)
  3942. AS
  3943. BEGIN
  3944.   DECLARE @servergroup_id INT
  3945.   DECLARE @server_id      INT
  3946.  
  3947.   SET NOCOUNT ON
  3948.  
  3949.   -- Remove any leading/trailing spaces from parameters
  3950.   SELECT @group_name = LTRIM(RTRIM(@group_name))
  3951.   SELECT @server_name = LTRIM(RTRIM(@server_name))
  3952.  
  3953.   -- Check if the group exists
  3954.   SELECT @servergroup_id = servergroup_id
  3955.   FROM msdb.dbo.systargetservergroups
  3956.   WHERE (name = @group_name)
  3957.  
  3958.   IF (@servergroup_id IS NULL)
  3959.   BEGIN
  3960.     RAISERROR(14262, -1, -1, '@group_name', @group_name)
  3961.     RETURN(1) -- Failure
  3962.   END
  3963.  
  3964.   -- Check if the server exists
  3965.   SELECT @server_id = server_id
  3966.   FROM msdb.dbo.systargetservers
  3967.   WHERE (server_name = @server_name)
  3968.  
  3969.   IF (@server_id IS NULL)
  3970.   BEGIN
  3971.     RAISERROR(14262, -1, -1, '@server_name', @server_name)
  3972.     RETURN(1) -- Failure
  3973.   END
  3974.  
  3975.   -- Check if the server is in the group
  3976.   IF (NOT EXISTS (SELECT *
  3977.                   FROM msdb.dbo.systargetservergroupmembers
  3978.                   WHERE (servergroup_id = @servergroup_id)
  3979.                     AND (server_id = @server_id)))
  3980.   BEGIN
  3981.     RAISERROR(14264, -1, -1, @server_name, @group_name)
  3982.     RETURN(1) -- Failure
  3983.   END
  3984.  
  3985.   -- Delete the row from systargetservergroupmembers
  3986.   DELETE FROM msdb.dbo.systargetservergroupmembers
  3987.   WHERE (servergroup_id = @servergroup_id)
  3988.     AND (server_id = @server_id)
  3989.  
  3990.   RETURN(@@error) -- 0 means success
  3991. END
  3992. go
  3993.  
  3994. /**************************************************************/
  3995. /* SP_VERIFY_CATEGORY                                         */
  3996. /**************************************************************/
  3997.  
  3998. PRINT ''
  3999. PRINT 'Creating procedure sp_verify_category...'
  4000. go
  4001. IF (EXISTS (SELECT *
  4002.             FROM msdb.dbo.sysobjects
  4003.             WHERE (name = N'sp_verify_category')
  4004.               AND (type = 'P')))
  4005.   DROP PROCEDURE sp_verify_category
  4006. go
  4007. CREATE PROCEDURE sp_verify_category
  4008.   @class          VARCHAR(8),
  4009.   @type           VARCHAR(12)  = NULL, -- Supply NULL only if you don't want it checked
  4010.   @name           sysname      = NULL, -- Supply NULL only if you don't want it checked
  4011.   @category_class INT OUTPUT,
  4012.   @category_type  INT OUTPUT           -- Supply NULL only if you don't want the return value
  4013. AS
  4014. BEGIN
  4015.   SET NOCOUNT ON
  4016.  
  4017.   -- Remove any leading/trailing spaces from parameters
  4018.   SELECT @class = LTRIM(RTRIM(@class))
  4019.   SELECT @type  = LTRIM(RTRIM(@type))
  4020.   SELECT @name  = LTRIM(RTRIM(@name))
  4021.  
  4022.   -- Turn [nullable] empty string parameters into NULLs
  4023.   IF (@type = '') SELECT @type = NULL
  4024.   IF (@name = N'') SELECT @name = NULL
  4025.  
  4026.   -- Check class
  4027.   SELECT @class = UPPER(@class)
  4028.   SELECT @category_class = CASE @class
  4029.                              WHEN 'JOB'      THEN 1
  4030.                              WHEN 'ALERT'    THEN 2
  4031.                              WHEN 'OPERATOR' THEN 3
  4032.                              ELSE 0
  4033.                            END
  4034.   IF (@category_class = 0)
  4035.   BEGIN
  4036.     RAISERROR(14266, -1, -1, '@class', 'JOB, ALERT, OPERATOR')
  4037.     RETURN(1) -- Failure
  4038.   END
  4039.  
  4040.   -- Check name
  4041.   IF ((@name IS NOT NULL) AND (@name = N'[DEFAULT]'))
  4042.   BEGIN
  4043.     RAISERROR(14200, -1, -1, '@name')
  4044.     RETURN(1) -- Failure
  4045.   END
  4046.  
  4047.   -- Check type [optionally]
  4048.   IF (@type IS NOT NULL)
  4049.   BEGIN
  4050.     IF (@class = 'JOB')
  4051.     BEGIN
  4052.       SELECT @type = UPPER(@type)
  4053.       SELECT @category_type = CASE @type
  4054.                                 WHEN 'LOCAL'        THEN 1
  4055.                                 WHEN 'MULTI-SERVER' THEN 2
  4056.                                 ELSE 0
  4057.                               END
  4058.       IF (@category_type = 0)
  4059.       BEGIN
  4060.         RAISERROR(14266, -1, -1, '@type', 'LOCAL, MULTI-SERVER')
  4061.         RETURN(1) -- Failure
  4062.       END
  4063.     END
  4064.     ELSE
  4065.     BEGIN
  4066.       IF (@type <> 'NONE')
  4067.       BEGIN
  4068.         RAISERROR(14266, -1, -1, '@type', 'NONE')
  4069.         RETURN(1) -- Failure
  4070.       END
  4071.       ELSE
  4072.         SELECT @category_type = 3
  4073.     END
  4074.   END
  4075.  
  4076.   RETURN(0) -- Success
  4077. END
  4078. go
  4079.  
  4080. /**************************************************************/
  4081. /* SP_ADD_CATEGORY                                            */
  4082. /**************************************************************/
  4083.  
  4084. PRINT ''
  4085. PRINT 'Creating procedure sp_add_category...'
  4086. go
  4087. IF (EXISTS (SELECT *
  4088.             FROM msdb.dbo.sysobjects
  4089.             WHERE (name = N'sp_add_category')
  4090.               AND (type = 'P')))
  4091.   DROP PROCEDURE sp_add_category
  4092. go
  4093. CREATE PROCEDURE sp_add_category
  4094.   @class VARCHAR(8)   = 'JOB',   -- JOB or ALERT or OPERATOR
  4095.   @type  VARCHAR(12)  = 'LOCAL', -- LOCAL or MULTI-SERVER (for JOB) or NONE otherwise
  4096.   @name  sysname
  4097. AS
  4098. BEGIN
  4099.   DECLARE @retval         INT
  4100.   DECLARE @category_type  INT
  4101.   DECLARE @category_class INT
  4102.  
  4103.   SET NOCOUNT ON
  4104.  
  4105.   -- Remove any leading/trailing spaces from parameters
  4106.   SELECT @class = LTRIM(RTRIM(@class))
  4107.   SELECT @type  = LTRIM(RTRIM(@type))
  4108.   SELECT @name  = LTRIM(RTRIM(@name))
  4109.  
  4110.   EXECUTE @retval = sp_verify_category @class,
  4111.                                        @type,
  4112.                                        @name,
  4113.                                        @category_class OUTPUT,
  4114.                                        @category_type  OUTPUT
  4115.   IF (@retval <> 0)
  4116.     RETURN(1) -- Failure
  4117.  
  4118.   -- Check name
  4119.   IF (EXISTS (SELECT *
  4120.               FROM msdb.dbo.syscategories
  4121.               WHERE (category_class = @category_class)
  4122.                 AND (name = @name)))
  4123.   BEGIN
  4124.     RAISERROR(14261, -1, -1, '@name', @name)
  4125.     RETURN(1) -- Failure
  4126.   END
  4127.  
  4128.   -- Add the row
  4129.   INSERT INTO msdb.dbo.syscategories (category_class, category_type, name)
  4130.   VALUES (@category_class, @category_type, @name)
  4131.  
  4132.   RETURN(@@error) -- 0 means success
  4133. END
  4134. go
  4135.  
  4136. /**************************************************************/
  4137. /* SP_UPDATE_CATEGORY                                         */
  4138. /**************************************************************/
  4139.  
  4140. PRINT ''
  4141. PRINT 'Creating procedure sp_update_category...'
  4142. go
  4143. IF (EXISTS (SELECT *
  4144.             FROM msdb.dbo.sysobjects
  4145.             WHERE (name = N'sp_update_category')
  4146.               AND (type = 'P')))
  4147.   DROP PROCEDURE sp_update_category
  4148. go
  4149. CREATE PROCEDURE sp_update_category
  4150.   @class    VARCHAR(8),  -- JOB or ALERT or OPERATOR
  4151.   @name     sysname,
  4152.   @new_name sysname
  4153. AS
  4154. BEGIN
  4155.   DECLARE @retval         INT
  4156.   DECLARE @category_id    INT
  4157.   DECLARE @category_class INT
  4158.  
  4159.   SET NOCOUNT ON
  4160.  
  4161.   -- Remove any leading/trailing spaces from parameters
  4162.   SELECT @class    = LTRIM(RTRIM(@class))
  4163.   SELECT @name     = LTRIM(RTRIM(@name))
  4164.   SELECT @new_name = LTRIM(RTRIM(@new_name))
  4165.  
  4166.   EXECUTE @retval = sp_verify_category @class,
  4167.                                        NULL,
  4168.                                        @new_name,
  4169.                                        @category_class OUTPUT,
  4170.                                        NULL
  4171.   IF (@retval <> 0)
  4172.     RETURN(1) -- Failure
  4173.  
  4174.   -- Check name
  4175.   SELECT @category_id = category_id
  4176.   FROM msdb.dbo.syscategories
  4177.   WHERE (category_class = @category_class)
  4178.     AND (name = @new_name)
  4179.   IF (@category_id IS NOT NULL)
  4180.   BEGIN
  4181.     RAISERROR(14261, -1, -1, '@new_name', @new_name)
  4182.     RETURN(1) -- Failure
  4183.   END
  4184.  
  4185.   -- Make sure that we're not updating one of the permanent categories (id's 0 - 99)
  4186.   IF (@category_id < 100)
  4187.   BEGIN
  4188.     RAISERROR(14276, -1, -1, @name, @class)
  4189.     RETURN(1) -- Failure
  4190.   END
  4191.  
  4192.   -- Update the category name
  4193.   UPDATE msdb.dbo.syscategories
  4194.   SET name = @new_name
  4195.   WHERE (category_class = @category_class)
  4196.     AND (name = @name)
  4197.  
  4198.   RETURN(@@error) -- 0 means success
  4199. END
  4200. go
  4201.  
  4202. /**************************************************************/
  4203. /* SP_DELETE_CATEGORY                                         */
  4204. /**************************************************************/
  4205.  
  4206. PRINT ''
  4207. PRINT 'Creating procedure sp_delete_category...'
  4208. go
  4209. IF (EXISTS (SELECT *
  4210.             FROM msdb.dbo.sysobjects
  4211.             WHERE (name = N'sp_delete_category')
  4212.               AND (type = 'P')))
  4213.   DROP PROCEDURE sp_delete_category
  4214. go
  4215. CREATE PROCEDURE sp_delete_category
  4216.   @class VARCHAR(8),  -- JOB or ALERT or OPERATOR
  4217.   @name  sysname
  4218. AS
  4219. BEGIN
  4220.   DECLARE @retval         INT
  4221.   DECLARE @category_id    INT
  4222.   DECLARE @category_class INT
  4223.   DECLARE @category_type  INT
  4224.  
  4225.   SET NOCOUNT ON
  4226.  
  4227.   -- Remove any leading/trailing spaces from parameters
  4228.   SELECT @class = LTRIM(RTRIM(@class))
  4229.   SELECT @name  = LTRIM(RTRIM(@name))
  4230.  
  4231.   EXECUTE @retval = sp_verify_category @class,
  4232.                                        NULL,
  4233.                                        NULL,
  4234.                                        @category_class OUTPUT,
  4235.                                        NULL
  4236.   IF (@retval <> 0)
  4237.     RETURN(1) -- Failure
  4238.  
  4239.   -- Check name
  4240.   SELECT @category_id = category_id,
  4241.          @category_type = category_type
  4242.   FROM msdb.dbo.syscategories
  4243.   WHERE (category_class = @category_class)
  4244.     AND (name = @name)
  4245.   IF (@category_id IS NULL)
  4246.   BEGIN
  4247.     RAISERROR(14262, -1, -1, '@name', @name)
  4248.     RETURN(1) -- Failure
  4249.   END
  4250.  
  4251.   -- Make sure that we're not deleting one of the permanent categories (id's 0 - 99)
  4252.   IF (@category_id < 100)
  4253.   BEGIN
  4254.     RAISERROR(14276, -1, -1, @name, @class)
  4255.     RETURN(1) -- Failure
  4256.   END
  4257.  
  4258.   BEGIN TRANSACTION
  4259.  
  4260.     -- Clean-up any Jobs that reference the deleted category
  4261.     UPDATE msdb.dbo.sysjobs
  4262.     SET category_id = CASE @category_type
  4263.                         WHEN 1 THEN 0 -- [Uncategorized (Local)]
  4264.                         WHEN 2 THEN 2 -- [Uncategorized (Multi-Server)]
  4265.                       END
  4266.     WHERE (category_id = @category_id)
  4267.  
  4268.     -- Clean-up any Alerts that reference the deleted category
  4269.     UPDATE msdb.dbo.sysalerts
  4270.     SET category_id = 98
  4271.     WHERE (category_id = @category_id)
  4272.  
  4273.     -- Clean-up any Operators that reference the deleted category
  4274.     UPDATE msdb.dbo.sysoperators
  4275.     SET category_id = 99
  4276.     WHERE (category_id = @category_id)
  4277.  
  4278.     -- Finally, delete the category itself
  4279.     DELETE FROM msdb.dbo.syscategories
  4280.     WHERE (category_id = @category_id)
  4281.  
  4282.   COMMIT TRANSACTION
  4283.  
  4284.   RETURN(0) -- Success
  4285. END
  4286. go
  4287.  
  4288. /**************************************************************/
  4289. /* SP_HELP_CATEGORY                                           */
  4290. /**************************************************************/
  4291.  
  4292. PRINT ''
  4293. PRINT 'Creating procedure sp_help_category...'
  4294. go
  4295. IF (EXISTS (SELECT *
  4296.             FROM msdb.dbo.sysobjects
  4297.             WHERE (name = N'sp_help_category')
  4298.               AND (type = 'P')))
  4299.   DROP PROCEDURE sp_help_category
  4300. go
  4301. CREATE PROCEDURE sp_help_category
  4302.   @class  VARCHAR(8)   = 'JOB', -- JOB, ALERT or OPERATOR
  4303.   @type   VARCHAR(12)  = NULL,  -- LOCAL, MULTI-SERVER, or NONE 
  4304.   @name   sysname      = NULL,
  4305.   @suffix BIT          = 0      -- 0 = no suffix, 1 = add suffix
  4306. AS
  4307. BEGIN
  4308.   DECLARE @retval         INT
  4309.   DECLARE @type_in        VARCHAR(12)
  4310.   DECLARE @category_type  INT
  4311.   DECLARE @category_class INT
  4312.   DECLARE @where_clause   NVARCHAR(255)
  4313.   DECLARE @cmd            NVARCHAR(255)
  4314.  
  4315.   SET NOCOUNT ON
  4316.  
  4317.   -- Both name and type can be NULL (this is valid, indeed it is how SQLDMO populates
  4318.   -- the JobCategory collection)
  4319.  
  4320.   -- Remove any leading/trailing spaces from parameters
  4321.   SELECT @class = LTRIM(RTRIM(@class))
  4322.   SELECT @type  = LTRIM(RTRIM(@type))
  4323.   SELECT @name  = LTRIM(RTRIM(@name))
  4324.  
  4325.   -- Turn [nullable] empty string parameters into NULLs
  4326.   IF (@type = '') SELECT @type = NULL
  4327.   IF (@name = N'') SELECT @name = NULL
  4328.  
  4329.   -- Double up any single quotes in @name
  4330.   IF (@name IS NOT NULL)
  4331.     SELECT @name = REPLACE(@name, N'''', N'''''')
  4332.  
  4333.   -- Check the type and class
  4334.   IF (@class = 'JOB') AND (@type IS NULL)
  4335.     SELECT @type_in = 'LOCAL' -- This prevents sp_verify_category from failing
  4336.   ELSE
  4337.   IF (@class <> 'JOB') AND (@type IS NULL)
  4338.     SELECT @type_in = 'NONE'
  4339.   ELSE
  4340.     SELECT @type_in = @type
  4341.  
  4342.   EXECUTE @retval = sp_verify_category @class,
  4343.                                        @type_in,
  4344.                                        NULL,
  4345.                                        @category_class OUTPUT,
  4346.                                        @category_type  OUTPUT
  4347.   IF (@retval <> 0)
  4348.     RETURN(1) -- Failure
  4349.  
  4350.   -- Make sure that 'suffix' is either 0 or 1
  4351.   IF (@suffix <> 0)
  4352.     SELECT @suffix = 1
  4353.  
  4354.   -- Build the WHERE qualifier
  4355.   SELECT @where_clause = N'WHERE (category_class = ' + CONVERT(NVARCHAR, @category_class) + N') '
  4356.   IF (@name IS NOT NULL)
  4357.     SELECT @where_clause = @where_clause + N'AND (name = N''' + @name + N''') '
  4358.   IF (@type IS NOT NULL)
  4359.     SELECT @where_clause = @where_clause + N'AND (category_type = ' + CONVERT(NVARCHAR, @category_type) + N') '
  4360.  
  4361.   -- Construct the query
  4362.   SELECT @cmd = N'SELECT category_id, '
  4363.   IF (@suffix = 1)
  4364.   BEGIN
  4365.     SELECT @cmd = @cmd + N'''category_type'' = '
  4366.     SELECT @cmd = @cmd + N'CASE category_type '
  4367.     SELECT @cmd = @cmd + N'WHEN 0 THEN ''NONE'' '
  4368.     SELECT @cmd = @cmd + N'WHEN 1 THEN ''LOCAL'' '
  4369.     SELECT @cmd = @cmd + N'WHEN 2 THEN ''MULTI-SERVER'' '
  4370.     SELECT @cmd = @cmd + N'ELSE FORMATMESSAGE(14205) '
  4371.     SELECT @cmd = @cmd + N'END, '
  4372.   END
  4373.   ELSE
  4374.   BEGIN
  4375.     SELECT @cmd = @cmd + N'category_type, '
  4376.   END
  4377.   SELECT @cmd = @cmd + N'name '
  4378.   SELECT @cmd = @cmd + N'FROM msdb.dbo.syscategories '
  4379.  
  4380.   -- Execute the query
  4381.   EXECUTE (@cmd + @where_clause + N'ORDER BY category_type, name')
  4382.  
  4383.   RETURN(@@error) -- 0 means success
  4384. END
  4385. go
  4386.  
  4387. /**************************************************************/
  4388. /* SP_DELETE_TARGETSERVER                                     */
  4389. /**************************************************************/
  4390.  
  4391. PRINT ''
  4392. PRINT 'Creating procedure sp_delete_targetserver...'
  4393. go
  4394. IF (EXISTS (SELECT *
  4395.             FROM msdb.dbo.sysobjects
  4396.             WHERE (name = N'sp_delete_targetserver')
  4397.               AND (type = 'P')))
  4398.   DROP PROCEDURE sp_delete_targetserver
  4399. go
  4400. CREATE PROCEDURE sp_delete_targetserver
  4401.   @server_name        NVARCHAR(30),
  4402.   @clear_downloadlist BIT = 1,
  4403.   @post_defection     BIT = 1
  4404. AS
  4405. BEGIN
  4406.   DECLARE @server_id INT
  4407.   DECLARE @tsx_probe NVARCHAR(50)
  4408.  
  4409.   SET NOCOUNT ON
  4410.  
  4411.   -- Remove any leading/trailing spaces from parameters
  4412.   SELECT @server_name = LTRIM(RTRIM(@server_name))
  4413.  
  4414.   -- Check server name
  4415.   SELECT @server_id = server_id
  4416.   FROM msdb.dbo.systargetservers
  4417.   WHERE (server_name = @server_name)
  4418.  
  4419.   IF (@server_id IS NULL)
  4420.   BEGIN
  4421.     RAISERROR(14262, -1, -1, '@server_name', @server_name)
  4422.     RETURN(1) -- Failure
  4423.   END
  4424.  
  4425.   -- If @post_defection is 0 then it is probable that the target server no-longer exists, so do
  4426.   -- the user/login cleanup that SQLServerAgent would have done in response to an sp_msx_defect
  4427.   IF (@post_defection = 0) 
  4428.   BEGIN
  4429.     SELECT @tsx_probe = LTRIM(RTRIM(@server_name)) + N'_msx_probe'
  4430.     IF (EXISTS (SELECT * 
  4431.                 FROM msdb.dbo.sysusers 
  4432.                 WHERE (name = @tsx_probe))) 
  4433.       EXECUTE msdb.dbo.sp_dropuser @name_in_db = @tsx_probe
  4434.     IF (EXISTS (SELECT * 
  4435.                 FROM master.dbo.syslogins 
  4436.                 WHERE (loginname = @tsx_probe))) 
  4437.       EXECUTE master.dbo.sp_droplogin @loginame = @tsx_probe
  4438.   END
  4439.  
  4440.   BEGIN TRANSACTION
  4441.  
  4442.     IF (@clear_downloadlist = 1)
  4443.     BEGIN
  4444.       DELETE FROM msdb.dbo.sysdownloadlist
  4445.       WHERE (target_server = @server_name)
  4446.     END
  4447.  
  4448.     IF (@post_defection = 1)
  4449.     BEGIN
  4450.       -- Post a defect instruction to the server
  4451.       -- NOTE: We must do this BEFORE deleting the systargetservers row
  4452.       EXECUTE msdb.dbo.sp_post_msx_operation 'DEFECT', 'SERVER', 0x00, @server_name
  4453.     END
  4454.  
  4455.     DELETE FROM msdb.dbo.systargetservers
  4456.     WHERE (server_id = @server_id)
  4457.  
  4458.     DELETE FROM msdb.dbo.systargetservergroupmembers
  4459.     WHERE (server_id = @server_id)
  4460.  
  4461.     DELETE FROM msdb.dbo.sysjobservers
  4462.     WHERE (server_id = @server_id)
  4463.  
  4464.   COMMIT TRANSACTION
  4465.  
  4466.   RETURN(@@error) -- 0 means success
  4467. END
  4468. go
  4469.  
  4470. /**************************************************************/
  4471. /* SP_HELP_TARGETSERVER                                       */
  4472. /**************************************************************/
  4473.  
  4474. PRINT ''
  4475. PRINT 'Creating procedure sp_help_targetserver...'
  4476. go
  4477. IF (EXISTS (SELECT *
  4478.             FROM msdb.dbo.sysobjects
  4479.             WHERE (name = N'sp_help_targetserver')
  4480.               AND (type = 'P')))
  4481.   DROP PROCEDURE sp_help_targetserver
  4482. go
  4483. CREATE PROCEDURE sp_help_targetserver
  4484.   @server_name NVARCHAR(30) = NULL
  4485. AS
  4486. BEGIN
  4487.   SET NOCOUNT ON
  4488.  
  4489.   -- Remove any leading/trailing spaces from parameters
  4490.   SELECT @server_name = LTRIM(RTRIM(@server_name))
  4491.  
  4492.   IF (@server_name IS NOT NULL)
  4493.   BEGIN
  4494.     IF (NOT EXISTS (SELECT *
  4495.                     FROM msdb.dbo.systargetservers
  4496.                     WHERE (server_name = @server_name)))
  4497.     BEGIN
  4498.       RAISERROR(14262, -1, -1, '@server_name', @server_name)
  4499.       RETURN(1) -- Failure
  4500.     END
  4501.   END
  4502.  
  4503.   CREATE TABLE #unread_instructions
  4504.   (
  4505.   target_server       NVARCHAR(30),
  4506.   unread_instructions INT
  4507.   )
  4508.  
  4509.   INSERT INTO #unread_instructions
  4510.   SELECT target_server, COUNT(*)
  4511.   FROM msdb.dbo.sysdownloadlist
  4512.   WHERE (status = 0)
  4513.   GROUP BY target_server
  4514.  
  4515.   SELECT sts.server_id,
  4516.          sts.server_name,
  4517.          sts.location,
  4518.          sts.time_zone_adjustment,
  4519.          sts.enlist_date,
  4520.          sts.last_poll_date,
  4521.         'status' = sts.status |
  4522.                    CASE WHEN DATEDIFF(ss, sts.last_poll_date, GETDATE()) > (3 * sts.poll_interval) THEN 0x2 ELSE 0 END |
  4523.                    CASE WHEN ((SELECT COUNT(*)
  4524.                                FROM msdb.dbo.sysdownloadlist sdl
  4525.                                WHERE (sdl.target_server = sts.server_name)
  4526.                                  AND (sdl.error_message IS NOT NULL)) > 0) THEN 0x4 ELSE 0 END,
  4527.         'unread_instructions' = ISNULL(ui.unread_instructions, 0),
  4528.         'local_time' = DATEADD(SS, DATEDIFF(SS, sts.last_poll_date, GETDATE()), sts.local_time_at_last_poll),
  4529.         sts.enlisted_by_nt_user,
  4530.         sts.poll_interval
  4531.   FROM msdb.dbo.systargetservers sts LEFT OUTER JOIN
  4532.        #unread_instructions      ui  ON (sts.server_name = ui.target_server)
  4533.   WHERE ((@server_name IS NULL) OR (sts.server_name = @server_name))
  4534.   ORDER BY server_name
  4535.  
  4536.   RETURN(@@error) -- 0 means success
  4537. END
  4538. go
  4539.  
  4540. /**************************************************************/
  4541. /* SP_RESYNC_TARGETSERVER                                     */
  4542. /**************************************************************/
  4543.  
  4544. PRINT ''
  4545. PRINT 'Creating procedure sp_resync_targetserver...'
  4546. go
  4547. IF (EXISTS (SELECT *
  4548.             FROM msdb.dbo.sysobjects
  4549.             WHERE (name = N'sp_resync_targetserver')
  4550.               AND (type = 'P')))
  4551.   DROP PROCEDURE sp_resync_targetserver
  4552. go
  4553. CREATE PROCEDURE sp_resync_targetserver
  4554.   @server_name NVARCHAR(30)
  4555. AS
  4556. BEGIN
  4557.   SET NOCOUNT ON
  4558.  
  4559.   -- Only a sysadmin can do this
  4560.   IF (ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) <> 1)
  4561.   BEGIN
  4562.     RAISERROR(15003, 16, 1, N'sysadmin')
  4563.     RETURN(1) -- Failure
  4564.   END
  4565.  
  4566.   -- Remove any leading/trailing spaces from parameters
  4567.   SELECT @server_name = LTRIM(RTRIM(@server_name))
  4568.  
  4569.   IF (@server_name <> N'ALL')
  4570.   BEGIN
  4571.     IF (NOT EXISTS (SELECT *
  4572.                     FROM msdb.dbo.systargetservers
  4573.                     WHERE (server_name = @server_name)))
  4574.     BEGIN
  4575.       RAISERROR(14262, -1, -1, '@server_name', @server_name)
  4576.       RETURN(1) -- Failure
  4577.     END
  4578.  
  4579.     -- We want the target server to:
  4580.     -- a) delete all their current MSX jobs, and
  4581.     -- b) download all their jobs again.
  4582.     -- So we delete all the current instructions and post a new set
  4583.     DELETE FROM msdb.dbo.sysdownloadlist
  4584.     WHERE (target_server = @server_name)
  4585.     EXECUTE msdb.dbo.sp_post_msx_operation 'DELETE', 'JOB', 0x00, @server_name
  4586.     EXECUTE msdb.dbo.sp_post_msx_operation 'INSERT', 'JOB', 0x00, @server_name
  4587.   END
  4588.   ELSE
  4589.   BEGIN
  4590.     -- We want ALL target servers to:
  4591.     -- a) delete all their current MSX jobs, and
  4592.     -- b) download all their jobs again.
  4593.     -- So we delete all the current instructions and post a new set
  4594.     TRUNCATE TABLE msdb.dbo.sysdownloadlist
  4595.     EXECUTE msdb.dbo.sp_post_msx_operation 'DELETE', 'JOB', 0x00, NULL
  4596.     EXECUTE msdb.dbo.sp_post_msx_operation 'INSERT', 'JOB', 0x00, NULL
  4597.   END
  4598.  
  4599.   RETURN(@@error) -- 0 means success
  4600. END
  4601. go
  4602.  
  4603. DUMP TRANSACTION msdb WITH NO_LOG
  4604. go
  4605. CHECKPOINT
  4606. go
  4607.  
  4608. /**************************************************************/
  4609. /* SP_PURGE_JOBHISTORY                                        */
  4610. /**************************************************************/
  4611.  
  4612. PRINT ''
  4613. PRINT 'Creating procedure sp_purge_jobhistory...'
  4614. go
  4615. IF (EXISTS (SELECT *
  4616.             FROM msdb.dbo.sysobjects
  4617.             WHERE (name = N'sp_purge_jobhistory')
  4618.               AND (type = 'P')))
  4619.   DROP PROCEDURE sp_purge_jobhistory
  4620. go
  4621. CREATE PROCEDURE sp_purge_jobhistory
  4622.   @job_name sysname          = NULL,
  4623.   @job_id   UNIQUEIDENTIFIER = NULL
  4624. AS
  4625. BEGIN
  4626.   DECLARE @rows_affected INT
  4627.   DECLARE @total_rows    INT
  4628.   DECLARE @retval        INT
  4629.   DECLARE @category_id   INT
  4630.  
  4631.   SET NOCOUNT ON
  4632.  
  4633.   IF ((@job_name IS NOT NULL) OR (@job_id IS NOT NULL))
  4634.   BEGIN
  4635.     EXECUTE @retval = sp_verify_job_identifiers '@job_name',
  4636.                                                 '@job_id',
  4637.                                                  @job_name OUTPUT,
  4638.                                                  @job_id   OUTPUT
  4639.     IF (@retval <> 0)
  4640.       RETURN(1) -- Failure
  4641.  
  4642.     -- Get category to see if it is a misc. replication agent. @category_id will be
  4643.     -- NULL if there is no @job_id.
  4644.     select @category_id = category_id from msdb.dbo.sysjobs where job_id = @job_id
  4645.  
  4646.     -- Delete the histories for this job
  4647.     DELETE FROM msdb.dbo.sysjobhistory
  4648.     WHERE (job_id = @job_id)
  4649.     SELECT @rows_affected = @@rowcount
  4650.  
  4651.     -- If misc. replication job, then update global replication status table
  4652.     IF (@category_id IN (11, 12, 16, 17, 18))
  4653.     BEGIN
  4654.       -- Nothing can be done if this fails, so don't worry about the return code
  4655.       EXECUTE master.dbo.sp_MSupdate_replication_status
  4656.         @publisher = '',
  4657.         @publisher_db = '',
  4658.         @publication = '',
  4659.         @publication_type = -1,
  4660.         @agent_type = 5,
  4661.         @agent_name = @job_name,
  4662.         @status = -1 -- Delete
  4663.     END
  4664.   END
  4665.   ELSE
  4666.   BEGIN
  4667.     -- Only a sysadmin can do this
  4668.     IF (ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) <> 1)
  4669.     BEGIN
  4670.       RAISERROR(15003, 16, 1, N'sysadmin')
  4671.       RETURN(1) -- Failure
  4672.     END
  4673.  
  4674.     SELECT @total_rows = COUNT(*)
  4675.     FROM msdb.dbo.sysjobhistory
  4676.     SELECT @rows_affected = @total_rows
  4677.     TRUNCATE TABLE msdb.dbo.sysjobhistory
  4678.  
  4679.     -- Remove all misc. replication jobs from global replication status table
  4680.     -- Nothing can be done if this fails, so don't worry about the return code
  4681.     EXECUTE master.dbo.sp_MSupdate_replication_status
  4682.       @publisher = '',
  4683.       @publisher_db = '',
  4684.       @publication = '',
  4685.       @publication_type = -1,
  4686.       @agent_type = 5,
  4687.       @agent_name = '%',
  4688.       @status = -1 -- Delete
  4689.   END
  4690.   RAISERROR(14226, 0, 1, @rows_affected)
  4691.  
  4692.   RETURN(0) -- Success
  4693. END
  4694. go
  4695.  
  4696. /**************************************************************/
  4697. /* SP_VERIFY_JOB_DATE                                         */
  4698. /**************************************************************/
  4699.  
  4700. PRINT ''
  4701. PRINT 'Creating procedure sp_verify_job_date...'
  4702. go
  4703. IF (EXISTS (SELECT *
  4704.             FROM msdb.dbo.sysobjects
  4705.             WHERE (name = N'sp_verify_job_date')
  4706.               AND (type = 'P')))
  4707.   DROP PROCEDURE sp_verify_job_date
  4708. go
  4709. CREATE PROCEDURE sp_verify_job_date
  4710.   @date           INT,
  4711.   @date_name      VARCHAR(60) = 'date',
  4712.   @error_severity INT         = -1
  4713. AS
  4714. BEGIN
  4715.   SET NOCOUNT ON
  4716.  
  4717.   -- Remove any leading/trailing spaces from parameters
  4718.   SELECT @date_name = LTRIM(RTRIM(@date_name))
  4719.  
  4720.   IF ((ISDATE(CONVERT(VARCHAR, @date)) = 0) OR (@date < 19900101) OR (@date > 99991231))
  4721.   BEGIN
  4722.     RAISERROR(14266, @error_severity, -1, @date_name, '19900101..99991231')
  4723.     RETURN(1) -- Failure
  4724.   END
  4725.  
  4726.   RETURN(0) -- Success
  4727. END
  4728. go
  4729.  
  4730. /**************************************************************/
  4731. /* SP_VERIFY_JOB_TIME                                         */
  4732. /**************************************************************/
  4733.  
  4734. PRINT ''
  4735. PRINT 'Creating procedure sp_verify_job_time...'
  4736. go
  4737. IF (EXISTS (SELECT *
  4738.             FROM msdb.dbo.sysobjects
  4739.             WHERE (name = N'sp_verify_job_time')
  4740.               AND (type = 'P')))
  4741.   DROP PROCEDURE sp_verify_job_time
  4742. go
  4743.  
  4744. CREATE PROCEDURE sp_verify_job_time
  4745.   @time           INT,
  4746.   @time_name      VARCHAR(60) = 'time',
  4747.   @error_severity INT = -1
  4748. AS
  4749. BEGIN
  4750.   DECLARE @hour      INT
  4751.   DECLARE @minute    INT
  4752.   DECLARE @second    INT
  4753.   DECLARE @part_name NVARCHAR(50)
  4754.  
  4755.   SET NOCOUNT ON
  4756.  
  4757.   -- Remove any leading/trailing spaces from parameters
  4758.   SELECT @time_name = LTRIM(RTRIM(@time_name))
  4759.  
  4760.   IF ((@time < 0) OR (@time > 235959))
  4761.   BEGIN
  4762.     RAISERROR(14266, @error_severity, -1, @time_name, '000000..235959')
  4763.     RETURN(1) -- Failure
  4764.   END
  4765.  
  4766.   SELECT @hour   = (@time / 10000)
  4767.   SELECT @minute = (@time % 10000) / 100
  4768.   SELECT @second = (@time % 100)
  4769.  
  4770.   -- Check hour range
  4771.   IF (@hour > 23)
  4772.   BEGIN
  4773.     SELECT @part_name = FORMATMESSAGE(14218)
  4774.     RAISERROR(14287, @error_severity, -1, @time_name, @part_name)
  4775.     RETURN(1) -- Failure
  4776.   END
  4777.  
  4778.   -- Check minute range
  4779.   IF (@minute > 59)
  4780.   BEGIN
  4781.     SELECT @part_name = FORMATMESSAGE(14219)
  4782.     RAISERROR(14287, @error_severity, -1, @time_name, @part_name)
  4783.     RETURN(1) -- Failure
  4784.   END
  4785.  
  4786.   -- Check second range
  4787.   IF (@second > 59)
  4788.   BEGIN
  4789.     SELECT @part_name = FORMATMESSAGE(14220)
  4790.     RAISERROR(14287, @error_severity, -1, @time_name, @part_name)
  4791.     RETURN(1) -- Failure
  4792.   END
  4793.  
  4794.   RETURN(0) -- Success
  4795. END
  4796. go
  4797.  
  4798. /**************************************************************/
  4799. /* SP_HELP_JOBHISTORY                                         */
  4800. /**************************************************************/
  4801.  
  4802. PRINT ''
  4803. PRINT 'Creating procedure sp_help_jobhistory...'
  4804. go
  4805. IF (EXISTS (SELECT *
  4806.             FROM msdb.dbo.sysobjects
  4807.             WHERE (name = N'sp_help_jobhistory')
  4808.               AND (type = 'P')))
  4809.   DROP PROCEDURE sp_help_jobhistory
  4810. go
  4811. CREATE PROCEDURE sp_help_jobhistory
  4812.   @job_id               UNIQUEIDENTIFIER = NULL,
  4813.   @job_name             sysname          = NULL,
  4814.   @step_id              INT              = NULL,
  4815.   @sql_message_id       INT              = NULL,
  4816.   @sql_severity         INT              = NULL,
  4817.   @start_run_date       INT              = NULL,     -- YYYYMMDD
  4818.   @end_run_date         INT              = NULL,     -- YYYYMMDD
  4819.   @start_run_time       INT              = NULL,     -- HHMMSS
  4820.   @end_run_time         INT              = NULL,     -- HHMMSS
  4821.   @minimum_run_duration INT              = NULL,     -- HHMMSS
  4822.   @run_status           INT              = NULL,     -- SQLAGENT_EXEC_X code
  4823.   @minimum_retries      INT              = NULL,
  4824.   @oldest_first         INT              = 0,        -- Or 1
  4825.   @server               NVARCHAR(30)     = NULL,
  4826.   @mode                 VARCHAR(7)       = 'SUMMARY' -- Or 'FULL' or 'SEM'
  4827. AS
  4828. BEGIN
  4829.   DECLARE @retval   INT
  4830.   DECLARE @order_by INT  -- Must be INT since it can be -1
  4831.  
  4832.   SET NOCOUNT ON
  4833.  
  4834.   -- Remove any leading/trailing spaces from parameters
  4835.   SELECT @server   = LTRIM(RTRIM(@server))
  4836.   SELECT @mode     = LTRIM(RTRIM(@mode))
  4837.  
  4838.   -- Turn [nullable] empty string parameters into NULLs
  4839.   IF (@server = N'')   SELECT @server = NULL
  4840.  
  4841.   -- Check job id/name (if supplied)
  4842.   IF ((@job_id IS NOT NULL) OR (@job_name IS NOT NULL))
  4843.   BEGIN
  4844.     EXECUTE @retval = sp_verify_job_identifiers '@job_name',
  4845.                                                 '@job_id',
  4846.                                                  @job_name OUTPUT,
  4847.                                                  @job_id   OUTPUT
  4848.     IF (@retval <> 0)
  4849.       RETURN(1) -- Failure
  4850.   END
  4851.  
  4852.   -- Check @start_run_date
  4853.   IF (@start_run_date IS NOT NULL)
  4854.   BEGIN
  4855.     EXECUTE @retval = sp_verify_job_date @start_run_date, '@start_run_date'
  4856.     IF (@retval <> 0)
  4857.       RETURN(1) -- Failure
  4858.   END
  4859.  
  4860.   -- Check @end_run_date
  4861.   IF (@end_run_date IS NOT NULL)
  4862.   BEGIN
  4863.     EXECUTE @retval = sp_verify_job_date @end_run_date, '@end_run_date'
  4864.     IF (@retval <> 0)
  4865.       RETURN(1) -- Failure
  4866.   END
  4867.  
  4868.   -- Check @start_run_time
  4869.   EXECUTE @retval = sp_verify_job_time @start_run_time, '@start_run_time'
  4870.   IF (@retval <> 0)
  4871.     RETURN(1) -- Failure
  4872.  
  4873.   -- Check @end_run_time
  4874.   EXECUTE @retval = sp_verify_job_time @end_run_time, '@end_run_time'
  4875.   IF (@retval <> 0)
  4876.     RETURN(1) -- Failure
  4877.  
  4878.   -- Check @run_status
  4879.   IF ((@run_status < 0) OR (@run_status > 5))
  4880.   BEGIN
  4881.     RAISERROR(13266, -1, -1, '@run_status', '0..5')
  4882.     RETURN(1) -- Failure
  4883.   END
  4884.  
  4885.   -- Check mode
  4886.   SELECT @mode = UPPER(@mode)
  4887.   IF (@mode NOT IN ('SUMMARY', 'FULL', 'SEM'))
  4888.   BEGIN
  4889.     RAISERROR(14266, -1, -1, '@mode', 'SUMMARY, FULL, SEM')
  4890.     RETURN(1) -- Failure
  4891.   END
  4892.  
  4893.   SELECT @order_by = -1
  4894.   IF (@oldest_first = 1)
  4895.     SELECT @order_by = 1
  4896.  
  4897.   -- Return history information filtered by the supplied parameters.
  4898.   -- NOTE: SQLDMO relies on the 'FULL' format; ** DO NOT CHANGE IT **
  4899.   IF (@mode = 'FULL')
  4900.   BEGIN
  4901.     SELECT sjh.instance_id, -- This is included just for ordering purposes
  4902.            sj.job_id,
  4903.            job_name = sj.name,
  4904.            sjh.step_id,
  4905.            sjh.step_name,
  4906.            sjh.sql_message_id,
  4907.            sjh.sql_severity,
  4908.            sjh.message,
  4909.            sjh.run_status,
  4910.            sjh.run_date,
  4911.            sjh.run_time,
  4912.            sjh.run_duration,
  4913.            operator_emailed = so1.name,
  4914.            operator_netsent = so2.name,
  4915.            operator_paged = so3.name,
  4916.            sjh.retries_attempted,
  4917.            sjh.server
  4918.     FROM msdb.dbo.sysjobhistory                sjh 
  4919.          LEFT OUTER JOIN msdb.dbo.sysoperators so1  ON (sjh.operator_id_emailed = so1.id)
  4920.          LEFT OUTER JOIN msdb.dbo.sysoperators so2  ON (sjh.operator_id_netsent = so2.id)
  4921.          LEFT OUTER JOIN msdb.dbo.sysoperators so3  ON (sjh.operator_id_paged = so3.id),
  4922.          msdb.dbo.sysjobs_view                 sj
  4923.     WHERE (sj.job_id = sjh.job_id)
  4924.       AND ((@job_id               IS NULL) OR (@job_id = sjh.job_id))
  4925.       AND ((@step_id              IS NULL) OR (@step_id = sjh.step_id))
  4926.       AND ((@sql_message_id       IS NULL) OR (@sql_message_id = sjh.sql_message_id))
  4927.       AND ((@sql_severity         IS NULL) OR (@sql_severity = sjh.sql_severity))
  4928.       AND ((@start_run_date       IS NULL) OR (sjh.run_date >= @start_run_date))
  4929.       AND ((@end_run_date         IS NULL) OR (sjh.run_date <= @end_run_date))
  4930.       AND ((@start_run_time       IS NULL) OR (sjh.run_time >= @start_run_time))
  4931.       AND ((@end_run_time         IS NULL) OR (sjh.run_time <= @end_run_time))
  4932.       AND ((@minimum_run_duration IS NULL) OR (sjh.run_duration >= @minimum_run_duration))
  4933.       AND ((@run_status           IS NULL) OR (@run_status = sjh.run_status))
  4934.       AND ((@minimum_retries      IS NULL) OR (sjh.retries_attempted >= @minimum_retries))
  4935.       AND ((@server               IS NULL) OR (sjh.server = @server))
  4936.     ORDER BY (sjh.instance_id * @order_by)
  4937.   END
  4938.   ELSE
  4939.   IF (@mode = 'SUMMARY')
  4940.   BEGIN
  4941.     -- Summary format: same WHERE clause just a different SELECT list
  4942.     SELECT sj.job_id,
  4943.            job_name = sj.name,
  4944.            sjh.run_status,
  4945.            sjh.run_date,
  4946.            sjh.run_time,
  4947.            sjh.run_duration,
  4948.            operator_emailed = substring(so1.name, 1, 20),
  4949.            operator_netsent = substring(so2.name, 1, 20),
  4950.            operator_paged = substring(so3.name, 1, 20),
  4951.            sjh.retries_attempted,
  4952.            sjh.server
  4953.     FROM msdb.dbo.sysjobhistory                sjh
  4954.          LEFT OUTER JOIN msdb.dbo.sysoperators so1  ON (sjh.operator_id_emailed = so1.id)
  4955.          LEFT OUTER JOIN msdb.dbo.sysoperators so2  ON (sjh.operator_id_netsent = so2.id)
  4956.          LEFT OUTER JOIN msdb.dbo.sysoperators so3  ON (sjh.operator_id_paged = so3.id),
  4957.          msdb.dbo.sysjobs_view                 sj
  4958.     WHERE (sj.job_id = sjh.job_id)
  4959.       AND ((@job_id               IS NULL) OR (@job_id = sjh.job_id))
  4960.       AND ((@step_id              IS NULL) OR (@step_id = sjh.step_id))
  4961.       AND ((@sql_message_id       IS NULL) OR (@sql_message_id = sjh.sql_message_id))
  4962.       AND ((@sql_severity         IS NULL) OR (@sql_severity = sjh.sql_severity))
  4963.       AND ((@start_run_date       IS NULL) OR (sjh.run_date >= @start_run_date))
  4964.       AND ((@end_run_date         IS NULL) OR (sjh.run_date <= @end_run_date))
  4965.       AND ((@start_run_time       IS NULL) OR (sjh.run_time >= @start_run_time))
  4966.       AND ((@end_run_time         IS NULL) OR (sjh.run_time <= @end_run_time))
  4967.       AND ((@minimum_run_duration IS NULL) OR (sjh.run_duration >= @minimum_run_duration))
  4968.       AND ((@run_status           IS NULL) OR (@run_status = sjh.run_status))
  4969.       AND ((@minimum_retries      IS NULL) OR (sjh.retries_attempted >= @minimum_retries))
  4970.       AND ((@server               IS NULL) OR (sjh.server = @server))
  4971.     ORDER BY (sjh.instance_id * @order_by)
  4972.   END
  4973.   ELSE
  4974.   IF (@mode = 'SEM')
  4975.   BEGIN
  4976.     -- SQL Enterprise Manager format
  4977.     SELECT sjh.step_id,
  4978.            sjh.step_name,
  4979.            sjh.message,
  4980.            sjh.run_status,
  4981.            sjh.run_date,
  4982.            sjh.run_time,
  4983.            sjh.run_duration,
  4984.            operator_emailed = so1.name,
  4985.            operator_netsent = so2.name,
  4986.            operator_paged = so3.name
  4987.     FROM msdb.dbo.sysjobhistory                sjh
  4988.          LEFT OUTER JOIN msdb.dbo.sysoperators so1  ON (sjh.operator_id_emailed = so1.id)
  4989.          LEFT OUTER JOIN msdb.dbo.sysoperators so2  ON (sjh.operator_id_netsent = so2.id)
  4990.          LEFT OUTER JOIN msdb.dbo.sysoperators so3  ON (sjh.operator_id_paged = so3.id),
  4991.          msdb.dbo.sysjobs_view                 sj
  4992.     WHERE (sj.job_id = sjh.job_id)
  4993.       AND (@job_id = sjh.job_id)
  4994.     ORDER BY (sjh.instance_id * @order_by)
  4995.   END
  4996.  
  4997.   RETURN(0) -- Success
  4998. END
  4999. go
  5000.  
  5001. /**************************************************************/
  5002. /* SP_ADD_JOBSERVER                                           */
  5003. /**************************************************************/
  5004.  
  5005. PRINT ''
  5006. PRINT 'Creating procedure sp_add_jobserver...'
  5007. go
  5008. IF (EXISTS (SELECT *
  5009.             FROM msdb.dbo.sysobjects
  5010.             WHERE (name = N'sp_add_jobserver')
  5011.               AND (type = 'P')))
  5012.   DROP PROCEDURE sp_add_jobserver
  5013. go
  5014. CREATE PROCEDURE sp_add_jobserver
  5015.   @job_id         UNIQUEIDENTIFIER = NULL, -- Must provide either this or job_name
  5016.   @job_name       sysname          = NULL, -- Must provide either this or job_id
  5017.   @server_name    NVARCHAR(30)     = N'(local)',
  5018.   @automatic_post BIT = 1                  -- Flag for SEM use only
  5019. AS
  5020. BEGIN
  5021.   DECLARE @retval                    INT
  5022.   DECLARE @server_id                 INT
  5023.   DECLARE @job_type                  VARCHAR(12)
  5024.   DECLARE @current_job_category_type VARCHAR(12)
  5025.   DECLARE @msx_operator_id           INT
  5026.   DECLARE @local_machine_name        NVARCHAR(30)
  5027.   DECLARE @is_sysadmin               INT
  5028.   DECLARE @job_owner                 sysname
  5029.  
  5030.   SET NOCOUNT ON
  5031.  
  5032.   -- Remove any leading/trailing spaces from parameters
  5033.   SELECT @server_name = LTRIM(RTRIM(@server_name))
  5034.  
  5035.   EXECUTE @retval = sp_verify_job_identifiers '@job_name',
  5036.                                               '@job_id',
  5037.                                                @job_name OUTPUT,
  5038.                                                @job_id   OUTPUT
  5039.   IF (@retval <> 0)
  5040.     RETURN(1) -- Failure
  5041.  
  5042.   -- First, check if the server is the local server
  5043.   EXECUTE @retval = master.dbo.xp_getnetname @local_machine_name OUTPUT
  5044.   IF (@retval <> 0)
  5045.     RETURN(1) -- Failure
  5046.   IF (@local_machine_name IS NOT NULL) AND (UPPER(@server_name) = UPPER(@local_machine_name))
  5047.     SELECT @server_name = N'(LOCAL)'
  5048.  
  5049.   -- Only the SA can add a multi-server job
  5050.   IF (UPPER(@server_name) <> N'(LOCAL)') AND (ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) = 0)
  5051.   BEGIN
  5052.     RAISERROR(15003, 16, 1, N'sysadmin')
  5053.     RETURN(1) -- Failure
  5054.   END
  5055.  
  5056.   -- For a multi-server job...
  5057.   IF (UPPER(@server_name) <> N'(LOCAL)')
  5058.   BEGIN
  5059.     -- 1) Check if the job owner is a sysadmin
  5060.     SELECT @job_owner = SUSER_SNAME(owner_sid)
  5061.     FROM msdb.dbo.sysjobs 
  5062.     WHERE (job_id = @job_id)
  5063.     SELECT @is_sysadmin = 0
  5064.     EXECUTE msdb.dbo.sp_sqlagent_has_server_access @login_name = @job_owner, @is_sysadmin_member = @is_sysadmin OUTPUT
  5065.     IF (@is_sysadmin = 0)
  5066.     BEGIN
  5067.       RAISERROR(14544, -1, -1, @job_owner, N'sysadmin')
  5068.       RETURN(1) -- Failure
  5069.     END
  5070.  
  5071.     -- 2) Check if any of the TSQL steps have a non-null database_user_name
  5072.     IF (EXISTS (SELECT *
  5073.                 FROM msdb.dbo.sysjobsteps
  5074.                 WHERE (job_id = @job_id)
  5075.                   AND (subsystem = N'TSQL')
  5076.                   AND (database_user_name IS NOT NULL)))
  5077.     BEGIN
  5078.       RAISERROR(14542, -1, -1, N'database_user_name') 
  5079.       RETURN(1) -- Failure
  5080.     END
  5081.   END
  5082.  
  5083.   -- Check server name
  5084.   IF (UPPER(@server_name) <> N'(LOCAL)')
  5085.   BEGIN
  5086.     SELECT @server_id = server_id
  5087.     FROM msdb.dbo.systargetservers
  5088.     WHERE (server_name = @server_name)
  5089.     IF (@server_id IS NULL)
  5090.     BEGIN
  5091.       RAISERROR(14262, -1, -1, '@server_name', @server_name)
  5092.       RETURN(1) -- Failure
  5093.     END
  5094.   END
  5095.   ELSE
  5096.     SELECT @server_id = 0
  5097.  
  5098.   -- Check that this job has not already been targeted at this server
  5099.   IF (EXISTS (SELECT *
  5100.                FROM msdb.dbo.sysjobservers
  5101.                WHERE (job_id = @job_id)
  5102.                  AND (server_id = @server_id)))
  5103.   BEGIN
  5104.     RAISERROR(14269, -1, -1, @job_name, @server_name)
  5105.     RETURN(1) -- Failure
  5106.   END
  5107.  
  5108.   -- Prevent the job from being targeted at both the local AND remote servers
  5109.   SELECT @job_type = 'UNKNOWN'
  5110.   IF (EXISTS (SELECT *
  5111.               FROM msdb.dbo.sysjobservers
  5112.               WHERE (job_id = @job_id)
  5113.                 AND (server_id = 0)))
  5114.     SELECT @job_type = 'LOCAL'
  5115.   ELSE
  5116.   IF (EXISTS (SELECT *
  5117.               FROM msdb.dbo.sysjobservers
  5118.               WHERE (job_id = @job_id)
  5119.                 AND (server_id <> 0)))
  5120.     SELECT @job_type = 'MULTI-SERVER'
  5121.  
  5122.   IF ((@server_id = 0) AND (@job_type = 'MULTI-SERVER'))
  5123.   BEGIN
  5124.     RAISERROR(14290, -1, -1)
  5125.     RETURN(1) -- Failure
  5126.   END
  5127.   IF ((@server_id <> 0) AND (@job_type = 'LOCAL'))
  5128.   BEGIN
  5129.     RAISERROR(14291, -1, -1)
  5130.     RETURN(1) -- Failure
  5131.   END
  5132.  
  5133.   -- For a multi-server job, check that any notifications are to the MSXOperator
  5134.   IF (@job_type = 'MULTI-SERVER')
  5135.   BEGIN
  5136.     SELECT @msx_operator_id = id
  5137.     FROM msdb.dbo.sysoperators
  5138.     WHERE (name = N'MSXOperator')
  5139.  
  5140.     IF (EXISTS (SELECT *
  5141.                 FROM msdb.dbo.sysjobs
  5142.                 WHERE (job_id = @job_id)
  5143.                   AND (((notify_email_operator_id <> 0)   AND (notify_email_operator_id <> @msx_operator_id)) OR
  5144.                        ((notify_page_operator_id <> 0)    AND (notify_page_operator_id <> @msx_operator_id))  OR
  5145.                        ((notify_netsend_operator_id <> 0) AND (notify_netsend_operator_id <> @msx_operator_id)))))
  5146.     BEGIN
  5147.       RAISERROR(14221, -1, -1, 'MSXOperator')
  5148.       RETURN(1) -- Failure
  5149.     END
  5150.   END
  5151.  
  5152.   -- Insert the sysjobservers row
  5153.   INSERT INTO msdb.dbo.sysjobservers
  5154.          (job_id,
  5155.           server_id,
  5156.           last_run_outcome,
  5157.           last_outcome_message,
  5158.           last_run_date,
  5159.           last_run_time,
  5160.           last_run_duration)
  5161.   VALUES (@job_id,
  5162.           @server_id,
  5163.           5,  -- ie. SQLAGENT_EXEC_UNKNOWN (can't use 0 since this is SQLAGENT_EXEC_FAIL)
  5164.           NULL,
  5165.           0,
  5166.           0,
  5167.           0)
  5168.  
  5169.   -- Re-categorize the job (if necessary)
  5170.   SELECT @current_job_category_type = CASE category_type
  5171.                                         WHEN 1 THEN 'LOCAL'
  5172.                                         WHEN 2 THEN 'MULTI-SERVER'
  5173.                                       END
  5174.   FROM msdb.dbo.sysjobs_view  sjv,
  5175.        msdb.dbo.syscategories sc
  5176.   WHERE (sjv.category_id = sc.category_id)
  5177.     AND (sjv.job_id = @job_id)
  5178.  
  5179.   IF (@server_id = 0) AND (@current_job_category_type = 'MULTI-SERVER')
  5180.   BEGIN
  5181.     UPDATE msdb.dbo.sysjobs
  5182.     SET category_id = 0 -- [Uncategorized (Local)]
  5183.     WHERE (job_id = @job_id)
  5184.   END
  5185.   IF (@server_id <> 0) AND (@current_job_category_type = 'LOCAL')
  5186.   BEGIN
  5187.     UPDATE msdb.dbo.sysjobs
  5188.     SET category_id = 2 -- [Uncategorized (Multi-Server)]
  5189.     WHERE (job_id = @job_id)
  5190.   END
  5191.  
  5192.   -- Instruct the new server to pick up the job
  5193.   IF (@automatic_post = 1)
  5194.     EXECUTE @retval = sp_post_msx_operation 'INSERT', 'JOB', @job_id, @server_name
  5195.  
  5196.   -- If the job is local, make sure that SQLServerAgent caches it
  5197.   IF (@server_id = 0)
  5198.   BEGIN
  5199.     EXECUTE msdb.dbo.sp_sqlagent_notify @op_type     = N'J',
  5200.                                         @job_id      = @job_id,
  5201.                                         @action_type = N'I'
  5202.   END
  5203.  
  5204.   RETURN(@retval) -- 0 means success
  5205. END
  5206. go
  5207.  
  5208. /**************************************************************/
  5209. /* SP_DELETE_JOBSERVER                                        */
  5210. /**************************************************************/
  5211.  
  5212. PRINT ''
  5213. PRINT 'Creating procedure sp_delete_jobserver...'
  5214. go
  5215. IF (EXISTS (SELECT *
  5216.             FROM msdb.dbo.sysobjects
  5217.             WHERE (name = N'sp_delete_jobserver')
  5218.               AND (type = 'P')))
  5219.   DROP PROCEDURE sp_delete_jobserver
  5220. go
  5221. CREATE PROCEDURE sp_delete_jobserver
  5222.   @job_id      UNIQUEIDENTIFIER = NULL, -- Must provide either this or job_name
  5223.   @job_name    sysname          = NULL, -- Must provide either this or job_id
  5224.   @server_name NVARCHAR(30)
  5225. AS
  5226. BEGIN
  5227.   DECLARE @retval             INT
  5228.   DECLARE @server_id          INT
  5229.   DECLARE @local_machine_name NVARCHAR(30)
  5230.  
  5231.   SET NOCOUNT ON
  5232.  
  5233.   -- Remove any leading/trailing spaces from parameters
  5234.   SELECT @server_name = LTRIM(RTRIM(@server_name))
  5235.  
  5236.   EXECUTE @retval = sp_verify_job_identifiers '@job_name',
  5237.                                               '@job_id',
  5238.                                                @job_name OUTPUT,
  5239.                                                @job_id   OUTPUT
  5240.   IF (@retval <> 0)
  5241.     RETURN(1) -- Failure
  5242.  
  5243.   -- First, check if the server is the local server
  5244.   EXECUTE @retval = master.dbo.xp_getnetname @local_machine_name OUTPUT
  5245.   IF (@retval <> 0)
  5246.     RETURN(1) -- Failure
  5247.   IF (@local_machine_name IS NOT NULL) AND (UPPER(@server_name) = UPPER(@local_machine_name))
  5248.     SELECT @server_name = N'(LOCAL)'
  5249.  
  5250.   -- Check server name
  5251.   IF (UPPER(@server_name) <> N'(LOCAL)')
  5252.   BEGIN
  5253.     SELECT @server_id = server_id
  5254.     FROM msdb.dbo.systargetservers
  5255.     WHERE (server_name = @server_name)
  5256.     IF (@server_id IS NULL)
  5257.     BEGIN
  5258.       RAISERROR(14262, -1, -1, '@server_name', @server_name)
  5259.       RETURN(1) -- Failure
  5260.     END
  5261.   END
  5262.   ELSE
  5263.     SELECT @server_id = 0
  5264.  
  5265.   -- Check that the job is indeed targeted at the server
  5266.   IF (NOT EXISTS (SELECT *
  5267.                   FROM msdb.dbo.sysjobservers
  5268.                   WHERE (job_id = @job_id)
  5269.                     AND (server_id = @server_id)))
  5270.   BEGIN
  5271.     RAISERROR(14270, -1, -1, @job_name, @server_name)
  5272.     RETURN(1) -- Failure
  5273.   END
  5274.  
  5275.   -- Instruct the deleted server to purge the job
  5276.   -- NOTE: We must do this BEFORE we delete the sysjobservers row
  5277.   EXECUTE @retval = sp_post_msx_operation 'DELETE', 'JOB', @job_id, @server_name
  5278.  
  5279.   -- Delete the sysjobservers row
  5280.   DELETE FROM msdb.dbo.sysjobservers
  5281.   WHERE (job_id = @job_id)
  5282.     AND (server_id = @server_id)
  5283.  
  5284.   -- If we deleted the last jobserver then re-categorize the job to the sp_add_job default
  5285.   IF (NOT EXISTS (SELECT *
  5286.                   FROM msdb.dbo.sysjobservers
  5287.                   WHERE (job_id = @job_id)))
  5288.   BEGIN
  5289.     UPDATE msdb.dbo.sysjobs
  5290.     SET category_id = 0 -- [Uncategorized (Local)]
  5291.     WHERE (job_id = @job_id)
  5292.   END
  5293.  
  5294.   -- If the job is local, make sure that SQLServerAgent removes it from cache
  5295.   IF (@server_id = 0)
  5296.   BEGIN
  5297.     EXECUTE msdb.dbo.sp_sqlagent_notify @op_type     = N'J',
  5298.                                         @job_id      = @job_id,
  5299.                                         @action_type = N'D'
  5300.   END
  5301.  
  5302.   RETURN(@retval) -- 0 means success
  5303. END
  5304. go
  5305.  
  5306. /**************************************************************/
  5307. /* SP_HELP_JOBSERVER                                          */
  5308. /**************************************************************/
  5309.  
  5310. PRINT ''
  5311. PRINT 'Creating procedure sp_help_jobserver...'
  5312. go
  5313. IF (EXISTS (SELECT *
  5314.             FROM msdb.dbo.sysobjects
  5315.             WHERE (name = N'sp_help_jobserver')
  5316.               AND (type = 'P')))
  5317.   DROP PROCEDURE sp_help_jobserver
  5318. go
  5319. CREATE PROCEDURE sp_help_jobserver
  5320.   @job_id                UNIQUEIDENTIFIER = NULL, -- Must provide either this or job_name
  5321.   @job_name              sysname          = NULL, -- Must provide either this or job_id
  5322.   @show_last_run_details TINYINT          = 0     -- Controls if last-run execution information is part of the result set (1 = yes, 0 = no)
  5323. AS
  5324. BEGIN
  5325.   DECLARE @retval INT
  5326.  
  5327.   SET NOCOUNT ON
  5328.  
  5329.   EXECUTE @retval = sp_verify_job_identifiers '@job_name',
  5330.                                               '@job_id',
  5331.                                                @job_name OUTPUT,
  5332.                                                @job_id   OUTPUT
  5333.   IF (@retval <> 0)
  5334.     RETURN(1) -- Failure
  5335.  
  5336.   -- The show-last-run-details flag must be either 1 or 0
  5337.   IF (@show_last_run_details <> 0)
  5338.     SELECT @show_last_run_details = 1
  5339.  
  5340.   IF (@show_last_run_details = 1)
  5341.   BEGIN
  5342.     -- List the servers that @job_name has been targeted at (INCLUDING last-run details)
  5343.     SELECT stsv.server_id,
  5344.            stsv.server_name,
  5345.            stsv.enlist_date,
  5346.            stsv.last_poll_date,
  5347.            sjs.last_run_date,
  5348.            sjs.last_run_time,
  5349.            sjs.last_run_duration,
  5350.            sjs.last_run_outcome,  -- Same as JOB_OUTCOME_CODE (SQLAGENT_EXEC_x)
  5351.            sjs.last_outcome_message
  5352.     FROM msdb.dbo.sysjobservers         sjs  LEFT OUTER JOIN
  5353.          msdb.dbo.systargetservers_view stsv ON (sjs.server_id = stsv.server_id)
  5354.     WHERE (sjs.job_id = @job_id)
  5355.   END
  5356.   ELSE
  5357.   BEGIN
  5358.     -- List the servers that @job_name has been targeted at (EXCLUDING last-run details)
  5359.     SELECT stsv.server_id,
  5360.            stsv.server_name,
  5361.            stsv.enlist_date,
  5362.            stsv.last_poll_date
  5363.     FROM msdb.dbo.sysjobservers         sjs  LEFT OUTER JOIN
  5364.          msdb.dbo.systargetservers_view stsv ON (sjs.server_id = stsv.server_id)
  5365.     WHERE (sjs.job_id = @job_id)
  5366.   END
  5367.  
  5368.   RETURN(@@error) -- 0 means success
  5369. END
  5370. go
  5371.  
  5372. /**************************************************************/
  5373. /* SP_HELP_DOWNLOADLIST                                       */
  5374. /**************************************************************/
  5375.  
  5376. PRINT ''
  5377. PRINT 'Creating procedure sp_help_downloadlist...'
  5378. go
  5379. IF (EXISTS (SELECT *
  5380.             FROM msdb.dbo.sysobjects
  5381.             WHERE (name = N'sp_help_downloadlist')
  5382.               AND (type = 'P')))
  5383.   DROP PROCEDURE sp_help_downloadlist
  5384. go
  5385. CREATE PROCEDURE sp_help_downloadlist
  5386.   @job_id          UNIQUEIDENTIFIER = NULL, -- If provided must NOT also provide job_name
  5387.   @job_name        sysname          = NULL, -- If provided must NOT also provide job_id
  5388.   @operation       VARCHAR(64)      = NULL,
  5389.   @object_type     VARCHAR(64)      = NULL, -- Only 'JOB' or 'SERVER' are valid in 7.0
  5390.   @object_name     sysname          = NULL,
  5391.   @target_server   NVARCHAR(30)     = NULL,
  5392.   @has_error       TINYINT          = NULL, -- NULL or 1
  5393.   @status          TINYINT          = NULL,
  5394.   @date_posted     DATETIME         = NULL  -- Include all entries made on OR AFTER this date
  5395. AS
  5396. BEGIN
  5397.   DECLARE @retval         INT
  5398.   DECLARE @operation_code INT
  5399.   DECLARE @object_type_id TINYINT
  5400.  
  5401.   SET NOCOUNT ON
  5402.  
  5403.   -- Remove any leading/trailing spaces from parameters
  5404.   SELECT @operation     = LTRIM(RTRIM(@operation))
  5405.   SELECT @object_type   = LTRIM(RTRIM(@object_type))
  5406.   SELECT @object_name   = LTRIM(RTRIM(@object_name))
  5407.   SELECT @target_server = LTRIM(RTRIM(@target_server))
  5408.  
  5409.   -- Turn [nullable] empty string parameters into NULLs
  5410.   IF (@operation     = '') SELECT @operation = NULL
  5411.   IF (@object_type   = '') SELECT @object_type = NULL
  5412.   IF (@object_name   = N'') SELECT @object_name = NULL
  5413.   IF (@target_server = N'') SELECT @target_server = NULL
  5414.  
  5415.   IF ((@job_id IS NOT NULL) OR (@job_name IS NOT NULL))
  5416.   BEGIN
  5417.     EXECUTE @retval = sp_verify_job_identifiers '@job_name',
  5418.                                                 '@job_id',
  5419.                                                  @job_name OUTPUT,
  5420.                                                  @job_id   OUTPUT
  5421.     IF (@retval <> 0)
  5422.       RETURN(1) -- Failure
  5423.   END
  5424.  
  5425.   -- Check operation
  5426.   IF (@operation IS NOT NULL)
  5427.   BEGIN
  5428.     SELECT @operation = UPPER(@operation)
  5429.     SELECT @operation_code = CASE @operation
  5430.                                WHEN 'INSERT'    THEN 1
  5431.                                WHEN 'UPDATE'    THEN 2
  5432.                                WHEN 'DELETE'    THEN 3
  5433.                                WHEN 'START'     THEN 4
  5434.                                WHEN 'STOP'      THEN 5
  5435.                                WHEN 'RE-ENLIST' THEN 6
  5436.                                WHEN 'DEFECT'    THEN 7
  5437.                                WHEN 'SYNC-TIME' THEN 8
  5438.                                WHEN 'SET-POLL'  THEN 9
  5439.                                ELSE 0
  5440.                              END
  5441.     IF (@operation_code = 0)
  5442.     BEGIN
  5443.       RAISERROR(14266, -1, -1, '@operation_code', 'INSERT, UPDATE, DELETE, START, STOP, RE-ENLIST, DEFECT, SYNC-TIME, SET-POLL')
  5444.       RETURN(1) -- Failure
  5445.     END
  5446.   END
  5447.  
  5448.   -- Check object type (in 7.0 only 'JOB' and 'SERVER' are valid)
  5449.   IF (@object_type IS NOT NULL)
  5450.   BEGIN
  5451.     SELECT @object_type = UPPER(@object_type)
  5452.     IF ((@object_type <> 'JOB') AND (@object_type <> 'SERVER'))
  5453.     BEGIN
  5454.       RAISERROR(14266, -1, -1, '@object_type', 'JOB, SERVER')
  5455.       RETURN(1) -- Failure
  5456.     END
  5457.     ELSE
  5458.       SELECT @object_type_id = CASE @object_type
  5459.                                  WHEN 'JOB'    THEN 1
  5460.                                  WHEN 'SERVER' THEN 2
  5461.                                  ELSE 0
  5462.                                END
  5463.   END
  5464.  
  5465.   -- If object-type is supplied then object-name must also be supplied
  5466.   IF ((@object_type IS NOT NULL) AND (@object_name IS NULL)) OR
  5467.      ((@object_type IS NULL)     AND (@object_name IS NOT NULL))
  5468.   BEGIN
  5469.     RAISERROR(14272, -1, -1)
  5470.     RETURN(1) -- Failure
  5471.   END
  5472.  
  5473.   -- Check target server
  5474.   IF (@target_server IS NOT NULL) AND NOT EXISTS (SELECT *
  5475.                                                   FROM msdb.dbo.systargetservers
  5476.                                                   WHERE server_name = @target_server)
  5477.   BEGIN
  5478.     RAISERROR(14262, -1, -1, '@target_server', @target_server)
  5479.     RETURN(1) -- Failure
  5480.   END
  5481.  
  5482.   -- Check has-error
  5483.   IF (@has_error IS NOT NULL) AND (@has_error <> 1)
  5484.   BEGIN
  5485.     RAISERROR(14266, -1, -1, '@has_error', '1, NULL')
  5486.     RETURN(1) -- Failure
  5487.   END
  5488.  
  5489.   -- Check status
  5490.   IF (@status IS NOT NULL) AND (@status <> 0) AND (@status <> 1)
  5491.   BEGIN
  5492.     RAISERROR(14266, -1, -1, '@status', '0, 1')
  5493.     RETURN(1) -- Failure
  5494.   END
  5495.  
  5496.   -- Return the result set
  5497.   SELECT sdl.instance_id,
  5498.          sdl.source_server,
  5499.         'operation_code' = CASE sdl.operation_code
  5500.                              WHEN 1 THEN '1 (INSERT)'
  5501.                              WHEN 2 THEN '2 (UPDATE)'
  5502.                              WHEN 3 THEN '3 (DELETE)'
  5503.                              WHEN 4 THEN '4 (START)'
  5504.                              WHEN 5 THEN '5 (STOP)'
  5505.                              WHEN 6 THEN '6 (RE-ENLIST)'
  5506.                              WHEN 7 THEN '7 (DEFECT)'
  5507.                              WHEN 8 THEN '8 (SYNC-TIME)'
  5508.                              WHEN 9 THEN '9 (SET-POLL)'
  5509.                              ELSE CONVERT(VARCHAR, sdl.operation_code) + ' ' + FORMATMESSAGE(14205)
  5510.                            END,
  5511.         'object_name' = ISNULL(sjv.name, CASE
  5512.                                            WHEN (sdl.operation_code >= 1) AND (sdl.operation_code <= 5) AND (sdl.object_id = CONVERT(UNIQUEIDENTIFIER, 0x00)) THEN FORMATMESSAGE(14212) -- '(all jobs)'
  5513.                                            WHEN (sdl.operation_code  = 3) AND (sdl.object_id <> CONVERT(UNIQUEIDENTIFIER, 0x00)) THEN sdl.deleted_object_name -- Special case handling for a deleted job
  5514.                                            WHEN (sdl.operation_code >= 1) AND (sdl.operation_code <= 5) AND (sdl.object_id <> CONVERT(UNIQUEIDENTIFIER, 0x00)) THEN FORMATMESSAGE(14580) -- 'job' (safety belt: should never appear)
  5515.                                            WHEN (sdl.operation_code >= 6) AND (sdl.operation_code <= 9) THEN sdl.target_server
  5516.                                            ELSE FORMATMESSAGE(14205)
  5517.                                          END),
  5518.         'object_id' = ISNULL(sjv.job_id, CASE sdl.object_id
  5519.                                            WHEN CONVERT(UNIQUEIDENTIFIER, 0x00) THEN CONVERT(UNIQUEIDENTIFIER, 0x00)
  5520.                                            ELSE sdl.object_id
  5521.                                          END),
  5522.          sdl.target_server,
  5523.          sdl.error_message,
  5524.          sdl.date_posted,
  5525.          sdl.date_downloaded,
  5526.          sdl.status
  5527.   FROM msdb.dbo.sysdownloadlist sdl LEFT OUTER JOIN 
  5528.        msdb.dbo.sysjobs_view    sjv ON (sdl.object_id = sjv.job_id)
  5529.   WHERE ((@operation_code IS NULL) OR (operation_code = @operation_code))
  5530.     AND ((@object_type_id IS NULL) OR (object_type = @object_type_id))
  5531.     AND ((@job_id         IS NULL) OR (object_id = @job_id))
  5532.     AND ((@target_server  IS NULL) OR (target_server = @target_server))
  5533.     AND ((@has_error      IS NULL) OR (DATALENGTH(error_message) >= 1 * @has_error))
  5534.     AND ((@status         IS NULL) OR (status = @status))
  5535.     AND ((@date_posted    IS NULL) OR (date_posted >= @date_posted))
  5536.   ORDER BY sdl.instance_id
  5537.  
  5538.   RETURN(@@error) -- 0 means success
  5539.  
  5540. END
  5541. go
  5542.  
  5543. /**************************************************************/
  5544. /* SP_ENUM_SQLAGENT_SUBSYSTEMS                                */
  5545. /**************************************************************/
  5546.  
  5547. PRINT ''
  5548. PRINT 'Creating procedure sp_enum_sqlagent_subsystems...'
  5549. go
  5550. IF (EXISTS (SELECT *
  5551.             FROM msdb.dbo.sysobjects
  5552.             WHERE (name = N'sp_enum_sqlagent_subsystems')
  5553.               AND (type = 'P')))
  5554.   DROP PROCEDURE sp_enum_sqlagent_subsystems
  5555. go
  5556. CREATE PROCEDURE sp_enum_sqlagent_subsystems
  5557. AS
  5558. BEGIN
  5559.   DECLARE @part                  NVARCHAR(300)
  5560.   DECLARE @fmt                   NVARCHAR(300)
  5561.   DECLARE @subsystem             NVARCHAR(40)
  5562.   DECLARE @replication_installed INT
  5563.  
  5564.   SET NOCOUNT ON
  5565.  
  5566.   CREATE TABLE #xp_results (subsystem   NVARCHAR(40)  NOT NULL,
  5567.                             description NVARCHAR(300) NOT NULL)
  5568.   CREATE TABLE #sp_enum_ss_temp (subsystem          NVARCHAR(40) NOT NULL,
  5569.                                  description        NVARCHAR(80) NOT NULL,
  5570.                                  subsystem_dll      NVARCHAR(80) NULL,
  5571.                                  agent_exe          NVARCHAR(80) NULL,
  5572.                                  start_entry_point  NVARCHAR(30) NULL,
  5573.                                  event_entry_point  NVARCHAR(30) NULL,
  5574.                                  stop_entry_point   NVARCHAR(30) NULL,
  5575.                                  max_worker_threads INT          NULL)
  5576.  
  5577.   -- Check if replication is installed
  5578.   EXECUTE master.dbo.xp_regread N'HKEY_LOCAL_MACHINE',
  5579.                                 N'SOFTWARE\Microsoft\MSSQLServer\Replication',
  5580.                                 N'IsInstalled',
  5581.                                  @replication_installed OUTPUT,
  5582.                                 N'no_output'
  5583.   SELECT @replication_installed = ISNULL(@replication_installed, 0)
  5584.  
  5585.   INSERT INTO #xp_results
  5586.   EXECUTE master.dbo.xp_regenumvalues N'HKEY_LOCAL_MACHINE', N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent\SubSystems'
  5587.  
  5588.   IF (@replication_installed = 0)
  5589.   BEGIN
  5590.     DELETE FROM #xp_results
  5591.     WHERE (subsystem IN (N'Distribution', N'LogReader', N'Merge', N'Snapshot'))
  5592.   END
  5593.  
  5594.   DECLARE all_subsystems CURSOR LOCAL
  5595.   FOR
  5596.   SELECT subsystem, description
  5597.   FROM #xp_results
  5598.  
  5599.   OPEN all_subsystems
  5600.   FETCH NEXT FROM all_subsystems INTO @subsystem, @part
  5601.   WHILE (@@fetch_status = 0)
  5602.   BEGIN
  5603.     IF (@subsystem = N'TSQL')
  5604.       INSERT INTO #sp_enum_ss_temp VALUES (N'TSQL', FORMATMESSAGE(14556), FORMATMESSAGE(14557), FORMATMESSAGE(14557), FORMATMESSAGE(14557), FORMATMESSAGE(14557), FORMATMESSAGE(14557), CONVERT(INT, @part))
  5605.     ELSE
  5606.     BEGIN
  5607.       SELECT @fmt = N''
  5608.       WHILE (CHARINDEX(N',', @part) > 0)
  5609.       BEGIN
  5610.         SELECT @fmt = @fmt + 'N''' + SUBSTRING(@part, 1, CHARINDEX(N',', @part) - 1) + ''', '
  5611.         SELECT @part = RIGHT(@part, (DATALENGTH(@part) / 2) - CHARINDEX(N',', @part))
  5612.       END
  5613.       SELECT @fmt = @fmt + @part
  5614.       IF (DATALENGTH(@fmt) > 0)
  5615.         INSERT INTO #sp_enum_ss_temp
  5616.         EXECUTE(N'SELECT ''' + @subsystem + N''', N'''', ' + @fmt) 
  5617.     END
  5618.     FETCH NEXT FROM all_subsystems INTO @subsystem, @part
  5619.   END
  5620.   DEALLOCATE all_subsystems
  5621.  
  5622.   UPDATE #sp_enum_ss_temp SET description = FORMATMESSAGE(14550)
  5623.   WHERE (subsystem = N'CmdExec')
  5624.   UPDATE #sp_enum_ss_temp SET description = FORMATMESSAGE(14551)
  5625.   WHERE (subsystem = N'Snapshot')
  5626.   UPDATE #sp_enum_ss_temp SET description = FORMATMESSAGE(14552)
  5627.   WHERE (subsystem = N'LogReader')
  5628.   UPDATE #sp_enum_ss_temp SET description = FORMATMESSAGE(14553)
  5629.   WHERE (subsystem = N'Distribution')
  5630.   UPDATE #sp_enum_ss_temp SET description = FORMATMESSAGE(14554)
  5631.   WHERE (subsystem = N'Merge')
  5632.   UPDATE #sp_enum_ss_temp SET description = FORMATMESSAGE(14555)
  5633.   WHERE (subsystem = N'ActiveScripting')
  5634.  
  5635.   -- 'TSQL' is always available (since it's a built-in subsystem), so we explicity add it
  5636.   -- to the result set
  5637.   IF (NOT EXISTS (SELECT * 
  5638.                   FROM #sp_enum_ss_temp 
  5639.                   WHERE (subsystem = N'TSQL')))
  5640.     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
  5641.  
  5642.   SELECT subsystem,
  5643.          description,
  5644.          subsystem_dll,
  5645.          agent_exe,
  5646.          start_entry_point,
  5647.          event_entry_point,
  5648.          stop_entry_point,
  5649.          max_worker_threads
  5650.   FROM #sp_enum_ss_temp
  5651.   ORDER BY subsystem
  5652. END
  5653. go
  5654.  
  5655. /**************************************************************/
  5656. /* SP_VERIFY_SUBSYSTEM                                        */
  5657. /**************************************************************/
  5658.  
  5659. PRINT ''
  5660. PRINT 'Creating procedure sp_verify_subsystem...'
  5661. go
  5662. IF (EXISTS (SELECT *
  5663.             FROM msdb.dbo.sysobjects
  5664.             WHERE (name = N'sp_verify_subsystem')
  5665.               AND (type = 'P')))
  5666.   DROP PROCEDURE sp_verify_subsystem
  5667. go
  5668. CREATE PROCEDURE sp_verify_subsystem
  5669.   @subsystem NVARCHAR(40)
  5670. AS
  5671. BEGIN
  5672.   SET NOCOUNT ON
  5673.  
  5674.   -- Remove any leading/trailing spaces from parameters
  5675.   SELECT @subsystem = LTRIM(RTRIM(@subsystem))
  5676.  
  5677.   -- NOTE: We don't use the results of sp_enum_sqlagent_subsystems for performance reasons
  5678.   IF (UPPER(@subsystem) IN (N'ACTIVESCRIPTING',
  5679.                             N'CMDEXEC',
  5680.                             N'DISTRIBUTION',
  5681.                             N'SNAPSHOT',
  5682.                             N'LOGREADER',
  5683.                             N'MERGE',
  5684.                             N'TSQL'))
  5685.     RETURN(0) -- Success
  5686.   ELSE
  5687.   BEGIN
  5688.     RAISERROR(14234, -1, -1, '@subsystem', 'sp_enum_sqlagent_subsystems')
  5689.     RETURN(1) -- Failure
  5690.   END
  5691. END
  5692. go
  5693.  
  5694. /**************************************************************/
  5695. /* SP_GET_JOBSTEP_DB_USERNAME                                 */
  5696. /*                                                            */
  5697. /* NOTE: For NT login names this procedure can take several   */
  5698. /*       seconds to return as it hits the PDC/BDC.            */
  5699. /*       SQLServerAgent calls this at runtime.                */
  5700. /**************************************************************/
  5701.  
  5702. PRINT ''
  5703. PRINT 'Creating procedure sp_get_jobstep_db_username...'
  5704. go
  5705. IF (EXISTS (SELECT *
  5706.             FROM msdb.dbo.sysobjects
  5707.             WHERE (name = N'sp_get_jobstep_db_username ')
  5708.               AND (type = 'P')))
  5709.   DROP PROCEDURE sp_get_jobstep_db_username 
  5710. go
  5711. CREATE PROCEDURE sp_get_jobstep_db_username 
  5712.   @database_name        sysname,
  5713.   @login_name           sysname = NULL, 
  5714.   @username_in_targetdb sysname OUTPUT
  5715. AS
  5716. BEGIN
  5717.   DECLARE @suser_sid_clause NVARCHAR(200)
  5718.  
  5719.   CREATE TABLE #temp_username (user_name sysname NOT NULL, is_aliased BIT)
  5720.  
  5721.   -- Check the database name
  5722.   IF (DB_ID(@database_name) IS NULL)
  5723.   BEGIN
  5724.     RAISERROR(14262, 16, 1, 'database', @database_name)
  5725.     RETURN(1) -- Failure
  5726.   END
  5727.  
  5728.   -- Initialize return value
  5729.   SELECT @username_in_targetdb = NULL
  5730.  
  5731.   -- Make sure login name is never NULL
  5732.   IF (@login_name IS NULL)
  5733.     SELECT @login_name = SUSER_SNAME()
  5734.   IF (@login_name IS NULL)
  5735.     RETURN(1) -- Failure
  5736.  
  5737.   -- Handle an NT login name
  5738.   IF (@login_name LIKE N'%\%')
  5739.   BEGIN
  5740.     -- Special case...
  5741.     IF (UPPER(@login_name) = N'NT AUTHORITY\SYSTEM')
  5742.       SELECT @username_in_targetdb = N'dbo'
  5743.     ELSE
  5744.       SELECT @username_in_targetdb = @login_name
  5745.  
  5746.     RETURN(0) -- Success
  5747.   END
  5748.  
  5749.   -- Handle a SQL login name
  5750.   SELECT @suser_sid_clause = N'SUSER_SID(N''' + @login_name + N''')'
  5751.   IF (SUSER_SID(@login_name) IS NULL)
  5752.     RETURN(1) -- Failure
  5753.  
  5754.   -- 1) Look for the user name of the current login in the target database
  5755.   INSERT INTO #temp_username
  5756.   EXECUTE (N'SET NOCOUNT ON
  5757.              SELECT name, isaliased
  5758.              FROM '+ @database_name + N'.dbo.sysusers
  5759.              WHERE (sid = ' + @suser_sid_clause + N')
  5760.                AND (hasdbaccess = 1)')
  5761.  
  5762.   -- 2) Look for the alias user name of the current login in the target database
  5763.   IF (EXISTS (SELECT *
  5764.               FROM #temp_username
  5765.               WHERE (is_aliased = 1)))
  5766.   BEGIN
  5767.     TRUNCATE TABLE #temp_username
  5768.     INSERT INTO #temp_username
  5769.     EXECUTE (N'SET NOCOUNT ON
  5770.                SELECT name, 0
  5771.                FROM '+ @database_name + N'.dbo.sysusers
  5772.                WHERE uid = (SELECT altuid
  5773.                             FROM ' + @database_name + N'.dbo.sysusers
  5774.                             WHERE (sid = ' + @suser_sid_clause + N'))
  5775.                  AND (hasdbaccess = 1)')
  5776.   END
  5777.  
  5778.   -- 3) Look for the guest user name in the target database
  5779.   IF (NOT EXISTS (SELECT *
  5780.                   FROM #temp_username))
  5781.     INSERT INTO #temp_username
  5782.     EXECUTE (N'SET NOCOUNT ON
  5783.                SELECT name, 0
  5784.                FROM '+ @database_name + N'.dbo.sysusers
  5785.                WHERE (name = N''guest'')
  5786.                  AND (hasdbaccess = 1)')
  5787.  
  5788.   SELECT @username_in_targetdb = user_name
  5789.   FROM #temp_username
  5790.  
  5791.   RETURN(0) -- Success
  5792. END
  5793. go
  5794.  
  5795. /**************************************************************/
  5796. /* SP_VERIFY_JOBSTEP                                          */
  5797. /**************************************************************/
  5798.  
  5799. PRINT ''
  5800. PRINT 'Creating procedure sp_verify_jobstep...'
  5801. go
  5802. IF (EXISTS (SELECT *
  5803.             FROM msdb.dbo.sysobjects
  5804.             WHERE (name = N'sp_verify_jobstep')
  5805.               AND (type = 'P')))
  5806.   DROP PROCEDURE sp_verify_jobstep
  5807. go
  5808. CREATE PROCEDURE sp_verify_jobstep
  5809.   @job_id             UNIQUEIDENTIFIER,
  5810.   @step_id            INT,
  5811.   @step_name          sysname,
  5812.   @subsystem          NVARCHAR(40),
  5813.   @command            NVARCHAR(3201),
  5814.   @server             NVARCHAR(30),
  5815.   @on_success_action  TINYINT,
  5816.   @on_success_step_id INT,
  5817.   @on_fail_action     TINYINT,
  5818.   @on_fail_step_id    INT,
  5819.   @os_run_priority    INT,
  5820.   @database_name      sysname OUTPUT,
  5821.   @database_user_name sysname OUTPUT,
  5822.   @flags              INT,
  5823.   @output_file_name   NVARCHAR(200)
  5824. AS
  5825. BEGIN
  5826.   DECLARE @max_step_id             INT
  5827.   DECLARE @retval                  INT
  5828.   DECLARE @valid_values            VARCHAR(50)
  5829.   DECLARE @owner_login_name        sysname
  5830.   DECLARE @database_name_temp      sysname
  5831.   DECLARE @database_user_name_temp sysname
  5832.   DECLARE @temp_command            NVARCHAR(3200)
  5833.   DECLARE @iPos                    INT
  5834.   DECLARE @create_count            INT
  5835.   DECLARE @destroy_count           INT
  5836.  
  5837.   SET NOCOUNT ON
  5838.  
  5839.   -- Remove any leading/trailing spaces from parameters
  5840.   SELECT @subsystem        = LTRIM(RTRIM(@subsystem))
  5841.   SELECT @server           = LTRIM(RTRIM(@server))
  5842.   SELECT @output_file_name = LTRIM(RTRIM(@output_file_name))
  5843.  
  5844.   -- Get current maximum step id
  5845.   SELECT @max_step_id = ISNULL(MAX(step_id), 0)
  5846.   FROM msdb.dbo.sysjobsteps
  5847.   WHERE (job_id = @job_id)
  5848.  
  5849.   -- Check step id
  5850.   IF (@step_id < 1) OR (@step_id > @max_step_id + 1)
  5851.   BEGIN
  5852.     SELECT @valid_values = '1..' + CONVERT(VARCHAR, @max_step_id + 1)
  5853.     RAISERROR(14266, -1, -1, '@step_id', @valid_values)
  5854.     RETURN(1) -- Failure
  5855.   END
  5856.  
  5857.   -- Check subsystem
  5858.   EXECUTE @retval = sp_verify_subsystem @subsystem
  5859.   IF (@retval <> 0)
  5860.     RETURN(1) -- Failure
  5861.  
  5862.   -- Check command length
  5863.   IF ((DATALENGTH(@command) / 2) > 3200)
  5864.   BEGIN
  5865.     RAISERROR(14250, 16, 1, '@command', 3200)
  5866.     RETURN(1) -- Failure
  5867.   END
  5868.  
  5869.   -- For a VBScript command, check that object creations are paired with object destructions
  5870.   IF ((UPPER(@subsystem) = N'ACTIVESCRIPTING') AND (@database_name = N'VBScript'))
  5871.   BEGIN
  5872.     SELECT @temp_command = @command
  5873.  
  5874.     SELECT @create_count = 0
  5875.     SELECT @iPos = PATINDEX('%[Cc]reate[Oo]bject[ (]%', @temp_command)
  5876.     WHILE(@iPos > 0)
  5877.     BEGIN
  5878.       SELECT @temp_command = SUBSTRING(@temp_command, @iPos + 1, DATALENGTH(@temp_command) / 2)
  5879.       SELECT @iPos = PATINDEX('%[Cc]reate[Oo]bject[ (]%', @temp_command)
  5880.       SELECT @create_count = @create_count + 1
  5881.     END
  5882.  
  5883.     SELECT @destroy_count = 0
  5884.     SELECT @iPos = PATINDEX('%[Ss]et %=%[Nn]othing%', @temp_command)
  5885.     WHILE(@iPos > 0)
  5886.     BEGIN
  5887.       SELECT @temp_command = SUBSTRING(@temp_command, @iPos + 1, DATALENGTH(@temp_command) / 2)
  5888.       SELECT @iPos = PATINDEX('%[Ss]et %=%[Nn]othing%', @temp_command)
  5889.       SELECT @destroy_count = @destroy_count + 1
  5890.     END
  5891.  
  5892.     IF(@create_count > @destroy_count)
  5893.     BEGIN
  5894.       RAISERROR(14277, -1, -1)
  5895.       RETURN(1) -- Failure
  5896.     END
  5897.   END
  5898.  
  5899.   -- Check step name
  5900.   IF (EXISTS (SELECT *
  5901.               FROM msdb.dbo.sysjobsteps
  5902.               WHERE (job_id = @job_id)
  5903.                 AND (step_name = @step_name)))
  5904.   BEGIN
  5905.     RAISERROR(14261, -1, -1, '@step_name', @step_name)
  5906.     RETURN(1) -- Failure
  5907.   END
  5908.  
  5909.   -- Check on-success action/step
  5910.   IF (@on_success_action <> 1) AND -- Quit Qith Success
  5911.      (@on_success_action <> 2) AND -- Quit Qith Failure
  5912.      (@on_success_action <> 3) AND -- Goto Next Step
  5913.      (@on_success_action <> 4)     -- Goto Step
  5914.   BEGIN
  5915.     RAISERROR(14266, -1, -1, '@on_success_action', '1, 2, 3, 4')
  5916.     RETURN(1) -- Failure
  5917.   END
  5918.   IF (@on_success_action = 4) AND
  5919.      ((@on_success_step_id < 1) OR (@on_success_step_id = @step_id))
  5920.   BEGIN
  5921.     -- NOTE: We allow forward references to non-existant steps to prevent the user from
  5922.     --       having to make a second update pass to fix up the flow
  5923.     RAISERROR(14235, -1, -1, '@on_success_step', @step_id)
  5924.     RETURN(1) -- Failure
  5925.   END
  5926.  
  5927.   -- Check on-fail action/step
  5928.   IF (@on_fail_action <> 1) AND -- Quit Qith Success
  5929.      (@on_fail_action <> 2) AND -- Quit Qith Failure
  5930.      (@on_fail_action <> 3) AND -- Goto Next Step
  5931.      (@on_fail_action <> 4)     -- Goto Step
  5932.   BEGIN
  5933.     RAISERROR(14266, -1, -1, '@on_failure_action', '1, 2, 3, 4')
  5934.     RETURN(1) -- Failure
  5935.   END
  5936.   IF (@on_fail_action = 4) AND
  5937.      ((@on_fail_step_id < 1) OR (@on_fail_step_id = @step_id))
  5938.   BEGIN
  5939.     -- NOTE: We allow forward references to non-existant steps to prevent the user from
  5940.     --       having to make a second update pass to fix up the flow
  5941.     RAISERROR(14235, -1, -1, '@on_failure_step', @step_id)
  5942.     RETURN(1) -- Failure
  5943.   END
  5944.  
  5945.   -- Warn the user about forward references
  5946.   IF ((@on_success_action = 4) AND (@on_success_step_id > @max_step_id))
  5947.     RAISERROR(14236, 0, 1, '@on_success_step_id')
  5948.   IF ((@on_fail_action = 4) AND (@on_fail_step_id > @max_step_id))
  5949.     RAISERROR(14236, 0, 1, '@on_fail_step_id')
  5950.  
  5951.   -- Check server (this is the replication server, NOT the job-target server)
  5952.   IF (@server IS NOT NULL) AND (NOT EXISTS (SELECT *
  5953.                                             FROM master.dbo.sysservers
  5954.                                             WHERE (srvname = @server)))
  5955.   BEGIN
  5956.     RAISERROR(14234, -1, -1, '@server', 'sp_helpserver')
  5957.     RETURN(1) -- Failure
  5958.   END
  5959.  
  5960.   -- Check run priority: must be a valid value to pass to SetThreadPriority:
  5961.   -- [-15 = IDLE, -1 = BELOW_NORMAL, 0 = NORMAL, 1 = ABOVE_NORMAL, 15 = TIME_CRITICAL]
  5962.   IF (@os_run_priority NOT IN (-15, -1, 0, 1, 15))
  5963.   BEGIN
  5964.     RAISERROR(14266, -1, -1, '@os_run_priority', '-15, -1, 0, 1, 15')
  5965.     RETURN(1) -- Failure
  5966.   END
  5967.  
  5968.   -- Check flags
  5969.   IF ((@flags < 0) OR (@flags > 7))
  5970.   BEGIN
  5971.     RAISERROR(14266, -1, -1, '@flags', '0..7')
  5972.     RETURN(1) -- Failure
  5973.   END
  5974.  
  5975.   -- Check output file
  5976.   IF (@output_file_name IS NOT NULL) AND (UPPER(@subsystem) NOT IN ('TSQL', 'CMDEXEC'))
  5977.   BEGIN
  5978.     RAISERROR(14545, -1, -1, '@output_file_name', @subsystem)
  5979.     RETURN(1) -- Failure
  5980.   END
  5981.  
  5982.   -- For CmdExec steps database-name and database-user-name should both be null
  5983.   IF (UPPER(@subsystem) = N'CMDEXEC')
  5984.     SELECT @database_name = NULL,
  5985.            @database_user_name = NULL
  5986.  
  5987.   -- For non-TSQL steps, database-user-name should be null
  5988.   IF (UPPER(@subsystem) <> 'TSQL')
  5989.     SELECT @database_user_name = NULL
  5990.  
  5991.   -- For a TSQL step, get (and check) the username of the caller in the target database.
  5992.   IF (UPPER(@subsystem) = 'TSQL')
  5993.   BEGIN
  5994.     SET NOCOUNT ON
  5995.  
  5996.     -- But first check if remote server name has been supplied
  5997.     IF (@server IS NOT NULL)
  5998.       SELECT @server = NULL
  5999.  
  6000.     -- Default database to 'master' if not supplied
  6001.     IF (LTRIM(RTRIM(@database_name)) IS NULL)
  6002.       SELECT @database_name = N'master'
  6003.  
  6004.     -- Check the database (although this is no guarantee that @database_user_name can access it)
  6005.     IF (DB_ID(@database_name) IS NULL)
  6006.     BEGIN
  6007.       RAISERROR(14262, -1, -1, '@database_name', @database_name)
  6008.       RETURN(1) -- Failure
  6009.     END
  6010.  
  6011.     SELECT @owner_login_name = SUSER_SNAME(owner_sid)
  6012.     FROM msdb.dbo.sysjobs
  6013.     WHERE (job_id = @job_id)
  6014.  
  6015.     SELECT @database_user_name = LTRIM(RTRIM(@database_user_name))
  6016.  
  6017.     -- Only if a SysAdmin is creating the job can the database user name be non-NULL [since only 
  6018.     -- SysAdmin's can call SETUSER].
  6019.     -- NOTE: In this case we don't try to validate the user name (it's too costly to do so)
  6020.     --       so if it's bad we'll get a runtime error when the job executes.
  6021.     IF (ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) = 1)
  6022.     BEGIN
  6023.       -- Special case handling if the username is 'sa'
  6024.       IF (UPPER(@database_user_name) = N'SA')
  6025.         SELECT @database_user_name = NULL
  6026.  
  6027.       -- If this is a multi-server job then @database_user_name must be null
  6028.       IF (@database_user_name IS NOT NULL)
  6029.       BEGIN
  6030.         IF (EXISTS (SELECT *
  6031.                     FROM msdb.dbo.sysjobs       sj,
  6032.                          msdb.dbo.sysjobservers sjs
  6033.                     WHERE (sj.job_id = sjs.job_id)
  6034.                       AND (sj.job_id = @job_id)
  6035.                       AND (sjs.server_id <> 0)))
  6036.         BEGIN
  6037.           RAISERROR(14542, -1, -1, N'database_user_name') 
  6038.           RETURN(1) -- Failure
  6039.         END
  6040.       END
  6041.  
  6042.       -- For a SQL-user, check if it exists
  6043.       IF (@database_user_name NOT LIKE N'%\%')
  6044.       BEGIN
  6045.         CREATE TABLE #result(user_count INT)
  6046.  
  6047.         SELECT @database_user_name_temp = REPLACE(@database_user_name, N'''', N'''''')
  6048.         SELECT @database_name_temp = REPLACE(@database_name, N'''', N'''''')
  6049.  
  6050.         INSERT INTO #result
  6051.         EXECUTE(N'SELECT COUNT(*)
  6052.                   FROM ' + @database_name_temp + N'.dbo.sysusers
  6053.                   WHERE (name = N''' + @database_user_name_temp + N''')')
  6054.         IF (EXISTS (SELECT * 
  6055.                     FROM #result 
  6056.                     WHERE (user_count = 0)))
  6057.         BEGIN
  6058.           RAISERROR(14262, -1, -1, '@database_user_name', @database_user_name) 
  6059.           RETURN(1) -- Failure
  6060.         END
  6061.       END
  6062.     END
  6063.     ELSE
  6064.       SELECT @database_user_name = NULL
  6065.  
  6066.   END  -- End of TSQL property verification
  6067.  
  6068.   RETURN(0) -- Success
  6069. END
  6070. go
  6071.  
  6072. /**************************************************************/
  6073. /* SP_ADD_JOBSTEP                                             */
  6074. /**************************************************************/
  6075.  
  6076. PRINT ''
  6077. PRINT 'Creating procedure sp_add_jobstep...'
  6078. go
  6079. IF (EXISTS (SELECT *
  6080.             FROM msdb.dbo.sysobjects
  6081.             WHERE (name = N'sp_add_jobstep')
  6082.               AND (type = 'P')))
  6083.   DROP PROCEDURE sp_add_jobstep
  6084. go
  6085. CREATE PROCEDURE sp_add_jobstep
  6086.   @job_id                UNIQUEIDENTIFIER = NULL,   -- Must provide either this or job_name
  6087.   @job_name              sysname          = NULL,   -- Must provide either this or job_id
  6088.   @step_id               INT              = NULL,   -- The proc assigns a default
  6089.   @step_name             sysname,
  6090.   @subsystem             NVARCHAR(40)     = N'TSQL',
  6091.   @command               NVARCHAR(3201)   = NULL,   -- We declare this as NVARCHAR(3201) not NVARCHAR(3200) so that we can catch 'silent truncation' of commands
  6092.   @additional_parameters NTEXT            = NULL,
  6093.   @cmdexec_success_code  INT              = 0,
  6094.   @on_success_action     TINYINT          = 1,      -- 1 = Quit With Success, 2 = Quit With Failure, 3 = Goto Next Step, 4 = Goto Step
  6095.   @on_success_step_id    INT              = 0,
  6096.   @on_fail_action        TINYINT          = 2,      -- 1 = Quit With Success, 2 = Quit With Failure, 3 = Goto Next Step, 4 = Goto Step
  6097.   @on_fail_step_id       INT              = 0,
  6098.   @server                NVARCHAR(30)     = NULL,
  6099.   @database_name         sysname          = NULL,
  6100.   @database_user_name    sysname          = NULL,
  6101.   @retry_attempts        INT              = 0,      -- No retries
  6102.   @retry_interval        INT              = 0,      -- 0 minute interval
  6103.   @os_run_priority       INT              = 0,      -- -15 = Idle, -1 = Below Normal, 0 = Normal, 1 = Above Normal, 15 = Time Critical)
  6104.   @output_file_name      NVARCHAR(200)    = NULL,
  6105.   @flags                 INT              = 0       -- 0 = Normal, 1 = Encrypted command (read only), 2 = Append output files (if any), 4 = Write TSQL step output to step history
  6106. AS
  6107. BEGIN
  6108.   DECLARE @retval      INT
  6109.   DECLARE @max_step_id INT
  6110.  
  6111.   SET NOCOUNT ON
  6112.  
  6113.   -- Remove any leading/trailing spaces from parameters
  6114.   SELECT @step_name          = LTRIM(RTRIM(@step_name))
  6115.   SELECT @subsystem          = LTRIM(RTRIM(@subsystem))
  6116.   SELECT @server             = LTRIM(RTRIM(@server))
  6117.   SELECT @database_name      = LTRIM(RTRIM(@database_name))
  6118.   SELECT @database_user_name = LTRIM(RTRIM(@database_user_name))
  6119.   SELECT @output_file_name   = LTRIM(RTRIM(@output_file_name))
  6120.  
  6121.   -- Turn [nullable] empty string parameters into NULLs
  6122.   IF (@server             = N'') SELECT @server             = NULL
  6123.   IF (@database_name      = N'') SELECT @database_name      = NULL
  6124.   IF (@database_user_name = N'') SELECT @database_user_name = NULL
  6125.   IF (@output_file_name   = N'') SELECT @output_file_name   = NULL
  6126.  
  6127.   -- Check authority (only SQLServerAgent can add a step to a non-local job)
  6128.   EXECUTE @retval = sp_verify_jobproc_caller @job_id = @job_id, @program_name = N'SQLAgent%'
  6129.   IF (@retval <> 0)
  6130.     RETURN(@retval)
  6131.  
  6132.   EXECUTE @retval = sp_verify_job_identifiers '@job_name',
  6133.                                               '@job_id',
  6134.                                                @job_name OUTPUT,
  6135.                                                @job_id   OUTPUT
  6136.   IF (@retval <> 0)
  6137.     RETURN(1) -- Failure
  6138.  
  6139.   -- Default step id (if not supplied)
  6140.   IF (@step_id IS NULL)
  6141.   BEGIN
  6142.     SELECT @step_id = ISNULL(MAX(step_id), 0) + 1
  6143.     FROM msdb.dbo.sysjobsteps
  6144.     WHERE (job_id = @job_id)
  6145.   END
  6146.  
  6147.   -- Check parameters
  6148.   EXECUTE @retval = sp_verify_jobstep @job_id,
  6149.                                       @step_id,
  6150.                                       @step_name,
  6151.                                       @subsystem,
  6152.                                       @command,
  6153.                                       @server,
  6154.                                       @on_success_action,
  6155.                                       @on_success_step_id,
  6156.                                       @on_fail_action,
  6157.                                       @on_fail_step_id,
  6158.                                       @os_run_priority,
  6159.                                       @database_name      OUTPUT,
  6160.                                       @database_user_name OUTPUT,
  6161.                                       @flags,
  6162.                                       @output_file_name
  6163.   IF (@retval <> 0)
  6164.     RETURN(1) -- Failure
  6165.  
  6166.   -- Get current maximum step id
  6167.   SELECT @max_step_id = ISNULL(MAX(step_id), 0)
  6168.   FROM msdb.dbo.sysjobsteps
  6169.   WHERE (job_id = @job_id)
  6170.  
  6171.   BEGIN TRANSACTION
  6172.  
  6173.     -- Update the job's version/last-modified information
  6174.     UPDATE msdb.dbo.sysjobs
  6175.     SET version_number = version_number + 1,
  6176.         date_modified = GETDATE()
  6177.     WHERE (job_id = @job_id)
  6178.  
  6179.     -- Adjust step id's (unless the new step is being inserted at the 'end')
  6180.     -- NOTE: We MUST do this before inserting the step.
  6181.     IF (@step_id <= @max_step_id)
  6182.     BEGIN
  6183.       UPDATE msdb.dbo.sysjobsteps
  6184.       SET step_id = step_id + 1
  6185.       WHERE (step_id >= @step_id)
  6186.         AND (job_id = @job_id)
  6187.  
  6188.       -- Clean up OnSuccess/OnFail references
  6189.       UPDATE msdb.dbo.sysjobsteps
  6190.       SET on_success_step_id = on_success_step_id + 1
  6191.       WHERE (on_success_step_id >= @step_id)
  6192.         AND (job_id = @job_id)
  6193.  
  6194.       UPDATE msdb.dbo.sysjobsteps
  6195.       SET on_fail_step_id = on_fail_step_id + 1
  6196.       WHERE (on_fail_step_id >= @step_id)
  6197.         AND (job_id = @job_id)
  6198.  
  6199.       UPDATE msdb.dbo.sysjobsteps
  6200.       SET on_success_step_id = 0,
  6201.           on_success_action = 1  -- Quit With Success
  6202.       WHERE (on_success_step_id = @step_id)
  6203.         AND (job_id = @job_id)
  6204.  
  6205.       UPDATE msdb.dbo.sysjobsteps
  6206.       SET on_fail_step_id = 0,
  6207.           on_fail_action = 2     -- Quit With Failure
  6208.       WHERE (on_fail_step_id = @step_id)
  6209.         AND (job_id = @job_id)
  6210.     END
  6211.  
  6212.     -- Insert the step
  6213.     INSERT INTO msdb.dbo.sysjobsteps
  6214.            (job_id,
  6215.             step_id,
  6216.             step_name,
  6217.             subsystem,
  6218.             command,
  6219.             flags,
  6220.             additional_parameters,
  6221.             cmdexec_success_code,
  6222.             on_success_action,
  6223.             on_success_step_id,
  6224.             on_fail_action,
  6225.             on_fail_step_id,
  6226.             server,
  6227.             database_name,
  6228.             database_user_name,
  6229.             retry_attempts,
  6230.             retry_interval,
  6231.             os_run_priority,
  6232.             output_file_name,
  6233.             last_run_outcome,
  6234.             last_run_duration,
  6235.             last_run_retries,
  6236.             last_run_date,
  6237.             last_run_time)
  6238.     VALUES (@job_id,
  6239.             @step_id,
  6240.             @step_name,
  6241.             @subsystem,
  6242.             @command,
  6243.             @flags,
  6244.             @additional_parameters,
  6245.             @cmdexec_success_code,
  6246.             @on_success_action,
  6247.             @on_success_step_id,
  6248.             @on_fail_action,
  6249.             @on_fail_step_id,
  6250.             @server,
  6251.             @database_name,
  6252.             @database_user_name,
  6253.             @retry_attempts,
  6254.             @retry_interval,
  6255.             @os_run_priority,
  6256.             @output_file_name,
  6257.             0,
  6258.             0,
  6259.             0,
  6260.             0,
  6261.             0)
  6262.  
  6263.   COMMIT TRANSACTION
  6264.  
  6265.   -- Make sure that SQLServerAgent refreshes the job if the 'Has Steps' property has changed
  6266.   IF ((SELECT COUNT(*)
  6267.        FROM msdb.dbo.sysjobsteps
  6268.        WHERE (job_id = @job_id)) = 1)
  6269.   BEGIN
  6270.     -- NOTE: We only notify SQLServerAgent if we know the job has been cached
  6271.     IF (EXISTS (SELECT * 
  6272.                 FROM msdb.dbo.sysjobservers 
  6273.                 WHERE (job_id = @job_id)
  6274.                   AND (server_id = 0)))
  6275.       EXECUTE msdb.dbo.sp_sqlagent_notify @op_type       = N'J',
  6276.                                             @job_id      = @job_id,
  6277.                                             @action_type = N'U'
  6278.   END
  6279.  
  6280.   -- For a multi-server job, remind the user that they need to call sp_post_msx_operation
  6281.   IF (EXISTS (SELECT *
  6282.               FROM msdb.dbo.sysjobservers
  6283.               WHERE (job_id = @job_id)
  6284.                 AND (server_id <> 0)))
  6285.     RAISERROR(14547, 0, 1, N'INSERT', N'sp_post_msx_operation')
  6286.  
  6287.   RETURN(0) -- Success
  6288. END
  6289. go
  6290.  
  6291. /**************************************************************/
  6292. /* SP_UPDATE_JOBSTEP                                          */
  6293. /**************************************************************/
  6294.  
  6295. PRINT ''
  6296. PRINT 'Creating procedure sp_update_jobstep...'
  6297. go
  6298. IF (EXISTS (SELECT *
  6299.             FROM msdb.dbo.sysobjects
  6300.             WHERE (name = N'sp_update_jobstep')
  6301.               AND (type = 'P')))
  6302.   DROP PROCEDURE sp_update_jobstep
  6303. go
  6304. CREATE PROCEDURE sp_update_jobstep
  6305.   @job_id                 UNIQUEIDENTIFIER = NULL, -- Must provide either this or job_name
  6306.   @job_name               sysname          = NULL, -- Not updatable (provided for identification purposes only)
  6307.   @step_id                INT,                     -- Not updatable (provided for identification purposes only)
  6308.   @step_name              sysname          = NULL,
  6309.   @subsystem              NVARCHAR(40)     = NULL,
  6310.   @command                NVARCHAR(3201)   = NULL, -- We declare this as NVARCHAR(3201) not NVARCHAR(3200) so that we can catch 'silent truncation' of commands
  6311.   @additional_parameters  NTEXT            = NULL,
  6312.   @cmdexec_success_code   INT              = NULL,
  6313.   @on_success_action      TINYINT          = NULL,
  6314.   @on_success_step_id     INT              = NULL,
  6315.   @on_fail_action         TINYINT          = NULL,
  6316.   @on_fail_step_id        INT              = NULL,
  6317.   @server                 NVARCHAR(30)     = NULL,
  6318.   @database_name          sysname          = NULL,
  6319.   @database_user_name     sysname          = NULL,
  6320.   @retry_attempts         INT              = NULL,
  6321.   @retry_interval         INT              = NULL,
  6322.   @os_run_priority        INT              = NULL,
  6323.   @output_file_name       NVARCHAR(200)    = NULL,
  6324.   @flags                  INT              = NULL
  6325. AS
  6326. BEGIN
  6327.   DECLARE @retval                 INT
  6328.   DECLARE @os_run_priority_code   INT
  6329.   DECLARE @step_id_as_char        VARCHAR(10)
  6330.   DECLARE @new_step_name          sysname
  6331.  
  6332.   DECLARE @x_step_name            sysname
  6333.   DECLARE @x_subsystem            NVARCHAR(40)
  6334.   DECLARE @x_command              NVARCHAR(3200)
  6335.   DECLARE @x_flags                INT
  6336.   DECLARE @x_cmdexec_success_code INT
  6337.   DECLARE @x_on_success_action    TINYINT
  6338.   DECLARE @x_on_success_step_id   INT
  6339.   DECLARE @x_on_fail_action       TINYINT
  6340.   DECLARE @x_on_fail_step_id      INT
  6341.   DECLARE @x_server               NVARCHAR(30)
  6342.   DECLARE @x_database_name        sysname
  6343.   DECLARE @x_database_user_name   sysname
  6344.   DECLARE @x_retry_attempts       INT
  6345.   DECLARE @x_retry_interval       INT
  6346.   DECLARE @x_os_run_priority      INT
  6347.   DECLARE @x_output_file_name     NVARCHAR(200)
  6348.   DECLARE @x_last_run_outcome     TINYINT      -- Not updatable (but may be in future)
  6349.   DECLARE @x_last_run_duration    INT          -- Not updatable (but may be in future)
  6350.   DECLARE @x_last_run_retries     INT          -- Not updatable (but may be in future)
  6351.   DECLARE @x_last_run_date        INT          -- Not updatable (but may be in future)
  6352.   DECLARE @x_last_run_time        INT          -- Not updatable (but may be in future)
  6353.  
  6354.   SET NOCOUNT ON
  6355.  
  6356.   -- Remove any leading/trailing spaces from parameters
  6357.   SELECT @step_name          = LTRIM(RTRIM(@step_name))
  6358.   SELECT @subsystem          = LTRIM(RTRIM(@subsystem))
  6359.   SELECT @command            = LTRIM(RTRIM(@command))
  6360.   SELECT @server             = LTRIM(RTRIM(@server))
  6361.   SELECT @database_name      = LTRIM(RTRIM(@database_name))
  6362.   SELECT @database_user_name = LTRIM(RTRIM(@database_user_name))
  6363.   SELECT @output_file_name   = LTRIM(RTRIM(@output_file_name))
  6364.  
  6365.   EXECUTE @retval = sp_verify_job_identifiers '@job_name',
  6366.                                               '@job_id',
  6367.                                                @job_name OUTPUT,
  6368.                                                @job_id   OUTPUT
  6369.   IF (@retval <> 0)
  6370.     RETURN(1) -- Failure
  6371.  
  6372.   -- Check that the step exists
  6373.   IF (NOT EXISTS (SELECT *
  6374.                   FROM msdb.dbo.sysjobsteps
  6375.                   WHERE (job_id = @job_id)
  6376.                     AND (step_id = @step_id)))
  6377.   BEGIN
  6378.     SELECT @step_id_as_char = CONVERT(VARCHAR(10), @step_id)
  6379.     RAISERROR(14262, -1, -1, '@step_id', @step_id_as_char)
  6380.     RETURN(1) -- Failure
  6381.   END
  6382.  
  6383.   -- Check authority (only SQLServerAgent can modify a step of a non-local job)
  6384.   EXECUTE @retval = sp_verify_jobproc_caller @job_id = @job_id, @program_name = N'SQLAgent%'
  6385.   IF (@retval <> 0)
  6386.     RETURN(@retval)
  6387.  
  6388.   -- Set the x_ (existing) variables
  6389.   SELECT @x_step_name            = step_name,
  6390.          @x_subsystem            = subsystem,
  6391.          @x_command              = command,
  6392.          @x_flags                = flags,
  6393.          @x_cmdexec_success_code = cmdexec_success_code,
  6394.          @x_on_success_action    = on_success_action,
  6395.          @x_on_success_step_id   = on_success_step_id,
  6396.          @x_on_fail_action       = on_fail_action,
  6397.          @x_on_fail_step_id      = on_fail_step_id,
  6398.          @x_server               = server,
  6399.          @x_database_name        = database_name,
  6400.          @x_database_user_name   = database_user_name,
  6401.          @x_retry_attempts       = retry_attempts,
  6402.          @x_retry_interval       = retry_interval,
  6403.          @x_os_run_priority      = os_run_priority,
  6404.          @x_output_file_name     = output_file_name,
  6405.          @x_last_run_outcome     = last_run_outcome,
  6406.          @x_last_run_duration    = last_run_duration,
  6407.          @x_last_run_retries     = last_run_retries,
  6408.          @x_last_run_date        = last_run_date,
  6409.          @x_last_run_time        = last_run_time
  6410.   FROM msdb.dbo.sysjobsteps
  6411.   WHERE (job_id = @job_id)
  6412.     AND (step_id = @step_id)
  6413.  
  6414.   IF ((@step_name IS NOT NULL) AND (@step_name <> @x_step_name))
  6415.     SELECT @new_step_name = @step_name
  6416.  
  6417.   -- Fill out the values for all non-supplied parameters from the existing values
  6418.   IF (@step_name            IS NULL) SELECT @step_name            = @x_step_name
  6419.   IF (@subsystem            IS NULL) SELECT @subsystem            = @x_subsystem
  6420.   IF (@command              IS NULL) SELECT @command              = @x_command
  6421.   IF (@flags                IS NULL) SELECT @flags                = @x_flags
  6422.   IF (@cmdexec_success_code IS NULL) SELECT @cmdexec_success_code = @x_cmdexec_success_code
  6423.   IF (@on_success_action    IS NULL) SELECT @on_success_action    = @x_on_success_action
  6424.   IF (@on_success_step_id   IS NULL) SELECT @on_success_step_id   = @x_on_success_step_id
  6425.   IF (@on_fail_action       IS NULL) SELECT @on_fail_action       = @x_on_fail_action
  6426.   IF (@on_fail_step_id      IS NULL) SELECT @on_fail_step_id      = @x_on_fail_step_id
  6427.   IF (@server               IS NULL) SELECT @server               = @x_server
  6428.   IF (@database_name        IS NULL) SELECT @database_name        = @x_database_name
  6429.   IF (@database_user_name   IS NULL) SELECT @database_user_name   = @x_database_user_name
  6430.   IF (@retry_attempts       IS NULL) SELECT @retry_attempts       = @x_retry_attempts
  6431.   IF (@retry_interval       IS NULL) SELECT @retry_interval       = @x_retry_interval
  6432.   IF (@os_run_priority      IS NULL) SELECT @os_run_priority      = @x_os_run_priority
  6433.   IF (@output_file_name     IS NULL) SELECT @output_file_name     = @x_output_file_name
  6434.  
  6435.   -- Turn [nullable] empty string parameters into NULLs
  6436.   IF (@command            = N'') SELECT @command            = NULL
  6437.   IF (@server             = N'') SELECT @server             = NULL
  6438.   IF (@database_name      = N'') SELECT @database_name      = NULL
  6439.   IF (@database_user_name = N'') SELECT @database_user_name = NULL
  6440.   IF (@output_file_name   = N'') SELECT @output_file_name   = NULL
  6441.  
  6442.   -- Check new values
  6443.   EXECUTE @retval = sp_verify_jobstep @job_id,
  6444.                                       @step_id,
  6445.                                       @new_step_name,
  6446.                                       @subsystem,
  6447.                                       @command,
  6448.                                       @server,
  6449.                                       @on_success_action,
  6450.                                       @on_success_step_id,
  6451.                                       @on_fail_action,
  6452.                                       @on_fail_step_id,
  6453.                                       @os_run_priority,
  6454.                                       @database_name      OUTPUT,
  6455.                                       @database_user_name OUTPUT,
  6456.                                       @flags,
  6457.                                       @output_file_name
  6458.   IF (@retval <> 0)
  6459.     RETURN(1) -- Failure
  6460.  
  6461.   BEGIN TRANSACTION
  6462.  
  6463.     -- Update the job's version/last-modified information
  6464.     UPDATE msdb.dbo.sysjobs
  6465.     SET version_number = version_number + 1,
  6466.         date_modified = GETDATE()
  6467.     WHERE (job_id = @job_id)
  6468.  
  6469.     -- Update the step
  6470.     UPDATE msdb.dbo.sysjobsteps
  6471.     SET step_name             = @step_name,
  6472.         subsystem             = @subsystem,
  6473.         command               = @command,
  6474.         flags                 = @flags,
  6475.         cmdexec_success_code  = @cmdexec_success_code,
  6476.         on_success_action     = @on_success_action,
  6477.         on_success_step_id    = @on_success_step_id,
  6478.         on_fail_action        = @on_fail_action,
  6479.         on_fail_step_id       = @on_fail_step_id,
  6480.         server                = @server,
  6481.         database_name         = @database_name,
  6482.         database_user_name    = @database_user_name,
  6483.         retry_attempts        = @retry_attempts,
  6484.         retry_interval        = @retry_interval,
  6485.         os_run_priority       = @os_run_priority,
  6486.         output_file_name      = @output_file_name,
  6487.         last_run_outcome      = @x_last_run_outcome,
  6488.         last_run_duration     = @x_last_run_duration,
  6489.         last_run_retries      = @x_last_run_retries,
  6490.         last_run_date         = @x_last_run_date,
  6491.         last_run_time         = @x_last_run_time
  6492.     WHERE (job_id = @job_id)
  6493.       AND (step_id = @step_id)
  6494.  
  6495.     -- Since we can't declare TEXT parameters (and therefore use the @x_ technique) we handle
  6496.     -- @additional_parameters as a special case...
  6497.     IF (@additional_parameters IS NOT NULL)
  6498.     BEGIN
  6499.       UPDATE msdb.dbo.sysjobsteps
  6500.       SET additional_parameters = @additional_parameters
  6501.       WHERE (job_id = @job_id)
  6502.         AND (step_id = @step_id)
  6503.     END
  6504.  
  6505.   COMMIT TRANSACTION
  6506.  
  6507.   -- For a multi-server job, remind the user that they need to call sp_post_msx_operation
  6508.   IF (EXISTS (SELECT *
  6509.               FROM msdb.dbo.sysjobservers
  6510.               WHERE (job_id = @job_id)
  6511.                 AND (server_id <> 0)))
  6512.     RAISERROR(14547, 0, 1, N'INSERT', N'sp_post_msx_operation')
  6513.  
  6514.   RETURN(0) -- Success
  6515. END
  6516. go
  6517.  
  6518. /**************************************************************/
  6519. /* SP_DELETE_JOBSTEP                                          */
  6520. /**************************************************************/
  6521.  
  6522. PRINT ''
  6523. PRINT 'Creating procedure sp_delete_jobstep...'
  6524. go
  6525. IF (EXISTS (SELECT *
  6526.             FROM msdb.dbo.sysobjects
  6527.             WHERE (name = N'sp_delete_jobstep')
  6528.               AND (type = 'P')))
  6529.   DROP PROCEDURE sp_delete_jobstep
  6530. go
  6531. CREATE PROCEDURE sp_delete_jobstep
  6532.   @job_id   UNIQUEIDENTIFIER = NULL, -- Must provide either this or job_name
  6533.   @job_name sysname          = NULL, -- Must provide either this or job_id
  6534.   @step_id  INT
  6535. AS
  6536. BEGIN
  6537.   DECLARE @retval      INT
  6538.   DECLARE @max_step_id INT
  6539.   DECLARE @valid_range VARCHAR(50)
  6540.  
  6541.   SET NOCOUNT ON
  6542.  
  6543.   EXECUTE @retval = sp_verify_job_identifiers '@job_name',
  6544.                                               '@job_id',
  6545.                                                @job_name OUTPUT,
  6546.                                                @job_id   OUTPUT
  6547.   IF (@retval <> 0)
  6548.     RETURN(1) -- Failure
  6549.  
  6550.   -- Check authority (only SQLServerAgent can delete a step of a non-local job)
  6551.   EXECUTE @retval = sp_verify_jobproc_caller @job_id = @job_id, @program_name = 'SQLAgent%'
  6552.   IF (@retval <> 0)
  6553.     RETURN(@retval)
  6554.  
  6555.   -- Get current maximum step id
  6556.   SELECT @max_step_id = ISNULL(MAX(step_id), 0)
  6557.   FROM msdb.dbo.sysjobsteps
  6558.   WHERE (job_id = @job_id)
  6559.  
  6560.   -- Check step id
  6561.   IF (@step_id < 0) OR (@step_id > @max_step_id)
  6562.   BEGIN
  6563.     SELECT @valid_range = FORMATMESSAGE(14201) + CONVERT(VARCHAR, @max_step_id)
  6564.     RAISERROR(14266, -1, -1, '@step_id', @valid_range)
  6565.     RETURN(1) -- Failure
  6566.   END
  6567.  
  6568.   BEGIN TRANSACTION
  6569.  
  6570.     -- Delete either the specified step or ALL the steps (if step id is 0)
  6571.     IF (@step_id = 0)
  6572.       DELETE FROM msdb.dbo.sysjobsteps
  6573.       WHERE (job_id = @job_id)
  6574.     ELSE
  6575.       DELETE FROM msdb.dbo.sysjobsteps
  6576.       WHERE (job_id = @job_id)
  6577.         AND (step_id = @step_id)
  6578.  
  6579.     IF (@step_id <> 0)
  6580.     BEGIN
  6581.       -- Adjust step id's
  6582.       UPDATE msdb.dbo.sysjobsteps
  6583.       SET step_id = step_id - 1
  6584.       WHERE (step_id > @step_id)
  6585.         AND (job_id = @job_id)
  6586.  
  6587.       -- Clean up OnSuccess/OnFail references
  6588.       UPDATE msdb.dbo.sysjobsteps
  6589.       SET on_success_step_id = on_success_step_id - 1
  6590.       WHERE (on_success_step_id > @step_id)
  6591.         AND (job_id = @job_id)
  6592.  
  6593.       UPDATE msdb.dbo.sysjobsteps
  6594.       SET on_fail_step_id = on_fail_step_id - 1
  6595.       WHERE (on_fail_step_id > @step_id)
  6596.         AND (job_id = @job_id)
  6597.  
  6598.       UPDATE msdb.dbo.sysjobsteps
  6599.       SET on_success_step_id = 0,
  6600.           on_success_action = 1   -- Quit With Success
  6601.       WHERE (on_success_step_id = @step_id)
  6602.         AND (job_id = @job_id)
  6603.  
  6604.       UPDATE msdb.dbo.sysjobsteps
  6605.       SET on_fail_step_id = 0,
  6606.           on_fail_action = 2   -- Quit With Failure
  6607.       WHERE (on_fail_step_id = @step_id)
  6608.         AND (job_id = @job_id)
  6609.     END
  6610.  
  6611.     -- Update the job's version/last-modified information
  6612.     UPDATE msdb.dbo.sysjobs
  6613.     SET version_number = version_number + 1,
  6614.         date_modified = GETDATE()
  6615.     WHERE (job_id = @job_id)
  6616.  
  6617.   COMMIT TRANSACTION
  6618.  
  6619.   -- Make sure that SQLServerAgent refreshes the job if the 'Has Steps' property has changed
  6620.   IF ((SELECT COUNT(*)
  6621.        FROM msdb.dbo.sysjobsteps
  6622.        WHERE (job_id = @job_id)) = 0)
  6623.   BEGIN
  6624.     -- NOTE: We only notify SQLServerAgent if we know the job has been cached
  6625.     IF (EXISTS (SELECT * 
  6626.                 FROM msdb.dbo.sysjobservers 
  6627.                 WHERE (job_id = @job_id)
  6628.                   AND (server_id = 0)))
  6629.       EXECUTE msdb.dbo.sp_sqlagent_notify @op_type       = N'J',
  6630.                                             @job_id      = @job_id,
  6631.                                             @action_type = N'U'
  6632.   END
  6633.  
  6634.   -- For a multi-server job, remind the user that they need to call sp_post_msx_operation
  6635.   IF (EXISTS (SELECT *
  6636.               FROM msdb.dbo.sysjobservers
  6637.               WHERE (job_id = @job_id)
  6638.                 AND (server_id <> 0)))
  6639.     RAISERROR(14547, 0, 1, N'INSERT', N'sp_post_msx_operation')
  6640.  
  6641.   RETURN(0) -- Success
  6642. END
  6643. go
  6644.  
  6645. /**************************************************************/
  6646. /* SP_HELP_JOBSTEP                                            */
  6647. /**************************************************************/
  6648.  
  6649. PRINT ''
  6650. PRINT 'Creating procedure sp_help_jobstep...'
  6651. go
  6652. IF (EXISTS (SELECT *
  6653.             FROM msdb.dbo.sysobjects
  6654.             WHERE (name = N'sp_help_jobstep')
  6655.               AND (type = 'P')))
  6656.   DROP PROCEDURE sp_help_jobstep
  6657. go
  6658. CREATE PROCEDURE sp_help_jobstep
  6659.   @job_id    UNIQUEIDENTIFIER = NULL, -- Must provide either this or job_name
  6660.   @job_name  sysname          = NULL, -- Must provide either this or job_id
  6661.   @step_id   INT              = NULL,
  6662.   @step_name sysname          = NULL,
  6663.   @suffix    BIT              = 0     -- A flag to control how the result set is formatted
  6664. AS
  6665. BEGIN
  6666.   DECLARE @retval      INT
  6667.   DECLARE @max_step_id INT
  6668.   DECLARE @valid_range VARCHAR(50)
  6669.  
  6670.   SET NOCOUNT ON
  6671.  
  6672.   EXECUTE @retval = sp_verify_job_identifiers '@job_name',
  6673.                                               '@job_id',
  6674.                                                @job_name OUTPUT,
  6675.                                                @job_id   OUTPUT,
  6676.                                               'NO_TEST'
  6677.   IF (@retval <> 0)
  6678.     RETURN(1) -- Failure
  6679.  
  6680.   -- The suffix flag must be either 0 (ie. no suffix) or 1 (ie. add suffix). 0 is the default.
  6681.   IF (@suffix <> 0)
  6682.     SELECT @suffix = 1
  6683.  
  6684.   -- Check step id (if supplied)
  6685.   IF (@step_id IS NOT NULL)
  6686.   BEGIN
  6687.     -- Get current maximum step id
  6688.     SELECT @max_step_id = ISNULL(MAX(step_id), 0)
  6689.     FROM msdb.dbo.sysjobsteps
  6690.     WHERE job_id = @job_id
  6691.  
  6692.     IF (@step_id < 1) OR (@step_id > @max_step_id)
  6693.     BEGIN
  6694.       SELECT @valid_range = '1..' + CONVERT(VARCHAR, @max_step_id)
  6695.       RAISERROR(14266, -1, -1, '@step_id', @valid_range)
  6696.       RETURN(1) -- Failure
  6697.     END
  6698.   END
  6699.  
  6700.   -- Check step name (if supplied)
  6701.   -- NOTE: A supplied step id overrides a supplied step name
  6702.   IF ((@step_id IS NULL) AND (@step_name IS NOT NULL)) 
  6703.   BEGIN
  6704.     SELECT @step_id = step_id
  6705.     FROM msdb.dbo.sysjobsteps
  6706.     WHERE (step_name = @step_name)
  6707.       AND (job_id = @job_id)
  6708.  
  6709.     IF (@step_id IS NULL)
  6710.     BEGIN
  6711.       RAISERROR(14262, -1, -1, '@step_name', @step_name)
  6712.       RETURN(1) -- Failure
  6713.     END
  6714.   END
  6715.  
  6716.   -- Return the job steps for this job (or just return the specific step)
  6717.   IF (@suffix = 0)
  6718.   BEGIN
  6719.     SELECT step_id,
  6720.            step_name,
  6721.            subsystem,
  6722.            command,
  6723.            flags,
  6724.            cmdexec_success_code,
  6725.            on_success_action,
  6726.            on_success_step_id,
  6727.            on_fail_action,
  6728.            on_fail_step_id,
  6729.            server,
  6730.            database_name,
  6731.            database_user_name,
  6732.            retry_attempts,
  6733.            retry_interval,
  6734.            os_run_priority,
  6735.            output_file_name,
  6736.            last_run_outcome,
  6737.            last_run_duration,
  6738.            last_run_retries,
  6739.            last_run_date,
  6740.            last_run_time
  6741.     FROM msdb.dbo.sysjobsteps
  6742.     WHERE (job_id = @job_id)
  6743.       AND ((@step_id IS NULL) OR (step_id = @step_id))
  6744.   END
  6745.   ELSE
  6746.   BEGIN
  6747.     SELECT step_id,
  6748.            step_name,
  6749.            subsystem,
  6750.            command,
  6751.           'flags' = CONVERT(NVARCHAR, flags) + N' (' +
  6752.                     ISNULL(CASE WHEN (flags = 0)     THEN FORMATMESSAGE(14561) END, '') +
  6753.                     ISNULL(CASE WHEN (flags & 1) = 1 THEN FORMATMESSAGE(14558) + ISNULL(CASE WHEN (flags > 1) THEN N', ' END, '') END, '') +
  6754.                     ISNULL(CASE WHEN (flags & 2) = 2 THEN FORMATMESSAGE(14559) + ISNULL(CASE WHEN (flags > 3) THEN N', ' END, '') END, '') +
  6755.                     ISNULL(CASE WHEN (flags & 4) = 4 THEN FORMATMESSAGE(14560) END, '') + N')',
  6756.            cmdexec_success_code,
  6757.           'on_success_action' = CASE on_success_action
  6758.                                   WHEN 1 THEN CONVERT(NVARCHAR, on_success_action) + N' ' + FORMATMESSAGE(14562)
  6759.                                   WHEN 2 THEN CONVERT(NVARCHAR, on_success_action) + N' ' + FORMATMESSAGE(14563)
  6760.                                   WHEN 3 THEN CONVERT(NVARCHAR, on_success_action) + N' ' + FORMATMESSAGE(14564)
  6761.                                   WHEN 4 THEN CONVERT(NVARCHAR, on_success_action) + N' ' + FORMATMESSAGE(14565)
  6762.                                   ELSE        CONVERT(NVARCHAR, on_success_action) + N' ' + FORMATMESSAGE(14205)
  6763.                                 END,
  6764.            on_success_step_id,
  6765.           'on_fail_action' = CASE on_fail_action
  6766.                                WHEN 1 THEN CONVERT(NVARCHAR, on_fail_action) + N' ' + FORMATMESSAGE(14562)
  6767.                                WHEN 2 THEN CONVERT(NVARCHAR, on_fail_action) + N' ' + FORMATMESSAGE(14563)
  6768.                                WHEN 3 THEN CONVERT(NVARCHAR, on_fail_action) + N' ' + FORMATMESSAGE(14564)
  6769.                                WHEN 4 THEN CONVERT(NVARCHAR, on_fail_action) + N' ' + FORMATMESSAGE(14565)
  6770.                                ELSE        CONVERT(NVARCHAR, on_fail_action) + N' ' + FORMATMESSAGE(14205)
  6771.                              END,
  6772.            on_fail_step_id,
  6773.            server,
  6774.            database_name,
  6775.            database_user_name,
  6776.            retry_attempts,
  6777.            retry_interval,
  6778.           'os_run_priority' = CASE os_run_priority
  6779.                                 WHEN -15 THEN CONVERT(NVARCHAR, os_run_priority) + N' ' + FORMATMESSAGE(14566)
  6780.                                 WHEN -1  THEN CONVERT(NVARCHAR, os_run_priority) + N' ' + FORMATMESSAGE(14567)
  6781.                                 WHEN  0  THEN CONVERT(NVARCHAR, os_run_priority) + N' ' + FORMATMESSAGE(14561)
  6782.                                 WHEN  1  THEN CONVERT(NVARCHAR, os_run_priority) + N' ' + FORMATMESSAGE(14568)
  6783.                                 WHEN  15 THEN CONVERT(NVARCHAR, os_run_priority) + N' ' + FORMATMESSAGE(14569)
  6784.                                 ELSE          CONVERT(NVARCHAR, os_run_priority) + N' ' + FORMATMESSAGE(14205)
  6785.                               END,
  6786.            output_file_name,
  6787.            last_run_outcome,
  6788.            last_run_duration,
  6789.            last_run_retries,
  6790.            last_run_date,
  6791.            last_run_time
  6792.     FROM msdb.dbo.sysjobsteps
  6793.     WHERE (job_id = @job_id)
  6794.       AND ((@step_id IS NULL) OR (step_id = @step_id))
  6795.   END
  6796.  
  6797.   RETURN(@@error) -- 0 means success
  6798.  
  6799. END
  6800. go
  6801.  
  6802. /**************************************************************/
  6803. /* SP_GET_SCHEDULE_DESCRIPTION                                */
  6804. /*                                                            */
  6805. /* NOTE: This SP only returns an English description of the   */
  6806. /*       schedule due to the piecemeal nature of the          */
  6807. /*       description's construction.                          */
  6808. /**************************************************************/
  6809.  
  6810. PRINT ''
  6811. PRINT 'Creating procedure sp_get_schedule_description...'
  6812. go
  6813. IF (EXISTS (SELECT *
  6814.             FROM msdb.dbo.sysobjects
  6815.             WHERE (name = N'sp_get_schedule_description')
  6816.               AND (type = 'P')))
  6817.   DROP PROCEDURE sp_get_schedule_description
  6818. go
  6819. CREATE PROCEDURE sp_get_schedule_description
  6820.   @freq_type              INT          = NULL,
  6821.   @freq_interval          INT          = NULL,
  6822.   @freq_subday_type       INT          = NULL,
  6823.   @freq_subday_interval   INT          = NULL,
  6824.   @freq_relative_interval INT          = NULL,
  6825.   @freq_recurrence_factor INT          = NULL,
  6826.   @active_start_date      INT          = NULL,
  6827.   @active_end_date        INT          = NULL,
  6828.   @active_start_time      INT          = NULL,
  6829.   @active_end_time        INT          = NULL,
  6830.   @schedule_description   NVARCHAR(255) OUTPUT
  6831. AS
  6832. BEGIN
  6833.   DECLARE @loop              INT
  6834.   DECLARE @idle_cpu_percent  INT
  6835.   DECLARE @idle_cpu_duration INT
  6836.  
  6837.   SET NOCOUNT ON
  6838.  
  6839.   IF (@freq_type = 0x1) -- OneTime
  6840.   BEGIN
  6841.     SELECT @schedule_description = N'Once on ' + CONVERT(NVARCHAR, @active_start_date) + N' at ' + CONVERT(NVARCHAR, @active_start_time)
  6842.     RETURN
  6843.   END
  6844.  
  6845.   IF (@freq_type = 0x4) -- Daily
  6846.   BEGIN
  6847.     SELECT @schedule_description = N'Every day '
  6848.   END
  6849.  
  6850.   IF (@freq_type = 0x8) -- Weekly
  6851.   BEGIN
  6852.     SELECT @schedule_description = N'Every ' + CONVERT(NVARCHAR, @freq_recurrence_factor) + N' week(s) on '
  6853.     SELECT @loop = 1
  6854.     WHILE (@loop <= 7)
  6855.     BEGIN
  6856.       IF (@freq_interval & POWER(2, @loop - 1) = POWER(2, @loop - 1))
  6857.         SELECT @schedule_description = @schedule_description + DATENAME(dw, N'1996120' + CONVERT(NVARCHAR, @loop)) + N', '
  6858.       SELECT @loop = @loop + 1
  6859.     END
  6860.     IF (RIGHT(@schedule_description, 2) = N', ')
  6861.       SELECT @schedule_description = SUBSTRING(@schedule_description, 1, (DATALENGTH(@schedule_description) / 2) - 2) + N' '
  6862.   END
  6863.  
  6864.   IF (@freq_type = 0x10) -- Monthly
  6865.   BEGIN
  6866.     SELECT @schedule_description = N'Every ' + CONVERT(NVARCHAR, @freq_recurrence_factor) + N' months(s) on day ' + CONVERT(NVARCHAR, @freq_interval) + N' of that month '
  6867.   END
  6868.  
  6869.   IF (@freq_type = 0x20) -- Monthly Relative
  6870.   BEGIN
  6871.     SELECT @schedule_description = N'Every ' + CONVERT(NVARCHAR, @freq_recurrence_factor) + N' months(s) on the '
  6872.     SELECT @schedule_description = @schedule_description +
  6873.       CASE @freq_relative_interval
  6874.         WHEN 0x01 THEN N'first '
  6875.         WHEN 0x02 THEN N'second '
  6876.         WHEN 0x04 THEN N'third '
  6877.         WHEN 0x08 THEN N'fourth '
  6878.         WHEN 0x10 THEN N'last '
  6879.       END +
  6880.       CASE
  6881.         WHEN (@freq_interval > 00)
  6882.          AND (@freq_interval < 08) THEN DATENAME(dw, N'1996120' + CONVERT(NVARCHAR, @freq_interval))
  6883.         WHEN (@freq_interval = 08) THEN N'day'
  6884.         WHEN (@freq_interval = 09) THEN N'week day'
  6885.         WHEN (@freq_interval = 10) THEN N'weekend day'
  6886.       END + N' of that month '
  6887.   END
  6888.  
  6889.   IF (@freq_type = 0x40) -- AutoStart
  6890.   BEGIN
  6891.     SELECT @schedule_description = FORMATMESSAGE(14579)
  6892.     RETURN
  6893.   END
  6894.  
  6895.   IF (@freq_type = 0x80) -- OnIdle
  6896.   BEGIN
  6897.     EXECUTE master.dbo.xp_regread N'HKEY_LOCAL_MACHINE',
  6898.                                   N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
  6899.                                   N'IdleCPUPercent',
  6900.                                    @idle_cpu_percent OUTPUT,
  6901.                                   N'no_output'
  6902.     EXECUTE master.dbo.xp_regread N'HKEY_LOCAL_MACHINE',
  6903.                                   N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
  6904.                                   N'IdleCPUDuration',
  6905.                                    @idle_cpu_duration OUTPUT,
  6906.                                   N'no_output'
  6907.     SELECT @schedule_description = FORMATMESSAGE(14578, ISNULL(@idle_cpu_percent, 10), ISNULL(@idle_cpu_duration, 600))
  6908.     RETURN
  6909.   END
  6910.  
  6911.   -- Subday stuff
  6912.   SELECT @schedule_description = @schedule_description +
  6913.     CASE @freq_subday_type
  6914.       WHEN 0x1 THEN N'at ' + CONVERT(NVARCHAR, @active_start_time)
  6915.       WHEN 0x2 THEN N'every ' + CONVERT(NVARCHAR, @freq_subday_interval) + N' second(s)'
  6916.       WHEN 0x4 THEN N'every ' + CONVERT(NVARCHAR, @freq_subday_interval) + N' minute(s)'
  6917.       WHEN 0x8 THEN N'every ' + CONVERT(NVARCHAR, @freq_subday_interval) + N' hour(s)'
  6918.     END
  6919.   IF (@freq_subday_type IN (0x2, 0x4, 0x8))
  6920.     SELECT @schedule_description = @schedule_description + N' between ' +
  6921.            CONVERT(NVARCHAR, @active_start_time) + N' and ' + CONVERT(NVARCHAR, @active_end_time)
  6922. END
  6923. go
  6924.  
  6925. DUMP TRANSACTION msdb WITH NO_LOG
  6926. go
  6927. CHECKPOINT
  6928. go
  6929.  
  6930. /**************************************************************/
  6931. /* SP_VERIFY_JOBSCHEDULE                                      */
  6932. /**************************************************************/
  6933.  
  6934. PRINT ''
  6935. PRINT 'Creating procedure sp_verify_jobschedule...'
  6936. go
  6937. IF (EXISTS (SELECT *
  6938.             FROM msdb.dbo.sysobjects
  6939.             WHERE (name = N'sp_verify_jobschedule')
  6940.               AND (type = 'P')))
  6941.   DROP PROCEDURE sp_verify_jobschedule
  6942. go
  6943. CREATE PROCEDURE sp_verify_jobschedule
  6944.   @name                   sysname,
  6945.   @enabled                TINYINT,
  6946.   @freq_type              INT,
  6947.   @freq_interval          INT OUTPUT,   -- Output because we may set it to 0 if Frequency Type is one-time or auto-start
  6948.   @freq_subday_type       INT OUTPUT,   -- As above
  6949.   @freq_subday_interval   INT OUTPUT,   -- As above
  6950.   @freq_relative_interval INT OUTPUT,   -- As above
  6951.   @freq_recurrence_factor INT OUTPUT,   -- As above
  6952.   @active_start_date      INT OUTPUT,
  6953.   @active_start_time      INT OUTPUT,
  6954.   @active_end_date        INT OUTPUT,
  6955.   @active_end_time        INT OUTPUT,
  6956.   @job_id                 UNIQUEIDENTIFIER,
  6957.   @schedule_id            INT           -- Will only be provided by sp_update_jobschedule
  6958. AS
  6959. BEGIN
  6960.   DECLARE @return_code             INT
  6961.   DECLARE @duplicate_schedule_id   INT
  6962.   DECLARE @duplicate_schedule_name sysname
  6963.   DECLARE @res_valid_range         NVARCHAR(100)
  6964.   DECLARE @reason                  NVARCHAR(200)
  6965.  
  6966.   SET NOCOUNT ON
  6967.  
  6968.   -- Remove any leading/trailing spaces from parameters
  6969.   SELECT @name = LTRIM(RTRIM(@name))
  6970.  
  6971.   -- Make sure that NULL input/output parameters - if NULL - are initialized to 0
  6972.   SELECT @freq_interval          = ISNULL(@freq_interval, 0)
  6973.   SELECT @freq_subday_type       = ISNULL(@freq_subday_type, 0)
  6974.   SELECT @freq_subday_interval   = ISNULL(@freq_subday_interval, 0)
  6975.   SELECT @freq_relative_interval = ISNULL(@freq_relative_interval, 0)
  6976.   SELECT @freq_recurrence_factor = ISNULL(@freq_recurrence_factor, 0)
  6977.   SELECT @active_start_date      = ISNULL(@active_start_date, 0)
  6978.   SELECT @active_start_time      = ISNULL(@active_start_time, 0)
  6979.   SELECT @active_end_date        = ISNULL(@active_end_date, 0)
  6980.   SELECT @active_end_time        = ISNULL(@active_end_time, 0)
  6981.  
  6982.   -- Verify name (we disallow schedules called 'ALL' since this has special meaning in sp_delete_jobschedules)
  6983.   IF (UPPER(@name) = N'ALL')
  6984.   BEGIN
  6985.     RAISERROR(14200, -1, -1, '@name')
  6986.     RETURN(1) -- Failure
  6987.   END
  6988.  
  6989.   -- Verify enabled state
  6990.   IF (@enabled <> 0) AND (@enabled <> 1)
  6991.   BEGIN
  6992.     RAISERROR(14266, -1, -1, '@enabled', '0, 1')
  6993.     RETURN(1) -- Failure
  6994.   END
  6995.  
  6996.   -- Verify frequency type
  6997.   IF (@freq_type = 0x2) -- OnDemand is no longer supported
  6998.   BEGIN
  6999.     RAISERROR(14295, -1, -1)
  7000.     RETURN(1) -- Failure
  7001.   END
  7002.   IF (@freq_type NOT IN (0x1, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80))
  7003.   BEGIN
  7004.     RAISERROR(14266, -1, -1, '@freq_type', '0x1, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80')
  7005.     RETURN(1) -- Failure
  7006.   END
  7007.  
  7008.   -- Verify frequency sub-day type
  7009.   IF (@freq_subday_type <> 0) AND (@freq_subday_type NOT IN (0x1, 0x2, 0x4, 0x8))
  7010.   BEGIN
  7011.     RAISERROR(14266, -1, -1, '@freq_subday_type', '0x1, 0x2, 0x4, 0x8')
  7012.     RETURN(1) -- Failure
  7013.   END
  7014.  
  7015.   -- Default active start/end date/times (if not supplied, or supplied as NULLs or 0)
  7016.   IF (@active_start_date = 0)
  7017.     SELECT @active_start_date = DATEPART(yy, GETDATE()) * 10000 +
  7018.                                 DATEPART(mm, GETDATE()) * 100 +
  7019.                                 DATEPART(dd, GETDATE())
  7020.   IF (@active_end_date = 0)
  7021.     SELECT @active_end_date = 99991231  -- December 31st 9999
  7022.   IF (@active_start_time = 0)
  7023.     SELECT @active_start_time = 000000  -- 12:00:00 am
  7024.   IF (@active_end_time = 0)
  7025.     SELECT @active_end_time = 235959    -- 11:59:59 pm
  7026.  
  7027.   -- Verify active start/end dates
  7028.   IF (@active_end_date = 0)
  7029.     SELECT @active_end_date = 99991231
  7030.  
  7031.   EXECUTE @return_code = sp_verify_job_date @active_end_date, '@active_end_date'
  7032.   IF (@return_code <> 0)
  7033.     RETURN(1) -- Failure
  7034.  
  7035.   EXECUTE @return_code = sp_verify_job_date @active_start_date, '@active_start_date'
  7036.   IF (@return_code <> 0)
  7037.     RETURN(1) -- Failure
  7038.  
  7039.   IF (@active_end_date < @active_start_date)
  7040.   BEGIN
  7041.     RAISERROR(14288, -1, -1, '@active_end_date', '@active_start_date')
  7042.     RETURN(1) -- Failure
  7043.   END
  7044.  
  7045.   -- Verify active start/end times
  7046.   IF (@active_end_time = 0)
  7047.     SELECT @active_end_time = 235959
  7048.  
  7049.   EXECUTE @return_code = sp_verify_job_time @active_end_time, '@active_end_time'
  7050.   IF (@return_code <> 0)
  7051.     RETURN(1) -- Failure
  7052.  
  7053.   EXECUTE @return_code = sp_verify_job_time @active_start_time, '@active_start_time'
  7054.   IF (@return_code <> 0)
  7055.     RETURN(1) -- Failure
  7056.  
  7057.   -- NOTE: It's valid for active_end_time to be less than active_start_time since in this
  7058.   --       case we assume that the user wants the active time zone to span midnight.
  7059.   --       But it's not valid for active_start_date and active_end_date to be the same...
  7060.   IF (@active_start_time = @active_end_time)
  7061.   BEGIN
  7062.     SELECT @res_valid_range = FORMATMESSAGE(14202)
  7063.     RAISERROR(14266, -1, -1, '@active_end_time', @res_valid_range)
  7064.     RETURN(1) -- Failure
  7065.   END
  7066.  
  7067.   -- NOTE: The rest of this procedure is a SQL implementation of VerifySchedule in job.c
  7068.  
  7069.   IF ((@freq_type = 0x1) OR  -- FREQTYPE_ONETIME
  7070.       (@freq_type = 0x40) OR -- FREQTYPE_AUTOSTART
  7071.       (@freq_type = 0x80))   -- FREQTYPE_ONIDLE
  7072.   BEGIN
  7073.     -- Set standard defaults for non-required parameters
  7074.     SELECT @freq_interval          = 0
  7075.     SELECT @freq_subday_type       = 0
  7076.     SELECT @freq_subday_interval   = 0
  7077.     SELECT @freq_relative_interval = 0
  7078.     SELECT @freq_recurrence_factor = 0
  7079. /*
  7080.     -- Check that a one-time schedule isn't already in the past
  7081.     IF (@freq_type = 0x1) -- FREQTYPE_ONETIME
  7082.     BEGIN
  7083.       DECLARE @current_date INT
  7084.       DECLARE @current_time INT
  7085.  
  7086.       SELECT @current_date = CONVERT(INT, CONVERT(VARCHAR, GETDATE(), 112))
  7087.       SELECT @current_time = (DATEPART(hh, GETDATE()) * 10000) + (DATEPART(mi, GETDATE()) * 100) + DATEPART(ss, GETDATE())
  7088.       IF (@active_start_date < @current_date) OR ((@active_start_date = @current_date) AND (@active_start_time <= @current_time))
  7089.       BEGIN
  7090.         SELECT @res_valid_range = '> ' + CONVERT(VARCHAR, @current_date) + ' / ' + CONVERT(VARCHAR, @current_time)
  7091.         RAISERROR(14266, -1, -1, '@active_start_date'' / ''@active_start_time', @res_valid_range)
  7092.         RETURN(1) -- Failure
  7093.       END
  7094.     END
  7095. */
  7096.     GOTO CheckForDuplicate
  7097.   END
  7098.  
  7099.   -- Safety net: If the sub-day-type is 0 (and we know that the schedule is not a one-time or
  7100.   --             auto-start) then set it to 1 (FREQSUBTYPE_ONCE).  If the user wanted something
  7101.   --             other than ONCE then they should have explicitly set @freq_subday_type.
  7102.   IF (@freq_subday_type = 0)
  7103.     SELECT @freq_subday_type = 0x1 -- FREQSUBTYPE_ONCE
  7104.  
  7105.   IF ((@freq_subday_type <> 0x1) AND  -- FREQSUBTYPE_ONCE   (see qsched.h)
  7106.       (@freq_subday_type <> 0x2) AND  -- FREQSUBTYPE_SECOND (see qsched.h)
  7107.       (@freq_subday_type <> 0x4) AND  -- FREQSUBTYPE_MINUTE (see qsched.h)
  7108.       (@freq_subday_type <> 0x8))     -- FREQSUBTYPE_HOUR   (see qsched.h)
  7109.   BEGIN
  7110.     SELECT @reason = FORMATMESSAGE(14266, '@freq_subday_type', '0x1, 0x2, 0x4, 0x8')
  7111.     RAISERROR(14278, -1, -1, @reason)
  7112.     RETURN(1) -- Failure
  7113.   END
  7114.   IF ((@freq_subday_type <> 0x1) AND (@freq_subday_interval < 1))
  7115.      OR
  7116.      ((@freq_subday_type = 0x2) AND (@freq_subday_interval < 10))
  7117.   BEGIN
  7118.     SELECT @reason = FORMATMESSAGE(14200, '@freq_subday_interval')
  7119.     RAISERROR(14278, -1, -1, @reason)
  7120.     RETURN(1) -- Failure
  7121.   END
  7122.  
  7123.   IF (@freq_type = 0x4)      -- FREQTYPE_DAILY
  7124.   BEGIN
  7125.     SELECT @freq_recurrence_factor = 0
  7126.     IF (@freq_interval < 1)
  7127.     BEGIN
  7128.       SELECT @reason = FORMATMESSAGE(14572)
  7129.       RAISERROR(14278, -1, -1, @reason)
  7130.       RETURN(1) -- Failure
  7131.     END
  7132.   END
  7133.  
  7134.   IF (@freq_type = 0x8)      -- FREQTYPE_WEEKLY
  7135.   BEGIN
  7136.     IF (@freq_interval < 1)   OR
  7137.        (@freq_interval > 127) -- (2^7)-1 [freq_interval is a bitmap (Sun=1..Sat=64)]
  7138.     BEGIN
  7139.       SELECT @reason = FORMATMESSAGE(14573)
  7140.       RAISERROR(14278, -1, -1, @reason)
  7141.       RETURN(1) -- Failure
  7142.     END
  7143.   END
  7144.  
  7145.   IF (@freq_type = 0x10)    -- FREQTYPE_MONTHLY
  7146.   BEGIN
  7147.     IF (@freq_interval < 1)  OR
  7148.        (@freq_interval > 31)
  7149.     BEGIN
  7150.       SELECT @reason = FORMATMESSAGE(14574)
  7151.       RAISERROR(14278, -1, -1, @reason)
  7152.       RETURN(1) -- Failure
  7153.     END
  7154.   END
  7155.  
  7156.   IF (@freq_type = 0x20)     -- FREQTYPE_MONTHLYRELATIVE
  7157.   BEGIN
  7158.     IF (@freq_relative_interval <> 0x01) AND  -- RELINT_1ST
  7159.        (@freq_relative_interval <> 0x02) AND  -- RELINT_2ND
  7160.        (@freq_relative_interval <> 0x04) AND  -- RELINT_3RD
  7161.        (@freq_relative_interval <> 0x08) AND  -- RELINT_4TH
  7162.        (@freq_relative_interval <> 0x10)      -- RELINT_LAST
  7163.     BEGIN
  7164.       SELECT @reason = FORMATMESSAGE(14575)
  7165.       RAISERROR(14278, -1, -1, @reason)
  7166.       RETURN(1) -- Failure
  7167.     END
  7168.   END
  7169.  
  7170.   IF (@freq_type = 0x20)     -- FREQTYPE_MONTHLYRELATIVE
  7171.   BEGIN
  7172.     IF (@freq_interval <> 01) AND -- RELATIVE_SUN
  7173.        (@freq_interval <> 02) AND -- RELATIVE_MON
  7174.        (@freq_interval <> 03) AND -- RELATIVE_TUE
  7175.        (@freq_interval <> 04) AND -- RELATIVE_WED
  7176.        (@freq_interval <> 05) AND -- RELATIVE_THU
  7177.        (@freq_interval <> 06) AND -- RELATIVE_FRI
  7178.        (@freq_interval <> 07) AND -- RELATIVE_SAT
  7179.        (@freq_interval <> 08) AND -- RELATIVE_DAY
  7180.        (@freq_interval <> 09) AND -- RELATIVE_WEEKDAY
  7181.        (@freq_interval <> 10)     -- RELATIVE_WEEKENDDAY
  7182.     BEGIN
  7183.       SELECT @reason = FORMATMESSAGE(14576)
  7184.       RAISERROR(14278, -1, -1, @reason)
  7185.       RETURN(1) -- Failure
  7186.     END
  7187.   END
  7188.  
  7189.   IF ((@freq_type = 0x08)  OR   -- FREQTYPE_WEEKLY
  7190.       (@freq_type = 0x10)  OR   -- FREQTYPE_MONTHLY
  7191.       (@freq_type = 0x20)) AND  -- FREQTYPE_MONTHLYRELATIVE
  7192.       (@freq_recurrence_factor < 1)
  7193.   BEGIN
  7194.     SELECT @reason = FORMATMESSAGE(14577)
  7195.     RAISERROR(14278, -1, -1, @reason)
  7196.     RETURN(1) -- Failure
  7197.   END
  7198.  
  7199. CheckForDuplicate:
  7200.  
  7201.   -- Check that the schedule is not a duplicate
  7202.   SELECT @duplicate_schedule_id = NULL
  7203.   SELECT @duplicate_schedule_id = schedule_id,
  7204.          @duplicate_schedule_name = name
  7205.   FROM msdb.dbo.sysjobschedules
  7206.   WHERE (job_id                 = @job_id)
  7207.     AND (freq_type              = @freq_type)
  7208.     AND (freq_interval          = @freq_interval)
  7209.     AND (freq_subday_type       = @freq_subday_type)
  7210.     AND (freq_subday_interval   = @freq_subday_interval)
  7211.     AND (freq_relative_interval = @freq_relative_interval)
  7212.     AND (freq_recurrence_factor = @freq_recurrence_factor)
  7213.     AND (active_start_date      = @active_start_date)
  7214.     AND (active_start_time      = @active_start_time)
  7215.   IF ((@duplicate_schedule_id IS NOT NULL) AND (@duplicate_schedule_id <> @schedule_id))
  7216.   BEGIN
  7217.     RAISERROR(14259, -1, -1, @duplicate_schedule_id, @duplicate_schedule_name)
  7218.     RETURN(1) -- Failure
  7219.   END
  7220.  
  7221.   -- If we made it this far the schedule is good
  7222.   RETURN(0) -- Success
  7223.  
  7224. END
  7225. go
  7226.  
  7227. /**************************************************************/
  7228. /* SP_ADD_JOBSCHEDULE                                         */
  7229. /**************************************************************/
  7230.  
  7231. PRINT ''
  7232. PRINT 'Creating procedure sp_add_jobschedule...'
  7233. go
  7234. IF (EXISTS (SELECT *
  7235.             FROM msdb.dbo.sysobjects
  7236.             WHERE (name = N'sp_add_jobschedule')
  7237.               AND (type = 'P')))
  7238.   DROP PROCEDURE sp_add_jobschedule
  7239. go
  7240. CREATE PROCEDURE sp_add_jobschedule
  7241.   @job_id                 UNIQUEIDENTIFIER = NULL,
  7242.   @job_name               sysname          = NULL,
  7243.   @name                   sysname,
  7244.   @enabled                TINYINT          = 1,
  7245.   @freq_type              INT              = 0,
  7246.   @freq_interval          INT              = 0,
  7247.   @freq_subday_type       INT              = 0,
  7248.   @freq_subday_interval   INT              = 0,
  7249.   @freq_relative_interval INT              = 0,
  7250.   @freq_recurrence_factor INT              = 0,
  7251.   @active_start_date      INT              = NULL,     -- sp_verify_jobschedule assigns a default
  7252.   @active_end_date        INT              = 99991231, -- December 31st 9999
  7253.   @active_start_time      INT              = 000000,   -- 12:00:00 am
  7254.   @active_end_time        INT              = 235959    -- 11:59:59 pm
  7255. AS
  7256. BEGIN
  7257.   DECLARE @retval      INT
  7258.   DECLARE @schedule_id INT
  7259.  
  7260.   SET NOCOUNT ON
  7261.  
  7262.   -- Remove any leading/trailing spaces from parameters
  7263.   SELECT @name = LTRIM(RTRIM(@name))
  7264.  
  7265.   SELECT @schedule_id = 0
  7266.  
  7267.   -- Check authority (only SQLServerAgent can add a schedule to a non-local job)
  7268.   EXECUTE @retval = sp_verify_jobproc_caller @job_id = @job_id, @program_name = N'SQLAgent%'
  7269.   IF (@retval <> 0)
  7270.     RETURN(@retval)
  7271.  
  7272.   -- Check that we can uniquely identify the job
  7273.   EXECUTE @retval = sp_verify_job_identifiers '@job_name',
  7274.                                               '@job_id',
  7275.                                                @job_name OUTPUT,
  7276.                                                @job_id   OUTPUT
  7277.   IF (@retval <> 0)
  7278.     RETURN(1) -- Failure
  7279.  
  7280.   -- Check that the schedule name doesn't already exist
  7281.   IF (EXISTS (SELECT *
  7282.               FROM msdb.dbo.sysjobschedules
  7283.               WHERE (job_id = @job_id)
  7284.                 AND (name = @name)))
  7285.   BEGIN
  7286.     RAISERROR(14261, -1, -1, '@name', @name)
  7287.     RETURN(1) -- Failure
  7288.   END
  7289.  
  7290.   -- Check schedule (frequency) parameters
  7291.   EXECUTE @retval = sp_verify_jobschedule @name,
  7292.                                           @enabled,
  7293.                                           @freq_type,
  7294.                                           @freq_interval          OUTPUT,
  7295.                                           @freq_subday_type       OUTPUT,
  7296.                                           @freq_subday_interval   OUTPUT,
  7297.                                           @freq_relative_interval OUTPUT,
  7298.                                           @freq_recurrence_factor OUTPUT,
  7299.                                           @active_start_date      OUTPUT,
  7300.                                           @active_start_time      OUTPUT,
  7301.                                           @active_end_date        OUTPUT,
  7302.                                           @active_end_time        OUTPUT,
  7303.                                           @job_id,
  7304.                                           NULL
  7305.   IF (@retval <> 0)
  7306.     RETURN(1) -- Failure
  7307.  
  7308.   INSERT INTO msdb.dbo.sysjobschedules
  7309.          (job_id,
  7310.           name,
  7311.           enabled,
  7312.           freq_type,
  7313.           freq_interval,
  7314.           freq_subday_type,
  7315.           freq_subday_interval,
  7316.           freq_relative_interval,
  7317.           freq_recurrence_factor,
  7318.           active_start_date,
  7319.           active_end_date,
  7320.           active_start_time,
  7321.           active_end_time,
  7322.           next_run_date,
  7323.           next_run_time)
  7324.   VALUES (@job_id,
  7325.           @name,
  7326.           @enabled,
  7327.           @freq_type,
  7328.           @freq_interval,
  7329.           @freq_subday_type,
  7330.           @freq_subday_interval,
  7331.           @freq_relative_interval,
  7332.           @freq_recurrence_factor,
  7333.           @active_start_date,
  7334.           @active_end_date,
  7335.           @active_start_time,
  7336.           @active_end_time,
  7337.           0,
  7338.           0)
  7339.  
  7340.   SELECT @retval = @@error
  7341.  
  7342.   -- Update the job's version/last-modified information
  7343.   UPDATE msdb.dbo.sysjobs
  7344.   SET version_number = version_number + 1,
  7345.       date_modified = GETDATE()
  7346.   WHERE (job_id = @job_id)
  7347.  
  7348.   SELECT @schedule_id = schedule_id
  7349.   FROM msdb.dbo.sysjobschedules
  7350.   WHERE (job_id = @job_id)
  7351.     AND (name = @name)
  7352.  
  7353.   -- Notify SQLServerAgent of the change, but only if we know the job has been cached
  7354.   IF (EXISTS (SELECT * 
  7355.               FROM msdb.dbo.sysjobservers 
  7356.               WHERE (job_id = @job_id)
  7357.                 AND (server_id = 0)))
  7358.   BEGIN
  7359.     EXECUTE msdb.dbo.sp_sqlagent_notify @op_type     = N'S',
  7360.                                         @job_id      = @job_id,
  7361.                                         @schedule_id = @schedule_id,
  7362.                                         @action_type = N'I'
  7363.   END
  7364.  
  7365.   -- For a multi-server job, remind the user that they need to call sp_post_msx_operation
  7366.   IF (EXISTS (SELECT *
  7367.               FROM msdb.dbo.sysjobservers
  7368.               WHERE (job_id = @job_id)
  7369.                 AND (server_id <> 0)))
  7370.     RAISERROR(14547, 0, 1, N'INSERT', N'sp_post_msx_operation')
  7371.  
  7372.   RETURN(@retval) -- 0 means success
  7373. END
  7374. go
  7375.  
  7376. /**************************************************************/
  7377. /* SP_UPDATE_REPLICATION_JOB_PARAMETER                        */
  7378. /**************************************************************/
  7379.  
  7380. PRINT ''
  7381. PRINT 'Creating procedure sp_update_replication_job_parameter...'
  7382. go
  7383. IF (EXISTS (SELECT *
  7384.             FROM msdb.dbo.sysobjects
  7385.             WHERE (name = 'sp_update_replication_job_parameter')
  7386.               AND (type = 'P')))
  7387.   DROP PROCEDURE sp_update_replication_job_parameter
  7388. go
  7389. CREATE PROCEDURE sp_update_replication_job_parameter
  7390.   @job_id        UNIQUEIDENTIFIER,
  7391.   @old_freq_type INT,
  7392.   @new_freq_type INT
  7393. AS
  7394. BEGIN
  7395.   DECLARE @category_id INT
  7396.   DECLARE @pattern     NVARCHAR(50)
  7397.   DECLARE @patternidx  INT
  7398.   DECLARE @cmdline     NVARCHAR(3200)
  7399.   DECLARE @step_id     INT
  7400.  
  7401.   SET NOCOUNT ON
  7402.   SELECT @pattern = N'%[-/][Cc][Oo][Nn][Tt][Ii][Nn][Uu][Oo][Uu][Ss]%'
  7403.  
  7404.   -- Make sure that we are dealing with relevant replication jobs
  7405.   SELECT @category_id = category_id 
  7406.   FROM msdb.dbo.sysjobs 
  7407.   WHERE (@job_id = job_id)
  7408.  
  7409.   -- @category_id = 10 (REPL-Distribution), 13 (REPL-LogReader), 14 (REPL-Merge)
  7410.   IF @category_id IN (10, 13, 14)
  7411.   BEGIN
  7412.     -- Adding the -Continuous parameter (non auto-start to auto-start)
  7413.     IF ((@old_freq_type <> 0x40) AND (@new_freq_type = 0x40))
  7414.     BEGIN
  7415.       -- Use a cursor to handle multiple replication agent job steps
  7416.       DECLARE step_cursor CURSOR LOCAL FOR
  7417.       SELECT command, step_id 
  7418.       FROM msdb.dbo.sysjobsteps 
  7419.       WHERE (@job_id = job_id)
  7420.         AND (UPPER(subsystem) IN (N'MERGE', N'LOGREADER', N'DISTRIBUTION'))
  7421.       OPEN step_cursor
  7422.       FETCH step_cursor INTO @cmdline, @step_id   
  7423.  
  7424.       WHILE (@@FETCH_STATUS <> -1)
  7425.       BEGIN
  7426.         SELECT @patternidx = PATINDEX(@pattern, @cmdline)
  7427.         -- Make sure that the -Continuous parameter has not been specified already
  7428.         IF (@patternidx = 0)
  7429.         BEGIN
  7430.           SELECT @cmdline = @cmdline + N' -Continuous'    
  7431.           UPDATE msdb.dbo.sysjobsteps
  7432.           SET command = @cmdline 
  7433.           WHERE (@job_id = job_id) 
  7434.             AND (@step_id = step_id)
  7435.         END -- IF (@patternidx = 0)
  7436.         FETCH NEXT FROM step_cursor into @cmdline, @step_id
  7437.       END -- WHILE (@@FETCH_STATUS <> -1)     
  7438.       CLOSE step_cursor
  7439.       DEALLOCATE step_cursor
  7440.     END -- IF ((@old_freq_type...
  7441.     -- Removing the -Continuous parameter (auto-start to non auto-start)
  7442.     ELSE 
  7443.     IF ((@old_freq_type = 0x40) AND (@new_freq_type <> 0x40))
  7444.     BEGIN
  7445.       DECLARE step_cursor CURSOR LOCAL FOR
  7446.       SELECT command, step_id 
  7447.       FROM msdb.dbo.sysjobsteps 
  7448.       WHERE (@job_id = job_id)
  7449.         AND (UPPER(subsystem) IN (N'MERGE', N'LOGREADER', N'DISTRIBUTION'))
  7450.       OPEN step_cursor
  7451.       FETCH step_cursor INTO @cmdline, @step_id
  7452.  
  7453.       WHILE (@@FETCH_STATUS <> -1)
  7454.       BEGIN
  7455.         SELECT @patternidx = PATINDEX(@pattern, @cmdline)
  7456.         IF (@patternidx <> 0)
  7457.         BEGIN
  7458.           -- Handle multiple instances of -Continuous in the commandline
  7459.           WHILE (@patternidx <> 0)
  7460.           BEGIN 
  7461.             SELECT @cmdline = STUFF(@cmdline, @patternidx, 11, N'') 
  7462.             IF (@patternidx > 1)
  7463.             BEGIN
  7464.               -- Remove the preceding space if -Continuous does not start at the beginning of the commandline
  7465.               SELECT @cmdline = stuff(@cmdline, @patternidx - 1, 1, N'')
  7466.             END
  7467.             SELECT @patternidx = PATINDEX(@pattern, @cmdline)
  7468.           END -- WHILE (@patternidx <> 0)
  7469.           UPDATE msdb.dbo.sysjobsteps
  7470.           SET command = @cmdline 
  7471.           WHERE (@job_id = job_id) 
  7472.             AND (@step_id = step_id)
  7473.         END -- IF (@patternidx <> -1)     
  7474.         FETCH NEXT FROM step_cursor INTO @cmdline, @step_id
  7475.       END -- WHILE (@@FETCH_STATUS <> -1)
  7476.       CLOSE step_cursor
  7477.       DEALLOCATE step_cursor
  7478.     END -- ELSE IF ((@old_freq_type = 0x40)... 
  7479.   END -- IF @category_id IN (10, 13, 14)      
  7480.  
  7481.   RETURN 0
  7482. END
  7483. go
  7484.  
  7485. /**************************************************************/
  7486. /* SP_UPDATE_JOBSCHEDULE                                      */
  7487. /**************************************************************/
  7488.  
  7489. PRINT ''
  7490. PRINT 'Creating procedure sp_update_jobschedule...'
  7491. go
  7492. IF (EXISTS (SELECT *
  7493.             FROM msdb.dbo.sysobjects
  7494.             WHERE (name = N'sp_update_jobschedule')
  7495.               AND (type = 'P')))
  7496.   DROP PROCEDURE sp_update_jobschedule
  7497. go
  7498. CREATE PROCEDURE sp_update_jobschedule
  7499.   @job_id                 UNIQUEIDENTIFIER = NULL,
  7500.   @job_name               sysname          = NULL,
  7501.   @name                   sysname,
  7502.   @new_name               sysname          = NULL,
  7503.   @enabled                TINYINT          = NULL,
  7504.   @freq_type              INT              = NULL,
  7505.   @freq_interval          INT              = NULL,
  7506.   @freq_subday_type       INT              = NULL,
  7507.   @freq_subday_interval   INT              = NULL,
  7508.   @freq_relative_interval INT              = NULL,
  7509.   @freq_recurrence_factor INT              = NULL,
  7510.   @active_start_date      INT              = NULL,
  7511.   @active_end_date        INT              = NULL,
  7512.   @active_start_time      INT              = NULL,
  7513.   @active_end_time        INT              = NULL
  7514. AS
  7515. BEGIN
  7516.   DECLARE @retval                   INT
  7517.   DECLARE @schedule_id              INT
  7518.   DECLARE @x_name                   sysname
  7519.   DECLARE @x_enabled                TINYINT
  7520.   DECLARE @x_freq_type              INT
  7521.   DECLARE @x_freq_interval          INT
  7522.   DECLARE @x_freq_subday_type       INT
  7523.   DECLARE @x_freq_subday_interval   INT
  7524.   DECLARE @x_freq_relative_interval INT
  7525.   DECLARE @x_freq_recurrence_factor INT
  7526.   DECLARE @x_active_start_date      INT
  7527.   DECLARE @x_active_end_date        INT
  7528.   DECLARE @x_active_start_time      INT
  7529.   DECLARE @x_active_end_time        INT
  7530.  
  7531.   SET NOCOUNT ON
  7532.  
  7533.   -- Remove any leading/trailing spaces from parameters
  7534.   SELECT @name     = LTRIM(RTRIM(@name))
  7535.   SELECT @new_name = LTRIM(RTRIM(@new_name))
  7536.  
  7537.   -- Turn [nullable] empty string parameters into NULLs
  7538.   IF (@new_name = N'') SELECT @new_name = NULL
  7539.  
  7540.   -- Check authority (only SQLServerAgent can modify a schedule of a non-local job)
  7541.   EXECUTE @retval = sp_verify_jobproc_caller @job_id = @job_id, @program_name = 'SQLAgent%'
  7542.   IF (@retval <> 0)
  7543.     RETURN(@retval)
  7544.  
  7545.   -- Check that we can uniquely identify the job
  7546.   EXECUTE @retval = sp_verify_job_identifiers '@job_name',
  7547.                                               '@job_id',
  7548.                                                @job_name OUTPUT,
  7549.                                                @job_id   OUTPUT
  7550.   IF (@retval <> 0)
  7551.     RETURN(1) -- Failure
  7552.  
  7553.   -- Check that the schedule exists
  7554.   SELECT @schedule_id = schedule_id
  7555.   FROM msdb.dbo.sysjobschedules
  7556.   WHERE (job_id = @job_id)
  7557.     AND (name = @name)
  7558.   IF (@schedule_id IS NULL)
  7559.   BEGIN
  7560.     RAISERROR(14262, -1, -1, 'Schedule Name', @name)
  7561.     RETURN(1) -- Failure
  7562.   END
  7563.  
  7564.   -- Set the x_ (existing) variables
  7565.   SELECT @x_name                   = name,
  7566.          @x_enabled                = enabled,
  7567.          @x_freq_type              = freq_type,
  7568.          @x_freq_interval          = freq_interval,
  7569.          @x_freq_subday_type       = freq_subday_type,
  7570.          @x_freq_subday_interval   = freq_subday_interval,
  7571.          @x_freq_relative_interval = freq_relative_interval,
  7572.          @x_freq_recurrence_factor = freq_recurrence_factor,
  7573.          @x_active_start_date      = active_start_date,
  7574.          @x_active_end_date        = active_end_date,
  7575.          @x_active_start_time      = active_start_time,
  7576.          @x_active_end_time        = active_end_time
  7577.   FROM msdb.dbo.sysjobschedules
  7578.   WHERE (job_id = @job_id)
  7579.     AND (name = @name)
  7580.  
  7581.   -- Check that the new name (if any) doesn't already exist for this job
  7582.   IF (@new_name IS NOT NULL)
  7583.   BEGIN
  7584.     IF (EXISTS (SELECT *
  7585.                 FROM msdb.dbo.sysjobschedules
  7586.                 WHERE (job_id = @job_id)
  7587.                   AND (name = @new_name)
  7588.                   AND (@name <> @new_name)))
  7589.     BEGIN
  7590.       RAISERROR(14261, -1, -1, '@new_name', @new_name)
  7591.       RETURN(1) -- Failure
  7592.     END
  7593.   END
  7594.  
  7595.   -- Fill out the values for all non-supplied parameters from the existing values
  7596.   IF (@new_name               IS NULL) SELECT @new_name               = @x_name
  7597.   IF (@enabled                IS NULL) SELECT @enabled                = @x_enabled
  7598.   IF (@freq_type              IS NULL) SELECT @freq_type              = @x_freq_type
  7599.   IF (@freq_interval          IS NULL) SELECT @freq_interval          = @x_freq_interval
  7600.   IF (@freq_subday_type       IS NULL) SELECT @freq_subday_type       = @x_freq_subday_type
  7601.   IF (@freq_subday_interval   IS NULL) SELECT @freq_subday_interval   = @x_freq_subday_interval
  7602.   IF (@freq_relative_interval IS NULL) SELECT @freq_relative_interval = @x_freq_relative_interval
  7603.   IF (@freq_recurrence_factor IS NULL) SELECT @freq_recurrence_factor = @x_freq_recurrence_factor
  7604.   IF (@active_start_date      IS NULL) SELECT @active_start_date      = @x_active_start_date
  7605.   IF (@active_end_date        IS NULL) SELECT @active_end_date        = @x_active_end_date
  7606.   IF (@active_start_time      IS NULL) SELECT @active_start_time      = @x_active_start_time
  7607.   IF (@active_end_time        IS NULL) SELECT @active_end_time        = @x_active_end_time
  7608.  
  7609.   -- Check schedule (frequency) parameters
  7610.   EXECUTE @retval = sp_verify_jobschedule @new_name,
  7611.                                           @enabled,
  7612.                                           @freq_type,
  7613.                                           @freq_interval          OUTPUT,
  7614.                                           @freq_subday_type       OUTPUT,
  7615.                                           @freq_subday_interval   OUTPUT,
  7616.                                           @freq_relative_interval OUTPUT,
  7617.                                           @freq_recurrence_factor OUTPUT,
  7618.                                           @active_start_date      OUTPUT,
  7619.                                           @active_start_time      OUTPUT,
  7620.                                           @active_end_date        OUTPUT,
  7621.                                           @active_end_time        OUTPUT,
  7622.                                           @job_id,
  7623.                                           @schedule_id
  7624.   IF (@retval <> 0)
  7625.     RETURN(1) -- Failure
  7626.  
  7627.   -- Update the JobSchedule
  7628.   UPDATE msdb.dbo.sysjobschedules
  7629.   SET name                   = @new_name,
  7630.       enabled                = @enabled,
  7631.       freq_type              = @freq_type,
  7632.       freq_interval          = @freq_interval,
  7633.       freq_subday_type       = @freq_subday_type,
  7634.       freq_subday_interval   = @freq_subday_interval,
  7635.       freq_relative_interval = @freq_relative_interval,
  7636.       freq_recurrence_factor = @freq_recurrence_factor,
  7637.       active_start_date      = @active_start_date,
  7638.       active_end_date        = @active_end_date,
  7639.       active_start_time      = @active_start_time,
  7640.       active_end_time        = @active_end_time,
  7641.       next_run_date          = 0, -- Since SQLServerAgent needs to recalculate it
  7642.       next_run_time          = 0  -- Since SQLServerAgent needs to recalculate it
  7643.   WHERE (job_id = @job_id)
  7644.     AND (name = @name)
  7645.  
  7646.   SELECT @retval = @@error
  7647.  
  7648.   -- Update the job's version/last-modified information
  7649.   UPDATE msdb.dbo.sysjobs
  7650.   SET version_number = version_number + 1,
  7651.       date_modified = GETDATE()
  7652.   WHERE (job_id = @job_id)
  7653.  
  7654.   -- Notify SQLServerAgent of the change, but only if we know the job has been cached
  7655.   IF (EXISTS (SELECT * 
  7656.               FROM msdb.dbo.sysjobservers 
  7657.               WHERE (job_id = @job_id)
  7658.                 AND (server_id = 0)))
  7659.   BEGIN
  7660.     EXECUTE msdb.dbo.sp_sqlagent_notify @op_type     = N'S',
  7661.                                         @job_id      = @job_id,
  7662.                                         @schedule_id = @schedule_id,
  7663.                                         @action_type = N'U'
  7664.   END
  7665.  
  7666.   -- For a multi-server job, remind the user that they need to call sp_post_msx_operation
  7667.   IF (EXISTS (SELECT *
  7668.               FROM msdb.dbo.sysjobservers
  7669.               WHERE (job_id = @job_id)
  7670.                 AND (server_id <> 0)))
  7671.     RAISERROR(14547, 0, 1, N'INSERT', N'sp_post_msx_operation')
  7672.  
  7673.   -- Automatic addition and removal of -Continous parameter for replication agent
  7674.   EXECUTE sp_update_replication_job_parameter @job_id = @job_id,
  7675.                                               @old_freq_type = @x_freq_type,
  7676.                                               @new_freq_type = @freq_type
  7677.  
  7678.   RETURN(@retval) -- 0 means success
  7679. END
  7680. go
  7681.  
  7682. /**************************************************************/
  7683. /* SP_DELETE_JOBSCHEDULE                                      */
  7684. /**************************************************************/
  7685.  
  7686. PRINT ''
  7687. PRINT 'Creating procedure sp_delete_jobschedule...'
  7688. go
  7689. IF (EXISTS (SELECT *
  7690.             FROM msdb.dbo.sysobjects
  7691.             WHERE (name = 'sp_delete_jobschedule')
  7692.               AND (type = 'P')))
  7693.   DROP PROCEDURE sp_delete_jobschedule
  7694. go
  7695. CREATE PROCEDURE sp_delete_jobschedule
  7696.   @job_id   UNIQUEIDENTIFIER = NULL,
  7697.   @job_name sysname          = NULL,
  7698.   @name     sysname
  7699. AS
  7700. BEGIN
  7701.   DECLARE @retval      INT
  7702.   DECLARE @schedule_id INT
  7703.  
  7704.   SET NOCOUNT ON
  7705.  
  7706.   -- Remove any leading/trailing spaces from parameters
  7707.   SELECT @name = LTRIM(RTRIM(@name))
  7708.  
  7709.   -- Check authority (only SQLServerAgent can delete a schedule of a non-local job)
  7710.   EXECUTE @retval = sp_verify_jobproc_caller @job_id = @job_id, @program_name = N'SQLAgent%'
  7711.   IF (@retval <> 0)
  7712.     RETURN(@retval)
  7713.  
  7714.   -- Check that we can uniquely identify the job
  7715.   EXECUTE @retval = sp_verify_job_identifiers '@job_name',
  7716.                                               '@job_id',
  7717.                                                @job_name OUTPUT,
  7718.                                                @job_id   OUTPUT
  7719.   IF (@retval <> 0)
  7720.     RETURN(1) -- Failure
  7721.  
  7722.   IF (UPPER(@name) = N'ALL')
  7723.   BEGIN
  7724.     SELECT @schedule_id = -1  -- We use this in the call to sp_sqlagent_notify
  7725.  
  7726.     DELETE FROM msdb.dbo.sysjobschedules
  7727.     WHERE (job_id = @job_id)
  7728.   END
  7729.   ELSE
  7730.   BEGIN
  7731.     -- Check that the schedule exists
  7732.     SELECT @schedule_id = schedule_id
  7733.     FROM msdb.dbo.sysjobschedules
  7734.     WHERE (job_id = @job_id)
  7735.       AND (name = @name)
  7736.     IF (@schedule_id IS NULL)
  7737.     BEGIN
  7738.       RAISERROR(14262, -1, -1, '@name', @name)
  7739.       RETURN(1) -- Failure
  7740.     END
  7741.  
  7742.     DELETE FROM msdb.dbo.sysjobschedules
  7743.     WHERE (job_id = @job_id)
  7744.       AND (schedule_id = @schedule_id)
  7745.   END
  7746.  
  7747.   SELECT @retval = @@error
  7748.  
  7749.   -- Update the job's version/last-modified information
  7750.   UPDATE msdb.dbo.sysjobs
  7751.   SET version_number = version_number + 1,
  7752.       date_modified = GETDATE()
  7753.   WHERE (job_id = @job_id)
  7754.  
  7755.   -- Notify SQLServerAgent of the change, but only if we know the job has been cached
  7756.   IF (EXISTS (SELECT *
  7757.               FROM msdb.dbo.sysjobservers 
  7758.               WHERE (job_id = @job_id)
  7759.                 AND (server_id = 0)))
  7760.   BEGIN
  7761.     EXECUTE msdb.dbo.sp_sqlagent_notify @op_type     = N'S',
  7762.                                         @job_id      = @job_id,
  7763.                                         @schedule_id = @schedule_id,
  7764.                                         @action_type = N'D'
  7765.   END
  7766.  
  7767.   -- For a multi-server job, remind the user that they need to call sp_post_msx_operation
  7768.   IF (EXISTS (SELECT *
  7769.               FROM msdb.dbo.sysjobservers
  7770.               WHERE (job_id = @job_id)
  7771.                 AND (server_id <> 0)))
  7772.     RAISERROR(14547, 0, 1, N'INSERT', N'sp_post_msx_operation')
  7773.  
  7774.   RETURN(@retval) -- 0 means success
  7775. END
  7776. go
  7777.  
  7778. /**************************************************************/
  7779. /* SP_HELP_JOBSCHEDULE                                        */
  7780. /**************************************************************/
  7781.  
  7782. PRINT ''
  7783. PRINT 'Creating procedure sp_help_jobschedule...'
  7784. go
  7785. IF (EXISTS (SELECT *
  7786.             FROM msdb.dbo.sysobjects
  7787.             WHERE (name = N'sp_help_jobschedule')
  7788.               AND (type = 'P')))
  7789.   DROP PROCEDURE sp_help_jobschedule
  7790. go
  7791. CREATE PROCEDURE sp_help_jobschedule
  7792.   @job_id              UNIQUEIDENTIFIER = NULL,
  7793.   @job_name            sysname          = NULL,
  7794.   @schedule_name       sysname          = NULL,
  7795.   @schedule_id         INT              = NULL,
  7796.   @include_description BIT              = 0 -- 1 if a schedule description is required (NOTE: It's expensive to generate the description)
  7797. AS
  7798. BEGIN
  7799.   DECLARE @retval                 INT
  7800.   DECLARE @schedule_description   NVARCHAR(255)
  7801.   DECLARE @name                   sysname
  7802.   DECLARE @freq_type              INT
  7803.   DECLARE @freq_interval          INT
  7804.   DECLARE @freq_subday_type       INT
  7805.   DECLARE @freq_subday_interval   INT
  7806.   DECLARE @freq_relative_interval INT
  7807.   DECLARE @freq_recurrence_factor INT
  7808.   DECLARE @active_start_date      INT
  7809.   DECLARE @active_end_date        INT
  7810.   DECLARE @active_start_time      INT
  7811.   DECLARE @active_end_time        INT
  7812.   DECLARE @schedule_id_as_char    VARCHAR(10)
  7813.  
  7814.   SET NOCOUNT ON
  7815.  
  7816.   -- Remove any leading/trailing spaces from parameters
  7817.   SELECT @schedule_name = LTRIM(RTRIM(@schedule_name))
  7818.  
  7819.   -- Turn [nullable] empty string parameters into NULLs
  7820.   IF (@schedule_name = N'') SELECT @schedule_name = NULL
  7821.  
  7822.   -- The user must provide either:
  7823.   -- 1) job_id (or job_name) and (optionally) a schedule name
  7824.   -- or...
  7825.   -- 2) just schedule_id
  7826.   IF (@schedule_id IS NULL) AND
  7827.      (@job_id      IS NULL) AND
  7828.      (@job_name    IS NULL)
  7829.   BEGIN
  7830.     RAISERROR(14273, -1, -1)
  7831.     RETURN(1) -- Failure
  7832.   END
  7833.  
  7834.   IF (@schedule_id IS NOT NULL) AND ((@job_id        IS NOT NULL) OR
  7835.                                      (@job_name      IS NOT NULL) OR
  7836.                                      (@schedule_name IS NOT NULL))
  7837.   BEGIN
  7838.     RAISERROR(14273, -1, -1)
  7839.     RETURN(1) -- Failure
  7840.   END
  7841.  
  7842.   -- Check that the schedule (by ID) exists
  7843.   IF (@schedule_id IS NOT NULL)
  7844.   BEGIN
  7845.     SELECT @job_id = job_id
  7846.     FROM msdb.dbo.sysjobschedules
  7847.     WHERE (schedule_id = @schedule_id)
  7848.     IF (@job_id IS NULL)
  7849.     BEGIN
  7850.       SELECT @schedule_id_as_char = CONVERT(VARCHAR, @schedule_id)
  7851.       RAISERROR(14262, -1, -1, '@schedule_id', @schedule_id_as_char)
  7852.       RETURN(1) -- Failure
  7853.     END
  7854.   END
  7855.  
  7856.   -- Check that we can uniquely identify the job
  7857.   IF (@job_id IS NOT NULL) OR (@job_name IS NOT NULL)
  7858.   BEGIN
  7859.     EXECUTE @retval = sp_verify_job_identifiers '@job_name',
  7860.                                                 '@job_id',
  7861.                                                  @job_name OUTPUT,
  7862.                                                  @job_id   OUTPUT,
  7863.                                                 'NO_TEST'
  7864.     IF (@retval <> 0)
  7865.       RETURN(1) -- Failure
  7866.   END
  7867.  
  7868.   -- Check that the schedule (by name) exists
  7869.   IF (@schedule_name IS NOT NULL)
  7870.   BEGIN
  7871.     IF (NOT EXISTS (SELECT *
  7872.                     FROM msdb.dbo.sysjobschedules
  7873.                     WHERE (job_id = @job_id)
  7874.                       AND (name = @schedule_name)))
  7875.     BEGIN
  7876.       RAISERROR(14262, -1, -1, '@schedule_name', @schedule_name)
  7877.       RETURN(1) -- Failure
  7878.     END
  7879.   END
  7880.  
  7881.   -- Get the schedule(s) into a temporary table
  7882.   SELECT schedule_id,
  7883.         'schedule_name' = name,
  7884.          enabled,
  7885.          freq_type,
  7886.          freq_interval,
  7887.          freq_subday_type,
  7888.          freq_subday_interval,
  7889.          freq_relative_interval,
  7890.          freq_recurrence_factor,
  7891.          active_start_date,
  7892.          active_end_date,
  7893.          active_start_time,
  7894.          active_end_time,
  7895.          date_created,
  7896.         'schedule_description' = FORMATMESSAGE(14549),
  7897.          next_run_date,
  7898.          next_run_time
  7899.   INTO #temp_jobschedule
  7900.   FROM msdb.dbo.sysjobschedules
  7901.   WHERE ((@job_id IS NULL) OR (job_id = @job_id))
  7902.     AND ((@schedule_name IS NULL) OR (name = @schedule_name))
  7903.     AND ((@schedule_id IS NULL) OR (schedule_id = @schedule_id))
  7904.  
  7905.   IF (@include_description = 1)
  7906.   BEGIN
  7907.     -- For each schedule, generate the textual schedule description and update the temporary
  7908.     -- table with it
  7909.     IF (EXISTS (SELECT *
  7910.                 FROM #temp_jobschedule))
  7911.     BEGIN
  7912.       WHILE (EXISTS (SELECT *
  7913.                      FROM #temp_jobschedule
  7914.                      WHERE schedule_description = FORMATMESSAGE(14549)))
  7915.       BEGIN
  7916.         SET ROWCOUNT 1
  7917.         SELECT @name                   = schedule_name,
  7918.                @freq_type              = freq_type,
  7919.                @freq_interval          = freq_interval,
  7920.                @freq_subday_type       = freq_subday_type,
  7921.                @freq_subday_interval   = freq_subday_interval,
  7922.                @freq_relative_interval = freq_relative_interval,
  7923.                @freq_recurrence_factor = freq_recurrence_factor,
  7924.                @active_start_date      = active_start_date,
  7925.                @active_end_date        = active_end_date,
  7926.                @active_start_time      = active_start_time,
  7927.                @active_end_time        = active_end_time
  7928.         FROM #temp_jobschedule
  7929.         WHERE (schedule_description = FORMATMESSAGE(14549))
  7930.         SET ROWCOUNT 0
  7931.  
  7932.         EXECUTE sp_get_schedule_description
  7933.           @freq_type,
  7934.           @freq_interval,
  7935.           @freq_subday_type,
  7936.           @freq_subday_interval,
  7937.           @freq_relative_interval,
  7938.           @freq_recurrence_factor,
  7939.           @active_start_date,
  7940.           @active_end_date,
  7941.           @active_start_time,
  7942.           @active_end_time,
  7943.           @schedule_description OUTPUT
  7944.  
  7945.         UPDATE #temp_jobschedule
  7946.         SET schedule_description = ISNULL(LTRIM(RTRIM(@schedule_description)), FORMATMESSAGE(14205))
  7947.         WHERE (schedule_name = @name)
  7948.       END -- While
  7949.     END
  7950.   END
  7951.  
  7952.   -- Return the result set
  7953.   SELECT *
  7954.   FROM #temp_jobschedule
  7955.   ORDER BY schedule_id
  7956.  
  7957.   RETURN(@@error) -- 0 means success
  7958. END
  7959. go
  7960.  
  7961. DUMP TRANSACTION msdb WITH NO_LOG
  7962. go
  7963. CHECKPOINT
  7964. go
  7965.  
  7966. /**************************************************************/
  7967. /* SP_VERIFY_JOB                                              */
  7968. /**************************************************************/
  7969.  
  7970. PRINT ''
  7971. PRINT 'Creating procedure sp_verify_job...'
  7972. go
  7973. IF (EXISTS (SELECT *
  7974.             FROM msdb.dbo.sysobjects
  7975.             WHERE (name = N'sp_verify_job')
  7976.               AND (type = 'P')))
  7977.   DROP PROCEDURE sp_verify_job
  7978. go
  7979. CREATE PROCEDURE sp_verify_job
  7980.   @job_id                       UNIQUEIDENTIFIER,
  7981.   @name                         sysname,
  7982.   @enabled                      TINYINT,
  7983.   @start_step_id                INT,
  7984.   @category_name                sysname,
  7985.   @owner_sid                    VARBINARY(85) OUTPUT, -- Output since we may modify it
  7986.   @notify_level_eventlog        INT,
  7987.   @notify_level_email           INT           OUTPUT, -- Output since we may reset it to 0
  7988.   @notify_level_netsend         INT           OUTPUT, -- Output since we may reset it to 0
  7989.   @notify_level_page            INT           OUTPUT, -- Output since we may reset it to 0
  7990.   @notify_email_operator_name   sysname,
  7991.   @notify_netsend_operator_name sysname,
  7992.   @notify_page_operator_name    sysname,
  7993.   @delete_level                 INT,
  7994.   @category_id                  INT           OUTPUT, -- The ID corresponding to the name
  7995.   @notify_email_operator_id     INT           OUTPUT, -- The ID corresponding to the name
  7996.   @notify_netsend_operator_id   INT           OUTPUT, -- The ID corresponding to the name
  7997.   @notify_page_operator_id      INT           OUTPUT, -- The ID corresponding to the name
  7998.   @originating_server           NVARCHAR(30)  OUTPUT  -- Output since we may modify it
  7999. AS
  8000. BEGIN
  8001.   DECLARE @job_type           INT
  8002.   DECLARE @retval             INT
  8003.   DECLARE @current_date       INT
  8004.   DECLARE @local_machine_name NVARCHAR(30)
  8005.   DECLARE @res_valid_range    NVARCHAR(200)
  8006.  
  8007.   SET NOCOUNT ON
  8008.  
  8009.   -- Remove any leading/trailing spaces from parameters
  8010.   SELECT @name                       = LTRIM(RTRIM(@name))
  8011.   SELECT @category_name              = LTRIM(RTRIM(@category_name))
  8012.   SELECT @originating_server         = LTRIM(RTRIM(@originating_server))
  8013.  
  8014.   -- Make sure that input/output strings - if NULL - are initialized to NOT null
  8015.   EXECUTE @retval = master.dbo.xp_getnetname @local_machine_name OUTPUT
  8016.   IF (@retval <> 0)
  8017.     RETURN(1) -- Failure
  8018.   SELECT @originating_server = ISNULL(@originating_server, ISNULL(@local_machine_name, N'(local)'))
  8019.  
  8020.   -- Replace the local server name with '(local)'
  8021.   IF (UPPER(@originating_server) = UPPER(@local_machine_name))
  8022.     SELECT @originating_server = N'(local)'
  8023.  
  8024.   -- Check originating server (only the SQLServerAgent can add jobs that originate from a remote server)
  8025.   IF (UPPER(@originating_server) <> N'(LOCAL)') AND
  8026.      (PROGRAM_NAME() NOT LIKE N'SQLAgent%')
  8027.   BEGIN
  8028.     RAISERROR(14275, -1, -1, @local_machine_name)
  8029.     RETURN(1) -- Failure
  8030.   END
  8031.  
  8032.   -- Make sure that the local server is always referred to as '(local)' (ie. lower-case)
  8033.   IF (UPPER(@originating_server) = N'(LOCAL)')
  8034.     SELECT @originating_server = LOWER(@originating_server)
  8035.  
  8036.   -- NOTE: We allow jobs with the same name (since job_id is always unique) but only if
  8037.   --       they originate from different servers.  Thus jobs can flow from an MSX to a TSX
  8038.   --       without having to worry about naming conflicts.
  8039.   IF (EXISTS (SELECT *
  8040.               FROM msdb.dbo.sysjobs
  8041.               WHERE (name = @name)
  8042.                 AND (originating_server = @originating_server)
  8043.                 AND (job_id <> ISNULL(@job_id, 0x911)))) -- When adding a new job @job_id is NULL
  8044.   BEGIN
  8045.     RAISERROR(14261, -1, -1, '@name', @name)
  8046.     RETURN(1) -- Failure
  8047.   END
  8048.  
  8049.   -- Check enabled state
  8050.   IF (@enabled <> 0) AND (@enabled <> 1)
  8051.   BEGIN
  8052.     RAISERROR(14266, -1, -1, '@enabled', '0, 1')
  8053.     RETURN(1) -- Failure
  8054.   END
  8055.  
  8056.   -- Check start step
  8057.   IF (@job_id IS NULL)
  8058.   BEGIN
  8059.     -- New job
  8060.     -- NOTE: For [new] MSX jobs we allow the start step to be other than 1 since
  8061.     --       the start step was validated when the job was created at the MSX
  8062.     IF (@start_step_id <> 1) AND (UPPER(@originating_server) = N'(LOCAL)')
  8063.     BEGIN
  8064.       RAISERROR(14266, -1, -1, '@start_step_id', '1')
  8065.       RETURN(1) -- Failure
  8066.     END
  8067.   END
  8068.   ELSE
  8069.   BEGIN
  8070.     -- Existing job
  8071.     DECLARE @max_step_id INT
  8072.     DECLARE @valid_range VARCHAR(50)
  8073.  
  8074.     -- Get current maximum step id
  8075.     SELECT @max_step_id = ISNULL(MAX(step_id), 0)
  8076.     FROM msdb.dbo.sysjobsteps
  8077.     WHERE (job_id = @job_id)
  8078.  
  8079.     IF (@start_step_id < 1) OR (@start_step_id > @max_step_id + 1)
  8080.     BEGIN
  8081.       SELECT @valid_range = '1..' + CONVERT(VARCHAR, @max_step_id + 1)
  8082.       RAISERROR(14266, -1, -1, '@start_step_id', @valid_range)
  8083.       RETURN(1) -- Failure
  8084.     END
  8085.   END
  8086.  
  8087.   -- Check category
  8088.   SELECT @job_type = NULL
  8089.  
  8090.   IF (EXISTS (SELECT *
  8091.               FROM msdb.dbo.sysjobservers
  8092.               WHERE (job_id = @job_id)
  8093.                 AND (server_id = 0)))
  8094.     SELECT @job_type = 1 -- LOCAL
  8095.  
  8096.   IF (EXISTS (SELECT *
  8097.               FROM msdb.dbo.sysjobservers
  8098.               WHERE (job_id = @job_id)
  8099.                 AND (server_id <> 0)))
  8100.     SELECT @job_type = 2 -- MULTI-SERVER
  8101.  
  8102.   -- A local job cannot be added to a multi-server job_category
  8103.   IF (@job_type = 1) AND (EXISTS (SELECT *
  8104.                                   FROM msdb.dbo.syscategories
  8105.                                   WHERE (category_class = 1) -- Job
  8106.                                     AND (category_type = 2) -- Multi-Server
  8107.                                     AND (name = @category_name)))
  8108.   BEGIN
  8109.     RAISERROR(14285, -1, -1)
  8110.     RETURN(1) -- Failure
  8111.   END
  8112.  
  8113.   -- A multi-server job cannot be added to a local job_category
  8114.   IF (@job_type = 2) AND (EXISTS (SELECT *
  8115.                                   FROM msdb.dbo.syscategories
  8116.                                   WHERE (category_class = 1) -- Job
  8117.                                     AND (category_type = 1) -- Local
  8118.                                     AND (name = @category_name)))
  8119.   BEGIN
  8120.     RAISERROR(14286, -1, -1)
  8121.     RETURN(1) -- Failure
  8122.   END
  8123.  
  8124.   -- Get the category_id, handling any special-cases as appropriate
  8125.   SELECT @category_id = NULL
  8126.   IF (@category_name = N'[DEFAULT]') -- User wants to revert to the default job category
  8127.   BEGIN
  8128.     SELECT @category_id = CASE ISNULL(@job_type, 1)
  8129.                             WHEN 1 THEN 0 -- [Uncategorized (Local)]
  8130.                             WHEN 2 THEN 2 -- [Uncategorized (Multi-Server)]
  8131.                           END
  8132.   END
  8133.   ELSE
  8134.   IF (@category_name IS NULL) -- The sp_add_job default
  8135.   BEGIN
  8136.     SELECT @category_id = 0
  8137.   END
  8138.   ELSE
  8139.   BEGIN
  8140.     SELECT @category_id = category_id
  8141.     FROM msdb.dbo.syscategories
  8142.     WHERE (category_class = 1) -- Job
  8143.       AND (name = @category_name)
  8144.   END
  8145.  
  8146.   IF (@category_id IS NULL)
  8147.   BEGIN
  8148.     RAISERROR(14234, -1, -1, '@category_name', 'sp_help_category')
  8149.     RETURN(1) -- Failure
  8150.   END
  8151.  
  8152.   -- Only SQLServerAgent may add jobs to the 'Jobs From MSX' category
  8153.   IF (@category_id = 1) AND
  8154.      (PROGRAM_NAME() NOT LIKE N'SQLAgent%')
  8155.   BEGIN
  8156.     RAISERROR(14267, -1, -1, @category_name)
  8157.     RETURN(1) -- Failure
  8158.   END
  8159.  
  8160.   -- Check owner
  8161.   -- If a non-sa is [illegally] trying to create a job for another user then default the owner
  8162.   -- to be the calling user.
  8163.   IF ((ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) = 0) AND (@owner_sid <> SUSER_SID()))
  8164.     SELECT @owner_sid = SUSER_SID()
  8165.  
  8166.   -- Now just check that the login id is valid (ie. it exists and isn't an NT group)
  8167.   IF (@owner_sid IS NULL) OR (EXISTS (SELECT *
  8168.                                       FROM master.dbo.syslogins
  8169.                                       WHERE (sid = @owner_sid)
  8170.                                         AND (isntgroup <> 0)))
  8171.   BEGIN
  8172.     -- NOTE: In the following message we quote @owner_login_name instead of @owner_sid
  8173.     --       since this is the parameter the user passed to the calling SP (ie. either
  8174.     --       sp_add_job or sp_update_job)
  8175.     SELECT @res_valid_range = FORMATMESSAGE(14203)
  8176.     RAISERROR(14234, -1, -1, '@owner_login_name', @res_valid_range)
  8177.     RETURN(1) -- Failure
  8178.   END
  8179.  
  8180.   -- Check notification levels (must be 0, 1, 2 or 3)
  8181.   IF (@notify_level_eventlog & 0x3 <> @notify_level_eventlog)
  8182.   BEGIN
  8183.     RAISERROR(14266, -1, -1, '@notify_level_eventlog', '0, 1, 2, 3')
  8184.     RETURN(1) -- Failure
  8185.   END
  8186.   IF (@notify_level_email & 0x3 <> @notify_level_email)
  8187.   BEGIN
  8188.     RAISERROR(14266, -1, -1, '@notify_level_email', '0, 1, 2, 3')
  8189.     RETURN(1) -- Failure
  8190.   END
  8191.   IF (@notify_level_netsend & 0x3 <> @notify_level_netsend)
  8192.   BEGIN
  8193.     RAISERROR(14266, -1, -1, '@notify_level_netsend', '0, 1, 2, 3')
  8194.     RETURN(1) -- Failure
  8195.   END
  8196.   IF (@notify_level_page & 0x3 <> @notify_level_page)
  8197.   BEGIN
  8198.     RAISERROR(14266, -1, -1, '@notify_level_page', '0, 1, 2, 3')
  8199.     RETURN(1) -- Failure
  8200.   END
  8201.  
  8202.   -- If we're at a TSX, only SQLServerAgent may add jobs that notify 'MSXOperator'
  8203.   IF (NOT EXISTS (SELECT *
  8204.                   FROM msdb.dbo.systargetservers)) AND
  8205.      ((@notify_email_operator_name = N'MSXOperator') OR
  8206.       (@notify_page_operator_name = N'MSXOperator') OR
  8207.       (@notify_netsend_operator_name = N'MSXOperator')) AND
  8208.      (PROGRAM_NAME() NOT LIKE N'SQLAgent%')
  8209.   BEGIN
  8210.     RAISERROR(14251, -1, -1, 'MSXOperator')
  8211.     RETURN(1) -- Failure
  8212.   END
  8213.  
  8214.   -- Check operator to notify (via email)
  8215.   IF (@notify_email_operator_name IS NOT NULL)
  8216.   BEGIN
  8217.     SELECT @notify_email_operator_id = id
  8218.     FROM msdb.dbo.sysoperators
  8219.     WHERE (name = @notify_email_operator_name)
  8220.  
  8221.     IF (@notify_email_operator_id IS NULL)
  8222.     BEGIN
  8223.       RAISERROR(14234, -1, -1, '@notify_email_operator_name', 'sp_help_operator')
  8224.       RETURN(1) -- Failure
  8225.     END
  8226.     -- If a valid operator is specified the level must be non-zero
  8227.     IF (@notify_level_email = 0)
  8228.     BEGIN
  8229.       RAISERROR(14266, -1, -1, '@notify_level_email', '1, 2, 3')
  8230.       RETURN(1) -- Failure
  8231.     END
  8232.   END
  8233.   ELSE
  8234.   BEGIN
  8235.     SELECT @notify_email_operator_id = 0
  8236.     SELECT @notify_level_email = 0
  8237.   END
  8238.  
  8239.   -- Check operator to notify (via netsend)
  8240.   IF (@notify_netsend_operator_name IS NOT NULL)
  8241.   BEGIN
  8242.     SELECT @notify_netsend_operator_id = id
  8243.     FROM msdb.dbo.sysoperators
  8244.     WHERE (name = @notify_netsend_operator_name)
  8245.  
  8246.     IF (@notify_netsend_operator_id IS NULL)
  8247.     BEGIN
  8248.       RAISERROR(14234, -1, -1, '@notify_netsend_operator_name', 'sp_help_operator')
  8249.       RETURN(1) -- Failure
  8250.     END
  8251.     -- If a valid operator is specified the level must be non-zero
  8252.     IF (@notify_level_netsend = 0)
  8253.     BEGIN
  8254.       RAISERROR(14266, -1, -1, '@notify_level_netsend', '1, 2, 3')
  8255.       RETURN(1) -- Failure
  8256.     END
  8257.   END
  8258.   ELSE
  8259.   BEGIN
  8260.     SELECT @notify_netsend_operator_id = 0
  8261.     SELECT @notify_level_netsend = 0
  8262.   END
  8263.  
  8264.   -- Check operator to notify (via page)
  8265.   IF (@notify_page_operator_name IS NOT NULL)
  8266.   BEGIN
  8267.     SELECT @notify_page_operator_id = id
  8268.     FROM msdb.dbo.sysoperators
  8269.     WHERE (name = @notify_page_operator_name)
  8270.  
  8271.     IF (@notify_page_operator_id IS NULL)
  8272.     BEGIN
  8273.       RAISERROR(14234, -1, -1, '@notify_page_operator_name', 'sp_help_operator')
  8274.       RETURN(1) -- Failure
  8275.     END
  8276.     -- If a valid operator is specified the level must be non-zero
  8277.     IF (@notify_level_page = 0)
  8278.     BEGIN
  8279.       RAISERROR(14266, -1, -1, '@notify_level_page', '1, 2, 3')
  8280.       RETURN(1) -- Failure
  8281.     END
  8282.   END
  8283.   ELSE
  8284.   BEGIN
  8285.     SELECT @notify_page_operator_id = 0
  8286.     SELECT @notify_level_page = 0
  8287.   END
  8288.  
  8289.   -- Check delete level (must be 0, 1, 2 or 3)
  8290.   IF (@delete_level & 0x3 <> @delete_level)
  8291.   BEGIN
  8292.     RAISERROR(14266, -1, -1, '@delete_level', '0, 1, 2, 3')
  8293.     RETURN(1) -- Failure
  8294.   END
  8295.  
  8296.   RETURN(0) -- Success
  8297. END
  8298. go
  8299.  
  8300. /**************************************************************/
  8301. /* SP_ADD_JOB                                                 */
  8302. /**************************************************************/
  8303.  
  8304. PRINT ''
  8305. PRINT 'Creating procedure sp_add_job...'
  8306. go
  8307. IF (EXISTS (SELECT *
  8308.             FROM msdb.dbo.sysobjects
  8309.             WHERE (name = N'sp_add_job')
  8310.               AND (type = 'P')))
  8311.   DROP PROCEDURE sp_add_job
  8312. go
  8313. CREATE PROCEDURE sp_add_job
  8314.   @job_name                     sysname,
  8315.   @enabled                      TINYINT          = 1,        -- 0 = Disabled, 1 = Enabled
  8316.   @description                  NVARCHAR(512)    = NULL,
  8317.   @start_step_id                INT              = 1,
  8318.   @category_name                sysname          = NULL,
  8319.   @category_id                  INT              = NULL,     -- A language-independent way to specify which category to use
  8320.   @owner_login_name             sysname          = NULL,     -- The procedure assigns a default
  8321.   @notify_level_eventlog        INT              = 2,        -- 0 = Never, 1 = On Success, 2 = On Failure, 3 = Always
  8322.   @notify_level_email           INT              = 0,        -- 0 = Never, 1 = On Success, 2 = On Failure, 3 = Always
  8323.   @notify_level_netsend         INT              = 0,        -- 0 = Never, 1 = On Success, 2 = On Failure, 3 = Always
  8324.   @notify_level_page            INT              = 0,        -- 0 = Never, 1 = On Success, 2 = On Failure, 3 = Always
  8325.   @notify_email_operator_name   sysname          = NULL,
  8326.   @notify_netsend_operator_name sysname          = NULL,
  8327.   @notify_page_operator_name    sysname          = NULL,
  8328.   @delete_level                 INT              = 0,        -- 0 = Never, 1 = On Success, 2 = On Failure, 3 = Always
  8329.   @job_id                       UNIQUEIDENTIFIER = NULL OUTPUT,
  8330.   @originating_server           NVARCHAR(30)     = N'(local)'
  8331. AS
  8332. BEGIN
  8333.   DECLARE @retval                     INT
  8334.   DECLARE @notify_email_operator_id   INT
  8335.   DECLARE @notify_netsend_operator_id INT
  8336.   DECLARE @notify_page_operator_id    INT
  8337.   DECLARE @owner_sid                  VARBINARY(85)
  8338.  
  8339.   SET NOCOUNT ON
  8340.  
  8341.   -- Remove any leading/trailing spaces from parameters (except @owner_login_name)
  8342.   SELECT @originating_server           = LTRIM(RTRIM(@originating_server))
  8343.   SELECT @job_name                     = LTRIM(RTRIM(@job_name))
  8344.   SELECT @description                  = LTRIM(RTRIM(@description))
  8345.   SELECT @category_name                = LTRIM(RTRIM(@category_name))
  8346.   SELECT @notify_email_operator_name   = LTRIM(RTRIM(@notify_email_operator_name))
  8347.   SELECT @notify_netsend_operator_name = LTRIM(RTRIM(@notify_netsend_operator_name))
  8348.   SELECT @notify_page_operator_name    = LTRIM(RTRIM(@notify_page_operator_name))
  8349.  
  8350.   -- Turn [nullable] empty string parameters into NULLs
  8351.   IF (@description                  = N'') SELECT @description                  = NULL
  8352.   IF (@category_name                = N'') SELECT @category_name                = NULL
  8353.   IF (@notify_email_operator_name   = N'') SELECT @notify_email_operator_name   = NULL
  8354.   IF (@notify_netsend_operator_name = N'') SELECT @notify_netsend_operator_name = NULL
  8355.   IF (@notify_page_operator_name    = N'') SELECT @notify_page_operator_name    = NULL
  8356.  
  8357.   -- Default the owner (if not supplied or if a non-sa is [illegally] trying to create a job for another user)
  8358.   IF (@owner_login_name IS NULL) OR ((ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) = 0) AND (@owner_login_name <> SUSER_SNAME()))
  8359.     SELECT @owner_sid = SUSER_SID()
  8360.   ELSE
  8361.     SELECT @owner_sid = SUSER_SID(@owner_login_name) -- If @owner_login_name is invalid then SUSER_SID() will return NULL
  8362.  
  8363.   -- Default the description (if not supplied)
  8364.   IF (@description IS NULL)
  8365.     SELECT @description = FORMATMESSAGE(14571)
  8366.  
  8367.   -- If a category ID is provided this overrides any supplied category name
  8368.   IF (@category_id IS NOT NULL)
  8369.   BEGIN
  8370.     SELECT @category_name = name
  8371.     FROM msdb.dbo.syscategories 
  8372.     WHERE (category_id = @category_id)
  8373.     SELECT @category_name = ISNULL(@category_name, FORMATMESSAGE(14205))
  8374.   END
  8375.  
  8376.   -- Check parameters
  8377.   EXECUTE @retval = sp_verify_job NULL,  --  The job id is null since this is a new job
  8378.                                   @job_name,
  8379.                                   @enabled,
  8380.                                   @start_step_id,
  8381.                                   @category_name,
  8382.                                   @owner_sid                  OUTPUT,
  8383.                                   @notify_level_eventlog,
  8384.                                   @notify_level_email         OUTPUT,
  8385.                                   @notify_level_netsend       OUTPUT,
  8386.                                   @notify_level_page          OUTPUT,
  8387.                                   @notify_email_operator_name,
  8388.                                   @notify_netsend_operator_name,
  8389.                                   @notify_page_operator_name,
  8390.                                   @delete_level,
  8391.                                   @category_id                OUTPUT,
  8392.                                   @notify_email_operator_id   OUTPUT,
  8393.                                   @notify_netsend_operator_id OUTPUT,
  8394.                                   @notify_page_operator_id    OUTPUT,
  8395.                                   @originating_server         OUTPUT
  8396.   IF (@retval <> 0)
  8397.     RETURN(1) -- Failure
  8398.  
  8399.   IF (@job_id IS NULL)
  8400.   BEGIN
  8401.     -- Assign the GUID
  8402.     SELECT @job_id = NEWID()
  8403.   END
  8404.   ELSE
  8405.   BEGIN
  8406.     -- A job ID has been provided, so check that the caller is SQLServerAgent (inserting an MSX job)
  8407.     IF (PROGRAM_NAME() NOT LIKE N'SQLAgent%')
  8408.     BEGIN
  8409.       RAISERROR(14284, -1, -1)
  8410.       RETURN(1) -- Failure
  8411.     END
  8412.   END
  8413.  
  8414.   INSERT INTO msdb.dbo.sysjobs
  8415.          (job_id,
  8416.           originating_server,
  8417.           name,
  8418.           enabled,
  8419.           description,
  8420.           start_step_id,
  8421.           category_id,
  8422.           owner_sid,
  8423.           notify_level_eventlog,
  8424.           notify_level_email,
  8425.           notify_level_netsend,
  8426.           notify_level_page,
  8427.           notify_email_operator_id,
  8428.           notify_netsend_operator_id,
  8429.           notify_page_operator_id,
  8430.           delete_level,
  8431.           date_created,
  8432.           date_modified,
  8433.           version_number)
  8434.   VALUES (@job_id,
  8435.           @originating_server,
  8436.           @job_name,
  8437.           @enabled,
  8438.           @description,
  8439.           @start_step_id,
  8440.           @category_id,
  8441.           @owner_sid,
  8442.           @notify_level_eventlog,
  8443.           @notify_level_email,
  8444.           @notify_level_netsend,
  8445.           @notify_level_page,
  8446.           @notify_email_operator_id,
  8447.           @notify_netsend_operator_id,
  8448.           @notify_page_operator_id,
  8449.           @delete_level,
  8450.           GETDATE(),
  8451.           GETDATE(),
  8452.           1) -- Version number 1
  8453.   SELECT @retval = @@error
  8454.  
  8455.   -- If misc. replication job, then update global replication status table
  8456.   IF (@category_id IN (11, 12, 16, 17, 18))
  8457.   BEGIN
  8458.     -- Nothing can be done if this fails, so don't worry about the return code
  8459.     EXECUTE master.dbo.sp_MSupdate_replication_status
  8460.       @publisher = '',
  8461.       @publisher_db = '',
  8462.       @publication = '',
  8463.       @publication_type = -1,
  8464.       @agent_type = 5,
  8465.       @agent_name = @job_name,
  8466.       @status = NULL    -- Never run
  8467.   END
  8468.  
  8469.   -- NOTE: We don't notify SQLServerAgent to update it's cache (we'll do this in sp_add_jobserver)
  8470.  
  8471.   RETURN(@retval) -- 0 means success
  8472. END
  8473. go
  8474.  
  8475. /**************************************************************/
  8476. /* SP_UPDATE_JOB                                              */
  8477. /**************************************************************/
  8478.  
  8479. PRINT ''
  8480. PRINT 'Creating procedure sp_update_job...'
  8481. go
  8482. IF (EXISTS (SELECT *
  8483.             FROM msdb.dbo.sysobjects
  8484.             WHERE (name = N'sp_update_job')
  8485.               AND (type = 'P')))
  8486.   DROP PROCEDURE sp_update_job
  8487. go
  8488. CREATE PROCEDURE sp_update_job
  8489.   @job_id                       UNIQUEIDENTIFIER = NULL, -- Must provide this or current_name
  8490.   @job_name                     sysname          = NULL, -- Must provide this or job_id
  8491.   @new_name                     sysname          = NULL,
  8492.   @enabled                      TINYINT          = NULL,
  8493.   @description                  NVARCHAR(512)    = NULL,
  8494.   @start_step_id                INT              = NULL,
  8495.   @category_name                sysname          = NULL,
  8496.   @owner_login_name             sysname          = NULL,
  8497.   @notify_level_eventlog        INT              = NULL,
  8498.   @notify_level_email           INT              = NULL,
  8499.   @notify_level_netsend         INT              = NULL,
  8500.   @notify_level_page            INT              = NULL,
  8501.   @notify_email_operator_name   sysname          = NULL,
  8502.   @notify_netsend_operator_name sysname          = NULL,
  8503.   @notify_page_operator_name    sysname          = NULL,
  8504.   @delete_level                 INT              = NULL,
  8505.   @automatic_post               BIT              = 1     -- Flag for SEM use only
  8506. AS
  8507. BEGIN
  8508.   DECLARE @retval                        INT
  8509.   DECLARE @category_id                   INT
  8510.   DECLARE @notify_email_operator_id      INT
  8511.   DECLARE @notify_netsend_operator_id    INT
  8512.   DECLARE @notify_page_operator_id       INT
  8513.   DECLARE @owner_sid                     VARBINARY(85)
  8514.   DECLARE @alert_id                      INT
  8515.   DECLARE @cached_attribute_modified     INT
  8516.   DECLARE @is_sysadmin                   INT
  8517.   DECLARE @current_owner                 sysname
  8518.  
  8519.   DECLARE @x_new_name                    sysname
  8520.   DECLARE @x_enabled                     TINYINT
  8521.   DECLARE @x_description                 NVARCHAR(512)
  8522.   DECLARE @x_start_step_id               INT
  8523.   DECLARE @x_category_name               sysname
  8524.   DECLARE @x_category_id                 INT
  8525.   DECLARE @x_owner_sid                   VARBINARY(85)
  8526.   DECLARE @x_notify_level_eventlog       INT
  8527.   DECLARE @x_notify_level_email          INT
  8528.   DECLARE @x_notify_level_netsend        INT
  8529.   DECLARE @x_notify_level_page           INT
  8530.   DECLARE @x_notify_email_operator_name  sysname
  8531.   DECLARE @x_notify_netsnd_operator_name sysname
  8532.   DECLARE @x_notify_page_operator_name   sysname
  8533.   DECLARE @x_delete_level                INT
  8534.   DECLARE @x_originating_server          NVARCHAR(30) -- Not updatable
  8535.  
  8536.   -- Remove any leading/trailing spaces from parameters (except @owner_login_name)
  8537.   SELECT @job_name                     = LTRIM(RTRIM(@job_name))
  8538.   SELECT @new_name                     = LTRIM(RTRIM(@new_name))
  8539.   SELECT @description                  = LTRIM(RTRIM(@description))
  8540.   SELECT @category_name                = LTRIM(RTRIM(@category_name))
  8541.   SELECT @notify_email_operator_name   = LTRIM(RTRIM(@notify_email_operator_name))
  8542.   SELECT @notify_netsend_operator_name = LTRIM(RTRIM(@notify_netsend_operator_name))
  8543.   SELECT @notify_page_operator_name    = LTRIM(RTRIM(@notify_page_operator_name))
  8544.  
  8545.   SET NOCOUNT ON
  8546.  
  8547.   EXECUTE @retval = sp_verify_job_identifiers '@job_name',
  8548.                                               '@job_id',
  8549.                                                @job_name OUTPUT,
  8550.                                                @job_id   OUTPUT
  8551.   IF (@retval <> 0)
  8552.     RETURN(1) -- Failure
  8553.  
  8554.   -- Are we modifying an attribute which SQLServerAgent caches?
  8555.   IF ((@new_name                     IS NOT NULL) OR
  8556.       (@enabled                      IS NOT NULL) OR
  8557.       (@start_step_id                IS NOT NULL) OR
  8558.       (@owner_login_name             IS NOT NULL) OR
  8559.       (@notify_level_eventlog        IS NOT NULL) OR
  8560.       (@notify_level_email           IS NOT NULL) OR
  8561.       (@notify_level_netsend         IS NOT NULL) OR
  8562.       (@notify_level_page            IS NOT NULL) OR
  8563.       (@notify_email_operator_name   IS NOT NULL) OR
  8564.       (@notify_netsend_operator_name IS NOT NULL) OR
  8565.       (@notify_page_operator_name    IS NOT NULL) OR
  8566.       (@delete_level                 IS NOT NULL))
  8567.     SELECT @cached_attribute_modified = 1
  8568.   ELSE
  8569.     SELECT @cached_attribute_modified = 0
  8570.  
  8571.   -- Set the x_ (existing) variables
  8572.   SELECT @x_new_name                    = sjv.name,
  8573.          @x_enabled                     = sjv.enabled,
  8574.          @x_description                 = sjv.description,
  8575.          @x_start_step_id               = sjv.start_step_id,
  8576.          @x_category_name               = sc.name,                  -- From syscategories
  8577.          @x_category_id                 = sc.category_id,           -- From syscategories
  8578.          @x_owner_sid                   = sjv.owner_sid,
  8579.          @x_notify_level_eventlog       = sjv.notify_level_eventlog,
  8580.          @x_notify_level_email          = sjv.notify_level_email,
  8581.          @x_notify_level_netsend        = sjv.notify_level_netsend,
  8582.          @x_notify_level_page           = sjv.notify_level_page,
  8583.          @x_notify_email_operator_name  = so1.name,                   -- From sysoperators
  8584.          @x_notify_netsnd_operator_name = so2.name,                   -- From sysoperators
  8585.          @x_notify_page_operator_name   = so3.name,                   -- From sysoperators
  8586.          @x_delete_level                = sjv.delete_level,
  8587.          @x_originating_server          = sjv.originating_server
  8588.   FROM msdb.dbo.sysjobs_view                 sjv
  8589.        LEFT OUTER JOIN msdb.dbo.sysoperators so1 ON (sjv.notify_email_operator_id = so1.id)
  8590.        LEFT OUTER JOIN msdb.dbo.sysoperators so2 ON (sjv.notify_netsend_operator_id = so2.id)
  8591.        LEFT OUTER JOIN msdb.dbo.sysoperators so3 ON (sjv.notify_page_operator_id = so3.id),
  8592.        msdb.dbo.syscategories                sc
  8593.   WHERE (sjv.job_id = @job_id)
  8594.     AND (sjv.category_id = sc.category_id)
  8595.  
  8596.   -- Check authority (only SQLServerAgent can modify a non-local job)
  8597.   IF (UPPER(@x_originating_server) <> N'(LOCAL)') AND
  8598.      (PROGRAM_NAME() NOT LIKE N'SQLAgent%')
  8599.   BEGIN
  8600.     RAISERROR(14274, -1, -1)
  8601.     RETURN(1) -- Failure
  8602.   END
  8603.  
  8604.   IF (@new_name = N'') SELECT @new_name = NULL
  8605.  
  8606.   -- Fill out the values for all non-supplied parameters from the existing values
  8607.   IF (@new_name                     IS NULL) SELECT @new_name                     = @x_new_name
  8608.   IF (@enabled                      IS NULL) SELECT @enabled                      = @x_enabled
  8609.   IF (@description                  IS NULL) SELECT @description                  = @x_description
  8610.   IF (@start_step_id                IS NULL) SELECT @start_step_id                = @x_start_step_id
  8611.   IF (@category_name                IS NULL) SELECT @category_name                = @x_category_name
  8612.   IF (@owner_sid                    IS NULL) SELECT @owner_sid                    = @x_owner_sid
  8613.   IF (@notify_level_eventlog        IS NULL) SELECT @notify_level_eventlog        = @x_notify_level_eventlog
  8614.   IF (@notify_level_email           IS NULL) SELECT @notify_level_email           = @x_notify_level_email
  8615.   IF (@notify_level_netsend         IS NULL) SELECT @notify_level_netsend         = @x_notify_level_netsend
  8616.   IF (@notify_level_page            IS NULL) SELECT @notify_level_page            = @x_notify_level_page
  8617.   IF (@notify_email_operator_name   IS NULL) SELECT @notify_email_operator_name   = @x_notify_email_operator_name
  8618.   IF (@notify_netsend_operator_name IS NULL) SELECT @notify_netsend_operator_name = @x_notify_netsnd_operator_name
  8619.   IF (@notify_page_operator_name    IS NULL) SELECT @notify_page_operator_name    = @x_notify_page_operator_name
  8620.   IF (@delete_level                 IS NULL) SELECT @delete_level                 = @x_delete_level
  8621.  
  8622.   -- If the SA is attempting to assign ownership of the job to someone else, then convert
  8623.   -- the login name to an ID
  8624.   IF ((ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) = 1) AND (@owner_login_name IS NOT NULL))
  8625.     SELECT @owner_sid = SUSER_SID(@owner_login_name) -- If @owner_login_name is invalid then SUSER_SID() will return NULL
  8626.  
  8627.   -- Only the SA can re-assign jobs
  8628.   IF ((ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) <> 1) AND (@owner_login_name IS NOT NULL))
  8629.     RAISERROR(14242, -1, -1)
  8630.  
  8631.   -- Ownership of a multi-server job cannot be assigned to a non-sysadmin
  8632.   IF (@owner_login_name IS NOT NULL) AND 
  8633.      (EXISTS (SELECT *
  8634.               FROM msdb.dbo.sysjobs       sj,
  8635.                    msdb.dbo.sysjobservers sjs
  8636.               WHERE (sj.job_id = sjs.job_id)
  8637.                 AND (sj.job_id = @job_id)
  8638.                 AND (sjs.server_id <> 0)))
  8639.   BEGIN
  8640.     SELECT @is_sysadmin = 0
  8641.     EXECUTE msdb.dbo.sp_sqlagent_has_server_access @login_name = @owner_login_name, @is_sysadmin_member = @is_sysadmin OUTPUT
  8642.     IF (@is_sysadmin = 0)
  8643.     BEGIN
  8644.       SELECT @current_owner = SUSER_SNAME(@x_owner_sid)
  8645.       RAISERROR(14543, -1, -1, @current_owner, N'sysadmin')
  8646.       RETURN(1) -- Failure
  8647.     END
  8648.   END
  8649.  
  8650.   -- Turn [nullable] empty string parameters into NULLs
  8651.   IF (@description                  = N'') SELECT @description                  = NULL
  8652.   IF (@category_name                = N'') SELECT @category_name                = NULL
  8653.   IF (@notify_email_operator_name   = N'') SELECT @notify_email_operator_name   = NULL
  8654.   IF (@notify_netsend_operator_name = N'') SELECT @notify_netsend_operator_name = NULL
  8655.   IF (@notify_page_operator_name    = N'') SELECT @notify_page_operator_name    = NULL
  8656.  
  8657.   -- Check new values
  8658.   EXECUTE @retval = sp_verify_job @job_id,
  8659.                                   @new_name,
  8660.                                   @enabled,
  8661.                                   @start_step_id,
  8662.                                   @category_name,
  8663.                                   @owner_sid                  OUTPUT,
  8664.                                   @notify_level_eventlog,
  8665.                                   @notify_level_email         OUTPUT,
  8666.                                   @notify_level_netsend       OUTPUT,
  8667.                                   @notify_level_page          OUTPUT,
  8668.                                   @notify_email_operator_name,
  8669.                                   @notify_netsend_operator_name,
  8670.                                   @notify_page_operator_name,
  8671.                                   @delete_level,
  8672.                                   @category_id                OUTPUT,
  8673.                                   @notify_email_operator_id   OUTPUT,
  8674.                                   @notify_netsend_operator_id OUTPUT,
  8675.                                   @notify_page_operator_id    OUTPUT,
  8676.                                   @x_originating_server       OUTPUT -- We ignore the return value
  8677.   IF (@retval <> 0)
  8678.     RETURN(1) -- Failure
  8679.  
  8680.   BEGIN TRANSACTION
  8681.  
  8682.   -- If the job is being re-assigned, modify sysjobsteps.database_user_name as necessary
  8683.   IF (@owner_login_name IS NOT NULL)
  8684.   BEGIN
  8685.     IF (EXISTS (SELECT * 
  8686.                 FROM msdb.dbo.sysjobsteps
  8687.                 WHERE (job_id = @job_id)
  8688.                   AND (subsystem = N'TSQL')))
  8689.     BEGIN
  8690.       IF (EXISTS (SELECT *
  8691.                   FROM master.dbo.syslogins
  8692.                   WHERE (sid = @owner_sid) 
  8693.                     AND (sysadmin <> 1)))
  8694.       BEGIN
  8695.         -- The job is being re-assigned to an non-SA
  8696.         UPDATE msdb.dbo.sysjobsteps
  8697.         SET database_user_name = NULL
  8698.         WHERE (job_id = @job_id)
  8699.           AND (subsystem = N'TSQL')
  8700.       END
  8701.     END
  8702.   END
  8703.  
  8704.   UPDATE msdb.dbo.sysjobs
  8705.   SET name                       = @new_name,
  8706.       enabled                    = @enabled,
  8707.       description                = @description,
  8708.       start_step_id              = @start_step_id,
  8709.       category_id                = @category_id,              -- Returned from sp_verify_job
  8710.       owner_sid                  = @owner_sid,
  8711.       notify_level_eventlog      = @notify_level_eventlog,
  8712.       notify_level_email         = @notify_level_email,
  8713.       notify_level_netsend       = @notify_level_netsend,
  8714.       notify_level_page          = @notify_level_page,
  8715.       notify_email_operator_id   = @notify_email_operator_id,   -- Returned from sp_verify_job
  8716.       notify_netsend_operator_id = @notify_netsend_operator_id, -- Returned from sp_verify_job
  8717.       notify_page_operator_id    = @notify_page_operator_id,    -- Returned from sp_verify_job
  8718.       delete_level               = @delete_level,
  8719.       version_number             = version_number + 1,  -- Update the job's version
  8720.       date_modified              = GETDATE()            -- Update the job's last-modified information
  8721.   WHERE (job_id = @job_id)
  8722.   SELECT @retval = @@error
  8723.  
  8724.   COMMIT TRANSACTION
  8725.  
  8726.   -- If change to or from a misc. replication job, then update global replication status table
  8727.   IF ((@category_name != @x_category_name) AND
  8728.     (@x_category_id IN (11, 12, 16, 17, 18) OR @category_id IN (11, 12,16, 17, 18)))
  8729.   BEGIN
  8730.     -- Delete entry if change misc. replication job to other
  8731.     IF (@x_category_name IS NOT NULL)
  8732.     BEGIN
  8733.       -- Nothing can be done if this fails, so don't worry about the return code
  8734.       EXECUTE master.dbo.sp_MSupdate_replication_status
  8735.         @publisher = '',
  8736.         @publisher_db = '',
  8737.         @publication = '',
  8738.         @publication_type = -1,
  8739.         @agent_type = 5,
  8740.         @agent_name = @job_name,
  8741.         @status = -1  -- Delete
  8742.     END
  8743.  
  8744.     -- Add entry if updated to misc. replication job
  8745.     IF (@x_category_name IS NOT NULL)
  8746.     BEGIN
  8747.       -- Nothing can be done if this fails, so don't worry about the return code
  8748.       EXECUTE master.dbo.sp_MSupdate_replication_status
  8749.         @publisher = '',
  8750.         @publisher_db = '',
  8751.         @publication = '',
  8752.         @publication_type = -1,
  8753.         @agent_type = 5,
  8754.         @agent_name = @job_name,
  8755.         @status = NULL    -- Never run
  8756.     END
  8757.   END
  8758.  
  8759.   -- Always re-post the job if it's an auto-delete job (or if we're updating an auto-delete job
  8760.   -- to be non-auto-delete)
  8761.   IF (((SELECT delete_level
  8762.         FROM msdb.dbo.sysjobs
  8763.         WHERE (job_id = @job_id)) <> 0) OR
  8764.       ((@x_delete_level = 1) AND (@delete_level = 0)))
  8765.     EXECUTE msdb.dbo.sp_post_msx_operation 'INSERT', 'JOB', @job_id
  8766.   ELSE
  8767.   BEGIN
  8768.     -- Post the update to target servers
  8769.     IF (@automatic_post = 1)
  8770.       EXECUTE msdb.dbo.sp_post_msx_operation 'UPDATE', 'JOB', @job_id
  8771.   END
  8772.  
  8773.   -- Keep SQLServerAgent's cache in-sync
  8774.   -- NOTE: We only notify SQLServerAgent if we know the job has been cached and if
  8775.   --       attributes other than description or category have been changed (since
  8776.   --       SQLServerAgent doesn't cache these two)
  8777.   IF (EXISTS (SELECT * 
  8778.               FROM msdb.dbo.sysjobservers 
  8779.               WHERE (job_id = @job_id) 
  8780.                 AND (server_id = 0)
  8781.                 AND (@cached_attribute_modified = 1)))
  8782.     EXECUTE msdb.dbo.sp_sqlagent_notify @op_type     = N'J',
  8783.                                         @job_id      = @job_id,
  8784.                                         @action_type = N'U'
  8785.  
  8786.   -- If the name was changed, make SQLServerAgent re-cache any alerts that reference the job
  8787.   -- since the alert cache contains the job name
  8788.   IF ((@job_name <> @new_name) AND (EXISTS (SELECT *
  8789.                                             FROM msdb.dbo.sysalerts
  8790.                                             WHERE (job_id = @job_id))))
  8791.   BEGIN
  8792.     DECLARE sysalerts_cache_update CURSOR LOCAL
  8793.     FOR
  8794.     SELECT id
  8795.     FROM msdb.dbo.sysalerts
  8796.     WHERE (job_id = @job_id)
  8797.  
  8798.     OPEN sysalerts_cache_update
  8799.     FETCH NEXT FROM sysalerts_cache_update INTO @alert_id
  8800.  
  8801.     WHILE (@@fetch_status = 0)
  8802.     BEGIN
  8803.       EXECUTE msdb.dbo.sp_sqlagent_notify @op_type     = N'A',
  8804.                                           @alert_id    = @alert_id,
  8805.                                           @action_type = N'U'
  8806.       FETCH NEXT FROM sysalerts_cache_update INTO @alert_id
  8807.     END
  8808.     DEALLOCATE sysalerts_cache_update
  8809.   END
  8810.  
  8811.   RETURN(@retval) -- 0 means success
  8812. END
  8813. go
  8814.  
  8815. /**************************************************************/
  8816. /* SP_DELETE_JOB                                              */
  8817. /**************************************************************/
  8818.  
  8819. PRINT ''
  8820. PRINT 'Creating procedure sp_delete_job...'
  8821. go
  8822. IF (EXISTS (SELECT *
  8823.             FROM msdb.dbo.sysobjects
  8824.             WHERE (name = N'sp_delete_job')
  8825.               AND (type = 'P')))
  8826.   DROP PROCEDURE sp_delete_job
  8827. go
  8828. CREATE PROCEDURE sp_delete_job
  8829.   @job_id             UNIQUEIDENTIFIER = NULL, -- If provided should NOT also provide job_name
  8830.   @job_name           sysname          = NULL, -- If provided should NOT also provide job_id
  8831.   @originating_server NVARCHAR(30)     = NULL, -- Reserved (used by SQLAgent)
  8832.   @delete_history     BIT              = 1     -- Reserved (used by SQLAgent)
  8833. AS
  8834. BEGIN
  8835.   DECLARE @current_msx_server NVARCHAR(30)
  8836.   DECLARE @bMSX_job           BIT
  8837.   DECLARE @retval             INT
  8838.   DECLARE @local_machine_name NVARCHAR(30)
  8839.   DECLARE @category_id        INT
  8840.  
  8841.   SET NOCOUNT ON
  8842.  
  8843.   -- Remove any leading/trailing spaces from parameters
  8844.   SELECT @originating_server = LTRIM(RTRIM(@originating_server))
  8845.  
  8846.   -- Turn [nullable] empty string parameters into NULLs
  8847.   IF (@originating_server = N'') SELECT @originating_server = NULL
  8848.  
  8849.   IF ((@job_id IS NOT NULL) OR (@job_name IS NOT NULL))
  8850.   BEGIN
  8851.     EXECUTE @retval = sp_verify_job_identifiers '@job_name',
  8852.                                                 '@job_id',
  8853.                                                  @job_name OUTPUT,
  8854.                                                  @job_id   OUTPUT
  8855.     IF (@retval <> 0)
  8856.       RETURN(1) -- Failure
  8857.   END
  8858.  
  8859.   -- We need either a job name or a server name, not both
  8860.   IF ((@job_name IS NULL)     AND (@originating_server IS NULL)) OR
  8861.      ((@job_name IS NOT NULL) AND (@originating_server IS NOT NULL))
  8862.   BEGIN
  8863.     RAISERROR(14279, -1, -1)
  8864.     RETURN(1) -- Failure
  8865.   END
  8866.  
  8867.   -- Get category to see if it is a misc. replication agent. @category_id will be
  8868.   -- NULL if there is no @job_id.
  8869.   select @category_id = category_id from msdb.dbo.sysjobs where job_id = @job_id
  8870.  
  8871.   -- If job name was given, determine if the job is from an MSX
  8872.   IF (@job_id IS NOT NULL)
  8873.   BEGIN
  8874.     SELECT @bMSX_job = CASE originating_server
  8875.                          WHEN N'(local)' THEN 0
  8876.                          ELSE 1
  8877.                        END
  8878.     FROM msdb.dbo.sysjobs_view
  8879.     WHERE (job_id = @job_id)
  8880.   END
  8881.  
  8882.   -- If server name was given, warn user if different from current MSX
  8883.   IF (@originating_server IS NOT NULL)
  8884.   BEGIN
  8885.     EXECUTE @retval = master.dbo.xp_getnetname @local_machine_name OUTPUT
  8886.     IF (@retval <> 0)
  8887.       RETURN(1) -- Failure
  8888.  
  8889.     IF ((UPPER(@originating_server) = N'(LOCAL)') OR (UPPER(@originating_server) = UPPER(@local_machine_name)))
  8890.       SELECT @originating_server = N'(local)'
  8891.  
  8892.     EXECUTE master.dbo.xp_regread N'HKEY_LOCAL_MACHINE',
  8893.                                   N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
  8894.                                   N'MSXServerName',
  8895.                                    @current_msx_server OUTPUT,
  8896.                                   N'no_output'
  8897.  
  8898.     -- If server name was given but it's not the current MSX, print a warning
  8899.     SELECT @current_msx_server = LTRIM(RTRIM(@current_msx_server))
  8900.     IF ((@current_msx_server IS NOT NULL) AND (@current_msx_server <> N'') AND (@originating_server <> @current_msx_server))
  8901.       RAISERROR(14224, 0, 1, @current_msx_server)
  8902.   END
  8903.  
  8904.   -- Check authority (only SQLServerAgent can delete a non-local job)
  8905.   IF (((@originating_server IS NOT NULL) AND (@originating_server <> N'(local)')) OR (@bMSX_job = 1)) AND
  8906.      (PROGRAM_NAME() NOT LIKE N'SQLAgent%')
  8907.   BEGIN
  8908.     RAISERROR(14274, -1, -1)
  8909.     RETURN(1) -- Failure
  8910.   END
  8911.  
  8912.   CREATE TABLE #temp_jobs_to_delete (job_id UNIQUEIDENTIFIER NOT NULL, job_is_cached INT NOT NULL)
  8913.  
  8914.   -- Do the delete (for a specific job)
  8915.   IF (@job_id IS NOT NULL)
  8916.   BEGIN
  8917.     INSERT INTO #temp_jobs_to_delete
  8918.     SELECT job_id, (SELECT COUNT(*) 
  8919.                     FROM msdb.dbo.sysjobservers 
  8920.                     WHERE (job_id = @job_id) 
  8921.                       AND (server_id = 0))
  8922.     FROM msdb.dbo.sysjobs_view
  8923.     WHERE (job_id = @job_id)
  8924.  
  8925.     -- Check if we have any work to do
  8926.     IF (NOT EXISTS (SELECT *
  8927.                     FROM #temp_jobs_to_delete))
  8928.       RETURN(0) -- Success
  8929.  
  8930.     -- Post the delete to any target servers (need to do this BEFORE deleting the job itself,
  8931.     -- but AFTER clearing all all pending download instructions).  Note that if the job is
  8932.     -- NOT a multi-server job then sp_post_msx_operation will catch this and will do nothing.
  8933.     DELETE FROM msdb.dbo.sysdownloadlist
  8934.     WHERE (object_id = @job_id)
  8935.     EXECUTE msdb.dbo.sp_post_msx_operation 'DELETE', 'JOB', @job_id
  8936.  
  8937.     -- Must do this before deleting the job itself since sp_sqlagent_notify does a lookup on sysjobs_view
  8938.     EXECUTE msdb.dbo.sp_delete_job_references
  8939.  
  8940.     -- Delete all traces of the job
  8941.     BEGIN TRANSACTION
  8942.  
  8943.     DELETE FROM msdb.dbo.sysjobs
  8944.     WHERE job_id IN (SELECT job_id FROM #temp_jobs_to_delete)
  8945.  
  8946.     DELETE FROM msdb.dbo.sysjobservers
  8947.     WHERE job_id IN (SELECT job_id FROM #temp_jobs_to_delete)
  8948.  
  8949.     DELETE FROM msdb.dbo.sysjobsteps
  8950.     WHERE job_id IN (SELECT job_id FROM #temp_jobs_to_delete)
  8951.  
  8952.     DELETE FROM msdb.dbo.sysjobschedules
  8953.     WHERE job_id IN (SELECT job_id FROM #temp_jobs_to_delete)
  8954.  
  8955.     IF (@delete_history = 1)
  8956.       DELETE FROM msdb.dbo.sysjobhistory
  8957.       WHERE job_id IN (SELECT job_id FROM #temp_jobs_to_delete)
  8958.  
  8959.     COMMIT TRANSACTION
  8960.  
  8961.   END
  8962.   ELSE
  8963.   -- Do the delete (for all jobs originating from the specific server)
  8964.   IF (@originating_server IS NOT NULL)
  8965.   BEGIN
  8966.     EXECUTE msdb.dbo.sp_delete_all_msx_jobs @msx_server = @originating_server
  8967.  
  8968.     -- NOTE: In this case there is no need to propagate the delete via sp_post_msx_operation
  8969.     --       since this type of delete is only ever performed on a TSX.
  8970.   END
  8971.  
  8972.   DROP TABLE #temp_jobs_to_delete
  8973.  
  8974.   -- If misc. replication job, then update global replication status table.
  8975.   -- @category_id will have a value ONLY if @job_name or @job_id is provided.
  8976.   IF (@category_id IS NOT NULL AND @category_id IN (11, 12, 16, 17, 18))
  8977.   BEGIN
  8978.     -- Nothing can be done if this fails, so don't worry about the return code
  8979.     EXECUTE master.dbo.sp_MSupdate_replication_status
  8980.       @publisher = '',
  8981.       @publisher_db = '',
  8982.       @publication = '',
  8983.       @publication_type = -1,
  8984.       @agent_type = 5,
  8985.       @agent_name = @job_name,
  8986.       @status = -1 -- Delete
  8987.   END
  8988.  
  8989.   RETURN(0) -- 0 means success
  8990. END
  8991. go
  8992.  
  8993. /**************************************************************/
  8994. /* SP_GET_COMPOSITE_JOB_INFO                                  */
  8995. /**************************************************************/
  8996.  
  8997. PRINT ''
  8998. PRINT 'Creating procedure sp_get_composite_job_info...'
  8999. go
  9000. IF (EXISTS (SELECT *
  9001.             FROM msdb.dbo.sysobjects
  9002.             WHERE (name = N'sp_get_composite_job_info')
  9003.               AND (type = 'P')))
  9004.   DROP PROCEDURE sp_get_composite_job_info
  9005. go
  9006. CREATE PROCEDURE sp_get_composite_job_info
  9007.   @job_id             UNIQUEIDENTIFIER = NULL,
  9008.   @job_type           VARCHAR(12)      = NULL,  -- LOCAL or MULTI-SERVER
  9009.   @owner_login_name   sysname          = NULL,
  9010.   @subsystem          NVARCHAR(40)     = NULL,
  9011.   @category_id        INT              = NULL,
  9012.   @enabled            TINYINT          = NULL,
  9013.   @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
  9014.   @date_comparator    CHAR(1)          = NULL,  -- >, < or =
  9015.   @date_created       DATETIME         = NULL,
  9016.   @date_last_modified DATETIME         = NULL,
  9017.   @description        NVARCHAR(512)    = NULL   -- We do a LIKE on this so it can include wildcards
  9018. AS
  9019. BEGIN
  9020.   DECLARE @is_sysadmin INT
  9021.   DECLARE @job_owner   sysname
  9022.  
  9023.   SET NOCOUNT ON
  9024.  
  9025.   -- By 'composite' we mean a combination of sysjobs and xp_sqlagent_enum_jobs data.
  9026.   -- This proc should only ever be called by sp_help_job, so we don't verify the
  9027.   -- parameters (sp_help_job has already done this).
  9028.  
  9029.   -- Step 1: Create intermediate work tables
  9030.   CREATE TABLE #job_execution_state (job_id                  UNIQUEIDENTIFIER NOT NULL,
  9031.                                      date_started            INT              NOT NULL,
  9032.                                      time_started            INT              NOT NULL,
  9033.                                      execution_job_status    INT              NOT NULL,
  9034.                                      execution_step_id       INT              NULL,
  9035.                                      execution_step_name     sysname          NULL,
  9036.                                      execution_retry_attempt INT              NOT NULL,
  9037.                                      next_run_date           INT              NOT NULL,
  9038.                                      next_run_time           INT              NOT NULL,
  9039.                                      next_run_schedule_id    INT              NOT NULL)
  9040.   CREATE TABLE #filtered_jobs (job_id                   UNIQUEIDENTIFIER NOT NULL,
  9041.                                date_created             DATETIME         NOT NULL,
  9042.                                date_last_modified       DATETIME         NOT NULL,
  9043.                                current_execution_status INT              NULL,
  9044.                                current_execution_step   sysname          NULL,
  9045.                                current_retry_attempt    INT              NULL,
  9046.                                last_run_date            INT              NOT NULL,
  9047.                                last_run_time            INT              NOT NULL,
  9048.                                last_run_outcome         INT              NOT NULL,
  9049.                                next_run_date            INT              NULL,
  9050.                                next_run_time            INT              NULL,
  9051.                                next_run_schedule_id     INT              NULL,
  9052.                                type                     INT              NOT NULL)
  9053.   CREATE TABLE #xp_results (job_id                UNIQUEIDENTIFIER NOT NULL,
  9054.                             last_run_date         INT              NOT NULL,
  9055.                             last_run_time         INT              NOT NULL,
  9056.                             next_run_date         INT              NOT NULL,
  9057.                             next_run_time         INT              NOT NULL,
  9058.                             next_run_schedule_id  INT              NOT NULL,
  9059.                             requested_to_run      INT              NOT NULL, -- BOOL
  9060.                             request_source        INT              NOT NULL,
  9061.                             request_source_id     sysname          NULL,
  9062.                             running               INT              NOT NULL, -- BOOL
  9063.                             current_step          INT              NOT NULL,
  9064.                             current_retry_attempt INT              NOT NULL,
  9065.                             job_state             INT              NOT NULL)
  9066.  
  9067.   -- Step 2: Capture job execution information (for local jobs only since that's all SQLServerAgent caches)
  9068.   SELECT @is_sysadmin = ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0)
  9069.   SELECT @job_owner = SUSER_SNAME()
  9070.  
  9071.   
  9072.   IF ((@@microsoftversion / 0x01000000) >= 8) -- SQL Server 8.0 or greater
  9073.     INSERT INTO #xp_results
  9074.     EXECUTE master.dbo.xp_sqlagent_enum_jobs @is_sysadmin, @job_owner, @job_id
  9075.   ELSE
  9076.     INSERT INTO #xp_results
  9077.     EXECUTE master.dbo.xp_sqlagent_enum_jobs @is_sysadmin, @job_owner
  9078.  
  9079.   INSERT INTO #job_execution_state
  9080.   SELECT xpr.job_id,
  9081.          xpr.last_run_date,
  9082.          xpr.last_run_time,
  9083.          xpr.job_state,
  9084.          sjs.step_id,
  9085.          sjs.step_name,
  9086.          xpr.current_retry_attempt,
  9087.          xpr.next_run_date,
  9088.          xpr.next_run_time,
  9089.          xpr.next_run_schedule_id
  9090.   FROM #xp_results                          xpr
  9091.        LEFT OUTER JOIN msdb.dbo.sysjobsteps sjs ON ((xpr.job_id = sjs.job_id) AND (xpr.current_step = sjs.step_id)),
  9092.        msdb.dbo.sysjobs_view                sjv
  9093.   WHERE (sjv.job_id = xpr.job_id)
  9094.  
  9095.   -- Step 3: Filter on everything but dates and job_type
  9096.   IF ((@subsystem        IS NULL) AND
  9097.       (@owner_login_name IS NULL) AND
  9098.       (@enabled          IS NULL) AND
  9099.       (@category_id      IS NULL) AND
  9100.       (@execution_status IS NULL) AND
  9101.       (@description      IS NULL) AND
  9102.       (@job_id           IS NULL))
  9103.   BEGIN
  9104.     -- Optimize for the frequently used case...
  9105.     INSERT INTO #filtered_jobs
  9106.     SELECT sjv.job_id,
  9107.            sjv.date_created,
  9108.            sjv.date_modified,
  9109.            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)
  9110.            CASE ISNULL(jes.execution_step_id, 0)
  9111.              WHEN 0 THEN NULL                   -- Will be NULL if the job is non-local or is not in #job_execution_state
  9112.              ELSE CONVERT(NVARCHAR, jes.execution_step_id) + N' (' + jes.execution_step_name + N')'
  9113.            END,
  9114.            jes.execution_retry_attempt,         -- Will be NULL if the job is non-local or is not in #job_execution_state
  9115.            0,  -- last_run_date placeholder    (we'll fix it up in step 3.3)
  9116.            0,  -- last_run_time placeholder    (we'll fix it up in step 3.3)
  9117.            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)
  9118.            jes.next_run_date,                   -- Will be NULL if the job is non-local or is not in #job_execution_state
  9119.            jes.next_run_time,                   -- Will be NULL if the job is non-local or is not in #job_execution_state
  9120.            jes.next_run_schedule_id,            -- Will be NULL if the job is non-local or is not in #job_execution_state
  9121.            0   -- type placeholder             (we'll fix it up in step 3.4)
  9122.     FROM msdb.dbo.sysjobs_view                sjv
  9123.          LEFT OUTER JOIN #job_execution_state jes ON (sjv.job_id = jes.job_id)
  9124.   END
  9125.   ELSE
  9126.   BEGIN
  9127.     INSERT INTO #filtered_jobs
  9128.     SELECT DISTINCT
  9129.            sjv.job_id,
  9130.            sjv.date_created,
  9131.            sjv.date_modified,
  9132.            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)
  9133.            CASE ISNULL(jes.execution_step_id, 0)
  9134.              WHEN 0 THEN NULL                   -- Will be NULL if the job is non-local or is not in #job_execution_state
  9135.              ELSE CONVERT(NVARCHAR, jes.execution_step_id) + N' (' + jes.execution_step_name + N')'
  9136.            END,
  9137.            jes.execution_retry_attempt,         -- Will be NULL if the job is non-local or is not in #job_execution_state
  9138.            0,  -- last_run_date placeholder    (we'll fix it up in step 3.3)
  9139.            0,  -- last_run_time placeholder    (we'll fix it up in step 3.3)
  9140.            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)
  9141.            jes.next_run_date,                   -- Will be NULL if the job is non-local or is not in #job_execution_state
  9142.            jes.next_run_time,                   -- Will be NULL if the job is non-local or is not in #job_execution_state
  9143.            jes.next_run_schedule_id,            -- Will be NULL if the job is non-local or is not in #job_execution_state
  9144.            0   -- type placeholder             (we'll fix it up in step 3.4)
  9145.     FROM msdb.dbo.sysjobs_view                sjv
  9146.          LEFT OUTER JOIN #job_execution_state jes ON (sjv.job_id = jes.job_id)
  9147.          LEFT OUTER JOIN msdb.dbo.sysjobsteps sjs ON (sjv.job_id = sjs.job_id)
  9148.     WHERE ((@subsystem        IS NULL) OR (sjs.subsystem            = @subsystem))
  9149.       AND ((@owner_login_name IS NULL) OR (sjv.owner_sid            = SUSER_SID(@owner_login_name)))
  9150.       AND ((@enabled          IS NULL) OR (sjv.enabled              = @enabled))
  9151.       AND ((@category_id      IS NULL) OR (sjv.category_id          = @category_id))
  9152.       AND ((@execution_status IS NULL) OR ((@execution_status > 0) AND (jes.execution_job_status = @execution_status)) 
  9153.                                        OR ((@execution_status = 0) AND (jes.execution_job_status <> 4) AND (jes.execution_job_status <> 5)))
  9154.       AND ((@description      IS NULL) OR (sjv.description       LIKE @description))
  9155.       AND ((@job_id           IS NULL) OR (sjv.job_id               = @job_id))
  9156.   END
  9157.  
  9158.   -- Step 3.1: Change the execution status of non-local jobs from 'Idle' to 'Unknown'
  9159.   UPDATE #filtered_jobs
  9160.   SET current_execution_status = NULL
  9161.   WHERE (current_execution_status = 4)
  9162.     AND (job_id IN (SELECT job_id
  9163.                     FROM msdb.dbo.sysjobservers
  9164.                     WHERE (server_id <> 0)))
  9165.  
  9166.   -- Step 3.2: Check that if the user asked to see idle jobs that we still have some.
  9167.   --           If we don't have any then the query should return no rows.
  9168.   IF (@execution_status = 4) AND
  9169.      (NOT EXISTS (SELECT *
  9170.                   FROM #filtered_jobs
  9171.                   WHERE (current_execution_status = 4)))
  9172.   BEGIN
  9173.     TRUNCATE TABLE #filtered_jobs
  9174.   END
  9175.  
  9176.   -- Step 3.3: Populate the last run date/time/outcome [this is a little tricky since for
  9177.   --           multi-server jobs there are multiple last run details in sysjobservers, so
  9178.   --           we simply choose the most recent].
  9179.   IF (EXISTS (SELECT *
  9180.               FROM msdb.dbo.systargetservers))
  9181.   BEGIN
  9182.     UPDATE #filtered_jobs
  9183.     SET last_run_date = sjs.last_run_date,
  9184.         last_run_time = sjs.last_run_time,
  9185.         last_run_outcome = sjs.last_run_outcome
  9186.     FROM #filtered_jobs         fj,
  9187.          msdb.dbo.sysjobservers sjs
  9188.     WHERE (CONVERT(FLOAT, sjs.last_run_date) * 1000000) + sjs.last_run_time =
  9189.            (SELECT MAX((CONVERT(FLOAT, last_run_date) * 1000000) + last_run_time)
  9190.             FROM msdb.dbo.sysjobservers
  9191.             WHERE (job_id = sjs.job_id))
  9192.       AND (fj.job_id = sjs.job_id)
  9193.   END
  9194.   ELSE
  9195.   BEGIN
  9196.     UPDATE #filtered_jobs
  9197.     SET last_run_date = sjs.last_run_date,
  9198.         last_run_time = sjs.last_run_time,
  9199.         last_run_outcome = sjs.last_run_outcome
  9200.     FROM #filtered_jobs         fj,
  9201.          msdb.dbo.sysjobservers sjs
  9202.     WHERE (fj.job_id = sjs.job_id)
  9203.   END
  9204.  
  9205.   -- Step 3.4 : Set the type of the job to local (1) or multi-server (2)
  9206.   --            NOTE: If the job has no jobservers then it wil have a type of 0 meaning
  9207.   --                  unknown.  This is marginally inconsistent with the behaviour of
  9208.   --                  defaulting the category of a new job to [Uncategorized (Local)], but
  9209.   --                  prevents incompletely defined jobs from erroneously showing up as valid
  9210.   --                  local jobs.
  9211.   UPDATE #filtered_jobs
  9212.   SET type = 1 -- LOCAL
  9213.   FROM #filtered_jobs         fj,
  9214.        msdb.dbo.sysjobservers sjs
  9215.   WHERE (fj.job_id = sjs.job_id)
  9216.     AND (server_id = 0)
  9217.   UPDATE #filtered_jobs
  9218.   SET type = 2 -- MULTI-SERVER
  9219.   FROM #filtered_jobs         fj,
  9220.        msdb.dbo.sysjobservers sjs
  9221.   WHERE (fj.job_id = sjs.job_id)
  9222.     AND (server_id <> 0)
  9223.  
  9224.   -- Step 4: Filter on job_type
  9225.   IF (@job_type IS NOT NULL)
  9226.   BEGIN
  9227.     IF (UPPER(@job_type) = 'LOCAL')
  9228.       DELETE FROM #filtered_jobs
  9229.       WHERE (type <> 1) -- IE. Delete all the non-local jobs
  9230.     IF (UPPER(@job_type) = 'MULTI-SERVER')
  9231.       DELETE FROM #filtered_jobs
  9232.       WHERE (type <> 2) -- IE. Delete all the non-multi-server jobs
  9233.   END
  9234.  
  9235.   -- Step 5: Filter on dates
  9236.   IF (@date_comparator IS NOT NULL)
  9237.   BEGIN
  9238.     IF (@date_created IS NOT NULL)
  9239.     BEGIN
  9240.       IF (@date_comparator = '=')
  9241.         DELETE FROM #filtered_jobs WHERE (date_created <> @date_created)
  9242.       IF (@date_comparator = '>')
  9243.         DELETE FROM #filtered_jobs WHERE (date_created <= @date_created)
  9244.       IF (@date_comparator = '<')
  9245.         DELETE FROM #filtered_jobs WHERE (date_created >= @date_created)
  9246.     END
  9247.     IF (@date_last_modified IS NOT NULL)
  9248.     BEGIN
  9249.       IF (@date_comparator = '=')
  9250.         DELETE FROM #filtered_jobs WHERE (date_last_modified <> @date_last_modified)
  9251.       IF (@date_comparator = '>')
  9252.         DELETE FROM #filtered_jobs WHERE (date_last_modified <= @date_last_modified)
  9253.       IF (@date_comparator = '<')
  9254.         DELETE FROM #filtered_jobs WHERE (date_last_modified >= @date_last_modified)
  9255.     END
  9256.   END
  9257.  
  9258.   -- Return the result set (NOTE: No filtering occurs here)
  9259.   SELECT sjv.job_id,
  9260.          sjv.originating_server,
  9261.          sjv.name,
  9262.          sjv.enabled,
  9263.          sjv.description,
  9264.          sjv.start_step_id,
  9265.          category = ISNULL(sc.name, FORMATMESSAGE(14205)),
  9266.          owner = SUSER_SNAME(sjv.owner_sid),
  9267.          sjv.notify_level_eventlog,
  9268.          sjv.notify_level_email,
  9269.          sjv.notify_level_netsend,
  9270.          sjv.notify_level_page,
  9271.          notify_email_operator   = ISNULL(so1.name, FORMATMESSAGE(14205)),
  9272.          notify_netsend_operator = ISNULL(so2.name, FORMATMESSAGE(14205)),
  9273.          notify_page_operator    = ISNULL(so3.name, FORMATMESSAGE(14205)),
  9274.          sjv.delete_level,
  9275.          sjv.date_created,
  9276.          sjv.date_modified,
  9277.          sjv.version_number,
  9278.          fj.last_run_date,
  9279.          fj.last_run_time,
  9280.          fj.last_run_outcome,
  9281.          next_run_date = ISNULL(fj.next_run_date, 0),                                 -- This column will be NULL if the job is non-local
  9282.          next_run_time = ISNULL(fj.next_run_time, 0),                                 -- This column will be NULL if the job is non-local
  9283.          next_run_schedule_id = ISNULL(fj.next_run_schedule_id, 0),                   -- This column will be NULL if the job is non-local
  9284.          current_execution_status = ISNULL(fj.current_execution_status, 0),           -- This column will be NULL if the job is non-local
  9285.          current_execution_step = ISNULL(fj.current_execution_step, N'0 ' + FORMATMESSAGE(14205)), -- This column will be NULL if the job is non-local
  9286.          current_retry_attempt = ISNULL(fj.current_retry_attempt, 0),                 -- This column will be NULL if the job is non-local
  9287.          has_step = (SELECT COUNT(*) 
  9288.                      FROM msdb.dbo.sysjobsteps sjst
  9289.                      WHERE (sjst.job_id = sjv.job_id)),
  9290.          has_schedule = (SELECT COUNT(*) 
  9291.                          FROM msdb.dbo.sysjobschedules sjsch 
  9292.                          WHERE (sjsch.job_id = sjv.job_id)),
  9293.          has_target = (SELECT COUNT(*)
  9294.                        FROM msdb.dbo.sysjobservers sjs
  9295.                        WHERE (sjs.job_id = sjv.job_id)),
  9296.          type = fj.type
  9297.   FROM #filtered_jobs                         fj
  9298.        LEFT OUTER JOIN msdb.dbo.sysjobs_view  sjv ON (fj.job_id = sjv.job_id)
  9299.        LEFT OUTER JOIN msdb.dbo.sysoperators  so1 ON (sjv.notify_email_operator_id = so1.id)
  9300.        LEFT OUTER JOIN msdb.dbo.sysoperators  so2 ON (sjv.notify_netsend_operator_id = so2.id)
  9301.        LEFT OUTER JOIN msdb.dbo.sysoperators  so3 ON (sjv.notify_page_operator_id = so3.id)
  9302.        LEFT OUTER JOIN msdb.dbo.syscategories sc  ON (sjv.category_id = sc.category_id)
  9303.   ORDER BY sjv.job_id
  9304.  
  9305.   -- Clean up
  9306.   DROP TABLE #job_execution_state
  9307.   DROP TABLE #filtered_jobs
  9308.   DROP TABLE #xp_results
  9309. END
  9310. go
  9311.  
  9312. /**************************************************************/
  9313. /* SP_HELP_JOB                                                */
  9314. /**************************************************************/
  9315.  
  9316. PRINT ''
  9317. PRINT 'Creating procedure sp_help_job...'
  9318. go
  9319. IF (EXISTS (SELECT *
  9320.             FROM msdb.dbo.sysobjects
  9321.             WHERE (name = N'sp_help_job')
  9322.               AND (type = 'P')))
  9323.   DROP PROCEDURE sp_help_job
  9324. go
  9325. CREATE PROCEDURE sp_help_job
  9326.   -- Individual job parameters
  9327.   @job_id                     UNIQUEIDENTIFIER = NULL,  -- If provided should NOT also provide job_name
  9328.   @job_name                   sysname          = NULL,  -- If provided should NOT also provide job_id
  9329.   @job_aspect                 VARCHAR(9)       = NULL,  -- JOB, STEPS, SCEDULES, TARGETS or ALL
  9330.   -- Job set parameters
  9331.   @job_type                   VARCHAR(12)      = NULL,  -- LOCAL or MULTI-SERVER
  9332.   @owner_login_name           sysname          = NULL,
  9333.   @subsystem                  NVARCHAR(40)     = NULL,
  9334.   @category_name              sysname          = NULL,
  9335.   @enabled                    TINYINT          = NULL,
  9336.   @execution_status           INT              = NULL,  -- 1 = Executing, 2 = Waiting For Thread, 3 = Between Retries, 4 = Idle, 5 = Suspended, 6 = [obsolete], 7 = PerformingCompletionActions
  9337.   @date_comparator            CHAR(1)          = NULL,  -- >, < or =
  9338.   @date_created               DATETIME         = NULL,
  9339.   @date_last_modified         DATETIME         = NULL,
  9340.   @description                NVARCHAR(512)    = NULL   -- We do a LIKE on this so it can include wildcards
  9341. AS
  9342. BEGIN
  9343.   DECLARE @retval          INT
  9344.   DECLARE @category_id     INT
  9345.   DECLARE @job_id_as_char  VARCHAR(36)
  9346.   DECLARE @res_valid_range NVARCHAR(200)
  9347.  
  9348.   SET NOCOUNT ON
  9349.  
  9350.   -- Remove any leading/trailing spaces from parameters (except @owner_login_name)
  9351.   SELECT @job_name         = LTRIM(RTRIM(@job_name))
  9352.   SELECT @job_aspect       = LTRIM(RTRIM(@job_aspect))
  9353.   SELECT @job_type         = LTRIM(RTRIM(@job_type))
  9354.   SELECT @subsystem        = LTRIM(RTRIM(@subsystem))
  9355.   SELECT @category_name    = LTRIM(RTRIM(@category_name))
  9356.   SELECT @description      = LTRIM(RTRIM(@description))
  9357.  
  9358.   -- Turn [nullable] empty string parameters into NULLs
  9359.   IF (@job_name         = N'') SELECT @job_name = NULL
  9360.   IF (@job_aspect       = '')  SELECT @job_aspect = NULL
  9361.   IF (@job_type         = '')  SELECT @job_type = NULL
  9362.   IF (@owner_login_name = N'') SELECT @owner_login_name = NULL
  9363.   IF (@subsystem        = N'') SELECT @subsystem = NULL
  9364.   IF (@category_name    = N'') SELECT @category_name = NULL
  9365.   IF (@description      = N'') SELECT @description = NULL
  9366.  
  9367.   IF ((@job_id IS NOT NULL) OR (@job_name IS NOT NULL))
  9368.   BEGIN
  9369.     EXECUTE @retval = sp_verify_job_identifiers '@job_name',
  9370.                                                 '@job_id',
  9371.                                                  @job_name OUTPUT,
  9372.                                                  @job_id   OUTPUT
  9373.     IF (@retval <> 0)
  9374.       RETURN(1) -- Failure
  9375.   END
  9376.  
  9377.   SELECT @job_id_as_char = CONVERT(VARCHAR(36), @job_id)
  9378.  
  9379.   -- If the user provided a job name or id but no aspect, default to ALL
  9380.   IF ((@job_name IS NOT NULL) OR (@job_id IS NOT NULL)) AND (@job_aspect IS NULL)
  9381.     SELECT @job_aspect = 'ALL'
  9382.  
  9383.   -- The caller must supply EITHER job name (or job id) and aspect OR one-or-more of the set
  9384.   -- parameters OR no parameters at all
  9385.   IF (((@job_name IS NOT NULL) OR (@job_id IS NOT NULL))
  9386.       AND ((@job_aspect          IS NULL)     OR
  9387.            (@job_type            IS NOT NULL) OR
  9388.            (@owner_login_name    IS NOT NULL) OR
  9389.            (@subsystem           IS NOT NULL) OR
  9390.            (@category_name       IS NOT NULL) OR
  9391.            (@enabled             IS NOT NULL) OR
  9392.            (@date_comparator     IS NOT NULL) OR
  9393.            (@date_created        IS NOT NULL) OR
  9394.            (@date_last_modified  IS NOT NULL)))
  9395.      OR
  9396.      ((@job_name IS NULL) AND (@job_id IS NULL) AND (@job_aspect IS NOT NULL))
  9397.   BEGIN
  9398.     RAISERROR(14280, -1, -1)
  9399.     RETURN(1) -- Failure
  9400.   END
  9401.  
  9402.   IF (@job_id IS NOT NULL)
  9403.   BEGIN
  9404.     -- Individual job...
  9405.  
  9406.     -- Check job aspect
  9407.     SELECT @job_aspect = UPPER(@job_aspect)
  9408.     IF (@job_aspect NOT IN ('JOB', 'STEPS', 'SCHEDULES', 'TARGETS', 'ALL'))
  9409.     BEGIN
  9410.       RAISERROR(14266, -1, -1, '@job_aspect', 'JOB, STEPS, SCHEDULES, TARGETS, ALL')
  9411.       RETURN(1) -- Failure
  9412.     END
  9413.  
  9414.     -- Generate results set...
  9415.  
  9416.     IF (@job_aspect IN ('JOB', 'ALL'))
  9417.     BEGIN
  9418.       IF (@job_aspect = 'ALL')
  9419.       BEGIN
  9420.         RAISERROR(14213, 0, 1)
  9421.         PRINT REPLICATE('=', DATALENGTH(FORMATMESSAGE(14213)) / 2)
  9422.       END
  9423.       EXECUTE sp_get_composite_job_info @job_id,
  9424.                                         @job_type,
  9425.                                         @owner_login_name,
  9426.                                         @subsystem,
  9427.                                         @category_id,
  9428.                                         @enabled,
  9429.                                         @execution_status,
  9430.                                         @date_comparator,
  9431.                                         @date_created,
  9432.                                         @date_last_modified,
  9433.                                         @description
  9434.     END
  9435.  
  9436.     IF (@job_aspect IN ('STEPS', 'ALL'))
  9437.     BEGIN
  9438.       IF (@job_aspect = 'ALL')
  9439.       BEGIN
  9440.         PRINT ''
  9441.         RAISERROR(14214, 0, 1)
  9442.         PRINT REPLICATE('=', DATALENGTH(FORMATMESSAGE(14214)) / 2)
  9443.       END
  9444.       EXECUTE ('EXECUTE sp_help_jobstep @job_id = ''' + @job_id_as_char + ''', @suffix = 1')
  9445.     END
  9446.  
  9447.     IF (@job_aspect IN ('SCHEDULES', 'ALL'))
  9448.     BEGIN
  9449.       IF (@job_aspect = 'ALL')
  9450.       BEGIN
  9451.         PRINT ''
  9452.         RAISERROR(14215, 0, 1)
  9453.         PRINT REPLICATE('=', DATALENGTH(FORMATMESSAGE(14215)) / 2)
  9454.       END
  9455.       EXECUTE ('EXECUTE sp_help_jobschedule @job_id = ''' + @job_id_as_char + '''')
  9456.     END
  9457.  
  9458.     IF (@job_aspect IN ('TARGETS', 'ALL'))
  9459.     BEGIN
  9460.       IF (@job_aspect = 'ALL')
  9461.       BEGIN
  9462.         PRINT ''
  9463.         RAISERROR(14216, 0, 1)
  9464.         PRINT REPLICATE('=', DATALENGTH(FORMATMESSAGE(14216)) / 2)
  9465.       END
  9466.       EXECUTE ('EXECUTE sp_help_jobserver @job_id = ''' + @job_id_as_char + ''', @show_last_run_details = 1')
  9467.     END
  9468.   END
  9469.   ELSE
  9470.   BEGIN
  9471.     -- Set of jobs...
  9472.  
  9473.     -- Check job type
  9474.     IF (@job_type IS NOT NULL)
  9475.     BEGIN
  9476.       SELECT @job_type = UPPER(@job_type)
  9477.       IF (@job_type NOT IN ('LOCAL', 'MULTI-SERVER'))
  9478.       BEGIN
  9479.         RAISERROR(14266, -1, -1, '@job_type', 'LOCAL, MULTI-SERVER')
  9480.         RETURN(1) -- Failure
  9481.       END
  9482.     END
  9483.  
  9484.     -- Check owner
  9485.     IF (@owner_login_name IS NOT NULL)
  9486.     BEGIN
  9487.       IF (SUSER_SID(@owner_login_name) IS NULL)
  9488.       BEGIN
  9489.         RAISERROR(14262, -1, -1, '@owner_login_name', @owner_login_name)
  9490.         RETURN(1) -- Failure
  9491.       END
  9492.     END
  9493.  
  9494.     -- Check subsystem
  9495.     IF (@subsystem IS NOT NULL)
  9496.     BEGIN
  9497.       EXECUTE @retval = sp_verify_subsystem @subsystem
  9498.       IF (@retval <> 0)
  9499.         RETURN(1) -- Failure
  9500.     END
  9501.  
  9502.     -- Check job category
  9503.     IF (@category_name IS NOT NULL)
  9504.     BEGIN
  9505.       SELECT @category_id = category_id
  9506.       FROM msdb.dbo.syscategories
  9507.       WHERE (category_class = 1) -- Job
  9508.         AND (name = @category_name)
  9509.       IF (@category_id IS NULL)
  9510.       BEGIN
  9511.         RAISERROR(14262, -1, -1, '@category_name', @category_name)
  9512.         RETURN(1) -- Failure
  9513.       END
  9514.     END
  9515.  
  9516.     -- Check enabled state
  9517.     IF (@enabled IS NOT NULL) AND (@enabled NOT IN (0, 1))
  9518.     BEGIN
  9519.       RAISERROR(14266, -1, -1, '@enabled', '0, 1')
  9520.       RETURN(1) -- Failure
  9521.     END
  9522.  
  9523.     -- Check current execution status
  9524.     IF (@execution_status IS NOT NULL)
  9525.     BEGIN
  9526.       IF (@execution_status NOT IN (0, 1, 2, 3, 4, 5, 7))
  9527.       BEGIN
  9528.         SELECT @res_valid_range = FORMATMESSAGE(14204)
  9529.         RAISERROR(14266, -1, -1, '@execution_status', @res_valid_range)
  9530.         RETURN(1) -- Failure
  9531.       END
  9532.     END
  9533.  
  9534.     -- If a date comparator is supplied, we must have either a date-created or date-last-modified
  9535.     IF ((@date_comparator IS NOT NULL) AND (@date_created IS NOT NULL) AND (@date_last_modified IS NOT NULL)) OR
  9536.        ((@date_comparator IS NULL)     AND ((@date_created IS NOT NULL) OR (@date_last_modified IS NOT NULL)))
  9537.     BEGIN
  9538.       RAISERROR(14282, -1, -1)
  9539.       RETURN(1) -- Failure
  9540.     END
  9541.  
  9542.     -- Check dates / comparator
  9543.     IF (@date_comparator IS NOT NULL) AND (@date_comparator NOT IN ('=', '<', '>'))
  9544.     BEGIN
  9545.       RAISERROR(14266, -1, -1, '@date_comparator', '=, >, <')
  9546.       RETURN(1) -- Failure
  9547.     END
  9548.     IF (@date_created IS NOT NULL) AND
  9549.        ((@date_created < '1 Jan 1990 12:00:00am') OR (@date_created > '31 Dec 9999 11:59:59pm'))
  9550.     BEGIN
  9551.       RAISERROR(14266, -1, -1, '@date_created', '1/1/1990 12:00am .. 12/31/9999 11:59pm')
  9552.       RETURN(1) -- Failure
  9553.     END
  9554.     IF (@date_last_modified IS NOT NULL) AND
  9555.        ((@date_last_modified < '1 Jan 1990 12:00am') OR (@date_last_modified > 'Dec 31 9999 11:59:59pm'))
  9556.     BEGIN
  9557.       RAISERROR(14266, -1, -1, '@date_last_modified', '1/1/1990 12:00am .. 12/31/9999 11:59pm')
  9558.       RETURN(1) -- Failure
  9559.     END
  9560.  
  9561.     -- Generate results set...
  9562.     EXECUTE sp_get_composite_job_info @job_id,
  9563.                                       @job_type,
  9564.                                       @owner_login_name,
  9565.                                       @subsystem,
  9566.                                       @category_id,
  9567.                                       @enabled,
  9568.                                       @execution_status,
  9569.                                       @date_comparator,
  9570.                                       @date_created,
  9571.                                       @date_last_modified,
  9572.                                       @description
  9573.   END
  9574.  
  9575.   RETURN(0) -- Success
  9576. END
  9577. go
  9578.  
  9579. DUMP TRANSACTION msdb WITH NO_LOG
  9580. go
  9581. CHECKPOINT
  9582. go
  9583.  
  9584. /**************************************************************/
  9585. /* SP_MANAGE_JOBS_BY_LOGIN                                    */
  9586. /**************************************************************/
  9587.  
  9588. PRINT ''
  9589. PRINT 'Creating procedure sp_manage_jobs_by_login...'
  9590. go
  9591. IF (EXISTS (SELECT *
  9592.             FROM msdb.dbo.sysobjects
  9593.             WHERE (name = N'sp_manage_jobs_by_login')
  9594.               AND (type = 'P')))
  9595.   DROP PROCEDURE sp_manage_jobs_by_login
  9596. go
  9597. CREATE PROCEDURE sp_manage_jobs_by_login
  9598.   @action                   VARCHAR(10), -- DELETE or REASSIGN
  9599.   @current_owner_login_name sysname,
  9600.   @new_owner_login_name     sysname = NULL
  9601. AS
  9602. BEGIN
  9603.   DECLARE @current_sid   VARBINARY(85)
  9604.   DECLARE @new_sid       VARBINARY(85)
  9605.   DECLARE @job_id        UNIQUEIDENTIFIER
  9606.   DECLARE @rows_affected INT
  9607.   DECLARE @is_sysadmin   INT
  9608.  
  9609.   SET NOCOUNT ON
  9610.  
  9611.   -- Remove any leading/trailing spaces from parameters
  9612.   SELECT @action                   = LTRIM(RTRIM(@action))
  9613.   SELECT @current_owner_login_name = LTRIM(RTRIM(@current_owner_login_name))
  9614.   SELECT @new_owner_login_name     = LTRIM(RTRIM(@new_owner_login_name))
  9615.  
  9616.   -- Turn [nullable] empty string parameters into NULLs
  9617.   IF (@new_owner_login_name = N'') SELECT @new_owner_login_name = NULL
  9618.  
  9619.   -- Only a sysadmin can do this
  9620.   IF (ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) <> 1)
  9621.   BEGIN
  9622.     RAISERROR(15003, 16, 1, N'sysadmin')
  9623.     RETURN(1) -- Failure
  9624.   END
  9625.  
  9626.   -- Check action
  9627.   IF (@action NOT IN ('DELETE', 'REASSIGN'))
  9628.   BEGIN
  9629.     RAISERROR(14266, -1, -1, '@action', 'DELETE, REASSIGN')
  9630.     RETURN(1) -- Failure
  9631.   END
  9632.  
  9633.   -- Check parameter combinations
  9634.   IF ((@action = 'DELETE') AND (@new_owner_login_name IS NOT NULL))
  9635.     RAISERROR(14281, 0, 1)
  9636.  
  9637.   IF ((@action = 'REASSIGN') AND (@new_owner_login_name IS NULL))
  9638.   BEGIN
  9639.     RAISERROR(14237, -1, -1)
  9640.     RETURN(1) -- Failure
  9641.   END
  9642.  
  9643.   -- Check current login
  9644.   SELECT @current_sid = SUSER_SID(@current_owner_login_name)
  9645.   IF (@current_sid IS NULL)
  9646.   BEGIN
  9647.     RAISERROR(14262, -1, -1, '@current_owner_login_name', @current_owner_login_name)
  9648.     RETURN(1) -- Failure
  9649.   END
  9650.  
  9651.   -- Check new login (if supplied)
  9652.   IF (@new_owner_login_name IS NOT NULL)
  9653.   BEGIN
  9654.     SELECT @new_sid = SUSER_SID(@new_owner_login_name)
  9655.     IF (@new_sid IS NULL)
  9656.     BEGIN
  9657.       RAISERROR(14262, -1, -1, '@new_owner_login_name', @new_owner_login_name)
  9658.       RETURN(1) -- Failure
  9659.     END
  9660.   END
  9661.  
  9662.   IF (@action = 'DELETE')
  9663.   BEGIN
  9664.     DECLARE jobs_to_delete CURSOR LOCAL
  9665.     FOR 
  9666.     SELECT job_id
  9667.     FROM msdb.dbo.sysjobs
  9668.     WHERE (owner_sid = @current_sid)
  9669.  
  9670.     OPEN jobs_to_delete
  9671.     FETCH NEXT FROM jobs_to_delete INTO @job_id
  9672.  
  9673.     SELECT @rows_affected = 0
  9674.     WHILE (@@fetch_status = 0)
  9675.     BEGIN
  9676.       EXECUTE sp_delete_job @job_id = @job_id
  9677.       SELECT @rows_affected = @rows_affected + 1
  9678.       FETCH NEXT FROM jobs_to_delete INTO @job_id
  9679.     END
  9680.     DEALLOCATE jobs_to_delete
  9681.     RAISERROR(14238, 0, 1, @rows_affected)
  9682.   END
  9683.   ELSE
  9684.   IF (@action = 'REASSIGN')
  9685.   BEGIN
  9686.     -- Check if the current owner owns any multi-server jobs.  
  9687.     -- If they do, then the new owner must be member of the sysadmin role.
  9688.     IF (EXISTS (SELECT *
  9689.                 FROM msdb.dbo.sysjobs       sj,
  9690.                      msdb.dbo.sysjobservers sjs
  9691.                 WHERE (sj.job_id = sjs.job_id)
  9692.                   AND (sj.owner_sid = @current_sid)
  9693.                   AND (sjs.server_id <> 0)))
  9694.     BEGIN
  9695.       SELECT @is_sysadmin = 0
  9696.       EXECUTE msdb.dbo.sp_sqlagent_has_server_access @login_name = @new_owner_login_name, @is_sysadmin_member = @is_sysadmin OUTPUT
  9697.       IF (@is_sysadmin = 0)
  9698.       BEGIN
  9699.         RAISERROR(14543, -1, -1, @current_owner_login_name, N'sysadmin')
  9700.         RETURN(1) -- Failure
  9701.       END
  9702.     END
  9703.  
  9704.     UPDATE msdb.dbo.sysjobs
  9705.     SET owner_sid = @new_sid
  9706.     WHERE (owner_sid = @current_sid)
  9707.     RAISERROR(14239, 0, 1, @@rowcount, @new_owner_login_name)
  9708.   END
  9709.  
  9710.   RETURN(0) -- Success
  9711. END
  9712. go
  9713.  
  9714. /**************************************************************/
  9715. /* SP_APPLY_JOB_TO_TARGETS                                    */
  9716. /**************************************************************/
  9717.  
  9718. PRINT ''
  9719. PRINT 'Creating procedure sp_apply_job_to_targets...'
  9720. go
  9721. IF (EXISTS (SELECT *
  9722.             FROM msdb.dbo.sysobjects
  9723.             WHERE (name = N'sp_apply_job_to_targets')
  9724.               AND (type = 'P')))
  9725.   DROP PROCEDURE sp_apply_job_to_targets
  9726. go
  9727. CREATE PROCEDURE sp_apply_job_to_targets
  9728.   @job_id               UNIQUEIDENTIFIER = NULL,   -- Must provide either this or job_name
  9729.   @job_name             sysname          = NULL,   -- Must provide either this or job_id
  9730.   @target_server_groups NVARCHAR(2048)   = NULL,   -- A comma-separated list of target server groups
  9731.   @target_servers       NVARCHAR(2048)   = NULL,   -- An comma-separated list of target servers
  9732.   @operation            VARCHAR(7)       = 'APPLY' -- Or 'REMOVE'
  9733. AS
  9734. BEGIN
  9735.   DECLARE @retval        INT
  9736.   DECLARE @rows_affected INT
  9737.   DECLARE @server_name   NVARCHAR(30)
  9738.   DECLARE @groups        NVARCHAR(2048)
  9739.   DECLARE @group         sysname
  9740.   DECLARE @servers       NVARCHAR(2048)
  9741.   DECLARE @server        NVARCHAR(30)
  9742.   DECLARE @pos_of_comma  INT
  9743.  
  9744.   SET NOCOUNT ON
  9745.  
  9746.   -- Only a sysadmin can do this
  9747.   IF (ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) <> 1)
  9748.   BEGIN
  9749.     RAISERROR(15003, 16, 1, N'sysadmin')
  9750.     RETURN(1) -- Failure
  9751.   END
  9752.  
  9753.   -- Remove any leading/trailing spaces from parameters
  9754.   SELECT @target_server_groups = LTRIM(RTRIM(@target_server_groups))
  9755.   SELECT @target_servers       = LTRIM(RTRIM(@target_servers))
  9756.   SELECT @operation            = LTRIM(RTRIM(@operation))
  9757.  
  9758.   -- Turn [nullable] empty string parameters into NULLs
  9759.   IF (@target_server_groups = NULL) SELECT @target_server_groups = NULL
  9760.   IF (@target_servers       = NULL) SELECT @target_servers = NULL
  9761.   IF (@operation            = NULL) SELECT @operation = NULL
  9762.  
  9763.   EXECUTE @retval = sp_verify_job_identifiers '@job_name',
  9764.                                               '@job_id',
  9765.                                                @job_name OUTPUT,
  9766.                                                @job_id   OUTPUT
  9767.   IF (@retval <> 0)
  9768.     RETURN(1) -- Failure
  9769.  
  9770.   -- Check operation type
  9771.   IF ((@operation <> 'APPLY') AND (@operation <> 'REMOVE'))
  9772.   BEGIN
  9773.     RAISERROR(14266, -1, -1, '@operation', 'APPLY, REMOVE')
  9774.     RETURN(1) -- Failure
  9775.   END
  9776.  
  9777.   CREATE TABLE #temp_groups (group_name sysname NOT NULL)
  9778.   CREATE TABLE #temp_server_name (server_name NVARCHAR(30) NOT NULL)
  9779.  
  9780.   -- Check that we have a target server group list and/or a target server list
  9781.   IF ((@target_server_groups IS NULL) AND (@target_servers IS NULL))
  9782.   BEGIN
  9783.     RAISERROR(14283, -1, -1)
  9784.     RETURN(1) -- Failure
  9785.   END
  9786.  
  9787.   -- Parse the Target Server comma-separated list (if supplied)
  9788.   IF (@target_servers IS NOT NULL)
  9789.   BEGIN
  9790.     SELECT @servers = @target_servers
  9791.     SELECT @pos_of_comma = CHARINDEX(N',', @servers)
  9792.     WHILE (@pos_of_comma <> 0)
  9793.     BEGIN
  9794.       SELECT @server = SUBSTRING(@servers, 1, @pos_of_comma - 1)
  9795.       INSERT INTO #temp_server_name (server_name) VALUES (LTRIM(RTRIM(@server)))
  9796.       SELECT @servers = RIGHT(@servers, (DATALENGTH(@servers) / 2) - @pos_of_comma)
  9797.       SELECT @pos_of_comma = CHARINDEX(N',', @servers)
  9798.     END
  9799.     INSERT INTO #temp_server_name (server_name) VALUES (LTRIM(RTRIM(@servers)))
  9800.   END
  9801.  
  9802.   -- Parse the Target Server Groups comma-separated list
  9803.   IF (@target_server_groups IS NOT NULL)
  9804.   BEGIN
  9805.     SELECT @groups = @target_server_groups
  9806.     SELECT @pos_of_comma = CHARINDEX(N',', @groups)
  9807.     WHILE (@pos_of_comma <> 0)
  9808.     BEGIN
  9809.       SELECT @group = SUBSTRING(@groups, 1, @pos_of_comma - 1)
  9810.       INSERT INTO #temp_groups (group_name) VALUES (LTRIM(RTRIM(@group)))
  9811.       SELECT @groups = RIGHT(@groups, (DATALENGTH(@groups) / 2) - @pos_of_comma)
  9812.       SELECT @pos_of_comma = CHARINDEX(N',', @groups)
  9813.     END
  9814.     INSERT INTO #temp_groups (group_name) VALUES (LTRIM(RTRIM(@groups)))
  9815.   END
  9816.  
  9817.   -- Check server groups
  9818.   SET ROWCOUNT 1 -- We do this so that we catch the FIRST invalid group
  9819.   SELECT @group = NULL
  9820.   SELECT @group = group_name
  9821.   FROM #temp_groups
  9822.   WHERE group_name NOT IN (SELECT name
  9823.                            FROM msdb.dbo.systargetservergroups)
  9824.   IF (@group IS NOT NULL)
  9825.   BEGIN
  9826.     RAISERROR(14262, -1, -1, '@target_server_groups', @group)
  9827.     RETURN(1) -- Failure
  9828.   END
  9829.   SET ROWCOUNT 0
  9830.  
  9831.   -- Find the distinct list of servers being targeted
  9832.   INSERT INTO #temp_server_name (server_name)
  9833.   SELECT DISTINCT sts.server_name
  9834.   FROM msdb.dbo.systargetservergroups       stsg,
  9835.        msdb.dbo.systargetservergroupmembers stsgm,
  9836.        msdb.dbo.systargetservers            sts
  9837.   WHERE (stsg.name IN (SELECT group_name FROM #temp_groups))
  9838.     AND (stsg.servergroup_id = stsgm.servergroup_id)
  9839.     AND (stsgm.server_id = sts.server_id)
  9840.     AND (sts.server_name NOT IN (SELECT server_name
  9841.                                  FROM #temp_server_name))
  9842.  
  9843.   IF (@operation = 'APPLY')
  9844.   BEGIN
  9845.     -- Remove those servers to which the job has already been applied
  9846.     DELETE FROM #temp_server_name
  9847.     WHERE server_name IN (SELECT sts.server_name
  9848.                           FROM msdb.dbo.sysjobservers    sjs,
  9849.                                msdb.dbo.systargetservers sts
  9850.                           WHERE (sjs.job_id = @job_id)
  9851.                             AND (sjs.server_id = sts.server_id))
  9852.   END
  9853.  
  9854.   IF (@operation = 'REMOVE')
  9855.   BEGIN
  9856.     -- Remove those servers to which the job is not currently applied
  9857.     DELETE FROM #temp_server_name
  9858.     WHERE server_name NOT IN (SELECT sts.server_name
  9859.                               FROM msdb.dbo.sysjobservers    sjs,
  9860.                                    msdb.dbo.systargetservers sts
  9861.                               WHERE (sjs.job_id = @job_id)
  9862.                                 AND (sjs.server_id = sts.server_id))
  9863.   END
  9864.  
  9865.   SELECT @rows_affected = COUNT(*)
  9866.   FROM #temp_server_name
  9867.  
  9868.   SET ROWCOUNT 1
  9869.   WHILE (EXISTS (SELECT *
  9870.                  FROM #temp_server_name))
  9871.   BEGIN
  9872.     SELECT @server_name = server_name
  9873.     FROM #temp_server_name
  9874.     IF (@operation = 'APPLY')
  9875.       EXECUTE sp_add_jobserver @job_id = @job_id, @server_name = @server_name
  9876.     ELSE
  9877.     IF (@operation = 'REMOVE')
  9878.       EXECUTE sp_delete_jobserver @job_id = @job_id, @server_name = @server_name
  9879.     DELETE FROM #temp_server_name
  9880.     WHERE (server_name = @server_name)
  9881.   END
  9882.   SET ROWCOUNT 0
  9883.  
  9884.   IF (@operation = 'APPLY')
  9885.     RAISERROR(14240, 0, 1, @rows_affected)
  9886.   IF (@operation = 'REMOVE')
  9887.     RAISERROR(14241, 0, 1, @rows_affected)
  9888.  
  9889.   RETURN(0) -- Success
  9890. END
  9891. go
  9892.  
  9893. /**************************************************************/
  9894. /* SP_REMOVE_JOB_FROM_TARGETS                                 */
  9895. /**************************************************************/
  9896.  
  9897. PRINT ''
  9898. PRINT 'Creating procedure sp_remove_job_from_targets...'
  9899. go
  9900. IF (EXISTS (SELECT *
  9901.             FROM msdb.dbo.sysobjects
  9902.             WHERE (name = N'sp_remove_job_from_targets')
  9903.               AND (type = 'P')))
  9904.   DROP PROCEDURE sp_remove_job_from_targets
  9905. go
  9906. CREATE PROCEDURE sp_remove_job_from_targets
  9907.   @job_id               UNIQUEIDENTIFIER = NULL,   -- Must provide either this or job_name
  9908.   @job_name             sysname          = NULL,   -- Must provide either this or job_id
  9909.   @target_server_groups NVARCHAR(1024)   = NULL,   -- A comma-separated list of target server groups
  9910.   @target_servers       NVARCHAR(1024)   = NULL    -- A comma-separated list of target servers
  9911. AS
  9912. BEGIN
  9913.   DECLARE @retval INT
  9914.  
  9915.   SET NOCOUNT ON
  9916.  
  9917.   EXECUTE @retval = sp_apply_job_to_targets @job_id,
  9918.                                             @job_name,
  9919.                                             @target_server_groups,
  9920.                                             @target_servers,
  9921.                                            'REMOVE'
  9922.   RETURN(@retval) -- 0 means success
  9923. END
  9924. go
  9925.  
  9926. /**************************************************************/
  9927. /* SP_GET_JOB_ALERTS                                          */
  9928. /**************************************************************/
  9929.  
  9930. PRINT ''
  9931. PRINT 'Creating procedure sp_get_job_alerts...'
  9932. go
  9933. IF (EXISTS (SELECT *
  9934.             FROM msdb.dbo.sysobjects
  9935.             WHERE (name = N'sp_get_job_alerts')
  9936.               AND (type = 'P')))
  9937.   DROP PROCEDURE sp_get_job_alerts
  9938. go
  9939. CREATE PROCEDURE sp_get_job_alerts 
  9940.   @job_id   UNIQUEIDENTIFIER = NULL,
  9941.   @job_name sysname          = NULL
  9942. AS
  9943. BEGIN
  9944.   DECLARE @retval INT
  9945.  
  9946.   EXECUTE @retval = sp_verify_job_identifiers '@job_name',
  9947.                                               '@job_id',
  9948.                                                @job_name OUTPUT,
  9949.                                                @job_id   OUTPUT
  9950.   IF (@retval <> 0)
  9951.     RETURN(1) -- Failure
  9952.  
  9953.   SELECT id,
  9954.          name, 
  9955.          enabled, 
  9956.          type = CASE ISNULL(performance_condition, N'!')
  9957.                   WHEN N'!' THEN
  9958.                     CASE event_source 
  9959.                       WHEN N'MSSQLServer' THEN 1 -- SQL Server event alert
  9960.                       ELSE 3                     -- Non SQL Server event alert
  9961.                     END
  9962.                   ELSE 2                         -- SQL Server performance condition alert
  9963.                 END
  9964.   FROM msdb.dbo.sysalerts
  9965.   WHERE (job_id = @job_id)
  9966.  
  9967.   RETURN(0) -- Success
  9968. END
  9969. go
  9970.  
  9971. /**************************************************************/
  9972. /*                                                            */
  9973. /*   S  U  P  P  O  R  T     P  R  O  C  E  D  U  R  E  S     */
  9974. /*                                                            */
  9975. /**************************************************************/
  9976.  
  9977. /**************************************************************/
  9978. /* SP_CONVERT_JOBID_TO_CHAR [used by SEM only]                */
  9979. /**************************************************************/
  9980.  
  9981. PRINT ''
  9982. PRINT 'Creating procedure sp_convert_jobid_to_char...'
  9983. go
  9984. IF (EXISTS (SELECT *
  9985.             FROM msdb.dbo.sysobjects
  9986.             WHERE (name = N'sp_convert_jobid_to_char')
  9987.               AND (type = 'P')))
  9988.   DROP PROCEDURE sp_convert_jobid_to_char
  9989. go
  9990. CREATE PROCEDURE sp_convert_jobid_to_char
  9991.   @job_id         UNIQUEIDENTIFIER,
  9992.   @job_id_as_char NVARCHAR(34) OUTPUT -- 34 because of the leading '0x'
  9993. AS
  9994. BEGIN
  9995.   DECLARE @job_id_as_binary BINARY(16)
  9996.   DECLARE @temp             NCHAR(8)
  9997.   DECLARE @counter          INT
  9998.   DECLARE @byte_value       INT
  9999.   DECLARE @high_word        INT
  10000.   DECLARE @low_word         INT
  10001.   DECLARE @high_high_nybble INT
  10002.   DECLARE @high_low_nybble  INT
  10003.   DECLARE @low_high_nybble  INT
  10004.   DECLARE @low_low_nybble   INT
  10005.  
  10006.   SET NOCOUNT ON
  10007.  
  10008.   SELECT @job_id_as_binary = CONVERT(BINARY(16), @job_id)
  10009.   SELECT @temp = CONVERT(NCHAR(8), @job_id_as_binary)
  10010.  
  10011.   SELECT @job_id_as_char = N''
  10012.   SELECT @counter = 1
  10013.  
  10014.   WHILE (@counter <= (DATALENGTH(@temp) / 2))
  10015.   BEGIN
  10016.     SELECT @byte_value       = CONVERT(INT, CONVERT(BINARY(2), SUBSTRING(@temp, @counter, 1)))
  10017.     SELECT @high_word        = (@byte_value & 0xff00) / 0x100
  10018.     SELECT @low_word         = (@byte_value & 0x00ff)
  10019.     SELECT @high_high_nybble = (@high_word & 0xff) / 16
  10020.     SELECT @high_low_nybble  = (@high_word & 0xff) % 16
  10021.     SELECT @low_high_nybble  = (@low_word & 0xff) / 16
  10022.     SELECT @low_low_nybble   = (@low_word & 0xff) % 16
  10023.  
  10024.     IF (@high_high_nybble < 10)
  10025.       SELECT @job_id_as_char = @job_id_as_char + NCHAR(ASCII('0') + @high_high_nybble)
  10026.     ELSE
  10027.       SELECT @job_id_as_char = @job_id_as_char + NCHAR(ASCII('A') + (@high_high_nybble - 10))
  10028.  
  10029.     IF (@high_low_nybble < 10)
  10030.       SELECT @job_id_as_char = @job_id_as_char + NCHAR(ASCII('0') + @high_low_nybble)
  10031.     ELSE
  10032.       SELECT @job_id_as_char = @job_id_as_char + NCHAR(ASCII('A') + (@high_low_nybble - 10))
  10033.  
  10034.     IF (@low_high_nybble < 10)
  10035.       SELECT @job_id_as_char = @job_id_as_char + NCHAR(ASCII('0') + @low_high_nybble)
  10036.     ELSE
  10037.       SELECT @job_id_as_char = @job_id_as_char + NCHAR(ASCII('A') + (@low_high_nybble - 10))
  10038.  
  10039.     IF (@low_low_nybble < 10)
  10040.       SELECT @job_id_as_char = @job_id_as_char + NCHAR(ASCII('0') + @low_low_nybble)
  10041.     ELSE
  10042.       SELECT @job_id_as_char = @job_id_as_char + NCHAR(ASCII('A') + (@low_low_nybble - 10))
  10043.  
  10044.     SELECT @counter = @counter + 1
  10045.   END
  10046.  
  10047.   SELECT @job_id_as_char = N'0x' + LOWER(@job_id_as_char)
  10048. END
  10049. go
  10050.  
  10051. /**************************************************************/
  10052. /* SP_START_JOB                                               */
  10053. /**************************************************************/
  10054.  
  10055. PRINT ''
  10056. PRINT 'Creating procedure sp_start_job...'
  10057. go
  10058. IF (EXISTS (SELECT *
  10059.             FROM msdb.dbo.sysobjects
  10060.             WHERE (name = N'sp_start_job')
  10061.               AND (type = 'P')))
  10062.   DROP PROCEDURE sp_start_job
  10063. go
  10064. CREATE PROCEDURE sp_start_job
  10065.   @job_name    sysname          = NULL,
  10066.   @job_id      UNIQUEIDENTIFIER = NULL,
  10067.   @error_flag  INT              = 1,    -- Set to 0 to suppress the error from sp_sqlagent_notify if SQLServerAgent is not running
  10068.   @server_name NVARCHAR(30)     = NULL, -- The specific target server to start the [multi-server] job on
  10069.   @step_name   sysname          = NULL, -- The name of the job step to start execution with [for use with a local job only] 
  10070.   @output_flag INT              = 1     -- Set to 0 to suppress the success message
  10071. AS
  10072. BEGIN
  10073.   DECLARE @job_id_as_char VARCHAR(36)
  10074.   DECLARE @retval         INT
  10075.   DECLARE @step_id        INT
  10076.  
  10077.   SET NOCOUNT ON
  10078.  
  10079.   -- Remove any leading/trailing spaces from parameters
  10080.   SELECT @job_name    = LTRIM(RTRIM(@job_name))
  10081.   SELECT @server_name = LTRIM(RTRIM(@server_name))
  10082.   SELECT @step_name   = LTRIM(RTRIM(@step_name))
  10083.  
  10084.   -- Turn [nullable] empty string parameters into NULLs
  10085.   IF (@job_name = N'')    SELECT @job_name = NULL
  10086.   IF (@server_name = N'') SELECT @server_name = NULL
  10087.   IF (@step_name = N'')   SELECT @step_name = NULL
  10088.  
  10089.   EXECUTE @retval = sp_verify_job_identifiers '@job_name',
  10090.                                               '@job_id',
  10091.                                                @job_name OUTPUT,
  10092.                                                @job_id   OUTPUT
  10093.   IF (@retval <> 0)
  10094.     RETURN(1) -- Failure
  10095.  
  10096.   IF (NOT EXISTS (SELECT *
  10097.                   FROM msdb.dbo.sysjobservers
  10098.                   WHERE (job_id = @job_id)))
  10099.   BEGIN
  10100.     SELECT @job_id_as_char = CONVERT(VARCHAR(36), @job_id)
  10101.     RAISERROR(14256, -1, -1, @job_name, @job_id_as_char)
  10102.     RETURN(1) -- Failure
  10103.   END
  10104.  
  10105.   IF (EXISTS (SELECT *
  10106.               FROM msdb.dbo.sysjobservers
  10107.               WHERE (job_id = @job_id)
  10108.                 AND (server_id = 0)))
  10109.   BEGIN
  10110.     -- The job is local, so start (run) the job locally
  10111.  
  10112.     -- Check the step name (if supplied)
  10113.     IF (@step_name IS NOT NULL)
  10114.     BEGIN
  10115.       SELECT @step_id = step_id
  10116.       FROM msdb.dbo.sysjobsteps
  10117.       WHERE (step_name = @step_name)
  10118.         AND (job_id = @job_id)
  10119.  
  10120.       IF (@step_id IS NULL)
  10121.       BEGIN
  10122.         RAISERROR(14262, -1, -1, '@step_name', @step_name)
  10123.         RETURN(1) -- Failure
  10124.       END
  10125.     END
  10126.  
  10127.     EXECUTE @retval = msdb.dbo.sp_sqlagent_notify @op_type     = N'J',
  10128.                                                   @job_id      = @job_id,
  10129.                                                   @schedule_id = @step_id, -- This is the start step
  10130.                                                   @action_type = N'S',
  10131.                                                   @error_flag  = @error_flag 
  10132.     IF ((@retval = 0) AND (@output_flag = 1))
  10133.       RAISERROR(14243, 0, 1, @job_name)
  10134.   END
  10135.   ELSE
  10136.   BEGIN
  10137.     -- The job is a multi-server job 
  10138.  
  10139.     -- Check target server name (if any)
  10140.     IF (@server_name IS NOT NULL)
  10141.     BEGIN
  10142.       IF (NOT EXISTS (SELECT *
  10143.                       FROM msdb.dbo.systargetservers
  10144.                       WHERE (server_name = @server_name)))
  10145.       BEGIN
  10146.         RAISERROR(14262, -1, -1, '@server_name', @server_name)
  10147.         RETURN(1) -- Failure
  10148.       END
  10149.     END
  10150.  
  10151.     -- Re-post the job if it's an auto-delete job
  10152.     IF ((SELECT delete_level
  10153.          FROM msdb.dbo.sysjobs
  10154.          WHERE (job_id = @job_id)) <> 0)
  10155.       EXECUTE @retval = msdb.dbo.sp_post_msx_operation 'INSERT', 'JOB', @job_id, @server_name
  10156.  
  10157.     -- Post start instruction(s)
  10158.     EXECUTE @retval = msdb.dbo.sp_post_msx_operation 'START', 'JOB', @job_id, @server_name
  10159.   END
  10160.  
  10161.   RETURN(@retval) -- 0 means success
  10162. END
  10163. go
  10164.  
  10165. /**************************************************************/
  10166. /* SP_STOP_JOB                                                */
  10167. /**************************************************************/
  10168.  
  10169. PRINT ''
  10170. PRINT 'Creating procedure sp_stop_job...'
  10171. go
  10172. IF (EXISTS (SELECT *
  10173.             FROM msdb.dbo.sysobjects
  10174.             WHERE (name = N'sp_stop_job')
  10175.               AND (type = 'P')))
  10176.   DROP PROCEDURE sp_stop_job
  10177. go
  10178. CREATE PROCEDURE sp_stop_job
  10179.   @job_name           sysname          = NULL,
  10180.   @job_id             UNIQUEIDENTIFIER = NULL,
  10181.   @originating_server NVARCHAR(30)     = NULL, -- So that we can stop ALL jobs that came from the given server
  10182.   @server_name        NVARCHAR(30)     = NULL  -- The specific target server to stop the [multi-server] job on
  10183. AS
  10184. BEGIN
  10185.   DECLARE @job_id_as_char VARCHAR(36)
  10186.   DECLARE @retval         INT
  10187.   DECLARE @num_parameters INT
  10188.  
  10189.   SET NOCOUNT ON
  10190.  
  10191.   -- Remove any leading/trailing spaces from parameters
  10192.   SELECT @job_name           = LTRIM(RTRIM(@job_name))
  10193.   SELECT @originating_server = LTRIM(RTRIM(@originating_server))
  10194.   SELECT @server_name        = LTRIM(RTRIM(@server_name))
  10195.  
  10196.   -- Turn [nullable] empty string parameters into NULLs
  10197.   IF (@job_name           = N'') SELECT @job_name = NULL
  10198.   IF (@originating_server = N'') SELECT @originating_server = NULL
  10199.   IF (@server_name        = N'') SELECT @server_name = NULL
  10200.  
  10201.   -- We must have EITHER a job id OR a job name OR an originating server
  10202.   SELECT @num_parameters = 0
  10203.   IF (@job_id IS NOT NULL)
  10204.     SELECT @num_parameters = @num_parameters + 1
  10205.   IF (@job_name IS NOT NULL)
  10206.     SELECT @num_parameters = @num_parameters + 1
  10207.   IF (@originating_server IS NOT NULL)
  10208.     SELECT @num_parameters = @num_parameters + 1
  10209.   IF (@num_parameters <> 1)
  10210.   BEGIN
  10211.     RAISERROR(14232, -1, -1)
  10212.     RETURN(1) -- Failure
  10213.   END
  10214.  
  10215.   IF (@originating_server IS NOT NULL)
  10216.   BEGIN
  10217.     -- Stop (cancel) ALL local jobs that originated from the specified server
  10218.     IF (NOT EXISTS (SELECT *
  10219.                     FROM msdb.dbo.sysjobs_view
  10220.                     WHERE (originating_server = @originating_server)))
  10221.     BEGIN
  10222.       RAISERROR(14268, -1, -1, @originating_server)
  10223.       RETURN(1) -- Failure
  10224.     END
  10225.  
  10226.     DECLARE @total_counter   INT
  10227.     DECLARE @success_counter INT
  10228.  
  10229.     DECLARE stop_jobs CURSOR LOCAL 
  10230.     FOR
  10231.     SELECT job_id
  10232.     FROM msdb.dbo.sysjobs_view
  10233.     WHERE (originating_server = @originating_server)
  10234.  
  10235.     SELECT @total_counter = 0, @success_counter = 0
  10236.     OPEN stop_jobs
  10237.     FETCH NEXT FROM stop_jobs INTO @job_id
  10238.     WHILE (@@fetch_status = 0)
  10239.     BEGIN
  10240.       SELECT @total_counter + @total_counter + 1
  10241.       EXECUTE @retval = msdb.dbo.sp_sqlagent_notify @op_type     = N'J',
  10242.                                                     @job_id      = @job_id,
  10243.                                                     @action_type = N'C'
  10244.       IF (@retval = 0)
  10245.         SELECT @success_counter = @success_counter + 1
  10246.       FETCH NEXT FROM stop_jobs INTO @job_id
  10247.     END
  10248.     RAISERROR(14253, 0, 1, @success_counter, @total_counter)
  10249.     DEALLOCATE stop_jobs
  10250.  
  10251.     RETURN(0) -- 0 means success
  10252.   END
  10253.   ELSE
  10254.   BEGIN
  10255.     -- Stop ONLY the specified job
  10256.     EXECUTE @retval = sp_verify_job_identifiers '@job_name',
  10257.                                                 '@job_id',
  10258.                                                  @job_name OUTPUT,
  10259.                                                  @job_id   OUTPUT
  10260.     IF (@retval <> 0)
  10261.       RETURN(1) -- Failure
  10262.  
  10263.     IF (NOT EXISTS (SELECT *
  10264.                     FROM msdb.dbo.sysjobservers
  10265.                     WHERE (job_id = @job_id)))
  10266.     BEGIN
  10267.       SELECT @job_id_as_char = CONVERT(VARCHAR(36), @job_id)
  10268.       RAISERROR(14257, -1, -1, @job_name, @job_id_as_char)
  10269.       RETURN(1) -- Failure
  10270.     END
  10271.  
  10272.     IF (EXISTS (SELECT *
  10273.                 FROM msdb.dbo.sysjobservers
  10274.                 WHERE (job_id = @job_id)
  10275.                   AND (server_id = 0)))
  10276.     BEGIN
  10277.       -- The job is local, so stop (cancel) the job locally
  10278.       EXECUTE @retval = msdb.dbo.sp_sqlagent_notify @op_type     = N'J',
  10279.                                                     @job_id      = @job_id,
  10280.                                                     @action_type = N'C'
  10281.       IF (@retval = 0)
  10282.         RAISERROR(14254, 0, 1, @job_name)
  10283.     END
  10284.     ELSE
  10285.     BEGIN
  10286.       -- The job is a multi-server job
  10287.  
  10288.       -- Check target server name (if any)
  10289.       IF (@server_name IS NOT NULL)
  10290.       BEGIN
  10291.         IF (NOT EXISTS (SELECT *
  10292.                         FROM msdb.dbo.systargetservers
  10293.                         WHERE (server_name = @server_name)))
  10294.         BEGIN
  10295.           RAISERROR(14262, -1, -1, '@server_name', @server_name)
  10296.           RETURN(1) -- Failure
  10297.         END
  10298.       END
  10299.  
  10300.       -- Post the stop instruction(s)
  10301.       EXECUTE @retval = sp_post_msx_operation 'STOP', 'JOB', @job_id, @server_name
  10302.     END
  10303.  
  10304.     RETURN(@retval) -- 0 means success
  10305.   END
  10306.  
  10307. END
  10308. go
  10309.  
  10310. /**************************************************************/
  10311. /* SP_GET_CHUNKED_JOBSTEP_PARAMS                              */
  10312. /**************************************************************/
  10313.  
  10314. PRINT ''
  10315. PRINT 'Creating procedure sp_get_chunked_jobstep_params...'
  10316. go
  10317. IF (EXISTS (SELECT *
  10318.             FROM msdb.dbo.sysobjects
  10319.             WHERE (name = N'sp_get_chunked_jobstep_params')
  10320.               AND (type = 'P')))
  10321.   DROP PROCEDURE sp_get_chunked_jobstep_params
  10322. go
  10323. CREATE PROCEDURE sp_get_chunked_jobstep_params
  10324.   @job_name sysname,
  10325.   @step_id  INT = 1
  10326. AS
  10327. BEGIN
  10328.   DECLARE @job_id           UNIQUEIDENTIFIER
  10329.   DECLARE @step_id_as_char  VARCHAR(10)
  10330.   DECLARE @text_pointer     VARBINARY(16)
  10331.   DECLARE @remaining_length INT
  10332.   DECLARE @offset           INT
  10333.   DECLARE @chunk            INT
  10334.   DECLARE @retval           INT
  10335.  
  10336.   SET NOCOUNT ON
  10337.  
  10338.   -- Check that the job exists
  10339.   EXECUTE @retval = sp_verify_job_identifiers '@job_name',
  10340.                                               '@job_id',
  10341.                                                @job_name OUTPUT,
  10342.                                                @job_id   OUTPUT
  10343.   IF (@retval <> 0)
  10344.     RETURN(1) -- Failure
  10345.  
  10346.   -- Check that the step exists
  10347.   IF (NOT EXISTS (SELECT *
  10348.                   FROM msdb.dbo.sysjobsteps
  10349.                   WHERE (job_id = @job_id)
  10350.                     AND (step_id = @step_id)))
  10351.   BEGIN
  10352.     SELECT @step_id_as_char = CONVERT(VARCHAR(10), @step_id)
  10353.     RAISERROR(14262, -1, -1, '@step_id', @step_id_as_char)
  10354.     RETURN(1) -- Failure
  10355.   END
  10356.  
  10357.   -- Return the sysjobsteps.additional_parameters TEXT column as multiple readtexts of
  10358.   -- length 2048
  10359.  
  10360.   SELECT @text_pointer = TEXTPTR(additional_parameters),
  10361.          @remaining_length = (DATALENGTH(additional_parameters) / 2)
  10362.   FROM msdb.dbo.sysjobsteps
  10363.   WHERE (job_id = @job_id)
  10364.     AND (step_id = @step_id)
  10365.  
  10366.   SELECT @offset = 0, @chunk = 100
  10367.  
  10368.   -- Get all the chunks of @chunk size
  10369.   WHILE (@remaining_length > @chunk)
  10370.   BEGIN
  10371.     READTEXT msdb.dbo.sysjobsteps.additional_parameters @text_pointer @offset @chunk
  10372.     SELECT @offset = @offset + @chunk
  10373.     SELECT @remaining_length = @remaining_length - @chunk
  10374.   END
  10375.  
  10376.   -- Get the last chunk
  10377.   IF (@remaining_length > 0)
  10378.     READTEXT msdb.dbo.sysjobsteps.additional_parameters @text_pointer @offset @remaining_length
  10379.  
  10380.   RETURN(@@error) -- 0 means success
  10381. END
  10382. go
  10383.  
  10384. /**************************************************************/
  10385. /* SP_CHECK_FOR_OWNED_JOBS                                    */
  10386. /**************************************************************/
  10387.  
  10388. PRINT ''
  10389. PRINT 'Creating procedure sp_check_for_owned_jobs...'
  10390. go
  10391. IF (EXISTS (SELECT *
  10392.             FROM msdb.dbo.sysobjects
  10393.             WHERE (name = N'sp_check_for_owned_jobs')
  10394.               AND (type = 'P')))
  10395.   DROP PROCEDURE sp_check_for_owned_jobs
  10396. go
  10397. CREATE PROCEDURE sp_check_for_owned_jobs
  10398.   @login_name sysname,
  10399.   @table_name sysname
  10400. AS
  10401. BEGIN
  10402.   SET NOCOUNT ON
  10403.  
  10404.   -- This procedure is called by sp_droplogin to check if the login being dropped
  10405.   -- still owns jobs.  The return value (the number of jobs owned) is passed back
  10406.   -- via the supplied table name [this cumbersome approach is necessary because
  10407.   -- sp_check_for_owned_jobs is invoked via an EXEC() and because we always want
  10408.   -- sp_droplogin to work, even if msdb and/or sysjobs does not exist].
  10409.  
  10410.   IF (EXISTS (SELECT *
  10411.               FROM msdb.dbo.sysobjects
  10412.               WHERE (name = N'sysjobs')
  10413.                 AND (type = 'U')))
  10414.   BEGIN
  10415.     SELECT @login_name = REPLACE(@login_name, N'''', N'''''')
  10416.     EXECUTE(N'INSERT INTO ' + @table_name + N' SELECT COUNT(*) FROM msdb.dbo.sysjobs_view WHERE (owner_sid = SUSER_SID(N''' + @login_name + '''))')
  10417.   END
  10418. END
  10419. go
  10420.  
  10421. /**************************************************************/
  10422. /* SP_CHECK_FOR_OWNED_JOBSTEPS                                */
  10423. /**************************************************************/
  10424.  
  10425. PRINT ''
  10426. PRINT 'Creating procedure sp_check_for_owned_jobsteps...'
  10427. go
  10428. IF (EXISTS (SELECT *
  10429.             FROM msdb.dbo.sysobjects
  10430.             WHERE (name = N'sp_check_for_owned_jobsteps')
  10431.               AND (type = 'P')))
  10432.   DROP PROCEDURE sp_check_for_owned_jobsteps
  10433. go
  10434. CREATE PROCEDURE sp_check_for_owned_jobsteps
  10435.   @login_name         sysname = NULL,  -- Supply this OR the database_X parameters, but not both 
  10436.   @database_name      sysname = NULL,
  10437.   @database_user_name sysname = NULL
  10438. AS
  10439. BEGIN
  10440.   DECLARE @db_name         NVARCHAR(255)
  10441.   DECLARE @escaped_db_name NVARCHAR(255)
  10442.  
  10443.   SET NOCOUNT ON
  10444.  
  10445.   CREATE TABLE #work_table
  10446.   (
  10447.   database_name      sysname,
  10448.   database_user_name sysname
  10449.   )
  10450.  
  10451.   IF ((@login_name IS NOT NULL) AND (@database_name IS NULL) AND (@database_user_name IS NULL))
  10452.   BEGIN
  10453.     IF (SUSER_SID(@login_name) IS NULL)
  10454.     BEGIN
  10455.       RAISERROR(14262, -1, -1, '@login_name', @login_name)
  10456.       RETURN(1) -- Failure
  10457.     END
  10458.  
  10459.     DECLARE all_databases CURSOR LOCAL
  10460.     FOR
  10461.     SELECT name
  10462.     FROM master.dbo.sysdatabases
  10463.  
  10464.     OPEN all_databases
  10465.     FETCH NEXT FROM all_databases INTO @db_name
  10466.  
  10467.     -- Double up any single quotes in @login_name
  10468.     SELECT @login_name = REPLACE(@login_name, N'''', N'''''')
  10469.  
  10470.     WHILE (@@fetch_status = 0)
  10471.     BEGIN
  10472.       SELECT @escaped_db_name = QUOTENAME(@db_name, N'[')
  10473.       SELECT @db_name = REPLACE(@db_name, '''', '''''')
  10474.       EXECUTE(N'INSERT INTO #work_table
  10475.                 SELECT N''' + @db_name + N''', name
  10476.                 FROM ' + @escaped_db_name + N'.dbo.sysusers 
  10477.                 WHERE (sid = SUSER_SID(N''' + @login_name + N'''))')
  10478.       FETCH NEXT FROM all_databases INTO @db_name
  10479.     END
  10480.  
  10481.     DEALLOCATE all_databases
  10482.  
  10483.     -- If the login is an NT login, check for steps run as the login directly (as is the case with transient NT logins)
  10484.     IF (@login_name LIKE '%\%')
  10485.     BEGIN
  10486.       INSERT INTO #work_table
  10487.       SELECT database_name, database_user_name
  10488.       FROM msdb.dbo.sysjobsteps
  10489.       WHERE (database_user_name = @login_name)
  10490.     END
  10491.   END
  10492.   
  10493.   IF ((@login_name IS NULL) AND (@database_name IS NOT NULL) AND (@database_user_name IS NOT NULL))
  10494.   BEGIN
  10495.     INSERT INTO #work_table
  10496.     SELECT @database_name, @database_user_name
  10497.   END  
  10498.  
  10499.   IF (EXISTS (SELECT *
  10500.               FROM #work_table wt,
  10501.                    msdb.dbo.sysjobsteps sjs
  10502.               WHERE (wt.database_name = sjs.database_name)
  10503.                 AND (wt.database_user_name = sjs.database_user_name)))
  10504.   BEGIN
  10505.     SELECT sjv.job_id,
  10506.            sjv.name,
  10507.            sjs.step_id,
  10508.            sjs.step_name
  10509.     FROM #work_table           wt,
  10510.          msdb.dbo.sysjobsteps  sjs,
  10511.          msdb.dbo.sysjobs_view sjv
  10512.     WHERE (wt.database_name = sjs.database_name)
  10513.       AND (wt.database_user_name = sjs.database_user_name)
  10514.       AND (sjv.job_id = sjs.job_id)
  10515.     ORDER BY sjs.job_id
  10516.   END
  10517.  
  10518.   RETURN(0) -- 0 means success
  10519. END
  10520. go
  10521.  
  10522. /**************************************************************/
  10523. /* SP_SQLAGENT_REFRESH_JOB                                    */
  10524. /**************************************************************/
  10525.  
  10526. PRINT ''
  10527. PRINT 'Creating procedure sp_sqlagent_refresh_job...'
  10528. go
  10529. IF (EXISTS (SELECT *
  10530.             FROM msdb.dbo.sysobjects
  10531.             WHERE (name = N'sp_sqlagent_refresh_job')
  10532.               AND (type = 'P')))
  10533.   DROP PROCEDURE sp_sqlagent_refresh_job
  10534. go
  10535. CREATE PROCEDURE sp_sqlagent_refresh_job
  10536.   @job_id      UNIQUEIDENTIFIER = NULL,
  10537.   @server_name NVARCHAR(30)     = N'(local)' -- This parameter allows a TSX to use this SP when updating a job
  10538. AS
  10539. BEGIN
  10540.   DECLARE @server_id INT
  10541.  
  10542.   SET NOCOUNT ON
  10543.  
  10544.   SELECT @server_id = server_id
  10545.   FROM msdb.dbo.systargetservers_view
  10546.   WHERE (server_name = ISNULL(@server_name, N'(local)'))
  10547.  
  10548.   SELECT @server_id = ISNULL(@server_id, 0)
  10549.  
  10550.   SELECT sjv.job_id,
  10551.          sjv.name,
  10552.          sjv.enabled,
  10553.          sjv.start_step_id,
  10554.          owner = SUSER_SNAME(sjv.owner_sid),
  10555.          sjv.notify_level_eventlog,
  10556.          sjv.notify_level_email,
  10557.          sjv.notify_level_netsend,
  10558.          sjv.notify_level_page,
  10559.          sjv.notify_email_operator_id,
  10560.          sjv.notify_netsend_operator_id,
  10561.          sjv.notify_page_operator_id,
  10562.          sjv.delete_level,
  10563.          has_step = (SELECT COUNT(*) 
  10564.                      FROM msdb.dbo.sysjobsteps sjst
  10565.                      WHERE (sjst.job_id = sjv.job_id)),
  10566.          sjv.version_number,
  10567.          last_run_date = ISNULL(sjs.last_run_date, 0),
  10568.          last_run_time = ISNULL(sjs.last_run_time, 0),
  10569.          sjv.originating_server,
  10570.          sjv.description
  10571.   FROM msdb.dbo.sysjobs_view  sjv,
  10572.        msdb.dbo.sysjobservers sjs
  10573.   WHERE ((@job_id IS NULL) OR (@job_id = sjv.job_id))
  10574.     AND (sjv.job_id = sjs.job_id)
  10575.     AND (sjs.server_id = @server_id)
  10576.   ORDER BY sjv.job_id
  10577.  
  10578.   RETURN(@@error) -- 0 means success
  10579. END
  10580. go
  10581.  
  10582. /**************************************************************/
  10583. /* SP_JOBHISTORY_ROW_LIMITER                                  */
  10584. /**************************************************************/
  10585.  
  10586. PRINT ''
  10587. PRINT 'Creating procedure sp_jobhistory_row_limiter...'
  10588. go
  10589. IF (EXISTS (SELECT *
  10590.             FROM msdb.dbo.sysobjects
  10591.             WHERE (name = N'sp_jobhistory_row_limiter')
  10592.               AND (type = 'P')))
  10593.   DROP PROCEDURE dbo.sp_jobhistory_row_limiter
  10594. go
  10595. CREATE PROCEDURE sp_jobhistory_row_limiter 
  10596.   @job_id UNIQUEIDENTIFIER
  10597. AS
  10598. BEGIN
  10599.   DECLARE @max_total_rows         INT -- This value comes from the registry (MaxJobHistoryTableRows)
  10600.   DECLARE @max_rows_per_job       INT -- This value comes from the registry (MaxJobHistoryRows)
  10601.   DECLARE @rows_to_delete         INT
  10602.   DECLARE @rows_to_delete_as_char VARCHAR(10)
  10603.   DECLARE @current_rows           INT
  10604.   DECLARE @current_rows_per_job   INT
  10605.   DECLARE @job_id_as_char         VARCHAR(36)
  10606.  
  10607.   SET NOCOUNT ON
  10608.  
  10609.   SELECT @job_id_as_char = CONVERT(VARCHAR(36), @job_id)
  10610.  
  10611.   -- Get max-job-history-rows from the registry
  10612.   EXECUTE master.dbo.xp_regread N'HKEY_LOCAL_MACHINE',
  10613.                                 N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
  10614.                                 N'JobHistoryMaxRows',
  10615.                                  @max_total_rows OUTPUT,
  10616.                                 N'no_output'
  10617.  
  10618.   -- Check if we are limiting sysjobhistory rows
  10619.   IF (ISNULL(@max_total_rows, -1) = -1)
  10620.     RETURN(0)
  10621.  
  10622.   -- Check that max_total_rows is more than 1
  10623.   IF (ISNULL(@max_total_rows, 0) < 2)
  10624.   BEGIN
  10625.     -- It isn't, so set the default to 1000 rows
  10626.     SELECT @max_total_rows = 1000
  10627.     EXECUTE master.dbo.xp_regwrite N'HKEY_LOCAL_MACHINE',
  10628.                                    N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
  10629.                                    N'JobHistoryMaxRows',
  10630.                                    N'REG_DWORD',
  10631.                                     @max_total_rows
  10632.   END
  10633.  
  10634.   -- Get the per-job maximum number of rows to keep
  10635.   SELECT @max_rows_per_job = 0
  10636.   EXECUTE master.dbo.xp_regread N'HKEY_LOCAL_MACHINE',
  10637.                                 N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
  10638.                                 N'JobHistoryMaxRowsPerJob',
  10639.                                  @max_rows_per_job OUTPUT,
  10640.                                 N'no_output'
  10641.  
  10642.   -- Check that max_rows_per_job is <= max_total_rows
  10643.   IF ((@max_rows_per_job > @max_total_rows) OR (@max_rows_per_job < 1))
  10644.   BEGIN
  10645.     -- It isn't, so default the rows_per_job to max_total_rows
  10646.     SELECT @max_rows_per_job = @max_total_rows
  10647.     EXECUTE master.dbo.xp_regwrite N'HKEY_LOCAL_MACHINE',
  10648.                                    N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
  10649.                                    N'JobHistoryMaxRowsPerJob',
  10650.                                    N'REG_DWORD',
  10651.                                     @max_rows_per_job
  10652.   END
  10653.  
  10654.   BEGIN TRANSACTION
  10655.  
  10656.   SELECT @current_rows_per_job = COUNT(*)
  10657.   FROM msdb.dbo.sysjobhistory (TABLOCKX)
  10658.   WHERE (job_id = @job_id)
  10659.  
  10660.   -- Delete the oldest history row(s) for the job being inserted if the new row has
  10661.   -- pushed us over the per-job row limit (MaxJobHistoryRows)
  10662.   SELECT @rows_to_delete = @current_rows_per_job - @max_rows_per_job
  10663.   SELECT @rows_to_delete_as_char = CONVERT(VARCHAR, @rows_to_delete)
  10664.  
  10665.   IF (@rows_to_delete > 0)
  10666.   BEGIN
  10667.     EXECUTE ('DECLARE @new_oldest_id INT
  10668.               SET NOCOUNT ON
  10669.               SET ROWCOUNT ' + @rows_to_delete_as_char +
  10670.              'SELECT @new_oldest_id = instance_id
  10671.               FROM msdb.dbo.sysjobhistory
  10672.               WHERE (job_id = ''' + @job_id_as_char + ''') ' +
  10673.              'ORDER BY instance_id
  10674.               SET ROWCOUNT 0
  10675.               DELETE FROM msdb.dbo.sysjobhistory
  10676.               WHERE (job_id = ''' + @job_id_as_char + ''')' +
  10677.              '  AND (instance_id <= @new_oldest_id)')
  10678.   END
  10679.  
  10680.   -- Delete the oldest history row(s) if inserting the new row has pushed us over the
  10681.   -- global MaxJobHistoryTableRows limit.
  10682.   SELECT @current_rows = COUNT(*)
  10683.   FROM msdb.dbo.sysjobhistory
  10684.  
  10685.   SELECT @rows_to_delete = @current_rows - @max_total_rows
  10686.   SELECT @rows_to_delete_as_char = CONVERT(VARCHAR, @rows_to_delete)
  10687.  
  10688.   IF (@rows_to_delete > 0)
  10689.   BEGIN
  10690.     EXECUTE ('DECLARE @new_oldest_id INT
  10691.               SET NOCOUNT ON
  10692.               SET ROWCOUNT ' + @rows_to_delete_as_char +
  10693.              'SELECT @new_oldest_id = instance_id
  10694.               FROM msdb.dbo.sysjobhistory
  10695.               ORDER BY instance_id
  10696.               SET ROWCOUNT 0
  10697.               DELETE FROM msdb.dbo.sysjobhistory
  10698.               WHERE (instance_id <= @new_oldest_id)')
  10699.   END
  10700.  
  10701.   IF (@@trancount > 0)
  10702.     COMMIT TRANSACTION
  10703.  
  10704.   RETURN(0) -- Success
  10705. END
  10706. go
  10707.  
  10708. /**************************************************************/
  10709. /* SP_SQLAGENT_LOG_JOBHISTORY                                 */
  10710. /**************************************************************/
  10711.  
  10712. PRINT ''
  10713. PRINT 'Creating procedure sp_sqlagent_log_jobhistory...'
  10714. go
  10715. IF (EXISTS (SELECT *
  10716.             FROM msdb.dbo.sysobjects
  10717.             WHERE (name = N'sp_sqlagent_log_jobhistory')
  10718.               AND (type = 'P')))
  10719.   DROP PROCEDURE sp_sqlagent_log_jobhistory
  10720. go
  10721. CREATE PROCEDURE sp_sqlagent_log_jobhistory
  10722.   @job_id               UNIQUEIDENTIFIER,
  10723.   @step_id              INT,
  10724.   @sql_message_id       INT = 0,
  10725.   @sql_severity         INT = 0,
  10726.   @message              NVARCHAR(1024) = NULL,
  10727.   @run_status           INT, -- SQLAGENT_EXEC_X code
  10728.   @run_date             INT,
  10729.   @run_time             INT,
  10730.   @run_duration         INT,
  10731.   @operator_id_emailed  INT = 0,
  10732.   @operator_id_netsent  INT = 0,
  10733.   @operator_id_paged    INT = 0,
  10734.   @retries_attempted    INT,
  10735.   @server               NVARCHAR(30) = N'(local)'
  10736. AS
  10737. BEGIN
  10738.   DECLARE @retval              INT
  10739.   DECLARE @job_id_as_char      VARCHAR(36)
  10740.   DECLARE @step_id_as_char     VARCHAR(10)
  10741.   DECLARE @operator_id_as_char VARCHAR(10)
  10742.   DECLARE @step_name           sysname
  10743.   DECLARE @error_severity      INT
  10744.   DECLARE @job_name            sysname
  10745.  
  10746.   SET NOCOUNT ON
  10747.  
  10748.   -- Check authority (only SQLServerAgent can add a history entry for a job)
  10749.   EXECUTE @retval = sp_verify_jobproc_caller @job_id = @job_id, @program_name = N'SQLAgent%'
  10750.   IF (@retval <> 0)
  10751.     RETURN(@retval)
  10752.  
  10753.   -- NOTE: We raise all errors as informational (sev 0) to prevent SQLServerAgent from caching
  10754.   --       the operation (if it fails) since if the operation will never run successfully we 
  10755.   --       don't want it to hang around in the operation cache.
  10756.   SELECT @error_severity = 0
  10757.  
  10758.   -- Check job_id
  10759.   IF (NOT EXISTS (SELECT *
  10760.                   FROM msdb.dbo.sysjobs_view
  10761.                   WHERE (job_id = @job_id)))
  10762.   BEGIN
  10763.     SELECT @job_id_as_char = CONVERT(VARCHAR(36), @job_id)
  10764.     RAISERROR(14262, @error_severity, -1, 'Job', @job_id_as_char) 
  10765.     RETURN(1) -- Failure
  10766.   END
  10767.  
  10768.   -- Check step id
  10769.   IF (@step_id <> 0) -- 0 means 'for the whole job'
  10770.   BEGIN
  10771.     SELECT @step_name = step_name
  10772.     FROM msdb.dbo.sysjobsteps
  10773.     WHERE (job_id = @job_id)
  10774.       AND (step_id = @step_id)
  10775.     IF (@step_name IS NULL)
  10776.     BEGIN
  10777.       SELECT @step_id_as_char = CONVERT(VARCHAR, @step_id)
  10778.       RAISERROR(14262, @error_severity, -1, '@step_id', @step_id_as_char)
  10779.       RETURN(1) -- Failure
  10780.     END
  10781.   END
  10782.   ELSE
  10783.     SELECT @step_name = FORMATMESSAGE(14570)
  10784.  
  10785.   -- Check run_status
  10786.   IF (@run_status NOT IN (0, 1, 2, 3, 4, 5)) -- SQLAGENT_EXEC_X code
  10787.   BEGIN
  10788.     RAISERROR(14266, @error_severity, -1, '@run_status', '0, 1, 2, 3, 4, 5')
  10789.     RETURN(1) -- Failure
  10790.   END
  10791.  
  10792.   -- Check run_date
  10793.   EXECUTE @retval = sp_verify_job_date @run_date, '@run_date', 10
  10794.   IF (@retval <> 0)
  10795.     RETURN(1) -- Failure
  10796.  
  10797.   -- Check run_time
  10798.   EXECUTE @retval = sp_verify_job_time @run_time, '@run_time', 10
  10799.   IF (@retval <> 0)
  10800.     RETURN(1) -- Failure
  10801.  
  10802.   -- Check operator_id_emailed
  10803.   IF (@operator_id_emailed <> 0)
  10804.   BEGIN
  10805.     IF (NOT EXISTS (SELECT *
  10806.                     FROM msdb.dbo.sysoperators
  10807.                     WHERE (id = @operator_id_emailed)))
  10808.     BEGIN
  10809.       SELECT @operator_id_as_char = CONVERT(VARCHAR, @operator_id_emailed)
  10810.       RAISERROR(14262, @error_severity, -1, '@operator_id_emailed', @operator_id_as_char)
  10811.       RETURN(1) -- Failure
  10812.     END
  10813.   END
  10814.  
  10815.   -- Check operator_id_netsent
  10816.   IF (@operator_id_netsent <> 0)
  10817.   BEGIN
  10818.     IF (NOT EXISTS (SELECT *
  10819.                     FROM msdb.dbo.sysoperators
  10820.                     WHERE (id = @operator_id_netsent)))
  10821.     BEGIN
  10822.       SELECT @operator_id_as_char = CONVERT(VARCHAR, @operator_id_netsent)
  10823.       RAISERROR(14262, @error_severity, -1, '@operator_id_netsent', @operator_id_as_char)
  10824.       RETURN(1) -- Failure
  10825.     END
  10826.   END
  10827.  
  10828.   -- Check operator_id_paged
  10829.   IF (@operator_id_paged <> 0)
  10830.   BEGIN
  10831.     IF (NOT EXISTS (SELECT *
  10832.                     FROM msdb.dbo.sysoperators
  10833.                     WHERE (id = @operator_id_paged)))
  10834.     BEGIN
  10835.       SELECT @operator_id_as_char = CONVERT(VARCHAR, @operator_id_paged)
  10836.       RAISERROR(14262, @error_severity, -1, '@operator_id_paged', @operator_id_as_char)
  10837.       RETURN(1) -- Failure
  10838.     END
  10839.   END
  10840.  
  10841.   -- Insert the history row
  10842.   INSERT INTO msdb.dbo.sysjobhistory
  10843.          (job_id,
  10844.           step_id,
  10845.           step_name,
  10846.           sql_message_id,
  10847.           sql_severity,
  10848.           message,
  10849.           run_status,
  10850.           run_date,
  10851.           run_time,
  10852.           run_duration,
  10853.           operator_id_emailed,
  10854.           operator_id_netsent,
  10855.           operator_id_paged,
  10856.           retries_attempted,
  10857.           server)
  10858.   VALUES (@job_id,
  10859.           @step_id,
  10860.           @step_name,
  10861.           @sql_message_id,
  10862.           @sql_severity,
  10863.           @message,
  10864.           @run_status,
  10865.           @run_date,
  10866.           @run_time,
  10867.           @run_duration,
  10868.           @operator_id_emailed,
  10869.           @operator_id_netsent,
  10870.           @operator_id_paged,
  10871.           @retries_attempted,
  10872.           @server)
  10873.  
  10874.   -- If misc. replication job, then update global replication status table
  10875.   SELECT @job_name = name from msdb.dbo.sysjobs where job_id = @job_id and
  10876.     category_id IN (11, 12, 16, 17, 18)
  10877.   IF @job_name IS NOT NULL
  10878.   BEGIN
  10879.     -- Nothing can be done if this fails, so don't worry about the return code
  10880.     EXECUTE master.dbo.sp_MSupdate_replication_status
  10881.       @publisher = '',
  10882.       @publisher_db = '',
  10883.       @publication = '',
  10884.       @publication_type = -1,
  10885.       @agent_type = 5,
  10886.       @agent_name = @job_name,
  10887.       @status = @run_status
  10888.   END
  10889.  
  10890.   -- Delete any history rows that are over the registry-defined limits
  10891.   EXECUTE msdb.dbo.sp_jobhistory_row_limiter @job_id
  10892.  
  10893.   RETURN(@@error) -- 0 means success
  10894. END
  10895. go
  10896.  
  10897. /**************************************************************/
  10898. /* SP_SQLAGENT_CHECK_MSX_VERSION                              */
  10899. /**************************************************************/
  10900.  
  10901. PRINT ''
  10902. PRINT 'Creating procedure sp_sqlagent_check_msx_version...'
  10903. go
  10904. IF (EXISTS (SELECT *
  10905.             FROM msdb.dbo.sysobjects
  10906.             WHERE (name = N'sp_sqlagent_check_msx_version')
  10907.               AND (type = 'P')))
  10908.   DROP PROCEDURE sp_sqlagent_check_msx_version
  10909. go
  10910. CREATE PROCEDURE sp_sqlagent_check_msx_version
  10911.   @required_microsoft_version INT = NULL
  10912. AS
  10913. BEGIN
  10914.   SET NOCOUNT ON
  10915.  
  10916.   DECLARE @msx_version          NVARCHAR(16)
  10917.   DECLARE @required_msx_version NVARCHAR(16)
  10918.  
  10919.   IF (@required_microsoft_version IS NULL)
  10920.     SELECT @required_microsoft_version = 0x07000252 -- 7.0.594
  10921.  
  10922.   IF (@@microsoftversion < @required_microsoft_version)
  10923.   BEGIN
  10924.     SELECT @msx_version = CONVERT(NVARCHAR(2), CONVERT(INT, CONVERT(BINARY(1), (CONVERT(BINARY(2), @@microsoftversion / 0xffff) / 256)))) + N'.' +
  10925.                           CONVERT(NVARCHAR(2), CONVERT(INT, CONVERT(BINARY(1), (CONVERT(BINARY(2), @@microsoftversion / 0xffff) % 256)))) + N'.' +
  10926.                           CONVERT(NVARCHAR(4), @@microsoftversion & 0xffff)
  10927.     SELECT @required_msx_version = CONVERT(NVARCHAR(2), CONVERT(INT, CONVERT(BINARY(1), (CONVERT(BINARY(2), @required_microsoft_version / 0xffff) / 256)))) + N'.' +
  10928.                                    CONVERT(NVARCHAR(2), CONVERT(INT, CONVERT(BINARY(1), (CONVERT(BINARY(2), @required_microsoft_version / 0xffff) % 256)))) + N'.' +
  10929.                                    CONVERT(NVARCHAR(4), @required_microsoft_version & 0xffff)
  10930.     RAISERROR(14541, -1, -1, @msx_version, @required_msx_version)
  10931.     RETURN(1) -- Failure
  10932.   END
  10933.   RETURN(0) -- Success
  10934. END
  10935. go
  10936.  
  10937. /**************************************************************/
  10938. /* SP_SQLAGENT_PROBE_MSX                                      */
  10939. /**************************************************************/
  10940.  
  10941. PRINT ''
  10942. PRINT 'Creating procedure sp_sqlagent_probe_msx...'
  10943. go
  10944. IF (EXISTS (SELECT *
  10945.             FROM msdb.dbo.sysobjects
  10946.             WHERE (name = N'sp_sqlagent_probe_msx')
  10947.               AND (type = 'P')))
  10948.   DROP PROCEDURE sp_sqlagent_probe_msx
  10949. go
  10950. CREATE PROCEDURE sp_sqlagent_probe_msx
  10951.   @server_name          NVARCHAR(30),  -- The name of the target server probing the MSX
  10952.   @local_time           NVARCHAR(100), -- The local time at the target server in the format YYYY/MM/DD HH:MM:SS
  10953.   @poll_interval        INT,           -- The frequency (in seconds) with which the target polls the MSX
  10954.   @time_zone_adjustment INT = NULL     -- The offset from GMT in minutes (may be NULL if unknown)
  10955. AS
  10956. BEGIN
  10957.   DECLARE @bad_enlistment        BIT
  10958.   DECLARE @blocking_instructions INT
  10959.   DECLARE @pending_instructions  INT
  10960.  
  10961.   SET NOCOUNT ON
  10962.  
  10963.   SELECT @bad_enlistment = 0, @blocking_instructions = 0, @pending_instructions = 0
  10964.  
  10965.   UPDATE msdb.dbo.systargetservers 
  10966.   SET last_poll_date = GETDATE(), 
  10967.       local_time_at_last_poll = CONVERT(DATETIME, @local_time, 111),
  10968.       poll_interval = @poll_interval,
  10969.       time_zone_adjustment = ISNULL(@time_zone_adjustment, time_zone_adjustment)
  10970.   WHERE (server_name = @server_name) 
  10971.  
  10972.   -- If the systargetservers entry is missing (and no DEFECT instruction has been posted)
  10973.   -- then the enlistment is bad
  10974.   IF (NOT EXISTS (SELECT 1 
  10975.                   FROM msdb.dbo.systargetservers 
  10976.                   WHERE (server_name = @server_name))) AND
  10977.      (NOT EXISTS (SELECT 1 
  10978.                   FROM msdb.dbo.sysdownloadlist 
  10979.                   WHERE (target_server = @server_name) 
  10980.                     AND (operation_code = 7) 
  10981.                     AND (object_type = 2)))
  10982.     SELECT @bad_enlistment = 1
  10983.  
  10984.   SELECT @blocking_instructions = COUNT(*) 
  10985.   FROM msdb.dbo.sysdownloadlist 
  10986.   WHERE (target_server = @server_name) 
  10987.     AND (error_message IS NOT NULL)
  10988.  
  10989.   SELECT @pending_instructions = COUNT(*) 
  10990.   FROM msdb.dbo.sysdownloadlist 
  10991.   WHERE (target_server = @server_name)
  10992.     AND (error_message IS NULL)
  10993.     AND (status = 0)
  10994.  
  10995.   SELECT @bad_enlistment, @blocking_instructions, @pending_instructions
  10996. END
  10997. go
  10998.  
  10999. /**************************************************************/
  11000. /* SP_SET_LOCAL_TIME                                          */
  11001. /**************************************************************/
  11002.  
  11003. PRINT ''
  11004. PRINT 'Creating procedure sp_set_local_time...'
  11005. go
  11006. IF (EXISTS (SELECT *
  11007.             FROM msdb.dbo.sysobjects
  11008.             WHERE (name = N'sp_set_local_time')
  11009.               AND (type = 'P')))
  11010.   DROP PROCEDURE sp_set_local_time
  11011. go
  11012. CREATE PROCEDURE sp_set_local_time
  11013.   @server_name           NVARCHAR(30) = NULL,
  11014.   @adjustment_in_minutes INT          = 0 -- Only needed for Win9x
  11015. AS
  11016. BEGIN
  11017.   DECLARE @ret              INT
  11018.   DECLARE @local_time       INT
  11019.   DECLARE @local_date       INT
  11020.   DECLARE @current_datetime DATETIME
  11021.   DECLARE @local_time_sz    VARCHAR(30)
  11022.   DECLARE @cmd              NVARCHAR(200)
  11023.   DECLARE @date_format      NVARCHAR(64)
  11024.   DECLARE @year_sz          NVARCHAR(16)
  11025.   DECLARE @month_sz         NVARCHAR(16)
  11026.   DECLARE @day_sz           NVARCHAR(16)
  11027.  
  11028.   -- Synchronize the clock with the remote server (if supplied)
  11029.   -- NOTE: NT takes timezones into account, whereas Win9x does not
  11030.   IF (@server_name IS NOT NULL)
  11031.   BEGIN
  11032.     SELECT @cmd = N'net time \\' + @server_name + N' /set /y'
  11033.     EXECUTE @ret = master.dbo.xp_cmdshell @cmd, no_output
  11034.     IF (@ret <> 0)
  11035.       RETURN(1) -- Failure
  11036.   END
  11037.  
  11038.   -- Since NET TIME on Win9x does not take time zones into account we need to manually adjust
  11039.   -- for this using @adjustment_in_minutes which will be the difference between the MSX GMT
  11040.   -- offset and the target server GMT offset
  11041.   IF ((PLATFORM() & 0x2) = 0x2) -- Win9x
  11042.   BEGIN
  11043.     -- Get the date format from the registry (so that we can construct our DATE command-line command)
  11044.     EXECUTE master.dbo.xp_regread N'HKEY_CURRENT_USER',
  11045.                                   N'Control Panel\International',
  11046.                                   N'sShortDate',
  11047.                                    @date_format OUTPUT,
  11048.                                   N'no_output'
  11049.     SELECT @date_format = LOWER(@date_format)
  11050.  
  11051.     IF (@adjustment_in_minutes <> 0)
  11052.     BEGIN
  11053.       -- Wait for SQLServer to re-cache the OS time
  11054.       WAITFOR DELAY '00:01:00'
  11055.  
  11056.       SELECT @current_datetime = DATEADD(mi, @adjustment_in_minutes, GETDATE())
  11057.       SELECT @local_time_sz = SUBSTRING(CONVERT(VARCHAR, @current_datetime, 8), 1, 5)
  11058.       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)))
  11059.       SELECT @local_date = CONVERT(INT, CONVERT(VARCHAR, @current_datetime, 112))
  11060.  
  11061.       -- Set the date
  11062.       SELECT @year_sz = CONVERT(NVARCHAR, @local_date / 10000)
  11063.       SELECT @month_sz = CONVERT(NVARCHAR, (@local_date % 10000) / 100)
  11064.       SELECT @day_sz = CONVERT(NVARCHAR, @local_date % 100)
  11065.  
  11066.       IF (@date_format LIKE N'y%m%d')
  11067.         SELECT @cmd = N'DATE ' + @year_sz + N'-' + @month_sz + N'-' + @day_sz
  11068.       IF (@date_format LIKE N'y%d%m')
  11069.         SELECT @cmd = N'DATE ' + @year_sz + N'-' + @day_sz + N'-' + @month_sz
  11070.       IF (@date_format LIKE N'm%d%y')
  11071.         SELECT @cmd = N'DATE ' + @month_sz + N'-' + @day_sz + N'-' + @year_sz
  11072.       IF (@date_format LIKE N'd%m%y')
  11073.         SELECT @cmd = N'DATE ' + @day_sz + N'-' + @month_sz + N'-' + @year_sz
  11074.  
  11075.       EXECUTE @ret = master.dbo.xp_cmdshell @cmd, no_output
  11076.       IF (@ret <> 0)
  11077.         RETURN 1 -- Failure
  11078.  
  11079.       -- Set the time (NOTE: We can't set the millisecond part of the time, so we may be up to .999 sec off)
  11080.       SELECT @cmd = N'TIME ' + CONVERT(NVARCHAR, @local_time / 100) + N':' + CONVERT(NVARCHAR, @local_time % 100) + ':' + CONVERT(NVARCHAR(2), DATEPART(SS, GETDATE()))
  11081.       EXECUTE @ret = master.dbo.xp_cmdshell @cmd, no_output
  11082.       IF (@ret <> 0)
  11083.         RETURN 1 -- Failure
  11084.     END
  11085.  
  11086.   END
  11087.  
  11088.   RETURN(0) -- Success
  11089. END
  11090. go
  11091.  
  11092. /**************************************************************/
  11093. /* SP_MULTI_SERVER_JOB_SUMMARY [used by SEM only]             */
  11094. /**************************************************************/
  11095.  
  11096. PRINT ''
  11097. PRINT 'Creating procedure sp_multi_server_job_summary...'
  11098. go
  11099. IF (EXISTS (SELECT *
  11100.             FROM msdb.dbo.sysobjects
  11101.             WHERE (name = N'sp_multi_server_job_summary')
  11102.               AND (type = 'P')))
  11103.   DROP PROCEDURE sp_multi_server_job_summary
  11104. go
  11105. CREATE PROCEDURE sp_multi_server_job_summary
  11106.   @job_id   UNIQUEIDENTIFIER = NULL,
  11107.   @job_name sysname          = NULL
  11108. AS
  11109. BEGIN
  11110.   DECLARE @retval INT
  11111.  
  11112.   SET NOCOUNT ON
  11113.  
  11114.   IF ((@job_id IS NOT NULL) OR (@job_name IS NOT NULL))
  11115.   BEGIN
  11116.     EXECUTE @retval = sp_verify_job_identifiers '@job_name',
  11117.                                                 '@job_id',
  11118.                                                  @job_name OUTPUT,
  11119.                                                  @job_id   OUTPUT
  11120.     IF (@retval <> 0)
  11121.       RETURN(1) -- Failure
  11122.   END
  11123.  
  11124.   -- NOTE: We join with syscategories - not sysjobservers - since we want to include jobs
  11125.   --       which are of type multi-server but which don't currently have any servers
  11126.   SELECT 'job_id'   = sj.job_id,
  11127.          'job_name' = sj.name, 
  11128.          'enabled'  = sj.enabled,
  11129.          'category_name'  = sc.name,
  11130.          'target_servers' = (SELECT COUNT(*) 
  11131.                              FROM msdb.dbo.sysjobservers sjs
  11132.                              WHERE (sjs.job_id = sj.job_id)),
  11133.          'pending_download_instructions' = (SELECT COUNT(*) 
  11134.                                             FROM msdb.dbo.sysdownloadlist sdl 
  11135.                                             WHERE (sdl.object_id = sj.job_id)
  11136.                                               AND (status = 0)),
  11137.          'download_errors' = (SELECT COUNT(*) 
  11138.                               FROM msdb.dbo.sysdownloadlist sdl 
  11139.                               WHERE (sdl.object_id = sj.job_id)
  11140.                                 AND (sdl.error_message IS NOT NULL)),
  11141.          'execution_failures' = (SELECT COUNT(*) 
  11142.                                  FROM msdb.dbo.sysjobservers sjs 
  11143.                                  WHERE (sjs.job_id = sj.job_id)
  11144.                                    AND (sjs.last_run_date <> 0)
  11145.                                    AND (sjs.last_run_outcome <> 1)) -- 1 is success
  11146.   FROM msdb.dbo.sysjobs sj,
  11147.        msdb.dbo.syscategories sc
  11148.   WHERE (sj.category_id = sc.category_id)
  11149.     AND (sc.category_class = 1) -- JOB
  11150.     AND (sc.category_type  = 2) -- Multi-Server
  11151.     AND ((@job_id IS NULL)   OR (sj.job_id = @job_id))
  11152.     AND ((@job_name IS NULL) OR (sj.name = @job_name))
  11153.  
  11154.   RETURN(0) -- Success
  11155. END
  11156. go
  11157.  
  11158. /**************************************************************/
  11159. /* SP_TARGET_SERVER_SUMMARY [used by SEM only]                */
  11160. /**************************************************************/
  11161.  
  11162. PRINT ''
  11163. PRINT 'Creating procedure sp_target_server_summary...'
  11164. go
  11165. IF (EXISTS (SELECT *
  11166.             FROM msdb.dbo.sysobjects
  11167.             WHERE (name = N'sp_target_server_summary')
  11168.               AND (type = 'P')))
  11169.   DROP PROCEDURE sp_target_server_summary
  11170. go
  11171. CREATE PROCEDURE sp_target_server_summary
  11172.   @target_server NVARCHAR(30) = NULL
  11173. AS
  11174. BEGIN
  11175.   SET NOCOUNT ON
  11176.  
  11177.   SELECT server_id,
  11178.          server_name,
  11179.         'local_time' = DATEADD(SS, DATEDIFF(SS, last_poll_date, GETDATE()), local_time_at_last_poll),
  11180.          last_poll_date,
  11181.         'unread_instructions' = (SELECT COUNT(*)
  11182.                                  FROM msdb.dbo.sysdownloadlist sdl
  11183.                                  WHERE (sdl.target_server = sts.server_name)
  11184.                                    AND (sdl.status = 0)),
  11185.         'blocked' = (SELECT COUNT(*)
  11186.                      FROM msdb.dbo.sysdownloadlist sdl
  11187.                      WHERE (sdl.target_server = sts.server_name)
  11188.                        AND (sdl.error_message IS NOT NULL)),
  11189.          poll_interval
  11190.   FROM msdb.dbo.systargetservers sts
  11191.   WHERE ((@target_server IS NULL) OR (@target_server = sts.server_name))
  11192. END
  11193. go
  11194.  
  11195. DUMP TRANSACTION msdb WITH NO_LOG
  11196. go
  11197. CHECKPOINT
  11198. go
  11199.  
  11200.  
  11201. /**************************************************************/
  11202. /*                                                            */
  11203. /*         6  .  X     P  R  O  C  E  D  U  R  E  S           */
  11204. /*                                                            */
  11205. /* These procedures are provided for backwards compatability  */
  11206. /* with 6.x scripts and 6.x replication.  The re-implemented  */
  11207. /* procedures are as follows:                                 */
  11208. /*                                                            */
  11209. /* - sp_uniquetaskname  (SQLDMO)                              */
  11210. /* - systasks_view      (INSTDIST.SQL)                        */
  11211. /* - sp_addtask         (INSTREPL.SQL, INSTDIST.SQL, SQLDMO)  */
  11212. /* - sp_updatetask      (INSTDIST.SQL)                        */
  11213. /* - sp_droptask        (INSTREPL.SQL, INSTDIST.SQL, SQLDMO)  */
  11214. /* - sp_helptask        (INSTREPL.SQL, SQLDMO)                */
  11215. /* - sp_verifytaskid    (INSTREPL.SQL)                        */
  11216. /* - sp_reassigntask    (INSTDIST.SQL)                        */
  11217. /* - sp_helphistory     (For completeness only)               */
  11218. /* - sp_purgehistory    (For completeness only)               */
  11219. /* - systasks           (For completeness only)               */
  11220. /**************************************************************/
  11221.  
  11222. /**************************************************************/
  11223. /* SYSTASKS (a view to simulate the 6.x systasks table)       */
  11224. /**************************************************************/
  11225.  
  11226. PRINT ''
  11227. PRINT 'Creating [legacy] table systasks [as a view]...'
  11228. go
  11229. IF (EXISTS (SELECT *
  11230.             FROM msdb.dbo.sysobjects
  11231.             WHERE (name = N'systasks')
  11232.               AND (type = 'U')))
  11233.   DROP TABLE systasks -- Just a precaution in case the systasks table is somehow still lingering around
  11234. IF (EXISTS (SELECT *
  11235.             FROM msdb.dbo.sysobjects
  11236.             WHERE (name = N'systasks')
  11237.               AND (type = 'V')))
  11238.   DROP VIEW systasks
  11239. go
  11240. CREATE VIEW systasks
  11241. AS
  11242.   SELECT 'id'                     = sti.task_id,
  11243.          'name'                   = sj.name,
  11244.          'subsystem'              = sjst.subsystem,
  11245.          'server'                 = sjst.server,
  11246.          'username'               = sjst.database_user_name,
  11247.          'ownerloginid'           = ISNULL(sl.suid, 1), -- Default to SA if owner not known
  11248.          'databasename'           = sjst.database_name,
  11249.          'enabled'                = sj.enabled,
  11250.          'freqtype'               = ISNULL(sjsch.freq_type, 2), -- On Demand
  11251.          'freqinterval'           = ISNULL(sjsch.freq_interval, 0),
  11252.          'freqsubtype'            = ISNULL(sjsch.freq_subday_type, 0),
  11253.          'freqsubinterval'        = ISNULL(sjsch.freq_subday_interval, 0),
  11254.          'freqrelativeinterval'   = ISNULL(sjsch.freq_relative_interval, 0),
  11255.          'freqrecurrencefactor'   = ISNULL(sjsch.freq_recurrence_factor, 0),
  11256.          'activestartdate'        = ISNULL(sjsch.active_start_date, 19900101),
  11257.          'activeenddate'          = ISNULL(sjsch.active_end_date, 99991231),
  11258.          'activestarttimeofday'   = ISNULL(sjsch.active_start_time, 0),
  11259.          'activeendtimeofday'     = ISNULL(sjsch.active_end_time, 235959),
  11260.          'lastrundate'            = sjs.last_run_date,
  11261.          'lastruntime'            = sjs.last_run_time,
  11262.          'nextrundate'            = ISNULL(sjsch.next_run_date, 0),
  11263.          'nextruntime'            = ISNULL(sjsch.next_run_time, 0),
  11264.          'runpriority'            = sjst.os_run_priority,
  11265.          'emailoperatorid'        = sj.notify_email_operator_id,
  11266.          'retryattempts'          = sjst.retry_attempts,
  11267.          'retrydelay'             = sjst.retry_interval,
  11268.          'datecreated'            = sj.date_created,
  11269.          'datemodified'           = sj.date_modified,
  11270.          'command'                = sjst.command,
  11271.          'lastruncompletionlevel' = sjs.last_run_outcome,
  11272.          'lastrunduration'        = sjst.last_run_duration,
  11273.          'lastrunretries'         = sjst.last_run_retries,
  11274.          'loghistcompletionlevel' = sj.notify_level_eventlog,
  11275.          'emailcompletionlevel'   = sj.notify_level_email,
  11276.          'description'            = sj.description,
  11277.          'tagadditionalinfo'      = 0,
  11278.          'tagobjectid'            = 0,
  11279.          'tagobjecttype'          = 0,
  11280.          'parameters'             = CONVERT(TEXT, sjst.additional_parameters),
  11281.          'cmdexecsuccesscode'     = sjst.cmdexec_success_code
  11282.     FROM msdb.dbo.sysjobs                         sj
  11283.          LEFT OUTER JOIN msdb.dbo.sysjobschedules sjsch ON (sj.job_id = sjsch.job_id)
  11284.          LEFT OUTER JOIN master.dbo.syslogins     sl    ON (sj.owner_sid = sl.sid),
  11285.          msdb.dbo.systaskids                      sti,
  11286.          msdb.dbo.sysjobsteps                     sjst,
  11287.          msdb.dbo.sysjobservers                   sjs
  11288.     WHERE (sj.job_id = sti.job_id)
  11289.       AND (sj.job_id = sjst.job_id)
  11290.       AND (sjst.step_id = 1)
  11291.       AND (sj.job_id = sjs.job_id)
  11292.       AND (sjs.server_id = 0)
  11293.       AND ((sjsch.name = N'6.x schedule') OR (sjsch.name IS NULL)) -- NULL handles the case of the job not having a schedule
  11294.   UNION ALL -- NOTE: We do this just to make the view non-updatable
  11295.   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
  11296.   WHERE (1 = 2)
  11297. go
  11298.  
  11299. /**************************************************************/
  11300. /* SYSTASKS_VIEW                                              */
  11301. /**************************************************************/
  11302.  
  11303. PRINT ''
  11304. PRINT 'Creating [legacy] view systasks_view...'
  11305. go
  11306. IF (EXISTS (SELECT *
  11307.             FROM msdb.dbo.sysobjects
  11308.             WHERE (name = N'systasks_view')
  11309.               AND (type = 'V')))
  11310.   DROP VIEW systasks_view
  11311. go
  11312. CREATE VIEW systasks_view
  11313. AS
  11314.   SELECT 'id'                     = sti.task_id,
  11315.          'name'                   = sjv.name,
  11316.          'subsystem'              = sjst.subsystem,
  11317.          'server'                 = sjst.server,
  11318.          'username'               = sjst.database_user_name,
  11319.          'ownerloginid'           = ISNULL(sl.suid, 1), -- Default to SA if owner not known
  11320.          'databasename'           = sjst.database_name,
  11321.          'enabled'                = sjv.enabled,
  11322.          'freqtype'               = ISNULL(sjsch.freq_type, 2), -- On Demand
  11323.          'freqinterval'           = ISNULL(sjsch.freq_interval, 0),
  11324.          'freqsubtype'            = ISNULL(sjsch.freq_subday_type, 0),
  11325.          'freqsubinterval'        = ISNULL(sjsch.freq_subday_interval, 0),
  11326.          'freqrelativeinterval'   = ISNULL(sjsch.freq_relative_interval, 0),
  11327.          'freqrecurrencefactor'   = ISNULL(sjsch.freq_recurrence_factor, 0),
  11328.          'activestartdate'        = ISNULL(sjsch.active_start_date, 19900101),
  11329.          'activeenddate'          = ISNULL(sjsch.active_end_date, 99991231),
  11330.          'activestarttimeofday'   = ISNULL(sjsch.active_start_time, 0),
  11331.          'activeendtimeofday'     = ISNULL(sjsch.active_end_time, 235959),
  11332.          'lastrundate'            = sjs.last_run_date,
  11333.          'lastruntime'            = sjs.last_run_time,
  11334.          'nextrundate'            = ISNULL(sjsch.next_run_date, 0),
  11335.          'nextruntime'            = ISNULL(sjsch.next_run_time, 0),
  11336.          'runpriority'            = sjst.os_run_priority,
  11337.          'emailoperatorid'        = sjv.notify_email_operator_id,
  11338.          'retryattempts'          = sjst.retry_attempts,
  11339.          'retrydelay'             = sjst.retry_interval,
  11340.          'datecreated'            = sjv.date_created,
  11341.          'datemodified'           = sjv.date_modified,
  11342.          'command'                = sjst.command,
  11343.          'lastruncompletionlevel' = sjs.last_run_outcome,
  11344.          'lastrunduration'        = sjst.last_run_duration,
  11345.          'lastrunretries'         = sjst.last_run_retries,
  11346.          'loghistcompletionlevel' = sjv.notify_level_eventlog,
  11347.          'emailcompletionlevel'   = sjv.notify_level_email,
  11348.          'description'            = sjv.description,
  11349.          'tagadditionalinfo'      = 0,
  11350.          'tagobjectid'            = 0,
  11351.          'tagobjecttype'          = 0,
  11352.          'parameters'             = CONVERT(TEXT, sjst.additional_parameters),
  11353.          'cmdexecsuccesscode'     = sjst.cmdexec_success_code
  11354.     FROM msdb.dbo.sysjobs_view                    sjv
  11355.          LEFT OUTER JOIN msdb.dbo.sysjobschedules sjsch ON (sjv.job_id = sjsch.job_id)
  11356.          LEFT OUTER JOIN master.dbo.syslogins     sl    ON (sjv.owner_sid = sl.sid),
  11357.          msdb.dbo.systaskids                      sti,
  11358.          msdb.dbo.sysjobsteps                     sjst,
  11359.          msdb.dbo.sysjobservers                   sjs
  11360.     WHERE (sjv.job_id = sti.job_id)
  11361.       AND (sjv.job_id = sjst.job_id)
  11362.       AND (sjst.step_id = 1)
  11363.       AND (sjv.job_id = sjs.job_id)
  11364.       AND (sjs.server_id = 0)
  11365.       AND ((sjsch.name = N'6.x schedule') OR (sjsch.name IS NULL)) -- NULL handles the case of the job not having a schedule
  11366.   UNION ALL -- NOTE: We do this just to make the view non-updatable
  11367.   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
  11368.   WHERE (1 = 2)
  11369. go
  11370.  
  11371. /**************************************************************/
  11372. /* SP_UNIQUETASKNAME                                          */
  11373. /**************************************************************/
  11374.  
  11375. PRINT ''
  11376. PRINT 'Creating [legacy] procedure sp_uniquetaskname...'
  11377. go
  11378. IF (EXISTS (SELECT *
  11379.             FROM msdb.dbo.sysobjects
  11380.             WHERE (name = N'sp_uniquetaskname')
  11381.               AND (type = 'P')))
  11382.   DROP PROCEDURE sp_uniquetaskname
  11383. go
  11384. CREATE PROCEDURE sp_uniquetaskname
  11385.   @seed NVARCHAR(92)
  11386. AS
  11387. BEGIN
  11388.   DECLARE @newest_suffix INT
  11389.  
  11390.   SET NOCOUNT ON
  11391.  
  11392.   -- We're going to add a suffix of 8 characters so make sure the seed is at most 84 characters
  11393.   SELECT @seed = LTRIM(RTRIM(@seed))
  11394.   IF (DATALENGTH(@seed) > 0)
  11395.     SELECT @seed = SUBSTRING(@seed, 1, 84)
  11396.  
  11397.   -- Find the newest (highest) suffix so far
  11398.   SELECT @newest_suffix = MAX(CONVERT(INT, RIGHT(name, 8)))
  11399.   FROM msdb.dbo.sysjobs -- DON'T use sysjobs_view here!
  11400.   WHERE (name LIKE N'%[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]')
  11401.  
  11402.   -- Generate the task name by appending the 'newest suffix' value (plus one) to the seed
  11403.   IF (@newest_suffix IS NOT NULL)
  11404.   BEGIN
  11405.     SELECT @newest_suffix = @newest_suffix + 1
  11406.     SELECT 'TaskName' = CONVERT(NVARCHAR(92), @seed + REPLICATE(N'0', 8 - (DATALENGTH(CONVERT(NVARCHAR, @newest_suffix)) / 2)) + CONVERT(NVARCHAR, @newest_suffix))
  11407.   END
  11408.   ELSE
  11409.     SELECT 'TaskName' = CONVERT(NVARCHAR(92), @seed + N'00000001')
  11410. END
  11411. go
  11412.  
  11413. /**************************************************************/
  11414. /* SP_ADDTASK                                                 */
  11415. /**************************************************************/
  11416.  
  11417. PRINT ''
  11418. PRINT 'Creating [legacy] procedure sp_addtask...'
  11419. go
  11420. IF (EXISTS (SELECT *
  11421.             FROM msdb.dbo.sysobjects
  11422.             WHERE (name = N'sp_addtask')
  11423.               AND (type = 'P')))
  11424.   DROP PROCEDURE sp_addtask
  11425. go
  11426. CREATE PROCEDURE sp_addtask
  11427.   @name                   sysname,               -- Was VARCHAR(100) in 6.x
  11428.   @subsystem              NVARCHAR(40)   = N'TSQL', -- Was VARCHAR(30) in 6.x
  11429.   @server                 NVARCHAR(30)   = NULL,
  11430.   @username               sysname        = NULL, -- Was VARCHAR(30) in 6.x
  11431.   @databasename           sysname        = NULL, -- Was VARCHAR(30) in 6.x
  11432.   @enabled                TINYINT        = 0,
  11433.   @freqtype               INT            = 2,    -- 2 means OnDemand
  11434.   @freqinterval           INT            = 1,
  11435.   @freqsubtype            INT            = 1,
  11436.   @freqsubinterval        INT            = 1,
  11437.   @freqrelativeinterval   INT            = 1,
  11438.   @freqrecurrencefactor   INT            = 1,
  11439.   @activestartdate        INT            = 0,
  11440.   @activeenddate          INT            = 0,
  11441.   @activestarttimeofday   INT            = 0,
  11442.   @activeendtimeofday     INT            = 0,
  11443.   @nextrundate            INT            = 0,
  11444.   @nextruntime            INT            = 0,
  11445.   @runpriority            INT            = 0,
  11446.   @emailoperatorname      sysname        = NULL, -- Was VARCHAR(50) in 6.x
  11447.   @retryattempts          INT            = 0,
  11448.   @retrydelay             INT            = 10,
  11449.   @command                NVARCHAR(3200) = NULL, -- Was VARCHAR(255) in 6.x
  11450.   @loghistcompletionlevel INT            = 2,
  11451.   @emailcompletionlevel   INT            = 0,
  11452.   @description            NVARCHAR(512)  = NULL, -- Was VARCHAR(255) in 6.x
  11453.   @tagadditionalinfo      VARCHAR(96)    = NULL, -- Obsolete in 7.0
  11454.   @tagobjectid            INT            = NULL, -- Obsolete in 7.0
  11455.   @tagobjecttype          INT            = NULL, -- Obsolete in 7.0
  11456.   @newid                  INT            = NULL OUTPUT,
  11457.   @parameters             NTEXT          = NULL, -- Was TEXT in 6.x
  11458.   @cmdexecsuccesscode     INT            = 0,
  11459.   @category_name          sysname        = NULL, -- New for 7.0
  11460.   @category_id            INT            = NULL  -- New for 7.0
  11461. AS
  11462. BEGIN
  11463.   DECLARE @retval INT
  11464.   DECLARE @job_id UNIQUEIDENTIFIER
  11465.   DECLARE @id     INT
  11466.   DECLARE @distdb sysname
  11467.   DECLARE @proc nvarchar(255) 
  11468.  
  11469.   SET NOCOUNT ON
  11470.  
  11471.   SELECT @retval = 1 -- 0 means success, 1 means failure
  11472.  
  11473.   -- Set 7.0 category names for 6.5 replication tasks
  11474.   IF (LOWER(@subsystem) = N'sync')
  11475.     SELECT @category_id = 15
  11476.   ELSE IF (LOWER(@subsystem) = N'logreader')
  11477.     SELECT @category_id = 13
  11478.   ELSE IF (LOWER(@subsystem) = N'distribution')
  11479.     SELECT @category_id = 10
  11480.  
  11481.   -- Convert old replication synchronization subsystem name to the 7.0 name
  11482.   IF (LOWER(@subsystem) = N'sync')
  11483.     SELECT @subsystem = N'Snapshot'
  11484.  
  11485.   -- If a category ID is provided this overrides any supplied category name
  11486.   IF (@category_id IS NOT NULL)
  11487.   BEGIN
  11488.     SELECT @category_name = name
  11489.     FROM msdb.dbo.syscategories 
  11490.     WHERE (category_id = @category_id)
  11491.     SELECT @category_name = ISNULL(@category_name, FORMATMESSAGE(14205))
  11492.   END
  11493.  
  11494.   -- In 6.x active start date was not restricted, but it is in 7.0; so to avoid a "noisey"
  11495.   -- failure in sp_add_jobschedule we modify the value accordingly
  11496.   IF ((@activestartdate <> 0) AND (@activestartdate < 19900101))
  11497.     SELECT @activestartdate = 19900101
  11498.  
  11499.   BEGIN TRANSACTION
  11500.  
  11501.     -- Add the job
  11502.     EXECUTE @retval = sp_add_job
  11503.       @job_name                   = @name,
  11504.       @enabled                    = @enabled,
  11505.       @start_step_id              = 1,
  11506.       @description                = @description,
  11507.       @category_name              = @category_name,
  11508.       @notify_level_eventlog      = @loghistcompletionlevel,
  11509.       @notify_level_email         = @emailcompletionlevel,
  11510.       @notify_email_operator_name = @emailoperatorname,
  11511.       @job_id                     = @job_id OUTPUT
  11512.  
  11513.     IF (@retval <> 0)
  11514.     BEGIN
  11515.       ROLLBACK TRANSACTION
  11516.       GOTO Quit
  11517.     END
  11518.  
  11519.     -- Add an entry to systaskids for the new job (created by a 6.x client)
  11520.     INSERT INTO msdb.dbo.systaskids (job_id) VALUES (@job_id)
  11521.  
  11522.     -- Get the assigned task id
  11523.     SELECT @id = task_id, @newid = task_id
  11524.     FROM msdb.dbo.systaskids
  11525.     WHERE (job_id = @job_id)
  11526.  
  11527.     -- Add the job step
  11528.     EXECUTE @retval = sp_add_jobstep
  11529.       @job_id                = @job_id,
  11530.       @step_id               = 1,
  11531.       @step_name             = N'Step 1',
  11532.       @subsystem             = @subsystem,
  11533.       @command               = @command,
  11534.       @additional_parameters = @parameters,
  11535.       @cmdexec_success_code  = @cmdexecsuccesscode,
  11536.       @server                = @server,
  11537.       @database_name         = @databasename,
  11538.       @database_user_name    = @username,
  11539.       @retry_attempts        = @retryattempts,
  11540.       @retry_interval        = @retrydelay,
  11541.       @os_run_priority       = @runpriority
  11542.  
  11543.     IF (@retval <> 0)
  11544.     BEGIN
  11545.       ROLLBACK TRANSACTION
  11546.       GOTO Quit
  11547.     END
  11548.  
  11549.     -- Add the job schedule
  11550.     IF (@activestartdate = 0)
  11551.       SELECT @activestartdate = NULL
  11552.     IF (@activeenddate = 0)
  11553.       SELECT @activeenddate = NULL
  11554.     IF (@activestarttimeofday = 0)
  11555.       SELECT @activestarttimeofday = NULL
  11556.     IF (@activeendtimeofday = 0)
  11557.       SELECT @activeendtimeofday = NULL
  11558.     IF (@freqtype <> 0x2) -- OnDemand tasks simply have no schedule in 7.0
  11559.     BEGIN
  11560.       EXECUTE @retval = sp_add_jobschedule
  11561.         @job_id                 = @job_id,
  11562.         @name                   = N'6.x schedule',
  11563.         @enabled                = 1,
  11564.         @freq_type              = @freqtype,
  11565.         @freq_interval          = @freqinterval,
  11566.         @freq_subday_type       = @freqsubtype,
  11567.         @freq_subday_interval   = @freqsubinterval,
  11568.         @freq_relative_interval = @freqrelativeinterval,
  11569.         @freq_recurrence_factor = @freqrecurrencefactor,
  11570.         @active_start_date      = @activestartdate,
  11571.         @active_end_date        = @activeenddate,
  11572.         @active_start_time      = @activestarttimeofday,
  11573.         @active_end_time        = @activeendtimeofday
  11574.  
  11575.       IF (@retval <> 0)
  11576.       BEGIN
  11577.         ROLLBACK TRANSACTION
  11578.         GOTO Quit
  11579.       END
  11580.     END
  11581.  
  11582.     -- And finally, add the job server
  11583.     EXECUTE @retval = sp_add_jobserver @job_id = @job_id, @server_name  = N'(local)'
  11584.  
  11585.     IF (@retval <> 0)
  11586.     BEGIN
  11587.       ROLLBACK TRANSACTION
  11588.       GOTO Quit
  11589.     END
  11590.  
  11591.     -- Add the replication agent for monitoring
  11592.     IF (@category_id = 13) -- Logreader
  11593.     BEGIN
  11594.       SELECT @distdb = distribution_db from MSdistpublishers where name = @server
  11595.       SELECT @proc = @distdb + '.dbo.sp_MSadd_logreader_agent'
  11596.  
  11597.       EXECUTE @retval = @proc
  11598.         @name = @name,
  11599.         @publisher = @server,
  11600.         @publisher_db = @databasename,
  11601.         @publication = '',  
  11602.         @local_job = 1,
  11603.         @job_existing = 1,
  11604.         @job_id = @job_id
  11605.  
  11606.       IF (@retval <> 0)
  11607.       BEGIN
  11608.         ROLLBACK TRANSACTION
  11609.         GOTO Quit
  11610.       END
  11611.     END
  11612.     ELSE 
  11613.     IF (@category_id = 15) -- Snapshot
  11614.     BEGIN
  11615.       DECLARE @publication sysname
  11616.  
  11617.       EXECUTE @retval = master.dbo.sp_MSget_publication_from_taskname
  11618.                             @taskname = @name,
  11619.                             @publisher = @server,
  11620.                             @publisherdb = @databasename,
  11621.                             @publication = @publication OUTPUT
  11622.       
  11623.       IF (@publication IS NOT NULL)
  11624.       BEGIN     
  11625.     
  11626.         SELECT @distdb = distribution_db from MSdistpublishers where name = @server
  11627.         SELECT @proc = @distdb + '.dbo.sp_MSadd_snapshot_agent'
  11628.  
  11629.         EXECUTE @retval = @proc
  11630.                 @name = @name,
  11631.                 @publisher = @server,
  11632.                 @publisher_db = @databasename,
  11633.                 @publication = @publication,
  11634.                 @local_job = 1,
  11635.                 @job_existing = 1,
  11636.                 @snapshot_jobid = @job_id
  11637.  
  11638.         IF (@retval <> 0)
  11639.         BEGIN
  11640.           ROLLBACK TRANSACTION
  11641.           GOTO Quit
  11642.         END
  11643.  
  11644.         SELECT @proc = @distdb + '.dbo.sp_MSadd_publication'
  11645.         EXECUTE @retval = @proc
  11646.                 @publisher = @server,
  11647.                 @publisher_db = @databasename,
  11648.                 @publication = @publication,
  11649.                 @publication_type = 0 -- Transactional
  11650.         IF (@retval <> 0)
  11651.         BEGIN
  11652.           ROLLBACK TRANSACTION
  11653.           GOTO Quit
  11654.         END
  11655.       END
  11656.     END
  11657.  
  11658.   COMMIT TRANSACTION
  11659.  
  11660.   -- If this is an autostart LogReader or Distribution job, add the [new] '-Continuous' paramter to the command
  11661.   IF (@freqtype = 0x40) AND ((UPPER(@subsystem) = N'LOGREADER') OR (UPPER(@subsystem) = N'DISTRIBUTION'))
  11662.   BEGIN
  11663.     UPDATE msdb.dbo.sysjobsteps
  11664.     SET command = command + N' -Continuous'
  11665.     WHERE (job_id = @job_id)
  11666.       AND (step_id = 1)
  11667.   END  
  11668.  
  11669.   -- If this is an autostart job, start it now (for backwards compatibility with 6.x SQLExecutive behaviour)
  11670.   IF (@freqtype = 0x40)
  11671.     EXECUTE msdb.dbo.sp_start_job @job_id = @job_id, @error_flag = 0, @output_flag = 0
  11672.  
  11673. Quit:
  11674.   RETURN(@retval) -- 0 means success
  11675.  
  11676. END
  11677. go
  11678.  
  11679. /**************************************************************/
  11680. /* SP_UPDATETASK                                              */
  11681. /**************************************************************/
  11682.  
  11683. PRINT ''
  11684. PRINT 'Creating [legacy] procedure sp_updatetask...'
  11685. go
  11686. IF (EXISTS (SELECT *
  11687.             FROM msdb.dbo.sysobjects
  11688.             WHERE (name = N'sp_updatetask')
  11689.               AND (type = 'P')))
  11690.   DROP PROCEDURE sp_updatetask
  11691. go
  11692. CREATE PROCEDURE sp_updatetask
  11693.   @currentname            sysname        = NULL, -- Was VARCHAR(100) in 6.x
  11694.   @id                     INT            = NULL,
  11695.   @name                   sysname        = NULL, -- Was VARCHAR(100) in 6.x
  11696.   @subsystem              NVARCHAR(40)   = NULL, -- Was VARCHAR(30) in 6.x
  11697.   @server                 NVARCHAR(30)   = NULL, -- Was VARCHAR(30) in 6.x
  11698.   @username               sysname        = NULL, -- Was VARCHAR(30) in 6.x
  11699.   @databasename           sysname        = NULL, -- Was VARCHAR(30) in 6.x
  11700.   @enabled                TINYINT        = NULL,
  11701.   @freqtype               INT            = NULL,
  11702.   @freqinterval           INT            = NULL,
  11703.   @freqsubtype            INT            = NULL,
  11704.   @freqsubinterval        INT            = NULL,
  11705.   @freqrelativeinterval   INT            = NULL,
  11706.   @freqrecurrencefactor   INT            = NULL,
  11707.   @activestartdate        INT            = NULL,
  11708.   @activeenddate          INT            = NULL,
  11709.   @activestarttimeofday   INT            = NULL,
  11710.   @activeendtimeofday     INT            = NULL,
  11711.   @nextrundate            INT            = NULL,
  11712.   @nextruntime            INT            = NULL,
  11713.   @runpriority            INT            = NULL,
  11714.   @emailoperatorname      sysname        = NULL, -- Was VARCHAR(50) in 6.x
  11715.   @retryattempts          INT            = NULL,
  11716.   @retrydelay             INT            = NULL,
  11717.   @command                NVARCHAR(3200) = NULL,
  11718.   @loghistcompletionlevel INT            = NULL,
  11719.   @emailcompletionlevel   INT            = NULL,
  11720.   @description            VARCHAR(512)   = NULL,
  11721.   @tagadditionalinfo      VARCHAR(96)    = NULL, -- Obsolete in 7.0
  11722.   @tagobjectid            INT            = NULL, -- Obsolete in 7.0
  11723.   @tagobjecttype          INT            = NULL, -- Obsolete in 7.0
  11724.   @parameters             TEXT           = NULL,
  11725.   @cmdexecsuccesscode     INT            = NULL
  11726. AS
  11727. BEGIN
  11728.   DECLARE @retval INT
  11729.   DECLARE @job_id UNIQUEIDENTIFIER
  11730.  
  11731.   SET NOCOUNT ON
  11732.  
  11733.   SELECT @retval = 1 -- 0 means success, 1 means failure
  11734.  
  11735.   -- Convert old replication synchronization subsystem name to the 7.0 name
  11736.   IF (LOWER(@subsystem) = N'sync')
  11737.     SELECT @subsystem = N'Snapshot'
  11738.  
  11739.   IF ((@id IS NULL) AND (@currentname IS NULL)) OR
  11740.      ((@id IS NOT NULL) AND (@currentname IS NOT NULL))
  11741.   BEGIN
  11742.     RAISERROR(14246, -1, -1)
  11743.     RETURN(1) -- Failure
  11744.   END
  11745.  
  11746.   -- In 6.x active start date was not restricted, but it is in 7.0; so to avoid a "noisey"
  11747.   -- failure in sp_update_jobschedule we modify the value accordingly
  11748.   IF ((@activestartdate IS NOT NULL) AND (@activestartdate < 19900101))
  11749.     SELECT @activestartdate = 19900101
  11750.  
  11751.   -- If the name is supplied, get the job_id directly from sysjobs
  11752.   IF (@currentname IS NOT NULL)
  11753.   BEGIN
  11754.     -- Check if the name is ambiguous
  11755.     IF ((SELECT COUNT(*)
  11756.          FROM msdb.dbo.sysjobs_view
  11757.          WHERE (name = @currentname)) > 1)
  11758.     BEGIN
  11759.       RAISERROR(14292, -1, -1, @currentname, '@id', '@currentname')
  11760.       RETURN(1) -- Failure
  11761.     END
  11762.  
  11763.     SELECT @job_id = job_id
  11764.     FROM msdb.dbo.sysjobs_view
  11765.     WHERE (name = @currentname)
  11766.  
  11767.     SELECT @id = task_id
  11768.     FROM msdb.dbo.systaskids
  11769.     WHERE (job_id = @job_id)
  11770.  
  11771.     IF (@job_id IS NULL)
  11772.     BEGIN
  11773.       RAISERROR(14262, -1, -1, '@currentname', @currentname)
  11774.       RETURN(1) -- Failure
  11775.     END
  11776.   END
  11777.  
  11778.   -- If the id is supplied lookup the corresponding job_id from systaskids
  11779.   IF (@id IS NOT NULL)
  11780.   BEGIN
  11781.     SELECT @job_id = job_id
  11782.     FROM msdb.dbo.systaskids
  11783.     WHERE (task_id = @id)
  11784.  
  11785.     -- Check that the job still exists
  11786.     IF (NOT EXISTS (SELECT *
  11787.                     FROM msdb.dbo.sysjobs_view
  11788.                     WHERE (job_id = @job_id)))
  11789.     BEGIN
  11790.       SELECT @currentname = CONVERT(NVARCHAR, @id)
  11791.       RAISERROR(14262, -1, -1, '@id', @currentname)
  11792.       RETURN(1) -- Failure
  11793.     END
  11794.   END
  11795.  
  11796.   -- Do the update
  11797.   BEGIN TRANSACTION
  11798.  
  11799.     -- Update the Job Step
  11800.     IF (@subsystem          IS NOT NULL) OR
  11801.        (@command            IS NOT NULL) OR
  11802.        (@cmdexecsuccesscode IS NOT NULL) OR
  11803.        (@server             IS NOT NULL) OR
  11804.        (@databasename       IS NOT NULL) OR
  11805.        (@username           IS NOT NULL) OR
  11806.        (@retryattempts      IS NOT NULL) OR
  11807.        (@retrydelay         IS NOT NULL) OR
  11808.        (@runpriority        IS NOT NULL)
  11809.     BEGIN
  11810.       EXECUTE @retval = sp_update_jobstep
  11811.         @job_id               = @job_id,
  11812.         @step_id              = 1,
  11813.         @subsystem            = @subsystem,
  11814.         @command              = @command,
  11815.         @cmdexec_success_code = @cmdexecsuccesscode,
  11816.         @server               = @server,
  11817.         @database_name        = @databasename,
  11818.         @database_user_name   = @username,
  11819.         @retry_attempts       = @retryattempts,
  11820.         @retry_interval       = @retrydelay,
  11821.         @os_run_priority      = @runpriority
  11822.  
  11823.       IF (@retval <> 0)
  11824.       BEGIN
  11825.         ROLLBACK TRANSACTION
  11826.         GOTO Quit
  11827.       END
  11828.     END
  11829.  
  11830.     -- Now update the job itself
  11831.     IF (@name                   IS NOT NULL) OR
  11832.        (@enabled                IS NOT NULL) OR
  11833.        (@description            IS NOT NULL) OR
  11834.        (@loghistcompletionlevel IS NOT NULL) OR
  11835.        (@emailcompletionlevel   IS NOT NULL) OR
  11836.        (@emailoperatorname      IS NOT NULL)
  11837.     BEGIN
  11838.       EXECUTE @retval = sp_update_job
  11839.         @job_id                     = @job_id,
  11840.         @new_name                   = @name,
  11841.         @enabled                    = @enabled,
  11842.         @description                = @description,
  11843.         @notify_level_eventlog      = @loghistcompletionlevel,
  11844.         @notify_level_email         = @emailcompletionlevel,
  11845.         @notify_email_operator_name = @emailoperatorname
  11846.  
  11847.     IF (@retval <> 0)
  11848.       BEGIN
  11849.         ROLLBACK TRANSACTION
  11850.         GOTO Quit
  11851.       END
  11852.     END
  11853.  
  11854.     -- Finally, update the job schedule
  11855.     IF (@freqtype             IS NOT NULL) OR
  11856.        (@freqinterval         IS NOT NULL) OR
  11857.        (@freqsubtype          IS NOT NULL) OR
  11858.        (@freqsubinterval      IS NOT NULL) OR
  11859.        (@freqrelativeinterval IS NOT NULL) OR
  11860.        (@freqrecurrencefactor IS NOT NULL) OR
  11861.        (@activestartdate      IS NOT NULL) OR
  11862.        (@activeenddate        IS NOT NULL) OR
  11863.        (@activestarttimeofday IS NOT NULL) OR
  11864.        (@activeendtimeofday   IS NOT NULL)
  11865.     BEGIN
  11866.       IF (@freqtype = 0x2)
  11867.       BEGIN
  11868.         -- OnDemand tasks simply have no schedule in 7.0, so delete the job schedule
  11869.         EXECUTE @retval = sp_delete_jobschedule
  11870.           @job_id = @job_id,
  11871.           @name   = N'6.x schedule'
  11872.       END
  11873.       ELSE
  11874.       BEGIN
  11875.         IF (NOT EXISTS (SELECT *
  11876.                         FROM msdb.dbo.sysjobschedules
  11877.                         WHERE (job_id = @job_id)
  11878.                           AND (name = N'6.x schedule')))
  11879.           EXECUTE @retval = sp_add_jobschedule
  11880.             @job_id                 = @job_id,
  11881.             @name                   = N'6.x schedule',
  11882.             @enabled                = 1,
  11883.             @freq_type              = @freqtype,
  11884.             @freq_interval          = @freqinterval,
  11885.             @freq_subday_type       = @freqsubtype,
  11886.             @freq_subday_interval   = @freqsubinterval,
  11887.             @freq_relative_interval = @freqrelativeinterval,
  11888.             @freq_recurrence_factor = @freqrecurrencefactor,
  11889.             @active_start_date      = @activestartdate,
  11890.             @active_end_date        = @activeenddate,
  11891.             @active_start_time      = @activestarttimeofday,
  11892.             @active_end_time        = @activeendtimeofday
  11893.         ELSE
  11894.           EXECUTE @retval = sp_update_jobschedule
  11895.             @job_id                 = @job_id,
  11896.             @name                   = N'6.x schedule',
  11897.             @enabled                = 1,
  11898.             @freq_type              = @freqtype,
  11899.             @freq_interval          = @freqinterval,
  11900.             @freq_subday_type       = @freqsubtype,
  11901.             @freq_subday_interval   = @freqsubinterval,
  11902.             @freq_relative_interval = @freqrelativeinterval,
  11903.             @freq_recurrence_factor = @freqrecurrencefactor,
  11904.             @active_start_date      = @activestartdate,
  11905.             @active_end_date        = @activeenddate,
  11906.             @active_start_time      = @activestarttimeofday,
  11907.             @active_end_time        = @activeendtimeofday
  11908.       END
  11909.  
  11910.       IF (@retval <> 0)
  11911.       BEGIN
  11912.         ROLLBACK TRANSACTION
  11913.         GOTO Quit
  11914.       END
  11915.     END
  11916.  
  11917.   COMMIT TRANSACTION
  11918.  
  11919. Quit:
  11920.   RETURN(@retval) -- 0 means success
  11921.  
  11922. END
  11923. go
  11924.  
  11925. /**************************************************************/
  11926. /* SP_DROPTASK                                                */
  11927. /**************************************************************/
  11928.  
  11929. PRINT ''
  11930. PRINT 'Creating [legacy] procedure sp_droptask...'
  11931. go
  11932. IF (EXISTS (SELECT *
  11933.             FROM msdb.dbo.sysobjects
  11934.             WHERE (name = N'sp_droptask')
  11935.               AND (type = 'P')))
  11936.   DROP PROCEDURE sp_droptask
  11937. go
  11938. CREATE PROCEDURE sp_droptask
  11939.   @name      sysname = NULL, -- Was VARCHAR(100) in 6.x
  11940.   @loginname sysname = NULL, -- Was VARCHAR(30) in 6.x
  11941.   @id        INT     = NULL
  11942. AS
  11943. BEGIN
  11944.   DECLARE @retval INT
  11945.   DECLARE @job_id UNIQUEIDENTIFIER
  11946.   DECLARE @category_id int
  11947.  
  11948.   SET NOCOUNT ON
  11949.  
  11950.   IF ((@name      IS NULL)     AND (@id    IS NULL)     AND (@loginname IS NULL)) OR
  11951.      ((@name      IS NOT NULL) AND ((@id   IS NOT NULL) OR  (@loginname IS NOT NULL))) OR
  11952.      ((@id        IS NOT NULL) AND ((@name IS NOT NULL) OR  (@loginname IS NOT NULL))) OR
  11953.      ((@loginname IS NOT NULL) AND ((@name IS NOT NULL) OR  (@id        IS NOT NULL)))
  11954.   BEGIN
  11955.     RAISERROR(14245, -1, -1)
  11956.     RETURN(1) -- Failure
  11957.   END
  11958.  
  11959.   -- If the name is supplied, get the job_id directly from sysjobs
  11960.   IF (@name IS NOT NULL)
  11961.   BEGIN
  11962.     -- Check if the name is ambiguous
  11963.     IF ((SELECT COUNT(*)
  11964.          FROM msdb.dbo.sysjobs_view
  11965.          WHERE (name = @name)) > 1)
  11966.     BEGIN
  11967.       RAISERROR(14292, -1, -1, @name, '@id', '@name')
  11968.       RETURN(1) -- Failure
  11969.     END
  11970.  
  11971.     SELECT @job_id = job_id, @category_id = category_id
  11972.     FROM msdb.dbo.sysjobs_view
  11973.     WHERE (name = @name)
  11974.  
  11975.     SELECT @id = task_id
  11976.     FROM msdb.dbo.systaskids
  11977.     WHERE (job_id = @job_id)
  11978.  
  11979.     IF (@job_id IS NULL)
  11980.     BEGIN
  11981.       RAISERROR(14262, -1, -1, '@name', @name)
  11982.       RETURN(1) -- Failure
  11983.     END
  11984.   END
  11985.  
  11986.   -- If the id is supplied lookup the corresponding job_id from systaskids
  11987.   IF (@id IS NOT NULL)
  11988.   BEGIN
  11989.     SELECT @job_id = job_id
  11990.     FROM msdb.dbo.systaskids
  11991.     WHERE (task_id = @id)
  11992.  
  11993.     -- Check that the job still exists
  11994.     IF (NOT EXISTS (SELECT *
  11995.                     FROM msdb.dbo.sysjobs_view
  11996.                     WHERE (job_id = @job_id)))
  11997.     BEGIN
  11998.       SELECT @name = CONVERT(NVARCHAR, @id)
  11999.       RAISERROR(14262, -1, -1, '@id', @name)
  12000.       RETURN(1) -- Failure
  12001.     END
  12002.  
  12003.     -- Get the name of this job
  12004.     SELECT @name = name, @category_id = category_id
  12005.     FROM msdb.dbo.sysjobs_view
  12006.     WHERE (job_id = @job_id)
  12007.   END
  12008.  
  12009.   -- Delete the specific job
  12010.   IF (@name IS NOT NULL)
  12011.   BEGIN
  12012.     BEGIN TRANSACTION
  12013.  
  12014.     DELETE FROM msdb.dbo.systaskids
  12015.     WHERE (job_id = @job_id)
  12016.     EXECUTE @retval = sp_delete_job @job_id = @job_id
  12017.     IF (@retval <> 0)
  12018.     BEGIN
  12019.       ROLLBACK TRANSACTION
  12020.       GOTO Quit
  12021.     END
  12022.  
  12023.     -- If a Logreader or Snapshot task, delete corresponding replication agent information 
  12024.     IF @category_id = 13 or @category_id = 15
  12025.     BEGIN
  12026.          EXECUTE @retval = sp_MSdrop_6x_replication_agent @job_id, @category_id
  12027.       IF (@retval <> 0)
  12028.       BEGIN
  12029.           ROLLBACK TRANSACTION
  12030.           GOTO Quit
  12031.       END
  12032.     END
  12033.  
  12034.  
  12035.     COMMIT TRANSACTION
  12036.   END
  12037.  
  12038.   -- Delete all jobs belonging to the specified login
  12039.   IF (@loginname IS NOT NULL)
  12040.   BEGIN
  12041.     BEGIN TRANSACTION
  12042.  
  12043.     DELETE FROM msdb.dbo.systaskids
  12044.     WHERE job_id IN (SELECT job_id
  12045.                      FROM msdb.dbo.sysjobs_view
  12046.                      WHERE (owner_sid = SUSER_SID(@loginname)))
  12047.     EXECUTE @retval = sp_manage_jobs_by_login @action = 'DELETE',
  12048.                                               @current_owner_login_name = @loginname
  12049.     IF (@retval <> 0)
  12050.     BEGIN
  12051.       ROLLBACK TRANSACTION
  12052.       GOTO Quit
  12053.     END        
  12054.  
  12055.     COMMIT TRANSACTION
  12056.   END
  12057.  
  12058. Quit:
  12059.   RETURN(@retval) -- 0 means success
  12060.  
  12061. END
  12062. go
  12063.  
  12064.  
  12065. /**************************************************************/
  12066. /* SP_HELPTASK                                                */
  12067. /**************************************************************/
  12068.  
  12069. PRINT ''
  12070. PRINT 'Creating [legacy] procedure procedure sp_helptask...'
  12071. go
  12072. IF (EXISTS (SELECT *
  12073.             FROM msdb.dbo.sysobjects
  12074.             WHERE (name = N'sp_helptask')
  12075.               AND (type = 'P')))
  12076.   DROP PROCEDURE sp_helptask
  12077. go
  12078. CREATE PROCEDURE sp_helptask
  12079.   @taskname     sysname      = NULL, -- Was VARCHAR(100) in 6.x
  12080.   @taskid       INT          = NULL,
  12081.   @loginname    sysname      = NULL, -- Was VARCHAR(20) in 6.x
  12082.   @operatorname sysname      = NULL, -- Was VARCHAR(50) in 6.x
  12083.   @subsystem    NVARCHAR(40) = NULL, -- Was VARCHAR(30) in 6.x
  12084.   @mode         VARCHAR(10)  = 'QUICK'  -- Or 'FULL'
  12085. AS
  12086. BEGIN
  12087.   DECLARE @operator_id INT
  12088.   DECLARE @owner_sid   VARBINARY(85)
  12089.  
  12090.   SET NOCOUNT ON
  12091.  
  12092.   -- Convert old replication synchronization subsystem name to the 7.0 name
  12093.   IF (LOWER(@subsystem) = N'sync')
  12094.     SELECT @subsystem = N'Snapshot'
  12095.  
  12096.   -- Get the login id for the login name (if supplied)
  12097.   IF (@loginname IS NOT NULL)
  12098.   BEGIN
  12099.     IF (ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) = 0) AND (SUSER_SNAME() <> @loginname)
  12100.     BEGIN
  12101.       RAISERROR(14247, -1, -1)
  12102.       RETURN(1) -- Failure
  12103.     END
  12104.  
  12105.     SELECT @owner_sid = SUSER_ID(@loginname)
  12106.     IF (@owner_sid IS NULL)
  12107.     BEGIN
  12108.       RAISERROR(14234, -1, -1, '@loginname', 'sp_helplogins')
  12109.       RETURN(1) -- Failure
  12110.     END
  12111.   END
  12112.  
  12113.   -- Get the operator id for the operator name (if supplied)
  12114.   IF (@operatorname IS NOT NULL)
  12115.   BEGIN
  12116.     SELECT @operator_id = id
  12117.     FROM msdb.dbo.sysoperators
  12118.     WHERE (name = @operatorname)
  12119.  
  12120.     IF (@operator_id IS NULL)
  12121.     BEGIN
  12122.       RAISERROR(14262, -1, -1, '@operatorname', @operatorname)
  12123.       RETURN(1) -- Failure
  12124.     END
  12125.   END
  12126.  
  12127.   -- Check the mode
  12128.   SELECT @mode = UPPER(@mode)
  12129.   IF (@mode NOT IN ('FULL', 'QUICK'))
  12130.   BEGIN
  12131.     RAISERROR(14266, -1, -1, '@mode', 'FULL, QUICK')
  12132.     RETURN(1) -- Failure
  12133.   END
  12134.  
  12135.   -- Return task details...
  12136.   -- NOTE: SQLOLE and Starfighter rely on the 'FULL' mode format - do not change it!
  12137.   IF (@mode = 'FULL')
  12138.   BEGIN
  12139.     SELECT name                   = sjv.name,
  12140.            id                     = sti.task_id,
  12141.            subsystem              = sjst.subsystem,
  12142.            server                 = sjst.server,
  12143.            username               = sjst.database_user_name,
  12144.            ownerloginname         = SUSER_SNAME(sjv.owner_sid),
  12145.            databasename           = sjst.database_name,
  12146.            enabled                = sjv.enabled,
  12147.            freqtype               = ISNULL(sjsch.freq_type, 2), -- On Demand
  12148.            freqinterval           = ISNULL(sjsch.freq_interval, 0),
  12149.            freqsubtype            = ISNULL(sjsch.freq_subday_type, 0),
  12150.            freqsubinterval        = ISNULL(sjsch.freq_subday_interval, 0),
  12151.            freqrelativeinterval   = ISNULL(sjsch.freq_relative_interval, 0),
  12152.            freqrecurrencefactor   = ISNULL(sjsch.freq_recurrence_factor, 0),
  12153.            activestartdate        = ISNULL(sjsch.active_start_date, 19900101),
  12154.            activeenddate          = ISNULL(sjsch.active_end_date, 99991231),
  12155.            activestarttimeofday   = ISNULL(sjsch.active_start_time, 0),
  12156.            activeendtimeofday     = ISNULL(sjsch.active_end_time, 235959),
  12157.            lastrundate            = sjs.last_run_date,
  12158.            lastruntime            = sjs.last_run_time,
  12159.            nextrundate            = ISNULL(sjsch.next_run_date, 0),
  12160.            nextruntime            = ISNULL(sjsch.next_run_time, 0),
  12161.            runpriority            = sjst.os_run_priority,
  12162.            emailoperatorname      = so.name,
  12163.            retryattempts          = sjst.retry_attempts,
  12164.            retrydelay             = sjst.retry_interval,
  12165.            datecreated            = sjv.date_created,
  12166.            datemodified           = sjv.date_modified,
  12167.            command                = sjst.command,
  12168.            lastruncompletionlevel = sjs.last_run_outcome,
  12169.            lastrunduration        = sjst.last_run_duration,
  12170.            lastrunretries         = sjst.last_run_retries,
  12171.            loghistcompletionlevel = sjv.notify_level_eventlog,
  12172.            emailcompletionlevel   = sjv.notify_level_email,
  12173.            description            = sjv.description,
  12174.            tagadditionalinfo      = 0,
  12175.            tagobjectid            = 0,
  12176.            tagobjecttype          = 0,
  12177.            cmdexecsuccesscode     = sjst.cmdexec_success_code
  12178.     FROM msdb.dbo.sysjobs_view                    sjv
  12179.          LEFT OUTER JOIN msdb.dbo.sysoperators    so    ON (sjv.notify_email_operator_id = so.id)
  12180.          LEFT OUTER JOIN msdb.dbo.systaskids      sti   ON (sjv.job_id = sti.job_id)
  12181.          LEFT OUTER JOIN msdb.dbo.sysjobschedules sjsch ON (sjv.job_id = sjsch.job_id),
  12182.          msdb.dbo.sysjobsteps                     sjst,
  12183.          msdb.dbo.sysjobservers                   sjs
  12184.     WHERE (sjv.job_id = sjst.job_id)
  12185.       AND (sjst.step_id = 1)
  12186.       AND (sjv.job_id = sjs.job_id)
  12187.       AND (sjs.server_id = 0)
  12188.       AND ((sjsch.name = N'6.x schedule') OR (sjsch.name IS NULL)) -- NULL handles the case of the job not having a schedule
  12189.       AND ((@owner_sid      IS NULL) OR (sjv.owner_sid                = @owner_sid))
  12190.       AND ((@subsystem      IS NULL) OR (sjst.subsystem               = @subsystem))
  12191.       AND ((@operator_id    IS NULL) OR (sjv.notify_email_operator_id = @operator_id))
  12192.       AND ((@taskname       IS NULL) OR (sjv.name                     = @taskname))
  12193.       AND ((@taskid         IS NULL) OR (sti.task_id                  = @taskid))
  12194.     ORDER BY sj.name
  12195.   END
  12196.   ELSE
  12197.   BEGIN
  12198.     SELECT name      = SUBSTRING(sjv.name, 1, 20),
  12199.            id        = sti.task_id,
  12200.            subsystem = SUBSTRING(sjst.subsystem, 1, 15),
  12201.            server    = SUBSTRING(sjst.server, 1, 20),
  12202.            username  = SUBSTRING(sjst.database_user_name, 1, 20),
  12203.            dbname    = SUBSTRING(sjst.database_name, 1, 20),
  12204.            enabled   = sjv.enabled
  12205.     FROM msdb.dbo.sysjobs_view               sjv
  12206.          LEFT OUTER JOIN msdb.dbo.systaskids sti ON (sjv.job_id = sti.job_id),
  12207.          msdb.dbo.sysjobsteps                sjst
  12208.     WHERE (sjv.job_id = sjst.job_id)
  12209.       AND (sjst.step_id = 1)
  12210.       AND ((@owner_sid      IS NULL) OR (sjv.owner_sid                = @owner_sid))
  12211.       AND ((@subsystem      IS NULL) OR (sjst.subsystem               = @subsystem))
  12212.       AND ((@operator_id    IS NULL) OR (sjv.notify_email_operator_id = @operator_id))
  12213.       AND ((@taskname       IS NULL) OR (sjv.name                     = @taskname))
  12214.       AND ((@taskid         IS NULL) OR (sti.task_id                  = @taskid))
  12215.     ORDER BY sjv.name
  12216.   END
  12217. END
  12218. go
  12219.  
  12220. DUMP TRANSACTION msdb WITH NO_LOG
  12221. go
  12222. CHECKPOINT
  12223. go
  12224.  
  12225. /**************************************************************/
  12226. /* SP_VERIFYTASKID                                            */
  12227. /**************************************************************/
  12228.  
  12229. PRINT ''
  12230. PRINT 'Creating [legacy] procedure procedure sp_verifytaskid...'
  12231. go
  12232. IF (EXISTS (SELECT *
  12233.             FROM msdb.dbo.sysobjects
  12234.             WHERE (name = N'sp_verifytaskid')
  12235.               AND (type = 'P')))
  12236.   DROP PROCEDURE sp_verifytaskid
  12237. go
  12238. CREATE PROCEDURE sp_verifytaskid
  12239.   @taskid    INT,
  12240.   @subsystem NVARCHAR(40) = N'%'
  12241. AS
  12242. BEGIN
  12243.   SET NOCOUNT ON
  12244.  
  12245.   -- Convert old replication synchronization subsystem name to the 7.0 name
  12246.   IF (LOWER(@subsystem) = N'sync')
  12247.     SELECT @subsystem = N'Snapshot'
  12248.  
  12249.   -- Check if the task [job] exists
  12250.   IF (EXISTS (SELECT *
  12251.               FROM msdb.dbo.sysjobs_view sjv,
  12252.                    msdb.dbo.sysjobsteps  sjst,
  12253.                    msdb.dbo.systaskids   sti
  12254.               WHERE (sjv.job_id = sjst.job_id)
  12255.                 AND (sjv.job_id = sti.job_id)
  12256.                 AND (sti.task_id = @taskid)
  12257.                 AND (LOWER(sjst.subsystem) LIKE LOWER(@subsystem))))
  12258.     RETURN(0) -- Success
  12259.   ELSE
  12260.     RETURN(1) -- Failure
  12261. END
  12262. go
  12263.  
  12264. /**************************************************************/
  12265. /* SP_REASSIGNTASK                                            */
  12266. /**************************************************************/
  12267.  
  12268. PRINT ''
  12269. PRINT 'Creating [legacy] procedure sp_reassigntask...'
  12270. go
  12271. IF (EXISTS (SELECT *
  12272.             FROM msdb.dbo.sysobjects
  12273.             WHERE (name = N'sp_reassigntask')
  12274.               AND (type = 'P')))
  12275.   DROP PROCEDURE sp_reassigntask
  12276. go
  12277. CREATE PROCEDURE sp_reassigntask
  12278.   @taskname     sysname = NULL, -- Was VARCHAR(100) in 6.x
  12279.   @newloginname sysname,        -- Was VARCHAR(30) in 6.x
  12280.   @oldloginname sysname = NULL  -- Was VARCHAR(30) in 6.x
  12281. AS
  12282. BEGIN
  12283.   DECLARE @retval INT
  12284.  
  12285.   SET NOCOUNT ON
  12286.  
  12287.   IF (ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) <> 1)
  12288.   BEGIN
  12289.     RAISERROR(14244, -1, -1)
  12290.     RETURN(1) -- Failure
  12291.   END
  12292.  
  12293.   -- Check that we have either task or old login name (or both, though it's redundant)
  12294.   IF ((@taskname IS NULL) AND (@oldloginname IS NULL))
  12295.   BEGIN
  12296.     RAISERROR(14249, -1, -1)
  12297.     RETURN(1) -- Failure
  12298.   END
  12299.  
  12300.   -- Case [1]: Reassign a specific task [job]...
  12301.   IF (@taskname IS NOT NULL)
  12302.   BEGIN
  12303.     -- Check new login id
  12304.     IF (SUSER_ID(@newloginname) IS NULL)
  12305.     BEGIN
  12306.       RAISERROR(14262, -1, -1, '@newloginname', @newloginname)
  12307.       RETURN(1) -- Failure
  12308.     END
  12309.  
  12310.     -- NOTE: Normally we'd invoke sp_update_job by supplying the job_id, but since this is
  12311.     --       a legacy procedure we cannot change the parameter list to have the job_id
  12312.     --       supplied to us.  Hence we use name and we run the risk of a [handled] error
  12313.     --       if the task [job] name is not unique.
  12314.     EXECUTE @retval = sp_update_job @job_name = @taskname, @owner_login_name = @newloginname
  12315.     RETURN(@retval) -- 0 means success
  12316.   END
  12317.  
  12318.   -- Case [2]: Reassign all jobs belonging to the specified old login name...
  12319.   IF (@oldloginname IS NOT NULL)
  12320.   BEGIN
  12321.     EXECUTE @retval = sp_manage_jobs_by_login @action = 'REASSIGN',
  12322.                                               @current_owner_login_name = @oldloginname,
  12323.                                               @new_owner_login_name = @newloginname
  12324.     RETURN(@retval) -- 0 means success
  12325.   END
  12326. END
  12327. go
  12328.  
  12329. /**************************************************************/
  12330. /* SP_HELPHISTORY (Replication doesn't need this - It is here */
  12331. /* for completeness only)                                     */
  12332. /**************************************************************/
  12333.  
  12334. PRINT ''
  12335. PRINT 'Creating [legacy] procedure sp_helphistory...'
  12336. go
  12337. IF (EXISTS (SELECT *
  12338.             FROM msdb.dbo.sysobjects
  12339.             WHERE (name = N'sp_helphistory')
  12340.               AND (type = 'P')))
  12341.   DROP PROCEDURE sp_helphistory
  12342. go
  12343. CREATE PROCEDURE sp_helphistory
  12344.   @taskname            sysname     = NULL,   -- Was VARCHAR(100) in 6.x
  12345.   @taskid              INT         = NULL,
  12346.   @eventid             INT         = NULL,
  12347.   @messageid           INT         = NULL,
  12348.   @severity            INT         = NULL,
  12349.   @source              VARCHAR(30) = NULL,   -- Obsolete in 7.0
  12350.   @category            VARCHAR(30) = NULL,   -- Obsolete in 7.0
  12351.   @startdate           INT         = NULL,   -- YYYYMMDD format
  12352.   @enddate             INT         = NULL,   -- YYYYMMDD format
  12353.   @starttime           INT         = NULL,   -- HHMMSS format
  12354.   @endtime             INT         = NULL,   -- HHMMSS format
  12355.   @minimumtimesskipped INT         = NULL,
  12356.   @minimumrunduration  INT         = NULL,   -- HHMMSS format
  12357.   @runstatusmask       INT         = NULL,   -- SQLOLE_COMPLETION_STATUS
  12358.   @minimumretries      INT         = NULL,
  12359.   @oldestfirst         INT         = NULL,
  12360.   @mode                VARCHAR(10) = 'QUICK' -- Or FULL
  12361. AS
  12362. BEGIN
  12363.   DECLARE @job_id   UNIQUEIDENTIFIER
  12364.   DECLARE @order_by INT
  12365.  
  12366.   SET NOCOUNT ON
  12367.  
  12368.   -- If the name is supplied, get the job_id directly from sysjobs
  12369.   IF (@taskname IS NOT NULL)
  12370.   BEGIN
  12371.     SELECT @job_id = job_id
  12372.     FROM msdb.dbo.sysjobs_view
  12373.     WHERE (name = @taskname)
  12374.  
  12375.     -- Check if the name is ambiguous
  12376.     IF (@@rowcount > 1)
  12377.     BEGIN
  12378.       RAISERROR(14292, -1, -1, @taskname, '@taskid', '@taskname')
  12379.       RETURN(1) -- Failure
  12380.     END
  12381.  
  12382.     IF (@job_id IS NULL)
  12383.     BEGIN
  12384.       RAISERROR(14262, -1, -1, '@taskname', @taskname)
  12385.       RETURN(1) -- Failure
  12386.     END
  12387.   END
  12388.  
  12389.   -- If the id is supplied lookup the corresponding job_id from systaskids
  12390.   IF (@taskid IS NOT NULL)
  12391.   BEGIN
  12392.     SELECT @job_id = job_id
  12393.     FROM msdb.dbo.systaskids
  12394.     WHERE (task_id = @taskid)
  12395.  
  12396.     -- Check that the job still exists
  12397.     IF (NOT EXISTS (SELECT *
  12398.                     FROM msdb.dbo.sysjobs_view
  12399.                     WHERE (job_id = @job_id)))
  12400.     BEGIN
  12401.       SELECT @taskname = CONVERT(NVARCHAR, @taskid)
  12402.       RAISERROR(14262, -1, -1, '@taskid', @taskname)
  12403.       RETURN(1) -- Failure
  12404.     END
  12405.   END
  12406.  
  12407.   SELECT @mode = UPPER(@mode)
  12408.   IF (@mode = 'QUICK')
  12409.     SELECT @mode = 'SUMMARY'
  12410.  
  12411.   CREATE TABLE #task_history_full
  12412.   (
  12413.   instance_id       INT              NOT NULL,
  12414.   job_id            UNIQUEIDENTIFIER NOT NULL,
  12415.   job_name          sysname          NOT NULL,
  12416.   step_id           INT              NOT NULL,
  12417.   step_name         sysname          NOT NULL,
  12418.   sql_message_id    INT              NOT NULL,
  12419.   sql_severity      INT              NOT NULL,
  12420.   message           NVARCHAR(1024)   NULL,
  12421.   run_status        INT              NOT NULL,
  12422.   run_date          INT              NOT NULL,
  12423.   run_time          INT              NOT NULL,
  12424.   run_duration      INT              NOT NULL,
  12425.   operator_emailed  sysname          NULL,
  12426.   operator_netsent  sysname          NULL,
  12427.   operator_paged    sysname          NULL,
  12428.   retries_attempted INT              NOT NULL,
  12429.   server            NVARCHAR(30)     NOT NULL
  12430.   )
  12431.  
  12432.   CREATE TABLE #task_history_quick
  12433.   (
  12434.   job_id            UNIQUEIDENTIFIER NOT NULL,
  12435.   job_name          sysname          NOT NULL,
  12436.   run_status        INT              NOT NULL,
  12437.   run_date          INT              NOT NULL,
  12438.   run_time          INT              NOT NULL,
  12439.   run_duration      INT              NOT NULL,
  12440.   operator_emailed  sysname          NULL,
  12441.   operator_netsent  sysname          NULL,
  12442.   operator_paged    sysname          NULL,
  12443.   retries_attempted INT              NOT NULL,
  12444.   server            NVARCHAR(30)     NOT NULL
  12445.   )
  12446.  
  12447.   IF (@mode = 'FULL')
  12448.   BEGIN
  12449.     INSERT INTO #task_history_full
  12450.     EXECUTE msdb.dbo.sp_help_jobhistory  @job_id               = @job_id,
  12451.                                          @sql_message_id       = @messageid,
  12452.                                          @sql_severity         = @severity,
  12453.                                          @start_run_date       = @startdate,
  12454.                                          @end_run_date         = @enddate,
  12455.                                          @start_run_time       = @starttime,
  12456.                                          @end_run_time         = @endtime,
  12457.                                          @minimum_run_duration = @minimumrunduration,
  12458.                                          @run_status           = @runstatusmask,
  12459.                                          @minimum_retries      = @minimumretries,
  12460.                                          @oldest_first         = @oldestfirst,
  12461.                                          @mode                 = @mode
  12462.   END
  12463.   ELSE
  12464.   BEGIN
  12465.     INSERT INTO #task_history_quick
  12466.     EXECUTE msdb.dbo.sp_help_jobhistory  @job_id               = @job_id,
  12467.                                          @sql_message_id       = @messageid,
  12468.                                          @sql_severity         = @severity,
  12469.                                          @start_run_date       = @startdate,
  12470.                                          @end_run_date         = @enddate,
  12471.                                          @start_run_time       = @starttime,
  12472.                                          @end_run_time         = @endtime,
  12473.                                          @minimum_run_duration = @minimumrunduration,
  12474.                                          @run_status           = @runstatusmask,
  12475.                                          @minimum_retries      = @minimumretries,
  12476.                                          @oldest_first         = @oldestfirst,
  12477.                                          @mode                 = @mode
  12478.   END
  12479.  
  12480.   IF (@mode = 'FULL')
  12481.   BEGIN
  12482.     SELECT id                = sti.task_id,
  12483.            eventid           = 0,
  12484.            messageid         = sql_message_id,
  12485.            severity          = sql_severity,
  12486.            taskname          = job_name,
  12487.            source            = '',
  12488.            category          = '',
  12489.            runstatus         = run_status,
  12490.            rundate           = run_date,
  12491.            runtime           = run_time,
  12492.            runduration       = run_duration,
  12493.            reviewstatus      = 0,
  12494.            emailoperatorname = operator_emailed,
  12495.            retries           = retries_attempted,
  12496.            comments          = message,
  12497.            timesskipped      = 0
  12498.     FROM #task_history_full thf,
  12499.          systaskids         sti
  12500.     WHERE (thf.job_id = sti.job_id)
  12501.   END
  12502.   ELSE
  12503.   BEGIN
  12504.     SELECT taskname          = job_name,
  12505.            source            = '',
  12506.            runstatus         = run_status,
  12507.            rundate           = run_date,
  12508.            runtime           = run_time,
  12509.            runduration       = run_duration,
  12510.            emailoperatorname = operator_emailed,
  12511.            retries           = retries_attempted
  12512.     FROM #task_history_quick
  12513.   END
  12514. END
  12515. go
  12516.  
  12517. /**************************************************************/
  12518. /* SP_PURGEHISTORY (Replication doesn't need this - It is     */
  12519. /* here for completeness only)                                */
  12520. /**************************************************************/
  12521.  
  12522. PRINT ''
  12523. PRINT 'Creating [legacy] procedure sp_purgehistory...'
  12524. go
  12525. IF (EXISTS (SELECT *
  12526.             FROM msdb.dbo.sysobjects
  12527.             WHERE (name = N'sp_purgehistory')
  12528.               AND (type = 'P')))
  12529.   DROP PROCEDURE sp_purgehistory
  12530. go
  12531. CREATE PROCEDURE sp_purgehistory
  12532.   @taskname sysname = NULL, -- Was VARCHAR(100) in 6.x
  12533.   @taskid   INT     = NULL
  12534. AS
  12535. BEGIN
  12536.   DECLARE @job_id UNIQUEIDENTIFIER
  12537.  
  12538.   SET NOCOUNT ON
  12539.  
  12540.   -- If the name is supplied, get the job_id directly from sysjobs
  12541.   IF (@taskname IS NOT NULL)
  12542.   BEGIN
  12543.     SELECT @job_id = job_id
  12544.     FROM msdb.dbo.sysjobs_view
  12545.     WHERE (name = @taskname)
  12546.  
  12547.     -- Check if the name is ambiguous
  12548.     IF (@@rowcount > 1)
  12549.     BEGIN
  12550.       RAISERROR(14292, -1, -1, @taskname, '@taskid', '@taskname')
  12551.       RETURN(1) -- Failure
  12552.     END
  12553.  
  12554.     IF (@job_id IS NULL)
  12555.     BEGIN
  12556.       RAISERROR(14262, -1, -1, '@taskname', @taskname)
  12557.       RETURN(1) -- Failure
  12558.     END
  12559.   END
  12560.  
  12561.   -- If the id is supplied lookup the corresponding job_id from systaskids
  12562.   IF (@taskid IS NOT NULL)
  12563.   BEGIN
  12564.     SELECT @job_id = job_id
  12565.     FROM msdb.dbo.systaskids
  12566.     WHERE (task_id = @taskid)
  12567.  
  12568.     -- Check that the job still exists
  12569.     IF (NOT EXISTS (SELECT *
  12570.                     FROM msdb.dbo.sysjobs_view
  12571.                     WHERE (job_id = @job_id)))
  12572.     BEGIN
  12573.       SELECT @taskname = CONVERT(NVARCHAR, @taskid)
  12574.       RAISERROR(14262, -1, -1, '@taskid', @taskname)
  12575.       RETURN(1) -- Failure
  12576.     END
  12577.   END
  12578.  
  12579.   EXECUTE sp_purge_jobhistory @job_id = @job_id
  12580. END
  12581. go
  12582.  
  12583.  
  12584. /**************************************************************/
  12585. /*                                                            */
  12586. /*         E  R  R  O  R    M  E  S  S  A  G  E  S            */
  12587. /*                                                            */
  12588. /*  These are now created by MESSAGES.SQL.                    */
  12589. /*                                                            */
  12590. /*  NOTE: 14255 and 14265 are called by dynamic SQL generated */
  12591. /*        by SQLServerAgent.                                  */
  12592. /**************************************************************/
  12593.  
  12594.  
  12595. /**************************************************************/
  12596. /*                                                            */
  12597. /*                   T  R  I  G  G  E  R  S                   */
  12598. /*                                                            */
  12599. /**************************************************************/
  12600.  
  12601. /**************************************************************/
  12602. /* TRIG_TARGETSERVER_INSERT                                   */
  12603. /**************************************************************/
  12604.  
  12605. PRINT ''
  12606. PRINT 'Creating trigger trig_targetserver_insert...'
  12607. go
  12608. IF (EXISTS (SELECT *
  12609.             FROM msdb.dbo.sysobjects
  12610.             WHERE (name = N'trig_targetserver_insert')
  12611.               AND (type = 'TR')))
  12612.   DROP TRIGGER dbo.trig_targetserver_insert
  12613. go
  12614. CREATE TRIGGER trig_targetserver_insert
  12615. ON msdb.dbo.systargetservers
  12616. FOR INSERT, DELETE
  12617. AS
  12618. BEGIN
  12619.   SET NOCOUNT ON
  12620.  
  12621.   -- Disallow the insert if the server is called 'ALL'
  12622.   -- NOTE: We have to do this check here in the trigger since there is no sp_add_targetserver
  12623.   --       (target servers insert a row for themselves when they 'enlist' in an MSX)
  12624.   IF (EXISTS (SELECT *
  12625.               FROM inserted
  12626.               WHERE (server_name = N'ALL')))
  12627.   BEGIN
  12628.     DELETE FROM msdb.dbo.systargetservers
  12629.     WHERE (server_name = N'ALL')
  12630.     RAISERROR(14271, -1, -1, 'ALL')
  12631.     RETURN
  12632.   END
  12633.  
  12634.   -- Set (or delete) the registy flag (so that SETUP can detect if we're an MSX)
  12635.   IF ((SELECT COUNT(*)
  12636.        FROM msdb.dbo.systargetservers) = 0)
  12637.   BEGIN
  12638.     DECLARE @val INT
  12639.  
  12640.     EXECUTE master.dbo.xp_regread N'HKEY_LOCAL_MACHINE',
  12641.                                   N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
  12642.                                   N'MSXServer',
  12643.                                   @val OUTPUT, 
  12644.                                   N'no_output'
  12645.     IF (@val IS NOT NULL)
  12646.       EXECUTE master.dbo.xp_regdeletevalue N'HKEY_LOCAL_MACHINE',
  12647.                                            N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
  12648.                                            N'MSXServer'
  12649.   END
  12650.   ELSE
  12651.     EXECUTE master.dbo.xp_regwrite N'HKEY_LOCAL_MACHINE',
  12652.                                    N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
  12653.                                    N'MSXServer',
  12654.                                    N'REG_DWORD',
  12655.                                    1
  12656. END
  12657. go
  12658.  
  12659. DUMP TRANSACTION msdb WITH NO_LOG
  12660. go
  12661. CHECKPOINT
  12662. go
  12663.  
  12664.  
  12665.  
  12666. /**************************************************************/
  12667. /**                                                          **/
  12668. /**          A L E R T S  A N D  O P E R A T O R S           **/
  12669. /**                                                          **/
  12670. /**************************************************************/
  12671.  
  12672. /**************************************************************/
  12673. /*                                                            */
  12674. /*        C  O  R  E     P  R  O  C  E  D  U  R  E  S         */
  12675. /*                                                            */
  12676. /**************************************************************/
  12677.  
  12678. DUMP TRANSACTION msdb WITH NO_LOG
  12679. go
  12680.  
  12681. /**************************************************************/
  12682. /* SP_VERIFY_PERFORMANCE_CONDITION                            */
  12683. /**************************************************************/
  12684.  
  12685. PRINT ''
  12686. PRINT 'Creating procedure sp_verify_performance_condition...'
  12687. go
  12688. IF (EXISTS (SELECT *
  12689.             FROM msdb.dbo.sysobjects
  12690.             WHERE (name = N'sp_verify_performance_condition')
  12691.               AND (type = 'P')))
  12692.   DROP PROCEDURE sp_verify_performance_condition
  12693. go
  12694. CREATE PROCEDURE sp_verify_performance_condition
  12695.   @performance_condition NVARCHAR(512)
  12696. AS
  12697. BEGIN
  12698.   DECLARE @delimiter_count INT
  12699.   DECLARE @temp_str        NVARCHAR(512)
  12700.   DECLARE @object_name     sysname
  12701.   DECLARE @counter_name    sysname
  12702.   DECLARE @instance_name   sysname
  12703.   DECLARE @pos             INT
  12704.   
  12705.   SET NOCOUNT ON
  12706.  
  12707.   -- The performance condition must have the format 'object|counter|instance|comparator|value'
  12708.   -- NOTE: 'instance' may be empty.
  12709.   IF (PATINDEX(N'%_|%_|%|[><=]|[0-9]%', @performance_condition) = 0)
  12710.   BEGIN
  12711.     RAISERROR(14507, 16, 1)
  12712.     RETURN(1) -- Failure
  12713.   END
  12714.  
  12715.   -- Parse the performance_condition
  12716.   SELECT @delimiter_count = 0
  12717.   SELECT @temp_str = @performance_condition
  12718.   SELECT @pos = CHARINDEX(N'|', @temp_str)
  12719.   WHILE (@pos <> 0)
  12720.   BEGIN
  12721.     SELECT @delimiter_count = @delimiter_count + 1
  12722.     IF (@delimiter_count = 1) SELECT @object_name = SUBSTRING(@temp_str, 1, @pos - 1)
  12723.     IF (@delimiter_count = 2) SELECT @counter_name = SUBSTRING(@temp_str, 1, @pos - 1)
  12724.     IF (@delimiter_count = 3) SELECT @instance_name = SUBSTRING(@temp_str, 1, @pos - 1)
  12725.     SELECT @temp_str = SUBSTRING(@temp_str, @pos + 1, (DATALENGTH(@temp_str) / 2) - @pos)
  12726.     SELECT @pos = CHARINDEX(N'|', @temp_str)
  12727.   END
  12728.   IF (@delimiter_count <> 4)
  12729.   BEGIN
  12730.     RAISERROR(14507, 16, 1)
  12731.     RETURN(1) -- Failure
  12732.   END
  12733.  
  12734.   -- Check the object_name
  12735.   IF (NOT EXISTS (SELECT *
  12736.                   FROM master.dbo.sysperfinfo
  12737.                   WHERE (object_name = @object_name)))
  12738.   BEGIN
  12739.     RAISERROR(14262, 16, 1, 'object_name', @object_name)
  12740.     RETURN(1) -- Failure
  12741.   END
  12742.  
  12743.   -- Check the counter_name
  12744.   IF (NOT EXISTS (SELECT *
  12745.                   FROM master.dbo.sysperfinfo
  12746.                   WHERE (object_name = @object_name)
  12747.                     AND (counter_name = @counter_name)))
  12748.   BEGIN
  12749.     RAISERROR(14262, 16, 1, 'counter_name', @counter_name)
  12750.     RETURN(1) -- Failure
  12751.   END
  12752.  
  12753.   -- Check the instance_name
  12754.   IF (@instance_name IS NOT NULL)
  12755.   BEGIN
  12756.     IF (NOT EXISTS (SELECT *
  12757.                     FROM master.dbo.sysperfinfo
  12758.                     WHERE (object_name = @object_name)
  12759.                       AND (counter_name = @counter_name)
  12760.                       AND (instance_name = @instance_name)))
  12761.     BEGIN
  12762.       RAISERROR(14262, 16, 1, 'instance_name', @instance_name)
  12763.       RETURN(1) -- Failure
  12764.     END
  12765.   END
  12766.  
  12767.   RETURN(0) -- Success
  12768. END
  12769. go
  12770.  
  12771. /**************************************************************/
  12772. /* SP_VERIFY_ALERT                                            */
  12773. /**************************************************************/
  12774.  
  12775. PRINT ''
  12776. PRINT 'Creating procedure sp_verify_alert...'
  12777. go
  12778. IF (EXISTS (SELECT *
  12779.             FROM msdb.dbo.sysobjects
  12780.             WHERE (name = N'sp_verify_alert')
  12781.               AND (type = 'P')))
  12782.   DROP PROCEDURE sp_verify_alert
  12783. go
  12784. CREATE PROCEDURE sp_verify_alert
  12785.   @name                          sysname,
  12786.   @message_id                    INT,
  12787.   @severity                      INT,
  12788.   @enabled                       TINYINT,
  12789.   @delay_between_responses       INT,
  12790.   @notification_message          NVARCHAR(512),
  12791.   @include_event_description_in  TINYINT,
  12792.   @database_name                 sysname,
  12793.   @event_description_keyword     NVARCHAR(100),
  12794.   @job_id                        UNIQUEIDENTIFIER OUTPUT,
  12795.   @job_name                      sysname          OUTPUT,
  12796.   @occurrence_count              INT,
  12797.   @raise_snmp_trap               TINYINT,
  12798.   @performance_condition         NVARCHAR(512),
  12799.   @category_name                 sysname,
  12800.   @category_id                   INT              OUTPUT,
  12801.   @count_reset_date              INT,
  12802.   @count_reset_time              INT
  12803. AS
  12804. BEGIN
  12805.   DECLARE @retval               INT
  12806.   DECLARE @non_alertable_errors VARCHAR(512)
  12807.   DECLARE @message_id_as_string VARCHAR(10)
  12808.   DECLARE @res_valid_range      NVARCHAR(100)
  12809.  
  12810.   SET NOCOUNT ON
  12811.  
  12812.   -- Remove any leading/trailing spaces from parameters
  12813.   SELECT @name                      = LTRIM(RTRIM(@name))
  12814.   SELECT @notification_message      = LTRIM(RTRIM(@notification_message))
  12815.   SELECT @database_name             = LTRIM(RTRIM(@database_name))
  12816.   SELECT @event_description_keyword = LTRIM(RTRIM(@event_description_keyword))
  12817.   SELECT @job_name                  = LTRIM(RTRIM(@job_name))
  12818.   SELECT @performance_condition     = LTRIM(RTRIM(@performance_condition))
  12819.   SELECT @category_name             = LTRIM(RTRIM(@category_name))
  12820.  
  12821.   -- Only a sysadmin can do this
  12822.   IF (ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) <> 1)
  12823.   BEGIN
  12824.     RAISERROR(15003, 16, 1, N'sysadmin')
  12825.     RETURN(1) -- Failure
  12826.   END
  12827.  
  12828.   -- Check if the NewName is unique
  12829.   IF (EXISTS (SELECT *
  12830.               FROM msdb.dbo.sysalerts
  12831.               WHERE (name = @name)))
  12832.   BEGIN
  12833.     RAISERROR(14261, 16, 1, '@name', @name)
  12834.     RETURN(1) -- Failure
  12835.   END
  12836.  
  12837.   -- Check if the user has supplied MessageID OR Severity OR Performance-Condition
  12838.   IF ((@performance_condition IS NULL)     AND ((@message_id = 0) AND (@severity = 0)) OR ((@message_id <> 0) AND (@severity <> 0))) OR
  12839.      ((@performance_condition IS NOT NULL) AND ((@message_id <> 0) OR (@severity <> 0)))
  12840.   BEGIN
  12841.     RAISERROR(14500, 16, 1)
  12842.     RETURN(1) -- Failure
  12843.   END
  12844.  
  12845.   -- Check the Severity
  12846.   IF ((@severity < 0) OR (@severity > 25))
  12847.   BEGIN
  12848.     RAISERROR(14266, 16, 1, '@severity', '0..25')
  12849.     RETURN(1) -- Failure
  12850.   END
  12851.  
  12852.   -- Check the MessageID
  12853.   IF (@message_id <> 0) AND 
  12854.      (NOT EXISTS (SELECT error
  12855.                   FROM master.dbo.sysmessages
  12856.                   WHERE (error = @message_id)))
  12857.   BEGIN
  12858.     SELECT @message_id_as_string = CONVERT(VARCHAR, @message_id)
  12859.     RAISERROR(14262, 16, 1, '@message_id', @message_id_as_string)
  12860.     RETURN(1) -- Failure
  12861.   END
  12862.  
  12863.   -- Check if it is legal to set an alert on this MessageID
  12864.   CREATE TABLE #TempRetVal (RetVal INT)
  12865.   EXECUTE master.dbo.xp_regread N'HKEY_LOCAL_MACHINE',
  12866.                                 N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
  12867.                                 N'NonAlertableErrors',
  12868.                                  @non_alertable_errors OUTPUT,
  12869.                                 N'no_output'
  12870.   IF (ISNULL(@non_alertable_errors, N'NULL') <> N'NULL')
  12871.   BEGIN
  12872.     DECLARE @message_id_as_char VARCHAR(10)
  12873.  
  12874.     SELECT @message_id_as_char = CONVERT(VARCHAR(10), @message_id)
  12875.     INSERT INTO #TempRetVal
  12876.     EXECUTE ('IF (' + @message_id_as_char + ' IN (' + @non_alertable_errors + ')) SELECT 1')
  12877.   END
  12878.  
  12879.   IF (EXISTS (SELECT *
  12880.               FROM #TempRetVal))
  12881.   BEGIN
  12882.     RAISERROR(14506, 16, 1, @message_id)
  12883.     RETURN(1) -- Failure
  12884.   END
  12885.  
  12886.   DROP TABLE #TempRetVal
  12887.  
  12888.   -- Enabled must be 0 or 1
  12889.   IF (@enabled NOT IN (0, 1))
  12890.   BEGIN
  12891.     RAISERROR(14266, 16, 1, '@enabled', '0, 1')
  12892.     RETURN(1) -- Failure
  12893.   END
  12894.  
  12895.   -- DelayBetweenResponses must be > 0
  12896.   IF (@delay_between_responses < 0)
  12897.   BEGIN
  12898.     SELECT @res_valid_range = FORMATMESSAGE(14206)
  12899.     RAISERROR(14266, 16, 1, '@delay_between_responses', @res_valid_range)
  12900.     RETURN(1) -- Failure
  12901.   END
  12902.  
  12903.   -- NOTE: We don't check the notification message
  12904.  
  12905.   -- Check IncludeEventDescriptionIn
  12906.   IF ((@include_event_description_in < 0) OR (@include_event_description_in > 7))
  12907.   BEGIN
  12908.     SELECT @res_valid_range = FORMATMESSAGE(14208)
  12909.     RAISERROR(14266, 16, 1, '@include_event_description_in', @res_valid_range)
  12910.     RETURN(1) -- Failure
  12911.   END
  12912.  
  12913.   -- Check the database name
  12914.   IF (@database_name IS NOT NULL) AND (DB_ID(@database_name) IS NULL)
  12915.   BEGIN
  12916.     RAISERROR(15010, 16, 1, @database_name)
  12917.     RETURN(1) -- Failure
  12918.   END
  12919.  
  12920.   -- NOTE: We don't check the event description keyword
  12921.  
  12922.   -- Check JobName/ID
  12923.   IF ((@job_id IS NOT NULL) OR (@job_name IS NOT NULL))
  12924.   BEGIN
  12925.     -- We use '' as a special value which means 'no job' (we cannot use NULL since this forces
  12926.     -- sp_update_alert to use the existing value)
  12927.     IF (@job_name = N'')
  12928.       SELECT @job_id = 0x00
  12929.     ELSE
  12930.     BEGIN
  12931.       EXECUTE @retval = sp_verify_job_identifiers '@job_name',
  12932.                                                   '@job_id',
  12933.                                                    @job_name OUTPUT,
  12934.                                                    @job_id   OUTPUT
  12935.       IF (@retval <> 0)
  12936.         RETURN(1) -- Failure
  12937.       -- Check that the job is a local job
  12938.       IF (NOT EXISTS (SELECT *
  12939.                       FROM msdb.dbo.sysjobservers
  12940.                       WHERE (job_id = @job_id)
  12941.                         AND (server_id = 0)))
  12942.       BEGIN
  12943.         RAISERROR(14234, -1, -1, '@job_id', 'sp_help_job @job_type = ''LOCAL''')
  12944.         RETURN(1) -- Failure
  12945.       END
  12946.     END
  12947.   END
  12948.  
  12949.   -- OccurrenceCount must be > 0
  12950.   IF (@occurrence_count < 0)
  12951.   BEGIN
  12952.     RAISERROR(14266, 16, 1, '@occurrence_count', '0..n')
  12953.     RETURN(1) -- Failure
  12954.   END
  12955.  
  12956.   -- RaiseSNMPTrap must be 0 or 1
  12957.   IF (@raise_snmp_trap NOT IN (0, 1))
  12958.   BEGIN
  12959.     RAISERROR(14266, 16, 1, '@raise_snmp_trap', '0, 1')
  12960.     RETURN(1) -- Failure
  12961.   END
  12962.  
  12963.   -- Check the performance condition (including invalid parameter combinations)
  12964.   IF (@performance_condition IS NOT NULL)
  12965.   BEGIN
  12966.     IF (@database_name IS NOT NULL)
  12967.     BEGIN
  12968.       RAISERROR(14505, 16, 1, 'database_name')
  12969.       RETURN(1) -- Failure
  12970.     END
  12971.  
  12972.     IF (@event_description_keyword IS NOT NULL)
  12973.     BEGIN
  12974.       RAISERROR(14505, 16, 1, 'event_description_keyword')
  12975.       RETURN(1) -- Failure
  12976.     END
  12977.  
  12978.     -- Verify the performance condition
  12979.     EXECUTE @retval = msdb.dbo.sp_verify_performance_condition @performance_condition
  12980.     IF (@retval <> 0)
  12981.       RETURN(1) -- Failure
  12982.   END
  12983.  
  12984.   -- Check category name
  12985.   IF (@category_name = N'[DEFAULT]')
  12986.     SELECT @category_id = 98
  12987.   ELSE
  12988.   BEGIN
  12989.     SELECT @category_id = category_id
  12990.     FROM msdb.dbo.syscategories
  12991.     WHERE (category_class = 2) -- Alerts
  12992.       AND (category_type = 3) -- None
  12993.       AND (name = @category_name)
  12994.   END
  12995.   IF (@category_id IS NULL)
  12996.   BEGIN
  12997.     RAISERROR(14262, -1, -1, '@category_name', @category_name)
  12998.     RETURN(1) -- Failure
  12999.   END
  13000.  
  13001.   -- Check count reset date
  13002.   IF (@count_reset_date <> 0)
  13003.   BEGIN
  13004.     EXECUTE @retval = msdb.dbo.sp_verify_job_date @count_reset_date, '@count_reset_date'
  13005.     IF (@retval <> 0)
  13006.       RETURN(1) -- Failure
  13007.   END
  13008.  
  13009.   -- Check count reset time
  13010.   IF (@count_reset_time <> 0)
  13011.   BEGIN
  13012.     EXECUTE @retval = msdb.dbo.sp_verify_job_time @count_reset_time, '@count_reset_time'
  13013.     IF (@retval <> 0)
  13014.       RETURN(1) -- Failure
  13015.   END
  13016.  
  13017.   RETURN(0) -- Success
  13018. END
  13019. go
  13020.  
  13021. /**************************************************************/
  13022. /* SP_ADD_ALERT                                               */
  13023. /**************************************************************/
  13024.  
  13025. PRINT ''
  13026. PRINT 'Creating procedure sp_add_alert...'
  13027. go
  13028. IF (EXISTS (SELECT *
  13029.             FROM msdb.dbo.sysobjects
  13030.             WHERE (name = N'sp_add_alert')
  13031.               AND (type = 'P')))
  13032.   DROP PROCEDURE sp_add_alert
  13033. go
  13034. CREATE PROCEDURE sp_add_alert
  13035.   @name                         sysname,
  13036.   @message_id                   INT              = 0,
  13037.   @severity                     INT              = 0,
  13038.   @enabled                      TINYINT          = 1,
  13039.   @delay_between_responses      INT              = 0,
  13040.   @notification_message         NVARCHAR(512)    = NULL,
  13041.   @include_event_description_in TINYINT          = 5,    -- 0 = None, 1 = Email, 2 = Pager, 4 = NetSend, 7 = All
  13042.   @database_name                sysname          = NULL,
  13043.   @event_description_keyword    NVARCHAR(100)    = NULL,
  13044.   @job_id                       UNIQUEIDENTIFIER = NULL, -- If provided must NOT also provide job_name
  13045.   @job_name                     sysname          = NULL, -- If provided must NOT also provide job_id
  13046.   @raise_snmp_trap              TINYINT          = 0,
  13047.   @performance_condition        NVARCHAR(512)    = NULL, -- New for 7.0
  13048.   @category_name                sysname          = NULL  -- New for 7.0
  13049. AS
  13050. BEGIN
  13051.   DECLARE @event_source           NVARCHAR(100)
  13052.   DECLARE @event_category_id      INT
  13053.   DECLARE @event_id               INT
  13054.   DECLARE @last_occurrence_date   INT
  13055.   DECLARE @last_occurrence_time   INT
  13056.   DECLARE @last_notification_date INT
  13057.   DECLARE @last_notification_time INT
  13058.   DECLARE @occurrence_count       INT
  13059.   DECLARE @count_reset_date       INT
  13060.   DECLARE @count_reset_time       INT
  13061.   DECLARE @has_notification       INT
  13062.   DECLARE @return_code            INT
  13063.   DECLARE @duplicate_name         sysname
  13064.   DECLARE @category_id            INT
  13065.   DECLARE @alert_id               INT
  13066.  
  13067.   SET NOCOUNT ON
  13068.  
  13069.   -- Remove any leading/trailing spaces from parameters
  13070.   SELECT @name                      = LTRIM(RTRIM(@name))
  13071.   SELECT @notification_message      = LTRIM(RTRIM(@notification_message))
  13072.   SELECT @database_name             = LTRIM(RTRIM(@database_name))
  13073.   SELECT @event_description_keyword = LTRIM(RTRIM(@event_description_keyword))
  13074.   SELECT @job_name                  = LTRIM(RTRIM(@job_name))
  13075.   SELECT @performance_condition     = LTRIM(RTRIM(@performance_condition))
  13076.   SELECT @category_name             = LTRIM(RTRIM(@category_name))
  13077.  
  13078.   -- Turn [nullable] empty string parameters into NULLs
  13079.   IF (@notification_message      = N'') SELECT @notification_message = NULL
  13080.   IF (@database_name             = N'') SELECT @database_name = NULL
  13081.   IF (@event_description_keyword = N'') SELECT @event_description_keyword = NULL
  13082.   IF (@job_name                  = N'') SELECT @job_name = NULL
  13083.   IF (@performance_condition     = N'') SELECT @performance_condition = NULL
  13084.   IF (@category_name             = N'') SELECT @category_name = NULL
  13085.  
  13086.   SELECT @message_id = ISNULL(@message_id, 0)
  13087.   SELECT @severity = ISNULL(@severity, 0)
  13088.  
  13089.   -- Only a sysadmin can do this
  13090.   IF (ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) <> 1)
  13091.   BEGIN
  13092.     RAISERROR(15003, 16, 1, N'sysadmin')
  13093.     RETURN(1) -- Failure
  13094.   END
  13095.  
  13096.   -- Check if SQLServerAgent is in the process of starting
  13097.   EXECUTE @return_code = msdb.dbo.sp_is_sqlagent_starting
  13098.   IF (@return_code <> 0)
  13099.     RETURN(1) -- Failure
  13100.  
  13101.   -- Hard-code the new Alert defaults
  13102.   SELECT @event_source = N'MSSQLServer'
  13103.   SELECT @event_category_id = NULL
  13104.   SELECT @event_id = NULL
  13105.   SELECT @last_occurrence_date = 0
  13106.   SELECT @last_occurrence_time = 0
  13107.   SELECT @last_notification_date = 0
  13108.   SELECT @last_notification_time = 0
  13109.   SELECT @occurrence_count = 0
  13110.   SELECT @count_reset_date = 0
  13111.   SELECT @count_reset_time = 0
  13112.   SELECT @has_notification = 0
  13113.  
  13114.   IF (@category_name IS NULL)
  13115.   BEGIN
  13116.     SELECT @category_name = name
  13117.     FROM msdb.dbo.syscategories
  13118.     WHERE (category_id = 98)
  13119.   END
  13120.  
  13121.   -- Map a job_id of 0 to the real value we use to mean 'no job'
  13122.   IF (@job_id = CONVERT(UNIQUEIDENTIFIER, 0x00)) AND (@job_name IS NULL)
  13123.     SELECT @job_name = N''
  13124.  
  13125.   -- Verify the Alert
  13126.   IF (@job_id = CONVERT(UNIQUEIDENTIFIER, 0x00))
  13127.     SELECT @job_id = NULL
  13128.   EXECUTE @return_code = sp_verify_alert @name,
  13129.                                          @message_id,
  13130.                                          @severity,
  13131.                                          @enabled,
  13132.                                          @delay_between_responses,
  13133.                                          @notification_message,
  13134.                                          @include_event_description_in,
  13135.                                          @database_name,
  13136.                                          @event_description_keyword,
  13137.                                          @job_id OUTPUT,
  13138.                                          @job_name OUTPUT,
  13139.                                          @occurrence_count,
  13140.                                          @raise_snmp_trap,
  13141.                                          @performance_condition,
  13142.                                          @category_name,
  13143.                                          @category_id OUTPUT,
  13144.                                          @count_reset_date,
  13145.                                          @count_reset_time
  13146.   IF (@return_code <> 0)
  13147.     RETURN(1) -- Failure
  13148.  
  13149.   -- Check if this Alert already exists
  13150.   SELECT @duplicate_name = FORMATMESSAGE(14205)
  13151.   SELECT @duplicate_name = name
  13152.   FROM msdb.dbo.sysalerts
  13153.   WHERE (ISNULL(performance_condition, N'apples') = ISNULL(@performance_condition, N'oranges'))
  13154.      OR ((performance_condition IS NULL) AND
  13155.          (message_id = @message_id) AND
  13156.          (severity = @severity) AND
  13157.          (ISNULL(database_name, N'') = ISNULL(@database_name, N'')) AND
  13158.          (ISNULL(event_description_keyword, N'') = ISNULL(@event_description_keyword, N'')))
  13159.   IF (@duplicate_name <> FORMATMESSAGE(14205))
  13160.   BEGIN
  13161.     RAISERROR(14501, 16, 1, @duplicate_name)
  13162.     RETURN(1) -- Failure
  13163.   END
  13164.  
  13165.   -- Finally, do the actual INSERT
  13166.   INSERT INTO msdb.dbo.sysalerts
  13167.          (name,
  13168.           event_source,
  13169.           event_category_id,
  13170.           event_id,
  13171.           message_id,
  13172.           severity,
  13173.           enabled,
  13174.           delay_between_responses,
  13175.           last_occurrence_date,
  13176.           last_occurrence_time,
  13177.           last_response_date,
  13178.           last_response_time,
  13179.           notification_message,
  13180.           include_event_description,
  13181.           database_name,
  13182.           event_description_keyword,
  13183.           occurrence_count,
  13184.           count_reset_date,
  13185.           count_reset_time,
  13186.           job_id,
  13187.           has_notification,
  13188.           flags,
  13189.           performance_condition,
  13190.           category_id)
  13191.   VALUES (@name,
  13192.           @event_source,
  13193.           @event_category_id,
  13194.           @event_id,
  13195.           @message_id,
  13196.           @severity,
  13197.           @enabled,
  13198.           @delay_between_responses,
  13199.           @last_occurrence_date,
  13200.           @last_occurrence_time,
  13201.           @last_notification_date,
  13202.           @last_notification_time,
  13203.           @notification_message,
  13204.           @include_event_description_in,
  13205.           @database_name,
  13206.           @event_description_keyword,
  13207.           @occurrence_count,
  13208.           @count_reset_date,
  13209.           @count_reset_time,
  13210.           ISNULL(@job_id, CONVERT(UNIQUEIDENTIFIER, 0x00)),
  13211.           @has_notification,
  13212.           @raise_snmp_trap,
  13213.           @performance_condition,
  13214.           @category_id)
  13215.  
  13216.   -- Notify SQLServerAgent of the change
  13217.   SELECT @alert_id = id
  13218.   FROM msdb.dbo.sysalerts
  13219.   WHERE (name = @name)
  13220.   EXECUTE msdb.dbo.sp_sqlagent_notify @op_type     = N'A',
  13221.                                       @alert_id    = @alert_id,
  13222.                                       @action_type = N'I'
  13223.   RETURN(0) -- Success
  13224. END
  13225. go
  13226.  
  13227. /**************************************************************/
  13228. /* SP_UPDATE_ALERT                                            */
  13229. /**************************************************************/
  13230.  
  13231. PRINT ''
  13232. PRINT 'Creating procedure sp_update_alert...'
  13233. go
  13234. IF (EXISTS (SELECT *
  13235.             FROM msdb.dbo.sysobjects
  13236.             WHERE (name = N'sp_update_alert')
  13237.               AND (type = 'P')))
  13238.   DROP PROCEDURE sp_update_alert
  13239. go
  13240. CREATE PROCEDURE sp_update_alert
  13241.   @name                         sysname,
  13242.   @new_name                     sysname          = NULL,
  13243.   @enabled                      TINYINT          = NULL,
  13244.   @message_id                   INT              = NULL,
  13245.   @severity                     INT              = NULL,
  13246.   @delay_between_responses      INT              = NULL,
  13247.   @notification_message         NVARCHAR(512)    = NULL,
  13248.   @include_event_description_in TINYINT          = NULL, -- 0 = None, 1 = Email, 2 = Pager. 4 = NetSend, 7 = All
  13249.   @database_name                sysname          = NULL,
  13250.   @event_description_keyword    NVARCHAR(100)    = NULL,
  13251.   @job_id                       UNIQUEIDENTIFIER = NULL, -- If provided must NOT also provide job_name
  13252.   @job_name                     sysname          = NULL, -- If provided must NOT also provide job_id
  13253.   @occurrence_count             INT              = NULL, -- Can only be set to 0
  13254.   @count_reset_date             INT              = NULL, 
  13255.   @count_reset_time             INT              = NULL, 
  13256.   @last_occurrence_date         INT              = NULL, -- Can only be set to 0
  13257.   @last_occurrence_time         INT              = NULL, -- Can only be set to 0
  13258.   @last_response_date           INT              = NULL, -- Can only be set to 0
  13259.   @last_response_time           INT              = NULL, -- Can only be set to 0
  13260.   @raise_snmp_trap              TINYINT          = NULL,
  13261.   @performance_condition        NVARCHAR(512)    = NULL, -- New for 7.0
  13262.   @category_name                sysname          = NULL  -- New for 7.0
  13263. AS
  13264. BEGIN
  13265.   DECLARE @x_enabled                   TINYINT
  13266.   DECLARE @x_message_id                INT
  13267.   DECLARE @x_severity                  INT
  13268.   DECLARE @x_delay_between_responses   INT
  13269.   DECLARE @x_notification_message      NVARCHAR(512)
  13270.   DECLARE @x_include_event_description TINYINT
  13271.   DECLARE @x_database_name             sysname
  13272.   DECLARE @x_event_description_keyword NVARCHAR(100)
  13273.   DECLARE @x_occurrence_count          INT
  13274.   DECLARE @x_count_reset_date          INT
  13275.   DECLARE @x_count_reset_time          INT
  13276.   DECLARE @x_last_occurrence_date      INT
  13277.   DECLARE @x_last_occurrence_time      INT
  13278.   DECLARE @x_last_response_date        INT
  13279.   DECLARE @x_last_response_time        INT
  13280.   DECLARE @x_flags                     INT
  13281.   DECLARE @x_performance_condition     NVARCHAR(512)
  13282.   DECLARE @x_job_id                    UNIQUEIDENTIFIER
  13283.   DECLARE @x_category_id               INT
  13284.  
  13285.   DECLARE @include_event_desc_code     TINYINT
  13286.   DECLARE @return_code                 INT
  13287.   DECLARE @duplicate_name              sysname
  13288.   DECLARE @category_id                 INT
  13289.   DECLARE @alert_id                    INT
  13290.   DECLARE @cached_attribute_modified   INT
  13291.  
  13292.   SET NOCOUNT ON
  13293.  
  13294.   -- Remove any leading/trailing spaces from parameters
  13295.   SELECT @new_name                  = LTRIM(RTRIM(@new_name))
  13296.   SELECT @job_name                  = LTRIM(RTRIM(@job_name))
  13297.   SELECT @notification_message      = LTRIM(RTRIM(@notification_message))
  13298.   SELECT @database_name             = LTRIM(RTRIM(@database_name))
  13299.   SELECT @event_description_keyword = LTRIM(RTRIM(@event_description_keyword))
  13300.   SELECT @performance_condition     = LTRIM(RTRIM(@performance_condition))
  13301.   SELECT @category_name             = LTRIM(RTRIM(@category_name))
  13302.  
  13303.   -- Are we modifying an attribute which SQLServerAgent caches?
  13304.   IF ((@new_name                     IS NOT NULL) OR
  13305.       (@enabled                      IS NOT NULL) OR
  13306.       (@message_id                   IS NOT NULL) OR
  13307.       (@severity                     IS NOT NULL) OR
  13308.       (@delay_between_responses      IS NOT NULL) OR
  13309.       (@notification_message         IS NOT NULL) OR
  13310.       (@include_event_description_in IS NOT NULL) OR
  13311.       (@database_name                IS NOT NULL) OR
  13312.       (@event_description_keyword    IS NOT NULL) OR
  13313.       (@job_id                       IS NOT NULL) OR
  13314.       (@job_name                     IS NOT NULL) OR
  13315.       (@last_response_date           IS NOT NULL) OR
  13316.       (@last_response_time           IS NOT NULL) OR
  13317.       (@raise_snmp_trap              IS NOT NULL) OR
  13318.       (@performance_condition        IS NOT NULL))
  13319.     SELECT @cached_attribute_modified = 1
  13320.   ELSE
  13321.     SELECT @cached_attribute_modified = 0
  13322.  
  13323.   -- Map a job_id of 0 to the real value we use to mean 'no job'
  13324.   IF (@job_id = CONVERT(UNIQUEIDENTIFIER, 0x00)) AND (@job_name IS NULL)
  13325.     SELECT @job_name = N''
  13326.  
  13327.   -- Only a sysadmin can do this
  13328.   IF (ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) <> 1)
  13329.   BEGIN
  13330.     RAISERROR(15003, 16, 1, N'sysadmin')
  13331.     RETURN(1)
  13332.   END
  13333.  
  13334.   -- Check if SQLServerAgent is in the process of starting
  13335.   EXECUTE @return_code = msdb.dbo.sp_is_sqlagent_starting
  13336.   IF (@return_code <> 0)
  13337.     RETURN(1) -- Failure
  13338.  
  13339.   -- Check if this Alert exists
  13340.   IF (NOT EXISTS (SELECT *
  13341.                   FROM msdb.dbo.sysalerts
  13342.                   WHERE (name = @name)))
  13343.   BEGIN
  13344.     RAISERROR(14262, 16, 1, '@name', @name)
  13345.     RETURN(1)
  13346.   END
  13347.  
  13348.   -- Certain values (if supplied) may only be updated to 0  
  13349.   IF (@occurrence_count <> 0)
  13350.   BEGIN
  13351.     RAISERROR(14266, -1, -1, '@occurrence_count', '0')
  13352.     RETURN(1) -- Failure
  13353.   END
  13354.   IF (@last_occurrence_date <> 0)
  13355.   BEGIN
  13356.     RAISERROR(14266, -1, -1, '@last_occurrence_date', '0')
  13357.     RETURN(1) -- Failure
  13358.   END
  13359.   IF (@last_occurrence_time <> 0)
  13360.   BEGIN
  13361.     RAISERROR(14266, -1, -1, '@last_occurrence_time', '0')
  13362.     RETURN(1) -- Failure
  13363.   END
  13364.   IF (@last_response_date <> 0)
  13365.   BEGIN
  13366.     RAISERROR(14266, -1, -1, '@last_response_date', '0')
  13367.     RETURN(1) -- Failure
  13368.   END
  13369.   IF (@last_response_time <> 0)
  13370.   BEGIN
  13371.     RAISERROR(14266, -1, -1, '@last_response_time', '0')
  13372.     RETURN(1) -- Failure
  13373.   END
  13374.  
  13375.   -- Get existing (@x_) values
  13376.   SELECT @alert_id                    = id,
  13377.          @x_enabled                   = enabled,
  13378.          @x_message_id                = message_id,
  13379.          @x_severity                  = severity,
  13380.          @x_delay_between_responses   = delay_between_responses,
  13381.          @x_notification_message      = notification_message,
  13382.          @x_include_event_description = include_event_description,
  13383.          @x_database_name             = database_name,
  13384.          @x_event_description_keyword = event_description_keyword,
  13385.          @x_occurrence_count          = occurrence_count,
  13386.          @x_count_reset_date          = count_reset_date,
  13387.          @x_count_reset_time          = count_reset_time,
  13388.          @x_job_id                    = job_id,
  13389.          @x_last_occurrence_date      = last_occurrence_date,
  13390.          @x_last_occurrence_time      = last_occurrence_time,
  13391.          @x_last_response_date        = last_response_date,
  13392.          @x_last_response_time        = last_response_time,
  13393.          @x_flags                     = flags,
  13394.          @x_performance_condition     = performance_condition,
  13395.          @x_category_id               = category_id
  13396.   FROM msdb.dbo.sysalerts
  13397.   WHERE (name = @name)
  13398.  
  13399.   SELECT @x_job_id = sjv.job_id
  13400.   FROM msdb.dbo.sysalerts    sa,
  13401.        msdb.dbo.sysjobs_view sjv
  13402.   WHERE (sa.job_id = sjv.job_id)
  13403.     AND (sa.name = @name)
  13404.  
  13405.   -- Fill out the values for all non-supplied parameters from the existsing values
  13406.   IF (@enabled                      IS NULL) SELECT @enabled                      = @x_enabled
  13407.   IF (@message_id                   IS NULL) SELECT @message_id                   = @x_message_id
  13408.   IF (@severity                     IS NULL) SELECT @severity                     = @x_severity
  13409.   IF (@delay_between_responses      IS NULL) SELECT @delay_between_responses      = @x_delay_between_responses
  13410.   IF (@notification_message         IS NULL) SELECT @notification_message         = @x_notification_message
  13411.   IF (@include_event_description_in IS NULL) SELECT @include_event_description_in = @x_include_event_description
  13412.   IF (@database_name                IS NULL) SELECT @database_name                = @x_database_name
  13413.   IF (@event_description_keyword    IS NULL) SELECT @event_description_keyword    = @x_event_description_keyword
  13414.   IF (@job_id IS NULL) AND (@job_name IS NULL) SELECT @job_id                     = @x_job_id
  13415.   IF (@occurrence_count             IS NULL) SELECT @occurrence_count             = @x_occurrence_count
  13416.   IF (@count_reset_date             IS NULL) SELECT @count_reset_date             = @x_count_reset_date
  13417.   IF (@count_reset_time             IS NULL) SELECT @count_reset_time             = @x_count_reset_time
  13418.   IF (@last_occurrence_date         IS NULL) SELECT @last_occurrence_date         = @x_last_occurrence_date
  13419.   IF (@last_occurrence_time         IS NULL) SELECT @last_occurrence_time         = @x_last_occurrence_time
  13420.   IF (@last_response_date           IS NULL) SELECT @last_response_date           = @x_last_response_date
  13421.   IF (@last_response_time           IS NULL) SELECT @last_response_time           = @x_last_response_time
  13422.   IF (@raise_snmp_trap              IS NULL) SELECT @raise_snmp_trap              = @x_flags & 0x1
  13423.   IF (@performance_condition        IS NULL) SELECT @performance_condition        = @x_performance_condition
  13424.   IF (@category_name                IS NULL) SELECT @category_name = name FROM msdb.dbo.syscategories WHERE (category_id = @x_category_id)
  13425.  
  13426.   IF (@category_name IS NULL)
  13427.   BEGIN
  13428.     SELECT @category_name = name
  13429.     FROM msdb.dbo.syscategories
  13430.     WHERE (category_id = 98)
  13431.   END
  13432.  
  13433.   -- Turn [nullable] empty string parameters into NULLs
  13434.   IF (@new_name                  = N'') SELECT @new_name                  = NULL
  13435.   IF (@notification_message      = N'') SELECT @notification_message      = NULL
  13436.   IF (@database_name             = N'') SELECT @database_name             = NULL
  13437.   IF (@event_description_keyword = N'') SELECT @event_description_keyword = NULL
  13438.   IF (@performance_condition     = N'') SELECT @performance_condition     = NULL
  13439.  
  13440.   -- Check if this alert would match an already existing alert
  13441.   SELECT @duplicate_name = FORMATMESSAGE(14205)
  13442.   SELECT @duplicate_name = name
  13443.   FROM msdb.dbo.sysalerts
  13444.   WHERE (ISNULL(performance_condition, N'') = ISNULL(@performance_condition, N''))
  13445.     AND (message_id = @message_id)
  13446.     AND (severity = @severity)
  13447.     AND (ISNULL(database_name, N'') = ISNULL(@database_name, N''))
  13448.     AND (ISNULL(event_description_keyword, N'') = ISNULL(@event_description_keyword, N''))
  13449.     AND (name <> @name)
  13450.   IF (@duplicate_name <> FORMATMESSAGE(14205))
  13451.   BEGIN
  13452.     RAISERROR(14501, 16, 1, @duplicate_name)
  13453.     RETURN(1) -- Failure
  13454.   END
  13455.  
  13456.   -- Verify the Alert
  13457.   IF (@job_id = CONVERT(UNIQUEIDENTIFIER, 0x00))
  13458.     SELECT @job_id = NULL
  13459.   EXECUTE @return_code = sp_verify_alert @new_name,
  13460.                                          @message_id,
  13461.                                          @severity,
  13462.                                          @enabled,
  13463.                                          @delay_between_responses,
  13464.                                          @notification_message,
  13465.                                          @include_event_description_in,
  13466.                                          @database_name,
  13467.                                          @event_description_keyword,
  13468.                                          @job_id OUTPUT,
  13469.                                          @job_name OUTPUT,
  13470.                                          @occurrence_count,
  13471.                                          @raise_snmp_trap,
  13472.                                          @performance_condition,
  13473.                                          @category_name,
  13474.                                          @category_id OUTPUT,
  13475.                                          @count_reset_date,
  13476.                                          @count_reset_time
  13477.   IF (@return_code <> 0)
  13478.     RETURN(1) -- Failure
  13479.  
  13480.   -- If the user didn't supply a NewName, use the old one.
  13481.   -- NOTE: This must be done AFTER sp_verify_alert.
  13482.   IF (@new_name IS NULL)
  13483.     SELECT @new_name = @name
  13484.  
  13485.   -- Turn the 1st 'flags' bit on or off accordingly
  13486.   IF (@raise_snmp_trap = 0)
  13487.     SELECT @x_flags = @x_flags & 0xFFFE
  13488.   ELSE
  13489.     SELECT @x_flags = @x_flags | 0x0001
  13490.  
  13491.   -- Finally, do the actual UPDATE
  13492.   UPDATE msdb.dbo.sysalerts
  13493.   SET name                        = @new_name,
  13494.       message_id                  = @message_id,
  13495.       severity                    = @severity,
  13496.       enabled                     = @enabled,
  13497.       delay_between_responses     = @delay_between_responses,
  13498.       notification_message        = @notification_message,
  13499.       include_event_description   = @include_event_description_in,
  13500.       database_name               = @database_name,
  13501.       event_description_keyword   = @event_description_keyword,
  13502.       job_id                      = ISNULL(@job_id, CONVERT(UNIQUEIDENTIFIER, 0x00)),
  13503.       occurrence_count            = @occurrence_count,
  13504.       count_reset_date            = @count_reset_date,
  13505.       count_reset_time            = @count_reset_time,
  13506.       last_occurrence_date        = @last_occurrence_date,
  13507.       last_occurrence_time        = @last_occurrence_time,
  13508.       last_response_date          = @last_response_date,
  13509.       last_response_time          = @last_response_time,
  13510.       flags                       = @x_flags,
  13511.       performance_condition       = @performance_condition,
  13512.       category_id                 = @category_id
  13513.   WHERE (name = @name)
  13514.  
  13515.   -- Notify SQLServerAgent of the change
  13516.   IF (@cached_attribute_modified = 1)
  13517.     EXECUTE msdb.dbo.sp_sqlagent_notify @op_type     = N'A',
  13518.                                         @alert_id    = @alert_id,
  13519.                                         @action_type = N'U'
  13520.   RETURN(0) -- Success
  13521. END
  13522. go
  13523.  
  13524. /**************************************************************/
  13525. /* SP_DELETE_ALERT                                            */
  13526. /**************************************************************/
  13527.  
  13528. PRINT ''
  13529. PRINT 'Creating procedure sp_delete_alert...'
  13530. go
  13531. IF (EXISTS (SELECT *
  13532.             FROM msdb.dbo.sysobjects
  13533.             WHERE (name = N'sp_delete_alert')
  13534.               AND (type = 'P')))
  13535.   DROP PROCEDURE sp_delete_alert
  13536. go
  13537. CREATE PROCEDURE sp_delete_alert
  13538.   @name sysname
  13539. AS
  13540. BEGIN
  13541.   DECLARE @alert_id    INT
  13542.   DECLARE @return_code INT
  13543.  
  13544.   SET NOCOUNT ON
  13545.  
  13546.   -- Remove any leading/trailing spaces from parameters
  13547.   SELECT @name = LTRIM(RTRIM(@name))
  13548.  
  13549.   -- Only a sysadmin can do this
  13550.   IF (ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) <> 1)
  13551.   BEGIN
  13552.     RAISERROR(15003, 16, 1, N'sysadmin')
  13553.     RETURN(1) -- Failure
  13554.   END
  13555.  
  13556.   -- Check if SQLServerAgent is in the process of starting
  13557.   EXECUTE @return_code = msdb.dbo.sp_is_sqlagent_starting
  13558.   IF (@return_code <> 0)
  13559.     RETURN(1) -- Failure
  13560.  
  13561.   -- Check if this Alert exists
  13562.   IF (NOT EXISTS (SELECT *
  13563.                   FROM msdb.dbo.sysalerts
  13564.                   WHERE (name = @name)))
  13565.   BEGIN
  13566.     RAISERROR(14262, 16, 1, '@name', @name)
  13567.     RETURN(1) -- Failure
  13568.   END
  13569.  
  13570.   -- Convert the Name to it's ID
  13571.   SELECT @alert_id = id
  13572.   FROM msdb.dbo.sysalerts
  13573.   WHERE (name = @name)
  13574.  
  13575.   BEGIN TRANSACTION
  13576.  
  13577.     -- Delete sysnotifications entries
  13578.     DELETE FROM msdb.dbo.sysnotifications
  13579.     WHERE (alert_id = @alert_id)
  13580.  
  13581.     -- Finally, do the actual DELETE
  13582.     DELETE FROM msdb.dbo.sysalerts
  13583.     WHERE (id = @alert_id)
  13584.  
  13585.   COMMIT TRANSACTION
  13586.  
  13587.   -- Notify SQLServerAgent of the change
  13588.   EXECUTE msdb.dbo.sp_sqlagent_notify @op_type     = N'A',
  13589.                                       @alert_id    = @alert_id,
  13590.                                       @action_type = N'D'
  13591.   RETURN(0) -- Success
  13592. END
  13593. go
  13594.  
  13595. /**************************************************************/
  13596. /* SP_HELP_ALERT                                              */
  13597. /**************************************************************/
  13598.  
  13599. PRINT ''
  13600. PRINT 'Creating procedure sp_help_alert...'
  13601. go
  13602. IF (EXISTS (SELECT *
  13603.             FROM msdb.dbo.sysobjects
  13604.             WHERE (name = N'sp_help_alert')
  13605.               AND (type = 'P')))
  13606.   DROP PROCEDURE sp_help_alert
  13607. go
  13608. CREATE PROCEDURE sp_help_alert
  13609.   @alert_name    sysname = NULL,
  13610.   @order_by      sysname = N'name',
  13611.   @alert_id      INT     = NULL,
  13612.   @category_name sysname = NULL
  13613. AS
  13614. BEGIN
  13615.   DECLARE @alert_id_as_char NVARCHAR(10)
  13616.  
  13617.   SET NOCOUNT ON
  13618.  
  13619.   -- Remove any leading/trailing spaces from parameters
  13620.   SELECT @alert_name    = LTRIM(RTRIM(@alert_name))
  13621.   SELECT @order_by      = LTRIM(RTRIM(@order_by))
  13622.   SELECT @category_name = LTRIM(RTRIM(@category_name))
  13623.  
  13624.   -- Turn [nullable] empty string parameters into NULLs
  13625.   IF (@category_name = N'') SELECT @category_name = NULL
  13626.   IF (@alert_name = N'')    SELECT @alert_name = NULL
  13627.  
  13628.   -- Check alert name
  13629.   IF (@alert_name IS NOT NULL)
  13630.   BEGIN
  13631.     IF (NOT EXISTS (SELECT *
  13632.                     FROM msdb.dbo.sysalerts 
  13633.                     WHERE (name = @alert_name)))
  13634.     BEGIN
  13635.       RAISERROR(14262, -1, -1, '@alert_name', @alert_name)
  13636.       RETURN(1) -- Failure
  13637.     END
  13638.   END
  13639.  
  13640.   -- Check alert id
  13641.   IF (@alert_id IS NOT NULL)
  13642.   BEGIN
  13643.     IF (NOT EXISTS (SELECT *
  13644.                     FROM msdb.dbo.sysalerts 
  13645.                     WHERE (id = @alert_id)))
  13646.     BEGIN
  13647.       SELECT @alert_id_as_char = CONVERT(VARCHAR, @alert_id)
  13648.       RAISERROR(14262, -1, -1, '@alert_id', @alert_id_as_char)
  13649.       RETURN(1) -- Failure
  13650.     END
  13651.   END
  13652.  
  13653.   IF (@order_by NOT LIKE N'job_name%')
  13654.     SELECT @order_by = N'sa.' + @order_by
  13655.  
  13656.   IF (@alert_id IS NOT NULL)
  13657.     SELECT @alert_id_as_char = CONVERT(VARCHAR, @alert_id)
  13658.   ELSE
  13659.     SELECT @alert_id_as_char = N'NULL'
  13660.  
  13661.   -- Double up any single quotes in @alert_name
  13662.   IF (@alert_name IS NOT NULL)
  13663.     SELECT @alert_name = REPLACE(@alert_name, N'''', N'''''')
  13664.  
  13665.   -- Double up any single quotes in @category_name
  13666.   IF (@category_name IS NOT NULL)
  13667.     SELECT @category_name = REPLACE(@category_name, N'''', N'''''')
  13668.  
  13669.   EXECUTE (N'SELECT sa.id,
  13670.                     sa.name,
  13671.                     sa.event_source,
  13672.                     sa.event_category_id,
  13673.                     sa.event_id,
  13674.                     sa.message_id,
  13675.                     sa.severity,
  13676.                     sa.enabled,
  13677.                     sa.delay_between_responses,
  13678.                     sa.last_occurrence_date,
  13679.                     sa.last_occurrence_time,
  13680.                     sa.last_response_date,
  13681.                     sa.last_response_time,
  13682.                     sa.notification_message,
  13683.                     sa.include_event_description,
  13684.                     sa.database_name,
  13685.                     sa.event_description_keyword,
  13686.                     sa.occurrence_count,
  13687.                     sa.count_reset_date,
  13688.                     sa.count_reset_time,
  13689.                     sjv.job_id,
  13690.                     job_name = sjv.name,
  13691.                     sa.has_notification,
  13692.                     sa.flags,
  13693.                     sa.performance_condition,
  13694.                     category_name = sc.name,
  13695.                     type = CASE ISNULL(performance_condition, ''!'')
  13696.                              WHEN ''!'' THEN
  13697.                                CASE event_source 
  13698.                                  WHEN ''MSSQLServer'' THEN 1 -- SQL Server event alert
  13699.                                  ELSE 3                      -- Non SQL Server event alert
  13700.                                END
  13701.                              ELSE 2                          -- SQL Server performance condition alert
  13702.                            END
  13703.              FROM msdb.dbo.sysalerts                     sa
  13704.                   LEFT OUTER JOIN msdb.dbo.sysjobs_view  sjv ON (sa.job_id = sjv.job_id)
  13705.                   LEFT OUTER JOIN msdb.dbo.syscategories sc  ON (sa.category_id = sc.category_id)
  13706.              WHERE ((N''' + @alert_name + N''' = N'''') OR (sa.name = N''' + @alert_name + N'''))
  13707.                AND ((' + @alert_id_as_char + N' IS NULL) OR (sa.id = ' + @alert_id_as_char + N'))
  13708.                AND ((N''' + @category_name + N''' = N'''') OR (sc.name = N''' + @category_name + N'''))
  13709.              ORDER BY ' + @order_by)
  13710.  
  13711.   RETURN(@@error) -- 0 means success
  13712. END
  13713. go
  13714.  
  13715. /**************************************************************/
  13716. /* SP_VERIFY_OPERATOR                                         */
  13717. /**************************************************************/
  13718.  
  13719. PRINT ''
  13720. PRINT 'Creating procedure sp_verify_operator...'
  13721. go
  13722. IF (EXISTS (SELECT *
  13723.             FROM msdb.dbo.sysobjects
  13724.             WHERE (name = N'sp_verify_operator')
  13725.               AND (type = 'P')))
  13726.   DROP PROCEDURE sp_verify_operator
  13727. go
  13728. CREATE PROCEDURE sp_verify_operator
  13729.   @name                      sysname,
  13730.   @enabled                   TINYINT,
  13731.   @pager_days                TINYINT,
  13732.   @weekday_pager_start_time  INT,
  13733.   @weekday_pager_end_time    INT,
  13734.   @saturday_pager_start_time INT,
  13735.   @saturday_pager_end_time   INT,
  13736.   @sunday_pager_start_time   INT,
  13737.   @sunday_pager_end_time     INT,
  13738.   @category_name             sysname,
  13739.   @category_id               INT OUTPUT
  13740. AS
  13741. BEGIN
  13742.   DECLARE @return_code     TINYINT
  13743.   DECLARE @res_valid_range NVARCHAR(100)
  13744.  
  13745.   SET NOCOUNT ON
  13746.  
  13747.   SELECT @res_valid_range = FORMATMESSAGE(14209)
  13748.  
  13749.   -- Remove any leading/trailing spaces from parameters
  13750.   SELECT @name          = LTRIM(RTRIM(@name))
  13751.   SELECT @category_name = LTRIM(RTRIM(@category_name))
  13752.  
  13753.   -- The name must be unique
  13754.   IF (EXISTS (SELECT *
  13755.               FROM msdb.dbo.sysoperators
  13756.               WHERE (name = @name)))
  13757.   BEGIN
  13758.     RAISERROR(14261, 16, 1, '@name', @name)
  13759.     RETURN(1) -- Failure
  13760.   END
  13761.  
  13762.   -- Enabled must be 0 or 1
  13763.   IF (@enabled NOT IN (0, 1))
  13764.   BEGIN
  13765.     RAISERROR(14266, 16, 1, '@enabled', '0, 1')
  13766.     RETURN(1) -- Failure
  13767.   END
  13768.  
  13769.   -- Check PagerDays
  13770.   IF (@pager_days < 0) OR (@pager_days > 127)
  13771.   BEGIN
  13772.     RAISERROR(14266, 16, 1, '@pager_days', @res_valid_range)
  13773.     RETURN(1) -- Failure
  13774.   END
  13775.  
  13776.   -- Check Start/End Times
  13777.   EXECUTE @return_code = sp_verify_job_time @weekday_pager_start_time, '@weekday_pager_start_time'
  13778.   IF (@return_code <> 0)
  13779.     RETURN(1)
  13780.  
  13781.   EXECUTE @return_code = sp_verify_job_time @weekday_pager_end_time, '@weekday_pager_end_time'
  13782.   IF (@return_code <> 0)
  13783.     RETURN(1)
  13784.  
  13785.   EXECUTE @return_code = sp_verify_job_time @saturday_pager_start_time, '@saturday_pager_start_time'
  13786.   IF (@return_code <> 0)
  13787.     RETURN(1)
  13788.  
  13789.   EXECUTE @return_code = sp_verify_job_time @saturday_pager_end_time, '@saturday_pager_end_time'
  13790.   IF (@return_code <> 0)
  13791.     RETURN(1)
  13792.  
  13793.   EXECUTE @return_code = sp_verify_job_time @sunday_pager_start_time, '@sunday_pager_start_time'
  13794.   IF (@return_code <> 0)
  13795.     RETURN(1)
  13796.  
  13797.   EXECUTE @return_code = sp_verify_job_time @sunday_pager_end_time, '@sunday_pager_end_time'
  13798.   IF (@return_code <> 0)
  13799.     RETURN(1)
  13800.  
  13801.   -- Check category name
  13802.   IF (@category_name = N'[DEFAULT]')
  13803.     SELECT @category_id = 99
  13804.   ELSE
  13805.   BEGIN
  13806.     SELECT @category_id = category_id
  13807.     FROM msdb.dbo.syscategories
  13808.     WHERE (category_class = 3) -- Operators
  13809.       AND (category_type = 3) -- None
  13810.       AND (name = @category_name)
  13811.   END
  13812.   IF (@category_id IS NULL)
  13813.   BEGIN
  13814.     RAISERROR(14262, -1, -1, '@category_name', @category_name)
  13815.     RETURN(1) -- Failure
  13816.   END
  13817.  
  13818.   RETURN(0)
  13819. END
  13820. go
  13821.  
  13822. /**************************************************************/
  13823. /* SP_ADD_OPERATOR                                            */
  13824. /**************************************************************/
  13825.  
  13826. PRINT ''
  13827. PRINT 'Creating procedure sp_add_operator...'
  13828. go
  13829. IF (EXISTS (SELECT *
  13830.             FROM msdb.dbo.sysobjects
  13831.             WHERE (name = N'sp_add_operator')
  13832.               AND (type = 'P')))
  13833.   DROP PROCEDURE sp_add_operator
  13834. go
  13835. CREATE PROCEDURE sp_add_operator
  13836.   @name                      sysname,
  13837.   @enabled                   TINYINT       = 1,
  13838.   @email_address             NVARCHAR(100) = NULL,
  13839.   @pager_address             NVARCHAR(100) = NULL,
  13840.   @weekday_pager_start_time  INT           = 090000, -- HHMMSS using 24 hour clock
  13841.   @weekday_pager_end_time    INT           = 180000, -- As above
  13842.   @saturday_pager_start_time INT           = 090000, -- As above
  13843.   @saturday_pager_end_time   INT           = 180000, -- As above
  13844.   @sunday_pager_start_time   INT           = 090000, -- As above
  13845.   @sunday_pager_end_time     INT           = 180000, -- As above
  13846.   @pager_days                TINYINT       = 0,      -- 1 = Sunday .. 64 = Saturday
  13847.   @netsend_address           NVARCHAR(100) = NULL,   -- New for 7.0
  13848.   @category_name             sysname       = NULL    -- New for 7.0
  13849. AS
  13850. BEGIN
  13851.   DECLARE @return_code TINYINT
  13852.   DECLARE @category_id INT
  13853.  
  13854.   SET NOCOUNT ON
  13855.  
  13856.   -- Remove any leading/trailing spaces from parameters
  13857.   SELECT @name            = LTRIM(RTRIM(@name))
  13858.   SELECT @email_address   = LTRIM(RTRIM(@email_address))
  13859.   SELECT @pager_address   = LTRIM(RTRIM(@pager_address))
  13860.   SELECT @netsend_address = LTRIM(RTRIM(@netsend_address))
  13861.   SELECT @category_name   = LTRIM(RTRIM(@category_name))
  13862.  
  13863.   -- Turn [nullable] empty string parameters into NULLs
  13864.   IF (@email_address   = N'') SELECT @email_address   = NULL
  13865.   IF (@pager_address   = N'') SELECT @pager_address   = NULL
  13866.   IF (@netsend_address = N'') SELECT @netsend_address = NULL
  13867.   IF (@category_name   = N'') SELECT @category_name   = NULL
  13868.  
  13869.   -- Only a sysadmin can do this
  13870.   IF (ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) <> 1)
  13871.   BEGIN
  13872.     RAISERROR(15003, 16, 1, N'sysadmin')
  13873.     RETURN(1) -- Failure
  13874.   END
  13875.  
  13876.   IF (@category_name IS NULL)
  13877.   BEGIN
  13878.     SELECT @category_name = name
  13879.     FROM msdb.dbo.syscategories
  13880.     WHERE (category_id = 99)
  13881.   END
  13882.  
  13883.   -- Verify the operator
  13884.   EXECUTE @return_code = sp_verify_operator @name,
  13885.                                             @enabled,
  13886.                                             @pager_days,
  13887.                                             @weekday_pager_start_time,
  13888.                                             @weekday_pager_end_time,
  13889.                                             @saturday_pager_start_time,
  13890.                                             @saturday_pager_end_time,
  13891.                                             @sunday_pager_start_time,
  13892.                                             @sunday_pager_end_time,
  13893.                                             @category_name,
  13894.                                             @category_id OUTPUT
  13895.   IF (@return_code <> 0)
  13896.     RETURN(1) -- Failure
  13897.  
  13898.   -- Finally, do the INSERT
  13899.   INSERT INTO msdb.dbo.sysoperators
  13900.          (name,
  13901.           enabled,
  13902.           email_address,
  13903.           last_email_date,
  13904.           last_email_time,
  13905.           pager_address,
  13906.           last_pager_date,
  13907.           last_pager_time,
  13908.           weekday_pager_start_time,
  13909.           weekday_pager_end_time,
  13910.           saturday_pager_start_time,
  13911.           saturday_pager_end_time,
  13912.           sunday_pager_start_time,
  13913.           sunday_pager_end_time,
  13914.           pager_days,
  13915.           netsend_address,
  13916.           last_netsend_date,
  13917.           last_netsend_time,
  13918.           category_id)
  13919.   VALUES (@name,
  13920.           @enabled,
  13921.           @email_address,
  13922.           0,
  13923.           0,
  13924.           @pager_address,
  13925.           0,
  13926.           0,
  13927.           @weekday_pager_start_time,
  13928.           @weekday_pager_end_time,
  13929.           @saturday_pager_start_time,
  13930.           @saturday_pager_end_time,
  13931.           @sunday_pager_start_time,
  13932.           @sunday_pager_end_time,
  13933.           @pager_days,
  13934.           @netsend_address,
  13935.           0,
  13936.           0,
  13937.           @category_id)
  13938.  
  13939.   RETURN(@@error) -- 0 means success
  13940. END
  13941. go
  13942.  
  13943. /**************************************************************/
  13944. /* SP_UPDATE_OPERATOR                                         */
  13945. /**************************************************************/
  13946.  
  13947. PRINT ''
  13948. PRINT 'Creating procedure sp_update_operator...'
  13949. go
  13950. IF (EXISTS (SELECT *
  13951.             FROM msdb.dbo.sysobjects
  13952.             WHERE (name = N'sp_update_operator')
  13953.               AND (type = 'P')))
  13954.   DROP PROCEDURE sp_update_operator
  13955. go
  13956. CREATE PROCEDURE sp_update_operator
  13957.   @name                      sysname,
  13958.   @new_name                  sysname       = NULL,
  13959.   @enabled                   TINYINT       = NULL,
  13960.   @email_address             NVARCHAR(100) = NULL,
  13961.   @pager_address             NVARCHAR(100) = NULL,
  13962.   @weekday_pager_start_time  INT           = NULL, -- HHMMSS using 24 hour clock
  13963.   @weekday_pager_end_time    INT           = NULL, -- As above
  13964.   @saturday_pager_start_time INT           = NULL, -- As above
  13965.   @saturday_pager_end_time   INT           = NULL, -- As above
  13966.   @sunday_pager_start_time   INT           = NULL, -- As above
  13967.   @sunday_pager_end_time     INT           = NULL, -- As above
  13968.   @pager_days                TINYINT       = NULL,
  13969.   @netsend_address           NVARCHAR(100) = NULL, -- New for 7.0
  13970.   @category_name             sysname       = NULL  -- New for 7.0
  13971. AS
  13972. BEGIN
  13973.   DECLARE @x_enabled                   TINYINT
  13974.   DECLARE @x_email_address             NVARCHAR(100)
  13975.   DECLARE @x_pager_address             NVARCHAR(100)
  13976.   DECLARE @x_weekday_pager_start_time  INT
  13977.   DECLARE @x_weekday_pager_end_time    INT
  13978.   DECLARE @x_saturday_pager_start_time INT
  13979.   DECLARE @x_saturday_pager_end_time   INT
  13980.   DECLARE @x_sunday_pager_start_time   INT
  13981.   DECLARE @x_sunday_pager_end_time     INT
  13982.   DECLARE @x_pager_days                TINYINT
  13983.   DECLARE @x_netsend_address           NVARCHAR(100)
  13984.   DECLARE @x_category_id               INT
  13985.  
  13986.   DECLARE @return_code                 INT
  13987.   DECLARE @notification_method         INT
  13988.   DECLARE @alert_fail_safe_operator    sysname
  13989.   DECLARE @current_msx_server          NVARCHAR(30)
  13990.   DECLARE @category_id                 INT
  13991.  
  13992.   SET NOCOUNT ON
  13993.  
  13994.   -- Remove any leading/trailing spaces from parameters
  13995.   SELECT @name            = LTRIM(RTRIM(@name))
  13996.   SELECT @new_name        = LTRIM(RTRIM(@new_name))
  13997.   SELECT @email_address   = LTRIM(RTRIM(@email_address))
  13998.   SELECT @pager_address   = LTRIM(RTRIM(@pager_address))
  13999.   SELECT @netsend_address = LTRIM(RTRIM(@netsend_address))
  14000.   SELECT @category_name   = LTRIM(RTRIM(@category_name))
  14001.  
  14002.   -- Only a sysadmin can do this
  14003.   IF (ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) <> 1)
  14004.   BEGIN
  14005.     RAISERROR(15003, 16, 1, N'sysadmin')
  14006.     RETURN(1) -- Failure
  14007.   END
  14008.  
  14009.   -- Check if this Operator exists
  14010.   IF (NOT EXISTS (SELECT *
  14011.                   FROM msdb.dbo.sysoperators
  14012.                   WHERE (name = @name)))
  14013.   BEGIN
  14014.     RAISERROR(14262, 16, 1, '@name', @name)
  14015.     RETURN(1) -- Failure
  14016.   END
  14017.  
  14018.   -- Check if this operator is 'MSXOperator'
  14019.   IF (@name = N'MSXOperator')
  14020.   BEGIN
  14021.     -- Disallow the update operation if we're at a TSX for all callers other than xp_msx_enlist
  14022.     EXECUTE master.dbo.xp_regread N'HKEY_LOCAL_MACHINE',
  14023.                                   N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
  14024.                                   N'MSXServerName',
  14025.                                    @current_msx_server OUTPUT,
  14026.                                   N'no_output'
  14027.     IF ((@current_msx_server IS NOT NULL) AND (PROGRAM_NAME() <> N'xp_msx_enlist'))
  14028.     BEGIN  
  14029.       RAISERROR(14223, 16, 1, 'MSXOperator', 'TSX')
  14030.       RETURN(1) -- Failure
  14031.     END
  14032.   END
  14033.  
  14034.   -- Get existing (@x_) operator property values
  14035.   SELECT @x_enabled                   = enabled,
  14036.          @x_email_address             = email_address,
  14037.          @x_pager_address             = pager_address,
  14038.          @x_weekday_pager_start_time  = weekday_pager_start_time,
  14039.          @x_weekday_pager_end_time    = weekday_pager_end_time,
  14040.          @x_saturday_pager_start_time = saturday_pager_start_time,
  14041.          @x_saturday_pager_end_time   = saturday_pager_end_time,
  14042.          @x_sunday_pager_start_time   = sunday_pager_start_time,
  14043.          @x_sunday_pager_end_time     = sunday_pager_end_time,
  14044.          @x_pager_days                = pager_days,
  14045.          @x_netsend_address           = netsend_address,
  14046.          @x_category_id               = category_id
  14047.   FROM msdb.dbo.sysoperators
  14048.   WHERE (name = @name)
  14049.  
  14050.   -- Fill out the values for all non-supplied parameters from the existsing values
  14051.   IF (@enabled                   IS NULL) SELECT @enabled                   = @x_enabled
  14052.   IF (@email_address             IS NULL) SELECT @email_address             = @x_email_address
  14053.   IF (@pager_address             IS NULL) SELECT @pager_address             = @x_pager_address
  14054.   IF (@weekday_pager_start_time  IS NULL) SELECT @weekday_pager_start_time  = @x_weekday_pager_start_time
  14055.   IF (@weekday_pager_end_time    IS NULL) SELECT @weekday_pager_end_time    = @x_weekday_pager_end_time
  14056.   IF (@saturday_pager_start_time IS NULL) SELECT @saturday_pager_start_time = @x_saturday_pager_start_time
  14057.   IF (@saturday_pager_end_time   IS NULL) SELECT @saturday_pager_end_time   = @x_saturday_pager_end_time
  14058.   IF (@sunday_pager_start_time   IS NULL) SELECT @sunday_pager_start_time   = @x_sunday_pager_start_time
  14059.   IF (@sunday_pager_end_time     IS NULL) SELECT @sunday_pager_end_time     = @x_sunday_pager_end_time
  14060.   IF (@pager_days                IS NULL) SELECT @pager_days                = @x_pager_days
  14061.   IF (@netsend_address           IS NULL) SELECT @netsend_address           = @x_netsend_address
  14062.   IF (@category_name             IS NULL) SELECT @category_name = name FROM msdb.dbo.syscategories WHERE (category_id = @x_category_id)
  14063.  
  14064.   IF (@category_name IS NULL)
  14065.   BEGIN
  14066.     SELECT @category_name = name
  14067.     FROM msdb.dbo.syscategories
  14068.     WHERE (category_id = 99)
  14069.   END
  14070.  
  14071.   -- Turn [nullable] empty string parameters into NULLs
  14072.   IF (@email_address   = N'') SELECT @email_address   = NULL
  14073.   IF (@pager_address   = N'') SELECT @pager_address   = NULL
  14074.   IF (@netsend_address = N'') SELECT @netsend_address = NULL
  14075.   IF (@category_name   = N'') SELECT @category_name   = NULL
  14076.  
  14077.   -- Verify the operator
  14078.   EXECUTE @return_code = sp_verify_operator @new_name,
  14079.                                             @enabled,
  14080.                                             @pager_days,
  14081.                                             @weekday_pager_start_time,
  14082.                                             @weekday_pager_end_time,
  14083.                                             @saturday_pager_start_time,
  14084.                                             @saturday_pager_end_time,
  14085.                                             @sunday_pager_start_time,
  14086.                                             @sunday_pager_end_time,
  14087.                                             @category_name,
  14088.                                             @category_id OUTPUT
  14089.   IF (@return_code <> 0)
  14090.     RETURN(1) -- Failure
  14091.  
  14092.   -- If no new name is supplied, use the old one
  14093.   -- NOTE: We must do this AFTER calling sp_verify_operator.
  14094.   IF (@new_name IS NULL)
  14095.     SELECT @new_name = @name
  14096.   ELSE
  14097.   BEGIN
  14098.     -- You can't rename the MSXOperator
  14099.     IF (@name = N'MSXOperator')
  14100.     BEGIN
  14101.       RAISERROR(14222, 16, 1, 'MSXOperator')
  14102.       RETURN(1) -- Failure
  14103.     END
  14104.   END
  14105.  
  14106.   -- Do the UPDATE
  14107.   UPDATE msdb.dbo.sysoperators
  14108.   SET name                      = @new_name,
  14109.       enabled                   = @enabled,
  14110.       email_address             = @email_address,
  14111.       pager_address             = @pager_address,
  14112.       weekday_pager_start_time  = @weekday_pager_start_time,
  14113.       weekday_pager_end_time    = @weekday_pager_end_time,
  14114.       saturday_pager_start_time = @saturday_pager_start_time,
  14115.       saturday_pager_end_time   = @saturday_pager_end_time,
  14116.       sunday_pager_start_time   = @sunday_pager_start_time,
  14117.       sunday_pager_end_time     = @sunday_pager_end_time,
  14118.       pager_days                = @pager_days,
  14119.       netsend_address           = @netsend_address,
  14120.       category_id               = @category_id
  14121.   WHERE (name = @name)
  14122.  
  14123.   -- Check if the operator is 'MSXOperator', in which case we need to re-enlist all the targets
  14124.   -- so that they will download the new MSXOperator details
  14125.   IF ((@name = N'MSXOperator') AND ((SELECT COUNT(*) FROM msdb.dbo.systargetservers) > 0))
  14126.     EXECUTE msdb.dbo.sp_post_msx_operation 'RE-ENLIST', 'SERVER', 0x00
  14127.  
  14128.   -- Check if this operator is the FailSafe Operator
  14129.   EXECUTE master.dbo.xp_regread N'HKEY_LOCAL_MACHINE',
  14130.                                 N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
  14131.                                 N'AlertFailSafeOperator',
  14132.                                  @alert_fail_safe_operator OUTPUT,
  14133.                                 N'no_output'
  14134.  
  14135.   -- If it is, we update the 4 'AlertFailSafe...' registry entries and AlertNotificationMethod
  14136.   IF (LTRIM(RTRIM(@alert_fail_safe_operator)) = @name)
  14137.   BEGIN
  14138.     -- Update AlertFailSafeX values
  14139.     EXECUTE master.dbo.xp_regwrite N'HKEY_LOCAL_MACHINE',
  14140.                                    N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
  14141.                                    N'AlertFailSafeOperator',
  14142.                                    N'REG_SZ',
  14143.                                     @new_name
  14144.     EXECUTE master.dbo.xp_regwrite N'HKEY_LOCAL_MACHINE',
  14145.                                    N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
  14146.                                    N'AlertFailSafeEmailAddress',
  14147.                                    N'REG_SZ',
  14148.                                     @email_address
  14149.     EXECUTE master.dbo.xp_regwrite N'HKEY_LOCAL_MACHINE',
  14150.                                    N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
  14151.                                    N'AlertFailSafePagerAddress',
  14152.                                    N'REG_SZ',
  14153.                                      @pager_address
  14154.     EXECUTE master.dbo.xp_regwrite N'HKEY_LOCAL_MACHINE',
  14155.                                    N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
  14156.                                    N'AlertFailSafeNetSendAddress',
  14157.                                    N'REG_SZ',
  14158.                                     @netsend_address
  14159.  
  14160.     -- Update AlertNotificationMethod values
  14161.     EXECUTE master.dbo.xp_regread N'HKEY_LOCAL_MACHINE',
  14162.                                   N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
  14163.                                   N'AlertNotificationMethod',
  14164.                                    @notification_method OUTPUT,
  14165.                                   N'no_output'
  14166.     IF (LTRIM(RTRIM(@email_address)) IS NULL)
  14167.       SELECT @notification_method = @notification_method & ~1
  14168.     IF (LTRIM(RTRIM(@pager_address)) IS NULL)
  14169.       SELECT @notification_method = @notification_method & ~2
  14170.     IF (LTRIM(RTRIM(@netsend_address)) IS NULL)
  14171.       SELECT @notification_method = @notification_method & ~4
  14172.     EXECUTE master.dbo.xp_regwrite N'HKEY_LOCAL_MACHINE',
  14173.                                    N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
  14174.                                    N'AlertNotificationMethod', 
  14175.                                    N'REG_DWORD',
  14176.                                     @notification_method
  14177.  
  14178.     -- And finally, let SQLServerAgent know of the changes
  14179.     EXECUTE msdb.dbo.sp_sqlagent_notify @op_type = N'G'
  14180.   END
  14181.  
  14182.   RETURN(0) -- Success
  14183. END
  14184. go
  14185.  
  14186. /**************************************************************/
  14187. /* SP_DELETE_OPERATOR                                         */
  14188. /**************************************************************/
  14189.  
  14190. PRINT ''
  14191. PRINT 'Creating procedure sp_delete_operator...'
  14192. go
  14193. IF (EXISTS (SELECT *
  14194.             FROM msdb.dbo.sysobjects
  14195.             WHERE (name = N'sp_delete_operator')
  14196.               AND (type = 'P')))
  14197.   DROP PROCEDURE sp_delete_operator
  14198. go
  14199. CREATE PROCEDURE sp_delete_operator
  14200.   @name                 sysname,
  14201.   @reassign_to_operator sysname = NULL
  14202. AS
  14203. BEGIN
  14204.   DECLARE @id                         INT
  14205.   DECLARE @alert_fail_safe_operator   sysname
  14206.   DECLARE @job_id                     UNIQUEIDENTIFIER
  14207.   DECLARE @job_id_as_char             VARCHAR(36)
  14208.   DECLARE @notify_email_operator_id   INT
  14209.   DECLARE @notify_netsend_operator_id INT
  14210.   DECLARE @notify_page_operator_id    INT
  14211.   DECLARE @reassign_to_id             INT
  14212.   DECLARE @cmd                        NVARCHAR(512)
  14213.   DECLARE @current_msx_server         NVARCHAR(30)
  14214.  
  14215.   SET NOCOUNT ON
  14216.  
  14217.   -- Remove any leading/trailing spaces from parameters
  14218.   SELECT @name                 = LTRIM(RTRIM(@name))
  14219.   SELECT @reassign_to_operator = LTRIM(RTRIM(@reassign_to_operator))
  14220.  
  14221.   -- Turn [nullable] empty string parameters into NULLs
  14222.   IF (@reassign_to_operator = N'') SELECT @reassign_to_operator = NULL
  14223.  
  14224.   -- Only a sysadmin can do this
  14225.   IF (ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) <> 1)
  14226.   BEGIN
  14227.     RAISERROR(15003, 16, 1, N'sysadmin')
  14228.     RETURN(1) -- Failure
  14229.   END
  14230.  
  14231.   -- Check if this Operator exists
  14232.   IF (NOT EXISTS (SELECT *
  14233.                   FROM msdb.dbo.sysoperators
  14234.                   WHERE (name = @name)))
  14235.   BEGIN
  14236.     RAISERROR(14262, 16, 1, '@name', @name)
  14237.     RETURN(1) -- Failure
  14238.   END
  14239.  
  14240.   -- Check if this operator the FailSafe Operator
  14241.   EXECUTE master.dbo.xp_regread N'HKEY_LOCAL_MACHINE',
  14242.                                 N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
  14243.                                 N'AlertFailSafeOperator',
  14244.                                  @alert_fail_safe_operator OUTPUT,
  14245.                                 N'no_output'
  14246.  
  14247.   -- If it is, we disallow the delete operation
  14248.   IF (LTRIM(RTRIM(@alert_fail_safe_operator)) = @name)
  14249.   BEGIN
  14250.     RAISERROR(14504, 16, 1, @name, @name)
  14251.     RETURN(1) -- Failure
  14252.   END
  14253.  
  14254.   -- Check if this operator is 'MSXOperator'
  14255.   IF (@name = N'MSXOperator')
  14256.   BEGIN
  14257.     DECLARE @server_type VARCHAR(3)
  14258.  
  14259.     -- Disallow the delete operation if we're an MSX or a TSX
  14260.     EXECUTE master.dbo.xp_regread N'HKEY_LOCAL_MACHINE',
  14261.                                   N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
  14262.                                   N'MSXServerName',
  14263.                                    @current_msx_server OUTPUT,
  14264.                                   N'no_output'
  14265.     IF (@current_msx_server IS NOT NULL)
  14266.       SELECT @server_type = 'TSX'
  14267.  
  14268.     IF ((SELECT COUNT(*)
  14269.          FROM msdb.dbo.systargetservers) > 0)
  14270.       SELECT @server_type = 'MSX'
  14271.  
  14272.     IF (@server_type IS NOT NULL)
  14273.     BEGIN
  14274.       RAISERROR(14223, 16, 1, 'MSXOperator', @server_type)
  14275.       RETURN(1) -- Failure
  14276.     END
  14277.   END
  14278.  
  14279.   -- Convert the Name to it's ID
  14280.   SELECT @id = id
  14281.   FROM msdb.dbo.sysoperators
  14282.   WHERE (name = @name)
  14283.  
  14284.   IF (@reassign_to_operator IS NOT NULL)
  14285.   BEGIN
  14286.     -- On a TSX or standalone server, disallow re-assigning to the MSXOperator
  14287.     IF (@reassign_to_operator = N'MSXOperator') AND
  14288.        (NOT EXISTS (SELECT *
  14289.                     FROM msdb.dbo.systargetservers))
  14290.     BEGIN
  14291.       RAISERROR(14251, -1, -1, @reassign_to_operator)
  14292.       RETURN(1) -- Failure
  14293.     END
  14294.  
  14295.     SELECT @reassign_to_id = id
  14296.     FROM msdb.dbo.sysoperators
  14297.     WHERE (name = @reassign_to_operator)
  14298.  
  14299.     IF (@reassign_to_id IS NULL)
  14300.     BEGIN
  14301.       RAISERROR(14261, -1, -1, '@reassign_to_operator', @reassign_to_operator)
  14302.       RETURN(1) -- Failure
  14303.     END
  14304.   END
  14305.  
  14306.   -- Double up any single quotes in @reassign_to_operator
  14307.   IF (@reassign_to_operator IS NOT NULL)
  14308.     SELECT @reassign_to_operator = REPLACE(@reassign_to_operator, N'''', N'''''')
  14309.  
  14310.   BEGIN TRANSACTION
  14311.  
  14312.     -- Reassign (or delete) any sysnotifications rows that reference this operator
  14313.     IF (@reassign_to_operator IS NOT NULL)
  14314.     BEGIN
  14315.       UPDATE msdb.dbo.sysnotifications
  14316.       SET operator_id = @reassign_to_id
  14317.       WHERE (operator_id = @id)
  14318.         AND (NOT EXISTS (SELECT *
  14319.                          FROM msdb.dbo.sysnotifications sn2
  14320.                          WHERE (sn2.alert_id = msdb.dbo.sysnotifications.alert_id)
  14321.                            AND (sn2.operator_id = @reassign_to_id)))
  14322.     END
  14323.  
  14324.     DELETE FROM msdb.dbo.sysnotifications
  14325.     WHERE (operator_id = @id)
  14326.  
  14327.     -- Update any jobs that reference this operator
  14328.     DECLARE jobs_referencing_this_operator CURSOR LOCAL
  14329.     FOR
  14330.     SELECT job_id, 
  14331.            notify_email_operator_id,
  14332.            notify_netsend_operator_id,
  14333.            notify_page_operator_id
  14334.     FROM msdb.dbo.sysjobs
  14335.     WHERE (notify_email_operator_id = @id)
  14336.        OR (notify_netsend_operator_id = @id)
  14337.        OR (notify_page_operator_id = @id)
  14338.  
  14339.     OPEN jobs_referencing_this_operator
  14340.     FETCH NEXT FROM jobs_referencing_this_operator INTO @job_id,
  14341.                                                         @notify_email_operator_id,
  14342.                                                         @notify_netsend_operator_id,
  14343.                                                         @notify_page_operator_id
  14344.     WHILE (@@fetch_status = 0)
  14345.     BEGIN
  14346.       SELECT @job_id_as_char = CONVERT(VARCHAR(36), @job_id)
  14347.       SELECT @cmd = N'msdb.dbo.sp_update_job @job_id = ''' + @job_id_as_char + N''', '
  14348.  
  14349.       IF (@notify_email_operator_id = @id)
  14350.         IF (@reassign_to_operator IS NOT NULL)
  14351.           SELECT @cmd = @cmd + N'@notify_email_operator_name = N''' + @reassign_to_operator + N''', '
  14352.         ELSE
  14353.           SELECT @cmd = @cmd + N'@notify_email_operator_name = N'''', @notify_level_email = 0, '
  14354.  
  14355.       IF (@notify_netsend_operator_id = @id)
  14356.         IF (@reassign_to_operator IS NOT NULL)
  14357.           SELECT @cmd = @cmd + N'@notify_netsend_operator_name = N''' + @reassign_to_operator + N''', '
  14358.         ELSE
  14359.           SELECT @cmd = @cmd + N'@notify_netsend_operator_name = N'''', @notify_level_netsend = 0, '
  14360.  
  14361.       IF (@notify_page_operator_id = @id)
  14362.         IF (@reassign_to_operator IS NOT NULL)
  14363.           SELECT @cmd = @cmd + N'@notify_page_operator_name = N''' + @reassign_to_operator + N''', '
  14364.         ELSE
  14365.           SELECT @cmd = @cmd + N'@notify_page_operator_name = N'''', @notify_level_page = 0, '
  14366.     
  14367.       SELECT @cmd = SUBSTRING(@cmd, 1, (DATALENGTH(@cmd) / 2) - 2) 
  14368.       EXECUTE (N'EXECUTE ' + @cmd)
  14369.  
  14370.       FETCH NEXT FROM jobs_referencing_this_operator INTO @job_id,
  14371.                                                           @notify_email_operator_id,
  14372.                                                           @notify_netsend_operator_id,
  14373.                                                           @notify_page_operator_id
  14374.     END
  14375.     DEALLOCATE jobs_referencing_this_operator
  14376.  
  14377.     -- Finally, do the actual DELETE
  14378.     DELETE FROM msdb.dbo.sysoperators
  14379.     WHERE (id = @id)
  14380.  
  14381.   COMMIT TRANSACTION
  14382.  
  14383.   RETURN(@@error) -- 0 means success
  14384. END
  14385. go
  14386.  
  14387. /**************************************************************/
  14388. /* SP_HELP_OPERATOR                                           */
  14389. /**************************************************************/
  14390.  
  14391. PRINT ''
  14392. PRINT 'Creating procedure sp_help_operator...'
  14393. go
  14394. IF (EXISTS (SELECT *
  14395.             FROM msdb.dbo.sysobjects
  14396.             WHERE (name = N'sp_help_operator')
  14397.               AND (type = 'P')))
  14398.   DROP PROCEDURE sp_help_operator
  14399. go
  14400. CREATE PROCEDURE sp_help_operator
  14401.   @operator_name sysname = NULL,
  14402.   @operator_id   INT     = NULL
  14403. AS
  14404. BEGIN
  14405.   DECLARE @operator_id_as_char VARCHAR(10)
  14406.  
  14407.   SET NOCOUNT ON
  14408.  
  14409.   -- Remove any leading/trailing spaces from parameters
  14410.   SELECT @operator_name = LTRIM(RTRIM(@operator_name))
  14411.   IF (@operator_name = '') SELECT @operator_name = NULL
  14412.  
  14413.   -- Check operator name
  14414.   IF (@operator_name IS NOT NULL)
  14415.   BEGIN
  14416.     IF (NOT EXISTS (SELECT *
  14417.                     FROM msdb.dbo.sysoperators 
  14418.                     WHERE (name = @operator_name)))
  14419.     BEGIN
  14420.       RAISERROR(14262, -1, -1, '@operator_name', @operator_name)
  14421.       RETURN(1) -- Failure
  14422.     END
  14423.   END
  14424.  
  14425.   -- Check operator id
  14426.   IF (@operator_id IS NOT NULL)
  14427.   BEGIN
  14428.     IF (NOT EXISTS (SELECT *
  14429.                     FROM msdb.dbo.sysoperators 
  14430.                     WHERE (id = @operator_id)))
  14431.     BEGIN
  14432.       SELECT @operator_id_as_char = CONVERT(VARCHAR, @operator_id)
  14433.       RAISERROR(14262, -1, -1, '@operator_id', @operator_id_as_char)
  14434.       RETURN(1) -- Failure
  14435.     END
  14436.   END
  14437.  
  14438.   SELECT so.id,
  14439.          so.name,
  14440.          so.enabled,
  14441.          so.email_address,
  14442.          so.last_email_date,
  14443.          so.last_email_time,
  14444.          so.pager_address,
  14445.          so.last_pager_date,
  14446.          so.last_pager_time,
  14447.          so.weekday_pager_start_time,
  14448.          so.weekday_pager_end_time,
  14449.          so.saturday_pager_start_time,
  14450.          so.saturday_pager_end_time,
  14451.          so.sunday_pager_start_time,
  14452.          so.sunday_pager_end_time,
  14453.          so.pager_days,
  14454.          so.netsend_address,
  14455.          so.last_netsend_date,
  14456.          so.last_netsend_time,
  14457.          category_name = sc.name
  14458.   FROM msdb.dbo.sysoperators                  so
  14459.        LEFT OUTER JOIN msdb.dbo.syscategories sc ON (so.category_id = sc.category_id)
  14460.   WHERE ((@operator_name IS NULL) OR (so.name = @operator_name))
  14461.     AND ((@operator_id IS NULL) OR (so.id = @operator_id))
  14462.   ORDER BY so.name
  14463.  
  14464.   RETURN(@@error) -- 0 means success
  14465. END
  14466. go
  14467.  
  14468. /**************************************************************/
  14469. /* SP_HELP_OPERATOR_JOBS                                      */
  14470. /**************************************************************/
  14471.  
  14472. PRINT ''
  14473. PRINT 'Creating procedure sp_help_operator_jobs...'
  14474. go
  14475. IF (EXISTS (SELECT *
  14476.             FROM msdb.dbo.sysobjects
  14477.             WHERE (name = 'sp_help_operator_jobs')
  14478.               AND (type = 'P')))
  14479.   DROP PROCEDURE sp_help_operator_jobs
  14480. go
  14481. CREATE PROCEDURE sp_help_operator_jobs
  14482.   @operator_name sysname = NULL
  14483. AS
  14484. BEGIN
  14485.   DECLARE @operator_id INT
  14486.  
  14487.   SET NOCOUNT ON
  14488.  
  14489.   -- Check operator name
  14490.   SELECT @operator_id = id
  14491.   FROM msdb.dbo.sysoperators 
  14492.   WHERE (name = @operator_name)
  14493.   IF (@operator_id IS NULL)
  14494.   BEGIN
  14495.     RAISERROR(14262, -1, -1, '@operator_name', @operator_name)
  14496.     RETURN(1) -- Failure
  14497.   END
  14498.  
  14499.   -- Get the job info
  14500.   SELECT job_id, name, notify_level_email, notify_level_netsend, notify_level_page
  14501.   FROM msdb.dbo.sysjobs_view
  14502.   WHERE ((notify_email_operator_id = @operator_id)   AND (notify_level_email <> 0))
  14503.      OR ((notify_netsend_operator_id = @operator_id) AND (notify_level_netsend <> 0))
  14504.      OR ((notify_page_operator_id = @operator_id)    AND (notify_level_page <> 0)) 
  14505.  
  14506.   RETURN(0) -- Success
  14507. END
  14508. go
  14509.  
  14510. /**************************************************************/
  14511. /* SP_VERIFY_NOTIFICATION                                     */
  14512. /**************************************************************/
  14513.  
  14514. PRINT ''
  14515. PRINT 'Creating procedure sp_verify_notification...'
  14516. go
  14517. IF (EXISTS (SELECT *
  14518.             FROM msdb.dbo.sysobjects
  14519.             WHERE (name = N'sp_verify_notification')
  14520.               AND (type = 'P')))
  14521.   DROP PROCEDURE sp_verify_notification
  14522. go
  14523. CREATE PROCEDURE sp_verify_notification
  14524.   @alert_name          sysname,
  14525.   @operator_name       sysname,
  14526.   @notification_method TINYINT,
  14527.   @alert_id            INT OUTPUT,
  14528.   @operator_id         INT OUTPUT
  14529. AS
  14530. BEGIN
  14531.   DECLARE @res_valid_range NVARCHAR(100)
  14532.  
  14533.   SET NOCOUNT ON
  14534.  
  14535.   SELECT @res_valid_range = FORMATMESSAGE(14208)
  14536.  
  14537.   -- Remove any leading/trailing spaces from parameters
  14538.   SELECT @alert_name    = LTRIM(RTRIM(@alert_name))
  14539.   SELECT @operator_name = LTRIM(RTRIM(@operator_name))
  14540.  
  14541.   -- Check if the AlertName is valid
  14542.   SELECT @alert_id = id
  14543.   FROM msdb.dbo.sysalerts
  14544.   WHERE (name = @alert_name)
  14545.  
  14546.   IF (@alert_id IS NULL)
  14547.   BEGIN
  14548.     RAISERROR(14262, 16, 1, '@alert_name', @alert_name)
  14549.     RETURN(1) -- Failure
  14550.   END
  14551.  
  14552.   -- Check if the OperatorName is valid
  14553.   SELECT @operator_id = id
  14554.   FROM msdb.dbo.sysoperators
  14555.   WHERE (name = @operator_name)
  14556.  
  14557.   IF (@operator_id IS NULL)
  14558.   BEGIN
  14559.     RAISERROR(14262, 16, 1, '@operator_name', @operator_name)
  14560.     RETURN(1) -- Failure
  14561.   END
  14562.  
  14563.   -- If we're at a TSX, we disallow using operator 'MSXOperator'
  14564.   IF (NOT EXISTS (SELECT *
  14565.                   FROM msdb.dbo.systargetservers)) AND
  14566.      (@operator_name = N'MSXOperator')
  14567.   BEGIN
  14568.     RAISERROR(14251, -1, -1, @operator_name)
  14569.     RETURN(1) -- Failure
  14570.   END
  14571.  
  14572.   -- Check if the NotificationMethod is valid
  14573.   IF ((@notification_method < 1) OR (@notification_method > 7))
  14574.   BEGIN
  14575.     RAISERROR(14266, 16, 1, '@notification_method', @res_valid_range)
  14576.     RETURN(1) -- Failure
  14577.   END
  14578.  
  14579.   RETURN(0) -- Success
  14580. END
  14581. go
  14582.  
  14583. /**************************************************************/
  14584. /* SP_ADD_NOTIFICATION                                        */
  14585. /**************************************************************/
  14586.  
  14587. PRINT ''
  14588. PRINT 'Creating procedure sp_add_notification...'
  14589. go
  14590. IF (EXISTS (SELECT *
  14591.             FROM msdb.dbo.sysobjects
  14592.             WHERE (name = N'sp_add_notification')
  14593.               AND (type = 'P')))
  14594.   DROP PROCEDURE sp_add_notification
  14595. go
  14596. CREATE PROCEDURE sp_add_notification
  14597.   @alert_name          sysname,
  14598.   @operator_name       sysname,
  14599.   @notification_method TINYINT -- 1 = Email, 2 = Pager, 4 = NetSend, 7 = All
  14600. AS
  14601. BEGIN
  14602.   DECLARE @alert_id             INT
  14603.   DECLARE @operator_id          INT
  14604.   DECLARE @notification         NVARCHAR(512)
  14605.   DECLARE @retval               INT
  14606.   DECLARE @old_has_notification INT
  14607.   DECLARE @new_has_notification INT
  14608.   DECLARE @res_notification     NVARCHAR(100)
  14609.  
  14610.   SET NOCOUNT ON
  14611.  
  14612.   SELECT @res_notification = FORMATMESSAGE(14210)
  14613.  
  14614.   -- Remove any leading/trailing spaces from parameters
  14615.   SELECT @alert_name    = LTRIM(RTRIM(@alert_name))
  14616.   SELECT @operator_name = LTRIM(RTRIM(@operator_name))
  14617.  
  14618.   -- Only a sysadmin can do this
  14619.   IF (ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) <> 1)
  14620.   BEGIN
  14621.     RAISERROR(15003, 16, 1, N'sysadmin')
  14622.     RETURN(1) -- Failure
  14623.   END
  14624.  
  14625.   -- Check if the Notification is valid
  14626.   EXECUTE @retval = msdb.dbo.sp_verify_notification @alert_name,
  14627.                                                     @operator_name,
  14628.                                                     @notification_method,
  14629.                                                     @alert_id     OUTPUT,
  14630.                                                     @operator_id  OUTPUT
  14631.   IF (@retval <> 0)
  14632.     RETURN(1) -- Failure
  14633.  
  14634.   -- Check if this notification already exists
  14635.   -- NOTE: The unique index would catch this, but testing for the problem here lets us
  14636.   --       control the message.
  14637.   IF (EXISTS (SELECT *
  14638.               FROM msdb.dbo.sysnotifications
  14639.               WHERE (alert_id = @alert_id)
  14640.                 AND (operator_id = @operator_id)))
  14641.   BEGIN
  14642.     SELECT @notification = @alert_name + N' / ' + @operator_name + N' / ' + CONVERT(NVARCHAR, @notification_method)
  14643.     RAISERROR(14261, 16, 1, @res_notification, @notification)
  14644.     RETURN(1) -- Failure
  14645.   END
  14646.  
  14647.   SELECT @old_has_notification = has_notification 
  14648.   FROM msdb.dbo.sysalerts 
  14649.   WHERE (id = @alert_id)
  14650.  
  14651.   -- Do the INSERT
  14652.   INSERT INTO msdb.dbo.sysnotifications
  14653.          (alert_id,
  14654.           operator_id,
  14655.           notification_method)
  14656.   VALUES (@alert_id,
  14657.           @operator_id,
  14658.           @notification_method)
  14659.  
  14660.   SELECT @retval = @@error
  14661.  
  14662.   SELECT @new_has_notification = has_notification 
  14663.   FROM msdb.dbo.sysalerts 
  14664.   WHERE (id = @alert_id)
  14665.  
  14666.   -- Notify SQLServerAgent of the change - if any - to has_notifications
  14667.   IF (@old_has_notification <> @new_has_notification)
  14668.     EXECUTE msdb.dbo.sp_sqlagent_notify @op_type     = N'A',
  14669.                                         @alert_id    = @alert_id,
  14670.                                         @action_type = N'U'
  14671.  
  14672.   RETURN(@retval) -- 0 means success
  14673. END
  14674. go
  14675.  
  14676. /**************************************************************/
  14677. /* SP_UPDATE_NOTIFICATION                                     */
  14678. /**************************************************************/
  14679.  
  14680. PRINT ''
  14681. PRINT 'Creating procedure sp_update_notification...'
  14682. go
  14683. IF (EXISTS (SELECT *
  14684.             FROM msdb.dbo.sysobjects
  14685.             WHERE (name = N'sp_update_notification')
  14686.               AND (type = 'P')))
  14687.   DROP PROCEDURE sp_update_notification
  14688. go
  14689. CREATE PROCEDURE sp_update_notification
  14690.   @alert_name          sysname,
  14691.   @operator_name       sysname,
  14692.   @notification_method TINYINT -- 1 = Email, 2 = Pager, 4 = NetSend, 7 = All
  14693. AS
  14694. BEGIN
  14695.   DECLARE @alert_id             INT
  14696.   DECLARE @operator_id          INT
  14697.   DECLARE @notification         NVARCHAR(512)
  14698.   DECLARE @retval               INT
  14699.   DECLARE @old_has_notification INT
  14700.   DECLARE @new_has_notification INT
  14701.   DECLARE @res_notification     NVARCHAR(100)
  14702.  
  14703.   SET NOCOUNT ON
  14704.  
  14705.   SELECT @res_notification = FORMATMESSAGE(14210)
  14706.  
  14707.   -- Remove any leading/trailing spaces from parameters
  14708.   SELECT @alert_name    = LTRIM(RTRIM(@alert_name))
  14709.   SELECT @operator_name = LTRIM(RTRIM(@operator_name))
  14710.  
  14711.   -- Only a sysadmin can do this
  14712.   IF (ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) <> 1)
  14713.   BEGIN
  14714.     RAISERROR(15003, 16, 1, N'sysadmin')
  14715.     RETURN(1) -- Failure
  14716.   END
  14717.  
  14718.   -- Check if the Notification is valid
  14719.   EXECUTE sp_verify_notification @alert_name,
  14720.                                  @operator_name,
  14721.                                  @notification_method,
  14722.                                  @alert_id     OUTPUT,
  14723.                                  @operator_id  OUTPUT
  14724.  
  14725.   -- Check if this notification exists
  14726.   IF (NOT EXISTS (SELECT *
  14727.                   FROM msdb.dbo.sysnotifications
  14728.                   WHERE (alert_id = @alert_id)
  14729.                     AND (operator_id = @operator_id)))
  14730.   BEGIN
  14731.     SELECT @notification = @alert_name + N' / ' + @operator_name
  14732.     RAISERROR(14262, 16, 1, @res_notification, @notification)
  14733.     RETURN(1) -- Failure
  14734.   END
  14735.  
  14736.   SELECT @old_has_notification = has_notification 
  14737.   FROM msdb.dbo.sysalerts 
  14738.   WHERE (id = @alert_id)
  14739.  
  14740.   -- Do the UPDATE
  14741.   UPDATE msdb.dbo.sysnotifications
  14742.   SET notification_method = @notification_method
  14743.   WHERE (alert_id = @alert_id)
  14744.     AND (operator_id = @operator_id)
  14745.  
  14746.   SELECT @retval = @@error
  14747.  
  14748.   SELECT @new_has_notification = has_notification 
  14749.   FROM msdb.dbo.sysalerts 
  14750.   WHERE (id = @alert_id)
  14751.  
  14752.   -- Notify SQLServerAgent of the change - if any - to has_notifications
  14753.   IF (@old_has_notification <> @new_has_notification)
  14754.     EXECUTE msdb.dbo.sp_sqlagent_notify @op_type       = N'A',
  14755.                                           @alert_id    = @alert_id,
  14756.                                           @action_type = N'U'
  14757.  
  14758.   RETURN(@retval) -- 0 means success
  14759. END
  14760. go
  14761.  
  14762. /**************************************************************/
  14763. /* SP_DELETE_NOTIFICATION                                     */
  14764. /**************************************************************/
  14765.  
  14766. PRINT ''
  14767. PRINT 'Creating procedure sp_delete_notification...'
  14768. go
  14769. IF (EXISTS (SELECT *
  14770.             FROM msdb.dbo.sysobjects
  14771.             WHERE (name = N'sp_delete_notification')
  14772.               AND (type = 'P')))
  14773.   DROP PROCEDURE sp_delete_notification
  14774. go
  14775. CREATE PROCEDURE sp_delete_notification
  14776.   @alert_name    sysname,
  14777.   @operator_name sysname
  14778. AS
  14779. BEGIN
  14780.   DECLARE @alert_id             INT
  14781.   DECLARE @operator_id          INT
  14782.   DECLARE @ignored              TINYINT
  14783.   DECLARE @notification         NVARCHAR(512)
  14784.   DECLARE @retval               INT
  14785.   DECLARE @old_has_notification INT
  14786.   DECLARE @new_has_notification INT
  14787.   DECLARE @res_notification     NVARCHAR(100)
  14788.  
  14789.   SET NOCOUNT ON
  14790.  
  14791.   SELECT @res_notification = FORMATMESSAGE(14210)
  14792.  
  14793.   -- Remove any leading/trailing spaces from parameters
  14794.   SELECT @alert_name    = LTRIM(RTRIM(@alert_name))
  14795.   SELECT @operator_name = LTRIM(RTRIM(@operator_name))
  14796.  
  14797.   -- Only a sysadmin can do this
  14798.   IF (ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) <> 1)
  14799.   BEGIN
  14800.     RAISERROR(15003, 16, 1, N'sysadmin')
  14801.     RETURN(1) -- Failure
  14802.   END
  14803.  
  14804.   -- Get the alert and operator ID's
  14805.   EXECUTE sp_verify_notification @alert_name,
  14806.                                  @operator_name,
  14807.                                  7,           -- A dummy (but valid) value
  14808.                                  @alert_id    OUTPUT,
  14809.                                  @operator_id OUTPUT
  14810.  
  14811.   -- Check if this notification exists
  14812.   IF (NOT EXISTS (SELECT *
  14813.                   FROM msdb.dbo.sysnotifications
  14814.                   WHERE (alert_id = @alert_id)
  14815.                     AND (operator_id = @operator_id)))
  14816.   BEGIN
  14817.     SELECT @notification = @alert_name + N' / ' + @operator_name
  14818.     RAISERROR(14262, 16, 1, @res_notification, @notification)
  14819.     RETURN(1) -- Failure
  14820.   END
  14821.  
  14822.   SELECT @old_has_notification = has_notification 
  14823.   FROM msdb.dbo.sysalerts 
  14824.   WHERE (id = @alert_id)
  14825.  
  14826.   -- Do the Delete
  14827.   DELETE FROM msdb.dbo.sysnotifications
  14828.   WHERE (alert_id = @alert_id)
  14829.     AND (operator_id = @operator_id)
  14830.  
  14831.   SELECT @retval = @@error
  14832.  
  14833.   SELECT @new_has_notification = has_notification 
  14834.   FROM msdb.dbo.sysalerts 
  14835.   WHERE (id = @alert_id)
  14836.  
  14837.   -- Notify SQLServerAgent of the change - if any - to has_notifications
  14838.   IF (@old_has_notification <> @new_has_notification)
  14839.     EXECUTE msdb.dbo.sp_sqlagent_notify @op_type       = N'A',
  14840.                                           @alert_id    = @alert_id,
  14841.                                           @action_type = N'U'
  14842.  
  14843.   RETURN(@retval) -- 0 means success
  14844. END
  14845. go
  14846.  
  14847. /**************************************************************/
  14848. /* SP_HELP_NOTIFICATION                                       */
  14849. /**************************************************************/
  14850.  
  14851. PRINT ''
  14852. PRINT 'Creating procedure sp_help_notification...'
  14853. go
  14854. IF (EXISTS (SELECT *
  14855.             FROM msdb.dbo.sysobjects
  14856.             WHERE (name = N'sp_help_notification')
  14857.               AND (type = 'P')))
  14858.   DROP PROCEDURE sp_help_notification
  14859. go
  14860. CREATE PROCEDURE sp_help_notification
  14861.   @object_type          CHAR(9),   -- Either 'ALERTS'    (enumerates Alerts for given Operator)
  14862.                                    --     or 'OPERATORS' (enumerates Operators for given Alert)
  14863.   @name                 sysname,   -- Either an Operator Name (if @object_type is 'ALERTS')
  14864.                                    --     or an Alert Name    (if @object_type is 'OPERATORS')
  14865.   @enum_type            CHAR(10),  -- Either 'ALL'    (enumerate all objects [eg. all alerts irrespective of whether 'Fred' receives a notification for them])
  14866.                                    --     or 'ACTUAL' (enumerate only the associated objects [eg. only the alerts which 'Fred' receives a notification for])
  14867.                                    --     or 'TARGET' (enumerate only the objects matching @target_name [eg. a single row showing how 'Fred' is notfied for alert 'Test'])
  14868.   @notification_method  TINYINT,   -- Either 1 (Email)   - Modifies the result set to only show use_email column
  14869.                                    --     or 2 (Pager)   - Modifies the result set to only show use_pager column
  14870.                                    --     or 4 (NetSend) - Modifies the result set to only show use_netsend column
  14871.                                    --     or 7 (All)     - Modifies the result set to show all the use_xxx columns
  14872.   @target_name   sysname = NULL    -- Either an Alert Name    (if @object_type is 'ALERTS')
  14873.                                    --     or an Operator Name (if @object_type is 'OPERATORS')
  14874.                                    -- NOTE: This parameter is only required if @enum_type is 'TARGET')
  14875. AS
  14876. BEGIN
  14877.   DECLARE @id              INT    -- We use this to store the decode of @name
  14878.   DECLARE @target_id       INT    -- We use this to store the decode of @target_name
  14879.   DECLARE @select_clause   NVARCHAR(1024)
  14880.   DECLARE @from_clause     NVARCHAR(512)
  14881.   DECLARE @where_clause    NVARCHAR(512)
  14882.   DECLARE @res_valid_range NVARCHAR(100)
  14883.  
  14884.   SET NOCOUNT ON
  14885.  
  14886.   SELECT @res_valid_range = FORMATMESSAGE(14208)
  14887.  
  14888.   -- Remove any leading/trailing spaces from parameters
  14889.   SELECT @object_type = UPPER(LTRIM(RTRIM(@object_type)))
  14890.   SELECT @name        = LTRIM(RTRIM(@name))
  14891.   SELECT @enum_type   = UPPER(LTRIM(RTRIM(@enum_type)))
  14892.   SELECT @target_name = LTRIM(RTRIM(@target_name))
  14893.  
  14894.   -- Turn [nullable] empty string parameters into NULLs
  14895.   IF (@target_name = N'') SELECT @target_name = NULL
  14896.  
  14897.   -- Check ObjectType
  14898.   IF (@object_type NOT IN ('ALERTS', 'OPERATORS'))
  14899.   BEGIN
  14900.     RAISERROR(14266, 16, 1, '@object_type', 'ALERTS, OPERATORS')
  14901.     RETURN(1) -- Failure
  14902.   END
  14903.  
  14904.   -- Check AlertName
  14905.   IF (@object_type = 'OPERATORS') AND
  14906.      (NOT EXISTS (SELECT *
  14907.                   FROM msdb.dbo.sysalerts
  14908.                   WHERE (name = @name)))
  14909.   BEGIN
  14910.     RAISERROR(14262, 16, 1, '@name', @name)
  14911.     RETURN(1) -- Failure
  14912.   END
  14913.  
  14914.   -- Check OperatorName
  14915.   IF (@object_type = 'ALERTS') AND
  14916.      (NOT EXISTS (SELECT *
  14917.                   FROM msdb.dbo.sysoperators
  14918.                   WHERE (name = @name)))
  14919.   BEGIN
  14920.     RAISERROR(14262, 16, 1, '@name', @name)
  14921.     RETURN(1) -- Failure
  14922.   END
  14923.  
  14924.   -- Check EnumType
  14925.   IF (@enum_type NOT IN ('ALL', 'ACTUAL', 'TARGET'))
  14926.   BEGIN
  14927.     RAISERROR(14266, 16, 1, '@enum_type', 'ALL, ACTUAL, TARGET')
  14928.     RETURN(1) -- Failure
  14929.   END
  14930.  
  14931.   -- Check Notification Method
  14932.   IF ((@notification_method < 1) OR (@notification_method > 7))
  14933.   BEGIN
  14934.     RAISERROR(14266, 16, 1, '@notification_method', @res_valid_range)
  14935.     RETURN(1) -- Failure
  14936.   END
  14937.  
  14938.   -- If EnumType is 'TARGET', check if we have a @TargetName parameter
  14939.   IF (@enum_type = 'TARGET') AND (@target_name IS NULL)
  14940.   BEGIN
  14941.     RAISERROR(14502, 16, 1)
  14942.     RETURN(1) -- Failure
  14943.   END
  14944.  
  14945.   -- If EnumType isn't 'TARGET', we shouldn't have an @target_name parameter
  14946.   IF (@enum_type <> 'TARGET') AND (@target_name IS NOT NULL)
  14947.   BEGIN
  14948.     RAISERROR(14503, 16, 1)
  14949.     RETURN(1) -- Failure
  14950.   END
  14951.  
  14952.   -- Translate the Name into an ID
  14953.   IF (@object_type = 'ALERTS')
  14954.   BEGIN
  14955.     SELECT @id = id
  14956.     FROM msdb.dbo.sysoperators
  14957.     WHERE (name = @name)
  14958.   END
  14959.   IF (@object_type = 'OPERATORS')
  14960.   BEGIN
  14961.     SELECT @id = id
  14962.     FROM msdb.dbo.sysalerts
  14963.     WHERE (name = @name)
  14964.   END
  14965.  
  14966.   -- Translate the TargetName into a TargetID
  14967.   IF (@target_name IS NOT NULL)
  14968.   BEGIN
  14969.     IF (@object_type = 'OPERATORS')
  14970.     BEGIN
  14971.       SELECT @target_id = id
  14972.       FROM msdb.dbo.sysoperators
  14973.       WHERE (name = @target_name )
  14974.     END
  14975.     IF (@object_type = 'ALERTS')
  14976.     BEGIN
  14977.       SELECT @target_id = id
  14978.       FROM msdb.dbo.sysalerts
  14979.       WHERE (name = @target_name)
  14980.     END
  14981.     IF (@target_id IS NULL) -- IE. the Target Name is invalid
  14982.     BEGIN
  14983.       RAISERROR(14262, 16, 1, @object_type, @target_name)
  14984.       RETURN(1) -- Failure
  14985.     END
  14986.   END
  14987.  
  14988.   -- Ok, the parameters look good so generate the SQL then EXECUTE() it...
  14989.  
  14990.   -- Generate the 'stub' SELECT clause and the FROM clause
  14991.   IF (@object_type = 'OPERATORS') -- So we want a list of Operators for the supplied AlertID
  14992.   BEGIN
  14993.     SELECT @select_clause = N'SELECT operator_id = o.id, operator_name = o.name, '
  14994.     IF (@enum_type = 'ALL')
  14995.       SELECT @from_clause = N'FROM msdb.dbo.sysoperators o LEFT OUTER JOIN msdb.dbo.sysnotifications sn ON (o.id = sn.operator_id) '
  14996.     ELSE
  14997.       SELECT @from_clause = N'FROM msdb.dbo.sysoperators o, msdb.dbo.sysnotifications sn '
  14998.   END
  14999.   IF (@object_type = 'ALERTS') -- So we want a list of Alerts for the supplied OperatorID
  15000.   BEGIN
  15001.     SELECT @select_clause = N'SELECT alert_id = a.id, alert_name = a.name, '
  15002.     IF (@enum_type = 'ALL')
  15003.       SELECT @from_clause = N'FROM msdb.dbo.sysalerts a LEFT OUTER JOIN msdb.dbo.sysnotifications sn ON (a.id = sn.alert_id) '
  15004.     ELSE
  15005.       SELECT @from_clause = N'FROM msdb.dbo.sysalerts a, msdb.dbo.sysnotifications sn '
  15006.   END
  15007.  
  15008.   -- Add the required use_xxx columns to the SELECT clause
  15009.   IF (@notification_method & 1 = 1)
  15010.     SELECT @select_clause = @select_clause + N'use_email = ISNULL((sn.notification_method & 1) / POWER(2, 0), 0), '
  15011.   IF (@notification_method & 2 = 2)
  15012.     SELECT @select_clause = @select_clause + N'use_pager = ISNULL((sn.notification_method & 2) / POWER(2, 1), 0), '
  15013.   IF (@notification_method & 4 = 4)
  15014.     SELECT @select_clause = @select_clause + N'use_netsend = ISNULL((sn.notification_method & 4) / POWER(2, 2), 0), '
  15015.  
  15016.   -- Remove the trailing comma
  15017.   SELECT @select_clause = SUBSTRING(@select_clause, 1, (DATALENGTH(@select_clause) / 2) - 2) + N' '
  15018.  
  15019.   -- Generate the WHERE clause
  15020.   IF (@object_type = 'OPERATORS')
  15021.   BEGIN
  15022.     IF (@enum_type = 'ALL')
  15023.       SELECT @from_clause = @from_clause + N' AND (sn.alert_id = ' + CONVERT(VARCHAR(10), @id) + N')'
  15024.  
  15025.     IF (@enum_type = 'ACTUAL')
  15026.       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)'
  15027.  
  15028.     IF (@enum_type = 'TARGET')
  15029.       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')'
  15030.   END
  15031.   IF (@object_type = 'ALERTS')
  15032.   BEGIN
  15033.     IF (@enum_type = 'ALL')
  15034.       SELECT @from_clause = @from_clause + N' AND (sn.operator_id = ' + CONVERT(VARCHAR(10), @id) + N')'
  15035.  
  15036.     IF (@enum_type = 'ACTUAL')
  15037.       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)'
  15038.  
  15039.     IF (@enum_type = 'TARGET')
  15040.       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')'
  15041.   END
  15042.  
  15043.   -- Add the has_email and has_pager columns to the SELECT clause
  15044.   IF (@object_type = 'OPERATORS')
  15045.   BEGIN
  15046.     SELECT @select_clause = @select_clause + N', has_email = PATINDEX(N''%[^ ]%'', ISNULL(o.email_address, N''''))'
  15047.     SELECT @select_clause = @select_clause + N', has_pager = PATINDEX(N''%[^ ]%'', ISNULL(o.pager_address, N''''))'
  15048.     SELECT @select_clause = @select_clause + N', has_netsend = PATINDEX(N''%[^ ]%'', ISNULL(o.netsend_address, N''''))'
  15049.   END
  15050.   IF (@object_type = 'ALERTS')
  15051.   BEGIN
  15052.     -- NOTE: We return counts so that the UI can detect 'unchecking' the last notification
  15053.     SELECT @select_clause = @select_clause + N', has_email = (SELECT COUNT(*) FROM sysnotifications WHERE (alert_id = a.id) AND ((notification_method & 1) = 1)) '
  15054.     SELECT @select_clause = @select_clause + N', has_pager = (SELECT COUNT(*) FROM sysnotifications WHERE (alert_id = a.id) AND ((notification_method & 2) = 2)) '
  15055.     SELECT @select_clause = @select_clause + N', has_netsend = (SELECT COUNT(*) FROM sysnotifications WHERE (alert_id = a.id) AND ((notification_method & 4) = 4)) '
  15056.   END
  15057.  
  15058.   EXECUTE (@select_clause + @from_clause + @where_clause)
  15059.  
  15060.   RETURN(@@error) -- 0 means success
  15061. END
  15062. go
  15063.  
  15064. DUMP TRANSACTION msdb WITH NO_LOG
  15065. go
  15066.  
  15067. /**************************************************************/
  15068. /*                                                            */
  15069. /*                    T  R  I G  G  E  R  S                   */
  15070. /*                                                            */
  15071. /**************************************************************/
  15072.  
  15073. /**************************************************************/
  15074. /* DROP THE OLD 6.x TRIGGERS                                  */
  15075. /* [multiple triggers of the same type are allowed in 7.0]    */
  15076. /**************************************************************/
  15077.  
  15078. IF (EXISTS (SELECT *
  15079.             FROM msdb.dbo.sysobjects
  15080.             WHERE (name = N'NewOrChangedNotification')
  15081.               AND (type = 'TR')))
  15082.   DROP TRIGGER NewOrChangedNotification
  15083.  
  15084. IF (EXISTS (SELECT *
  15085.             FROM msdb.dbo.sysobjects
  15086.             WHERE (name = N'RemovedNotification')
  15087.               AND (type = 'TR')))
  15088.   DROP TRIGGER RemovedNotification
  15089. go
  15090.  
  15091. /**************************************************************/
  15092. /* TRIG_NOTIFICATION_INS_OR_UPD                               */
  15093. /**************************************************************/
  15094.  
  15095. PRINT ''
  15096. PRINT 'Creating trigger trig_notification_ins_or_upd...'
  15097. go
  15098. IF (EXISTS (SELECT *
  15099.             FROM msdb.dbo.sysobjects
  15100.             WHERE (name = N'trig_notification_ins_or_upd')
  15101.               AND (type = 'TR')))
  15102.   DROP TRIGGER trig_notification_ins_or_upd
  15103. go
  15104. CREATE TRIGGER trig_notification_ins_or_upd
  15105. ON msdb.dbo.sysnotifications
  15106. FOR INSERT,
  15107.     UPDATE
  15108. AS
  15109. BEGIN
  15110.   SET NOCOUNT ON
  15111.  
  15112.   -- First, throw out 'non-notification' rows
  15113.   DELETE FROM msdb.dbo.sysnotifications
  15114.   WHERE (notification_method = 0)
  15115.  
  15116.   -- Reset the has_notification flag for the affected alerts
  15117.   UPDATE msdb.dbo.sysalerts
  15118.   SET has_notification = 0
  15119.   FROM inserted           i,
  15120.        msdb.dbo.sysalerts sa
  15121.   WHERE (i.alert_id = sa.id)
  15122.  
  15123.   -- Update sysalerts.has_notification (for email)
  15124.   UPDATE msdb.dbo.sysalerts
  15125.   SET has_notification = has_notification | 1
  15126.   FROM msdb.dbo.sysalerts        sa,
  15127.        msdb.dbo.sysnotifications sn,
  15128.        inserted                  i
  15129.   WHERE (sa.id = sn.alert_id) 
  15130.     AND (sa.id = i.alert_id)
  15131.     AND ((sn.notification_method & 1) = 1)
  15132.  
  15133.   -- Update sysalerts.has_notification (for pager)
  15134.   UPDATE msdb.dbo.sysalerts
  15135.   SET has_notification = has_notification | 2
  15136.   FROM msdb.dbo.sysalerts        sa,
  15137.        msdb.dbo.sysnotifications sn,
  15138.        inserted                  i
  15139.   WHERE (sa.id = sn.alert_id) 
  15140.     AND (sa.id = i.alert_id)
  15141.     AND ((sn.notification_method & 2) = 2)
  15142.  
  15143.   -- Update sysalerts.has_notification (for netsend)
  15144.   UPDATE msdb.dbo.sysalerts
  15145.   SET has_notification = has_notification | 4
  15146.   FROM msdb.dbo.sysalerts        sa,
  15147.        msdb.dbo.sysnotifications sn,
  15148.        inserted                  i
  15149.   WHERE (sa.id = sn.alert_id) 
  15150.     AND (sa.id = i.alert_id)
  15151.     AND ((sn.notification_method & 4) = 4)
  15152. END
  15153. go
  15154.  
  15155. /**************************************************************/
  15156. /* TRIG_NOTIFICATION_DELETE                                   */
  15157. /**************************************************************/
  15158.  
  15159. PRINT ''
  15160. PRINT 'Creating trigger trig_notification_delete...'
  15161. go
  15162. IF (EXISTS (SELECT *
  15163.             FROM msdb.dbo.sysobjects
  15164.             WHERE (name = N'trig_notification_delete')
  15165.               AND (type = 'TR')))
  15166.   DROP TRIGGER trig_notification_delete
  15167. go
  15168. CREATE TRIGGER trig_notification_delete
  15169. ON msdb.dbo.sysnotifications
  15170. FOR DELETE
  15171. AS
  15172. BEGIN
  15173.   SET NOCOUNT ON
  15174.  
  15175.   -- Reset the has_notification flag for the affected alerts
  15176.   UPDATE msdb.dbo.sysalerts
  15177.   SET has_notification = 0
  15178.   FROM deleted            d,
  15179.        msdb.dbo.sysalerts sa
  15180.   WHERE (d.alert_id = sa.id)
  15181.  
  15182.   -- Update sysalerts.has_notification (for email)
  15183.   UPDATE msdb.dbo.sysalerts
  15184.   SET has_notification = has_notification | 1
  15185.   FROM msdb.dbo.sysalerts        sa,
  15186.        msdb.dbo.sysnotifications sn,
  15187.        deleted                   d
  15188.   WHERE (sa.id = sn.alert_id) 
  15189.     AND (sa.id = d.alert_id)
  15190.     AND ((sn.notification_method & 1) = 1)
  15191.  
  15192.   -- Update sysalerts.has_notification (for pager)
  15193.   UPDATE msdb.dbo.sysalerts
  15194.   SET has_notification = has_notification | 2
  15195.   FROM msdb.dbo.sysalerts        sa,
  15196.        msdb.dbo.sysnotifications sn,
  15197.        deleted                   d
  15198.   WHERE (sa.id = sn.alert_id) 
  15199.     AND (sa.id = d.alert_id)
  15200.     AND ((sn.notification_method & 2) = 2)
  15201.  
  15202.   -- Update sysalerts.has_notification (for netsend)
  15203.   UPDATE msdb.dbo.sysalerts
  15204.   SET has_notification = has_notification | 4
  15205.   FROM msdb.dbo.sysalerts        sa,
  15206.        msdb.dbo.sysnotifications sn,
  15207.        deleted                   d
  15208.   WHERE (sa.id = sn.alert_id) 
  15209.     AND (sa.id = d.alert_id)
  15210.     AND ((sn.notification_method & 4) = 4)
  15211. END
  15212. go
  15213.  
  15214. DUMP TRANSACTION msdb WITH NO_LOG
  15215. go
  15216.  
  15217. /**************************************************************/
  15218. /*                                                            */
  15219. /*          D  E  F  A  U  L  T    A  L  E  R  T  S           */
  15220. /*                                                            */
  15221. /**************************************************************/
  15222.  
  15223. PRINT ''
  15224. PRINT 'Installing default alerts...'
  15225. go
  15226.  
  15227. EXECUTE master.dbo.sp_altermessage 9002, 'WITH_LOG', TRUE
  15228. go
  15229.  
  15230. IF (NOT EXISTS (SELECT *
  15231.                 FROM msdb.dbo.sysalerts
  15232.                 WHERE (name = N'Demo: Full msdb log')
  15233.                    OR ((severity = 0) AND
  15234.                        (message_id = 9002) AND
  15235.                        (database_name = N'msdb') AND
  15236.                        (event_description_keyword IS NULL) AND
  15237.                        (performance_condition IS NULL))))
  15238.   EXECUTE msdb.dbo.sp_add_alert @name = N'Demo: Full msdb log',
  15239.                                 @message_id = 9002,
  15240.                                 @severity = 0,
  15241.                                 @enabled = 1,
  15242.                                 @delay_between_responses = 10,
  15243.                                 @database_name = N'msdb',
  15244.                                 @notification_message = NULL,
  15245.                                 @job_name = NULL,
  15246.                                 @event_description_keyword = NULL,
  15247.                                 @include_event_description_in = 5 -- Email and NetSend
  15248. go
  15249.  
  15250. IF (NOT EXISTS (SELECT *
  15251.                 FROM msdb.dbo.sysalerts
  15252.                 WHERE (name = N'Demo: Full tempdb')
  15253.                    OR ((severity = 0) AND
  15254.                        (message_id = 9002) AND
  15255.                        (database_name = N'tempdb') AND
  15256.                        (event_description_keyword IS NULL) AND
  15257.                        (performance_condition IS NULL))))
  15258.   EXECUTE msdb.dbo.sp_add_alert @name = N'Demo: Full tempdb',
  15259.                                 @message_id = 9002,
  15260.                                 @severity = 0,
  15261.                                 @enabled = 1,
  15262.                                 @delay_between_responses = 10,
  15263.                                 @database_name = N'tempdb',
  15264.                                 @notification_message = NULL,
  15265.                                 @job_name = NULL,
  15266.                                 @event_description_keyword = NULL,
  15267.                                 @include_event_description_in = 5 -- Email and NetSend
  15268. go
  15269.  
  15270. IF (NOT EXISTS (SELECT *
  15271.                 FROM msdb.dbo.sysalerts
  15272.                 WHERE (name = N'Demo: Sev. 19 Errors')
  15273.                    OR ((severity = 19) AND
  15274.                        (message_id = 0) AND
  15275.                        (database_name IS NULL) AND
  15276.                        (event_description_keyword IS NULL) AND
  15277.                        (performance_condition IS NULL))))
  15278.   EXECUTE msdb.dbo.sp_add_alert @name = N'Demo: Sev. 19 Errors',
  15279.                                 @message_id = 0,
  15280.                                 @severity = 19,
  15281.                                 @enabled = 1,
  15282.                                 @delay_between_responses = 10,
  15283.                                 @database_name = NULL,
  15284.                                 @notification_message = NULL,
  15285.                                 @job_name = NULL,
  15286.                                 @event_description_keyword = NULL,
  15287.                                 @include_event_description_in = 5 -- Email and NetSend
  15288. go
  15289.  
  15290. IF (NOT EXISTS (SELECT *
  15291.                 FROM msdb.dbo.sysalerts
  15292.                 WHERE (name = N'Demo: Sev. 20 Errors')
  15293.                    OR ((severity = 20) AND
  15294.                        (message_id = 0) AND
  15295.                        (database_name IS NULL) AND
  15296.                        (event_description_keyword IS NULL) AND
  15297.                        (performance_condition IS NULL))))
  15298.   EXECUTE msdb.dbo.sp_add_alert @name = N'Demo: Sev. 20 Errors',
  15299.                                 @message_id = 0,
  15300.                                 @severity = 20,
  15301.                                 @enabled = 1,
  15302.                                 @delay_between_responses = 10,
  15303.                                 @database_name = NULL,
  15304.                                 @notification_message = NULL,
  15305.                                 @job_name = NULL,
  15306.                                 @event_description_keyword = NULL,
  15307.                                 @include_event_description_in = 5 -- Email and NetSend
  15308. go
  15309.  
  15310. IF (NOT EXISTS (SELECT *
  15311.                 FROM msdb.dbo.sysalerts
  15312.                 WHERE (name = N'Demo: Sev. 21 Errors')
  15313.                    OR ((severity = 21) AND
  15314.                        (message_id = 0) AND
  15315.                        (database_name IS NULL) AND
  15316.                        (event_description_keyword IS NULL) AND
  15317.                        (performance_condition IS NULL))))
  15318.   EXECUTE msdb.dbo.sp_add_alert @name = N'Demo: Sev. 21 Errors',
  15319.                                 @message_id = 0,
  15320.                                 @severity = 21,
  15321.                                 @enabled = 1,
  15322.                                 @delay_between_responses = 10,
  15323.                                 @database_name = NULL,
  15324.                                 @notification_message = NULL,
  15325.                                 @job_name = NULL,
  15326.                                 @event_description_keyword = NULL,
  15327.                                 @include_event_description_in = 5 -- Email and NetSend
  15328. go
  15329.  
  15330. IF (NOT EXISTS (SELECT *
  15331.                 FROM msdb.dbo.sysalerts
  15332.                 WHERE (name = N'Demo: Sev. 22 Errors')
  15333.                    OR ((severity = 22) AND
  15334.                        (message_id = 0) AND
  15335.                        (database_name IS NULL) AND
  15336.                        (event_description_keyword IS NULL) AND
  15337.                        (performance_condition IS NULL))))
  15338.   EXECUTE msdb.dbo.sp_add_alert @name = N'Demo: Sev. 22 Errors',
  15339.                                 @message_id = 0,
  15340.                                 @severity = 22,
  15341.                                 @enabled = 1,
  15342.                                 @delay_between_responses = 10,
  15343.                                 @database_name = NULL,
  15344.                                 @notification_message = NULL,
  15345.                                 @job_name = NULL,
  15346.                                 @event_description_keyword = NULL,
  15347.                                 @include_event_description_in = 5 -- Email and NetSend
  15348. go
  15349.  
  15350. IF (NOT EXISTS (SELECT *
  15351.                 FROM msdb.dbo.sysalerts
  15352.                 WHERE name = N'Demo: Sev. 23 Errors'
  15353.                    OR ((severity = 23) AND
  15354.                        (message_id = 0) AND
  15355.                        (database_name IS NULL) AND
  15356.                        (event_description_keyword IS NULL) AND
  15357.                        (performance_condition IS NULL))))
  15358.   EXECUTE msdb.dbo.sp_add_alert @name = N'Demo: Sev. 23 Errors',
  15359.                                 @message_id = 0,
  15360.                                 @severity = 23,
  15361.                                 @enabled = 1,
  15362.                                 @delay_between_responses = 10,
  15363.                                 @database_name = NULL,
  15364.                                 @notification_message = NULL,
  15365.                                 @job_name = NULL,
  15366.                                 @event_description_keyword = NULL,
  15367.                                 @include_event_description_in = 5 -- Email and NetSend
  15368. go
  15369.  
  15370. IF (NOT EXISTS (SELECT *
  15371.                 FROM msdb.dbo.sysalerts
  15372.                 WHERE (name = N'Demo: Sev. 24 Errors')
  15373.                    OR ((severity = 24) AND
  15374.                        (message_id = 0) AND
  15375.                        (database_name IS NULL) AND
  15376.                        (event_description_keyword IS NULL) AND
  15377.                        (performance_condition IS NULL))))
  15378.   EXECUTE msdb.dbo.sp_add_alert @name = N'Demo: Sev. 24 Errors',
  15379.                                 @message_id = 0,
  15380.                                 @severity = 24,
  15381.                                 @enabled = 1,
  15382.                                 @delay_between_responses = 10,
  15383.                                 @database_name = NULL,
  15384.                                 @notification_message = NULL,
  15385.                                 @job_name = NULL,
  15386.                                 @event_description_keyword = NULL,
  15387.                                 @include_event_description_in = 5 -- Email and NetSend
  15388. go
  15389.  
  15390. IF (NOT EXISTS (SELECT *
  15391.                 FROM msdb.dbo.sysalerts
  15392.                 WHERE (name = N'Demo: Sev. 25 Errors')
  15393.                    OR ((severity = 25) AND
  15394.                        (message_id = 0) AND
  15395.                        (database_name IS NULL) AND
  15396.                        (event_description_keyword IS NULL) AND
  15397.                        (performance_condition IS NULL))))
  15398.   EXECUTE msdb.dbo.sp_add_alert @name = N'Demo: Sev. 25 Errors',
  15399.                                 @message_id = 0,
  15400.                                 @severity = 25,
  15401.                                 @enabled = 1,
  15402.                                 @delay_between_responses = 10,
  15403.                                 @database_name = NULL,
  15404.                                 @notification_message = NULL,
  15405.                                 @job_name = NULL,
  15406.                                 @event_description_keyword = NULL,
  15407.                                 @include_event_description_in = 5 -- Email and NetSend
  15408. go
  15409.  
  15410.  
  15411. /**************************************************************/
  15412. /**                                                          **/
  15413. /**       B A C K U P   H I S T O R Y   S U P P O R T        **/
  15414. /**                                                          **/
  15415. /**************************************************************/
  15416.  
  15417. /**************************************************************/
  15418. /* T A B L E S                                                */
  15419. /**************************************************************/
  15420.  
  15421. /**************************************************************/
  15422. /* BACKUPMEDIASET                                             */
  15423. /**************************************************************/
  15424.  
  15425. IF (NOT EXISTS (SELECT *
  15426.                 FROM msdb.dbo.sysobjects
  15427.                 WHERE (name = 'backupmediaset')))
  15428. BEGIN
  15429.   PRINT ''
  15430.   PRINT 'Creating table backupmediaset...'
  15431.  
  15432.   CREATE TABLE backupmediaset
  15433.   (
  15434.   media_set_id       INT IDENTITY     NOT NULL PRIMARY KEY,
  15435.   media_uuid         UNIQUEIDENTIFIER NULL,  -- Null if this media set only one media family
  15436.   media_family_count TINYINT          NULL,  -- Number of media families in the media set
  15437.   name               NVARCHAR(128)    NULL,
  15438.   description        NVARCHAR(255)    NULL,
  15439.   software_name      NVARCHAR(128)    NULL,
  15440.   software_vendor_id INT              NULL,
  15441.   MTF_major_version  TINYINT          NULL
  15442.   )
  15443.  
  15444.   CREATE INDEX backupmediasetuuid ON backupmediaset (media_uuid)
  15445. END
  15446. go
  15447.  
  15448. /**************************************************************/
  15449. /* BACKUPMEDIAFAMILY                                          */
  15450. /**************************************************************/
  15451.  
  15452. IF (NOT EXISTS (SELECT *
  15453.                 FROM msdb.dbo.sysobjects
  15454.                 WHERE (name = 'backupmediafamily')))
  15455. BEGIN
  15456.   PRINT ''
  15457.   PRINT 'Creating table backupmediafamily...'
  15458.  
  15459.   CREATE TABLE backupmediafamily
  15460.   (
  15461.   media_set_id           INT              NOT NULL REFERENCES backupmediaset(media_set_id),
  15462.   family_sequence_number TINYINT          NOT NULL, -- Raid sequence number
  15463.   media_family_id        UNIQUEIDENTIFIER NULL,     -- This will be a uuid in MTF 2.0, allow space
  15464.   media_count            INT              NULL,     -- Number of media in the family
  15465.   logical_device_name    NVARCHAR(128)    NULL,     -- Name from sysdevices, if any
  15466.   physical_device_name   NVARCHAR(260)    NULL,     -- To facilitate restores from online media (disk)
  15467.   device_type            TINYINT          NULL,  -- Disk, tape, pipe, ...
  15468.   physical_block_size    INT              NULL
  15469.   PRIMARY KEY (media_set_id, family_sequence_number)
  15470.   )
  15471.  
  15472.   CREATE INDEX backupmediafamilyuuid ON backupmediafamily (media_family_id)
  15473. END
  15474. go
  15475.  
  15476. /**************************************************************/
  15477. /* BACKUPSET - One row per backup operation.                  */
  15478. /**************************************************************/
  15479.  
  15480. IF (NOT EXISTS (SELECT *
  15481.                 FROM msdb.dbo.sysobjects
  15482.                 WHERE (name = 'backupset')))
  15483. BEGIN
  15484.   PRINT ''
  15485.   PRINT 'Creating table backupset...'
  15486.  
  15487.   CREATE TABLE backupset
  15488.   (
  15489.   backup_set_id          INT IDENTITY     NOT NULL PRIMARY KEY,
  15490.   backup_set_uuid        UNIQUEIDENTIFIER NOT NULL,
  15491.   media_set_id           INT              NOT NULL REFERENCES backupmediaset(media_set_id),
  15492.   first_family_number    TINYINT          NULL,  -- family number & media number of the media
  15493.   first_media_number     SMALLINT         NULL,  -- containing the start of this backup (first SSET)
  15494.   last_family_number     TINYINT          NULL,  -- family number & media number of the media
  15495.   last_media_number      SMALLINT         NULL,  -- containing the end of this backup (ESET after MBC)
  15496.   catalog_family_number  TINYINT          NULL,  -- family number & media number of the media
  15497.   catalog_media_number   SMALLINT         NULL,  -- containing the start of the 'directory' data stream
  15498.  
  15499.   position               INT              NULL,  -- For FILE=
  15500.   expiration_date        DATETIME         NULL,
  15501.  
  15502.   -- From SSET...
  15503.   software_vendor_id     INT              NULL,  -- Might want table for sw vendors
  15504.   name                   NVARCHAR(128)    NULL,
  15505.   description            NVARCHAR(255)    NULL,
  15506.   user_name              NVARCHAR(128)    NULL,
  15507.   software_major_version TINYINT          NULL,    
  15508.   software_minor_version TINYINT          NULL,    
  15509.   software_build_version SMALLINT         NULL,
  15510.   time_zone              SMALLINT         NULL,        
  15511.   mtf_minor_version      TINYINT          NULL,
  15512.  
  15513.   -- From CONFIG_INFO...
  15514.   first_lsn              NUMERIC(25,0)    NULL,
  15515.   last_lsn               NUMERIC(25,0)    NULL,
  15516.   checkpoint_lsn         NUMERIC(25,0)    NULL,
  15517.   database_backup_lsn    NUMERIC(25,0)    NULL,
  15518.   database_creation_date DATETIME         NULL,
  15519.   backup_start_date      DATETIME         NULL,
  15520.   backup_finish_date     DATETIME         NULL,
  15521.   type                   CHAR(1)          NULL,
  15522.   sort_order             SMALLINT         NULL,
  15523.   code_page              SMALLINT         NULL,
  15524.   compatibility_level    TINYINT          NULL,
  15525.   database_version       INT              NULL,
  15526.   backup_size            NUMERIC(20,0)    NULL,
  15527.   database_name          NVARCHAR(128)    NULL,
  15528.   server_name            NVARCHAR(128)    NULL,
  15529.   machine_name           NVARCHAR(128)    NULL
  15530.   )
  15531.  
  15532.   CREATE INDEX backupsetuuid ON backupset (backup_set_uuid)
  15533. END
  15534. go
  15535.  
  15536. /**************************************************************/
  15537. /* BACKUPFILE - One row per file backed up (data file, log    */
  15538. /*              file)                                         */
  15539. /**************************************************************/
  15540.  
  15541. IF (NOT EXISTS (SELECT *
  15542.                 FROM msdb.dbo.sysobjects
  15543.                 WHERE (name = 'backupfile')))
  15544. BEGIN
  15545.   PRINT ''
  15546.   PRINT 'Creating table backupfile...'
  15547.  
  15548.   CREATE TABLE backupfile
  15549.   (
  15550.   backup_set_id          INT           NOT NULL REFERENCES backupset(backup_set_id),
  15551.   first_family_number    TINYINT       NULL,     -- Family number & media number of he first media
  15552.   first_media_number     SMALLINT      NULL,     -- containing this file
  15553.   filegroup_name         NVARCHAR(128) NULL,
  15554.   page_size              INT           NULL,
  15555.   file_number            NUMERIC(10,0) NOT NULL,
  15556.   backed_up_page_count   NUMERIC(10,0) NULL,
  15557.   file_type              CHAR(1)       NULL,     -- database or log
  15558.   source_file_block_size NUMERIC(10,0) NULL,
  15559.   file_size              NUMERIC(20,0) NULL,
  15560.   logical_name           NVARCHAR(128) NULL,
  15561.   physical_drive         VARCHAR(260)  NULL,     -- Drive or partition name
  15562.   physical_name          VARCHAR(260)  NULL      -- Remainder of physical (OS) filename
  15563.   PRIMARY KEY (backup_set_id, file_number)
  15564.   )
  15565. END
  15566. go
  15567.  
  15568. /**************************************************************/
  15569. /* RESTOREHISTORY - One row per restore operation.            */
  15570. /**************************************************************/
  15571.  
  15572. IF (NOT EXISTS (SELECT *
  15573.                 FROM msdb.dbo.sysobjects
  15574.                 WHERE (name = 'restorehistory')))
  15575. BEGIN
  15576.   PRINT ''
  15577.   PRINT 'Creating table restorehistory...'
  15578.  
  15579.   CREATE TABLE restorehistory
  15580.   (
  15581.   restore_history_id        INT           NOT NULL IDENTITY PRIMARY KEY,
  15582.   restore_date              DATETIME      NULL,
  15583.   destination_database_name NVARCHAR(128) NULL,
  15584.   user_name                 NVARCHAR(128) NULL,
  15585.   backup_set_id             INT           NOT NULL REFERENCES backupset(backup_set_id), -- The backup set restored
  15586.   restore_type              CHAR(1)       NULL,      -- Database, file, filegroup, log, verifyonly, ...
  15587.  
  15588.   -- Various options...
  15589.   replace                   BIT           NULL,      -- Replace(1), Noreplace(0)
  15590.   recovery                  BIT           NULL,      -- Recovery(1), Norecovery(0)
  15591.   restart                   BIT           NULL,      -- Restart(1), Norestart(0)
  15592.   stop_at                   DATETIME      NULL,
  15593.   device_count              TINYINT       NULL       -- Can be less than number of media families
  15594.   )
  15595.  
  15596.   CREATE INDEX restorehistorybackupset ON restorehistory (backup_set_id)
  15597. END
  15598. go
  15599.  
  15600. /**************************************************************/
  15601. /* RESTOREFILE - One row per file restored.                   */
  15602. /**************************************************************/
  15603.  
  15604. IF (NOT EXISTS (SELECT *
  15605.                 FROM msdb.dbo.sysobjects
  15606.                 WHERE (name = 'restorefile')))
  15607. BEGIN
  15608.   PRINT ''
  15609.   PRINT 'Creating table restorefile...'
  15610.  
  15611.   CREATE TABLE restorefile
  15612.   (
  15613.   restore_history_id     INT           NOT NULL REFERENCES restorehistory(restore_history_id),
  15614.   file_number            NUMERIC(10,0) NULL,      -- Note: requires database to make unique
  15615.   destination_phys_drive VARCHAR(260)  NULL,
  15616.   destination_phys_name  VARCHAR(260)  NULL
  15617.   )
  15618. END
  15619. go
  15620.  
  15621. /**************************************************************/
  15622. /* RESTOREFILEGROUP - One row per filegroup restored.         */
  15623. /**************************************************************/
  15624.  
  15625. IF (NOT EXISTS (SELECT *
  15626.                 FROM msdb.dbo.sysobjects
  15627.                 WHERE (name = 'restorefilegroup')))
  15628. BEGIN
  15629.   PRINT ''
  15630.   PRINT 'Creating table restorefilegroup...'
  15631.  
  15632.   CREATE TABLE restorefilegroup
  15633.   (
  15634.   restore_history_id INT           NOT NULL REFERENCES restorehistory(restore_history_id),
  15635.   filegroup_name     NVARCHAR(128) NULL
  15636.   )
  15637. END
  15638. go
  15639.  
  15640.  
  15641. /**************************************************************/
  15642. /**                                                          **/
  15643. /**           O B J E C T    P E R M I S S I O N S           **/
  15644. /**                                                          **/
  15645. /**************************************************************/
  15646.  
  15647. PRINT ''
  15648. PRINT 'Setting object permissions...'
  15649. go
  15650.  
  15651. -- Permissions a non-SA needs to create/update/delete a job
  15652. GRANT EXECUTE ON sp_get_sqlagent_properties  TO PUBLIC
  15653. GRANT EXECUTE ON sp_help_category            TO PUBLIC
  15654. GRANT EXECUTE ON sp_enum_sqlagent_subsystems TO PUBLIC
  15655. GRANT EXECUTE ON sp_add_jobserver            TO PUBLIC
  15656. GRANT EXECUTE ON sp_delete_jobserver         TO PUBLIC
  15657. GRANT SELECT  ON syscategories               TO PUBLIC
  15658.  
  15659. GRANT EXECUTE ON sp_purge_jobhistory TO PUBLIC
  15660. GRANT EXECUTE ON sp_help_jobhistory  TO PUBLIC
  15661.  
  15662. GRANT EXECUTE ON sp_add_jobstep    TO PUBLIC
  15663. GRANT EXECUTE ON sp_update_jobstep TO PUBLIC
  15664. GRANT EXECUTE ON sp_delete_jobstep TO PUBLIC
  15665. GRANT EXECUTE ON sp_help_jobstep   TO PUBLIC
  15666.  
  15667. GRANT EXECUTE ON sp_add_jobschedule    TO PUBLIC
  15668. GRANT EXECUTE ON sp_update_jobschedule TO PUBLIC
  15669. GRANT EXECUTE ON sp_delete_jobschedule TO PUBLIC
  15670. GRANT EXECUTE ON sp_help_jobschedule   TO PUBLIC
  15671.  
  15672. GRANT EXECUTE ON sp_add_job    TO PUBLIC
  15673. GRANT EXECUTE ON sp_update_job TO PUBLIC
  15674. GRANT EXECUTE ON sp_delete_job TO PUBLIC
  15675. GRANT EXECUTE ON sp_help_job   TO PUBLIC
  15676. GRANT EXECUTE ON sp_start_job  TO PUBLIC
  15677. GRANT EXECUTE ON sp_stop_job   TO PUBLIC
  15678.  
  15679. GRANT EXECUTE ON sp_help_jobserver TO PUBLIC
  15680.  
  15681. GRANT EXECUTE ON sp_check_for_owned_jobs     TO PUBLIC
  15682. GRANT EXECUTE ON sp_check_for_owned_jobsteps TO PUBLIC
  15683. GRANT EXECUTE ON sp_get_jobstep_db_username  TO PUBLIC
  15684. GRANT EXECUTE ON sp_post_msx_operation       TO PUBLIC
  15685. GRANT EXECUTE ON sp_get_job_alerts           TO PUBLIC
  15686.  
  15687. GRANT EXECUTE ON sp_uniquetaskname TO PUBLIC
  15688. GRANT EXECUTE ON sp_addtask        TO PUBLIC
  15689. GRANT EXECUTE ON sp_updatetask     TO PUBLIC
  15690. GRANT EXECUTE ON sp_droptask       TO PUBLIC
  15691. GRANT EXECUTE ON sp_helptask       TO PUBLIC
  15692. GRANT EXECUTE ON sp_verifytaskid   TO PUBLIC
  15693. GRANT EXECUTE ON sp_reassigntask   TO PUBLIC
  15694. GRANT EXECUTE ON sp_helphistory    TO PUBLIC
  15695. GRANT EXECUTE ON sp_purgehistory   TO PUBLIC
  15696.  
  15697. GRANT SELECT ON sysjobs_view  TO PUBLIC
  15698. GRANT SELECT ON systasks_view TO PUBLIC
  15699. REVOKE ALL ON systargetservers                 FROM PUBLIC
  15700. REVOKE ALL ON systargetservers_view            FROM PUBLIC
  15701. REVOKE ALL ON systargetservergroups            FROM PUBLIC
  15702. REVOKE ALL ON systargetservergroupmembers      FROM PUBLIC
  15703. REVOKE INSERT, UPDATE, DELETE ON syscategories FROM PUBLIC
  15704. REVOKE ALL ON sysalerts                        FROM PUBLIC
  15705. REVOKE ALL ON sysoperators                     FROM PUBLIC
  15706. REVOKE ALL ON sysnotifications                 FROM PUBLIC
  15707.  
  15708. GRANT SELECT ON backupfile        TO PUBLIC
  15709. GRANT SELECT ON backupmediafamily TO PUBLIC
  15710. GRANT SELECT ON backupmediaset    TO PUBLIC
  15711. GRANT SELECT ON backupset         TO PUBLIC
  15712. GRANT SELECT ON restorehistory    TO PUBLIC
  15713. GRANT SELECT ON restorefile       TO PUBLIC
  15714. GRANT SELECT ON restorefilegroup  TO PUBLIC
  15715. go
  15716.  
  15717. -- Create the TargetServers role (for use by target servers when downloading jobs / uploading status)
  15718. IF (EXISTS (SELECT * 
  15719.             FROM msdb.dbo.sysusers
  15720.             WHERE (name = N'TargetServersRole')
  15721.               AND (issqlrole = 1)))
  15722. BEGIN
  15723.   -- If there are no members in the role, then drop and re-create it
  15724.   IF ((SELECT COUNT(*) 
  15725.        FROM msdb.dbo.sysusers   su,
  15726.             msdb.dbo.sysmembers sm
  15727.        WHERE (su.uid = sm.groupuid)
  15728.          AND (su.name = N'TargetServersRole')
  15729.          AND (su.issqlrole = 1)) = 0)
  15730.   BEGIN
  15731.     EXECUTE msdb.dbo.sp_droprole @rolename = N'TargetServersRole'
  15732.     EXECUTE msdb.dbo.sp_addrole @rolename = N'TargetServersRole'
  15733.   END
  15734. END
  15735. ELSE
  15736.   EXECUTE msdb.dbo.sp_addrole @rolename = N'TargetServersRole'
  15737.  
  15738. GRANT SELECT, UPDATE, DELETE ON sysdownloadlist               TO TargetServersRole
  15739. GRANT SELECT, UPDATE         ON sysjobservers                 TO TargetServersRole
  15740. GRANT SELECT, UPDATE         ON systargetservers              TO TargetServersRole
  15741. GRANT EXECUTE                ON sp_downloaded_row_limiter     TO TargetServersRole
  15742. GRANT SELECT                 ON sysjobs                       TO TargetServersRole
  15743. GRANT EXECUTE                ON sp_help_jobstep               TO TargetServersRole
  15744. GRANT EXECUTE                ON sp_help_jobschedule           TO TargetServersRole
  15745. GRANT EXECUTE                ON sp_sqlagent_refresh_job       TO TargetServersRole
  15746. GRANT EXECUTE                ON sp_sqlagent_probe_msx         TO TargetServersRole
  15747. GRANT EXECUTE                ON sp_sqlagent_check_msx_version TO TargetServersRole
  15748. go
  15749.  
  15750. USE msdb
  15751. go
  15752.  
  15753. /**************************************************************/
  15754. /**************************************************************/
  15755. /* BEGIN DTS                                                  */
  15756. /**************************************************************/
  15757. /**************************************************************/
  15758.  
  15759. /**************************************************************/
  15760. /* DTS TABLES                                                 */
  15761. /* These are never dropped since we dropped MSDB itself if    */
  15762. /* this was an upgrade from pre-beta3, and we preserve beta3  */
  15763. /* packages.  However, we need to add the owner_sid column    */
  15764. /* if it's not there already, defaulting to sa ownership.     */
  15765. /**************************************************************/
  15766.  
  15767. /**************************************************************/
  15768. /* SYSDTSCATEGORIES                                           */
  15769. /**************************************************************/
  15770. IF (NOT EXISTS (SELECT *
  15771.                 FROM msdb.dbo.sysobjects
  15772.                 WHERE (name = N'sysdtscategories')))
  15773. BEGIN
  15774.   PRINT ''
  15775.   PRINT 'Creating table sysdtscategories...'
  15776.   CREATE TABLE sysdtscategories
  15777.   (
  15778.     name                   sysname             NOT NULL,
  15779.     description            NVARCHAR(1024)      NULL,
  15780.     id                     UNIQUEIDENTIFIER    NOT NULL,
  15781.     parentid               UNIQUEIDENTIFIER    NOT NULL,         --// IID_NULL if a predefined root category
  15782.     CONSTRAINT pk_dtscategories PRIMARY KEY (id),
  15783.     CONSTRAINT uq_dtscategories_name_parent UNIQUE (name, parentid)
  15784.   )
  15785.  
  15786.   /**************************************************************/
  15787.   /* PREDEFINED DTS CATEGORIES                                  */
  15788.   /**************************************************************/
  15789.   PRINT ''
  15790.   PRINT 'Adding predefined dts categories...'
  15791.   --// MUST BE IN SYNC with DTSPkg.h!
  15792.   --// These must be INSERTed explicitly as the IID_NULL parent does not exist.
  15793.   INSERT sysdtscategories VALUES (N'Local', 'DTS Packages stored on local SQL Server', 'B8C30000-A282-11D1-B7D9-00C04FB6EFD5', '00000000-0000-0000-0000-000000000000')
  15794.   INSERT sysdtscategories VALUES (N'Repository', 'DTS Packages stored on Repository', 'B8C30001-A282-11D1-B7D9-00C04FB6EFD5', '00000000-0000-0000-0000-000000000000')
  15795.  
  15796.   --// Default location for DTSPackage.SaveToSQLServer
  15797.   INSERT sysdtscategories VALUES (N'LocalDefault', 'Default local subcategory for DTS Packages', 'B8C30002-A282-11D1-B7D9-00C04FB6EFD5', 'B8C30000-A282-11D1-B7D9-00C04FB6EFD5')
  15798. END
  15799. GO
  15800.  
  15801. /**************************************************************/
  15802. /* SYSDTSPACKAGES                                             */
  15803. /**************************************************************/
  15804. IF (NOT EXISTS (SELECT *
  15805.                 FROM msdb.dbo.sysobjects
  15806.                 WHERE (name = N'sysdtspackages')))
  15807. BEGIN
  15808.   PRINT ''
  15809.   PRINT 'Creating table sysdtspackages...'
  15810.   CREATE TABLE sysdtspackages
  15811.   (
  15812.     name                   sysname             NOT NULL,                   --// May have multiple ids
  15813.     id                     UNIQUEIDENTIFIER    NOT NULL,                   --// May have multiple versionids
  15814.     versionid              UNIQUEIDENTIFIER    NOT NULL UNIQUE,
  15815.     description            NVARCHAR(1024)      NULL,
  15816.     categoryid             UNIQUEIDENTIFIER    NOT NULL REFERENCES sysdtscategories (id),
  15817.     createdate             DATETIME,
  15818.     owner                  sysname,
  15819.     packagedata            IMAGE,
  15820.     owner_sid              VARBINARY(85)       NOT NULL DEFAULT SUSER_SID(N'sa')
  15821.     CONSTRAINT pk_dtspackages PRIMARY KEY (id, versionid)
  15822.   )
  15823. END ELSE BEGIN
  15824.   IF (NOT EXISTS (SELECT *
  15825.                   FROM msdb.dbo.syscolumns
  15826.                   WHERE name = N'owner_sid' AND id = OBJECT_ID(N'sysdtspackages')))
  15827.   BEGIN
  15828.     PRINT ''
  15829.     PRINT 'Altering table sysdtspackages...'
  15830.     ALTER TABLE sysdtspackages ADD owner_sid VARBINARY(85) NOT NULL DEFAULT SUSER_SID(N'sa')
  15831.   END
  15832. END
  15833. GO
  15834.  
  15835. /**************************************************************/
  15836. /* SP_MAKE_DTSPACKAGENAME                                     */
  15837. /**************************************************************/
  15838. PRINT ''
  15839. PRINT 'Creating procedure sp_make_dtspackagename...'
  15840. go
  15841. IF OBJECT_ID(N'sp_make_dtspackagename') IS NOT NULL
  15842.   DROP PROCEDURE sp_make_dtspackagename
  15843. go
  15844. CREATE PROCEDURE sp_make_dtspackagename
  15845.   @categoryid UNIQUEIDENTIFIER,
  15846.   @name sysname OUTPUT,
  15847.   @flags int = 0
  15848. AS
  15849.   SET NOCOUNT ON
  15850.  
  15851.   --// If NULL catid, default to the LocalDefault category.
  15852.   IF (@categoryid IS NULL)
  15853.     SELECT @categoryid = 'B8C30002-A282-11d1-B7D9-00C04FB6EFD5'
  15854.  
  15855.   --// Validate category.  We'll generate a unique name within category.
  15856.   DECLARE @stringfromclsid NVARCHAR(200)
  15857.   IF NOT EXISTS (SELECT * FROM sysdtscategories WHERE id = @categoryid)
  15858.   BEGIN
  15859.     SELECT @stringfromclsid = CONVERT(NVARCHAR(50), @categoryid)
  15860.     RAISERROR(14262, 16, 1, '@categoryid', @stringfromclsid)
  15861.     RETURN(1) -- Failure
  15862.   END
  15863.  
  15864.   --// Autogenerate the next name in our format.
  15865.   DECLARE @max sysname, @i INT, @spidchar NVARCHAR(20)
  15866.  
  15867.   --// Any logic we use may have collisions so let's get the max and wrap if we have to.
  15868.   --// @@spid is necessary for guaranteed uniqueness but makes it ugly so for now, don't use it.
  15869.   --// Note:  use only 9 characters as it makes the pattern match easier without overflowing.
  15870.   SELECT @i = 0, @spidchar = '_'               -- + LTRIM(STR(@@spid)) + '_'
  15871.   SELECT @max = MAX(name)
  15872.     FROM sysdtspackages
  15873.     WHERE name like 'DTS_' + @spidchar + '[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]'
  15874.   IF @max IS NOT NULL
  15875.     SELECT @i = CONVERT(INT, SUBSTRING(@max, (DATALENGTH(N'DTS_' + @spidchar) / 2) + 1, 9))
  15876.  
  15877.   --// Wrap if needed.  Find a gap in the names.
  15878.   IF @i < 999999999
  15879.   BEGIN
  15880.     SELECT @i = @i + 1
  15881.   END ELSE BEGIN
  15882.     SELECT @i = 1
  15883.     DECLARE @existingname sysname
  15884.     DECLARE hC CURSOR LOCAL FOR SELECT name FROM sysdtspackages WHERE categoryid = @categoryid ORDER BY name FOR READ ONLY
  15885.     OPEN hC
  15886.     FETCH NEXT FROM hC INTO @existingname
  15887.     WHILE @@FETCH_STATUS = 0 AND @i < 999999999
  15888.     BEGIN
  15889.       SELECT @name = 'DTS_' + @spidchar + REPLICATE('0', 9 - DATALENGTH(LTRIM(STR(@i)))) + LTRIM(STR(@i))
  15890.       IF @existingname > @name
  15891.         BREAK
  15892.       SELECT @i = @i + 1
  15893.       FETCH NEXT FROM hC INTO @existingname
  15894.     END
  15895.     CLOSE hC
  15896.     DEALLOCATE hC
  15897.   END
  15898.  
  15899.   --// Set the name.
  15900.   SELECT @name = 'DTS_' + @spidchar + REPLICATE('0', 9 - DATALENGTH(LTRIM(STR(@i)))) + LTRIM(STR(@i))
  15901.   IF (@flags & 1) <> 0
  15902.     SELECT @name
  15903. GO
  15904. GRANT EXECUTE ON sp_make_dtspackagename TO PUBLIC
  15905. GO
  15906.  
  15907. /**************************************************************/
  15908. /* SP_ADD_DTSPACKAGE                                          */
  15909. /**************************************************************/
  15910. PRINT ''
  15911. PRINT 'Creating procedure sp_add_dtspackage...'
  15912. GO
  15913. IF OBJECT_ID(N'sp_add_dtspackage') IS NOT NULL
  15914.   DROP PROCEDURE sp_add_dtspackage
  15915. GO
  15916. CREATE PROCEDURE sp_add_dtspackage
  15917.   @name sysname,
  15918.   @id UNIQUEIDENTIFIER,
  15919.   @versionid UNIQUEIDENTIFIER,
  15920.   @description NVARCHAR(255),
  15921.   @categoryid UNIQUEIDENTIFIER,
  15922.   @owner sysname,
  15923.   @packagedata IMAGE
  15924. AS
  15925.   SET NOCOUNT ON
  15926.  
  15927.   --// If NULL catid, default to the LocalDefault category.
  15928.   IF (@categoryid IS NULL)
  15929.     SELECT @categoryid = 'B8C30002-A282-11d1-B7D9-00C04FB6EFD5'
  15930.  
  15931.   --// Autogenerate name if it came in NULL.  If it didn't, the below will validate uniqueness.
  15932.   IF DATALENGTH(@name) = 0
  15933.     SELECT @name = NULL
  15934.   IF @name IS NULL
  15935.   BEGIN
  15936.     --// First see if they specified a new version based on id instead of name.
  15937.     if @id IS NOT NULL
  15938.     BEGIN
  15939.       SELECT @name = name
  15940.         FROM sysdtspackages WHERE @id = id
  15941.       IF @name IS NOT NULL
  15942.         GOTO AddPackage          -- OK, add with the existing name
  15943.     END
  15944.  
  15945.     --// Name not available, autogenerate one.
  15946.     exec sp_make_dtspackagename @categoryid, @name OUTPUT
  15947.     GOTO AddPackage
  15948.   END
  15949.  
  15950.   --// Verify name unique within category.  Allow a new versionid of the same name though.
  15951.   IF EXISTS (SELECT * FROM sysdtspackages WHERE name = @name AND categoryid = @categoryid AND id <> @id)
  15952.   BEGIN
  15953.     RAISERROR (14590, -1, -1, @name)
  15954.     RETURN(1) -- Failure
  15955.   END
  15956.  
  15957.   --// Verify that the same id is not getting a different name.
  15958.   IF EXISTS (SELECT * FROM sysdtspackages WHERE id = @id AND name <> @name)
  15959.   BEGIN
  15960.     DECLARE @stringfromclsid NVARCHAR(200)
  15961.     SELECT @stringfromclsid = CONVERT(NVARCHAR(50), @id)
  15962.     RAISERROR (14597, -1, -1, @stringfromclsid)
  15963.     RETURN(1) -- Failure
  15964.   END
  15965.  
  15966.   --// Verify all versions of a package go in the same category.
  15967.   IF EXISTS (SELECT * FROM sysdtspackages WHERE id = @id AND categoryid <> @categoryid)
  15968.   BEGIN
  15969.     RAISERROR (14596, -1, -1, @name)
  15970.     RETURN(1) -- Failure
  15971.   END
  15972.  
  15973.   --// The real information is in the IMAGE; the rest is "documentary".
  15974.   --// Therefore, there is no need to verify anything.
  15975.   --// The REFERENCE in sysdtspackages will validate @categoryid.
  15976. AddPackage:
  15977.  
  15978.   --// We will use the original owner_sid for all new versions - all must have the same owner.
  15979.   --// New packages will get the current login's SID as owner_sid.
  15980.   DECLARE @owner_sid VARBINARY(85)
  15981.   SELECT @owner_sid = MIN(owner_sid) FROM sysdtspackages WHERE id = @id
  15982.   IF @@rowcount = 0 OR @owner_sid IS NULL
  15983.   BEGIN
  15984.     SELECT @owner_sid = SUSER_SID()
  15985.   END ELSE BEGIN
  15986.     --// Only the owner of DTS Package ''%s'' or a member of the sysadmin role may create new versions of it.
  15987.     IF (@owner_sid <> SUSER_SID() AND (ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) <> 1))
  15988.     BEGIN
  15989.       RAISERROR (14586, -1, -1, @name)
  15990.       RETURN(1) -- Failure
  15991.     END
  15992.   END
  15993.  
  15994.   --// Everything checks out, add the package or its new version.
  15995.   INSERT sysdtspackages (
  15996.     name,
  15997.     id,
  15998.     versionid,
  15999.     description,
  16000.     categoryid,
  16001.     createdate,
  16002.     owner,
  16003.     packagedata,
  16004.     owner_sid
  16005.   ) VALUES (
  16006.     @name,
  16007.     @id,
  16008.     @versionid,
  16009.     @description,
  16010.     @categoryid,
  16011.     GETDATE(),
  16012.     @owner,
  16013.     @packagedata,
  16014.     @owner_sid
  16015.   )
  16016.   RETURN 0    -- SUCCESS
  16017. GO
  16018. GRANT EXECUTE ON sp_add_dtspackage TO PUBLIC
  16019. GO
  16020.  
  16021. /**************************************************************/
  16022. /* SP_DROP_DTSPACKAGE                                         */
  16023. /**************************************************************/
  16024. PRINT ''
  16025. PRINT 'Creating procedure sp_drop_dtspackage...'
  16026. go
  16027. IF OBJECT_ID(N'sp_drop_dtspackage') IS NOT NULL
  16028.   DROP PROCEDURE sp_drop_dtspackage
  16029. go
  16030. CREATE PROCEDURE sp_drop_dtspackage
  16031.   @name sysname,
  16032.   @id UNIQUEIDENTIFIER,
  16033.   @versionid UNIQUEIDENTIFIER
  16034. AS
  16035.   SET NOCOUNT ON
  16036.  
  16037.   --// Does the specified package (uniquely) exist?  Referencing by name only may not be unique.
  16038.   --// We do a bit of a hack here as SQL can't handle a DISTINCT clause with UNIQUEIDENTIFIER.
  16039.   --// @id will get the first id returned; if only name specified, see if there are more.
  16040.   DECLARE @findid UNIQUEIDENTIFIER
  16041.   SELECT @findid = id FROM sysdtspackages 
  16042.     WHERE (@name IS NOT NULL OR @id IS NOT NULL OR @versionid IS NOT NULL)
  16043.       AND (@name IS NULL OR @name = name)
  16044.       AND (@id IS NULL OR @id = id)
  16045.       AND (@versionid IS NULL or @versionid = versionid)
  16046.   IF @@rowcount = 0
  16047.   BEGIN
  16048.     DECLARE @pkgnotfound NVARCHAR(200)
  16049.     DECLARE @dts_package_res NVARCHAR(100)
  16050.     SELECT @pkgnotfound = FORMATMESSAGE(14599) + ' = ''' + ISNULL(@name, FORMATMESSAGE(14589)) + '''; ' + FORMATMESSAGE(14588) + ' {'
  16051.     SELECT @pkgnotfound = @pkgnotfound + CASE WHEN @id IS NULL THEN FORMATMESSAGE(14589) ELSE CONVERT(NVARCHAR(50), @id) END + '}.{'
  16052.     SELECT @pkgnotfound = @pkgnotfound + CASE WHEN @versionid IS NULL THEN FORMATMESSAGE(14589) ELSE CONVERT(NVARCHAR(50), @versionid) END + '}'
  16053.     SELECT @dts_package_res = FORMATMESSAGE(14594)
  16054.     RAISERROR(14262, 16, 1, @dts_package_res, @pkgnotfound)
  16055.     RETURN(1) -- Failure
  16056.   END ELSE IF @name IS NOT NULL AND @id IS NULL AND @versionid IS NULL AND
  16057.       EXISTS (SELECT * FROM sysdtspackages WHERE name = @name AND id <> @findid)
  16058.   BEGIN
  16059.     RAISERROR(14595, -1, -1, @name)
  16060.     RETURN(1) -- Failure
  16061.   END
  16062.   SELECT @id = @findid
  16063.  
  16064.   --// Only the owner of DTS Package ''%s'' or a member of the sysadmin role may drop it or any of its versions.
  16065.   --// sp_add_dtspackage ensures that all versions have the same owner_sid.
  16066.   IF (ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) <> 1)
  16067.   BEGIN
  16068.     IF (NOT EXISTS (SELECT * FROM sysdtspackages WHERE id = @id AND owner_sid = SUSER_SID()))
  16069.     BEGIN
  16070.       SELECT @name = name FROM sysdtspackages WHERE id = @id
  16071.       RAISERROR (14587, -1, -1, @name)
  16072.       RETURN(1) -- Failure
  16073.     END
  16074.   END
  16075.  
  16076.   --// If @versionid is NULL, drop all versions of name, else only the @versionid version.
  16077.   DELETE sysdtspackages
  16078.   WHERE id = @id 
  16079.     AND (@versionid IS NULL OR @versionid = versionid)
  16080.   RETURN 0    -- SUCCESS
  16081. go
  16082. GRANT EXECUTE ON sp_drop_dtspackage TO PUBLIC
  16083. go
  16084.  
  16085. /**************************************************************/
  16086. /* SP_REASSIGN_DTSPACKAGEOWNER                                */
  16087. /**************************************************************/
  16088. PRINT ''
  16089. PRINT 'Creating procedure sp_reassign_dtspackageowner...'
  16090. go
  16091. IF OBJECT_ID(N'sp_reassign_dtspackageowner') IS NOT NULL
  16092.   DROP PROCEDURE sp_reassign_dtspackageowner
  16093. go
  16094. CREATE PROCEDURE sp_reassign_dtspackageowner
  16095.   @name sysname,
  16096.   @id UNIQUEIDENTIFIER,
  16097.   @newloginname sysname
  16098. AS
  16099.   SET NOCOUNT ON
  16100.  
  16101.   --// First, is this a valid login?
  16102.   IF SUSER_SID(@newloginname) IS NULL
  16103.   BEGIN
  16104.     RAISERROR(14262, -1, -1, '@newloginname', @newloginname)
  16105.     RETURN(1) -- Failure
  16106.   END
  16107.  
  16108.   --// Does the specified package (uniquely) exist?  Referencing by name only may not be unique.
  16109.   --// We do a bit of a hack here as SQL can't handle a DISTINCT clause with UNIQUEIDENTIFIER.
  16110.   --// @id will get the first id returned; if only name specified, see if there are more.
  16111.   DECLARE @findid UNIQUEIDENTIFIER
  16112.   SELECT @findid = id FROM sysdtspackages 
  16113.     WHERE (@name IS NOT NULL OR @id IS NOT NULL)
  16114.       AND (@name IS NULL OR @name = name)
  16115.       AND (@id IS NULL OR @id = id)
  16116.   IF @@rowcount = 0
  16117.   BEGIN
  16118.     DECLARE @pkgnotfound NVARCHAR(200)
  16119.     DECLARE @dts_package_res NVARCHAR(100)
  16120.     SELECT @pkgnotfound = FORMATMESSAGE(14599) + ' = ''' + ISNULL(@name, FORMATMESSAGE(14589)) + '''; ' + FORMATMESSAGE(14588) + ' {'
  16121.     SELECT @pkgnotfound = @pkgnotfound + CASE WHEN @id IS NULL THEN FORMATMESSAGE(14589) ELSE CONVERT(NVARCHAR(50), @id) END + '}.{'
  16122.     SELECT @pkgnotfound = @pkgnotfound + FORMATMESSAGE(14589) + '}'
  16123.     SELECT @dts_package_res = FORMATMESSAGE(14594)
  16124.     RAISERROR(14262, 16, 1, @dts_package_res, @pkgnotfound)
  16125.     RETURN(1) -- Failure
  16126.   END ELSE IF @name IS NOT NULL AND @id IS NULL AND 
  16127.       EXISTS (SELECT * FROM sysdtspackages WHERE name = @name AND id <> @findid)
  16128.   BEGIN
  16129.     RAISERROR(14595, -1, -1, @name)
  16130.     RETURN(1) -- Failure
  16131.   END
  16132.   SELECT @id = @findid
  16133.  
  16134.   --// Only the owner of DTS Package ''%s'' or a member of the sysadmin role may reassign its ownership.
  16135.   --// sp_add_dtspackage ensures that all versions have the same owner_sid.
  16136.   IF (ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) <> 1)
  16137.   BEGIN
  16138.     IF (NOT EXISTS (SELECT * FROM sysdtspackages WHERE id = @id AND owner_sid = SUSER_SID()))
  16139.     BEGIN
  16140.       SELECT @name = name FROM sysdtspackages WHERE id = @id
  16141.       RAISERROR (14585, -1, -1, @name)
  16142.       RETURN(1) -- Failure
  16143.     END
  16144.   END
  16145.  
  16146.   --// Everything checks out, so reassign the owner.
  16147.   --// Note that @newloginname may be a sql server login rather than a network user,
  16148.   --// which is not quite the same as when a package is created.
  16149.   UPDATE sysdtspackages
  16150.     SET owner_sid = SUSER_SID(@newloginname),
  16151.         owner = @newloginname
  16152.     WHERE id = @id
  16153.  
  16154.   RETURN 0    -- SUCCESS
  16155. GO
  16156. GRANT EXECUTE ON sp_reassign_dtspackageowner TO PUBLIC
  16157. GO
  16158.  
  16159. /**************************************************************/
  16160. /* SP_GET_DTSPACKAGE                                          */
  16161. /**************************************************************/
  16162. PRINT ''
  16163. PRINT 'Creating procedure sp_get_dtspackage...'
  16164. go
  16165. IF OBJECT_ID(N'sp_get_dtspackage') IS NOT NULL
  16166.   DROP PROCEDURE sp_get_dtspackage
  16167. go
  16168. CREATE PROCEDURE sp_get_dtspackage
  16169.   @name sysname,
  16170.   @id UNIQUEIDENTIFIER,
  16171.   @versionid UNIQUEIDENTIFIER
  16172. AS
  16173.   SET NOCOUNT ON
  16174.  
  16175.   --// Does the specified package (uniquely) exist?  Dropping by name only may not be unique.
  16176.   --// We do a bit of a hack here as SQL can't handle a DISTINCT clause with UNIQUEIDENTIFIER.
  16177.   --// @id will get the first id returned; if only name specified, see if there are more.
  16178.   DECLARE @findid UNIQUEIDENTIFIER
  16179.   SELECT @findid = id FROM sysdtspackages 
  16180.     WHERE (@name IS NOT NULL OR @id IS NOT NULL OR @versionid IS NOT NULL)
  16181.       AND (@name IS NULL OR @name = name)
  16182.       AND (@id IS NULL OR @id = id)
  16183.       AND (@versionid IS NULL or @versionid = versionid)
  16184.   IF @@rowcount = 0
  16185.   BEGIN
  16186.     DECLARE @pkgnotfound NVARCHAR(200)
  16187.     DECLARE @dts_package_res NVARCHAR(100)
  16188.     SELECT @pkgnotfound = FORMATMESSAGE(14599) + ' = ''' + ISNULL(@name, FORMATMESSAGE(14589)) + '''; ' + FORMATMESSAGE(14588) + ' {'
  16189.     SELECT @pkgnotfound = @pkgnotfound + CASE WHEN @id IS NULL THEN FORMATMESSAGE(14589) ELSE CONVERT(NVARCHAR(50), @id) END + '}.{'
  16190.     SELECT @pkgnotfound = @pkgnotfound + CASE WHEN @versionid IS NULL THEN FORMATMESSAGE(14589) ELSE CONVERT(NVARCHAR(50), @versionid) END + '}'
  16191.     SELECT @dts_package_res = FORMATMESSAGE(14594)
  16192.     RAISERROR(14262, 16, 1, @dts_package_res, @pkgnotfound)
  16193.     RETURN(1) -- Failure
  16194.   END ELSE IF @name IS NOT NULL AND @id IS NULL AND @versionid IS NULL AND
  16195.       EXISTS (SELECT * FROM sysdtspackages WHERE name = @name AND id <> @findid)
  16196.   BEGIN
  16197.     RAISERROR(14595, -1, -1, @name)
  16198.     RETURN(1) -- Failure
  16199.   END
  16200.   SELECT @id = @findid
  16201.  
  16202.   --// If @versionid is NULL, select all versions of name, else only the @versionid version.
  16203.   --// This must return the IMAGE as the rightmost column.
  16204.   SELECT
  16205.     name,
  16206.     id,
  16207.     versionid,
  16208.     description,
  16209.     createdate,
  16210.     owner,
  16211.     pkgsize = datalength(packagedata),
  16212.     packagedata,
  16213.     isowner = CASE WHEN (ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) = 1 OR owner_sid = SUSER_SID()) THEN 1 ELSE 0 END
  16214.   FROM sysdtspackages
  16215.   WHERE id = @id
  16216.     AND (@versionid IS NULL OR @versionid = versionid)
  16217.   ORDER BY name, createdate DESC
  16218.  
  16219.   RETURN 0    -- SUCCESS
  16220. go
  16221. GRANT EXECUTE ON sp_get_dtspackage TO PUBLIC
  16222. go
  16223.  
  16224. /**************************************************************/
  16225. /* SP_REASSIGN_DTSPACKAGECATEGORY                             */
  16226. /**************************************************************/
  16227. PRINT ''
  16228. PRINT 'Creating procedure sp_reassign_dtspackagecategory...'
  16229. go
  16230. IF OBJECT_ID(N'sp_reassign_dtspackagecategory') IS NOT NULL
  16231.   DROP PROCEDURE sp_reassign_dtspackagecategory
  16232. go
  16233. CREATE PROCEDURE sp_reassign_dtspackagecategory
  16234.   @packageid UNIQUEIDENTIFIER,
  16235.   @categoryid UNIQUEIDENTIFIER
  16236. AS
  16237.   SET NOCOUNT ON
  16238.  
  16239.   --// Does the package exist?
  16240.   DECLARE @stringfromclsid NVARCHAR(200)
  16241.   IF NOT EXISTS (SELECT * from sysdtspackages WHERE id = @packageid)
  16242.   BEGIN
  16243.     SELECT @stringfromclsid = CONVERT(NVARCHAR(50), @packageid)
  16244.     RAISERROR(14262, 16, 1, '@packageid', @stringfromclsid)
  16245.     RETURN(1) -- Failure
  16246.   END
  16247.  
  16248.   --// Does the category exist?
  16249.   IF NOT EXISTS (SELECT * FROM sysdtscategories WHERE id = @categoryid)
  16250.   BEGIN
  16251.     SELECT @stringfromclsid = CONVERT(NVARCHAR(50), @categoryid)
  16252.     RAISERROR(14262, 16, 1, '@categoryid', @stringfromclsid)
  16253.     RETURN(1) -- Failure
  16254.   END
  16255.  
  16256.   UPDATE sysdtspackages SET categoryid = @categoryid WHERE id = @packageid
  16257. go
  16258.  
  16259. /**************************************************************/
  16260. /* SP_ENUM_DTSPACKAGES                                        */
  16261. /**************************************************************/
  16262. PRINT ''
  16263. PRINT 'Creating procedure sp_enum_dtspackages...'
  16264. go
  16265. IF OBJECT_ID(N'sp_enum_dtspackages') IS NOT NULL
  16266.   DROP PROCEDURE sp_enum_dtspackages
  16267. go
  16268. CREATE PROCEDURE sp_enum_dtspackages
  16269.   @name_like sysname = '%',
  16270.   @description_like NVARCHAR(255) = '%',
  16271.   @categoryid UNIQUEIDENTIFIER = NULL,
  16272.   @flags INT = 0,          --// Bitmask:  0x01 == return image data
  16273.                            --//           0x02 == recursive (packagenames and categorynames only)
  16274.                            --//           0x04 == all versions (default == only most-recent-versions)
  16275.                            --//           0x08 == all prior versions versions (not most-recent; requires @id)
  16276.   @id UNIQUEIDENTIFIER = NULL    --// If non-NULL, enum versions of this package.
  16277. AS
  16278.   IF (@flags & 0x02) <> 0
  16279.     GOTO DO_RECURSE
  16280.  
  16281.   --// Just return the non-IMAGE stuff - sp_get_dtspackage will return the
  16282.   --// actual dtspackage info. 
  16283.   DECLARE @latestversiondate datetime
  16284.   SELECT @latestversiondate = NULL
  16285.   IF (@flags & 0x08 = 0x08)
  16286.   BEGIN
  16287.     SELECT @latestversiondate = MAX(t.createdate) FROM sysdtspackages t WHERE t.id = @id
  16288.     IF @latestversiondate IS NULL
  16289.     BEGIN
  16290.       DECLARE @pkgnotfound NVARCHAR(200)
  16291.       DECLARE @dts_package_res NVARCHAR(100)
  16292.       SELECT @pkgnotfound = FORMATMESSAGE(14599) + ' = ' + FORMATMESSAGE(14589) + '; ' + FORMATMESSAGE(14588) + ' {'
  16293.       SELECT @pkgnotfound = @pkgnotfound + CASE WHEN @id IS NULL THEN FORMATMESSAGE(14589) ELSE CONVERT(NVARCHAR(50), @id) END + '}.{'
  16294.       SELECT @pkgnotfound = @pkgnotfound + FORMATMESSAGE(14589) + '}'
  16295.       SELECT @dts_package_res = FORMATMESSAGE(14594)
  16296.       RAISERROR(14262, 16, 1, @dts_package_res, @pkgnotfound)
  16297.       RETURN(1) -- Failure
  16298.     END 
  16299.   END
  16300.   SELECT
  16301.     p.name,
  16302.     p.id,
  16303.     p.versionid,
  16304.     p.description,
  16305.     p.createdate,
  16306.     p.owner,
  16307.     size = datalength(p.packagedata),
  16308.     packagedata = CASE (@flags & 0x01) WHEN 0 THEN NULL ELSE p.packagedata END,
  16309.     isowner = CASE WHEN (ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) = 1 OR owner_sid = SUSER_SID()) THEN 1 ELSE 0 END
  16310.   FROM sysdtspackages p
  16311.   WHERE (@name_like IS NULL OR p.name LIKE @name_like)
  16312.     AND (@description_like IS NULL OR p.description LIKE @description_like)
  16313.     AND (@categoryid IS NULL OR p.categoryid = @categoryid)
  16314.     AND (@id is NULL OR p.id = @id)
  16315.     -- These filter by version
  16316.     AND ( (@flags & 0x08 = 0x08 AND p.createdate < @latestversiondate)
  16317.           OR ( (@flags & 0x04 = 0x04)
  16318.                OR (@flags & 0x08 = 0 AND p.createdate = (SELECT MAX(t.createdate) FROM sysdtspackages t WHERE t.id = p.id))
  16319.              )
  16320.         )
  16321.   ORDER BY id, createdate DESC
  16322.   RETURN 0    -- SUCCESS
  16323.  
  16324.   DO_RECURSE:
  16325.   DECLARE @packagesfound INT
  16326.   SELECT @packagesfound = 0
  16327.  
  16328.   --// Starting parent category.  If null, start at root.
  16329.   if (@categoryid IS NULL)
  16330.     SELECT @categoryid = '00000000-0000-0000-0000-000000000000'
  16331.  
  16332.   IF EXISTS (SELECT *
  16333.       FROM sysdtspackages p INNER JOIN sysdtscategories c ON p.categoryid = c.id
  16334.       WHERE p.categoryid = @categoryid
  16335.       AND (@name_like IS NULL OR p.name LIKE @name_like)
  16336.       AND (@description_like IS NULL OR p.description LIKE @description_like)
  16337.     )
  16338.     SELECT @packagesfound = 1
  16339.  
  16340.   IF (@packagesfound <> 0)
  16341.   BEGIN
  16342.     --// Identify the category and list its Packages.
  16343.     SELECT 'Level' = @@nestlevel, 'PackageName' = p.name, 'CategoryName' = c.name
  16344.         FROM sysdtspackages p INNER JOIN sysdtscategories c ON p.categoryid = c.id
  16345.         WHERE p.categoryid = @categoryid
  16346.         AND (@name_like IS NULL OR p.name LIKE @name_like)
  16347.         AND (@description_like IS NULL OR p.description LIKE @description_like)
  16348.   END
  16349.  
  16350.   --// List its subcategories' packages
  16351.   DECLARE @childid UNIQUEIDENTIFIER
  16352.   DECLARE hC CURSOR LOCAL FOR SELECT id FROM sysdtscategories c WHERE parentid = @categoryid ORDER BY c.name FOR READ ONLY
  16353.   OPEN hC
  16354.   FETCH NEXT FROM hC INTO @childid
  16355.   WHILE @@FETCH_STATUS = 0
  16356.   BEGIN
  16357.     EXECUTE sp_enum_dtspackages @name_like, @description_like, @childid, @flags
  16358.     FETCH NEXT FROM hC INTO @childid
  16359.   END
  16360.   CLOSE hC
  16361.   DEALLOCATE hC
  16362.   RETURN 0
  16363. go
  16364.  
  16365. GRANT EXECUTE ON sp_enum_dtspackages TO PUBLIC
  16366. go
  16367.  
  16368. /**************************************************************/
  16369. /* SP_ADD_DTSCATEGORY                                         */
  16370. /**************************************************************/
  16371. PRINT ''
  16372. PRINT 'Creating procedure sp_add_dtscategory...'
  16373. go
  16374. IF OBJECT_ID(N'sp_add_dtscategory') IS NOT NULL
  16375.   DROP PROCEDURE sp_add_dtscategory
  16376. go
  16377. CREATE PROCEDURE sp_add_dtscategory
  16378.   @name sysname,
  16379.   @description NVARCHAR(1024),
  16380.   @id UNIQUEIDENTIFIER,
  16381.   @parentid UNIQUEIDENTIFIER
  16382. AS
  16383.   SET NOCOUNT ON
  16384.  
  16385.   --// If parentid is NULL, use 'Local'
  16386.   IF @parentid IS NULL
  16387.     SELECT @parentid = 'B8C30000-A282-11d1-B7D9-00C04FB6EFD5'
  16388.  
  16389.   --// First do some simple validation of "non-assert" cases.  UI should validate others and the table
  16390.   --// definitions will act as an "assert", but we check here (with a nice message) for user-error stuff
  16391.   --// it would be hard for UI to validate.
  16392.   IF NOT EXISTS (SELECT * FROM sysdtscategories WHERE id = @parentid)
  16393.   BEGIN
  16394.     DECLARE @stringfromclsid NVARCHAR(200)
  16395.     SELECT @stringfromclsid = CONVERT(NVARCHAR(50), @parentid)
  16396.     RAISERROR(14262, 16, 1, '@parentid', @stringfromclsid)
  16397.     RETURN(1) -- Failure
  16398.   END
  16399.  
  16400.   IF EXISTS (SELECT * FROM sysdtscategories WHERE name = @name AND parentid = @parentid)
  16401.   BEGIN
  16402.     RAISERROR(14591, 16, -1, @name)
  16403.     RETURN(1) -- Failure
  16404.   END
  16405.  
  16406.   --// id uniqueness is ensured by the primary key.
  16407.   INSERT sysdtscategories (
  16408.     name,
  16409.     description,
  16410.     id,
  16411.     parentid
  16412.   ) VALUES (
  16413.     @name,
  16414.     @description,
  16415.     @id,
  16416.     @parentid
  16417.   )
  16418.   RETURN 0    -- SUCCESS
  16419. go
  16420.  
  16421. /**************************************************************/
  16422. /* SP_DROP_DTSCATEGORY                                        */
  16423. /**************************************************************/
  16424. PRINT ''
  16425. PRINT 'Creating procedure sp_drop_dtscategory...'
  16426. go
  16427. IF OBJECT_ID(N'sp_drop_dtscategory') IS NOT NULL
  16428.   DROP PROCEDURE sp_drop_dtscategory
  16429. go
  16430. CREATE PROCEDURE sp_drop_dtscategory
  16431.   @name_like sysname,
  16432.   @id UNIQUEIDENTIFIER = NULL,
  16433.   @flags INT = 0           --// Bitmask:  0x01 == recursive (drop all subcategories and packages)
  16434. AS
  16435.   SET NOCOUNT ON
  16436.  
  16437.   --// Temp table in case recursion is needed.
  16438.   CREATE TABLE #recurse(id UNIQUEIDENTIFIER, passcount INT DEFAULT(0))
  16439.  
  16440.   IF (@name_like IS NOT NULL)
  16441.   BEGIN
  16442.     INSERT #recurse (id) SELECT id FROM sysdtscategories WHERE name LIKE @name_like
  16443.     IF @@rowcount = 0
  16444.     BEGIN
  16445.       RAISERROR(14262, 16, 1, '@name_like', @name_like)
  16446.       RETURN(1) -- Failure
  16447.     END
  16448.     IF @@rowcount > 1
  16449.     BEGIN
  16450.       RAISERROR(14592, 16, -1, @name_like)
  16451.       RETURN(1) -- Failure
  16452.     END
  16453.     SELECT @name_like = name, @id = id FROM sysdtscategories WHERE name LIKE @name_like
  16454.   END ELSE BEGIN
  16455.     --// Verify the id.  @name_like will be NULL if we're here so no need to initialize.
  16456.     SELECT @name_like = name FROM sysdtscategories WHERE id = @id
  16457.     IF @name_like IS NULL
  16458.     BEGIN
  16459.       DECLARE @stringfromclsid NVARCHAR(200)
  16460.       SELECT @stringfromclsid = CONVERT(NVARCHAR(50), @id)
  16461.       RAISERROR(14262, 16, 1, '@id', @stringfromclsid)
  16462.       RETURN(1) -- Failure
  16463.     END
  16464.     INSERT #recurse (id) VALUES (@id)
  16465.   END
  16466.  
  16467.   --// We now have a unique category.
  16468.  
  16469.   --// Cannot drop the predefined categories (or the root, which already failed above as IID_NULL
  16470.   --// is not an id in sysdtscategories).  These will be at top level.
  16471.   IF @id IN (
  16472.     'B8C30000-A282-11d1-B7D9-00C04FB6EFD5'
  16473.     , 'B8C30001-A282-11d1-B7D9-00C04FB6EFD5'
  16474.     , 'B8C30002-A282-11d1-B7D9-00C04FB6EFD5'
  16475.   ) BEGIN
  16476.       RAISERROR(14598, 16, 1)
  16477.       RETURN(1) -- Failure
  16478.   END
  16479.  
  16480.   --// Check for subcategories or packages.
  16481.   IF EXISTS (SELECT * FROM sysdtspackages WHERE categoryid = @id)
  16482.              OR EXISTS (SELECT * FROM sysdtscategories WHERE parentid = @id)
  16483.   BEGIN
  16484.     --// It does.  Make sure recursion was requested.
  16485.     IF (@flags & 0x01 = 0)
  16486.     BEGIN
  16487.       RAISERROR(14593, 16, -1, @name_like)
  16488.       RETURN(1) -- Failure
  16489.     END
  16490.  
  16491.     --// Fill up #recurse.
  16492.     UPDATE #recurse SET passcount = 0
  16493.     WHILE (1 = 1)
  16494.     BEGIN
  16495.       UPDATE #recurse SET passcount = passcount + 1
  16496.       INSERT #recurse (id, passcount)
  16497.         SELECT c.id, 0 FROM sysdtscategories c INNER JOIN #recurse r ON c.parentid = r.id
  16498.         WHERE passcount = 1
  16499.       IF @@rowcount = 0
  16500.         BREAK
  16501.     END
  16502.   END
  16503.  
  16504.   DELETE sysdtspackages FROM sysdtspackages INNER JOIN #recurse ON sysdtspackages.categoryid = #recurse.id
  16505.   DELETE sysdtscategories FROM sysdtscategories INNER JOIN #recurse ON sysdtscategories.id = #recurse.id
  16506.   RETURN(0) -- SUCCESS
  16507. go
  16508.  
  16509. /**************************************************************/
  16510. /* SP_MODIFY_DTSCATEGORY                                      */
  16511. /**************************************************************/
  16512. PRINT ''
  16513. PRINT 'Creating procedure sp_modify_dtscategory...'
  16514. go
  16515. IF OBJECT_ID(N'sp_modify_dtscategory') IS NOT NULL
  16516.   DROP PROCEDURE sp_modify_dtscategory
  16517. go
  16518. CREATE PROCEDURE sp_modify_dtscategory
  16519.   @id UNIQUEIDENTIFIER,
  16520.   @name sysname,
  16521.   @description NVARCHAR(1024),
  16522.   @parentid UNIQUEIDENTIFIER
  16523. AS
  16524.   SET NOCOUNT ON
  16525.  
  16526.   --// Validate.
  16527.   DECLARE @stringfromclsid NVARCHAR(200)
  16528.   IF NOT EXISTS (SELECT * FROM sysdtscategories WHERE id = @id)
  16529.   BEGIN
  16530.     SELECT @stringfromclsid = CONVERT(NVARCHAR(50), @id)
  16531.     RAISERROR(14262, 16, 1, '@id', @stringfromclsid)
  16532.     RETURN(1) -- Failure
  16533.   END
  16534.  
  16535.   IF NOT EXISTS (SELECT * FROM sysdtscategories WHERE id = @parentid)
  16536.   BEGIN
  16537.     SELECT @stringfromclsid = CONVERT(NVARCHAR(50), @parentid)
  16538.     RAISERROR(14262, 16, 1, '@parentid', @stringfromclsid)
  16539.     RETURN(1) -- Failure
  16540.   END
  16541.  
  16542.   --// Check the name uniqueness within parent, but make sure the id is different (we may just be renaming
  16543.   --// without reassigning parentage).
  16544.   IF EXISTS (SELECT * FROM sysdtscategories WHERE name = @name AND parentid = @parentid and id <> @id)
  16545.   BEGIN
  16546.     RAISERROR(14591, 16, -1, @name)
  16547.     RETURN(1) -- Failure
  16548.   END
  16549.  
  16550.   UPDATE sysdtscategories SET name = @name, description = @description, parentid = @parentid
  16551.     WHERE id = @id
  16552.   RETURN(0) -- SUCCESS
  16553. go
  16554.  
  16555. /**************************************************************/
  16556. /* SP_ENUM_DTSCATEGORIES                                      */
  16557. /**************************************************************/
  16558. PRINT ''
  16559. PRINT 'Creating procedure sp_enum_dtscategories...'
  16560. go
  16561. IF OBJECT_ID(N'sp_enum_dtscategories') IS NOT NULL
  16562.   DROP PROCEDURE sp_enum_dtscategories
  16563. go
  16564. CREATE PROCEDURE sp_enum_dtscategories
  16565.   @parentid UNIQUEIDENTIFIER = NULL,
  16566.   @flags INT = 0           --// Bitmask:  0x01 == recursive (enum all subcategories; names only)
  16567. AS
  16568.   IF (@flags & 0x01) <> 0
  16569.     GOTO DO_RECURSE
  16570.  
  16571.   --// Go to the root if no parentid specified
  16572.   IF @parentid IS NULL
  16573.     SELECT @parentid = '00000000-0000-0000-0000-000000000000'
  16574.  
  16575.   --// 'No results' is valid here.
  16576.   SELECT name, description, id FROM sysdtscategories WHERE parentid = @parentid
  16577.     ORDER BY name
  16578.   RETURN 0
  16579.  
  16580.   DO_RECURSE:
  16581.  
  16582.   --// Identify the category.
  16583.   IF @@nestlevel <> 0
  16584.     SELECT 'Level' = @@nestlevel, name FROM sysdtscategories WHERE id = @parentid
  16585.  
  16586.   --// List its subcategories
  16587.   DECLARE @childid UNIQUEIDENTIFIER
  16588.   DECLARE hC CURSOR LOCAL FOR SELECT id FROM sysdtscategories c WHERE parentid = @parentid ORDER BY c.name FOR READ ONLY
  16589.   OPEN hC
  16590.   FETCH NEXT FROM hC INTO @childid
  16591.   WHILE @@FETCH_STATUS = 0
  16592.   BEGIN
  16593.     EXECUTE sp_enum_dtscategories @childid, @flags
  16594.     FETCH NEXT FROM hC INTO @childid
  16595.   END
  16596.   CLOSE hC
  16597.   DEALLOCATE hC
  16598.   RETURN 0
  16599. go
  16600.  
  16601. /**************************************************************/
  16602. /*                                                            */
  16603. /*  D  B    M  A  I  N  T  E  N  A  N  C  E    P  L  A  N  S  */
  16604. /*                                                            */
  16605. /**************************************************************/
  16606.  
  16607. /**************************************************************/
  16608. /* SYSDBMAINTPLANS                                            */
  16609. /**************************************************************/
  16610.  
  16611. IF (NOT EXISTS (SELECT *
  16612.                 FROM msdb.dbo.sysobjects
  16613.                 WHERE (name = N'sysdbmaintplans')
  16614.                   AND (type = 'U')))
  16615. BEGIN
  16616.   PRINT ''
  16617.   PRINT 'Creating table sysdbmaintplans...'
  16618.  
  16619.   CREATE TABLE sysdbmaintplans
  16620.   (
  16621.   plan_id                    UNIQUEIDENTIFIER NOT NULL PRIMARY KEY CLUSTERED,
  16622.   plan_name                  sysname          NOT NULL,
  16623.   date_created               DATETIME         NOT NULL DEFAULT (GETDATE()),
  16624.   owner                      sysname          NOT NULL DEFAULT (ISNULL(NT_CLIENT(), SUSER_SNAME())),
  16625.   max_history_rows           INT              NOT NULL DEFAULT (0),
  16626.   remote_history_server      sysname          NOT NULL DEFAULT (''),
  16627.   max_remote_history_rows    INT              NOT NULL DEFAULT (0),
  16628.   user_defined_1             INT              NULL,
  16629.   user_defined_2             NVARCHAR(100)    NULL,
  16630.   user_defined_3             DATETIME         NULL,
  16631.   user_defined_4             UNIQUEIDENTIFIER NULL
  16632.   )
  16633. END
  16634. go
  16635.  
  16636. -- Add row for "plan 0"
  16637. IF (NOT EXISTS (SELECT *
  16638.                 FROM msdb.dbo.sysdbmaintplans
  16639.                 WHERE (plan_id = CONVERT(UNIQUEIDENTIFIER, 0x00))))
  16640.   INSERT INTO sysdbmaintplans(plan_id, plan_name) VALUES (0x00, N'All ad-hoc plans')
  16641. go
  16642.  
  16643. /**************************************************************/
  16644. /* SYSDBMAINTPLAN_JOBS                                        */
  16645. /**************************************************************/
  16646.  
  16647. IF (NOT EXISTS (SELECT *
  16648.                 FROM msdb.dbo.sysobjects
  16649.                 WHERE (name = N'sysdbmaintplan_jobs')
  16650.                   AND (type = 'U')))
  16651. BEGIN
  16652.   PRINT ''
  16653.   PRINT 'Creating table sysdbmaintplan_jobs...'
  16654.  
  16655.   CREATE TABLE sysdbmaintplan_jobs
  16656.   (
  16657.   plan_id UNIQUEIDENTIFIER NOT NULL UNIQUE CLUSTERED (plan_id, job_id)
  16658.                                     FOREIGN KEY REFERENCES msdb.dbo.sysdbmaintplans (plan_id),
  16659.   job_id  UNIQUEIDENTIFIER NOT NULL
  16660.   )
  16661. END
  16662. go
  16663.  
  16664. /**************************************************************/
  16665. /* SYSDBMAINTPLAN_DATABASES                                   */
  16666. /**************************************************************/
  16667.  
  16668. IF (NOT EXISTS (SELECT *
  16669.                 FROM msdb.dbo.sysobjects
  16670.                 WHERE (name = N'sysdbmaintplan_databases')
  16671.                   AND (type = 'U')))
  16672. BEGIN
  16673.   PRINT ''
  16674.   PRINT 'Creating table sysdbmaintplan_databases...'
  16675.  
  16676.   CREATE TABLE sysdbmaintplan_databases
  16677.   (
  16678.   plan_id       UNIQUEIDENTIFIER NOT NULL UNIQUE CLUSTERED (plan_id, database_name) 
  16679.                                           FOREIGN KEY REFERENCES msdb.dbo.sysdbmaintplans (plan_id),
  16680.   database_name sysname          NOT NULL
  16681.   )
  16682. END
  16683. go
  16684.  
  16685. /**************************************************************/
  16686. /* SYSDBMAINTPLAN_HISTORY                                     */
  16687. /**************************************************************/
  16688.  
  16689. IF (NOT EXISTS (SELECT *
  16690.                 FROM msdb.dbo.sysobjects
  16691.                 WHERE (name = N'sysdbmaintplan_history')
  16692.                   AND (type = 'U')))
  16693. BEGIN
  16694.   PRINT ''
  16695.   PRINT 'Creating table sysdbmaintplan_history...'
  16696.  
  16697.   CREATE TABLE sysdbmaintplan_history
  16698.   (
  16699.   sequence_id    INT               NOT NULL IDENTITY UNIQUE NONCLUSTERED,
  16700.   plan_id        UNIQUEIDENTIFIER  NOT NULL DEFAULT('00000000-0000-0000-0000-000000000000'),
  16701.   plan_name      sysname           NOT NULL DEFAULT('All ad-hoc plans'),
  16702.   database_name  sysname           NULL,
  16703.   server_name    sysname           NOT NULL DEFAULT (@@servername),
  16704.   activity       NVARCHAR(128)     NULL,
  16705.   succeeded      BIT               NOT NULL DEFAULT (1),
  16706.   end_time       DATETIME          NOT NULL DEFAULT (GETDATE()),
  16707.   duration       INT               NULL     DEFAULT (0),
  16708.   start_time     AS                DATEADD (ss, -duration, end_time),
  16709.   error_number   INT               NOT NULL DEFAULT (0),
  16710.   message        NVARCHAR(512)     NULL
  16711.   )
  16712.  
  16713.   CREATE CLUSTERED INDEX clust ON sysdbmaintplan_history(plan_id)
  16714. END
  16715. go
  16716.  
  16717. /**************************************************************/
  16718. /*                                                            */
  16719. /* B A C K U P  H I S T O R Y                                 */
  16720. /*                                                            */
  16721. /**************************************************************/
  16722.  
  16723. /**************************************************************/
  16724. /* SP_DELETE_BACKUPHISTORY                                    */
  16725. /**************************************************************/
  16726.  
  16727. PRINT ''
  16728. PRINT 'Creating procedure sp_delete_backuphistory...'
  16729. go
  16730. IF (EXISTS (SELECT *
  16731.             FROM msdb.dbo.sysobjects
  16732.             WHERE (name = N'sp_delete_backuphistory')
  16733.               AND (type = 'P')))
  16734.   DROP PROCEDURE sp_delete_backuphistory
  16735. go
  16736. CREATE   PROCEDURE sp_delete_backuphistory
  16737.   @oldest_date datetime
  16738. AS
  16739. BEGIN
  16740.   declare @bsid int
  16741.   declare @msid int
  16742.   declare @rows int
  16743.   declare @errorflag int
  16744.   declare @str nvarchar(64)
  16745.  
  16746.   set nocount on
  16747.   set @errorflag = 0
  16748.   declare oldbackups insensitive cursor for
  16749.     select backup_set_id from backupset where backup_finish_date < @oldest_date
  16750.     for read only
  16751.   open oldbackups
  16752.   fetch next from oldbackups into @bsid
  16753.   while(@@fetch_status = 0)
  16754.   begin
  16755.     begin transaction
  16756.     set rowcount 1
  16757.     set @rows = (select count(*) from restorehistory where backup_set_id = @bsid)
  16758.     set rowcount 0
  16759.     if (@rows > 0)
  16760.     begin
  16761.       delete from restorefile where restore_history_id in (select restore_history_id from restorehistory where backup_set_id = @bsid)
  16762.       if (@@error <> 0)
  16763.       begin
  16764.          rollback transaction 
  16765.          set @errorflag = 1
  16766.          break
  16767.       end
  16768.       delete from restorefilegroup where restore_history_id in (select restore_history_id from restorehistory where backup_set_id = @bsid)
  16769.       if (@@error <> 0)
  16770.       begin
  16771.          rollback transaction 
  16772.          set @errorflag = 1
  16773.          break
  16774.       end
  16775.       delete from restorehistory where backup_set_id = @bsid
  16776.       if (@@error <> 0)
  16777.       begin
  16778.          rollback transaction 
  16779.          set @errorflag = 1
  16780.          break
  16781.       end
  16782.     end 
  16783.     delete from backupfile where backup_set_id = @bsid
  16784.     if (@@error <> 0)
  16785.     begin
  16786.        rollback transaction 
  16787.        set @errorflag = 1
  16788.        break
  16789.     end
  16790.     set @msid = (select media_set_id from backupset where backup_set_id = @bsid)
  16791.     delete from backupset where backup_set_id = @bsid
  16792.     if (@@error <> 0)
  16793.     begin
  16794.        rollback transaction 
  16795.        set @errorflag = 1
  16796.        break
  16797.     end
  16798.     set rowcount 1
  16799.     set @rows = (select count(*) from backupset where media_set_id = @msid)
  16800.     set rowcount 0
  16801.     if (@rows = 0)
  16802.     begin
  16803.       delete from backupmediafamily where media_set_id = @msid
  16804.       if (@@error <> 0)
  16805.       begin
  16806.          rollback transaction 
  16807.          set @errorflag = 1
  16808.          break
  16809.       end
  16810.       delete from backupmediaset where media_set_id = @msid
  16811.       if (@@error <> 0)
  16812.       begin
  16813.          rollback transaction 
  16814.          set @errorflag = 1
  16815.          break
  16816.       end
  16817.     end
  16818.     commit transaction
  16819.     fetch next from oldbackups into @bsid
  16820.   end
  16821.   deallocate oldbackups
  16822.   set nocount off
  16823.  
  16824.   if (@errorflag <> 0)
  16825.   begin
  16826.     set @str = (select convert( nvarchar(64), @bsid))
  16827.     raiserror( 4325, -1, -1, @str )
  16828.     return(1)
  16829.   end
  16830.  
  16831.   set @str = (select convert( nvarchar(64), @oldest_date))
  16832.   raiserror( 4324, -1, -1, @str  )
  16833.   return(0)
  16834.  
  16835. END
  16836. go
  16837.  
  16838. /**************************************************************/
  16839. /* Turn 'System Object' marking OFF                           */
  16840. /**************************************************************/
  16841. PRINT ''
  16842. EXECUTE master.dbo.sp_MS_upd_sysobj_category 2
  16843. go
  16844.  
  16845. EXECUTE master.dbo.sp_configure N'allow updates', 0
  16846. go
  16847. RECONFIGURE WITH OVERRIDE
  16848. go
  16849.  
  16850. PRINT ''
  16851. PRINT '----------------------------------'
  16852. PRINT 'Execution of INSTMSDB.SQL complete'
  16853. PRINT '----------------------------------'
  16854. go
  16855.  
  16856. DUMP TRANSACTION msdb WITH NO_LOG
  16857. go
  16858. CHECKPOINT
  16859. go
  16860.