home *** CD-ROM | disk | FTP | other *** search
/ 95.86.62.111 / 95.86.62.111.tar / 95.86.62.111 / sql2000 / INSTALL / instmsdb.sql < prev    next >
Text File  |  2000-07-06  |  736KB  |  19,496 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. /*
  13. ** Copyright Microsoft, Inc. 1994 - 2000
  14. ** All Rights Reserved.
  15. */
  16. /**********************************************************************/
  17.  
  18. PRINT '----------------------------------'
  19. PRINT 'Starting execution of INSTMSDB.SQL'
  20. PRINT '----------------------------------'
  21. go
  22.  
  23. /**************************************************************/
  24. /* Turn 'System Object' marking ON                            */
  25. /**************************************************************/
  26. EXECUTE master.dbo.sp_MS_upd_sysobj_category 1
  27. go
  28.  
  29. -- Explicitly set the options that the server stores with the object in sysobjects.status
  30. -- so that it doesn't matter if the script is run using a DBLib or ODBC based client.
  31. SET QUOTED_IDENTIFIER OFF -- We don't use quoted identifiers
  32. SET ANSI_NULLS ON         -- We don't want (NULL = NULL) == TRUE
  33. go
  34. SET ANSI_PADDING ON       -- Set so that trailing zeros aren't trimmed off sysjobs.owner_login_sid
  35. go
  36.  
  37. -- Allow updates to system catalogs so that all our SP's inherit full DML capability on
  38. -- system objects and so that we can exercise full DDL control on our system objects
  39. EXECUTE master.dbo.sp_configure N'allow updates', 1
  40. go
  41. RECONFIGURE WITH OVERRIDE
  42. go
  43.  
  44. /**************************************************************/
  45. /*                                                            */
  46. /*      D  A  T  A  B  A  S  E    C  R  E  A  T  I  O  N      */
  47. /*                                                            */
  48. /**************************************************************/
  49.  
  50. IF (NOT EXISTS (SELECT name
  51.                 FROM master.dbo.sysdatabases
  52.                 WHERE (name = N'msdb')))
  53. BEGIN
  54.   PRINT 'Creating the msdb database...'
  55. END
  56. go
  57.  
  58. USE master
  59. go
  60.  
  61. SET NOCOUNT ON
  62.  
  63. -- NOTE: It is important that this script can be re-run WITHOUT causing loss of data, hence
  64. --       we only create the database if it missing (if the database already exists we test
  65. --       that it has enough free space and if not we expand both the device and the database).
  66. DECLARE @model_db_size    INT
  67. DECLARE @msdb_db_size     INT
  68. DECLARE @sz_msdb_db_size  VARCHAR(10)
  69. DECLARE @device_directory NVARCHAR(520)
  70. DECLARE @page_size        INT
  71. DECLARE @size             INT
  72. DECLARE @free_db_space    FLOAT
  73.  
  74. SELECT @page_size = 8
  75.  
  76. IF (NOT EXISTS (SELECT name
  77.                 FROM master.dbo.sysdatabases
  78.                 WHERE (name = N'msdb')))
  79. BEGIN
  80.   -- Make sure that we create [the data portion of] MSDB to be at least as large as
  81.   -- the MODEL database
  82.   SELECT @model_db_size = (SUM(size) * @page_size)
  83.   FROM model.dbo.sysfiles
  84.  
  85.   IF (@model_db_size > 3072) -- 3 is the minimum required size for MSDB (in megabytes)
  86.     SELECT @msdb_db_size = @model_db_size
  87.   ELSE
  88.     SELECT @msdb_db_size = 3072
  89.  
  90.   SELECT @device_directory = SUBSTRING(phyname, 1, CHARINDEX(N'master.mdf', LOWER(phyname)) - 1)
  91.   FROM master.dbo.sysdevices
  92.   WHERE (name = N'master')
  93.  
  94.   -- Drop any existing MSDBData / MSDBLog file(s)
  95.   EXECUTE(N'EXECUTE master.dbo.xp_cmdshell N''DEL ' + @device_directory + N'MSDBData.mdf'', no_output')
  96.   EXECUTE(N'EXECUTE master.dbo.xp_cmdshell N''DEL ' + @device_directory + N'MSDBLog.ldf'', no_output')
  97.  
  98.   -- Create the database
  99.   PRINT ''
  100.   PRINT 'Creating MSDB database...'
  101.   SELECT @sz_msdb_db_size = RTRIM(LTRIM(CONVERT(VARCHAR, @msdb_db_size)))
  102.   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)
  103.                           LOG ON (NAME = N''MSDBLog'',  FILENAME = N''' + @device_directory + N'MSDBLog.ldf'',  SIZE = 512KB, MAXSIZE = UNLIMITED, FILEGROWTH = 256KB)')
  104.   PRINT ''
  105. END
  106. ELSE
  107. BEGIN
  108.   PRINT 'Checking the size of MSDB...'
  109.  
  110.   DBCC UPDATEUSAGE(N'msdb') WITH NO_INFOMSGS
  111.  
  112.   -- Make sure that MSDBLog has unlimited growth
  113.   ALTER DATABASE msdb MODIFY FILE (NAME = N'MSDBLog', MAXSIZE = UNLIMITED)
  114.  
  115.   -- Determine amount of free space in msdb. We need at least 2MB free.
  116.   SELECT @free_db_space = ((((SELECT SUM(size)
  117.                               FROM msdb.dbo.sysfiles
  118.                               WHERE status & 0x8040 = 0) -
  119.                              (SELECT SUM(reserved)
  120.                               FROM msdb.dbo.sysindexes
  121.                               WHERE indid IN (0, 1, 255))) * @page_size) / 1024.0)
  122.  
  123.   IF (@free_db_space < 2)
  124.   BEGIN
  125.     DECLARE @logical_file_name sysname
  126.     DECLARE @os_file_name      NVARCHAR(255)
  127.     DECLARE @size_as_char      VARCHAR(10)
  128.     
  129.     SELECT @logical_file_name = name,
  130.            @os_file_name = phyname,
  131.            @size_as_char = CONVERT(VARCHAR(10), ((high + 1) / 4) + 2048)
  132.     FROM master.dbo.sysdevices
  133.     WHERE (name = N'MSDBData')
  134.  
  135.     PRINT 'Attempting to expand the msdb database...'
  136.     EXECUTE (N'ALTER DATABASE msdb MODIFY FILE (NAME = N''' + @logical_file_name + N''',
  137.                                                 FILENAME = N''' + @os_file_name + N''',
  138.                                                 SIZE = @size_as_char)')
  139.     IF (@@error <> 0)
  140.       RAISERROR('Unable to expand the msdb database. INSTMSDB.SQL terminating.', 20, 127) WITH LOG
  141.   END
  142.   PRINT ''
  143. END
  144. go
  145.  
  146. EXECUTE sp_dboption msdb, N'trunc. log on chkpt.', TRUE
  147. go
  148.  
  149. USE msdb
  150. go
  151.  
  152. -- Check that we're in msdb
  153. IF (DB_NAME() <> N'msdb')
  154.   RAISERROR('A problem was encountered accessing msdb. INSTMSDB.SQL terminating.', 20, 127) WITH LOG
  155. go
  156.  
  157. -- Add the guest user
  158. IF (NOT EXISTS (SELECT *
  159.                 FROM msdb.dbo.sysusers
  160.                 WHERE (name = N'guest')
  161.                   AND (hasdbaccess = 1)))
  162. BEGIN
  163.   PRINT ''
  164.   EXECUTE sp_adduser N'guest'
  165. END
  166. go
  167.  
  168. DUMP TRANSACTION msdb WITH NO_LOG
  169. go
  170. CHECKPOINT
  171. go
  172.  
  173. /**************************************************************/
  174. /*                                                            */
  175. /*                      U P G R A D E S                       */
  176. /*                                                            */
  177. /**************************************************************/
  178.  
  179. /**************************************************************/
  180. -- If not on Windows 9x, use LSA instead of Registry to store
  181. -- confidential information
  182. /**************************************************************/
  183. DECLARE @OS int
  184. EXECUTE master.dbo.xp_MSplatform @OS OUTPUT
  185.  
  186. IF (@OS <> 2)
  187. BEGIN
  188.   PRINT 'Update SQL Agent Registry Settings'
  189.  
  190.   DECLARE @host_login_name               sysname
  191.   DECLARE @host_login_password           VARBINARY(64)
  192.  
  193.   -- HostLoginID
  194.   EXECUTE master.dbo.xp_instance_regread N'HKEY_LOCAL_MACHINE',
  195.                                          N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
  196.                                          N'HostLoginID',
  197.                                          @host_login_name OUTPUT,
  198.                                          N'no_output'
  199.  
  200.   IF (@host_login_name IS NULL) SELECT @host_login_name = N'sa'
  201.  
  202.   EXECUTE master.dbo.xp_sqlagent_param   1, 
  203.                                          N'HostLoginID',
  204.                                          @host_login_name
  205.  
  206.   EXECUTE master.dbo.xp_instance_regwrite
  207.                                          N'HKEY_LOCAL_MACHINE',
  208.                                          N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
  209.                                          N'HostLoginID',
  210.                                          N'REG_SZ',
  211.                                          N''
  212.  
  213.   EXECUTE master.dbo.xp_instance_regdeletevalue
  214.                                          N'HKEY_LOCAL_MACHINE',
  215.                                          N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
  216.                                          N'HostLoginID'
  217.  
  218.   -- HostPassword
  219.   EXECUTE master.dbo.xp_instance_regread N'HKEY_LOCAL_MACHINE',
  220.                                          N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
  221.                                          N'HostPassword',
  222.                                          @host_login_password OUTPUT,
  223.                                          N'no_output'
  224.  
  225.   EXECUTE master.dbo.xp_sqlagent_param   1, 
  226.                                          N'HostPassword',
  227.                                          @host_login_password
  228.  
  229.   EXECUTE master.dbo.xp_instance_regwrite
  230.                                          N'HKEY_LOCAL_MACHINE',
  231.                                          N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
  232.                                          N'HostPassword',
  233.                                          N'REG_BINARY',
  234.                                          N''
  235.  
  236.   EXECUTE master.dbo.xp_instance_regdeletevalue
  237.                                          N'HKEY_LOCAL_MACHINE',
  238.                                          N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
  239.                                          N'HostPassword'
  240.  
  241. END -- If not Windows 9x, use LSA instead of Registry
  242. /**************************************************************/
  243. go
  244.  
  245. /**************************************************************/
  246. -- Upgrade the SQLAgent table to no longer use "(local)"
  247. -- but always use the server name or server\instance name
  248. /**************************************************************/
  249. IF EXISTS (SELECT * FROM msdb.dbo.sysobjects WHERE name = N'sysjobs' and type = 'U')
  250. BEGIN
  251.   PRINT ''
  252.   PRINT 'Update sysjobs'
  253.   UPDATE  msdb.dbo.sysjobs
  254.   SET     originating_server = CONVERT(NVARCHAR(30), SERVERPROPERTY('servername'))
  255.   WHERE   UPPER(originating_server) = '(LOCAL)'
  256. END
  257.  
  258. IF EXISTS (SELECT * FROM msdb.dbo.sysobjects WHERE name = N'sysjobhistory' and type = 'U')
  259. BEGIN
  260.   PRINT ''
  261.   PRINT 'Update sysjobhistory'
  262.   UPDATE  msdb.dbo.sysjobhistory
  263.   SET     server = CONVERT(NVARCHAR(30), SERVERPROPERTY('servername'))
  264.   WHERE   UPPER(server) = '(LOCAL)'
  265. END
  266. /**************************************************************/
  267. go
  268.  
  269. /**************************************************************/
  270. /*                                                            */
  271. /*              T  A  B  L  E     D  R  O  P  S               */
  272. /*                                                            */
  273. /**************************************************************/
  274.  
  275. SET NOCOUNT ON
  276.  
  277. DECLARE @build_number   INT
  278. DECLARE @rebuild_needed TINYINT
  279.  
  280. SELECT @build_number = @@microsoftversion & 0xffff
  281.  
  282. IF (@build_number <= 0) -- The last build that we changed the schema in
  283.   SELECT @rebuild_needed = 1
  284. ELSE
  285.   SELECT @rebuild_needed = 0
  286.  
  287. IF (EXISTS (SELECT *
  288.             FROM msdb.dbo.sysobjects
  289.             WHERE (name = N'sqlagent_info')
  290.               AND (type = 'U')
  291.               AND (@rebuild_needed = 1)))
  292. BEGIN
  293.   PRINT ''
  294.   PRINT 'Dropping table sqlagent_info...'
  295.   DROP TABLE dbo.sqlagent_info
  296. END
  297.  
  298. IF (EXISTS (SELECT *
  299.             FROM msdb.dbo.sysobjects
  300.             WHERE (name = N'sysdownloadlist')
  301.               AND (type = 'U')
  302.               AND (@rebuild_needed = 1)))
  303. BEGIN
  304.   PRINT ''
  305.   PRINT 'Dropping table sysdownloadlist...'
  306.  
  307.   IF (EXISTS (SELECT *
  308.               FROM msdb.dbo.syscolumns
  309.               WHERE (id = OBJECT_ID(N'sysdownloadlist'))
  310.                 AND (name = N'error_message')
  311.                 AND (cdefault <> 0)))
  312.     EXECUTE sp_unbindefault N'sysdownloadlist.error_message'
  313.  
  314.   IF (EXISTS (SELECT *
  315.               FROM msdb.dbo.syscolumns
  316.               WHERE (id = OBJECT_ID(N'sysdownloadlist'))
  317.                 AND (name = N'date_posted')
  318.                 AND (cdefault <> 0)))
  319.     EXECUTE sp_unbindefault N'sysdownloadlist.date_posted'
  320.  
  321.   IF (EXISTS (SELECT *
  322.               FROM msdb.dbo.syscolumns
  323.               WHERE (id = OBJECT_ID(N'sysdownloadlist'))
  324.                 AND (name = N'status')
  325.                 AND (cdefault <> 0)))
  326.     EXECUTE sp_unbindefault N'sysdownloadlist.status'
  327.  
  328.   DROP TABLE dbo.sysdownloadlist
  329. END
  330.  
  331. IF (EXISTS (SELECT *
  332.             FROM msdb.dbo.sysobjects
  333.             WHERE (name = N'sysjobhistory')
  334.               AND (type = 'U')
  335.               AND (@rebuild_needed = 1)))
  336. BEGIN
  337.   PRINT ''
  338.   PRINT 'Dropping table sysjobhistory...'
  339.   DROP TABLE dbo.sysjobhistory
  340. END
  341.  
  342. IF (EXISTS (SELECT *
  343.             FROM msdb.dbo.sysobjects
  344.             WHERE (name = N'sysjobservers')
  345.               AND (type = 'U')
  346.               AND (@rebuild_needed = 1)))
  347. BEGIN
  348.   PRINT ''
  349.   PRINT 'Dropping table sysjobservers...'
  350.   DROP TABLE dbo.sysjobservers
  351. END
  352.  
  353. IF (EXISTS (SELECT *
  354.             FROM msdb.dbo.sysobjects
  355.             WHERE (name = N'sysjobs')
  356.               AND (type = 'U')
  357.               AND (@rebuild_needed = 1)))
  358. BEGIN
  359.   PRINT ''
  360.   PRINT 'Dropping table sysjobs...'
  361.   DROP TABLE dbo.sysjobs
  362. END
  363.  
  364. IF (EXISTS (SELECT *
  365.             FROM msdb.dbo.sysobjects
  366.             WHERE (name = N'sysjobsteps')
  367.               AND (type = 'U')
  368.               AND (@rebuild_needed = 1)))
  369. BEGIN
  370.   PRINT ''
  371.   PRINT 'Dropping table sysjobsteps...'
  372.   DROP TABLE dbo.sysjobsteps
  373. END
  374.  
  375. IF (EXISTS (SELECT *
  376.             FROM msdb.dbo.sysobjects
  377.             WHERE (name = N'sysjobschedules')
  378.               AND (type = 'U')
  379.               AND (@rebuild_needed = 1)))
  380. BEGIN
  381.   PRINT ''
  382.   PRINT 'Dropping table sysjobschedules...'
  383.  
  384.   IF (EXISTS (SELECT *
  385.               FROM msdb.dbo.syscolumns
  386.               WHERE (id = OBJECT_ID(N'sysjobschedules'))
  387.                 AND (name = N'date_created')
  388.                 AND (cdefault <> 0)))
  389.     EXECUTE sp_unbindefault N'sysjobschedules.date_created'
  390.  
  391.   DROP TABLE dbo.sysjobschedules
  392. END
  393.  
  394. IF (EXISTS (SELECT *
  395.             FROM msdb.dbo.sysobjects
  396.             WHERE (name = N'syscategories')
  397.               AND (type = 'U')
  398.               AND (@rebuild_needed = 1)))
  399. BEGIN
  400.   PRINT ''
  401.   PRINT 'Dropping table syscategories...'
  402.   DROP TABLE dbo.syscategories
  403. END
  404.  
  405. IF (EXISTS (SELECT *
  406.             FROM msdb.dbo.sysobjects
  407.             WHERE (name = N'systargetservers')
  408.               AND (type = 'U')
  409.               AND (@rebuild_needed = 1)))
  410. BEGIN
  411.   PRINT ''
  412.   PRINT 'Dropping table systargetservers...'
  413.  
  414.   IF (EXISTS (SELECT *
  415.               FROM msdb.dbo.syscolumns
  416.               WHERE (id = OBJECT_ID(N'systargetservers'))
  417.                 AND (name = N'enlist_date')
  418.                 AND (cdefault <> 0)))
  419.     EXECUTE sp_unbindefault N'systargetservers.enlist_date'
  420.  
  421.   IF (EXISTS (SELECT *
  422.               FROM msdb.dbo.syscolumns
  423.               WHERE (id = OBJECT_ID(N'systargetservers'))
  424.                 AND (name = N'last_poll_date')
  425.                 AND (cdefault <> 0)))
  426.     EXECUTE sp_unbindefault N'systargetservers.last_poll_date'
  427.  
  428.   IF (EXISTS (SELECT *
  429.               FROM msdb.dbo.syscolumns
  430.               WHERE (id = OBJECT_ID(N'systargetservers'))
  431.                 AND (name = N'status')
  432.                 AND (cdefault <> 0)))
  433.     EXECUTE sp_unbindefault N'systargetservers.status'
  434.  
  435.   DROP TABLE dbo.systargetservers
  436. END
  437.  
  438. IF (EXISTS (SELECT *
  439.             FROM msdb.dbo.sysobjects
  440.             WHERE (name = N'systargetservergroups')
  441.               AND (type = 'U')
  442.               AND (@rebuild_needed = 1)))
  443. BEGIN
  444.   PRINT ''
  445.   PRINT 'Dropping table systargetservergroups...'
  446.   DROP TABLE dbo.systargetservergroups
  447. END
  448.  
  449. IF (EXISTS (SELECT *
  450.             FROM msdb.dbo.sysobjects
  451.             WHERE (name = N'systargetservergroupmembers')
  452.               AND (type = 'U')
  453.               AND (@rebuild_needed = 1)))
  454. BEGIN
  455.   PRINT ''
  456.   PRINT 'Dropping table systargetservergroupmembers...'
  457.   DROP TABLE dbo.systargetservergroupmembers
  458. END
  459.  
  460. IF (EXISTS (SELECT *
  461.             FROM msdb.dbo.sysobjects
  462.             WHERE (name = N'systaskids')
  463.               AND (type = 'U')
  464.               AND (@rebuild_needed = 1)))
  465. BEGIN
  466.   PRINT ''
  467.   PRINT 'Dropping table systaskids...'
  468.   DROP TABLE dbo.systaskids
  469. END
  470.  
  471. IF (EXISTS (SELECT *
  472.             FROM msdb.dbo.sysobjects
  473.             WHERE (name = N'sysalerts')
  474.               AND (type = 'U')
  475.               AND (@rebuild_needed = 1)))
  476. BEGIN
  477.   PRINT ''
  478.   PRINT 'Dropping table sysalerts...'
  479.   DROP TABLE dbo.sysalerts
  480. END
  481.  
  482. IF (EXISTS (SELECT *
  483.             FROM msdb.dbo.sysobjects
  484.             WHERE (name = N'sysoperators')
  485.               AND (type = 'U')
  486.               AND (@rebuild_needed = 1)))
  487. BEGIN
  488.   PRINT ''
  489.   PRINT 'Dropping table sysoperators...'
  490.   DROP TABLE dbo.sysoperators
  491. END
  492.  
  493. IF (EXISTS (SELECT *
  494.             FROM msdb.dbo.sysobjects
  495.             WHERE (name = N'sysnotifications')
  496.               AND (type = 'U')
  497.               AND (@rebuild_needed = 1)))
  498. BEGIN
  499.   PRINT ''
  500.   PRINT 'Dropping table sysnotifications...'
  501.   DROP TABLE dbo.sysnotifications
  502. END
  503.  
  504. IF (EXISTS (SELECT *
  505.             FROM msdb.dbo.sysobjects
  506.             WHERE (name = N'sysdbmaintplan_jobs')
  507.               AND (type = 'U')
  508.               AND (@rebuild_needed = 1)))
  509. BEGIN
  510.   PRINT ''
  511.   PRINT 'Dropping table sysdbmaintplan_jobs...'
  512.   DROP TABLE sysdbmaintplan_jobs
  513. END
  514.  
  515. IF (EXISTS (SELECT *
  516.             FROM msdb.dbo.sysobjects
  517.             WHERE (name = N'sysdbmaintplan_databases')
  518.               AND (type = 'U')
  519.               AND (@rebuild_needed = 1)))
  520. BEGIN
  521.   PRINT ''
  522.   PRINT 'Dropping table sysdbmaintplan_databases...'
  523.   DROP TABLE sysdbmaintplan_databases
  524. END
  525.  
  526. IF (EXISTS (SELECT *
  527.             FROM msdb.dbo.sysobjects
  528.             WHERE (name = N'sysdbmaintplan_history')
  529.               AND (type = 'U')
  530.               AND (@rebuild_needed = 1)))
  531. BEGIN
  532.   PRINT ''
  533.   PRINT 'Dropping table sysdbmaintplan_history...'
  534.   DROP TABLE sysdbmaintplan_history
  535. END
  536.  
  537. IF (EXISTS (SELECT *
  538.             FROM msdb.dbo.sysobjects
  539.             WHERE (name = N'sysdbmaintplans')
  540.               AND (type = 'U')
  541.               AND (@rebuild_needed = 1)))
  542. BEGIN
  543.   PRINT ''
  544.   PRINT 'Dropping table sysdbmaintplans...'
  545.   DROP TABLE sysdbmaintplans
  546. END
  547.  
  548. IF (EXISTS (SELECT *
  549.             FROM msdb.dbo.sysobjects
  550.             WHERE (name = N'syscachedcredentials')
  551.               AND (type = 'U')
  552.               AND (@rebuild_needed = 1)))
  553. BEGIN
  554.   PRINT ''
  555.   PRINT 'Dropping table syscachedcredentials...'
  556.   DROP TABLE syscachedcredentials
  557. END
  558.  
  559. IF (EXISTS (SELECT *
  560.             FROM msdb.dbo.sysobjects
  561.             WHERE (name = N'default_sdl_error_message')
  562.               AND (type = 'D')
  563.               AND (@rebuild_needed = 1)))
  564.   DROP DEFAULT default_sdl_error_message
  565.  
  566. IF (EXISTS (SELECT *
  567.             FROM msdb.dbo.sysobjects
  568.             WHERE (name = N'default_current_date')
  569.               AND (type = 'D')
  570.               AND (@rebuild_needed = 1)))
  571.   DROP DEFAULT default_current_date
  572.  
  573. IF (EXISTS (SELECT *
  574.             FROM msdb.dbo.sysobjects
  575.             WHERE (name = N'default_zero')
  576.               AND (type = 'D')
  577.               AND (@rebuild_needed = 1)))
  578.   DROP DEFAULT default_zero
  579.  
  580. IF (EXISTS (SELECT *
  581.             FROM msdb.dbo.sysobjects
  582.             WHERE (name = N'default_one')
  583.               AND (type = 'D')
  584.               AND (@rebuild_needed = 1)))
  585.   DROP DEFAULT default_one
  586. go
  587.  
  588. DUMP TRANSACTION msdb WITH NO_LOG
  589. go
  590. CHECKPOINT
  591. go
  592.  
  593. /**************************************************************/
  594. /*                                                            */
  595. /*                     D  E  F  A  U  L  T  S                 */
  596. /*                                                            */
  597. /**************************************************************/
  598.  
  599. IF (NOT EXISTS (SELECT *
  600.                 FROM msdb.dbo.sysobjects
  601.                 WHERE (name = N'default_sdl_error_message')
  602.                   AND (type = 'D')))
  603.   EXECUTE('CREATE DEFAULT default_sdl_error_message AS NULL')
  604. go
  605. IF (NOT EXISTS (SELECT *
  606.                 FROM msdb.dbo.sysobjects
  607.                 WHERE (name = N'default_current_date')
  608.                   AND (type = 'D')))
  609.   EXECUTE('CREATE DEFAULT default_current_date AS GETDATE()')
  610. go
  611. IF (NOT EXISTS (SELECT *
  612.                 FROM msdb.dbo.sysobjects
  613.                 WHERE (name = N'default_zero')
  614.                   AND (type = 'D')))
  615.   EXECUTE('CREATE DEFAULT default_zero AS 0')
  616. go
  617. IF (NOT EXISTS (SELECT *
  618.                 FROM msdb.dbo.sysobjects
  619.                 WHERE (name = N'default_one')
  620.                   AND (type = 'D')))
  621.   EXECUTE('CREATE DEFAULT default_one AS 1')
  622. go
  623.  
  624. /**************************************************************/
  625. /*                                                            */
  626. /*                       T  A  B  L  E  S                     */
  627. /*                                                            */
  628. /**************************************************************/
  629.  
  630. /**************************************************************/
  631. /* SQLAGENT_INFO                                              */
  632. /**************************************************************/
  633.  
  634. IF (NOT EXISTS (SELECT *
  635.                 FROM msdb.dbo.sysobjects
  636.                 WHERE (name = N'sqlagent_info')
  637.                   AND (type = 'U')))
  638. BEGIN
  639.   PRINT ''
  640.   PRINT 'Creating table sqlagent_info...'
  641.  
  642.   CREATE TABLE sqlagent_info
  643.   (
  644.   attribute sysname       NOT NULL,
  645.   value     NVARCHAR(512) NOT NULL
  646.   )
  647. END
  648. go
  649.  
  650. /**************************************************************/
  651. /* SYSDOWNLOADLIST                                            */
  652. /**************************************************************/
  653.  
  654. IF (NOT EXISTS (SELECT *
  655.                 FROM msdb.dbo.sysobjects
  656.                 WHERE (name = N'sysdownloadlist')
  657.                   AND (type = 'U')))
  658. BEGIN
  659.   PRINT ''
  660.   PRINT 'Creating table sysdownloadlist...'
  661.  
  662.   CREATE TABLE sysdownloadlist
  663.   (
  664.   instance_id         INT IDENTITY     NOT NULL,
  665.   source_server       NVARCHAR(30)     NOT NULL,
  666.   operation_code      TINYINT          NOT NULL,
  667.   object_type         TINYINT          NOT NULL,
  668.   object_id           UNIQUEIDENTIFIER NOT NULL,
  669.   target_server       NVARCHAR(30)     NOT NULL,
  670.   error_message       NVARCHAR(1024)   NULL,
  671.   date_posted         DATETIME         NOT NULL,
  672.   date_downloaded     DATETIME         NULL,
  673.   status              TINYINT          NOT NULL,
  674.   deleted_object_name sysname          NULL
  675.   )
  676.  
  677.   EXECUTE sp_bindefault default_sdl_error_message, N'sysdownloadlist.error_message'
  678.   EXECUTE sp_bindefault default_current_date,      N'sysdownloadlist.date_posted'
  679.   EXECUTE sp_bindefault default_zero,              N'sysdownloadlist.status'
  680.  
  681.   CREATE UNIQUE CLUSTERED INDEX clust ON sysdownloadlist(instance_id)
  682.   CREATE NONCLUSTERED     INDEX nc1   ON sysdownloadlist(target_server)
  683.   CREATE NONCLUSTERED     INDEX nc2   ON sysdownloadlist(object_id)
  684. END
  685. go
  686.  
  687. /**************************************************************/
  688. /* SYSJOBHISTORY                                              */
  689. /**************************************************************/
  690.  
  691. IF (NOT EXISTS (SELECT *
  692.                 FROM msdb.dbo.sysobjects
  693.                 WHERE (name = N'sysjobhistory')
  694.                   AND (type = 'U')))
  695. BEGIN
  696.   PRINT ''
  697.   PRINT 'Creating table sysjobhistory...'
  698.  
  699.   CREATE TABLE sysjobhistory
  700.   (
  701.   instance_id          INT IDENTITY     NOT NULL,
  702.   job_id               UNIQUEIDENTIFIER NOT NULL,
  703.   step_id              INT              NOT NULL,
  704.   step_name            sysname          NOT NULL,
  705.   sql_message_id       INT              NOT NULL,
  706.   sql_severity         INT              NOT NULL,
  707.   message              NVARCHAR(1024)   NULL,
  708.   run_status           INT              NOT NULL,
  709.   run_date             INT              NOT NULL,
  710.   run_time             INT              NOT NULL,
  711.   run_duration         INT              NOT NULL,
  712.   operator_id_emailed  INT              NOT NULL,
  713.   operator_id_netsent  INT              NOT NULL,
  714.   operator_id_paged    INT              NOT NULL,
  715.   retries_attempted    INT              NOT NULL,
  716.   server               NVARCHAR(30)     NOT NULL
  717.   )
  718.  
  719.   CREATE UNIQUE CLUSTERED INDEX clust ON sysjobhistory(instance_id)
  720.   CREATE NONCLUSTERED     INDEX nc1   ON sysjobhistory(job_id)
  721. END
  722. go
  723.  
  724. /**************************************************************/
  725. /* SYSJOBS                                                    */
  726. /**************************************************************/
  727.  
  728. IF (NOT EXISTS (SELECT *
  729.                 FROM msdb.dbo.sysobjects
  730.                 WHERE (name = N'sysjobs')
  731.                   AND (type = 'U')))
  732. BEGIN
  733.   PRINT ''
  734.   PRINT 'Creating table sysjobs...'
  735.  
  736.   CREATE TABLE sysjobs
  737.   (
  738.   job_id                     UNIQUEIDENTIFIER NOT NULL,
  739.   originating_server         NVARCHAR(30)     NOT NULL,
  740.   name                       sysname          NOT NULL,
  741.   enabled                    TINYINT          NOT NULL,
  742.   description                NVARCHAR(512)    NULL,
  743.   start_step_id              INT              NOT NULL,
  744.   category_id                INT              NOT NULL,
  745.   owner_sid                  VARBINARY(85)    NOT NULL,
  746.   notify_level_eventlog      INT              NOT NULL,
  747.   notify_level_email         INT              NOT NULL,
  748.   notify_level_netsend       INT              NOT NULL,
  749.   notify_level_page          INT              NOT NULL,
  750.   notify_email_operator_id   INT              NOT NULL,
  751.   notify_netsend_operator_id INT              NOT NULL,
  752.   notify_page_operator_id    INT              NOT NULL,
  753.   delete_level               INT              NOT NULL,
  754.   date_created               DATETIME         NOT NULL,
  755.   date_modified              DATETIME         NOT NULL,
  756.   version_number             INT              NOT NULL
  757.   )
  758.  
  759.   CREATE UNIQUE CLUSTERED INDEX clust ON sysjobs(job_id)
  760.   CREATE NONCLUSTERED     INDEX nc1   ON sysjobs(name) -- NOTE: This is deliberately non-unique
  761.   CREATE NONCLUSTERED     INDEX nc2   ON sysjobs(originating_server)
  762.   CREATE NONCLUSTERED     INDEX nc3   ON sysjobs(category_id)
  763.   CREATE NONCLUSTERED     INDEX nc4   ON sysjobs(owner_sid)
  764. END
  765. go
  766.  
  767. /**************************************************************/
  768. /* SYSJOBS_VIEW                                               */
  769. /**************************************************************/
  770.  
  771. PRINT ''
  772. PRINT 'Creating view sysjobs_view...'
  773. go
  774. IF (EXISTS (SELECT *
  775.             FROM msdb.dbo.sysobjects
  776.             WHERE (name = N'sysjobs_view')
  777.               AND (type = 'V')))
  778.   DROP VIEW sysjobs_view
  779. go
  780. CREATE VIEW sysjobs_view
  781. AS
  782. SELECT *
  783. FROM msdb.dbo.sysjobs
  784. WHERE (owner_sid = SUSER_SID())
  785.    OR (ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) = 1)
  786.    OR (ISNULL(IS_MEMBER(N'TargetServersRole'), 0) = 1)
  787. go
  788.  
  789. /**************************************************************/
  790. /* SYSJOBSERVERS                                              */
  791. /**************************************************************/
  792.  
  793. IF (NOT EXISTS (SELECT *
  794.                 FROM msdb.dbo.sysobjects
  795.                 WHERE (name = N'sysjobservers')
  796.                   AND (type = 'U')))
  797. BEGIN
  798.   PRINT ''
  799.   PRINT 'Creating table sysjobservers...'
  800.  
  801.   CREATE TABLE sysjobservers
  802.   (
  803.   job_id               UNIQUEIDENTIFIER NOT NULL,
  804.   server_id            INT              NOT NULL,
  805.   last_run_outcome     TINYINT          NOT NULL,
  806.   last_outcome_message NVARCHAR(1024)   NULL,
  807.   last_run_date        INT              NOT NULL,
  808.   last_run_time        INT              NOT NULL,
  809.   last_run_duration    INT              NOT NULL
  810.   )
  811.  
  812.   CREATE CLUSTERED    INDEX clust ON sysjobservers(job_id)
  813.   CREATE NONCLUSTERED INDEX nc1   ON sysjobservers(server_id)
  814. END
  815. go
  816.  
  817. /**************************************************************/
  818. /* SYSJOBSTEPS                                                */
  819. /**************************************************************/
  820.  
  821. IF (NOT EXISTS (SELECT *
  822.                 FROM msdb.dbo.sysobjects
  823.                 WHERE (name = N'sysjobsteps')
  824.                   AND (type = 'U')))
  825. BEGIN
  826.   PRINT ''
  827.   PRINT 'Creating table sysjobsteps...'
  828.  
  829.   CREATE TABLE sysjobsteps
  830.   (
  831.   job_id                UNIQUEIDENTIFIER NOT NULL,
  832.   step_id               INT              NOT NULL,
  833.   step_name             sysname          NOT NULL,
  834.   subsystem             NVARCHAR(40)     NOT NULL,
  835.   command               NVARCHAR(3200)   NULL,      -- NOTE: 3.125K since unicode requires 2x space
  836.   flags                 INT              NOT NULL,
  837.   additional_parameters NTEXT            NULL,
  838.   cmdexec_success_code  INT              NOT NULL,
  839.   on_success_action     TINYINT          NOT NULL,
  840.   on_success_step_id    INT              NOT NULL,
  841.   on_fail_action        TINYINT          NOT NULL,
  842.   on_fail_step_id       INT              NOT NULL,
  843.   server                sysname          NULL,      -- Used only by replication
  844.   database_name         sysname          NULL,
  845.   database_user_name    sysname          NULL,
  846.   retry_attempts        INT              NOT NULL,
  847.   retry_interval        INT              NOT NULL,
  848.   os_run_priority       INT              NOT NULL,  -- NOTE: Cannot use TINYINT because we need a signed number
  849.   output_file_name      NVARCHAR(200)    NULL,
  850.   last_run_outcome      INT              NOT NULL,
  851.   last_run_duration     INT              NOT NULL,
  852.   last_run_retries      INT              NOT NULL,
  853.   last_run_date         INT              NOT NULL,
  854.   last_run_time         INT              NOT NULL
  855.   )
  856.  
  857.   CREATE UNIQUE CLUSTERED INDEX clust ON sysjobsteps(job_id, step_id)
  858.   CREATE UNIQUE NONCLUSTERED INDEX nc1 ON sysjobsteps(job_id, step_name)
  859. END
  860. go
  861.  
  862. /**************************************************************/
  863. /* SYSJOBSCHEDULES                                            */
  864. /**************************************************************/
  865.  
  866. IF (NOT EXISTS (SELECT *
  867.                 FROM msdb.dbo.sysobjects
  868.                 WHERE (name = N'sysjobschedules')
  869.                   AND (type = 'U')))
  870. BEGIN
  871.   PRINT ''
  872.   PRINT 'Creating table sysjobschedules...'
  873.  
  874.   CREATE TABLE sysjobschedules
  875.   (
  876.   schedule_id            INT IDENTITY     NOT NULL,
  877.   job_id                 UNIQUEIDENTIFIER NOT NULL,
  878.   name                   sysname          NOT NULL,
  879.   enabled                INT              NOT NULL,
  880.   freq_type              INT              NOT NULL,
  881.   freq_interval          INT              NOT NULL,
  882.   freq_subday_type       INT              NOT NULL,
  883.   freq_subday_interval   INT              NOT NULL,
  884.   freq_relative_interval INT              NOT NULL,
  885.   freq_recurrence_factor INT              NOT NULL,
  886.   active_start_date      INT              NOT NULL,
  887.   active_end_date        INT              NOT NULL,
  888.   active_start_time      INT              NOT NULL,
  889.   active_end_time        INT              NOT NULL,
  890.   next_run_date          INT              NOT NULL,
  891.   next_run_time          INT              NOT NULL,
  892.   date_created           DATETIME         NOT NULL
  893.   )
  894.  
  895.   EXECUTE sp_bindefault default_current_date, N'sysjobschedules.date_created'
  896.  
  897.   CREATE UNIQUE CLUSTERED INDEX clust ON sysjobschedules(job_id, name)
  898.   CREATE UNIQUE NONCLUSTERED INDEX nc1 ON sysjobschedules(schedule_id)
  899. END
  900. go
  901.  
  902. /**************************************************************/
  903. /* SYSCATEGORIES                                              */
  904. /**************************************************************/
  905.  
  906. IF (NOT EXISTS (SELECT *
  907.                 FROM msdb.dbo.sysobjects
  908.                 WHERE (name = N'syscategories')
  909.                   AND (type = 'U')))
  910. BEGIN
  911.   PRINT ''
  912.   PRINT 'Creating table syscategories...'
  913.  
  914.   CREATE TABLE syscategories
  915.   (
  916.   category_id    INT IDENTITY NOT NULL,
  917.   category_class INT          NOT NULL, -- 1 = Job, 2 = Alert, 3 = Operator
  918.   category_type  TINYINT      NOT NULL, -- 1 = Local, 2 = Multi-Server [Only relevant if class is 1; otherwise, 3 (None)]
  919.   name           sysname      NOT NULL
  920.   )
  921.  
  922.   CREATE UNIQUE CLUSTERED INDEX clust ON syscategories(name, category_class)
  923. END
  924. go
  925.  
  926. -- Install standard [permanent] categories (reserved ID range is 0 - 99)
  927. SET IDENTITY_INSERT msdb.dbo.syscategories ON
  928.  
  929. DELETE FROM msdb.dbo.syscategories
  930. WHERE (category_id < 100)
  931.  
  932. -- Core categories
  933. INSERT INTO msdb.dbo.syscategories (category_id, category_class, category_type, name) VALUES ( 0, 1, 1, N'[Uncategorized (Local)]')        -- Local default
  934. 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
  935. INSERT INTO msdb.dbo.syscategories (category_id, category_class, category_type, name) VALUES ( 2, 1, 2, N'[Uncategorized (Multi-Server)]') -- Multi-server default
  936. 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
  937. 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
  938. 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
  939. INSERT INTO msdb.dbo.syscategories (category_id, category_class, category_type, name) VALUES (98, 2, 3, N'[Uncategorized]')                -- Alert default
  940. INSERT INTO msdb.dbo.syscategories (category_id, category_class, category_type, name) VALUES (99, 3, 3, N'[Uncategorized]')                -- Operator default
  941.  
  942. -- Replication categories
  943. INSERT INTO msdb.dbo.syscategories (category_id, category_class, category_type, name) VALUES (10, 1, 1, N'REPL-Distribution')
  944. INSERT INTO msdb.dbo.syscategories (category_id, category_class, category_type, name) VALUES (11, 1, 1, N'REPL-Distribution Cleanup')
  945. INSERT INTO msdb.dbo.syscategories (category_id, category_class, category_type, name) VALUES (12, 1, 1, N'REPL-History Cleanup')
  946. INSERT INTO msdb.dbo.syscategories (category_id, category_class, category_type, name) VALUES (13, 1, 1, N'REPL-LogReader')
  947. INSERT INTO msdb.dbo.syscategories (category_id, category_class, category_type, name) VALUES (14, 1, 1, N'REPL-Merge')
  948. INSERT INTO msdb.dbo.syscategories (category_id, category_class, category_type, name) VALUES (15, 1, 1, N'REPL-Snapshot')
  949. INSERT INTO msdb.dbo.syscategories (category_id, category_class, category_type, name) VALUES (16, 1, 1, N'REPL-Checkup')
  950. INSERT INTO msdb.dbo.syscategories (category_id, category_class, category_type, name) VALUES (17, 1, 1, N'REPL-Subscription Cleanup')
  951. INSERT INTO msdb.dbo.syscategories (category_id, category_class, category_type, name) VALUES (18, 1, 1, N'REPL-Alert Response')
  952. INSERT INTO msdb.dbo.syscategories (category_id, category_class, category_type, name) VALUES (19, 1, 1, N'REPL-QueueReader')
  953. INSERT INTO msdb.dbo.syscategories (category_id, category_class, category_type, name) VALUES (20, 2, 3, N'Replication')
  954.  
  955. SET IDENTITY_INSERT msdb.dbo.syscategories OFF
  956. go
  957.  
  958. /**************************************************************/
  959. /* SYSTARGETSERVERS                                           */
  960. /**************************************************************/
  961.  
  962. IF (NOT EXISTS (SELECT *
  963.                 FROM msdb.dbo.sysobjects
  964.                 WHERE (name = N'systargetservers')
  965.                   AND (type = 'U')))
  966. BEGIN
  967.   PRINT ''
  968.   PRINT 'Creating table systargetservers...'
  969.  
  970.   CREATE TABLE systargetservers
  971.   (
  972.   server_id               INT IDENTITY  NOT NULL,
  973.   server_name             NVARCHAR(30)  NOT NULL,
  974.   location                NVARCHAR(200) NULL,
  975.   time_zone_adjustment    INT           NOT NULL,  -- The offset from GMT in minutes (set by sp_msx_enlist)
  976.   enlist_date             DATETIME      NOT NULL,
  977.   last_poll_date          DATETIME      NOT NULL,
  978.   status                  INT           NOT NULL,  -- 1 = Normal, 2 = Offline, 4 = Blocked
  979.   local_time_at_last_poll DATETIME      NOT NULL,  -- The local time at the target server as-of the last time it polled the MSX
  980.   enlisted_by_nt_user     NVARCHAR(100) NOT NULL,
  981.   poll_interval           INT           NOT NULL   -- The MSX polling interval (in seconds)
  982.   )
  983.  
  984.   EXECUTE sp_bindefault default_current_date, N'systargetservers.enlist_date'
  985.   EXECUTE sp_bindefault default_current_date, N'systargetservers.last_poll_date'
  986.   EXECUTE sp_bindefault default_one,          N'systargetservers.status'
  987.  
  988.   CREATE UNIQUE CLUSTERED    INDEX clust ON systargetservers(server_id)
  989.   CREATE UNIQUE NONCLUSTERED INDEX nc1   ON systargetservers(server_name)
  990. END
  991. go
  992.  
  993. /**************************************************************/
  994. /* SYSTARGETSERVERS_VIEW                                      */
  995. /**************************************************************/
  996.  
  997. PRINT ''
  998. PRINT 'Creating view systargetservers_view...'
  999. go
  1000. IF (EXISTS (SELECT *
  1001.             FROM msdb.dbo.sysobjects
  1002.             WHERE (name = N'systargetservers_view')
  1003.               AND (type = 'V')))
  1004.   DROP VIEW systargetservers_view
  1005. go
  1006. CREATE VIEW systargetservers_view
  1007. AS
  1008. SELECT server_id,
  1009.        server_name,
  1010.        enlist_date,
  1011.        last_poll_date
  1012. FROM msdb.dbo.systargetservers
  1013. UNION
  1014. SELECT 0,
  1015.        CONVERT(NVARCHAR(30), SERVERPROPERTY('ServerName')),
  1016.        CONVERT(DATETIME, N'19981113', 112),
  1017.        CONVERT(DATETIME, N'19981113', 112)
  1018. go
  1019.  
  1020. /**************************************************************/
  1021. /* SYSTARGETSERVERGROUPS                                      */
  1022. /**************************************************************/
  1023.  
  1024. IF (NOT EXISTS (SELECT *
  1025.                 FROM msdb.dbo.sysobjects
  1026.                 WHERE (name = N'systargetservergroups')
  1027.                   AND (type = 'U')))
  1028. BEGIN
  1029.   PRINT ''
  1030.   PRINT 'Creating table systargetservergroups...'
  1031.  
  1032.   CREATE TABLE systargetservergroups
  1033.   (
  1034.   servergroup_id INT IDENTITY NOT NULL,
  1035.   name           sysname      NOT NULL
  1036.   )
  1037.  
  1038.   CREATE UNIQUE CLUSTERED INDEX clust ON systargetservergroups(name)
  1039. END
  1040. go
  1041.  
  1042. /**************************************************************/
  1043. /* SYSTARGETSERVERGROUPMEMBERS                                */
  1044. /**************************************************************/
  1045.  
  1046. IF (NOT EXISTS (SELECT *
  1047.                 FROM msdb.dbo.sysobjects
  1048.                 WHERE (name = N'systargetservergroupmembers')
  1049.                   AND (type = 'U')))
  1050. BEGIN
  1051.   PRINT ''
  1052.   PRINT 'Creating table systargetservergroupmembers...'
  1053.  
  1054.   CREATE TABLE systargetservergroupmembers
  1055.   (
  1056.   servergroup_id INT NOT NULL,
  1057.   server_id      INT NOT NULL
  1058.   )
  1059.  
  1060.   CREATE UNIQUE CLUSTERED INDEX clust ON systargetservergroupmembers(servergroup_id, server_id)
  1061.   CREATE NONCLUSTERED     INDEX nc1   ON systargetservergroupmembers(server_id)
  1062. END
  1063. go
  1064.  
  1065. /**************************************************************/
  1066. /* SYSALERTS                                                  */
  1067. /**************************************************************/
  1068.  
  1069. IF (NOT EXISTS (SELECT *
  1070.                 FROM msdb.dbo.sysobjects
  1071.                 WHERE (name = N'sysalerts')
  1072.                   AND (type = 'U')))
  1073. BEGIN
  1074.   PRINT ''
  1075.   PRINT 'Creating table sysalerts...'
  1076.  
  1077.   CREATE TABLE sysalerts
  1078.   (
  1079.   id                        INT IDENTITY     NOT NULL,
  1080.   name                      sysname          NOT NULL, -- Was length 60 in 6.x
  1081.   event_source              NVARCHAR(100)    NOT NULL,
  1082.   event_category_id         INT              NULL,
  1083.   event_id                  INT              NULL,
  1084.   message_id                INT              NOT NULL, -- Was NULL in 6.x
  1085.   severity                  INT              NOT NULL, -- Was NULL in 6.x
  1086.   enabled                   TINYINT          NOT NULL,
  1087.   delay_between_responses   INT              NOT NULL,
  1088.   last_occurrence_date      INT              NOT NULL, -- Was NULL in 6.x
  1089.   last_occurrence_time      INT              NOT NULL, -- Was NULL in 6.x
  1090.   last_response_date        INT              NOT NULL, -- Was NULL in 6.x
  1091.   last_response_time        INT              NOT NULL, -- Was NULL in 6.x
  1092.   notification_message      NVARCHAR(512)    NULL,
  1093.   include_event_description TINYINT          NOT NULL,
  1094.   database_name             sysname          NULL,
  1095.   event_description_keyword NVARCHAR(100)    NULL,
  1096.   occurrence_count          INT              NOT NULL,
  1097.   count_reset_date          INT              NOT NULL, -- Was NULL in 6.x
  1098.   count_reset_time          INT              NOT NULL, -- Was NULL in 6.x
  1099.   job_id                    UNIQUEIDENTIFIER NOT NULL, -- Was NULL in 6.x
  1100.   has_notification          INT              NOT NULL, -- New for 7.0
  1101.   flags                     INT              NOT NULL, -- Was NULL in 6.x
  1102.   performance_condition     NVARCHAR(512)    NULL,
  1103.   category_id               INT              NOT NULL  -- New for 7.0
  1104.   )
  1105.  
  1106.   CREATE UNIQUE CLUSTERED INDEX ByName ON sysalerts(name)
  1107.   CREATE UNIQUE INDEX ByID ON sysalerts(id)
  1108. END
  1109. go
  1110.  
  1111. /**************************************************************/
  1112. /* SYSOPERATORS                                               */
  1113. /**************************************************************/
  1114.  
  1115. IF (NOT EXISTS (SELECT *
  1116.                 FROM msdb.dbo.sysobjects
  1117.                 WHERE (name = N'sysoperators')
  1118.                   AND (type = 'U')))
  1119. BEGIN
  1120.   PRINT ''
  1121.   PRINT 'Creating table sysoperators...'
  1122.  
  1123.   CREATE TABLE sysoperators
  1124.   (
  1125.   id                        INT IDENTITY  NOT NULL,
  1126.   name                      sysname       NOT NULL, -- Was length 50 in 6.x
  1127.   enabled                   TINYINT       NOT NULL,
  1128.   email_address             NVARCHAR(100) NULL,
  1129.   last_email_date           INT           NOT NULL, -- Was NULL in 6.x
  1130.   last_email_time           INT           NOT NULL, -- Was NULL in 6.x
  1131.   pager_address             NVARCHAR(100) NULL,
  1132.   last_pager_date           INT           NOT NULL, -- Was NULL in 6.x
  1133.   last_pager_time           INT           NOT NULL, -- Was NULL in 6.x
  1134.   weekday_pager_start_time  INT           NOT NULL,
  1135.   weekday_pager_end_time    INT           NOT NULL,
  1136.   saturday_pager_start_time INT           NOT NULL,
  1137.   saturday_pager_end_time   INT           NOT NULL,
  1138.   sunday_pager_start_time   INT           NOT NULL,
  1139.   sunday_pager_end_time     INT           NOT NULL,
  1140.   pager_days                TINYINT       NOT NULL,
  1141.   netsend_address           NVARCHAR(100) NULL,     -- New for 7.0
  1142.   last_netsend_date         INT           NOT NULL, -- New for 7.0
  1143.   last_netsend_time         INT           NOT NULL, -- New for 7.0
  1144.   category_id               INT           NOT NULL  -- New for 7.0
  1145.   )
  1146.  
  1147.   CREATE UNIQUE CLUSTERED INDEX ByName ON sysoperators(name)
  1148.   CREATE UNIQUE INDEX ByID ON sysoperators(id)
  1149. END
  1150. go
  1151.  
  1152. /**************************************************************/
  1153. /* SYSNOTIFICATIONS                                           */
  1154. /**************************************************************/
  1155.  
  1156. IF (NOT EXISTS (SELECT *
  1157.                 FROM msdb.dbo.sysobjects
  1158.                 WHERE (name = N'sysnotifications')
  1159.                   AND (type = 'U')))
  1160. BEGIN
  1161.   PRINT ''
  1162.   PRINT 'Creating table sysnotifications...'
  1163.  
  1164.   CREATE TABLE sysnotifications
  1165.   (
  1166.   alert_id             INT      NOT NULL,
  1167.   operator_id          INT      NOT NULL,
  1168.   notification_method  TINYINT  NOT NULL
  1169.   )
  1170.  
  1171.   CREATE UNIQUE CLUSTERED INDEX ByAlertIDAndOperatorID ON sysnotifications(alert_id, operator_id)
  1172. END
  1173. go
  1174.  
  1175. /**************************************************************/
  1176. /* SYSTASKIDS                                                 */
  1177. /*                                                            */
  1178. /* This table provides a mapping between new GUID job ID's    */
  1179. /* and 6.x INT task ID's.                                     */
  1180. /* Entries are made in this table for all existing 6.x tasks  */
  1181. /* and for all new tasks added using the 7.0 version of       */
  1182. /* sp_addtask.                                                */
  1183. /* Callers of the 7.0 version of sp_helptask will ONLY see    */
  1184. /* tasks [jobs] that have a corresponding entry in this table */
  1185. /* [IE. Jobs created with sp_add_job will not be returned].   */
  1186. /**************************************************************/
  1187.  
  1188. IF (NOT EXISTS (SELECT *
  1189.                 FROM msdb.dbo.sysobjects
  1190.                 WHERE (name = N'systaskids')
  1191.                   AND (type = 'U')))
  1192. BEGIN
  1193.   CREATE TABLE systaskids
  1194.   (
  1195.   task_id INT IDENTITY     NOT NULL,
  1196.   job_id  UNIQUEIDENTIFIER NOT NULL
  1197.   )
  1198.  
  1199.   CREATE CLUSTERED INDEX clust ON systaskids(job_id)
  1200. END
  1201. go
  1202.  
  1203. /**************************************************************/
  1204. /* SYSCACHEDCREDENTIALS                                       */
  1205. /*                                                            */
  1206. /**************************************************************/
  1207.  
  1208. IF (NOT EXISTS (SELECT *
  1209.                 FROM msdb.dbo.sysobjects
  1210.                 WHERE (name = N'syscachedcredentials')
  1211.                   AND (type = 'U')))
  1212. BEGIN
  1213.   CREATE TABLE syscachedcredentials
  1214.   (
  1215.   login_name          sysname      COLLATE database_default NOT NULL PRIMARY KEY,
  1216.   has_server_access   BIT          NOT NULL DEFAULT 0,
  1217.   is_sysadmin_member  BIT          NOT NULL DEFAULT 0,
  1218.   cachedate           DATETIME     NOT NULL DEFAULT getdate()
  1219.   )
  1220. END
  1221. go
  1222.  
  1223. DUMP TRANSACTION msdb WITH NO_LOG
  1224. go
  1225. CHECKPOINT
  1226. go
  1227.  
  1228. /**************************************************************/
  1229. /*                                                            */
  1230. /*        C  O  R  E     P  R  O  C  E  D  U  R  E  S         */
  1231. /*                                                            */
  1232. /**************************************************************/
  1233.  
  1234. /**************************************************************/
  1235. /* SP_SQLAGENT_GET_STARTUP_INFO                               */
  1236. /**************************************************************/
  1237.  
  1238. PRINT ''
  1239. PRINT 'Creating procedure sp_sqlagent_get_startup_info...'
  1240. go
  1241. IF (EXISTS (SELECT *
  1242.             FROM msdb.dbo.sysobjects
  1243.             WHERE (name = 'sp_sqlagent_get_startup_info')
  1244.               AND (type = 'P')))
  1245.   DROP PROCEDURE sp_sqlagent_get_startup_info
  1246. go
  1247. CREATE PROCEDURE sp_sqlagent_get_startup_info
  1248. AS
  1249. BEGIN
  1250.   DECLARE @tbu INT
  1251.  
  1252.   SET NOCOUNT ON
  1253.  
  1254.   IF (ServerProperty('InstanceName') IS NULL)
  1255.   BEGIN
  1256.     EXECUTE @tbu = master.dbo.xp_qv '1338198028'
  1257.   END
  1258.   ELSE
  1259.   BEGIN
  1260.     DECLARE @instancename NVARCHAR(128)
  1261.     SELECT @instancename = CONVERT(NVARCHAR(128), ServerProperty('InstanceName'))
  1262.     EXECUTE @tbu = master.dbo.xp_qv '1338198028', @instancename
  1263.   END
  1264.  
  1265.   IF (@tbu < 0)
  1266.     SELECT @tbu = 0
  1267.  
  1268.   SELECT 'msdb_70_compatible' = (SELECT CASE WHEN cmptlevel >= 70 THEN 1 ELSE 0 END FROM master.dbo.sysdatabases WHERE (name = 'msdb')),
  1269.          'msdb_read_only' = DATABASEPROPERTY('msdb', 'IsReadOnly'),
  1270.          'msdb_available' = CASE ISNULL(DATABASEPROPERTY('msdb', 'IsSingleUser'), 0) WHEN 0 THEN 1 ELSE 0 END &
  1271.                             CASE ISNULL(DATABASEPROPERTY('msdb', 'IsDboOnly'), 0) WHEN 0 THEN 1 ELSE 0 END &
  1272.                             CASE ISNULL(DATABASEPROPERTY('msdb', 'IsNotRecovered'), 0) WHEN 0 THEN 1 ELSE 0 END &
  1273.                             CASE ISNULL(DATABASEPROPERTY('msdb', 'IsSuspect'), 0) WHEN 0 THEN 1 ELSE 0 END,
  1274.          'case_sensitive_server' = CASE ISNULL((SELECT 1 WHERE 'a' = 'A'), 0)
  1275.                                      WHEN 1 THEN 0
  1276.                                      ELSE 1
  1277.                                    END,
  1278.          'max_user_connection' = (SELECT value FROM master.dbo.syscurconfigs WHERE (config = 103)),
  1279.          'sql_server_name' = CONVERT(sysname, SERVERPROPERTY('SERVERNAME')),
  1280.          'tbu' = ISNULL(@tbu, 0),
  1281.          'platform' = PLATFORM(),
  1282.          'instance_name' = ISNULL(CONVERT(sysname, SERVERPROPERTY('INSTANCENAME')), 'MSSQLSERVER'),
  1283.          'is_clustered' = CONVERT(INT, SERVERPROPERTY('ISCLUSTERED'))
  1284.  
  1285.   RETURN(0) -- Success
  1286. END
  1287. go
  1288.  
  1289. /**************************************************************/
  1290. /* SP_SQLAGENT_HAS_SERVER_ACCESS                              */
  1291. /**************************************************************/
  1292.  
  1293. PRINT ''
  1294. PRINT 'Creating procedure sp_sqlagent_has_server_access...'
  1295. go
  1296. IF (EXISTS (SELECT *
  1297.             FROM msdb.dbo.sysobjects
  1298.             WHERE (name = 'sp_sqlagent_has_server_access')
  1299.               AND (type = 'P')))
  1300.   DROP PROCEDURE sp_sqlagent_has_server_access
  1301. go
  1302. CREATE PROCEDURE sp_sqlagent_has_server_access
  1303.   @login_name         sysname = NULL,
  1304.   @is_sysadmin_member INT     = NULL OUTPUT
  1305. AS
  1306. BEGIN
  1307.   DECLARE @has_server_access BIT
  1308.   DECLARE @is_sysadmin       BIT
  1309.   DECLARE @actual_login_name sysname
  1310.   DECLARE @cachedate         DATETIME
  1311.  
  1312.   SET NOCOUNT ON
  1313.  
  1314.   SELECT @cachedate = NULL
  1315.  
  1316.   -- remove expired entries from the cache
  1317.   DELETE msdb.dbo.syscachedcredentials
  1318.   WHERE  DATEDIFF(MINUTE, cachedate, GETDATE()) >= 29
  1319.  
  1320.   -- query the cache
  1321.   SELECT  @is_sysadmin = is_sysadmin_member,
  1322.           @has_server_access = has_server_access,
  1323.           @cachedate = cachedate
  1324.   FROM    msdb.dbo.syscachedcredentials
  1325.   WHERE   login_name = @login_name
  1326.   AND     DATEDIFF(MINUTE, cachedate, GETDATE()) < 29
  1327.  
  1328.   IF (@cachedate IS NOT NULL)
  1329.   BEGIN
  1330.     -- no output variable
  1331.     IF (@is_sysadmin_member IS NULL)
  1332.     BEGIN
  1333.       -- Return result row
  1334.       SELECT has_server_access = @has_server_access,
  1335.              is_sysadmin       = @is_sysadmin,
  1336.              actual_login_name = @login_name
  1337.       RETURN
  1338.     END
  1339.     ELSE
  1340.     BEGIN
  1341.       SELECT @is_sysadmin_member = @is_sysadmin
  1342.       RETURN
  1343.     END
  1344.   END -- select from cache
  1345.  
  1346.   CREATE TABLE #xp_results
  1347.   (
  1348.   account_name      sysname      COLLATE database_default NOT NULL PRIMARY KEY,
  1349.   type              NVARCHAR(10) COLLATE database_default NOT NULL,
  1350.   privilege         NVARCHAR(10) COLLATE database_default NOT NULL,
  1351.   mapped_login_name sysname      COLLATE database_default NOT NULL,
  1352.   permission_path   sysname      COLLATE database_default NULL
  1353.   )
  1354.  
  1355.   -- Set defaults
  1356.   SELECT @has_server_access = 0
  1357.   SELECT @is_sysadmin = 0
  1358.   SELECT @actual_login_name = FORMATMESSAGE(14205)
  1359.  
  1360.   IF (@login_name IS NULL)
  1361.   BEGIN
  1362.     SELECT has_server_access = 1,
  1363.            is_sysadmin       = IS_SRVROLEMEMBER(N'sysadmin'),
  1364.            actual_login_name = SUSER_SNAME()
  1365.     RETURN
  1366.   END
  1367.  
  1368.   IF (@login_name LIKE '%\%')
  1369.   BEGIN
  1370.     -- Handle the LocalSystem account ('NT AUTHORITY\SYSTEM') as a special case
  1371.     IF (UPPER(@login_name) = N'NT AUTHORITY\SYSTEM')
  1372.     BEGIN
  1373.       IF (EXISTS (SELECT *
  1374.                   FROM master.dbo.syslogins
  1375.                   WHERE (UPPER(loginname) = N'BUILTIN\ADMINISTRATORS')))
  1376.       BEGIN
  1377.         SELECT @has_server_access = hasaccess,
  1378.                @is_sysadmin = sysadmin,
  1379.                @actual_login_name = loginname
  1380.         FROM master.dbo.syslogins
  1381.         WHERE (UPPER(loginname) = N'BUILTIN\ADMINISTRATORS')
  1382.       END
  1383.     END
  1384.     ELSE
  1385.     BEGIN
  1386.       -- Check if the NT login has been explicitly denied access
  1387.       IF (EXISTS (SELECT *
  1388.                   FROM master.dbo.syslogins
  1389.                   WHERE (loginname = @login_name)
  1390.                     AND (denylogin = 1)))
  1391.       BEGIN
  1392.         SELECT @has_server_access = 0,
  1393.                @is_sysadmin = sysadmin,
  1394.                @actual_login_name = loginname
  1395.         FROM master.dbo.syslogins
  1396.         WHERE (loginname = @login_name)
  1397.       END
  1398.       ELSE
  1399.       BEGIN
  1400.         -- Call xp_logininfo to determine server access
  1401.         INSERT INTO #xp_results
  1402.         EXECUTE master.dbo.xp_logininfo @login_name
  1403.  
  1404.         SELECT @has_server_access = CASE COUNT(*)
  1405.                                       WHEN 0 THEN 0
  1406.                                       ELSE 1
  1407.                                     END
  1408.         FROM #xp_results
  1409.         SELECT @actual_login_name = mapped_login_name,
  1410.                @is_sysadmin = CASE UPPER(privilege)
  1411.                                 WHEN 'ADMIN' THEN 1
  1412.                                 ELSE 0
  1413.                              END
  1414.         FROM #xp_results
  1415.       END
  1416.     END
  1417.   END
  1418.   ELSE
  1419.   BEGIN
  1420.     -- Standard login
  1421.     IF (EXISTS (SELECT *
  1422.                 FROM master.dbo.syslogins
  1423.                 WHERE (loginname = @login_name)))
  1424.     BEGIN
  1425.       SELECT @has_server_access = hasaccess,
  1426.              @is_sysadmin = sysadmin,
  1427.              @actual_login_name = loginname
  1428.       FROM master.dbo.syslogins
  1429.       WHERE (loginname = @login_name)
  1430.     END
  1431.   END
  1432.  
  1433.   -- update the cache only if something is found
  1434.   IF  (UPPER(@actual_login_name) <> '(UNKNOWN)')
  1435.   BEGIN
  1436.     IF EXISTS (SELECT * FROM msdb.dbo.syscachedcredentials WHERE login_name = @login_name)
  1437.     BEGIN
  1438.       UPDATE msdb.dbo.syscachedcredentials
  1439.       SET    has_server_access = @has_server_access,
  1440.              is_sysadmin_member = @is_sysadmin,
  1441.              cachedate = GETDATE()
  1442.       WHERE  login_name = @login_name
  1443.     END
  1444.     ELSE
  1445.     BEGIN
  1446.       INSERT INTO msdb.dbo.syscachedcredentials(login_name, has_server_access, is_sysadmin_member) 
  1447.       VALUES(@login_name, @has_server_access, @is_sysadmin)
  1448.     END
  1449.   END
  1450.  
  1451.   IF (@is_sysadmin_member IS NULL)
  1452.     -- Return result row
  1453.     SELECT has_server_access = @has_server_access,
  1454.            is_sysadmin       = @is_sysadmin,
  1455.            actual_login_name = @actual_login_name
  1456.   ELSE
  1457.     -- output variable only
  1458.     SELECT @is_sysadmin_member = @is_sysadmin
  1459. END
  1460. go
  1461.  
  1462. /**************************************************************/
  1463. /* SP_SEM_ADD_MESSAGE [used by SEM only]                      */
  1464. /**************************************************************/
  1465.  
  1466. PRINT ''
  1467. PRINT 'Creating procedure sp_sem_add_message...'
  1468. go
  1469. IF (EXISTS (SELECT *
  1470.             FROM msdb.dbo.sysobjects
  1471.             WHERE (name = 'sp_sem_add_message')
  1472.               AND (type = 'P')))
  1473.   DROP PROCEDURE sp_sem_add_message
  1474. go
  1475. CREATE PROCEDURE sp_sem_add_message
  1476.   @msgnum   INT           = NULL,
  1477.   @severity SMALLINT      = NULL,
  1478.   @msgtext  NVARCHAR(255) = NULL,
  1479.   @lang     sysname       = NULL, -- Message language name
  1480.   @with_log VARCHAR(5)    = 'FALSE',
  1481.   @replace  VARCHAR(7)    = NULL
  1482. AS
  1483. BEGIN
  1484.   DECLARE @retval        INT
  1485.   DECLARE @language_name sysname
  1486.  
  1487.   SET NOCOUNT ON
  1488.  
  1489.   SET ROWCOUNT 1
  1490.   SELECT @language_name = name
  1491.   FROM master.dbo.syslanguages
  1492.   WHERE msglangid = (SELECT number
  1493.                      FROM master.dbo.spt_values
  1494.                      WHERE (type = 'LNG')
  1495.                        AND (name = @lang))
  1496.   SET ROWCOUNT 0
  1497.  
  1498.   SELECT @language_name = ISNULL(@language_name, 'us_english')
  1499.   EXECUTE @retval = master.dbo.sp_addmessage @msgnum, @severity, @msgtext, @language_name, @with_log, @replace
  1500.   RETURN(@retval)
  1501. END
  1502. go
  1503.  
  1504. /**************************************************************/
  1505. /* SP_SEM_DROP_MESSAGE [used by SEM only]                     */
  1506. /**************************************************************/
  1507.  
  1508. PRINT ''
  1509. PRINT 'Creating procedure sp_sem_drop_message...'
  1510. go
  1511. IF (EXISTS (SELECT *
  1512.             FROM msdb.dbo.sysobjects
  1513.             WHERE (name = 'sp_sem_drop_message')
  1514.               AND (type = 'P')))
  1515.   DROP PROCEDURE sp_sem_drop_message
  1516. go
  1517. CREATE PROCEDURE sp_sem_drop_message
  1518.   @msgnum int     = NULL,
  1519.   @lang   sysname = NULL -- Message language name
  1520. AS
  1521. BEGIN
  1522.   DECLARE @retval        INT
  1523.   DECLARE @language_name sysname
  1524.  
  1525.   SET NOCOUNT ON
  1526.  
  1527.   SET ROWCOUNT 1
  1528.   SELECT @language_name = name
  1529.   FROM master.dbo.syslanguages
  1530.   WHERE msglangid = (SELECT number
  1531.                      FROM master.dbo.spt_values
  1532.                      WHERE (type = 'LNG')
  1533.                        AND (name = @lang))
  1534.   SET ROWCOUNT 0
  1535.  
  1536.   SELECT @language_name = ISNULL(@language_name, 'us_english')
  1537.   EXECUTE @retval = master.dbo.sp_dropmessage @msgnum, @language_name
  1538.   RETURN(@retval)
  1539. END
  1540. go
  1541.  
  1542. /**************************************************************/
  1543. /* SP_GET_MESSAGE_DESCRIPTION [used by SEM only]              */
  1544. /**************************************************************/
  1545.  
  1546. PRINT ''
  1547. PRINT 'Creating procedure sp_get_message_description...'
  1548. go
  1549. IF (EXISTS (SELECT *
  1550.             FROM msdb.dbo.sysobjects
  1551.             WHERE (name = 'sp_get_message_description')
  1552.               AND (type = 'P')))
  1553.   DROP PROCEDURE sp_get_message_description
  1554. go
  1555. CREATE PROCEDURE sp_get_message_description
  1556.   @error INT
  1557. AS
  1558. BEGIN
  1559.   IF EXISTS (SELECT * FROM master.dbo.sysmessages WHERE (error = @error) AND (msglangid = (SELECT msglangid FROM master.dbo.syslanguages WHERE (langid = @@langid))))
  1560.     SELECT description FROM master.dbo.sysmessages WHERE (error = @error) AND (msglangid = (SELECT msglangid FROM master.dbo.syslanguages WHERE (langid = @@langid)))
  1561.   ELSE
  1562.     SELECT description FROM master.dbo.sysmessages WHERE (error = @error) AND (msglangid = 1033)
  1563. END
  1564. go
  1565.  
  1566. /**************************************************************/
  1567. /* SP_SQLAGENT_GET_PERF_COUNTERS                              */
  1568. /**************************************************************/
  1569.  
  1570. PRINT ''
  1571. PRINT 'Creating procedure sp_sqlagent_get_perf_counters...'
  1572. go
  1573. IF (EXISTS (SELECT *
  1574.             FROM msdb.dbo.sysobjects
  1575.             WHERE (name = N'sp_sqlagent_get_perf_counters')
  1576.               AND (type = 'P')))
  1577.   DROP PROCEDURE sp_sqlagent_get_perf_counters
  1578. go
  1579. CREATE PROCEDURE sp_sqlagent_get_perf_counters
  1580.   @all_counters BIT = 0
  1581. AS
  1582. BEGIN
  1583.   SET NOCOUNT ON
  1584.  
  1585.   CREATE TABLE #temp
  1586.   (
  1587.   performance_condition NVARCHAR(1024) COLLATE database_default NOT NULL
  1588.   )
  1589.  
  1590.   INSERT INTO #temp VALUES (N'dummy')
  1591.  
  1592.   IF (@all_counters = 0)
  1593.   BEGIN
  1594.     INSERT INTO #temp
  1595.     SELECT DISTINCT SUBSTRING(performance_condition, 1, CHARINDEX('|', performance_condition, PATINDEX('%[_|_]%', performance_condition) + 1) - 1)
  1596.     FROM msdb.dbo.sysalerts
  1597.     WHERE (performance_condition IS NOT NULL)
  1598.       AND (enabled = 1)
  1599.   END
  1600.  
  1601.   SELECT 'object_name' = RTRIM(SUBSTRING(spi1.object_name, 1, 50)),
  1602.          'counter_name' = RTRIM(SUBSTRING(spi1.counter_name, 1, 50)),
  1603.          'instance_name' = CASE spi1.instance_name
  1604.                              WHEN N'' THEN NULL
  1605.                              ELSE RTRIM(spi1.instance_name)
  1606.                            END,
  1607.          'value' = CASE spi1.cntr_type
  1608.                      WHEN 537003008 -- A ratio
  1609.                        THEN CONVERT(FLOAT, spi1.cntr_value) / (SELECT CASE spi2.cntr_value WHEN 0 THEN 1 ELSE spi2.cntr_value END
  1610.                                                                FROM master.dbo.sysperfinfo spi2
  1611.                                                                WHERE (spi1.counter_name + ' ' = SUBSTRING(spi2.counter_name, 1, PATINDEX('% Base%', spi2.counter_name)))
  1612.                                                                  AND (spi1.instance_name = spi2.instance_name)
  1613.                                                                  AND (spi2.cntr_type = 1073939459))
  1614.                      ELSE spi1.cntr_value
  1615.                    END
  1616.   FROM master.dbo.sysperfinfo spi1,
  1617.        #temp tmp
  1618.   WHERE (spi1.cntr_type <> 1073939459) -- Divisors
  1619.     AND ((@all_counters = 1) OR
  1620.          (tmp.performance_condition = RTRIM(spi1.object_name) + '|' + RTRIM(spi1.counter_name)))
  1621. END
  1622. go
  1623.  
  1624.  
  1625. /**************************************************************/
  1626. /* SP_SQLAGENT_NOTIFY                                         */
  1627. /*                                                            */
  1628. /* NOTE: We define this procedure here instead of in the      */
  1629. /*      'Support procedures' section because of the many      */
  1630. /*       other procedures that reference it.                  */
  1631. /**************************************************************/
  1632.  
  1633. PRINT ''
  1634. PRINT 'Creating procedure sp_sqlagent_notify...'
  1635. go
  1636.  
  1637. IF (EXISTS (SELECT *
  1638.             FROM msdb.dbo.sysobjects
  1639.             WHERE (name = N'sp_sqlagent_notify')
  1640.               AND (type = 'P')))
  1641.   DROP PROCEDURE sp_sqlagent_notify
  1642. go
  1643. CREATE PROCEDURE sp_sqlagent_notify
  1644.   @op_type     NCHAR(1),                -- One of: J (Job action [refresh or start/stop]),
  1645.                                         --         S (Schedule action [refresh only])
  1646.                                         --         A (Alert action [refresh only]),
  1647.                                         --         G (Re-cache all registry settings),
  1648.                                         --         D (Dump job [or job schedule] cache to errorlog)
  1649.                                         --         P (Force an immediate poll of the MSX)
  1650.   @job_id      UNIQUEIDENTIFIER = NULL, -- JobID (for OpTypes 'J', 'S' and 'D')
  1651.   @schedule_id INT              = NULL, -- ScheduleID (for OpType 'S')
  1652.   @alert_id    INT              = NULL, -- AlertID (for OpType 'A')
  1653.   @action_type NCHAR(1)         = NULL, -- For 'J' one of: R (Run - no service check),
  1654.                                         --                 S (Start - with service check),
  1655.                                         --                 I (Insert),
  1656.                                         --                 U (Update),
  1657.                                         --                 D (Delete),
  1658.                                         --                 C (Stop [Cancel])
  1659.                                         -- For 'S' or 'A' one of: I (Insert),
  1660.                                         --                        U (Update),
  1661.                                         --                        D (Delete)
  1662.   @error_flag  INT              = 1     -- Set to 0 to suppress the error from xp_sqlagent_notify if SQLServer agent is not running
  1663. AS
  1664. BEGIN
  1665.   DECLARE @retval         INT
  1666.   DECLARE @id_as_char     VARCHAR(10)
  1667.   DECLARE @job_id_as_char VARCHAR(36)
  1668.   DECLARE @nt_user_name   NVARCHAR(100)
  1669.  
  1670.   SET NOCOUNT ON
  1671.  
  1672.   SELECT @retval = 0 -- Success
  1673.  
  1674.   -- Make sure that we're dealing only with uppercase characters
  1675.   SELECT @op_type     = UPPER(@op_type)
  1676.   SELECT @action_type = UPPER(@action_type)
  1677.  
  1678.   -- Verify operation code
  1679.   IF (CHARINDEX(@op_type, N'JSAGDP') = 0)
  1680.   BEGIN
  1681.     RAISERROR(14266, -1, -1, '@op_type', 'J, S, A, G, D, P')
  1682.     RETURN(1) -- Failure
  1683.   END
  1684.  
  1685.   -- Check the job id for those who use it
  1686.   IF (CHARINDEX(@op_type, N'JSD') <> 0)
  1687.   BEGIN
  1688.     IF (NOT ((@op_type = N'D') AND (@job_id IS NULL))) -- For 'D', job_id is optional
  1689.     BEGIN
  1690.       IF ((@job_id IS NULL) OR
  1691.           ((@action_type <> N'D') AND NOT EXISTS (SELECT *
  1692.                                                   FROM msdb.dbo.sysjobs_view
  1693.                                                   WHERE (job_id = @job_id))))
  1694.       BEGIN
  1695.         SELECT @job_id_as_char = CONVERT(VARCHAR(36), @job_id)
  1696.         RAISERROR(14262, -1, -1, '@job_id', @job_id_as_char)
  1697.         RETURN(1) -- Failure
  1698.       END
  1699.     END
  1700.   END
  1701.  
  1702.   -- Verify 'job' action parameters
  1703.   IF (@op_type = N'J')
  1704.   BEGIN
  1705.     SELECT @alert_id = 0
  1706.     IF (@schedule_id IS NULL) SELECT @schedule_id = 0
  1707.  
  1708.     -- The schedule_id (if specified) is the start step
  1709.     IF ((CHARINDEX(@action_type, N'RS') <> 0) AND (@schedule_id <> 0))
  1710.     BEGIN
  1711.       IF (NOT EXISTS (SELECT *
  1712.                       FROM msdb.dbo.sysjobsteps
  1713.                       WHERE (job_id = @job_id)
  1714.                         AND (step_id = @schedule_id)))
  1715.       BEGIN
  1716.         SELECT @id_as_char = ISNULL(CONVERT(VARCHAR, @schedule_id), '(null)')
  1717.         RAISERROR(14262, -1, -1, '@schedule_id', @id_as_char)
  1718.         RETURN(1) -- Failure
  1719.       END
  1720.     END
  1721.     ELSE
  1722.       SELECT @schedule_id = 0
  1723.  
  1724.     IF (CHARINDEX(@action_type, N'RSIUDC') = 0)
  1725.     BEGIN
  1726.       RAISERROR(14266, -1, -1, '@action_type', 'R, S, I, U, D, C')
  1727.       RETURN(1) -- Failure
  1728.     END
  1729.   END
  1730.  
  1731.   -- Verify 'schedule' action parameters
  1732.   IF (@op_type = N'S')
  1733.   BEGIN
  1734.     SELECT @alert_id = 0
  1735.  
  1736.     IF (CHARINDEX(@action_type, N'IUD') = 0)
  1737.     BEGIN
  1738.       RAISERROR(14266, -1, -1, '@action_type', 'I, U, D')
  1739.       RETURN(1) -- Failure
  1740.     END
  1741.  
  1742.     IF ((@schedule_id IS NULL) OR
  1743.         ((@action_type <> N'D') AND NOT EXISTS (SELECT *
  1744.                                                 FROM msdb.dbo.sysjobschedules
  1745.                                                 WHERE (schedule_id = @schedule_id))))
  1746.     BEGIN
  1747.       SELECT @id_as_char = ISNULL(CONVERT(VARCHAR, @schedule_id), '(null)')
  1748.       RAISERROR(14262, -1, -1, '@schedule_id', @id_as_char)
  1749.       RETURN(1) -- Failure
  1750.     END
  1751.   END
  1752.  
  1753.   -- Verify 'alert' action parameters
  1754.   IF (@op_type = N'A')
  1755.   BEGIN
  1756.     SELECT @job_id = 0x00
  1757.     SELECT @schedule_id = 0
  1758.  
  1759.     IF (CHARINDEX(@action_type, N'IUD') = 0)
  1760.     BEGIN
  1761.       RAISERROR(14266, -1, -1, '@action_type', 'I, U, D')
  1762.       RETURN(1) -- Failure
  1763.     END
  1764.  
  1765.     IF ((@alert_id IS NULL) OR
  1766.         ((@action_type <> N'D') AND NOT EXISTS (SELECT *
  1767.                                                 FROM msdb.dbo.sysalerts
  1768.                                                 WHERE (id = @alert_id))))
  1769.     BEGIN
  1770.       SELECT @id_as_char = ISNULL(CONVERT(VARCHAR, @alert_id), '(null)')
  1771.       RAISERROR(14262, -1, -1, '@alert_id', @id_as_char)
  1772.       RETURN(1) -- Failure
  1773.     END
  1774.   END
  1775.  
  1776.   -- Verify 'registry', 'job dump' and 'force MSX poll' action parameters
  1777.   IF (CHARINDEX(@op_type, N'GDP') <> 0)
  1778.   BEGIN
  1779.     IF (@op_type <> N'D')
  1780.       SELECT @job_id = 0x00
  1781.     SELECT @alert_id = 0
  1782.     SELECT @schedule_id = 0
  1783.     SELECT @action_type = NULL
  1784.   END
  1785.  
  1786.   -- Parameters are valid, so now check execution permissions...
  1787.  
  1788.   -- For anything except a job (or schedule) action the caller must be SysAdmin, DBO, or DB_Owner
  1789.   IF (@op_type NOT IN (N'J', N'S'))
  1790.   BEGIN
  1791.     IF NOT ((ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) = 1) OR
  1792.             (ISNULL(IS_MEMBER(N'db_owner'), 0) = 1) OR
  1793.             (UPPER(USER_NAME()) = N'DBO'))
  1794.     BEGIN
  1795.       RAISERROR(14260, -1, -1)
  1796.       RETURN(1) -- Failure
  1797.     END
  1798.   END
  1799.  
  1800.   -- For a Job Action the caller must be SysAdmin, DBO, DB_Owner, or the job owner
  1801.   IF (@op_type = N'J')
  1802.   BEGIN
  1803.     IF NOT ((ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) = 1) OR
  1804.             (ISNULL(IS_MEMBER(N'db_owner'), 0) = 1) OR
  1805.             (UPPER(USER_NAME()) = N'DBO') OR
  1806.             (EXISTS (SELECT *
  1807.                      FROM msdb.dbo.sysjobs_view
  1808.                      WHERE (job_id = @job_id))))
  1809.     BEGIN
  1810.       RAISERROR(14252, -1, -1)
  1811.       RETURN(1) -- Failure
  1812.     END
  1813.   END
  1814.  
  1815.   -- Ok, let's do it...
  1816.   SELECT @nt_user_name = ISNULL(NT_CLIENT(), ISNULL(SUSER_SNAME(), FORMATMESSAGE(14205)))
  1817.   EXECUTE @retval = master.dbo.xp_sqlagent_notify @op_type, @job_id, @schedule_id, @alert_id, @action_type, @nt_user_name, @error_flag, @@trancount
  1818.  
  1819.   RETURN(@retval)
  1820. END
  1821. go
  1822.  
  1823. /**************************************************************/
  1824. /* SP_IS_SQLAGENT_STARTING                                    */
  1825. /**************************************************************/
  1826.  
  1827. PRINT ''
  1828. PRINT 'Creating procedure sp_is_sqlagent_starting...'
  1829. go
  1830. IF (EXISTS (SELECT *
  1831.             FROM msdb.dbo.sysobjects
  1832.             WHERE (name = N'sp_is_sqlagent_starting')
  1833.               AND (type = 'P')))
  1834.   DROP PROCEDURE sp_is_sqlagent_starting
  1835. go
  1836. CREATE PROCEDURE sp_is_sqlagent_starting
  1837. AS
  1838. BEGIN
  1839.   DECLARE @retval INT
  1840.  
  1841.   SELECT @retval = 0
  1842.   EXECUTE master.dbo.xp_sqlagent_is_starting @retval OUTPUT
  1843.   IF (@retval = 1)
  1844.     RAISERROR(14258, -1, -1)
  1845.  
  1846.   RETURN(@retval)
  1847. END
  1848. go
  1849.  
  1850. /**************************************************************/
  1851. /* SP_VERIFY_JOB_IDENTIFIERS                                  */
  1852. /*                                                            */
  1853. /* NOTE: We define this procedure here instead of in the      */
  1854. /*      'Support procedures' section because of the many      */
  1855. /*       other procedures that reference it.                  */
  1856. /**************************************************************/
  1857.  
  1858. PRINT ''
  1859. PRINT 'Creating procedure sp_verify_job_identifiers...'
  1860. go
  1861. IF (EXISTS (SELECT *
  1862.             FROM msdb.dbo.sysobjects
  1863.             WHERE (name = N'sp_verify_job_identifiers')
  1864.               AND (type = 'P')))
  1865.   DROP PROCEDURE sp_verify_job_identifiers
  1866. go
  1867. CREATE PROCEDURE sp_verify_job_identifiers
  1868.   @name_of_name_parameter  VARCHAR(60),             -- Eg. '@job_name'
  1869.   @name_of_id_parameter    VARCHAR(60),             -- Eg. '@job_id'
  1870.   @job_name                sysname          OUTPUT, -- Eg. 'My Job'
  1871.   @job_id                  UNIQUEIDENTIFIER OUTPUT,
  1872.   @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)
  1873. AS
  1874. BEGIN
  1875.   DECLARE @retval         INT
  1876.   DECLARE @job_id_as_char VARCHAR(36)
  1877.  
  1878.   SET NOCOUNT ON
  1879.  
  1880.   -- Remove any leading/trailing spaces from parameters
  1881.   SELECT @name_of_name_parameter = LTRIM(RTRIM(@name_of_name_parameter))
  1882.   SELECT @name_of_id_parameter   = LTRIM(RTRIM(@name_of_id_parameter))
  1883.   SELECT @job_name               = LTRIM(RTRIM(@job_name))
  1884.  
  1885.   IF (@job_name = N'') SELECT @job_name = NULL
  1886.  
  1887.   IF ((@job_name IS NULL)     AND (@job_id IS NULL)) OR
  1888.      ((@job_name IS NOT NULL) AND (@job_id IS NOT NULL))
  1889.   BEGIN
  1890.     RAISERROR(14294, -1, -1, @name_of_id_parameter, @name_of_name_parameter)
  1891.     RETURN(1) -- Failure
  1892.   END
  1893.  
  1894.   -- Check job id
  1895.   IF (@job_id IS NOT NULL)
  1896.   BEGIN
  1897.     SELECT @job_name = name,
  1898.            @job_id = job_id
  1899.     FROM msdb.dbo.sysjobs_view
  1900.     WHERE (job_id = @job_id)
  1901.     IF (@job_name IS NULL)
  1902.     BEGIN
  1903.       SELECT @job_id_as_char = CONVERT(VARCHAR(36), @job_id)
  1904.       RAISERROR(14262, -1, -1, '@job_id', @job_id_as_char)
  1905.       RETURN(1) -- Failure
  1906.     END
  1907.   END
  1908.   ELSE
  1909.   -- Check job name
  1910.   IF (@job_name IS NOT NULL)
  1911.   BEGIN
  1912.     -- Check if the job name is ambiguous
  1913.     IF ((SELECT COUNT(*)
  1914.          FROM msdb.dbo.sysjobs_view
  1915.          WHERE (name = @job_name)) > 1)
  1916.     BEGIN
  1917.       RAISERROR(14293, -1, -1, @job_name, @name_of_id_parameter, @name_of_name_parameter)
  1918.       RETURN(1) -- Failure
  1919.     END
  1920.  
  1921.     -- The name is not ambiguous, so get the corresponding job_id (if the job exists)
  1922.     SELECT @job_id = job_id
  1923.     FROM msdb.dbo.sysjobs_view
  1924.     WHERE (name = @job_name)
  1925.     IF (@job_id IS NULL)
  1926.     BEGIN
  1927.       RAISERROR(14262, -1, -1, '@job_name', @job_name)
  1928.       RETURN(1) -- Failure
  1929.     END
  1930.   END
  1931.  
  1932.   IF (@sqlagent_starting_test = 'TEST')
  1933.   BEGIN
  1934.     -- Finally, check if SQLServerAgent is in the process of starting and if so prevent the
  1935.     -- calling SP from running
  1936.     EXECUTE @retval = msdb.dbo.sp_is_sqlagent_starting
  1937.     IF (@retval <> 0)
  1938.       RETURN(1) -- Failure
  1939.   END
  1940.  
  1941.   RETURN(0) -- Success
  1942. END
  1943. go
  1944.  
  1945. /**************************************************************/
  1946. /* SP_VERIFY_JOBPROC_CALLER                                   */
  1947. /*                                                            */
  1948. /* NOTE: We define this procedure here instead of in the      */
  1949. /*      'Support procedures' section because of the many      */
  1950. /*       other procedures that reference it.                  */
  1951. /**************************************************************/
  1952.  
  1953. PRINT ''
  1954. PRINT 'Creating procedure sp_verify_jobproc_caller...'
  1955. go
  1956. IF (EXISTS (SELECT *
  1957.             FROM msdb.dbo.sysobjects
  1958.             WHERE (name = N'sp_verify_jobproc_caller')
  1959.               AND (type = 'P')))
  1960.   DROP PROCEDURE sp_verify_jobproc_caller
  1961. go
  1962. CREATE PROCEDURE sp_verify_jobproc_caller
  1963.   @job_id       UNIQUEIDENTIFIER,
  1964.   @program_name sysname
  1965. AS
  1966. BEGIN
  1967.   SET NOCOUNT ON
  1968.  
  1969.   -- Remove any leading/trailing spaces from parameters
  1970.   SELECT @program_name = LTRIM(RTRIM(@program_name))
  1971.  
  1972.   IF (EXISTS (SELECT    *
  1973.               FROM      msdb.dbo.sysjobs_view
  1974.               WHERE     (job_id = @job_id)
  1975.               AND       (UPPER(originating_server) <> UPPER(CONVERT(NVARCHAR(30), SERVERPROPERTY('ServerName')))))) 
  1976.               AND       (PROGRAM_NAME() NOT LIKE @program_name)
  1977.   BEGIN
  1978.     RAISERROR(14274, -1, -1)
  1979.     RETURN(1) -- Failure
  1980.   END
  1981.  
  1982.   RETURN(0)
  1983. END
  1984. go
  1985.  
  1986. /**************************************************************/
  1987. /* SP_DOWNLOADED_ROW_LIMITER                                  */
  1988. /**************************************************************/
  1989.  
  1990. PRINT ''
  1991. PRINT 'Creating procedure sp_downloaded_row_limiter...'
  1992. go
  1993. IF (EXISTS (SELECT *
  1994.             FROM msdb.dbo.sysobjects
  1995.             WHERE (name = N'sp_downloaded_row_limiter')
  1996.               AND (type = 'P')))
  1997.   DROP PROCEDURE dbo.sp_downloaded_row_limiter
  1998. go
  1999. CREATE PROCEDURE sp_downloaded_row_limiter
  2000.   @server_name NVARCHAR(30) -- Target server name
  2001. AS
  2002. BEGIN
  2003.   -- This trigger controls how many downloaded (status = 1) sysdownloadlist rows exist
  2004.   -- for any given server.  It does NOT control the absolute number of rows in the table.
  2005.  
  2006.   DECLARE @current_rows_per_server INT
  2007.   DECLARE @max_rows_per_server     INT -- This value comes from the resgistry (DownloadedMaxRows)
  2008.   DECLARE @rows_to_delete          INT
  2009.   DECLARE @rows_to_delete_as_char  VARCHAR(10)
  2010.  
  2011.   SET NOCOUNT ON
  2012.  
  2013.   -- Remove any leading/trailing spaces from parameters
  2014.   SELECT @server_name = LTRIM(RTRIM(@server_name))
  2015.  
  2016.   -- Check the server name (if it's bad we fail silently)
  2017.   IF (@server_name IS NULL) OR
  2018.      (NOT EXISTS (SELECT *
  2019.                   FROM msdb.dbo.sysdownloadlist
  2020.                   WHERE (target_server = @server_name)))
  2021.     RETURN(1) -- Failure
  2022.  
  2023.   SELECT @max_rows_per_server = 0
  2024.  
  2025.   -- Get the max-rows-per-server from the registry
  2026.   EXECUTE master.dbo.xp_instance_regread N'HKEY_LOCAL_MACHINE',
  2027.                                          N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
  2028.                                          N'DownloadedMaxRows',
  2029.                                          @max_rows_per_server OUTPUT,
  2030.                                          N'no_output'
  2031.  
  2032.   -- Check if we are limiting sysdownloadlist rows
  2033.   IF (ISNULL(@max_rows_per_server, -1) = -1)
  2034.     RETURN
  2035.  
  2036.   -- Check that max_rows_per_server is >= 0
  2037.   IF (@max_rows_per_server < -1)
  2038.   BEGIN
  2039.     -- It isn't, so default to 100 rows
  2040.     SELECT @max_rows_per_server = 100
  2041.     EXECUTE master.dbo.xp_instance_regwrite N'HKEY_LOCAL_MACHINE',
  2042.                                             N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
  2043.                                             N'DownloadedMaxRows',
  2044.                                             N'REG_DWORD',
  2045.                                             @max_rows_per_server
  2046.   END
  2047.  
  2048.   -- Get the number of downloaded rows in sysdownloadlist for the target server in question
  2049.   -- NOTE: Determining this [quickly] requires a [non-clustered] index on target_server
  2050.   SELECT @current_rows_per_server = COUNT(*)
  2051.   FROM msdb.dbo.sysdownloadlist
  2052.   WHERE (target_server = @server_name)
  2053.     AND (status = 1)
  2054.  
  2055.   -- Delete the oldest downloaded row(s) for the target server in question if the new row has
  2056.   -- pushed us over the per-server row limit
  2057.   SELECT @rows_to_delete = @current_rows_per_server - @max_rows_per_server
  2058.   SELECT @rows_to_delete_as_char = CONVERT(VARCHAR, @rows_to_delete)
  2059.  
  2060.   IF (@rows_to_delete > 0)
  2061.   BEGIN
  2062.     EXECUTE ('DECLARE @new_oldest_id INT
  2063.               SET NOCOUNT ON
  2064.               SET ROWCOUNT ' + @rows_to_delete_as_char +
  2065.              'SELECT @new_oldest_id = instance_id
  2066.               FROM msdb.dbo.sysdownloadlist
  2067.               WHERE (target_server = N''' + @server_name + ''')' +
  2068.              '  AND (status = 1)
  2069.               ORDER BY instance_id
  2070.               SET ROWCOUNT 0
  2071.               DELETE FROM msdb.dbo.sysdownloadlist
  2072.               WHERE (target_server = N''' + @server_name + ''')' +
  2073.              '  AND (instance_id <= @new_oldest_id)
  2074.                 AND (status = 1)')
  2075.   END
  2076. END
  2077. go
  2078.  
  2079. /**************************************************************/
  2080. /* SP_POST_MSX_OPERATION                                      */
  2081. /*                                                            */
  2082. /* NOTE: We define this procedure here instead of in the      */
  2083. /*      'Support procedures' section because of the many      */
  2084. /*       other procedures that reference it.                  */
  2085. /**************************************************************/
  2086.  
  2087. PRINT ''
  2088. PRINT 'Creating procedure sp_post_msx_operation...'
  2089. go
  2090. IF (EXISTS (SELECT *
  2091.             FROM msdb.dbo.sysobjects
  2092.             WHERE (name = 'sp_post_msx_operation')
  2093.               AND (type = 'P')))
  2094.   DROP PROCEDURE sp_post_msx_operation
  2095. go
  2096. CREATE PROCEDURE sp_post_msx_operation
  2097.   @operation              VARCHAR(64),
  2098.   @object_type            VARCHAR(64)      = 'JOB',
  2099.   @job_id                 UNIQUEIDENTIFIER = NULL, -- NOTE: 0x00 means 'ALL'
  2100.   @specific_target_server NVARCHAR(30)     = NULL,
  2101.   @value                  INT              = NULL  -- For polling interval value
  2102. AS
  2103. BEGIN
  2104.   DECLARE @operation_code            INT
  2105.   DECLARE @specific_target_server_id INT
  2106.   DECLARE @instructions_posted       INT
  2107.   DECLARE @job_id_as_char            VARCHAR(36)
  2108.   DECLARE @msx_time_zone_adjustment  INT
  2109.   DECLARE @local_machine_name        NVARCHAR(30)
  2110.   DECLARE @retval                    INT
  2111.  
  2112.   SET NOCOUNT ON
  2113.  
  2114.   -- Remove any leading/trailing spaces from parameters
  2115.   SELECT @operation              = LTRIM(RTRIM(@operation))
  2116.   SELECT @object_type            = LTRIM(RTRIM(@object_type))
  2117.   SELECT @specific_target_server = LTRIM(RTRIM(@specific_target_server))
  2118.  
  2119.   -- Turn [nullable] empty string parameters into NULLs
  2120.   IF (@specific_target_server = N'') SELECT @specific_target_server = NULL
  2121.  
  2122.   -- Only a sysadmin can do this, but fail silently for a non-sysadmin
  2123.   IF (ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) <> 1)
  2124.     RETURN(0) -- Success (or more accurately a no-op)
  2125.  
  2126.   -- Check operation
  2127.   SELECT @operation = UPPER(@operation)
  2128.   SELECT @operation_code = CASE @operation
  2129.                              WHEN 'INSERT'    THEN 1
  2130.                              WHEN 'UPDATE'    THEN 2
  2131.                              WHEN 'DELETE'    THEN 3
  2132.                              WHEN 'START'     THEN 4
  2133.                              WHEN 'STOP'      THEN 5
  2134.                              WHEN 'RE-ENLIST' THEN 6
  2135.                              WHEN 'DEFECT'    THEN 7
  2136.                              WHEN 'SYNC-TIME' THEN 8
  2137.                              WHEN 'SET-POLL'  THEN 9
  2138.                              ELSE 0
  2139.                            END
  2140.   IF (@operation_code = 0)
  2141.   BEGIN
  2142.     RAISERROR(14266, -1, -1, '@operation_code', 'INSERT, UPDATE, DELETE, START, STOP, RE-ENLIST, DEFECT, SYNC-TIME, SET-POLL')
  2143.     RETURN(1) -- Failure
  2144.   END
  2145.  
  2146.   -- Check object type (in 7.0 only 'JOB' or 'SERVER' are valid)
  2147.   IF ((@object_type <> 'JOB') AND (@object_type <> 'SERVER'))
  2148.   BEGIN
  2149.     RAISERROR(14266, -1, -1, '@object_type', 'JOB, SERVER')
  2150.     RETURN(1) -- Failure
  2151.   END
  2152.  
  2153.   -- Check that for a object type of JOB a job_id has been supplied
  2154.   IF ((@object_type = 'JOB') AND (@job_id IS NULL))
  2155.   BEGIN
  2156.     RAISERROR(14233, -1, -1)
  2157.     RETURN(1) -- Failure
  2158.   END
  2159.  
  2160.   -- Check polling interval value
  2161.   IF (@operation_code = 9) AND ((ISNULL(@value, 0) < 10) OR (ISNULL(@value, 0) > 28800))
  2162.   BEGIN
  2163.     RAISERROR(14266, -1, -1, '@value', '10..28800')
  2164.     RETURN(1) -- Failure
  2165.   END
  2166.  
  2167.   -- Check specific target server
  2168.   IF (@specific_target_server IS NOT NULL)
  2169.   BEGIN
  2170.     -- Check if the local server is being targeted
  2171.     IF (UPPER(@specific_target_server) = UPPER(CONVERT(NVARCHAR(30), SERVERPROPERTY('ServerName'))))
  2172.     BEGIN
  2173.       RETURN(0)
  2174.     END
  2175.     ELSE
  2176.     BEGIN
  2177.       SELECT @specific_target_server_id = server_id
  2178.       FROM msdb.dbo.systargetservers
  2179.       WHERE (server_name = @specific_target_server)
  2180.       IF (@specific_target_server_id IS NULL)
  2181.       BEGIN
  2182.         RAISERROR(14262, -1, -1, '@specific_target_server', @specific_target_server)
  2183.         RETURN(1) -- Failure
  2184.       END
  2185.     END
  2186.   END
  2187.  
  2188.   -- Check that this server is an MSX server
  2189.   IF ((SELECT COUNT(*)
  2190.        FROM msdb.dbo.systargetservers) = 0)
  2191.   BEGIN
  2192.     RETURN(0)
  2193.   END
  2194.  
  2195.   -- Get local machine name
  2196.   EXECUTE @retval = master.dbo.xp_getnetname @local_machine_name OUTPUT
  2197.   IF (@retval <> 0) OR (@local_machine_name IS NULL)
  2198.   BEGIN
  2199.     RAISERROR(14225, -1, -1)
  2200.     RETURN(1)
  2201.   END
  2202.  
  2203.   CREATE TABLE #target_servers (server_name sysname COLLATE database_default NOT NULL)
  2204.  
  2205.   -- Optimization: Simply update the date-posted if the operation has already been posted (but
  2206.   -- not yet downloaded) and the target server is not currently polling...
  2207.   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
  2208.      ((@object_type = 'SERVER') AND (@operation_code IN (6, 7))) -- RE-ENLIST or DEFECT operations
  2209.   BEGIN
  2210.     -- Populate the list of target servers to post to
  2211.     IF (@specific_target_server IS NOT NULL)
  2212.       INSERT INTO #target_servers VALUES (@specific_target_server)
  2213.     ELSE
  2214.     BEGIN
  2215.       IF (@object_type = 'SERVER')
  2216.         INSERT INTO #target_servers
  2217.         SELECT server_name
  2218.         FROM msdb.dbo.systargetservers
  2219.  
  2220.       IF (@object_type = 'JOB')
  2221.         INSERT INTO #target_servers
  2222.         SELECT sts.server_name
  2223.         FROM msdb.dbo.sysjobs_view     sjv,
  2224.              msdb.dbo.sysjobservers    sjs,
  2225.              msdb.dbo.systargetservers sts
  2226.         WHERE (sjv.job_id = @job_id)
  2227.           AND (sjv.job_id = sjs.job_id)
  2228.           AND (sjs.server_id = sts.server_id)
  2229.           AND (sjs.server_id <> 0)
  2230.     END
  2231.  
  2232.     IF (EXISTS (SELECT *
  2233.                 FROM #target_servers))
  2234.     BEGIN
  2235.       DECLARE @target_server sysname
  2236.       DECLARE @optimized     BIT
  2237.  
  2238.       SELECT @optimized = 1
  2239.  
  2240.       DECLARE targets_to_post_to CURSOR LOCAL
  2241.       FOR
  2242.       SELECT server_name
  2243.       FROM #target_servers
  2244.  
  2245.       OPEN targets_to_post_to
  2246.       FETCH NEXT FROM targets_to_post_to INTO @target_server
  2247.  
  2248.       -- Optimizing is an all-or-nothing thing, so we do the updates inside a transaction so
  2249.       -- that we can rollback if necessary
  2250.       BEGIN TRANSACTION
  2251.       SAVE TRANSACTION start
  2252.       WHILE (@@fetch_status = 0)
  2253.       BEGIN
  2254.         IF (EXISTS (SELECT *
  2255.                     FROM msdb.dbo.sysdownloadlist
  2256.                     WHERE (target_server = @target_server)
  2257.                       AND (operation_code = @operation_code)
  2258.                       AND (object_id = ISNULL(@job_id, CONVERT(UNIQUEIDENTIFIER, 0x00)))
  2259.                       AND (status = 0))) AND
  2260.            (NOT EXISTS (SELECT *
  2261.                         FROM master.dbo.sysprocesses
  2262.                         WHERE (loginame = @target_server + N'_msx_probe')))
  2263.         BEGIN
  2264.           UPDATE msdb.dbo.sysdownloadlist
  2265.           SET date_posted = GETDATE()
  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)
  2270.         END
  2271.         ELSE
  2272.         BEGIN
  2273.           SELECT @optimized = 0
  2274.           BREAK
  2275.         END
  2276.  
  2277.         FETCH NEXT FROM targets_to_post_to INTO @target_server
  2278.       END
  2279.       DEALLOCATE targets_to_post_to
  2280.  
  2281.       IF (@optimized = 1)
  2282.       BEGIN
  2283.         COMMIT TRANSACTION
  2284.         SELECT @instructions_posted = 0
  2285.         GOTO DoReport
  2286.       END
  2287.       ELSE
  2288.       BEGIN
  2289.         ROLLBACK TRANSACTION start
  2290.         COMMIT TRANSACTION
  2291.       END
  2292.     END
  2293.   END
  2294.  
  2295.   -- Job-specific processing...
  2296.   IF (@object_type = 'JOB')
  2297.   BEGIN
  2298.     -- Validate the job (if supplied)
  2299.     IF (@job_id <> CONVERT(UNIQUEIDENTIFIER, 0x00))
  2300.     BEGIN
  2301.       SELECT @job_id_as_char = CONVERT(VARCHAR(36), @job_id)
  2302.  
  2303.       -- Check if the job exists
  2304.       IF (NOT EXISTS (SELECT *
  2305.                       FROM msdb.dbo.sysjobs_view
  2306.                       WHERE (job_id = @job_id)))
  2307.       BEGIN
  2308.         RAISERROR(14262, -1, -1, '@job_id', @job_id_as_char)
  2309.         RETURN(1) -- Failure
  2310.       END
  2311.  
  2312.       -- If this is a local job then there's nothing for us to do
  2313.       IF (EXISTS (SELECT *
  2314.                   FROM msdb.dbo.sysjobservers
  2315.                   WHERE (job_id = @job_id)
  2316.                     AND (server_id = 0))) -- 0 means local server
  2317.       OR (NOT EXISTS (SELECT *
  2318.                       FROM msdb.dbo.sysjobservers
  2319.                       WHERE (job_id = @job_id)))
  2320.       BEGIN
  2321.         RETURN(0)
  2322.       END
  2323.     END
  2324.  
  2325.     -- Generate the sysdownloadlist row(s)...
  2326.     IF (@operation_code = 1) OR  -- Insert
  2327.        (@operation_code = 2) OR  -- Update
  2328.        (@operation_code = 3) OR  -- Delete
  2329.        (@operation_code = 4) OR  -- Start
  2330.        (@operation_code = 5)     -- Stop
  2331.     BEGIN
  2332.       IF (@job_id = CONVERT(UNIQUEIDENTIFIER, 0x00)) -- IE. 'ALL'
  2333.       BEGIN
  2334.         -- All jobs
  2335.  
  2336.         -- Handle DELETE as a special case (rather than posting 1 instruction per job we just
  2337.         -- post a single instruction that means 'delete all jobs from the MSX')
  2338.         IF (@operation_code = 3)
  2339.         BEGIN
  2340.           INSERT INTO msdb.dbo.sysdownloadlist
  2341.                 (source_server,
  2342.                  operation_code,
  2343.                  object_type,
  2344.                  object_id,
  2345.                  target_server)
  2346.           SELECT @local_machine_name,
  2347.                  @operation_code,
  2348.                  1,                -- 1 means 'JOB'
  2349.                  CONVERT(UNIQUEIDENTIFIER, 0x00),
  2350.                  sts.server_name
  2351.           FROM systargetservers sts
  2352.           WHERE ((@specific_target_server_id IS NULL) OR (sts.server_id = @specific_target_server_id))
  2353.             AND ((SELECT COUNT(*)
  2354.                   FROM msdb.dbo.sysjobservers
  2355.                   WHERE (server_id = sts.server_id)) > 0)
  2356.           SELECT @instructions_posted = @@rowcount
  2357.         END
  2358.         ELSE
  2359.         BEGIN
  2360.           INSERT INTO msdb.dbo.sysdownloadlist
  2361.                 (source_server,
  2362.                  operation_code,
  2363.                  object_type,
  2364.                  object_id,
  2365.                  target_server)
  2366.           SELECT @local_machine_name,
  2367.                  @operation_code,
  2368.                  1,                -- 1 means 'JOB'
  2369.                  sjv.job_id,
  2370.                  sts.server_name
  2371.           FROM sysjobs_view     sjv,
  2372.                sysjobservers    sjs,
  2373.                systargetservers sts
  2374.           WHERE (sjv.job_id = sjs.job_id)
  2375.             AND (sjs.server_id = sts.server_id)
  2376.             AND (sjs.server_id <> 0) -- We want to exclude local jobs
  2377.             AND ((@specific_target_server_id IS NULL) OR (sjs.server_id = @specific_target_server_id))
  2378.           SELECT @instructions_posted = @@rowcount
  2379.         END
  2380.       END
  2381.       ELSE
  2382.       BEGIN
  2383.         -- Specific job (ie. @job_id is not 0x00)
  2384.         INSERT INTO msdb.dbo.sysdownloadlist
  2385.               (source_server,
  2386.                operation_code,
  2387.                object_type,
  2388.                object_id,
  2389.                target_server,
  2390.                deleted_object_name)
  2391.         SELECT @local_machine_name,
  2392.                @operation_code,
  2393.                1,                -- 1 means 'JOB'
  2394.                sjv.job_id,
  2395.                sts.server_name,
  2396.                CASE @operation_code WHEN 3 -- Delete
  2397.                                       THEN sjv.name
  2398.                                       ELSE NULL
  2399.                                     END
  2400.         FROM sysjobs_view     sjv,
  2401.              sysjobservers    sjs,
  2402.              systargetservers sts
  2403.         WHERE (sjv.job_id = @job_id)
  2404.           AND (sjv.job_id = sjs.job_id)
  2405.           AND (sjs.server_id = sts.server_id)
  2406.           AND (sjs.server_id <> 0) -- We want to exclude local jobs
  2407.           AND ((@specific_target_server_id IS NULL) OR (sjs.server_id = @specific_target_server_id))
  2408.         SELECT @instructions_posted = @@rowcount
  2409.       END
  2410.     END
  2411.     ELSE
  2412.     BEGIN
  2413.       RAISERROR(14266, -1, -1, '@operation_code', 'INSERT, UPDATE, DELETE, START, STOP')
  2414.       RETURN(1) -- Failure
  2415.     END
  2416.   END
  2417.  
  2418.   -- Server-specific processing...
  2419.   IF (@object_type = 'SERVER')
  2420.   BEGIN
  2421.     -- Generate the sysdownloadlist row(s)...
  2422.     IF (@operation_code = 6) OR  -- ReEnlist
  2423.        (@operation_code = 7) OR  -- Defect
  2424.        (@operation_code = 8) OR  -- Synchronize time (with MSX)
  2425.        (@operation_code = 9)     -- Set MSX polling interval (in seconds)
  2426.     BEGIN
  2427.       IF (@operation_code = 8)
  2428.       BEGIN
  2429.         EXECUTE master.dbo.xp_regread N'HKEY_LOCAL_MACHINE',
  2430.                                       N'SYSTEM\CurrentControlSet\Control\TimeZoneInformation',
  2431.                                       N'Bias',
  2432.                                       @msx_time_zone_adjustment OUTPUT,
  2433.                                       N'no_output'
  2434.         SELECT @msx_time_zone_adjustment = -ISNULL(@msx_time_zone_adjustment, 0)
  2435.       END
  2436.  
  2437.       INSERT INTO msdb.dbo.sysdownloadlist
  2438.             (source_server,
  2439.              operation_code,
  2440.              object_type,
  2441.              object_id,
  2442.              target_server)
  2443.       SELECT @local_machine_name,
  2444.              @operation_code,
  2445.              2,                  -- 2 means 'SERVER'
  2446.              CASE @operation_code
  2447.                WHEN 8 THEN CONVERT(UNIQUEIDENTIFIER, CONVERT(BINARY(16), -(@msx_time_zone_adjustment - sts.time_zone_adjustment)))
  2448.                WHEN 9 THEN CONVERT(UNIQUEIDENTIFIER, CONVERT(BINARY(16), @value))
  2449.                ELSE CONVERT(UNIQUEIDENTIFIER, 0x00)
  2450.              END,
  2451.              sts.server_name
  2452.       FROM systargetservers sts
  2453.       WHERE ((@specific_target_server_id IS NULL) OR (sts.server_id = @specific_target_server_id))
  2454.       SELECT @instructions_posted = @@rowcount
  2455.     END
  2456.     ELSE
  2457.     BEGIN
  2458.       RAISERROR(14266, -1, -1, '@operation_code', 'RE-ENLIST, DEFECT, SYNC-TIME, SET-POLL')
  2459.       RETURN(1) -- Failure
  2460.     END
  2461.   END
  2462.  
  2463. DoReport:
  2464.  
  2465.   -- Report number of rows inserted
  2466.   IF (@object_type = 'JOB') AND
  2467.      (@job_id = CONVERT(UNIQUEIDENTIFIER, 0x00)) AND
  2468.      (@instructions_posted = 0) AND
  2469.      (@specific_target_server_id IS NOT NULL)
  2470.     RAISERROR(14231, 0, 1, '@specific_target_server', @specific_target_server)
  2471.   ELSE
  2472.     RAISERROR(14230, 0, 1, @instructions_posted, @operation)
  2473.  
  2474.   -- Delete any [downloaded] instructions that are over the registry-defined limit
  2475.   IF (@specific_target_server IS NOT NULL)
  2476.     EXECUTE msdb.dbo.sp_downloaded_row_limiter @specific_target_server
  2477.  
  2478.   RETURN(0) -- 0 means success
  2479. END
  2480. go
  2481.  
  2482. /**************************************************************/
  2483. /* SP_DELETE_JOB_REFERENCES                                   */
  2484. /**************************************************************/
  2485.  
  2486. PRINT ''
  2487. PRINT 'Creating procedure sp_delete_job_references...'
  2488. go
  2489. IF (EXISTS (SELECT *
  2490.             FROM msdb.dbo.sysobjects
  2491.             WHERE (name = N'sp_delete_job_references')
  2492.               AND (type = 'P')))
  2493.   DROP PROCEDURE sp_delete_job_references
  2494. go
  2495. CREATE PROCEDURE sp_delete_job_references
  2496. AS
  2497. BEGIN
  2498.   DECLARE @deleted_job_id  UNIQUEIDENTIFIER
  2499.   DECLARE @task_id_as_char VARCHAR(10)
  2500.   DECLARE @job_is_cached   INT
  2501.   DECLARE @alert_name      sysname
  2502.  
  2503.   -- Keep SQLServerAgent's cache in-sync and cleanup any 'webtask' cross-references to the deleted job(s)
  2504.   -- NOTE: The caller must have created a table called #temp_jobs_to_delete of the format
  2505.   --       (job_id UNIQUEIDENTIFIER NOT NULL, job_is_cached INT NOT NULL).
  2506.  
  2507.   DECLARE sqlagent_notify CURSOR LOCAL
  2508.   FOR
  2509.   SELECT job_id, job_is_cached
  2510.   FROM #temp_jobs_to_delete
  2511.  
  2512.   OPEN sqlagent_notify
  2513.   FETCH NEXT FROM sqlagent_notify INTO @deleted_job_id, @job_is_cached
  2514.  
  2515.   WHILE (@@fetch_status = 0)
  2516.   BEGIN
  2517.     -- NOTE: We only notify SQLServerAgent if we know the job has been cached
  2518.     IF(@job_is_cached = 1)
  2519.       EXECUTE msdb.dbo.sp_sqlagent_notify @op_type     = N'J',
  2520.                                           @job_id      = @deleted_job_id,
  2521.                                           @action_type = N'D'
  2522.  
  2523.     IF (EXISTS (SELECT *
  2524.                 FROM master.dbo.sysobjects
  2525.                 WHERE (name = N'sp_cleanupwebtask')
  2526.                   AND (type = 'P')))
  2527.     BEGIN
  2528.       SELECT @task_id_as_char = CONVERT(VARCHAR(10), task_id)
  2529.       FROM msdb.dbo.systaskids
  2530.       WHERE (job_id = @deleted_job_id)
  2531.       IF (@task_id_as_char IS NOT NULL)
  2532.         EXECUTE ('master.dbo.sp_cleanupwebtask @taskid = ' + @task_id_as_char)
  2533.     END
  2534.  
  2535.     FETCH NEXT FROM sqlagent_notify INTO @deleted_job_id, @job_is_cached
  2536.   END
  2537.   DEALLOCATE sqlagent_notify
  2538.  
  2539.   -- Remove systaskid references (must do this AFTER sp_cleanupwebtask stuff)
  2540.   DELETE FROM msdb.dbo.systaskids
  2541.   WHERE job_id IN (SELECT job_id FROM #temp_jobs_to_delete)
  2542.  
  2543.   -- Remove sysdbmaintplan_jobs references
  2544.   DELETE FROM msdb.dbo.sysdbmaintplan_jobs
  2545.   WHERE job_id IN (SELECT job_id FROM #temp_jobs_to_delete)
  2546.  
  2547.   -- Finally, clean up any dangling references in sysalerts to the deleted job(s)
  2548.   DECLARE sysalerts_cleanup CURSOR LOCAL
  2549.   FOR
  2550.   SELECT name
  2551.   FROM msdb.dbo.sysalerts
  2552.   WHERE (job_id IN (SELECT job_id FROM #temp_jobs_to_delete))
  2553.  
  2554.   OPEN sysalerts_cleanup
  2555.   FETCH NEXT FROM sysalerts_cleanup INTO @alert_name
  2556.   WHILE (@@fetch_status = 0)
  2557.   BEGIN
  2558.     EXECUTE msdb.dbo.sp_update_alert @name   = @alert_name,
  2559.                                      @job_id = 0x00
  2560.     FETCH NEXT FROM sysalerts_cleanup INTO @alert_name
  2561.   END
  2562.   DEALLOCATE sysalerts_cleanup
  2563. END
  2564. go
  2565.  
  2566. /**************************************************************/
  2567. /* SP_DELETE_ALL_MSX_JOBS                                     */
  2568. /*                                                            */
  2569. /* NOTE: This is a separate procedure because SQLServerAgent  */
  2570. /*       needs to call it, as does sp_msx_defect and          */
  2571. /*       sp_delete_job.                                       */
  2572. /**************************************************************/
  2573.  
  2574. PRINT ''
  2575. PRINT 'Creating procedure sp_delete_all_msx_jobs...'
  2576. go
  2577. IF (EXISTS (SELECT *
  2578.             FROM msdb.dbo.sysobjects
  2579.             WHERE (name = N'sp_delete_all_msx_jobs')
  2580.               AND (type = 'P')))
  2581.   DROP PROCEDURE sp_delete_all_msx_jobs
  2582. go
  2583. CREATE PROCEDURE sp_delete_all_msx_jobs
  2584.   @msx_server   NVARCHAR(30),
  2585.   @jobs_deleted INT = NULL OUTPUT
  2586. AS
  2587. BEGIN
  2588.   SET NOCOUNT ON
  2589.  
  2590.   -- Change server name to always reflect real servername or servername\instancename
  2591.   IF (UPPER(@msx_server) = '(LOCAL)')
  2592.     SELECT @msx_server = UPPER(CONVERT(NVARCHAR(30), SERVERPROPERTY('ServerName')))
  2593.  
  2594.   -- Delete all the jobs that originated from the MSX
  2595.   CREATE TABLE #temp_jobs_to_delete (job_id UNIQUEIDENTIFIER NOT NULL, job_is_cached INT NOT NULL)
  2596.  
  2597.   -- NOTE: The left outer-join here is to handle the [unlikely] case of missing sysjobservers rows
  2598.   INSERT INTO #temp_jobs_to_delete
  2599.   SELECT sjv.job_id, CASE sjs.server_id WHEN 0 THEN 1 ELSE 0 END
  2600.   FROM msdb.dbo.sysjobs_view sjv
  2601.        LEFT OUTER JOIN msdb.dbo.sysjobservers sjs ON (sjv.job_id = sjs.job_id)
  2602.   WHERE (ISNULL(sjs.server_id, 0) = 0)
  2603.     AND (sjv.originating_server = @msx_server)
  2604.  
  2605.   -- Must do this before deleting the job itself since sp_sqlagent_notify does a lookup on sysjobs_view
  2606.   EXECUTE msdb.dbo.sp_delete_job_references
  2607.  
  2608.   BEGIN TRANSACTION
  2609.  
  2610.     DELETE FROM msdb.dbo.sysjobs_view
  2611.     WHERE job_id IN (SELECT job_id FROM #temp_jobs_to_delete)
  2612.  
  2613.     DELETE FROM msdb.dbo.sysjobservers
  2614.     WHERE job_id IN (SELECT job_id FROM #temp_jobs_to_delete)
  2615.  
  2616.     DELETE FROM msdb.dbo.sysjobsteps
  2617.     WHERE job_id IN (SELECT job_id FROM #temp_jobs_to_delete)
  2618.  
  2619.     DELETE FROM msdb.dbo.sysjobschedules
  2620.     WHERE job_id IN (SELECT job_id FROM #temp_jobs_to_delete)
  2621.  
  2622.     DELETE FROM msdb.dbo.sysjobhistory
  2623.     WHERE job_id IN (SELECT job_id FROM #temp_jobs_to_delete)
  2624.  
  2625.   COMMIT TRANSACTION
  2626.  
  2627.   SELECT @jobs_deleted = COUNT(*)
  2628.   FROM #temp_jobs_to_delete
  2629.  
  2630.   DROP TABLE #temp_jobs_to_delete
  2631. END
  2632. go
  2633.  
  2634. /**************************************************************/
  2635. /* SP_GENERATE_TARGET_SERVER_JOB_ASSIGNMENT_SQL               */
  2636. /**************************************************************/
  2637.  
  2638. PRINT ''
  2639. PRINT 'Creating procedure sp_generate_target_server_job_assignment_sql...'
  2640. go
  2641. IF (EXISTS (SELECT *
  2642.             FROM msdb.dbo.sysobjects
  2643.             WHERE (name = N'sp_generate_target_server_job_assignment_sql')
  2644.               AND (type = 'P')))
  2645.   DROP PROCEDURE sp_generate_target_server_job_assignment_sql
  2646. go
  2647. CREATE PROCEDURE sp_generate_target_server_job_assignment_sql
  2648.   @server_name     NVARCHAR(30) = NULL, 
  2649.   @new_server_name NVARCHAR(30) = NULL  -- Use this if the target server computer has been renamed
  2650. AS
  2651. BEGIN
  2652.   SET NOCOUNT ON
  2653.  
  2654.   -- Change server name to always reflect real servername or servername\instancename
  2655.   IF (@server_name IS NULL) OR (UPPER(@server_name) = '(LOCAL)')
  2656.     SELECT @server_name = UPPER(CONVERT(NVARCHAR(30), SERVERPROPERTY('ServerName')))
  2657.  
  2658.   -- Verify the server name
  2659.   IF (UPPER(@server_name) <> UPPER(CONVERT(NVARCHAR(30), SERVERPROPERTY('ServerName')))) AND
  2660.      (NOT EXISTS (SELECT *
  2661.                   FROM msdb.dbo.systargetservers
  2662.                   WHERE (server_name = @server_name)))
  2663.   BEGIN
  2664.     RAISERROR(14262, 16, 1, '@server_name', @server_name)
  2665.     RETURN(1) -- Failure
  2666.   END
  2667.  
  2668.   IF (EXISTS (SELECT *
  2669.               FROM msdb.dbo.sysjobservers    sjs,
  2670.                    msdb.dbo.systargetservers sts
  2671.               WHERE (sjs.server_id = sts.server_id)
  2672.                 AND (sts.server_name = @server_name)))
  2673.   BEGIN
  2674.     -- Generate the SQL
  2675.     SELECT 'Execute this SQL to re-assign jobs to the target server' =
  2676.            'EXECUTE msdb.dbo.sp_add_jobserver @job_id = ''' + CONVERT(VARCHAR(36), sjs.job_id) +
  2677.            ''', @server_name = ''' +  ISNULL(@new_server_name, sts.server_name) + ''''
  2678.     FROM msdb.dbo.sysjobservers    sjs,
  2679.          msdb.dbo.systargetservers sts
  2680.     WHERE (sjs.server_id = sts.server_id)
  2681.       AND (sts.server_name = @server_name)
  2682.   END
  2683.   ELSE
  2684.     RAISERROR(14548, 10, 1, @server_name)
  2685.  
  2686.   RETURN(0) -- Success
  2687. END
  2688. go
  2689.  
  2690. /**************************************************************/
  2691. /* SP_GENERATE_SERVER_DESCRIPTION                             */
  2692. /**************************************************************/
  2693.  
  2694. PRINT ''
  2695. PRINT 'Creating procedure sp_generate_server_description...'
  2696. go
  2697.  
  2698. IF (EXISTS (SELECT *
  2699.             FROM msdb.dbo.sysobjects
  2700.             WHERE (name = N'sp_generate_server_description')
  2701.               AND (type = 'P')))
  2702.   DROP PROCEDURE sp_generate_server_description
  2703. go
  2704. CREATE PROCEDURE sp_generate_server_description
  2705.   @description NVARCHAR(100) = NULL OUTPUT,
  2706.   @result_set  BIT = 0
  2707. AS
  2708. BEGIN
  2709.   SET NOCOUNT ON
  2710.  
  2711.   CREATE TABLE #xp_results
  2712.   (
  2713.   id              INT           NOT NULL,
  2714.   name            NVARCHAR(30)  COLLATE database_default NOT NULL,
  2715.   internal_value  INT           NULL,
  2716.   character_value NVARCHAR(212) COLLATE database_default NULL
  2717.   )
  2718.   INSERT INTO #xp_results
  2719.   EXECUTE master.dbo.xp_msver
  2720.  
  2721.   UPDATE #xp_results
  2722.   SET character_value = FORMATMESSAGE(14205)
  2723.   WHERE (character_value IS NULL)
  2724.  
  2725.   SELECT @description = (SELECT character_value FROM #xp_results WHERE (id = 1)) + N' ' +
  2726.                         (SELECT character_value FROM #xp_results WHERE (id = 2)) + N' / Windows ' +
  2727.                         (SELECT character_value FROM #xp_results WHERE (id = 15)) + N' / ' +
  2728.                         (SELECT character_value FROM #xp_results WHERE (id = 16)) + N' ' +
  2729.                         (SELECT CASE character_value
  2730.                                   WHEN N'PROCESSOR_INTEL_386'     THEN N'386'
  2731.                                   WHEN N'PROCESSOR_INTEL_486'     THEN N'486'
  2732.                                   WHEN N'PROCESSOR_INTEL_PENTIUM' THEN N'Pentium'
  2733.                                   WHEN N'PROCESSOR_MIPS_R4000'    THEN N'MIPS'
  2734.                                   WHEN N'PROCESSOR_ALPHA_21064'   THEN N'Alpha'
  2735.                                   ELSE character_value
  2736.                                 END
  2737.                          FROM #xp_results WHERE (id = 18)) + N' CPU(s) / ' +
  2738.                         (SELECT CONVERT(NVARCHAR, internal_value) FROM #xp_results WHERE (id = 19)) + N' MB RAM.'
  2739.   DROP TABLE #xp_results
  2740.   IF (@result_set = 1)
  2741.     SELECT @description
  2742. END
  2743. go
  2744.  
  2745. /**************************************************************/
  2746. /* SP_MSX_ENLIST                                              */
  2747. /**************************************************************/
  2748.  
  2749. PRINT ''
  2750. PRINT 'Creating procedure sp_msx_enlist...'
  2751. go
  2752. IF (EXISTS (SELECT *
  2753.             FROM msdb.dbo.sysobjects
  2754.             WHERE (name = 'sp_msx_enlist')
  2755.               AND (type = 'P')))
  2756.   DROP PROCEDURE sp_msx_enlist
  2757. go
  2758. CREATE PROCEDURE sp_msx_enlist
  2759.   @msx_server_name NVARCHAR(30),
  2760.   @location        NVARCHAR(100) = NULL, -- The procedure will supply a default
  2761.   @ping_server     BIT = 1               -- Set to 0 to skip the MSX ping test
  2762. AS
  2763. BEGIN
  2764.   DECLARE @current_msx_server   NVARCHAR(30)
  2765.   DECLARE @local_machine_name   NVARCHAR(30)
  2766.   DECLARE @retval               INT
  2767.   DECLARE @time_zone_adjustment INT
  2768.   DECLARE @local_time           NVARCHAR(100)
  2769.   DECLARE @nt_user              NVARCHAR(100)
  2770.   DECLARE @poll_interval        INT
  2771.  
  2772.   SET NOCOUNT ON
  2773.  
  2774.   -- Only a sysadmin can do this
  2775.   IF (ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) <> 1)
  2776.   BEGIN
  2777.     RAISERROR(15003, 16, 1, N'sysadmin')
  2778.     RETURN(1) -- Failure
  2779.   END
  2780.  
  2781.   -- Only an NT server can be enlisted
  2782.   IF ((PLATFORM() & 0x1) <> 0x1) -- NT
  2783.   BEGIN
  2784.     RAISERROR(14540, -1, 1)
  2785.     RETURN(1) -- Failure
  2786.   END
  2787.  
  2788.   -- Only SBS, Standard, or Enterprise editions of SQL Server can be enlisted
  2789.   IF ((PLATFORM() & 0x100) = 0x100) -- Desktop package
  2790.   BEGIN
  2791.     RAISERROR(14539, -1, -1)
  2792.     RETURN(1) -- Failure
  2793.   END
  2794.  
  2795.   -- Remove any leading/trailing spaces from parameters
  2796.   SELECT @msx_server_name = LTRIM(RTRIM(@msx_server_name))
  2797.   SELECT @location        = LTRIM(RTRIM(@location))
  2798.  
  2799.   -- Turn [nullable] empty string parameters into NULLs
  2800.   IF (@location = N'') SELECT @location = NULL
  2801.  
  2802.   -- Change to MSX server name to upper-case since it's a machine name
  2803. --  SELECT @msx_server_name = UPPER(@msx_server_name)
  2804.  
  2805.   SELECT @retval = 0
  2806.  
  2807.   -- Get the values that we'll need for the [re]enlistment operation (except the local time
  2808.   -- which we get right before we call xp_msx_enlist to that it's as accurate as possible)
  2809.   SELECT @nt_user = ISNULL(NT_CLIENT(), ISNULL(SUSER_SNAME(), FORMATMESSAGE(14205)))
  2810.   EXECUTE master.dbo.xp_regread N'HKEY_LOCAL_MACHINE',
  2811.                                 N'SYSTEM\CurrentControlSet\Control\TimeZoneInformation',
  2812.                                 N'Bias',
  2813.                                 @time_zone_adjustment OUTPUT,
  2814.                                 N'no_output'
  2815.   IF ((PLATFORM() & 0x1) = 0x1) -- NT
  2816.     SELECT @time_zone_adjustment = -ISNULL(@time_zone_adjustment, 0)
  2817.   ELSE
  2818.     SELECT @time_zone_adjustment = -CONVERT(INT, CONVERT(BINARY(2), ISNULL(@time_zone_adjustment, 0)))
  2819.  
  2820.   EXECUTE master.dbo.xp_instance_regread N'HKEY_LOCAL_MACHINE',
  2821.                                          N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
  2822.                                          N'MSXPollInterval',
  2823.                                          @poll_interval OUTPUT,
  2824.                                          N'no_output'
  2825.   SELECT @poll_interval = ISNULL(@poll_interval, 60) -- This should be the same as DEF_REG_MSX_POLL_INTERVAL
  2826.   EXECUTE master.dbo.xp_instance_regread N'HKEY_LOCAL_MACHINE',
  2827.                                          N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
  2828.                                          N'MSXServerName',
  2829.                                          @current_msx_server OUTPUT,
  2830.                                          N'no_output'
  2831.   SELECT @current_msx_server = LTRIM(RTRIM(@current_msx_server))
  2832.   EXECUTE @retval = master.dbo.xp_getnetname @local_machine_name OUTPUT
  2833.   IF (@retval <> 0)
  2834.     RETURN(1) -- Failure
  2835.  
  2836.   -- Check if this machine is an MSX (and therefore cannot be enlisted into another MSX)
  2837.   IF (EXISTS (SELECT *
  2838.               FROM msdb.dbo.systargetservers))
  2839.   BEGIN
  2840.     RAISERROR(14299, -1, -1, @local_machine_name)
  2841.     RETURN(1) -- Failure
  2842.   END
  2843.  
  2844.   -- Check if the MSX supplied is the same as the local machine (this is not allowed)
  2845. /*  IF (UPPER(@local_machine_name) = UPPER(@msx_server_name))
  2846.   BEGIN
  2847.     RAISERROR(14297, -1, -1)
  2848.     RETURN(1) -- Failure
  2849.   END*/
  2850.  
  2851.   -- Check if MSDB has be re-installed since we enlisted
  2852.   IF (@current_msx_server IS NOT NULL) AND
  2853.      (NOT EXISTS (SELECT *
  2854.                   FROM msdb.dbo.sqlagent_info
  2855.                   WHERE (attribute = 'DateEnlisted')))
  2856.   BEGIN
  2857.     -- User is tring to [re]enlist after a re-install, so we have to forcefully defect before
  2858.     -- we can fully enlist again
  2859.     EXECUTE msdb.dbo.sp_msx_defect @forced_defection = 1
  2860.     SELECT @current_msx_server = NULL
  2861.   END
  2862.  
  2863.   -- Check if we are already enlisted, in which case we re-enlist
  2864.   IF ((@current_msx_server IS NOT NULL) AND (@current_msx_server <> N''))
  2865.   BEGIN
  2866.     IF (UPPER(@current_msx_server) = UPPER(@msx_server_name))
  2867.     BEGIN
  2868.       -- Update the [existing] enlistment
  2869.       SELECT @local_time = CONVERT(NVARCHAR, GETDATE(), 112) + N' ' + CONVERT(NVARCHAR, GETDATE(), 108)
  2870.       EXECUTE @retval = master.dbo.xp_msx_enlist 2, @msx_server_name, @nt_user, @location, @time_zone_adjustment, @local_time, @poll_interval
  2871.       RETURN(@retval) -- 0 means success
  2872.     END
  2873.     ELSE
  2874.     BEGIN
  2875.       RAISERROR(14296, -1, -1, @current_msx_server)
  2876.       RETURN(1) -- Failure
  2877.     END
  2878.   END
  2879.  
  2880.   -- If we get this far then we're dealing with a new enlistment...
  2881.  
  2882.   -- Check if the MSX supplied exists on the network
  2883.  
  2884.   IF (@ping_server = 1)
  2885.   BEGIN
  2886.     DECLARE @msx_machine_name NVARCHAR (30)
  2887.     DECLARE @char_index       INT
  2888.  
  2889.     SELECT @char_index = CHARINDEX (N'\', @msx_server_name)
  2890.     IF (@char_index > 0)
  2891.     BEGIN
  2892.       SELECT @msx_machine_name = LEFT (@msx_server_name, @char_index - 1)
  2893.     END
  2894.     ELSE
  2895.     BEGIN
  2896.       SELECT @msx_machine_name = @msx_server_name
  2897.     END
  2898.  
  2899.     IF ((PLATFORM() & 0x2) = 0x2) -- Win9x
  2900.     BEGIN
  2901.       EXECUTE(N'CREATE TABLE #output (output NVARCHAR(1024) COLLATE database_default)
  2902.                 SET NOCOUNT ON
  2903.                 INSERT INTO #output
  2904.                 EXECUTE master.dbo.xp_cmdshell N''net view \\' + @msx_machine_name + N'''
  2905.                 IF (EXISTS (SELECT *
  2906.                             FROM #output
  2907.                             WHERE (output LIKE N''% 53%'')))
  2908.                    RAISERROR(14262, -1, -1, N''@msx_server_name'', N''' + @msx_machine_name + N''') WITH SETERROR')
  2909.       IF (@@error <> 0)
  2910.         RETURN(1) -- Failure
  2911.     END
  2912.     ELSE
  2913.     BEGIN
  2914.       EXECUTE(N'DECLARE @retval INT
  2915.                 SET NOCOUNT ON
  2916.                 EXECUTE @retval = master.dbo.xp_cmdshell N''net view \\' + @msx_machine_name + N' > nul'', no_output
  2917.                 IF (@retval <> 0)
  2918.                   RAISERROR(14262, -1, -1, N''@msx_server_name'', N''' + @msx_machine_name + N''') WITH SETERROR')
  2919.       IF (@@error <> 0)
  2920.         RETURN(1) -- Failure
  2921.     END
  2922.   END
  2923.  
  2924.   -- If no location is supplied, generate one (such as we can)
  2925.   IF (@location IS NULL)
  2926.     EXECUTE msdb.dbo.sp_generate_server_description @location OUTPUT
  2927.  
  2928.   SELECT @local_time = CONVERT(NVARCHAR, GETDATE(), 112) + ' ' + CONVERT(NVARCHAR, GETDATE(), 108)
  2929.   EXECUTE @retval = master.dbo.xp_msx_enlist 0, @msx_server_name, @nt_user, @location, @time_zone_adjustment, @local_time, @poll_interval
  2930.  
  2931.   IF (@retval = 0)
  2932.   BEGIN
  2933.     EXECUTE master.dbo.xp_instance_regwrite N'HKEY_LOCAL_MACHINE',
  2934.                                             N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
  2935.                                             N'MSXServerName',
  2936.                                             N'REG_SZ',
  2937.                                             @msx_server_name
  2938.  
  2939.     IF (@current_msx_server IS NOT NULL)
  2940.       RAISERROR(14228, 0, 1, @current_msx_server, @msx_server_name)
  2941.     ELSE
  2942.       RAISERROR(14229, 0, 1, @msx_server_name)
  2943.  
  2944.     -- Add entry to sqlagent_info
  2945.     INSERT INTO msdb.dbo.sqlagent_info (attribute, value) VALUES ('DateEnlisted', CONVERT(VARCHAR(10), GETDATE(), 112))
  2946.   END
  2947.  
  2948.   RETURN(@retval) -- 0 means success
  2949. END
  2950. go
  2951.  
  2952. /**************************************************************/
  2953. /* SP_MSX_DEFECT                                              */
  2954. /**************************************************************/
  2955.  
  2956. PRINT ''
  2957. PRINT 'Creating procedure sp_msx_defect...'
  2958. go
  2959. IF (EXISTS (SELECT *
  2960.             FROM msdb.dbo.sysobjects
  2961.             WHERE (name = N'sp_msx_defect')
  2962.               AND (type = 'P')))
  2963.   DROP PROCEDURE sp_msx_defect
  2964. go
  2965. CREATE PROCEDURE sp_msx_defect
  2966.   @forced_defection BIT = 0
  2967. AS
  2968. BEGIN
  2969.   DECLARE @current_msx_server NVARCHAR(30)
  2970.   DECLARE @retval             INT
  2971.   DECLARE @jobs_deleted       INT
  2972.   DECLARE @polling_interval   INT
  2973.   DECLARE @nt_user            NVARCHAR(100)
  2974.  
  2975.   SET NOCOUNT ON
  2976.  
  2977.   -- Only a sysadmin can do this
  2978.   IF (ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) <> 1)
  2979.   BEGIN
  2980.     RAISERROR(15003, 16, 1, N'sysadmin')
  2981.     RETURN(1) -- Failure
  2982.   END
  2983.  
  2984.   SELECT @retval = 0
  2985.   SELECT @jobs_deleted = 0
  2986.  
  2987.   -- Get the current MSX server name from the registry
  2988.   EXECUTE master.dbo.xp_instance_regread N'HKEY_LOCAL_MACHINE',
  2989.                                          N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
  2990.                                          N'MSXServerName',
  2991.                                          @current_msx_server OUTPUT,
  2992.                                          N'no_output'
  2993.  
  2994.   SELECT @current_msx_server = LTRIM(RTRIM(@current_msx_server))
  2995.   IF ((@current_msx_server IS NULL) OR (@current_msx_server = N''))
  2996.   BEGIN
  2997.     RAISERROR(14298, -1, -1)
  2998.     RETURN(1) -- Failure
  2999.   END
  3000.  
  3001.   SELECT @nt_user = ISNULL(NT_CLIENT(), ISNULL(SUSER_SNAME(), FORMATMESSAGE(14205)))
  3002.  
  3003.   EXECUTE @retval = master.dbo.xp_msx_enlist 1, @current_msx_server, @nt_user
  3004.  
  3005.   IF (@retval <> 0) AND (@forced_defection = 0)
  3006.     RETURN(1) -- Failure
  3007.  
  3008.   -- Clear the MSXServerName registry entry
  3009.   EXECUTE master.dbo.xp_instance_regwrite N'HKEY_LOCAL_MACHINE',
  3010.                                           N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
  3011.                                           N'MSXServerName',
  3012.                                           N'REG_SZ',
  3013.                                           N''
  3014.  
  3015.   -- Delete the MSXPollingInterval registry entry
  3016.   EXECUTE master.dbo.xp_instance_regread N'HKEY_LOCAL_MACHINE',
  3017.                                          N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
  3018.                                          N'MSXPollInterval',
  3019.                                          @polling_interval OUTPUT,
  3020.                                          N'no_output'
  3021.   IF (@polling_interval IS NOT NULL)
  3022.     EXECUTE master.dbo.xp_instance_regdeletevalue N'HKEY_LOCAL_MACHINE',
  3023.                                                   N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
  3024.                                                   N'MSXPollInterval'
  3025.  
  3026.   -- Remove the entry from sqlagent_info
  3027.   DELETE FROM msdb.dbo.sqlagent_info
  3028.   WHERE (attribute = N'DateEnlisted')
  3029.  
  3030.   -- Delete all the jobs that originated from the MSX
  3031.   -- NOTE: We can't use sp_delete_job here since sp_delete_job checks if the caller is
  3032.   --       SQLServerAgent (only SQLServerAgent can delete non-local jobs).
  3033.   EXECUTE msdb.dbo.sp_delete_all_msx_jobs @current_msx_server, @jobs_deleted OUTPUT
  3034.   RAISERROR(14227, 0, 1, @current_msx_server, @jobs_deleted)
  3035.  
  3036.   -- If a forced defection was performed, attempt to notify the MSXOperator
  3037.   IF (@forced_defection = 1)
  3038.   BEGIN
  3039.     DECLARE @network_address    NVARCHAR(100)
  3040.     DECLARE @command            NVARCHAR(512)
  3041.     DECLARE @local_machine_name NVARCHAR(30)
  3042.     DECLARE @res_warning        NVARCHAR(300)
  3043.  
  3044.     SELECT @network_address = netsend_address
  3045.     FROM msdb.dbo.sysoperators
  3046.     WHERE (name = N'MSXOperator')
  3047.  
  3048.     IF (@network_address IS NOT NULL)
  3049.     BEGIN
  3050.       EXECUTE @retval = master.dbo.xp_getnetname @local_machine_name OUTPUT
  3051.       IF (@retval <> 0)
  3052.         RETURN(1) -- Failure
  3053.       SELECT @res_warning = FORMATMESSAGE(14217)
  3054.       SELECT @command = N'NET SEND ' + @network_address + N' ' + @res_warning
  3055.       SELECT @command = STUFF(@command, PATINDEX(N'%[%%]s%', @command), 2, NT_CLIENT())
  3056.       SELECT @command = STUFF(@command, PATINDEX(N'%[%%]s%', @command), 2, @local_machine_name)
  3057.       EXECUTE master.dbo.xp_cmdshell @command, no_output
  3058.     END
  3059.   END
  3060.  
  3061.   -- Delete the 'MSXOperator' (must do this last)
  3062.   IF (EXISTS (SELECT *
  3063.               FROM msdb.dbo.sysoperators
  3064.               WHERE (name = N'MSXOperator')))
  3065.     EXECUTE msdb.dbo.sp_delete_operator @name = N'MSXOperator'
  3066.  
  3067.   RETURN(0) -- 0 means success
  3068. END
  3069. go
  3070.  
  3071. /**************************************************************/
  3072. /* SP_GET_SQLAGENT_PROPERTIES                                 */
  3073. /**************************************************************/
  3074.  
  3075. PRINT ''
  3076. PRINT 'Creating procedure sp_get_sqlagent_properties...'
  3077. go
  3078. IF (EXISTS (SELECT *
  3079.             FROM msdb.dbo.sysobjects
  3080.             WHERE (name = N'sp_get_sqlagent_properties')
  3081.               AND (type = 'P')))
  3082.   DROP PROCEDURE sp_get_sqlagent_properties
  3083. go
  3084. CREATE PROCEDURE sp_get_sqlagent_properties
  3085. AS
  3086. BEGIN
  3087.   DECLARE @auto_start                  INT
  3088.   DECLARE @startup_account             NVARCHAR(100)
  3089.   DECLARE @msx_server_name             NVARCHAR(30)
  3090.  
  3091.   -- Non-SQLDMO exposed properties
  3092.   DECLARE @sqlserver_restart           INT
  3093.   DECLARE @jobhistory_max_rows         INT
  3094.   DECLARE @jobhistory_max_rows_per_job INT
  3095.   DECLARE @errorlog_file               NVARCHAR(255)
  3096.   DECLARE @errorlogging_level          INT
  3097.   DECLARE @error_recipient             NVARCHAR(30)
  3098.   DECLARE @monitor_autostart           INT
  3099.   DECLARE @local_host_server           NVARCHAR(30)
  3100.   DECLARE @job_shutdown_timeout        INT
  3101.   DECLARE @cmdexec_account             VARBINARY(64)
  3102.   DECLARE @regular_connections         INT
  3103.   DECLARE @host_login_name             sysname
  3104.   DECLARE @host_login_password         VARBINARY(64)
  3105.   DECLARE @login_timeout               INT
  3106.   DECLARE @idle_cpu_percent            INT
  3107.   DECLARE @idle_cpu_duration           INT
  3108.   DECLARE @oem_errorlog                INT
  3109.   DECLARE @sysadmin_only               INT
  3110.   DECLARE @email_profile               NVARCHAR(64)
  3111.   DECLARE @email_save_in_sent_folder   INT
  3112.   DECLARE @cpu_poller_enabled          INT
  3113.  
  3114.   SET NOCOUNT ON
  3115.  
  3116.   -- NOTE: We return all SQLServerAgent properties at one go for performance reasons
  3117.  
  3118.   -- Read the values from the registry
  3119.   IF ((PLATFORM() & 0x1) = 0x1) -- NT
  3120.   BEGIN
  3121.     DECLARE @key NVARCHAR(200)
  3122.  
  3123.     SELECT @key = N'SYSTEM\CurrentControlSet\Services\'
  3124.     IF (SERVERPROPERTY('INSTANCENAME') IS NOT NULL)
  3125.       SELECT @key = @key + N'SQLAgent$' + CONVERT (sysname, SERVERPROPERTY('INSTANCENAME'))
  3126.     ELSE
  3127.       SELECT @key = @key + N'SQLServerAgent'
  3128.  
  3129.     EXECUTE master.dbo.xp_regread N'HKEY_LOCAL_MACHINE',
  3130.                                   @key,
  3131.                                   N'Start',
  3132.                                   @auto_start OUTPUT,
  3133.                                   N'no_output'
  3134.     EXECUTE master.dbo.xp_regread N'HKEY_LOCAL_MACHINE',
  3135.                                   @key,
  3136.                                   N'ObjectName',
  3137.                                   @startup_account OUTPUT,
  3138.                                   N'no_output'
  3139.   END
  3140.   ELSE
  3141.   BEGIN
  3142.     SELECT @auto_start = 3 -- Manual start
  3143.     SELECT @startup_account = NULL
  3144.   END
  3145.   EXECUTE master.dbo.xp_instance_regread N'HKEY_LOCAL_MACHINE',
  3146.                                          N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
  3147.                                          N'MSXServerName',
  3148.                                          @msx_server_name OUTPUT,
  3149.                                          N'no_output'
  3150.  
  3151.   -- Non-SQLDMO exposed properties
  3152.   EXECUTE master.dbo.xp_instance_regread N'HKEY_LOCAL_MACHINE',
  3153.                                          N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
  3154.                                          N'RestartSQLServer',
  3155.                                          @sqlserver_restart OUTPUT,
  3156.                                          N'no_output'
  3157.   EXECUTE master.dbo.xp_instance_regread N'HKEY_LOCAL_MACHINE',
  3158.                                          N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
  3159.                                          N'JobHistoryMaxRows',
  3160.                                          @jobhistory_max_rows OUTPUT,
  3161.                                          N'no_output'
  3162.   EXECUTE master.dbo.xp_instance_regread N'HKEY_LOCAL_MACHINE',
  3163.                                          N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
  3164.                                          N'JobHistoryMaxRowsPerJob',
  3165.                                          @jobhistory_max_rows_per_job OUTPUT,
  3166.                                          N'no_output'
  3167.   EXECUTE master.dbo.xp_instance_regread N'HKEY_LOCAL_MACHINE',
  3168.                                          N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
  3169.                                          N'ErrorLogFile',
  3170.                                          @errorlog_file OUTPUT,
  3171.                                          N'no_output'
  3172.   EXECUTE master.dbo.xp_instance_regread N'HKEY_LOCAL_MACHINE',
  3173.                                          N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
  3174.                                          N'ErrorLoggingLevel',
  3175.                                          @errorlogging_level OUTPUT,
  3176.                                          N'no_output'
  3177.   EXECUTE master.dbo.xp_instance_regread N'HKEY_LOCAL_MACHINE',
  3178.                                          N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
  3179.                                          N'ErrorMonitor',
  3180.                                          @error_recipient OUTPUT,
  3181.                                          N'no_output'
  3182.   EXECUTE master.dbo.xp_instance_regread N'HKEY_LOCAL_MACHINE',
  3183.                                          N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
  3184.                                          N'MonitorAutoStart',
  3185.                                          @monitor_autostart OUTPUT,
  3186.                                          N'no_output'
  3187.   EXECUTE master.dbo.xp_instance_regread N'HKEY_LOCAL_MACHINE',
  3188.                                          N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
  3189.                                          N'ServerHost',
  3190.                                          @local_host_server OUTPUT,
  3191.                                          N'no_output'
  3192.   EXECUTE master.dbo.xp_instance_regread N'HKEY_LOCAL_MACHINE',
  3193.                                          N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
  3194.                                          N'JobShutdownTimeout',
  3195.                                          @job_shutdown_timeout OUTPUT,
  3196.                                          N'no_output'
  3197.   EXECUTE master.dbo.xp_instance_regread N'HKEY_LOCAL_MACHINE',
  3198.                                          N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
  3199.                                          N'CmdExecAccount',
  3200.                                          @cmdexec_account OUTPUT,
  3201.                                          N'no_output'
  3202.   EXECUTE master.dbo.xp_instance_regread N'HKEY_LOCAL_MACHINE',
  3203.                                          N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
  3204.                                          N'RegularConnections',
  3205.                                          @regular_connections OUTPUT,
  3206.                                          N'no_output'
  3207.   DECLARE @OS int
  3208.   EXECUTE master.dbo.xp_MSplatform @OS OUTPUT
  3209.  
  3210.   IF (@OS = 2)
  3211.   EXECUTE master.dbo.xp_instance_regread N'HKEY_LOCAL_MACHINE',
  3212.                                          N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
  3213.                                          N'HostLoginID',
  3214.                                          @host_login_name OUTPUT,
  3215.                                          N'no_output'
  3216.   ELSE
  3217.   EXECUTE master.dbo.xp_sqlagent_param   0, 
  3218.                                          N'HostLoginID',
  3219.                                          @host_login_name OUTPUT
  3220.  
  3221.   IF (@OS = 2)
  3222.   EXECUTE master.dbo.xp_instance_regread N'HKEY_LOCAL_MACHINE',
  3223.                                          N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
  3224.                                          N'HostPassword',
  3225.                                          @host_login_password OUTPUT,
  3226.                                          N'no_output'
  3227.   ELSE
  3228.   EXECUTE master.dbo.xp_sqlagent_param   0, 
  3229.                                          N'HostPassword',
  3230.                                          @host_login_password OUTPUT
  3231.  
  3232.   EXECUTE master.dbo.xp_instance_regread N'HKEY_LOCAL_MACHINE',
  3233.                                          N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
  3234.                                          N'LoginTimeout',
  3235.                                          @login_timeout OUTPUT,
  3236.                                          N'no_output'
  3237.   EXECUTE master.dbo.xp_instance_regread N'HKEY_LOCAL_MACHINE',
  3238.                                          N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
  3239.                                          N'IdleCPUPercent',
  3240.                                          @idle_cpu_percent OUTPUT,
  3241.                                          N'no_output'
  3242.   EXECUTE master.dbo.xp_instance_regread N'HKEY_LOCAL_MACHINE',
  3243.                                          N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
  3244.                                          N'IdleCPUDuration',
  3245.                                          @idle_cpu_duration OUTPUT,
  3246.                                          N'no_output'
  3247.   EXECUTE master.dbo.xp_instance_regread N'HKEY_LOCAL_MACHINE',
  3248.                                          N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
  3249.                                          N'OemErrorLog',
  3250.                                          @oem_errorlog OUTPUT,
  3251.                                          N'no_output'
  3252.   EXECUTE master.dbo.xp_instance_regread N'HKEY_LOCAL_MACHINE',
  3253.                                          N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
  3254.                                          N'SysAdminOnly',
  3255.                                          @sysadmin_only OUTPUT,
  3256.                                          N'no_output'
  3257.   EXECUTE master.dbo.xp_instance_regread N'HKEY_LOCAL_MACHINE',
  3258.                                          N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
  3259.                                          N'EmailProfile',
  3260.                                          @email_profile OUTPUT,
  3261.                                          N'no_output'
  3262.   EXECUTE master.dbo.xp_instance_regread N'HKEY_LOCAL_MACHINE',
  3263.                                          N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
  3264.                                          N'EmailSaveSent',
  3265.                                          @email_save_in_sent_folder OUTPUT,
  3266.                                          N'no_output'
  3267.   EXECUTE master.dbo.xp_instance_regread N'HKEY_LOCAL_MACHINE',
  3268.                                          N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
  3269.                                          N'CoreEngineMask',
  3270.                                          @cpu_poller_enabled OUTPUT,
  3271.                                          N'no_output'
  3272.   IF (@cpu_poller_enabled IS NOT NULL)
  3273.     SELECT @cpu_poller_enabled = CASE WHEN (@cpu_poller_enabled & 32) = 32 THEN 0 ELSE 1 END
  3274.  
  3275.   -- Return the values to the client
  3276.   SELECT auto_start = CASE @auto_start
  3277.                         WHEN 2 THEN 1 -- 2 means auto-start
  3278.                         WHEN 3 THEN 0 -- 3 means don't auto-start
  3279.                         ELSE 0        -- Safety net
  3280.                       END,
  3281.          msx_server_name = @msx_server_name,
  3282.          sqlagent_type = (SELECT CASE
  3283.                                     WHEN (COUNT(*) = 0) AND (ISNULL(DATALENGTH(@msx_server_name), 0) = 0) THEN 1 -- Standalone
  3284.                                     WHEN (COUNT(*) = 0) AND (ISNULL(DATALENGTH(@msx_server_name), 0) > 0) THEN 2 -- TSX
  3285.                                     WHEN (COUNT(*) > 0) AND (ISNULL(DATALENGTH(@msx_server_name), 0) = 0) THEN 3 -- MSX
  3286.                                     WHEN (COUNT(*) > 0) AND (ISNULL(DATALENGTH(@msx_server_name), 0) > 0) THEN 0 -- Multi-Level MSX (currently invalid)
  3287.                                     ELSE 0 -- Invalid
  3288.                                   END
  3289.                            FROM msdb.dbo.systargetservers),
  3290.          startup_account = @startup_account,
  3291.  
  3292.          -- Non-SQLDMO exposed properties
  3293.          sqlserver_restart = @sqlserver_restart,
  3294.          jobhistory_max_rows = @jobhistory_max_rows,
  3295.          jobhistory_max_rows_per_job = @jobhistory_max_rows_per_job,
  3296.          errorlog_file = @errorlog_file,
  3297.          errorlogging_level = ISNULL(@errorlogging_level, 7),
  3298.          error_recipient = @error_recipient,
  3299.          monitor_autostart = ISNULL(@monitor_autostart, 0),
  3300.          local_host_server = @local_host_server,
  3301.          job_shutdown_timeout = ISNULL(@job_shutdown_timeout, 15),
  3302.          cmdexec_account = @cmdexec_account,
  3303.          regular_connections = ISNULL(@regular_connections, 0),
  3304.          host_login_name = @host_login_name,
  3305.          host_login_password = @host_login_password,
  3306.          login_timeout = ISNULL(@login_timeout, 30),
  3307.          idle_cpu_percent = ISNULL(@idle_cpu_percent, 10),
  3308.          idle_cpu_duration = ISNULL(@idle_cpu_duration, 600),
  3309.          oem_errorlog = ISNULL(@oem_errorlog, 0),
  3310.          sysadmin_only = ISNULL(@sysadmin_only, 0),
  3311.          email_profile = @email_profile,
  3312.          email_save_in_sent_folder = ISNULL(@email_save_in_sent_folder, 0),
  3313.          cpu_poller_enabled = ISNULL(@cpu_poller_enabled, 0)
  3314. END
  3315. go
  3316.  
  3317. /**************************************************************/
  3318. /* SP_SET_SQLAGENT_PROPERTIES                                 */
  3319. /**************************************************************/
  3320.  
  3321. PRINT ''
  3322. PRINT 'Creating procedure sp_set_sqlagent_properties...'
  3323. go
  3324. IF (EXISTS (SELECT *
  3325.             FROM msdb.dbo.sysobjects
  3326.             WHERE (name = N'sp_set_sqlagent_properties')
  3327.               AND (type = 'P')))
  3328.   DROP PROCEDURE sp_set_sqlagent_properties
  3329. go
  3330. CREATE PROCEDURE sp_set_sqlagent_properties
  3331.   @auto_start                  INT           = NULL, -- 1 or 0
  3332.  
  3333.   -- Non-SQLDMO exposed properties
  3334.   @sqlserver_restart           INT           = NULL, -- 1 or 0
  3335.   @jobhistory_max_rows         INT           = NULL, -- No maximum = -1, otherwise must be > 1
  3336.   @jobhistory_max_rows_per_job INT           = NULL, -- 1 to @jobhistory_max_rows
  3337.   @errorlog_file               NVARCHAR(255) = NULL, -- Full drive\path\name of errorlog file
  3338.   @errorlogging_level          INT           = NULL, -- 1 = error, 2 = warning, 4 = information
  3339.   @error_recipient             NVARCHAR(30)  = NULL, -- Network address of error popup recipient
  3340.   @monitor_autostart           INT           = NULL, -- 1 or 0
  3341.   @local_host_server           NVARCHAR(30)  = NULL, -- Alias of local host server
  3342.   @job_shutdown_timeout        INT           = NULL, -- 5 to 600 seconds
  3343.   @cmdexec_account             VARBINARY(64) = NULL, -- CmdExec account information
  3344.   @regular_connections         INT           = NULL, -- 1 or 0
  3345.   @host_login_name             sysname       = NULL, -- Login name (if regular_connections = 1)
  3346.   @host_login_password         VARBINARY(64) = NULL, -- Login password (if regular_connections = 1)
  3347.   @login_timeout               INT           = NULL, -- 5 to 45 (seconds)
  3348.   @idle_cpu_percent            INT           = NULL, -- 1 to 100
  3349.   @idle_cpu_duration           INT           = NULL, -- 20 to 86400 seconds
  3350.   @oem_errorlog                INT           = NULL, -- 1 or 0
  3351.   @sysadmin_only               INT           = NULL, -- 1 or 0
  3352.   @email_profile               NVARCHAR(64)  = NULL, -- Email profile name
  3353.   @email_save_in_sent_folder   INT           = NULL, -- 1 or 0
  3354.   @cpu_poller_enabled          INT           = NULL  -- 1 or 0
  3355. AS
  3356. BEGIN
  3357.   -- NOTE: We set all SQLServerAgent properties at one go for performance reasons.
  3358.   -- NOTE: You cannot set the value of the properties msx_server_name, is_msx or
  3359.   --       startup_account - they are all read only.
  3360.  
  3361.   DECLARE @res_valid_range           NVARCHAR(100)
  3362.   DECLARE @existing_core_engine_mask INT
  3363.  
  3364.   SET NOCOUNT ON
  3365.  
  3366.   -- Remove any leading/trailing spaces from parameters
  3367.   SELECT @errorlog_file     = LTRIM(RTRIM(@errorlog_file))
  3368.   SELECT @error_recipient   = LTRIM(RTRIM(@error_recipient))
  3369.   SELECT @local_host_server = LTRIM(RTRIM(@local_host_server))
  3370.   SELECT @host_login_name   = LTRIM(RTRIM(@host_login_name))
  3371.   SELECT @email_profile     = LTRIM(RTRIM(@email_profile))
  3372.  
  3373.   -- Make sure values (if supplied) are good
  3374.   IF (@auto_start IS NOT NULL)
  3375.   BEGIN
  3376.     -- NOTE: When setting the the services start value, 2 == auto-start, 3 == Don't auto-start
  3377.     SELECT @auto_start = CASE @auto_start
  3378.                            WHEN 0 THEN 3
  3379.                            WHEN 1 THEN 2
  3380.                            ELSE 3 -- Assume non auto-start if passed a junk value
  3381.                           END
  3382.   END
  3383.  
  3384.   -- Non-SQLDMO exposed properties
  3385.   IF ((@sqlserver_restart IS NOT NULL) AND (@sqlserver_restart <> 0))
  3386.     SELECT @sqlserver_restart = 1
  3387.  
  3388.   IF (@jobhistory_max_rows IS NOT NULL)
  3389.   BEGIN
  3390.     SELECT @res_valid_range = FORMATMESSAGE(14207)
  3391.     IF ((@jobhistory_max_rows < -1) OR (@jobhistory_max_rows = 0))
  3392.     BEGIN
  3393.       RAISERROR(14266, -1, -1, '@jobhistory_max_rows', @res_valid_range)
  3394.       RETURN(1) -- Failure
  3395.     END
  3396.   END
  3397.   ELSE
  3398.   BEGIN
  3399.     EXECUTE master.dbo.xp_instance_regread N'HKEY_LOCAL_MACHINE',
  3400.                                            N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
  3401.                                            N'JobHistoryMaxRows',
  3402.                                            @jobhistory_max_rows OUTPUT,
  3403.                                            N'no_output'
  3404.     SELECT @jobhistory_max_rows = ISNULL(@jobhistory_max_rows, -1)
  3405.   END
  3406.  
  3407.   IF (@jobhistory_max_rows_per_job IS NOT NULL)
  3408.   BEGIN
  3409.     IF (@jobhistory_max_rows = -1)
  3410.       SELECT @jobhistory_max_rows_per_job = 0
  3411.     ELSE
  3412.     BEGIN
  3413.       IF ((@jobhistory_max_rows_per_job < 1) OR (@jobhistory_max_rows_per_job > @jobhistory_max_rows))
  3414.       BEGIN
  3415.         SELECT @res_valid_range = N'1..' + CONVERT(NVARCHAR, @jobhistory_max_rows)
  3416.         RAISERROR(14266, -1, -1, '@jobhistory_max_rows', @res_valid_range)
  3417.         RETURN(1) -- Failure
  3418.       END
  3419.     END
  3420.   END
  3421.  
  3422.   IF (@errorlogging_level IS NOT NULL) AND ((@errorlogging_level < 1) OR (@errorlogging_level > 7))
  3423.   BEGIN
  3424.     RAISERROR(14266, -1, -1, '@errorlogging_level', '1..7')
  3425.     RETURN(1) -- Failure
  3426.   END
  3427.  
  3428.   IF (@monitor_autostart IS NOT NULL) AND ((@monitor_autostart < 0) OR (@monitor_autostart > 1))
  3429.   BEGIN
  3430.     RAISERROR(14266, -1, -1, '@monitor_autostart', '0, 1')
  3431.     RETURN(1) -- Failure
  3432.   END
  3433.  
  3434.   IF (@job_shutdown_timeout IS NOT NULL) AND ((@job_shutdown_timeout < 5) OR (@job_shutdown_timeout > 600))
  3435.   BEGIN
  3436.     RAISERROR(14266, -1, -1, '@job_shutdown_timeout', '5..600')
  3437.     RETURN(1) -- Failure
  3438.   END
  3439.  
  3440.   IF (@regular_connections IS NOT NULL) AND ((@regular_connections < 0) OR (@regular_connections > 1))
  3441.   BEGIN
  3442.     RAISERROR(14266, -1, -1, '@regular_connections', '0, 1')
  3443.     RETURN(1) -- Failure
  3444.   END
  3445.  
  3446.   IF (@login_timeout IS NOT NULL) AND ((@login_timeout < 5) OR (@login_timeout > 45))
  3447.   BEGIN
  3448.     RAISERROR(14266, -1, -1, '@login_timeout', '5..45')
  3449.     RETURN(1) -- Failure
  3450.   END
  3451.  
  3452.   IF ((@idle_cpu_percent IS NOT NULL) AND ((@idle_cpu_percent < 1) OR (@idle_cpu_percent > 100)))
  3453.   BEGIN
  3454.     RAISERROR(14266, -1, -1, '@idle_cpu_percent', '10..100')
  3455.     RETURN(1) -- Failure
  3456.   END
  3457.  
  3458.   IF ((@idle_cpu_duration IS NOT NULL) AND ((@idle_cpu_duration < 20) OR (@idle_cpu_duration > 86400)))
  3459.   BEGIN
  3460.     RAISERROR(14266, -1, -1, '@idle_cpu_duration', '20..86400')
  3461.     RETURN(1) -- Failure
  3462.   END
  3463.  
  3464.   IF (@oem_errorlog IS NOT NULL) AND ((@oem_errorlog < 0) OR (@oem_errorlog > 1))
  3465.   BEGIN
  3466.     RAISERROR(14266, -1, -1, '@oem_errorlog', '0, 1')
  3467.     RETURN(1) -- Failure
  3468.   END
  3469.  
  3470.   IF (@sysadmin_only IS NOT NULL) AND ((@sysadmin_only < 0) OR (@sysadmin_only > 1))
  3471.   BEGIN
  3472.     RAISERROR(14266, -1, -1, '@sysadmin_only', '0, 1')
  3473.     RETURN(1) -- Failure
  3474.   END
  3475.  
  3476.   IF (@email_save_in_sent_folder IS NOT NULL) AND ((@email_save_in_sent_folder < 0) OR (@email_save_in_sent_folder > 1))
  3477.   BEGIN
  3478.     RAISERROR(14266, -1, -1, 'email_save_in_sent_folder', '0, 1')
  3479.     RETURN(1) -- Failure
  3480.   END
  3481.  
  3482.   IF (@cpu_poller_enabled IS NOT NULL) AND ((@cpu_poller_enabled < 0) OR (@cpu_poller_enabled > 1))
  3483.   BEGIN
  3484.     RAISERROR(14266, -1, -1, 'cpu_poller_enabled', '0, 1')
  3485.     RETURN(1) -- Failure
  3486.   END
  3487.  
  3488.   -- Write out the values
  3489.   IF (@auto_start IS NOT NULL)
  3490.   BEGIN
  3491.     IF ((PLATFORM() & 0x1) = 0x1) -- NT
  3492.     BEGIN
  3493.       DECLARE @key NVARCHAR(200)
  3494.  
  3495.       SELECT @key = N'SYSTEM\CurrentControlSet\Services\'
  3496.       IF (SERVERPROPERTY('INSTANCENAME') IS NOT NULL)
  3497.         SELECT @key = @key + N'SQLAgent$' + CONVERT (sysname, SERVERPROPERTY('INSTANCENAME'))
  3498.       ELSE
  3499.         SELECT @key = @key + N'SQLServerAgent'
  3500.  
  3501.       EXECUTE master.dbo.xp_regwrite N'HKEY_LOCAL_MACHINE',
  3502.                                      @key,
  3503.                                      N'Start',
  3504.                                      N'REG_DWORD',
  3505.                                      @auto_start
  3506.     END
  3507.     ELSE
  3508.       RAISERROR(14546, 16, 1, '@auto_start')
  3509.   END
  3510.  
  3511.   -- Non-SQLDMO exposed properties
  3512.   IF (@sqlserver_restart IS NOT NULL)
  3513.     EXECUTE master.dbo.xp_instance_regwrite N'HKEY_LOCAL_MACHINE',
  3514.                                             N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
  3515.                                             N'RestartSQLServer',
  3516.                                             N'REG_DWORD',
  3517.                                             @sqlserver_restart
  3518.   IF (@jobhistory_max_rows IS NOT NULL)
  3519.     EXECUTE master.dbo.xp_instance_regwrite N'HKEY_LOCAL_MACHINE',
  3520.                                             N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
  3521.                                             N'JobHistoryMaxRows',
  3522.                                             N'REG_DWORD',
  3523.                                             @jobhistory_max_rows
  3524.   IF (@jobhistory_max_rows_per_job IS NOT NULL)
  3525.     EXECUTE master.dbo.xp_instance_regwrite N'HKEY_LOCAL_MACHINE',
  3526.                                             N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
  3527.                                             N'JobHistoryMaxRowsPerJob',
  3528.                                             N'REG_DWORD',
  3529.                                             @jobhistory_max_rows_per_job
  3530.   IF (@errorlog_file IS NOT NULL)
  3531.     EXECUTE master.dbo.xp_instance_regwrite N'HKEY_LOCAL_MACHINE',
  3532.                                             N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
  3533.                                             N'ErrorLogFile',
  3534.                                             N'REG_SZ',
  3535.                                             @errorlog_file
  3536.   IF (@errorlogging_level IS NOT NULL)
  3537.     EXECUTE master.dbo.xp_instance_regwrite N'HKEY_LOCAL_MACHINE',
  3538.                                             N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
  3539.                                             N'ErrorLoggingLevel',
  3540.                                             N'REG_DWORD',
  3541.                                             @errorlogging_level
  3542.   IF (@error_recipient IS NOT NULL)
  3543.     EXECUTE master.dbo.xp_instance_regwrite N'HKEY_LOCAL_MACHINE',
  3544.                                             N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
  3545.                                             N'ErrorMonitor',
  3546.                                             N'REG_SZ',
  3547.                                             @error_recipient
  3548.   IF (@monitor_autostart IS NOT NULL)
  3549.     EXECUTE master.dbo.xp_instance_regwrite N'HKEY_LOCAL_MACHINE',
  3550.                                             N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
  3551.                                             N'MonitorAutoStart',
  3552.                                             N'REG_DWORD',
  3553.                                             @monitor_autostart
  3554.   IF (@local_host_server IS NOT NULL)
  3555.     EXECUTE master.dbo.xp_instance_regwrite N'HKEY_LOCAL_MACHINE',
  3556.                                             N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
  3557.                                             N'ServerHost',
  3558.                                             N'REG_SZ',
  3559.                                             @local_host_server
  3560.   IF (@job_shutdown_timeout IS NOT NULL)
  3561.     EXECUTE master.dbo.xp_instance_regwrite N'HKEY_LOCAL_MACHINE',
  3562.                                             N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
  3563.                                             N'JobShutdownTimeout',
  3564.                                             N'REG_DWORD',
  3565.                                             @job_shutdown_timeout
  3566.   IF (@cmdexec_account IS NOT NULL)
  3567.     EXECUTE master.dbo.xp_instance_regwrite N'HKEY_LOCAL_MACHINE',
  3568.                                             N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
  3569.                                             N'CmdExecAccount',
  3570.                                             N'REG_BINARY',
  3571.                                             @cmdexec_account
  3572.   IF (@regular_connections IS NOT NULL)
  3573.     EXECUTE master.dbo.xp_instance_regwrite N'HKEY_LOCAL_MACHINE',
  3574.                                             N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
  3575.                                             N'RegularConnections',
  3576.                                             N'REG_DWORD',
  3577.                                             @regular_connections
  3578.   DECLARE @OS int
  3579.   EXECUTE master.dbo.xp_MSplatform @OS OUTPUT
  3580.  
  3581.   IF (@host_login_name IS NOT NULL)
  3582.   BEGIN
  3583.     IF (@OS = 2)
  3584.     EXECUTE master.dbo.xp_instance_regwrite N'HKEY_LOCAL_MACHINE',
  3585.                                             N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
  3586.                                             N'HostLoginID',
  3587.                                             N'REG_SZ',
  3588.                                             @host_login_name
  3589.     ELSE
  3590.     EXECUTE master.dbo.xp_sqlagent_param    1,
  3591.                                             N'HostLoginID',
  3592.                                             @host_login_name
  3593.   END
  3594.  
  3595.   IF (@host_login_password IS NOT NULL)
  3596.   BEGIN
  3597.     IF (@OS = 2)
  3598.     EXECUTE master.dbo.xp_instance_regwrite N'HKEY_LOCAL_MACHINE',
  3599.                                             N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
  3600.                                             N'HostPassword',
  3601.                                             N'REG_BINARY',
  3602.                                             @host_login_password
  3603.     ELSE
  3604.     EXECUTE master.dbo.xp_sqlagent_param    1,
  3605.                                             N'HostPassword',
  3606.                                             @host_login_password
  3607.   END
  3608.  
  3609.   IF (@login_timeout IS NOT NULL)
  3610.     EXECUTE master.dbo.xp_instance_regwrite N'HKEY_LOCAL_MACHINE',
  3611.                                             N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
  3612.                                             N'LoginTimeout',
  3613.                                             N'REG_DWORD',
  3614.                                             @login_timeout
  3615.   IF (@idle_cpu_percent IS NOT NULL)
  3616.     EXECUTE master.dbo.xp_instance_regwrite N'HKEY_LOCAL_MACHINE',
  3617.                                             N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
  3618.                                             N'IdleCPUPercent',
  3619.                                             N'REG_DWORD',
  3620.                                             @idle_cpu_percent
  3621.   IF (@idle_cpu_duration IS NOT NULL)
  3622.     EXECUTE master.dbo.xp_instance_regwrite N'HKEY_LOCAL_MACHINE',
  3623.                                             N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
  3624.                                             N'IdleCPUDuration',
  3625.                                             N'REG_DWORD',
  3626.                                             @idle_cpu_duration
  3627.   IF (@oem_errorlog IS NOT NULL)
  3628.     EXECUTE master.dbo.xp_instance_regwrite N'HKEY_LOCAL_MACHINE',
  3629.                                             N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
  3630.                                             N'OemErrorLog',
  3631.                                             N'REG_DWORD',
  3632.                                             @oem_errorlog
  3633.   IF (@sysadmin_only IS NOT NULL)
  3634.     EXECUTE master.dbo.xp_instance_regwrite N'HKEY_LOCAL_MACHINE',
  3635.                                             N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
  3636.                                             N'SysAdminOnly',
  3637.                                             N'REG_DWORD',
  3638.                                             @sysadmin_only
  3639.   IF (@email_profile IS NOT NULL)
  3640.     EXECUTE master.dbo.xp_instance_regwrite N'HKEY_LOCAL_MACHINE',
  3641.                                             N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
  3642.                                             N'EmailProfile',
  3643.                                             N'REG_SZ',
  3644.                                             @email_profile
  3645.   IF (@email_save_in_sent_folder IS NOT NULL)
  3646.     EXECUTE master.dbo.xp_instance_regwrite N'HKEY_LOCAL_MACHINE',
  3647.                                             N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
  3648.                                             N'EmailSaveSent',
  3649.                                             N'REG_DWORD',
  3650.                                             @email_save_in_sent_folder
  3651.   IF (@cpu_poller_enabled IS NOT NULL)
  3652.   BEGIN
  3653.     EXECUTE master.dbo.xp_instance_regread N'HKEY_LOCAL_MACHINE',
  3654.                                            N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
  3655.                                            N'CoreEngineMask',
  3656.                                            @existing_core_engine_mask OUTPUT,
  3657.                                            N'no_output'
  3658.     IF ((@existing_core_engine_mask IS NOT NULL) OR (@cpu_poller_enabled = 1))
  3659.     BEGIN
  3660.       IF (@cpu_poller_enabled = 1)
  3661.         SELECT @cpu_poller_enabled = (ISNULL(@existing_core_engine_mask, 0) & ~32)
  3662.       ELSE
  3663.         SELECT @cpu_poller_enabled = (ISNULL(@existing_core_engine_mask, 0) | 32)
  3664.  
  3665.       IF ((@existing_core_engine_mask IS NOT NULL) AND (@cpu_poller_enabled = 32))
  3666.         EXECUTE master.dbo.xp_instance_regdeletevalue N'HKEY_LOCAL_MACHINE',
  3667.                                                       N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
  3668.                                                       N'CoreEngineMask'
  3669.       ELSE
  3670.         EXECUTE master.dbo.xp_instance_regwrite N'HKEY_LOCAL_MACHINE',
  3671.                                                 N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
  3672.                                                 N'CoreEngineMask',
  3673.                                                 N'REG_DWORD',
  3674.                                                 @cpu_poller_enabled
  3675.     END
  3676.   END
  3677.  
  3678.   RETURN(0) -- Success
  3679. END
  3680. go
  3681.  
  3682. /**************************************************************/
  3683. /* SP_ADD_TARGETSERVERGROUP                                   */
  3684. /**************************************************************/
  3685.  
  3686. PRINT ''
  3687. PRINT 'Creating procedure sp_add_targetservergroup...'
  3688. go
  3689. IF (EXISTS (SELECT *
  3690.             FROM msdb.dbo.sysobjects
  3691.             WHERE (name = N'sp_add_targetservergroup')
  3692.               AND (type = 'P')))
  3693.   DROP PROCEDURE sp_add_targetservergroup
  3694. go
  3695. CREATE PROCEDURE sp_add_targetservergroup
  3696.   @name sysname
  3697. AS
  3698. BEGIN
  3699.   SET NOCOUNT ON
  3700.  
  3701.   -- Only a sysadmin can do this
  3702.   IF (ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) <> 1)
  3703.   BEGIN
  3704.     RAISERROR(15003, 16, 1, N'sysadmin')
  3705.     RETURN(1) -- Failure
  3706.   END
  3707.  
  3708.   -- Remove any leading/trailing spaces from parameters
  3709.   SELECT @name = LTRIM(RTRIM(@name))
  3710.  
  3711.   -- Check if the group already exists
  3712.   IF (EXISTS (SELECT *
  3713.               FROM msdb.dbo.systargetservergroups
  3714.               WHERE name = @name))
  3715.   BEGIN
  3716.     RAISERROR(14261, -1, -1, '@name', @name)
  3717.     RETURN(1) -- Failure
  3718.   END
  3719.  
  3720.   -- Disallow names with commas in them (since sp_apply_job_to_targets parses a comma-separated list of group names)
  3721.   IF (@name LIKE N'%,%')
  3722.   BEGIN
  3723.     RAISERROR(14289, -1, -1, '@name', ',')
  3724.     RETURN(1) -- Failure
  3725.   END
  3726.  
  3727.   INSERT INTO msdb.dbo.systargetservergroups (name)
  3728.   VALUES (@name)
  3729.  
  3730.   RETURN(@@error) -- 0 means success
  3731. END
  3732. go
  3733.  
  3734. /**************************************************************/
  3735. /* SP_UPDATE_TARGETSERVERGROUP                                */
  3736. /**************************************************************/
  3737.  
  3738. PRINT ''
  3739. PRINT 'Creating procedure sp_update_targetservergroup...'
  3740. go
  3741. IF (EXISTS (SELECT *
  3742.             FROM msdb.dbo.sysobjects
  3743.             WHERE (name = N'sp_update_targetservergroup')
  3744.               AND (type = 'P')))
  3745.   DROP PROCEDURE sp_update_targetservergroup
  3746. go
  3747. CREATE PROCEDURE sp_update_targetservergroup
  3748.   @name     sysname,
  3749.   @new_name sysname
  3750. AS
  3751. BEGIN
  3752.   SET NOCOUNT ON
  3753.  
  3754.   -- Only a sysadmin can do this
  3755.   IF (ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) <> 1)
  3756.   BEGIN
  3757.     RAISERROR(15003, 16, 1, N'sysadmin')
  3758.     RETURN(1) -- Failure
  3759.   END
  3760.  
  3761.   -- Remove any leading/trailing spaces from parameters
  3762.   SELECT @name     = LTRIM(RTRIM(@name))
  3763.   SELECT @new_name = LTRIM(RTRIM(@new_name))
  3764.  
  3765.   -- Check if the group exists
  3766.   IF (NOT EXISTS (SELECT *
  3767.                   FROM msdb.dbo.systargetservergroups
  3768.                   WHERE (name = @name)))
  3769.   BEGIN
  3770.     RAISERROR(14262, -1, -1, '@name', @name)
  3771.     RETURN(1) -- Failure
  3772.   END
  3773.  
  3774.   -- Check if a group with the new name already exists
  3775.   IF (EXISTS (SELECT *
  3776.               FROM msdb.dbo.systargetservergroups
  3777.               WHERE (name = @new_name)))
  3778.   BEGIN
  3779.     RAISERROR(14261, -1, -1, '@new_name', @new_name)
  3780.     RETURN(1) -- Failure
  3781.   END
  3782.  
  3783.   -- Disallow names with commas in them (since sp_apply_job_to_targets parses a comma-separated list of group names)
  3784.   IF (@new_name LIKE N'%,%')
  3785.   BEGIN
  3786.     RAISERROR(14289, -1, -1, '@new_name', ',')
  3787.     RETURN(1) -- Failure
  3788.   END
  3789.  
  3790.   -- Update the group's name
  3791.   UPDATE msdb.dbo.systargetservergroups
  3792.   SET name = @new_name
  3793.   WHERE (name = @name)
  3794.  
  3795.   RETURN(@@error) -- 0 means success
  3796. END
  3797. go
  3798.  
  3799. /**************************************************************/
  3800. /* SP_DELETE_TARGETSERVERGROUP                                */
  3801. /**************************************************************/
  3802.  
  3803. PRINT ''
  3804. PRINT 'Creating procedure sp_delete_targetservergroup...'
  3805. go
  3806. IF (EXISTS (SELECT *
  3807.             FROM msdb.dbo.sysobjects
  3808.             WHERE (name = N'sp_delete_targetservergroup')
  3809.               AND (type = 'P')))
  3810.   DROP PROCEDURE sp_delete_targetservergroup
  3811. go
  3812. CREATE PROCEDURE sp_delete_targetservergroup
  3813.   @name sysname
  3814. AS
  3815. BEGIN
  3816.   DECLARE @servergroup_id INT
  3817.  
  3818.   SET NOCOUNT ON
  3819.  
  3820.   -- Only a sysadmin can do this
  3821.   IF (ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) <> 1)
  3822.   BEGIN
  3823.     RAISERROR(15003, 16, 1, N'sysadmin')
  3824.     RETURN(1) -- Failure
  3825.   END
  3826.  
  3827.   -- Remove any leading/trailing spaces from parameters
  3828.   SELECT @name = LTRIM(RTRIM(@name))
  3829.  
  3830.   -- Check if the group exists
  3831.   SELECT @servergroup_id = servergroup_id
  3832.   FROM msdb.dbo.systargetservergroups
  3833.   WHERE (name = @name)
  3834.  
  3835.   IF (@servergroup_id IS NULL)
  3836.   BEGIN
  3837.     RAISERROR(14262, -1, -1, '@name', @name)
  3838.     RETURN(1) -- Failure
  3839.   END
  3840.  
  3841.   -- Remove the group members
  3842.   DELETE FROM msdb.dbo.systargetservergroupmembers
  3843.   WHERE (servergroup_id = @servergroup_id)
  3844.  
  3845.   -- Remove the group
  3846.   DELETE FROM msdb.dbo.systargetservergroups
  3847.   WHERE (name = @name)
  3848.  
  3849.   RETURN(@@error) -- 0 means success
  3850. END
  3851. go
  3852.  
  3853. /**************************************************************/
  3854. /* SP_HELP_TARGETSERVERGROUP                                  */
  3855. /**************************************************************/
  3856.  
  3857. PRINT ''
  3858. PRINT 'Creating procedure sp_help_targetservergroup...'
  3859. go
  3860. IF (EXISTS (SELECT *
  3861.             FROM msdb.dbo.sysobjects
  3862.             WHERE (name = N'sp_help_targetservergroup')
  3863.               AND (type = 'P')))
  3864.   DROP PROCEDURE sp_help_targetservergroup
  3865. go
  3866. CREATE PROCEDURE sp_help_targetservergroup
  3867.   @name sysname = NULL
  3868. AS
  3869. BEGIN
  3870.   DECLARE @servergroup_id INT
  3871.  
  3872.   SET NOCOUNT ON
  3873.  
  3874.   -- Remove any leading/trailing spaces from parameters
  3875.   SELECT @name = LTRIM(RTRIM(@name))
  3876.  
  3877.   IF (@name IS NULL)
  3878.   BEGIN
  3879.     -- Show all groups
  3880.     SELECT servergroup_id, name
  3881.     FROM msdb.dbo.systargetservergroups
  3882.     RETURN(@@error) -- 0 means success
  3883.   END
  3884.   ELSE
  3885.   BEGIN
  3886.     -- Check if the group exists
  3887.     SELECT @servergroup_id = servergroup_id
  3888.     FROM msdb.dbo.systargetservergroups
  3889.     WHERE (name = @name)
  3890.  
  3891.     IF (@servergroup_id IS NULL)
  3892.     BEGIN
  3893.       RAISERROR(14262, -1, -1, '@name', @name)
  3894.       RETURN(1) -- Failure
  3895.     END
  3896.  
  3897.     -- Return the members of the group
  3898.     SELECT sts.server_id,
  3899.            sts.server_name
  3900.     FROM msdb.dbo.systargetservers sts,
  3901.          msdb.dbo.systargetservergroupmembers stsgm
  3902.     WHERE (stsgm.servergroup_id = @servergroup_id)
  3903.       AND (stsgm.server_id = sts.server_id)
  3904.  
  3905.     RETURN(@@error) -- 0 means success
  3906.   END
  3907. END
  3908. go
  3909.  
  3910. /**************************************************************/
  3911. /* SP_ADD_TARGETSVRGRP_MEMBER                                 */
  3912. /**************************************************************/
  3913.  
  3914. PRINT ''
  3915. PRINT 'Creating procedure sp_add_targetsvgrp_member...'
  3916. go
  3917. IF (EXISTS (SELECT *
  3918.             FROM msdb.dbo.sysobjects
  3919.             WHERE (name = N'sp_add_targetsvrgrp_member')
  3920.               AND (type = 'P')))
  3921.   DROP PROCEDURE sp_add_targetsvrgrp_member
  3922. go
  3923. CREATE PROCEDURE sp_add_targetsvrgrp_member
  3924.   @group_name  sysname,
  3925.   @server_name NVARCHAR(30)
  3926. AS
  3927. BEGIN
  3928.   DECLARE @servergroup_id INT
  3929.   DECLARE @server_id      INT
  3930.  
  3931.   SET NOCOUNT ON
  3932.  
  3933.   -- Remove any leading/trailing spaces from parameters
  3934.   SELECT @group_name = LTRIM(RTRIM(@group_name))
  3935.   SELECT @server_name = LTRIM(RTRIM(@server_name))
  3936.  
  3937.   -- Check if the group exists
  3938.   SELECT @servergroup_id = servergroup_id
  3939.   FROM msdb.dbo.systargetservergroups
  3940.   WHERE (name = @group_name)
  3941.  
  3942.   IF (@servergroup_id IS NULL)
  3943.   BEGIN
  3944.     RAISERROR(14262, -1, -1, '@group_name', @group_name)
  3945.     RETURN(1) -- Failure
  3946.   END
  3947.  
  3948.   -- Check if the server exists
  3949.   SELECT @server_id = server_id
  3950.   FROM msdb.dbo.systargetservers
  3951.   WHERE (server_name = @server_name)
  3952.  
  3953.   IF (@server_id IS NULL)
  3954.   BEGIN
  3955.     RAISERROR(14262, -1, -1, '@server_name', @server_name)
  3956.     RETURN(1) -- Failure
  3957.   END
  3958.  
  3959.   -- Check if the server is already in this group
  3960.   IF (EXISTS (SELECT *
  3961.               FROM msdb.dbo.systargetservergroupmembers
  3962.               WHERE (servergroup_id = @servergroup_id)
  3963.                 AND (server_id = @server_id)))
  3964.   BEGIN
  3965.     RAISERROR(14263, -1, -1, @server_name, @group_name)
  3966.     RETURN(1) -- Failure
  3967.   END
  3968.  
  3969.   -- Add the row to systargetservergroupmembers
  3970.   INSERT INTO msdb.dbo.systargetservergroupmembers
  3971.   VALUES (@servergroup_id, @server_id)
  3972.  
  3973.   RETURN(@@error) -- 0 means success
  3974. END
  3975. go
  3976.  
  3977. /**************************************************************/
  3978. /* SP_DELETE_TARGETSVRGRP_MEMBER                              */
  3979. /**************************************************************/
  3980.  
  3981. PRINT ''
  3982. PRINT 'Creating procedure sp_delete_targetsvrgrp_member...'
  3983. go
  3984. IF (EXISTS (SELECT *
  3985.             FROM msdb.dbo.sysobjects
  3986.             WHERE (name = N'sp_delete_targetsvrgrp_member')
  3987.               AND (type = 'P')))
  3988.   DROP PROCEDURE sp_delete_targetsvrgrp_member
  3989. go
  3990. CREATE PROCEDURE sp_delete_targetsvrgrp_member
  3991.   @group_name  sysname,
  3992.   @server_name NVARCHAR(30)
  3993. AS
  3994. BEGIN
  3995.   DECLARE @servergroup_id INT
  3996.   DECLARE @server_id      INT
  3997.  
  3998.   SET NOCOUNT ON
  3999.  
  4000.   -- Remove any leading/trailing spaces from parameters
  4001.   SELECT @group_name = LTRIM(RTRIM(@group_name))
  4002.   SELECT @server_name = LTRIM(RTRIM(@server_name))
  4003.  
  4004.   -- Check if the group exists
  4005.   SELECT @servergroup_id = servergroup_id
  4006.   FROM msdb.dbo.systargetservergroups
  4007.   WHERE (name = @group_name)
  4008.  
  4009.   IF (@servergroup_id IS NULL)
  4010.   BEGIN
  4011.     RAISERROR(14262, -1, -1, '@group_name', @group_name)
  4012.     RETURN(1) -- Failure
  4013.   END
  4014.  
  4015.   -- Check if the server exists
  4016.   SELECT @server_id = server_id
  4017.   FROM msdb.dbo.systargetservers
  4018.   WHERE (server_name = @server_name)
  4019.  
  4020.   IF (@server_id IS NULL)
  4021.   BEGIN
  4022.     RAISERROR(14262, -1, -1, '@server_name', @server_name)
  4023.     RETURN(1) -- Failure
  4024.   END
  4025.  
  4026.   -- Check if the server is in the group
  4027.   IF (NOT EXISTS (SELECT *
  4028.                   FROM msdb.dbo.systargetservergroupmembers
  4029.                   WHERE (servergroup_id = @servergroup_id)
  4030.                     AND (server_id = @server_id)))
  4031.   BEGIN
  4032.     RAISERROR(14264, -1, -1, @server_name, @group_name)
  4033.     RETURN(1) -- Failure
  4034.   END
  4035.  
  4036.   -- Delete the row from systargetservergroupmembers
  4037.   DELETE FROM msdb.dbo.systargetservergroupmembers
  4038.   WHERE (servergroup_id = @servergroup_id)
  4039.     AND (server_id = @server_id)
  4040.  
  4041.   RETURN(@@error) -- 0 means success
  4042. END
  4043. go
  4044.  
  4045. /**************************************************************/
  4046. /* SP_VERIFY_CATEGORY                                         */
  4047. /**************************************************************/
  4048.  
  4049. PRINT ''
  4050. PRINT 'Creating procedure sp_verify_category...'
  4051. go
  4052. IF (EXISTS (SELECT *
  4053.             FROM msdb.dbo.sysobjects
  4054.             WHERE (name = N'sp_verify_category')
  4055.               AND (type = 'P')))
  4056.   DROP PROCEDURE sp_verify_category
  4057. go
  4058. CREATE PROCEDURE sp_verify_category
  4059.   @class          VARCHAR(8),
  4060.   @type           VARCHAR(12)  = NULL, -- Supply NULL only if you don't want it checked
  4061.   @name           sysname      = NULL, -- Supply NULL only if you don't want it checked
  4062.   @category_class INT OUTPUT,
  4063.   @category_type  INT OUTPUT           -- Supply NULL only if you don't want the return value
  4064. AS
  4065. BEGIN
  4066.   SET NOCOUNT ON
  4067.  
  4068.   -- Remove any leading/trailing spaces from parameters
  4069.   SELECT @class = LTRIM(RTRIM(@class))
  4070.   SELECT @type  = LTRIM(RTRIM(@type))
  4071.   SELECT @name  = LTRIM(RTRIM(@name))
  4072.  
  4073.   -- Turn [nullable] empty string parameters into NULLs
  4074.   IF (@type = '') SELECT @type = NULL
  4075.   IF (@name = N'') SELECT @name = NULL
  4076.  
  4077.   -- Check class
  4078.   SELECT @class = UPPER(@class)
  4079.   SELECT @category_class = CASE @class
  4080.                              WHEN 'JOB'      THEN 1
  4081.                              WHEN 'ALERT'    THEN 2
  4082.                              WHEN 'OPERATOR' THEN 3
  4083.                              ELSE 0
  4084.                            END
  4085.   IF (@category_class = 0)
  4086.   BEGIN
  4087.     RAISERROR(14266, -1, -1, '@class', 'JOB, ALERT, OPERATOR')
  4088.     RETURN(1) -- Failure
  4089.   END
  4090.  
  4091.   -- Check name
  4092.   IF ((@name IS NOT NULL) AND (@name = N'[DEFAULT]'))
  4093.   BEGIN
  4094.     RAISERROR(14200, -1, -1, '@name')
  4095.     RETURN(1) -- Failure
  4096.   END
  4097.  
  4098.   -- Check type [optionally]
  4099.   IF (@type IS NOT NULL)
  4100.   BEGIN
  4101.     IF (@class = 'JOB')
  4102.     BEGIN
  4103.       SELECT @type = UPPER(@type)
  4104.       SELECT @category_type = CASE @type
  4105.                                 WHEN 'LOCAL'        THEN 1
  4106.                                 WHEN 'MULTI-SERVER' THEN 2
  4107.                                 ELSE 0
  4108.                               END
  4109.       IF (@category_type = 0)
  4110.       BEGIN
  4111.         RAISERROR(14266, -1, -1, '@type', 'LOCAL, MULTI-SERVER')
  4112.         RETURN(1) -- Failure
  4113.       END
  4114.     END
  4115.     ELSE
  4116.     BEGIN
  4117.       IF (@type <> 'NONE')
  4118.       BEGIN
  4119.         RAISERROR(14266, -1, -1, '@type', 'NONE')
  4120.         RETURN(1) -- Failure
  4121.       END
  4122.       ELSE
  4123.         SELECT @category_type = 3
  4124.     END
  4125.   END
  4126.  
  4127.   RETURN(0) -- Success
  4128. END
  4129. go
  4130.  
  4131. /**************************************************************/
  4132. /* SP_ADD_CATEGORY                                            */
  4133. /**************************************************************/
  4134.  
  4135. PRINT ''
  4136. PRINT 'Creating procedure sp_add_category...'
  4137. go
  4138. IF (EXISTS (SELECT *
  4139.             FROM msdb.dbo.sysobjects
  4140.             WHERE (name = N'sp_add_category')
  4141.               AND (type = 'P')))
  4142.   DROP PROCEDURE sp_add_category
  4143. go
  4144. CREATE PROCEDURE sp_add_category
  4145.   @class VARCHAR(8)   = 'JOB',   -- JOB or ALERT or OPERATOR
  4146.   @type  VARCHAR(12)  = 'LOCAL', -- LOCAL or MULTI-SERVER (for JOB) or NONE otherwise
  4147.   @name  sysname
  4148. AS
  4149. BEGIN
  4150.   DECLARE @retval         INT
  4151.   DECLARE @category_type  INT
  4152.   DECLARE @category_class INT
  4153.  
  4154.   SET NOCOUNT ON
  4155.  
  4156.   -- Remove any leading/trailing spaces from parameters
  4157.   SELECT @class = LTRIM(RTRIM(@class))
  4158.   SELECT @type  = LTRIM(RTRIM(@type))
  4159.   SELECT @name  = LTRIM(RTRIM(@name))
  4160.  
  4161.   EXECUTE @retval = sp_verify_category @class,
  4162.                                        @type,
  4163.                                        @name,
  4164.                                        @category_class OUTPUT,
  4165.                                        @category_type  OUTPUT
  4166.   IF (@retval <> 0)
  4167.     RETURN(1) -- Failure
  4168.  
  4169.   -- Check name
  4170.   IF (EXISTS (SELECT *
  4171.               FROM msdb.dbo.syscategories
  4172.               WHERE (category_class = @category_class)
  4173.                 AND (name = @name)))
  4174.   BEGIN
  4175.     RAISERROR(14261, -1, -1, '@name', @name)
  4176.     RETURN(1) -- Failure
  4177.   END
  4178.  
  4179.   -- Add the row
  4180.   INSERT INTO msdb.dbo.syscategories (category_class, category_type, name)
  4181.   VALUES (@category_class, @category_type, @name)
  4182.  
  4183.   RETURN(@@error) -- 0 means success
  4184. END
  4185. go
  4186.  
  4187. /**************************************************************/
  4188. /* SP_UPDATE_CATEGORY                                         */
  4189. /**************************************************************/
  4190.  
  4191. PRINT ''
  4192. PRINT 'Creating procedure sp_update_category...'
  4193. go
  4194. IF (EXISTS (SELECT *
  4195.             FROM msdb.dbo.sysobjects
  4196.             WHERE (name = N'sp_update_category')
  4197.               AND (type = 'P')))
  4198.   DROP PROCEDURE sp_update_category
  4199. go
  4200. CREATE PROCEDURE sp_update_category
  4201.   @class    VARCHAR(8),  -- JOB or ALERT or OPERATOR
  4202.   @name     sysname,
  4203.   @new_name sysname
  4204. AS
  4205. BEGIN
  4206.   DECLARE @retval         INT
  4207.   DECLARE @category_id    INT
  4208.   DECLARE @category_class INT
  4209.  
  4210.   SET NOCOUNT ON
  4211.  
  4212.   -- Remove any leading/trailing spaces from parameters
  4213.   SELECT @class    = LTRIM(RTRIM(@class))
  4214.   SELECT @name     = LTRIM(RTRIM(@name))
  4215.   SELECT @new_name = LTRIM(RTRIM(@new_name))
  4216.  
  4217.   EXECUTE @retval = sp_verify_category @class,
  4218.                                        NULL,
  4219.                                        @new_name,
  4220.                                        @category_class OUTPUT,
  4221.                                        NULL
  4222.   IF (@retval <> 0)
  4223.     RETURN(1) -- Failure
  4224.  
  4225.   -- Check name
  4226.   SELECT @category_id = category_id
  4227.   FROM msdb.dbo.syscategories
  4228.   WHERE (category_class = @category_class)
  4229.     AND (name = @new_name)
  4230.   IF (@category_id IS NOT NULL)
  4231.   BEGIN
  4232.     RAISERROR(14261, -1, -1, '@new_name', @new_name)
  4233.     RETURN(1) -- Failure
  4234.   END
  4235.  
  4236.   -- Make sure that we're not updating one of the permanent categories (id's 0 - 99)
  4237.   IF (@category_id < 100)
  4238.   BEGIN
  4239.     RAISERROR(14276, -1, -1, @name, @class)
  4240.     RETURN(1) -- Failure
  4241.   END
  4242.  
  4243.   -- Update the category name
  4244.   UPDATE msdb.dbo.syscategories
  4245.   SET name = @new_name
  4246.   WHERE (category_class = @category_class)
  4247.     AND (name = @name)
  4248.  
  4249.   RETURN(@@error) -- 0 means success
  4250. END
  4251. go
  4252.  
  4253. /**************************************************************/
  4254. /* SP_DELETE_CATEGORY                                         */
  4255. /**************************************************************/
  4256.  
  4257. PRINT ''
  4258. PRINT 'Creating procedure sp_delete_category...'
  4259. go
  4260. IF (EXISTS (SELECT *
  4261.             FROM msdb.dbo.sysobjects
  4262.             WHERE (name = N'sp_delete_category')
  4263.               AND (type = 'P')))
  4264.   DROP PROCEDURE sp_delete_category
  4265. go
  4266. CREATE PROCEDURE sp_delete_category
  4267.   @class VARCHAR(8),  -- JOB or ALERT or OPERATOR
  4268.   @name  sysname
  4269. AS
  4270. BEGIN
  4271.   DECLARE @retval         INT
  4272.   DECLARE @category_id    INT
  4273.   DECLARE @category_class INT
  4274.   DECLARE @category_type  INT
  4275.  
  4276.   SET NOCOUNT ON
  4277.  
  4278.   -- Remove any leading/trailing spaces from parameters
  4279.   SELECT @class = LTRIM(RTRIM(@class))
  4280.   SELECT @name  = LTRIM(RTRIM(@name))
  4281.  
  4282.   EXECUTE @retval = sp_verify_category @class,
  4283.                                        NULL,
  4284.                                        NULL,
  4285.                                        @category_class OUTPUT,
  4286.                                        NULL
  4287.   IF (@retval <> 0)
  4288.     RETURN(1) -- Failure
  4289.  
  4290.   -- Check name
  4291.   SELECT @category_id = category_id,
  4292.          @category_type = category_type
  4293.   FROM msdb.dbo.syscategories
  4294.   WHERE (category_class = @category_class)
  4295.     AND (name = @name)
  4296.   IF (@category_id IS NULL)
  4297.   BEGIN
  4298.     RAISERROR(14262, -1, -1, '@name', @name)
  4299.     RETURN(1) -- Failure
  4300.   END
  4301.  
  4302.   -- Make sure that we're not deleting one of the permanent categories (id's 0 - 99)
  4303.   IF (@category_id < 100)
  4304.   BEGIN
  4305.     RAISERROR(14276, -1, -1, @name, @class)
  4306.     RETURN(1) -- Failure
  4307.   END
  4308.  
  4309.   BEGIN TRANSACTION
  4310.  
  4311.     -- Clean-up any Jobs that reference the deleted category
  4312.     UPDATE msdb.dbo.sysjobs
  4313.     SET category_id = CASE @category_type
  4314.                         WHEN 1 THEN 0 -- [Uncategorized (Local)]
  4315.                         WHEN 2 THEN 2 -- [Uncategorized (Multi-Server)]
  4316.                       END
  4317.     WHERE (category_id = @category_id)
  4318.  
  4319.     -- Clean-up any Alerts that reference the deleted category
  4320.     UPDATE msdb.dbo.sysalerts
  4321.     SET category_id = 98
  4322.     WHERE (category_id = @category_id)
  4323.  
  4324.     -- Clean-up any Operators that reference the deleted category
  4325.     UPDATE msdb.dbo.sysoperators
  4326.     SET category_id = 99
  4327.     WHERE (category_id = @category_id)
  4328.  
  4329.     -- Finally, delete the category itself
  4330.     DELETE FROM msdb.dbo.syscategories
  4331.     WHERE (category_id = @category_id)
  4332.  
  4333.   COMMIT TRANSACTION
  4334.  
  4335.   RETURN(0) -- Success
  4336. END
  4337. go
  4338.  
  4339. /**************************************************************/
  4340. /* SP_HELP_CATEGORY                                           */
  4341. /**************************************************************/
  4342.  
  4343. PRINT ''
  4344. PRINT 'Creating procedure sp_help_category...'
  4345. go
  4346. IF (EXISTS (SELECT *
  4347.             FROM msdb.dbo.sysobjects
  4348.             WHERE (name = N'sp_help_category')
  4349.               AND (type = 'P')))
  4350.   DROP PROCEDURE sp_help_category
  4351. go
  4352. CREATE PROCEDURE sp_help_category
  4353.   @class  VARCHAR(8)   = 'JOB', -- JOB, ALERT or OPERATOR
  4354.   @type   VARCHAR(12)  = NULL,  -- LOCAL, MULTI-SERVER, or NONE
  4355.   @name   sysname      = NULL,
  4356.   @suffix BIT          = 0      -- 0 = no suffix, 1 = add suffix
  4357. AS
  4358. BEGIN
  4359.   DECLARE @retval         INT
  4360.   DECLARE @type_in        VARCHAR(12)
  4361.   DECLARE @category_type  INT
  4362.   DECLARE @category_class INT
  4363.   DECLARE @where_clause   NVARCHAR(255)
  4364.   DECLARE @cmd            NVARCHAR(255)
  4365.  
  4366.   SET NOCOUNT ON
  4367.  
  4368.   -- Both name and type can be NULL (this is valid, indeed it is how SQLDMO populates
  4369.   -- the JobCategory collection)
  4370.  
  4371.   -- Remove any leading/trailing spaces from parameters
  4372.   SELECT @class = LTRIM(RTRIM(@class))
  4373.   SELECT @type  = LTRIM(RTRIM(@type))
  4374.   SELECT @name  = LTRIM(RTRIM(@name))
  4375.  
  4376.   -- Turn [nullable] empty string parameters into NULLs
  4377.   IF (@type = '') SELECT @type = NULL
  4378.   IF (@name = N'') SELECT @name = NULL
  4379.  
  4380.   -- Double up any single quotes in @name
  4381.   IF (@name IS NOT NULL)
  4382.     SELECT @name = REPLACE(@name, N'''', N'''''')
  4383.  
  4384.   -- Check the type and class
  4385.   IF (@class = 'JOB') AND (@type IS NULL)
  4386.     SELECT @type_in = 'LOCAL' -- This prevents sp_verify_category from failing
  4387.   ELSE
  4388.   IF (@class <> 'JOB') AND (@type IS NULL)
  4389.     SELECT @type_in = 'NONE'
  4390.   ELSE
  4391.     SELECT @type_in = @type
  4392.  
  4393.   EXECUTE @retval = sp_verify_category @class,
  4394.                                        @type_in,
  4395.                                        NULL,
  4396.                                        @category_class OUTPUT,
  4397.                                        @category_type  OUTPUT
  4398.   IF (@retval <> 0)
  4399.     RETURN(1) -- Failure
  4400.  
  4401.   -- Make sure that 'suffix' is either 0 or 1
  4402.   IF (@suffix <> 0)
  4403.     SELECT @suffix = 1
  4404.  
  4405.   -- Build the WHERE qualifier
  4406.   SELECT @where_clause = N'WHERE (category_class = ' + CONVERT(NVARCHAR, @category_class) + N') '
  4407.   IF (@name IS NOT NULL)
  4408.     SELECT @where_clause = @where_clause + N'AND (name = N''' + @name + N''') '
  4409.   IF (@type IS NOT NULL)
  4410.     SELECT @where_clause = @where_clause + N'AND (category_type = ' + CONVERT(NVARCHAR, @category_type) + N') '
  4411.  
  4412.   -- Construct the query
  4413.   SELECT @cmd = N'SELECT category_id, '
  4414.   IF (@suffix = 1)
  4415.   BEGIN
  4416.     SELECT @cmd = @cmd + N'''category_type'' = '
  4417.     SELECT @cmd = @cmd + N'CASE category_type '
  4418.     SELECT @cmd = @cmd + N'WHEN 0 THEN ''NONE'' '
  4419.     SELECT @cmd = @cmd + N'WHEN 1 THEN ''LOCAL'' '
  4420.     SELECT @cmd = @cmd + N'WHEN 2 THEN ''MULTI-SERVER'' '
  4421.     SELECT @cmd = @cmd + N'ELSE FORMATMESSAGE(14205) '
  4422.     SELECT @cmd = @cmd + N'END, '
  4423.   END
  4424.   ELSE
  4425.   BEGIN
  4426.     SELECT @cmd = @cmd + N'category_type, '
  4427.   END
  4428.   SELECT @cmd = @cmd + N'name '
  4429.   SELECT @cmd = @cmd + N'FROM msdb.dbo.syscategories '
  4430.  
  4431.   -- Execute the query
  4432.   EXECUTE (@cmd + @where_clause + N'ORDER BY category_type, name')
  4433.  
  4434.   RETURN(@@error) -- 0 means success
  4435. END
  4436. go
  4437.  
  4438. /**************************************************************/
  4439. /* SP_DELETE_TARGETSERVER                                     */
  4440. /**************************************************************/
  4441.  
  4442. PRINT ''
  4443. PRINT 'Creating procedure sp_delete_targetserver...'
  4444. go
  4445. IF (EXISTS (SELECT *
  4446.             FROM msdb.dbo.sysobjects
  4447.             WHERE (name = N'sp_delete_targetserver')
  4448.               AND (type = 'P')))
  4449.   DROP PROCEDURE sp_delete_targetserver
  4450. go
  4451. CREATE PROCEDURE sp_delete_targetserver
  4452.   @server_name        NVARCHAR(30),
  4453.   @clear_downloadlist BIT = 1,
  4454.   @post_defection     BIT = 1
  4455. AS
  4456. BEGIN
  4457.   DECLARE @server_id INT
  4458.   DECLARE @tsx_probe NVARCHAR(50)
  4459.  
  4460.   SET NOCOUNT ON
  4461.  
  4462.   -- Remove any leading/trailing spaces from parameters
  4463.   SELECT @server_name = LTRIM(RTRIM(@server_name))
  4464.  
  4465.   -- Check server name
  4466.   SELECT @server_id = server_id
  4467.   FROM msdb.dbo.systargetservers
  4468.   WHERE (server_name = @server_name)
  4469.  
  4470.   IF (@server_id IS NULL)
  4471.   BEGIN
  4472.     RAISERROR(14262, -1, -1, '@server_name', @server_name)
  4473.     RETURN(1) -- Failure
  4474.   END
  4475.  
  4476.   -- If @post_defection is 0 then it is probable that the target server no-longer exists, so do
  4477.   -- the user/login cleanup that SQLServerAgent would have done in response to an sp_msx_defect
  4478.   IF (@post_defection = 0)
  4479.   BEGIN
  4480.     SELECT @tsx_probe = LTRIM(RTRIM(@server_name)) + N'_msx_probe'
  4481.     IF (EXISTS (SELECT *
  4482.                 FROM msdb.dbo.sysusers
  4483.                 WHERE (name = @tsx_probe)))
  4484.       EXECUTE msdb.dbo.sp_dropuser @name_in_db = @tsx_probe
  4485.     IF (EXISTS (SELECT *
  4486.                 FROM master.dbo.syslogins
  4487.                 WHERE (loginname = @tsx_probe)))
  4488.       EXECUTE master.dbo.sp_droplogin @loginame = @tsx_probe
  4489.   END
  4490.  
  4491.   BEGIN TRANSACTION
  4492.  
  4493.     IF (@clear_downloadlist = 1)
  4494.     BEGIN
  4495.       DELETE FROM msdb.dbo.sysdownloadlist
  4496.       WHERE (target_server = @server_name)
  4497.     END
  4498.  
  4499.     IF (@post_defection = 1)
  4500.     BEGIN
  4501.       -- Post a defect instruction to the server
  4502.       -- NOTE: We must do this BEFORE deleting the systargetservers row
  4503.       EXECUTE msdb.dbo.sp_post_msx_operation 'DEFECT', 'SERVER', 0x00, @server_name
  4504.     END
  4505.  
  4506.     DELETE FROM msdb.dbo.systargetservers
  4507.     WHERE (server_id = @server_id)
  4508.  
  4509.     DELETE FROM msdb.dbo.systargetservergroupmembers
  4510.     WHERE (server_id = @server_id)
  4511.  
  4512.     DELETE FROM msdb.dbo.sysjobservers
  4513.     WHERE (server_id = @server_id)
  4514.  
  4515.   COMMIT TRANSACTION
  4516.  
  4517.   RETURN(@@error) -- 0 means success
  4518. END
  4519. go
  4520.  
  4521. /**************************************************************/
  4522. /* SP_HELP_TARGETSERVER                                       */
  4523. /**************************************************************/
  4524.  
  4525. PRINT ''
  4526. PRINT 'Creating procedure sp_help_targetserver...'
  4527. go
  4528. IF (EXISTS (SELECT *
  4529.             FROM msdb.dbo.sysobjects
  4530.             WHERE (name = N'sp_help_targetserver')
  4531.               AND (type = 'P')))
  4532.   DROP PROCEDURE sp_help_targetserver
  4533. go
  4534. CREATE PROCEDURE sp_help_targetserver
  4535.   @server_name NVARCHAR(30) = NULL
  4536. AS
  4537. BEGIN
  4538.   SET NOCOUNT ON
  4539.  
  4540.   -- Remove any leading/trailing spaces from parameters
  4541.   SELECT @server_name = LTRIM(RTRIM(@server_name))
  4542.  
  4543.   IF (@server_name IS NOT NULL)
  4544.   BEGIN
  4545.     IF (NOT EXISTS (SELECT *
  4546.                     FROM msdb.dbo.systargetservers
  4547.                     WHERE (server_name = @server_name)))
  4548.     BEGIN
  4549.       RAISERROR(14262, -1, -1, '@server_name', @server_name)
  4550.       RETURN(1) -- Failure
  4551.     END
  4552.   END
  4553.  
  4554.   CREATE TABLE #unread_instructions
  4555.   (
  4556.   target_server       NVARCHAR(30) COLLATE database_default,
  4557.   unread_instructions INT
  4558.   )
  4559.  
  4560.   INSERT INTO #unread_instructions
  4561.   SELECT target_server, COUNT(*)
  4562.   FROM msdb.dbo.sysdownloadlist
  4563.   WHERE (status = 0)
  4564.   GROUP BY target_server
  4565.  
  4566.   SELECT sts.server_id,
  4567.          sts.server_name,
  4568.          sts.location,
  4569.          sts.time_zone_adjustment,
  4570.          sts.enlist_date,
  4571.          sts.last_poll_date,
  4572.         'status' = sts.status |
  4573.                    CASE WHEN DATEDIFF(ss, sts.last_poll_date, GETDATE()) > (3 * sts.poll_interval) THEN 0x2 ELSE 0 END |
  4574.                    CASE WHEN ((SELECT COUNT(*)
  4575.                                FROM msdb.dbo.sysdownloadlist sdl
  4576.                                WHERE (sdl.target_server = sts.server_name)
  4577.                                  AND (sdl.error_message IS NOT NULL)) > 0) THEN 0x4 ELSE 0 END,
  4578.         'unread_instructions' = ISNULL(ui.unread_instructions, 0),
  4579.         'local_time' = DATEADD(SS, DATEDIFF(SS, sts.last_poll_date, GETDATE()), sts.local_time_at_last_poll),
  4580.         sts.enlisted_by_nt_user,
  4581.         sts.poll_interval
  4582.   FROM msdb.dbo.systargetservers sts LEFT OUTER JOIN
  4583.        #unread_instructions      ui  ON (sts.server_name = ui.target_server)
  4584.   WHERE ((@server_name IS NULL) OR (sts.server_name = @server_name))
  4585.   ORDER BY server_name
  4586.  
  4587.   RETURN(@@error) -- 0 means success
  4588. END
  4589. go
  4590.  
  4591. /**************************************************************/
  4592. /* SP_RESYNC_TARGETSERVER                                     */
  4593. /**************************************************************/
  4594.  
  4595. PRINT ''
  4596. PRINT 'Creating procedure sp_resync_targetserver...'
  4597. go
  4598. IF (EXISTS (SELECT *
  4599.             FROM msdb.dbo.sysobjects
  4600.             WHERE (name = N'sp_resync_targetserver')
  4601.               AND (type = 'P')))
  4602.   DROP PROCEDURE sp_resync_targetserver
  4603. go
  4604. CREATE PROCEDURE sp_resync_targetserver
  4605.   @server_name NVARCHAR(30)
  4606. AS
  4607. BEGIN
  4608.   SET NOCOUNT ON
  4609.  
  4610.   -- Only a sysadmin can do this
  4611.   IF (ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) <> 1)
  4612.   BEGIN
  4613.     RAISERROR(15003, 16, 1, N'sysadmin')
  4614.     RETURN(1) -- Failure
  4615.   END
  4616.  
  4617.   -- Remove any leading/trailing spaces from parameters
  4618.   SELECT @server_name = LTRIM(RTRIM(@server_name))
  4619.  
  4620.   IF (@server_name <> N'ALL')
  4621.   BEGIN
  4622.     IF (NOT EXISTS (SELECT *
  4623.                     FROM msdb.dbo.systargetservers
  4624.                     WHERE (server_name = @server_name)))
  4625.     BEGIN
  4626.       RAISERROR(14262, -1, -1, '@server_name', @server_name)
  4627.       RETURN(1) -- Failure
  4628.     END
  4629.  
  4630.     -- We want the target server to:
  4631.     -- a) delete all their current MSX jobs, and
  4632.     -- b) download all their jobs again.
  4633.     -- So we delete all the current instructions and post a new set
  4634.     DELETE FROM msdb.dbo.sysdownloadlist
  4635.     WHERE (target_server = @server_name)
  4636.     EXECUTE msdb.dbo.sp_post_msx_operation 'DELETE', 'JOB', 0x00, @server_name
  4637.     EXECUTE msdb.dbo.sp_post_msx_operation 'INSERT', 'JOB', 0x00, @server_name
  4638.   END
  4639.   ELSE
  4640.   BEGIN
  4641.     -- We want ALL target servers to:
  4642.     -- a) delete all their current MSX jobs, and
  4643.     -- b) download all their jobs again.
  4644.     -- So we delete all the current instructions and post a new set
  4645.     TRUNCATE TABLE msdb.dbo.sysdownloadlist
  4646.     EXECUTE msdb.dbo.sp_post_msx_operation 'DELETE', 'JOB', 0x00, NULL
  4647.     EXECUTE msdb.dbo.sp_post_msx_operation 'INSERT', 'JOB', 0x00, NULL
  4648.   END
  4649.  
  4650.   RETURN(@@error) -- 0 means success
  4651. END
  4652. go
  4653.  
  4654. DUMP TRANSACTION msdb WITH NO_LOG
  4655. go
  4656. CHECKPOINT
  4657. go
  4658.  
  4659. /**************************************************************/
  4660. /* SP_PURGE_JOBHISTORY                                        */
  4661. /**************************************************************/
  4662.  
  4663. PRINT ''
  4664. PRINT 'Creating procedure sp_purge_jobhistory...'
  4665. go
  4666. IF (EXISTS (SELECT *
  4667.             FROM msdb.dbo.sysobjects
  4668.             WHERE (name = N'sp_purge_jobhistory')
  4669.               AND (type = 'P')))
  4670.   DROP PROCEDURE sp_purge_jobhistory
  4671. go
  4672. CREATE PROCEDURE sp_purge_jobhistory
  4673.   @job_name sysname          = NULL,
  4674.   @job_id   UNIQUEIDENTIFIER = NULL
  4675. AS
  4676. BEGIN
  4677.   DECLARE @rows_affected INT
  4678.   DECLARE @total_rows    INT
  4679.   DECLARE @retval        INT
  4680.   DECLARE @category_id   INT
  4681.  
  4682.   SET NOCOUNT ON
  4683.  
  4684.   IF ((@job_name IS NOT NULL) OR (@job_id IS NOT NULL))
  4685.   BEGIN
  4686.     EXECUTE @retval = sp_verify_job_identifiers '@job_name',
  4687.                                                 '@job_id',
  4688.                                                  @job_name OUTPUT,
  4689.                                                  @job_id   OUTPUT
  4690.     IF (@retval <> 0)
  4691.       RETURN(1) -- Failure
  4692.  
  4693.     -- Get category to see if it is a misc. replication agent. @category_id will be
  4694.     -- NULL if there is no @job_id.
  4695.     select @category_id = category_id from msdb.dbo.sysjobs where job_id = @job_id
  4696.  
  4697.     -- Delete the histories for this job
  4698.     DELETE FROM msdb.dbo.sysjobhistory
  4699.     WHERE (job_id = @job_id)
  4700.     SELECT @rows_affected = @@rowcount
  4701.  
  4702.     -- If misc. replication job, then update global replication status table
  4703.     IF (@category_id IN (11, 12, 16, 17, 18))
  4704.     BEGIN
  4705.       -- Nothing can be done if this fails, so don't worry about the return code
  4706.       EXECUTE master.dbo.sp_MSupdate_replication_status
  4707.         @publisher = '',
  4708.         @publisher_db = '',
  4709.         @publication = '',
  4710.         @publication_type = -1,
  4711.         @agent_type = 5,
  4712.         @agent_name = @job_name,
  4713.         @status = -1 -- Delete
  4714.     END
  4715.   END
  4716.   ELSE
  4717.   BEGIN
  4718.     -- Only a sysadmin can do this
  4719.     IF (ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) <> 1)
  4720.     BEGIN
  4721.       RAISERROR(15003, 16, 1, N'sysadmin')
  4722.       RETURN(1) -- Failure
  4723.     END
  4724.  
  4725.     SELECT @total_rows = COUNT(*)
  4726.     FROM msdb.dbo.sysjobhistory
  4727.     SELECT @rows_affected = @total_rows
  4728.     TRUNCATE TABLE msdb.dbo.sysjobhistory
  4729.  
  4730.     -- Remove all misc. replication jobs from global replication status table
  4731.     -- Nothing can be done if this fails, so don't worry about the return code
  4732.     EXECUTE master.dbo.sp_MSupdate_replication_status
  4733.       @publisher = '',
  4734.       @publisher_db = '',
  4735.       @publication = '',
  4736.       @publication_type = -1,
  4737.       @agent_type = 5,
  4738.       @agent_name = '%',
  4739.       @status = -1 -- Delete
  4740.   END
  4741.   RAISERROR(14226, 0, 1, @rows_affected)
  4742.  
  4743.   RETURN(0) -- Success
  4744. END
  4745. go
  4746.  
  4747. /**************************************************************/
  4748. /* SP_VERIFY_JOB_DATE                                         */
  4749. /**************************************************************/
  4750.  
  4751. PRINT ''
  4752. PRINT 'Creating procedure sp_verify_job_date...'
  4753. go
  4754. IF (EXISTS (SELECT *
  4755.             FROM msdb.dbo.sysobjects
  4756.             WHERE (name = N'sp_verify_job_date')
  4757.               AND (type = 'P')))
  4758.   DROP PROCEDURE sp_verify_job_date
  4759. go
  4760. CREATE PROCEDURE sp_verify_job_date
  4761.   @date           INT,
  4762.   @date_name      VARCHAR(60) = 'date',
  4763.   @error_severity INT         = -1
  4764. AS
  4765. BEGIN
  4766.   SET NOCOUNT ON
  4767.  
  4768.   -- Remove any leading/trailing spaces from parameters
  4769.   SELECT @date_name = LTRIM(RTRIM(@date_name))
  4770.  
  4771.   IF ((ISDATE(CONVERT(VARCHAR, @date)) = 0) OR (@date < 19900101) OR (@date > 99991231))
  4772.   BEGIN
  4773.     RAISERROR(14266, @error_severity, -1, @date_name, '19900101..99991231')
  4774.     RETURN(1) -- Failure
  4775.   END
  4776.  
  4777.   RETURN(0) -- Success
  4778. END
  4779. go
  4780.  
  4781. /**************************************************************/
  4782. /* SP_VERIFY_JOB_TIME                                         */
  4783. /**************************************************************/
  4784.  
  4785. PRINT ''
  4786. PRINT 'Creating procedure sp_verify_job_time...'
  4787. go
  4788. IF (EXISTS (SELECT *
  4789.             FROM msdb.dbo.sysobjects
  4790.             WHERE (name = N'sp_verify_job_time')
  4791.               AND (type = 'P')))
  4792.   DROP PROCEDURE sp_verify_job_time
  4793. go
  4794.  
  4795. CREATE PROCEDURE sp_verify_job_time
  4796.   @time           INT,
  4797.   @time_name      VARCHAR(60) = 'time',
  4798.   @error_severity INT = -1
  4799. AS
  4800. BEGIN
  4801.   DECLARE @hour      INT
  4802.   DECLARE @minute    INT
  4803.   DECLARE @second    INT
  4804.   DECLARE @part_name NVARCHAR(50)
  4805.  
  4806.   SET NOCOUNT ON
  4807.  
  4808.   -- Remove any leading/trailing spaces from parameters
  4809.   SELECT @time_name = LTRIM(RTRIM(@time_name))
  4810.  
  4811.   IF ((@time < 0) OR (@time > 235959))
  4812.   BEGIN
  4813.     RAISERROR(14266, @error_severity, -1, @time_name, '000000..235959')
  4814.     RETURN(1) -- Failure
  4815.   END
  4816.  
  4817.   SELECT @hour   = (@time / 10000)
  4818.   SELECT @minute = (@time % 10000) / 100
  4819.   SELECT @second = (@time % 100)
  4820.  
  4821.   -- Check hour range
  4822.   IF (@hour > 23)
  4823.   BEGIN
  4824.     SELECT @part_name = FORMATMESSAGE(14218)
  4825.     RAISERROR(14287, @error_severity, -1, @time_name, @part_name)
  4826.     RETURN(1) -- Failure
  4827.   END
  4828.  
  4829.   -- Check minute range
  4830.   IF (@minute > 59)
  4831.   BEGIN
  4832.     SELECT @part_name = FORMATMESSAGE(14219)
  4833.     RAISERROR(14287, @error_severity, -1, @time_name, @part_name)
  4834.     RETURN(1) -- Failure
  4835.   END
  4836.  
  4837.   -- Check second range
  4838.   IF (@second > 59)
  4839.   BEGIN
  4840.     SELECT @part_name = FORMATMESSAGE(14220)
  4841.     RAISERROR(14287, @error_severity, -1, @time_name, @part_name)
  4842.     RETURN(1) -- Failure
  4843.   END
  4844.  
  4845.   RETURN(0) -- Success
  4846. END
  4847. go
  4848.  
  4849. /**************************************************************/
  4850. /* SP_HELP_JOBHISTORY                                         */
  4851. /**************************************************************/
  4852.  
  4853. PRINT ''
  4854. PRINT 'Creating procedure sp_help_jobhistory...'
  4855. go
  4856. IF (EXISTS (SELECT *
  4857.             FROM msdb.dbo.sysobjects
  4858.             WHERE (name = N'sp_help_jobhistory')
  4859.               AND (type = 'P')))
  4860.   DROP PROCEDURE sp_help_jobhistory
  4861. go
  4862. CREATE PROCEDURE sp_help_jobhistory
  4863.   @job_id               UNIQUEIDENTIFIER = NULL,
  4864.   @job_name             sysname          = NULL,
  4865.   @step_id              INT              = NULL,
  4866.   @sql_message_id       INT              = NULL,
  4867.   @sql_severity         INT              = NULL,
  4868.   @start_run_date       INT              = NULL,     -- YYYYMMDD
  4869.   @end_run_date         INT              = NULL,     -- YYYYMMDD
  4870.   @start_run_time       INT              = NULL,     -- HHMMSS
  4871.   @end_run_time         INT              = NULL,     -- HHMMSS
  4872.   @minimum_run_duration INT              = NULL,     -- HHMMSS
  4873.   @run_status           INT              = NULL,     -- SQLAGENT_EXEC_X code
  4874.   @minimum_retries      INT              = NULL,
  4875.   @oldest_first         INT              = 0,        -- Or 1
  4876.   @server               NVARCHAR(30)     = NULL,
  4877.   @mode                 VARCHAR(7)       = 'SUMMARY' -- Or 'FULL' or 'SEM'
  4878. AS
  4879. BEGIN
  4880.   DECLARE @retval   INT
  4881.   DECLARE @order_by INT  -- Must be INT since it can be -1
  4882.  
  4883.   SET NOCOUNT ON
  4884.  
  4885.   -- Remove any leading/trailing spaces from parameters
  4886.   SELECT @server   = LTRIM(RTRIM(@server))
  4887.   SELECT @mode     = LTRIM(RTRIM(@mode))
  4888.  
  4889.   -- Turn [nullable] empty string parameters into NULLs
  4890.   IF (@server = N'')   SELECT @server = NULL
  4891.  
  4892.   -- Check job id/name (if supplied)
  4893.   IF ((@job_id IS NOT NULL) OR (@job_name IS NOT NULL))
  4894.   BEGIN
  4895.     EXECUTE @retval = sp_verify_job_identifiers '@job_name',
  4896.                                                 '@job_id',
  4897.                                                  @job_name OUTPUT,
  4898.                                                  @job_id   OUTPUT
  4899.     IF (@retval <> 0)
  4900.       RETURN(1) -- Failure
  4901.   END
  4902.  
  4903.   -- Check @start_run_date
  4904.   IF (@start_run_date IS NOT NULL)
  4905.   BEGIN
  4906.     EXECUTE @retval = sp_verify_job_date @start_run_date, '@start_run_date'
  4907.     IF (@retval <> 0)
  4908.       RETURN(1) -- Failure
  4909.   END
  4910.  
  4911.   -- Check @end_run_date
  4912.   IF (@end_run_date IS NOT NULL)
  4913.   BEGIN
  4914.     EXECUTE @retval = sp_verify_job_date @end_run_date, '@end_run_date'
  4915.     IF (@retval <> 0)
  4916.       RETURN(1) -- Failure
  4917.   END
  4918.  
  4919.   -- Check @start_run_time
  4920.   EXECUTE @retval = sp_verify_job_time @start_run_time, '@start_run_time'
  4921.   IF (@retval <> 0)
  4922.     RETURN(1) -- Failure
  4923.  
  4924.   -- Check @end_run_time
  4925.   EXECUTE @retval = sp_verify_job_time @end_run_time, '@end_run_time'
  4926.   IF (@retval <> 0)
  4927.     RETURN(1) -- Failure
  4928.  
  4929.   -- Check @run_status
  4930.   IF ((@run_status < 0) OR (@run_status > 5))
  4931.   BEGIN
  4932.     RAISERROR(13266, -1, -1, '@run_status', '0..5')
  4933.     RETURN(1) -- Failure
  4934.   END
  4935.  
  4936.   -- Check mode
  4937.   SELECT @mode = UPPER(@mode)
  4938.   IF (@mode NOT IN ('SUMMARY', 'FULL', 'SEM'))
  4939.   BEGIN
  4940.     RAISERROR(14266, -1, -1, '@mode', 'SUMMARY, FULL, SEM')
  4941.     RETURN(1) -- Failure
  4942.   END
  4943.  
  4944.   SELECT @order_by = -1
  4945.   IF (@oldest_first = 1)
  4946.     SELECT @order_by = 1
  4947.  
  4948.   -- Return history information filtered by the supplied parameters.
  4949.   -- NOTE: SQLDMO relies on the 'FULL' format; ** DO NOT CHANGE IT **
  4950.   IF (@mode = 'FULL')
  4951.   BEGIN
  4952.     SELECT sjh.instance_id, -- This is included just for ordering purposes
  4953.            sj.job_id,
  4954.            job_name = sj.name,
  4955.            sjh.step_id,
  4956.            sjh.step_name,
  4957.            sjh.sql_message_id,
  4958.            sjh.sql_severity,
  4959.            sjh.message,
  4960.            sjh.run_status,
  4961.            sjh.run_date,
  4962.            sjh.run_time,
  4963.            sjh.run_duration,
  4964.            operator_emailed = so1.name,
  4965.            operator_netsent = so2.name,
  4966.            operator_paged = so3.name,
  4967.            sjh.retries_attempted,
  4968.            sjh.server
  4969.     FROM msdb.dbo.sysjobhistory                sjh
  4970.          LEFT OUTER JOIN msdb.dbo.sysoperators so1  ON (sjh.operator_id_emailed = so1.id)
  4971.          LEFT OUTER JOIN msdb.dbo.sysoperators so2  ON (sjh.operator_id_netsent = so2.id)
  4972.          LEFT OUTER JOIN msdb.dbo.sysoperators so3  ON (sjh.operator_id_paged = so3.id),
  4973.          msdb.dbo.sysjobs_view                 sj
  4974.     WHERE (sj.job_id = sjh.job_id)
  4975.       AND ((@job_id               IS NULL) OR (@job_id = sjh.job_id))
  4976.       AND ((@step_id              IS NULL) OR (@step_id = sjh.step_id))
  4977.       AND ((@sql_message_id       IS NULL) OR (@sql_message_id = sjh.sql_message_id))
  4978.       AND ((@sql_severity         IS NULL) OR (@sql_severity = sjh.sql_severity))
  4979.       AND ((@start_run_date       IS NULL) OR (sjh.run_date >= @start_run_date))
  4980.       AND ((@end_run_date         IS NULL) OR (sjh.run_date <= @end_run_date))
  4981.       AND ((@start_run_time       IS NULL) OR (sjh.run_time >= @start_run_time))
  4982.       AND ((@end_run_time         IS NULL) OR (sjh.run_time <= @end_run_time))
  4983.       AND ((@minimum_run_duration IS NULL) OR (sjh.run_duration >= @minimum_run_duration))
  4984.       AND ((@run_status           IS NULL) OR (@run_status = sjh.run_status))
  4985.       AND ((@minimum_retries      IS NULL) OR (sjh.retries_attempted >= @minimum_retries))
  4986.       AND ((@server               IS NULL) OR (sjh.server = @server))
  4987.     ORDER BY (sjh.instance_id * @order_by)
  4988.   END
  4989.   ELSE
  4990.   IF (@mode = 'SUMMARY')
  4991.   BEGIN
  4992.     -- Summary format: same WHERE clause just a different SELECT list
  4993.     SELECT sj.job_id,
  4994.            job_name = sj.name,
  4995.            sjh.run_status,
  4996.            sjh.run_date,
  4997.            sjh.run_time,
  4998.            sjh.run_duration,
  4999.            operator_emailed = substring(so1.name, 1, 20),
  5000.            operator_netsent = substring(so2.name, 1, 20),
  5001.            operator_paged = substring(so3.name, 1, 20),
  5002.            sjh.retries_attempted,
  5003.            sjh.server
  5004.     FROM msdb.dbo.sysjobhistory                sjh
  5005.          LEFT OUTER JOIN msdb.dbo.sysoperators so1  ON (sjh.operator_id_emailed = so1.id)
  5006.          LEFT OUTER JOIN msdb.dbo.sysoperators so2  ON (sjh.operator_id_netsent = so2.id)
  5007.          LEFT OUTER JOIN msdb.dbo.sysoperators so3  ON (sjh.operator_id_paged = so3.id),
  5008.          msdb.dbo.sysjobs_view                 sj
  5009.     WHERE (sj.job_id = sjh.job_id)
  5010.       AND ((@job_id               IS NULL) OR (@job_id = sjh.job_id))
  5011.       AND ((@step_id              IS NULL) OR (@step_id = sjh.step_id))
  5012.       AND ((@sql_message_id       IS NULL) OR (@sql_message_id = sjh.sql_message_id))
  5013.       AND ((@sql_severity         IS NULL) OR (@sql_severity = sjh.sql_severity))
  5014.       AND ((@start_run_date       IS NULL) OR (sjh.run_date >= @start_run_date))
  5015.       AND ((@end_run_date         IS NULL) OR (sjh.run_date <= @end_run_date))
  5016.       AND ((@start_run_time       IS NULL) OR (sjh.run_time >= @start_run_time))
  5017.       AND ((@end_run_time         IS NULL) OR (sjh.run_time <= @end_run_time))
  5018.       AND ((@minimum_run_duration IS NULL) OR (sjh.run_duration >= @minimum_run_duration))
  5019.       AND ((@run_status           IS NULL) OR (@run_status = sjh.run_status))
  5020.       AND ((@minimum_retries      IS NULL) OR (sjh.retries_attempted >= @minimum_retries))
  5021.       AND ((@server               IS NULL) OR (sjh.server = @server))
  5022.     ORDER BY (sjh.instance_id * @order_by)
  5023.   END
  5024.   ELSE
  5025.   IF (@mode = 'SEM')
  5026.   BEGIN
  5027.     -- SQL Enterprise Manager format
  5028.     SELECT sjh.step_id,
  5029.            sjh.step_name,
  5030.            sjh.message,
  5031.            sjh.run_status,
  5032.            sjh.run_date,
  5033.            sjh.run_time,
  5034.            sjh.run_duration,
  5035.            operator_emailed = so1.name,
  5036.            operator_netsent = so2.name,
  5037.            operator_paged = so3.name
  5038.     FROM msdb.dbo.sysjobhistory                sjh
  5039.          LEFT OUTER JOIN msdb.dbo.sysoperators so1  ON (sjh.operator_id_emailed = so1.id)
  5040.          LEFT OUTER JOIN msdb.dbo.sysoperators so2  ON (sjh.operator_id_netsent = so2.id)
  5041.          LEFT OUTER JOIN msdb.dbo.sysoperators so3  ON (sjh.operator_id_paged = so3.id),
  5042.          msdb.dbo.sysjobs_view                 sj
  5043.     WHERE (sj.job_id = sjh.job_id)
  5044.       AND (@job_id = sjh.job_id)
  5045.     ORDER BY (sjh.instance_id * @order_by)
  5046.   END
  5047.  
  5048.   RETURN(0) -- Success
  5049. END
  5050. go
  5051.  
  5052. /**************************************************************/
  5053. /* SP_ADD_JOBSERVER                                           */
  5054. /**************************************************************/
  5055.  
  5056. PRINT ''
  5057. PRINT 'Creating procedure sp_add_jobserver...'
  5058. go
  5059. IF (EXISTS (SELECT *
  5060.             FROM msdb.dbo.sysobjects
  5061.             WHERE (name = N'sp_add_jobserver')
  5062.               AND (type = 'P')))
  5063.   DROP PROCEDURE sp_add_jobserver
  5064. go
  5065.  
  5066. CREATE PROCEDURE sp_add_jobserver
  5067.   @job_id         UNIQUEIDENTIFIER = NULL, -- Must provide either this or job_name
  5068.   @job_name       sysname          = NULL, -- Must provide either this or job_id
  5069.   @server_name    NVARCHAR(30)     = NULL, -- if NULL will default to serverproperty('ServerName')
  5070.   @automatic_post BIT = 1                  -- Flag for SEM use only
  5071. AS
  5072. BEGIN
  5073.   DECLARE @retval                    INT
  5074.   DECLARE @server_id                 INT
  5075.   DECLARE @job_type                  VARCHAR(12)
  5076.   DECLARE @current_job_category_type VARCHAR(12)
  5077.   DECLARE @msx_operator_id           INT
  5078.   DECLARE @local_server_name         NVARCHAR(30)
  5079.   DECLARE @is_sysadmin               INT
  5080.   DECLARE @job_owner                 sysname
  5081.  
  5082.   SET NOCOUNT ON
  5083.  
  5084.   IF (@server_name IS NULL) OR (UPPER(@server_name) = N'(LOCAL)')
  5085.     SELECT @server_name = CONVERT(NVARCHAR(30), SERVERPROPERTY('ServerName'))
  5086.  
  5087.   -- Remove any leading/trailing spaces from parameters
  5088.   SELECT @server_name = LTRIM(RTRIM(@server_name))
  5089.  
  5090.   EXECUTE @retval = sp_verify_job_identifiers '@job_name',
  5091.                                               '@job_id',
  5092.                                                @job_name OUTPUT,
  5093.                                                @job_id   OUTPUT
  5094.   IF (@retval <> 0)
  5095.     RETURN(1) -- Failure
  5096.  
  5097.   -- First, check if the server is the local server
  5098.   SELECT @local_server_name = CONVERT(NVARCHAR,SERVERPROPERTY ('SERVERNAME'))
  5099.  
  5100.   IF (UPPER(@server_name) = UPPER(@local_server_name))
  5101.     SELECT @server_name = UPPER(CONVERT(NVARCHAR(30), SERVERPROPERTY('ServerName')))
  5102.  
  5103.   -- Only the SA can add a multi-server job
  5104.   IF (UPPER(@server_name) <> UPPER(CONVERT(NVARCHAR(30), SERVERPROPERTY('ServerName')))) AND 
  5105.      (ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) = 0)
  5106.   BEGIN
  5107.     RAISERROR(15003, 16, 1, N'sysadmin')
  5108.     RETURN(1) -- Failure
  5109.   END
  5110.  
  5111.   -- For a multi-server job...
  5112.   IF (UPPER(@server_name) <> UPPER(CONVERT(NVARCHAR(30), SERVERPROPERTY('ServerName'))))
  5113.   BEGIN
  5114.     -- 1) Check if the job owner is a sysadmin
  5115.     SELECT @job_owner = SUSER_SNAME(owner_sid)
  5116.     FROM msdb.dbo.sysjobs
  5117.     WHERE (job_id = @job_id)
  5118.     SELECT @is_sysadmin = 0
  5119.     EXECUTE msdb.dbo.sp_sqlagent_has_server_access @login_name = @job_owner, @is_sysadmin_member = @is_sysadmin OUTPUT
  5120.     IF (@is_sysadmin = 0)
  5121.     BEGIN
  5122.       RAISERROR(14544, -1, -1, @job_owner, N'sysadmin')
  5123.       RETURN(1) -- Failure
  5124.     END
  5125.  
  5126.     -- 2) Check if any of the TSQL steps have a non-null database_user_name
  5127.     IF (EXISTS (SELECT *
  5128.                 FROM msdb.dbo.sysjobsteps
  5129.                 WHERE (job_id = @job_id)
  5130.                   AND (subsystem = N'TSQL')
  5131.                   AND (database_user_name IS NOT NULL)))
  5132.     BEGIN
  5133.       RAISERROR(14542, -1, -1, N'database_user_name')
  5134.       RETURN(1) -- Failure
  5135.     END
  5136.   END
  5137.  
  5138.   -- Check server name
  5139.   IF (UPPER(@server_name) <> UPPER(CONVERT(NVARCHAR(30), SERVERPROPERTY('ServerName'))))
  5140.   BEGIN
  5141.     SELECT @server_id = server_id
  5142.     FROM msdb.dbo.systargetservers
  5143.     WHERE (server_name = @server_name)
  5144.     IF (@server_id IS NULL)
  5145.     BEGIN
  5146.       RAISERROR(14262, -1, -1, '@server_name', @server_name)
  5147.       RETURN(1) -- Failure
  5148.     END
  5149.   END
  5150.   ELSE
  5151.     SELECT @server_id = 0
  5152.  
  5153.   -- Check that this job has not already been targeted at this server
  5154.   IF (EXISTS (SELECT *
  5155.                FROM msdb.dbo.sysjobservers
  5156.                WHERE (job_id = @job_id)
  5157.                  AND (server_id = @server_id)))
  5158.   BEGIN
  5159.     RAISERROR(14269, -1, -1, @job_name, @server_name)
  5160.     RETURN(1) -- Failure
  5161.   END
  5162.  
  5163.   -- Prevent the job from being targeted at both the local AND remote servers
  5164.   SELECT @job_type = 'UNKNOWN'
  5165.   IF (EXISTS (SELECT *
  5166.               FROM msdb.dbo.sysjobservers
  5167.               WHERE (job_id = @job_id)
  5168.                 AND (server_id = 0)))
  5169.     SELECT @job_type = 'LOCAL'
  5170.   ELSE
  5171.   IF (EXISTS (SELECT *
  5172.               FROM msdb.dbo.sysjobservers
  5173.               WHERE (job_id = @job_id)
  5174.                 AND (server_id <> 0)))
  5175.     SELECT @job_type = 'MULTI-SERVER'
  5176.  
  5177.   IF ((@server_id = 0) AND (@job_type = 'MULTI-SERVER'))
  5178.   BEGIN
  5179.     RAISERROR(14290, -1, -1)
  5180.     RETURN(1) -- Failure
  5181.   END
  5182.   IF ((@server_id <> 0) AND (@job_type = 'LOCAL'))
  5183.   BEGIN
  5184.     RAISERROR(14291, -1, -1)
  5185.     RETURN(1) -- Failure
  5186.   END
  5187.  
  5188.   -- For a multi-server job, check that any notifications are to the MSXOperator
  5189.   IF (@job_type = 'MULTI-SERVER')
  5190.   BEGIN
  5191.     SELECT @msx_operator_id = id
  5192.     FROM msdb.dbo.sysoperators
  5193.     WHERE (name = N'MSXOperator')
  5194.  
  5195.     IF (EXISTS (SELECT *
  5196.                 FROM msdb.dbo.sysjobs
  5197.                 WHERE (job_id = @job_id)
  5198.                   AND (((notify_email_operator_id <> 0)   AND (notify_email_operator_id <> @msx_operator_id)) OR
  5199.                        ((notify_page_operator_id <> 0)    AND (notify_page_operator_id <> @msx_operator_id))  OR
  5200.                        ((notify_netsend_operator_id <> 0) AND (notify_netsend_operator_id <> @msx_operator_id)))))
  5201.     BEGIN
  5202.       RAISERROR(14221, -1, -1, 'MSXOperator')
  5203.       RETURN(1) -- Failure
  5204.     END
  5205.   END
  5206.  
  5207.   -- Insert the sysjobservers row
  5208.   INSERT INTO msdb.dbo.sysjobservers
  5209.          (job_id,
  5210.           server_id,
  5211.           last_run_outcome,
  5212.           last_outcome_message,
  5213.           last_run_date,
  5214.           last_run_time,
  5215.           last_run_duration)
  5216.   VALUES (@job_id,
  5217.           @server_id,
  5218.           5,  -- ie. SQLAGENT_EXEC_UNKNOWN (can't use 0 since this is SQLAGENT_EXEC_FAIL)
  5219.           NULL,
  5220.           0,
  5221.           0,
  5222.           0)
  5223.  
  5224.   -- Re-categorize the job (if necessary)
  5225.   SELECT @current_job_category_type = CASE category_type
  5226.                                         WHEN 1 THEN 'LOCAL'
  5227.                                         WHEN 2 THEN 'MULTI-SERVER'
  5228.                                       END
  5229.   FROM msdb.dbo.sysjobs_view  sjv,
  5230.        msdb.dbo.syscategories sc
  5231.   WHERE (sjv.category_id = sc.category_id)
  5232.     AND (sjv.job_id = @job_id)
  5233.  
  5234.   IF (@server_id = 0) AND (@current_job_category_type = 'MULTI-SERVER')
  5235.   BEGIN
  5236.     UPDATE msdb.dbo.sysjobs
  5237.     SET category_id = 0 -- [Uncategorized (Local)]
  5238.     WHERE (job_id = @job_id)
  5239.   END
  5240.   IF (@server_id <> 0) AND (@current_job_category_type = 'LOCAL')
  5241.   BEGIN
  5242.     UPDATE msdb.dbo.sysjobs
  5243.     SET category_id = 2 -- [Uncategorized (Multi-Server)]
  5244.     WHERE (job_id = @job_id)
  5245.   END
  5246.  
  5247.   -- Instruct the new server to pick up the job
  5248.   IF (@automatic_post = 1)
  5249.     EXECUTE @retval = sp_post_msx_operation 'INSERT', 'JOB', @job_id, @server_name
  5250.  
  5251.   -- If the job is local, make sure that SQLServerAgent caches it
  5252.   IF (@server_id = 0)
  5253.   BEGIN
  5254.     EXECUTE msdb.dbo.sp_sqlagent_notify @op_type     = N'J',
  5255.                                         @job_id      = @job_id,
  5256.                                         @action_type = N'I'
  5257.   END
  5258.  
  5259.   RETURN(@retval) -- 0 means success
  5260. END
  5261. go
  5262.  
  5263. /**************************************************************/
  5264. /* SP_DELETE_JOBSERVER                                        */
  5265. /**************************************************************/
  5266.  
  5267. PRINT ''
  5268. PRINT 'Creating procedure sp_delete_jobserver...'
  5269. go
  5270. IF (EXISTS (SELECT *
  5271.             FROM msdb.dbo.sysobjects
  5272.             WHERE (name = N'sp_delete_jobserver')
  5273.               AND (type = 'P')))
  5274.   DROP PROCEDURE sp_delete_jobserver
  5275. go
  5276. CREATE PROCEDURE sp_delete_jobserver
  5277.   @job_id      UNIQUEIDENTIFIER = NULL, -- Must provide either this or job_name
  5278.   @job_name    sysname          = NULL, -- Must provide either this or job_id
  5279.   @server_name NVARCHAR(30)
  5280. AS
  5281. BEGIN
  5282.   DECLARE @retval             INT
  5283.   DECLARE @server_id          INT
  5284.   DECLARE @local_machine_name NVARCHAR(30)
  5285.  
  5286.   SET NOCOUNT ON
  5287.  
  5288.   -- Remove any leading/trailing spaces from parameters
  5289.   SELECT @server_name = LTRIM(RTRIM(@server_name))
  5290.  
  5291.   IF (UPPER(@server_name) = '(LOCAL)')
  5292.     SELECT @server_name = UPPER(CONVERT(NVARCHAR(30), SERVERPROPERTY('ServerName')))
  5293.  
  5294.   EXECUTE @retval = sp_verify_job_identifiers '@job_name',
  5295.                                               '@job_id',
  5296.                                                @job_name OUTPUT,
  5297.                                                @job_id   OUTPUT
  5298.   IF (@retval <> 0)
  5299.     RETURN(1) -- Failure
  5300.  
  5301.   -- First, check if the server is the local server
  5302.   EXECUTE @retval = master.dbo.xp_getnetname @local_machine_name OUTPUT
  5303.   IF (@retval <> 0)
  5304.     RETURN(1) -- Failure
  5305.   IF (@local_machine_name IS NOT NULL) AND (UPPER(@server_name) = UPPER(@local_machine_name))
  5306.     SELECT @server_name = UPPER(CONVERT(NVARCHAR(30), SERVERPROPERTY('ServerName')))
  5307.  
  5308.   -- Check server name
  5309.   IF (UPPER(@server_name) <> UPPER(CONVERT(NVARCHAR(30), SERVERPROPERTY('ServerName'))))
  5310.   BEGIN
  5311.     SELECT @server_id = server_id
  5312.     FROM msdb.dbo.systargetservers
  5313.     WHERE (server_name = @server_name)
  5314.     IF (@server_id IS NULL)
  5315.     BEGIN
  5316.       RAISERROR(14262, -1, -1, '@server_name', @server_name)
  5317.       RETURN(1) -- Failure
  5318.     END
  5319.   END
  5320.   ELSE
  5321.     SELECT @server_id = 0
  5322.  
  5323.   -- Check that the job is indeed targeted at the server
  5324.   IF (NOT EXISTS (SELECT *
  5325.                   FROM msdb.dbo.sysjobservers
  5326.                   WHERE (job_id = @job_id)
  5327.                     AND (server_id = @server_id)))
  5328.   BEGIN
  5329.     RAISERROR(14270, -1, -1, @job_name, @server_name)
  5330.     RETURN(1) -- Failure
  5331.   END
  5332.  
  5333.   -- Instruct the deleted server to purge the job
  5334.   -- NOTE: We must do this BEFORE we delete the sysjobservers row
  5335.   EXECUTE @retval = sp_post_msx_operation 'DELETE', 'JOB', @job_id, @server_name
  5336.  
  5337.   -- Delete the sysjobservers row
  5338.   DELETE FROM msdb.dbo.sysjobservers
  5339.   WHERE (job_id = @job_id)
  5340.     AND (server_id = @server_id)
  5341.  
  5342.   -- If we deleted the last jobserver then re-categorize the job to the sp_add_job default
  5343.   IF (NOT EXISTS (SELECT *
  5344.                   FROM msdb.dbo.sysjobservers
  5345.                   WHERE (job_id = @job_id)))
  5346.   BEGIN
  5347.     UPDATE msdb.dbo.sysjobs
  5348.     SET category_id = 0 -- [Uncategorized (Local)]
  5349.     WHERE (job_id = @job_id)
  5350.   END
  5351.  
  5352.   -- If the job is local, make sure that SQLServerAgent removes it from cache
  5353.   IF (@server_id = 0)
  5354.   BEGIN
  5355.     EXECUTE msdb.dbo.sp_sqlagent_notify @op_type     = N'J',
  5356.                                         @job_id      = @job_id,
  5357.                                         @action_type = N'D'
  5358.   END
  5359.  
  5360.   RETURN(@retval) -- 0 means success
  5361. END
  5362. go
  5363.  
  5364. /**************************************************************/
  5365. /* SP_HELP_JOBSERVER                                          */
  5366. /**************************************************************/
  5367.  
  5368. PRINT ''
  5369. PRINT 'Creating procedure sp_help_jobserver...'
  5370. go
  5371. IF (EXISTS (SELECT *
  5372.             FROM msdb.dbo.sysobjects
  5373.             WHERE (name = N'sp_help_jobserver')
  5374.               AND (type = 'P')))
  5375.   DROP PROCEDURE sp_help_jobserver
  5376. go
  5377. CREATE PROCEDURE sp_help_jobserver
  5378.   @job_id                UNIQUEIDENTIFIER = NULL, -- Must provide either this or job_name
  5379.   @job_name              sysname          = NULL, -- Must provide either this or job_id
  5380.   @show_last_run_details TINYINT          = 0     -- Controls if last-run execution information is part of the result set (1 = yes, 0 = no)
  5381. AS
  5382. BEGIN
  5383.   DECLARE @retval INT
  5384.  
  5385.   SET NOCOUNT ON
  5386.  
  5387.   EXECUTE @retval = sp_verify_job_identifiers '@job_name',
  5388.                                               '@job_id',
  5389.                                                @job_name OUTPUT,
  5390.                                                @job_id   OUTPUT
  5391.   IF (@retval <> 0)
  5392.     RETURN(1) -- Failure
  5393.  
  5394.   -- The show-last-run-details flag must be either 1 or 0
  5395.   IF (@show_last_run_details <> 0)
  5396.     SELECT @show_last_run_details = 1
  5397.  
  5398.   IF (@show_last_run_details = 1)
  5399.   BEGIN
  5400.     -- List the servers that @job_name has been targeted at (INCLUDING last-run details)
  5401.     SELECT stsv.server_id,
  5402.            stsv.server_name,
  5403.            stsv.enlist_date,
  5404.            stsv.last_poll_date,
  5405.            sjs.last_run_date,
  5406.            sjs.last_run_time,
  5407.            sjs.last_run_duration,
  5408.            sjs.last_run_outcome,  -- Same as JOB_OUTCOME_CODE (SQLAGENT_EXEC_x)
  5409.            sjs.last_outcome_message
  5410.     FROM msdb.dbo.sysjobservers         sjs  LEFT OUTER JOIN
  5411.          msdb.dbo.systargetservers_view stsv ON (sjs.server_id = stsv.server_id)
  5412.     WHERE (sjs.job_id = @job_id)
  5413.   END
  5414.   ELSE
  5415.   BEGIN
  5416.     -- List the servers that @job_name has been targeted at (EXCLUDING last-run details)
  5417.     SELECT stsv.server_id,
  5418.            stsv.server_name,
  5419.            stsv.enlist_date,
  5420.            stsv.last_poll_date
  5421.     FROM msdb.dbo.sysjobservers         sjs  LEFT OUTER JOIN
  5422.          msdb.dbo.systargetservers_view stsv ON (sjs.server_id = stsv.server_id)
  5423.     WHERE (sjs.job_id = @job_id)
  5424.   END
  5425.  
  5426.   RETURN(@@error) -- 0 means success
  5427. END
  5428. go
  5429.  
  5430. /**************************************************************/
  5431. /* SP_HELP_DOWNLOADLIST                                       */
  5432. /**************************************************************/
  5433.  
  5434. PRINT ''
  5435. PRINT 'Creating procedure sp_help_downloadlist...'
  5436. go
  5437. IF (EXISTS (SELECT *
  5438.             FROM msdb.dbo.sysobjects
  5439.             WHERE (name = N'sp_help_downloadlist')
  5440.               AND (type = 'P')))
  5441.   DROP PROCEDURE sp_help_downloadlist
  5442. go
  5443. CREATE PROCEDURE sp_help_downloadlist
  5444.   @job_id          UNIQUEIDENTIFIER = NULL, -- If provided must NOT also provide job_name
  5445.   @job_name        sysname          = NULL, -- If provided must NOT also provide job_id
  5446.   @operation       VARCHAR(64)      = NULL,
  5447.   @object_type     VARCHAR(64)      = NULL, -- Only 'JOB' or 'SERVER' are valid in 7.0
  5448.   @object_name     sysname          = NULL,
  5449.   @target_server   NVARCHAR(30)     = NULL,
  5450.   @has_error       TINYINT          = NULL, -- NULL or 1
  5451.   @status          TINYINT          = NULL,
  5452.   @date_posted     DATETIME         = NULL  -- Include all entries made on OR AFTER this date
  5453. AS
  5454. BEGIN
  5455.   DECLARE @retval         INT
  5456.   DECLARE @operation_code INT
  5457.   DECLARE @object_type_id TINYINT
  5458.  
  5459.   SET NOCOUNT ON
  5460.  
  5461.   -- Remove any leading/trailing spaces from parameters
  5462.   SELECT @operation     = LTRIM(RTRIM(@operation))
  5463.   SELECT @object_type   = LTRIM(RTRIM(@object_type))
  5464.   SELECT @object_name   = LTRIM(RTRIM(@object_name))
  5465.   SELECT @target_server = LTRIM(RTRIM(@target_server))
  5466.  
  5467.   -- Turn [nullable] empty string parameters into NULLs
  5468.   IF (@operation     = '') SELECT @operation = NULL
  5469.   IF (@object_type   = '') SELECT @object_type = NULL
  5470.   IF (@object_name   = N'') SELECT @object_name = NULL
  5471.   IF (@target_server = N'') SELECT @target_server = NULL
  5472.  
  5473.   IF ((@job_id IS NOT NULL) OR (@job_name IS NOT NULL))
  5474.   BEGIN
  5475.     EXECUTE @retval = sp_verify_job_identifiers '@job_name',
  5476.                                                 '@job_id',
  5477.                                                  @job_name OUTPUT,
  5478.                                                  @job_id   OUTPUT
  5479.     IF (@retval <> 0)
  5480.       RETURN(1) -- Failure
  5481.   END
  5482.  
  5483.   -- Check operation
  5484.   IF (@operation IS NOT NULL)
  5485.   BEGIN
  5486.     SELECT @operation = UPPER(@operation)
  5487.     SELECT @operation_code = CASE @operation
  5488.                                WHEN 'INSERT'    THEN 1
  5489.                                WHEN 'UPDATE'    THEN 2
  5490.                                WHEN 'DELETE'    THEN 3
  5491.                                WHEN 'START'     THEN 4
  5492.                                WHEN 'STOP'      THEN 5
  5493.                                WHEN 'RE-ENLIST' THEN 6
  5494.                                WHEN 'DEFECT'    THEN 7
  5495.                                WHEN 'SYNC-TIME' THEN 8
  5496.                                WHEN 'SET-POLL'  THEN 9
  5497.                                ELSE 0
  5498.                              END
  5499.     IF (@operation_code = 0)
  5500.     BEGIN
  5501.       RAISERROR(14266, -1, -1, '@operation_code', 'INSERT, UPDATE, DELETE, START, STOP, RE-ENLIST, DEFECT, SYNC-TIME, SET-POLL')
  5502.       RETURN(1) -- Failure
  5503.     END
  5504.   END
  5505.  
  5506.   -- Check object type (in 7.0 only 'JOB' and 'SERVER' are valid)
  5507.   IF (@object_type IS NOT NULL)
  5508.   BEGIN
  5509.     SELECT @object_type = UPPER(@object_type)
  5510.     IF ((@object_type <> 'JOB') AND (@object_type <> 'SERVER'))
  5511.     BEGIN
  5512.       RAISERROR(14266, -1, -1, '@object_type', 'JOB, SERVER')
  5513.       RETURN(1) -- Failure
  5514.     END
  5515.     ELSE
  5516.       SELECT @object_type_id = CASE @object_type
  5517.                                  WHEN 'JOB'    THEN 1
  5518.                                  WHEN 'SERVER' THEN 2
  5519.                                  ELSE 0
  5520.                                END
  5521.   END
  5522.  
  5523.   -- If object-type is supplied then object-name must also be supplied
  5524.   IF ((@object_type IS NOT NULL) AND (@object_name IS NULL)) OR
  5525.      ((@object_type IS NULL)     AND (@object_name IS NOT NULL))
  5526.   BEGIN
  5527.     RAISERROR(14272, -1, -1)
  5528.     RETURN(1) -- Failure
  5529.   END
  5530.  
  5531.   -- Check target server
  5532.   IF (@target_server IS NOT NULL) AND NOT EXISTS (SELECT *
  5533.                                                   FROM msdb.dbo.systargetservers
  5534.                                                   WHERE server_name = @target_server)
  5535.   BEGIN
  5536.     RAISERROR(14262, -1, -1, '@target_server', @target_server)
  5537.     RETURN(1) -- Failure
  5538.   END
  5539.  
  5540.   -- Check has-error
  5541.   IF (@has_error IS NOT NULL) AND (@has_error <> 1)
  5542.   BEGIN
  5543.     RAISERROR(14266, -1, -1, '@has_error', '1, NULL')
  5544.     RETURN(1) -- Failure
  5545.   END
  5546.  
  5547.   -- Check status
  5548.   IF (@status IS NOT NULL) AND (@status <> 0) AND (@status <> 1)
  5549.   BEGIN
  5550.     RAISERROR(14266, -1, -1, '@status', '0, 1')
  5551.     RETURN(1) -- Failure
  5552.   END
  5553.  
  5554.   -- Return the result set
  5555.   SELECT sdl.instance_id,
  5556.          sdl.source_server,
  5557.         'operation_code' = CASE sdl.operation_code
  5558.                              WHEN 1 THEN '1 (INSERT)'
  5559.                              WHEN 2 THEN '2 (UPDATE)'
  5560.                              WHEN 3 THEN '3 (DELETE)'
  5561.                              WHEN 4 THEN '4 (START)'
  5562.                              WHEN 5 THEN '5 (STOP)'
  5563.                              WHEN 6 THEN '6 (RE-ENLIST)'
  5564.                              WHEN 7 THEN '7 (DEFECT)'
  5565.                              WHEN 8 THEN '8 (SYNC-TIME)'
  5566.                              WHEN 9 THEN '9 (SET-POLL)'
  5567.                              ELSE CONVERT(VARCHAR, sdl.operation_code) + ' ' + FORMATMESSAGE(14205)
  5568.                            END,
  5569.         'object_name' = ISNULL(sjv.name, CASE
  5570.                                            WHEN (sdl.operation_code >= 1) AND (sdl.operation_code <= 5) AND (sdl.object_id = CONVERT(UNIQUEIDENTIFIER, 0x00)) THEN FORMATMESSAGE(14212) -- '(all jobs)'
  5571.                                            WHEN (sdl.operation_code  = 3) AND (sdl.object_id <> CONVERT(UNIQUEIDENTIFIER, 0x00)) THEN sdl.deleted_object_name -- Special case handling for a deleted job
  5572.                                            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)
  5573.                                            WHEN (sdl.operation_code >= 6) AND (sdl.operation_code <= 9) THEN sdl.target_server
  5574.                                            ELSE FORMATMESSAGE(14205)
  5575.                                          END),
  5576.         'object_id' = ISNULL(sjv.job_id, CASE sdl.object_id
  5577.                                            WHEN CONVERT(UNIQUEIDENTIFIER, 0x00) THEN CONVERT(UNIQUEIDENTIFIER, 0x00)
  5578.                                            ELSE sdl.object_id
  5579.                                          END),
  5580.          sdl.target_server,
  5581.          sdl.error_message,
  5582.          sdl.date_posted,
  5583.          sdl.date_downloaded,
  5584.          sdl.status
  5585.   FROM msdb.dbo.sysdownloadlist sdl LEFT OUTER JOIN
  5586.        msdb.dbo.sysjobs_view    sjv ON (sdl.object_id = sjv.job_id)
  5587.   WHERE ((@operation_code IS NULL) OR (operation_code = @operation_code))
  5588.     AND ((@object_type_id IS NULL) OR (object_type = @object_type_id))
  5589.     AND ((@job_id         IS NULL) OR (object_id = @job_id))
  5590.     AND ((@target_server  IS NULL) OR (target_server = @target_server))
  5591.     AND ((@has_error      IS NULL) OR (DATALENGTH(error_message) >= 1 * @has_error))
  5592.     AND ((@status         IS NULL) OR (status = @status))
  5593.     AND ((@date_posted    IS NULL) OR (date_posted >= @date_posted))
  5594.   ORDER BY sdl.instance_id
  5595.  
  5596.   RETURN(@@error) -- 0 means success
  5597.  
  5598. END
  5599. go
  5600.  
  5601. /**************************************************************/
  5602. /* SP_ENUM_SQLAGENT_SUBSYSTEMS                                */
  5603. /**************************************************************/
  5604.  
  5605. PRINT ''
  5606. PRINT 'Creating procedure sp_enum_sqlagent_subsystems...'
  5607. go
  5608. IF (EXISTS (SELECT *
  5609.             FROM msdb.dbo.sysobjects
  5610.             WHERE (name = N'sp_enum_sqlagent_subsystems')
  5611.               AND (type = 'P')))
  5612.   DROP PROCEDURE sp_enum_sqlagent_subsystems
  5613. go
  5614. CREATE PROCEDURE sp_enum_sqlagent_subsystems
  5615. AS
  5616. BEGIN
  5617.   DECLARE @part                  NVARCHAR(300)
  5618.   DECLARE @fmt                   NVARCHAR(300)
  5619.   DECLARE @subsystem             NVARCHAR(40)
  5620.   DECLARE @replication_installed INT
  5621.  
  5622.   SET NOCOUNT ON
  5623.  
  5624.   CREATE TABLE #xp_results (subsystem   NVARCHAR(40)  COLLATE database_default NOT NULL,
  5625.                             description NVARCHAR(300) COLLATE database_default NOT NULL)
  5626.   CREATE TABLE #sp_enum_ss_temp (subsystem          NVARCHAR(40)  COLLATE database_default NOT NULL,
  5627.                                  description        NVARCHAR(80)  COLLATE database_default NOT NULL,
  5628.                                  subsystem_dll      NVARCHAR(255) COLLATE database_default NULL,
  5629.                                  agent_exe          NVARCHAR(80)  COLLATE database_default NULL,
  5630.                                  start_entry_point  NVARCHAR(30)  COLLATE database_default NULL,
  5631.                                  event_entry_point  NVARCHAR(30)  COLLATE database_default NULL,
  5632.                                  stop_entry_point   NVARCHAR(30)  COLLATE database_default NULL,
  5633.                                  max_worker_threads INT           NULL)
  5634.  
  5635.   -- Check if replication is installed
  5636.   EXECUTE master.dbo.xp_instance_regread N'HKEY_LOCAL_MACHINE',
  5637.                                          N'SOFTWARE\Microsoft\MSSQLServer\Replication',
  5638.                                          N'IsInstalled',
  5639.                                          @replication_installed OUTPUT,
  5640.                                          N'no_output'
  5641.   SELECT @replication_installed = ISNULL(@replication_installed, 0)
  5642.  
  5643.   INSERT INTO #xp_results
  5644.   EXECUTE master.dbo.xp_instance_regenumvalues N'HKEY_LOCAL_MACHINE', N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent\SubSystems'
  5645.  
  5646.   IF (@replication_installed = 0)
  5647.   BEGIN
  5648.     DELETE FROM #xp_results
  5649.     WHERE (subsystem IN (N'Distribution', N'LogReader', N'Merge', N'Snapshot', N'QueueReader'))
  5650.   END
  5651.  
  5652.   DECLARE all_subsystems CURSOR LOCAL
  5653.   FOR
  5654.   SELECT subsystem, description
  5655.   FROM #xp_results
  5656.  
  5657.   OPEN all_subsystems
  5658.   FETCH NEXT FROM all_subsystems INTO @subsystem, @part
  5659.   WHILE (@@fetch_status = 0)
  5660.   BEGIN
  5661.     IF (@subsystem = N'TSQL')
  5662.       INSERT INTO #sp_enum_ss_temp VALUES (N'TSQL', FORMATMESSAGE(14556), FORMATMESSAGE(14557), FORMATMESSAGE(14557), FORMATMESSAGE(14557), FORMATMESSAGE(14557), FORMATMESSAGE(14557), CONVERT(INT, @part))
  5663.     ELSE
  5664.     BEGIN
  5665.       SELECT @fmt = N''
  5666.       WHILE (CHARINDEX(N',', @part) > 0)
  5667.       BEGIN
  5668.         SELECT @fmt = @fmt + 'N''' + SUBSTRING(@part, 1, CHARINDEX(N',', @part) - 1) + ''', '
  5669.         SELECT @part = RIGHT(@part, (DATALENGTH(@part) / 2) - CHARINDEX(N',', @part))
  5670.       END
  5671.       SELECT @fmt = @fmt + @part
  5672.       IF (DATALENGTH(@fmt) > 0)
  5673.         INSERT INTO #sp_enum_ss_temp
  5674.         EXECUTE(N'SELECT ''' + @subsystem + N''', N'''', ' + @fmt)
  5675.     END
  5676.     FETCH NEXT FROM all_subsystems INTO @subsystem, @part
  5677.   END
  5678.   DEALLOCATE all_subsystems
  5679.  
  5680.   UPDATE #sp_enum_ss_temp SET description = FORMATMESSAGE(14550)
  5681.   WHERE (subsystem = N'CmdExec')
  5682.   UPDATE #sp_enum_ss_temp SET description = FORMATMESSAGE(14551)
  5683.   WHERE (subsystem = N'Snapshot')
  5684.   UPDATE #sp_enum_ss_temp SET description = FORMATMESSAGE(14552)
  5685.   WHERE (subsystem = N'LogReader')
  5686.   UPDATE #sp_enum_ss_temp SET description = FORMATMESSAGE(14553)
  5687.   WHERE (subsystem = N'Distribution')
  5688.   UPDATE #sp_enum_ss_temp SET description = FORMATMESSAGE(14554)
  5689.   WHERE (subsystem = N'Merge')
  5690.   UPDATE #sp_enum_ss_temp SET description = FORMATMESSAGE(14555)
  5691.   WHERE (subsystem = N'ActiveScripting')
  5692.   UPDATE #sp_enum_ss_temp SET description = FORMATMESSAGE(14581)
  5693.   WHERE (subsystem = N'QueueReader')
  5694.  
  5695.   -- 'TSQL' is always available (since it's a built-in subsystem), so we explicity add it
  5696.   -- to the result set
  5697.   IF (NOT EXISTS (SELECT *
  5698.                   FROM #sp_enum_ss_temp
  5699.                   WHERE (subsystem = N'TSQL')))
  5700.     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
  5701.  
  5702.   SELECT subsystem,
  5703.          description,
  5704.          subsystem_dll,
  5705.          agent_exe,
  5706.          start_entry_point,
  5707.          event_entry_point,
  5708.          stop_entry_point,
  5709.          max_worker_threads
  5710.   FROM #sp_enum_ss_temp
  5711.   ORDER BY subsystem
  5712. END
  5713. go
  5714.  
  5715. /**************************************************************/
  5716. /* SP_VERIFY_SUBSYSTEM                                        */
  5717. /**************************************************************/
  5718.  
  5719. PRINT ''
  5720. PRINT 'Creating procedure sp_verify_subsystem...'
  5721. go
  5722. IF (EXISTS (SELECT *
  5723.             FROM msdb.dbo.sysobjects
  5724.             WHERE (name = N'sp_verify_subsystem')
  5725.               AND (type = 'P')))
  5726.   DROP PROCEDURE sp_verify_subsystem
  5727. go
  5728. CREATE PROCEDURE sp_verify_subsystem
  5729.   @subsystem NVARCHAR(40)
  5730. AS
  5731. BEGIN
  5732.   SET NOCOUNT ON
  5733.  
  5734.   -- Remove any leading/trailing spaces from parameters
  5735.   SELECT @subsystem = LTRIM(RTRIM(@subsystem))
  5736.  
  5737.   -- NOTE: We don't use the results of sp_enum_sqlagent_subsystems for performance reasons
  5738.   IF (UPPER(@subsystem) IN (N'ACTIVESCRIPTING',
  5739.                             N'CMDEXEC',
  5740.                             N'DISTRIBUTION',
  5741.                             N'SNAPSHOT',
  5742.                             N'LOGREADER',
  5743.                             N'MERGE',
  5744.                             N'TSQL',
  5745.                             N'QUEUEREADER'))
  5746.     RETURN(0) -- Success
  5747.   ELSE
  5748.   BEGIN
  5749.     RAISERROR(14234, -1, -1, '@subsystem', 'sp_enum_sqlagent_subsystems')
  5750.     RETURN(1) -- Failure
  5751.   END
  5752. END
  5753. go
  5754.  
  5755. /**************************************************************/
  5756. /* SP_GET_JOBSTEP_DB_USERNAME                                 */
  5757. /*                                                            */
  5758. /* NOTE: For NT login names this procedure can take several   */
  5759. /*       seconds to return as it hits the PDC/BDC.            */
  5760. /*       SQLServerAgent calls this at runtime.                */
  5761. /**************************************************************/
  5762.  
  5763. PRINT ''
  5764. PRINT 'Creating procedure sp_get_jobstep_db_username...'
  5765. go
  5766. IF (EXISTS (SELECT *
  5767.             FROM msdb.dbo.sysobjects
  5768.             WHERE (name = N'sp_get_jobstep_db_username ')
  5769.               AND (type = 'P')))
  5770.   DROP PROCEDURE sp_get_jobstep_db_username
  5771. go
  5772. CREATE PROCEDURE sp_get_jobstep_db_username
  5773.   @database_name        sysname,
  5774.   @login_name           sysname = NULL,
  5775.   @username_in_targetdb sysname OUTPUT
  5776. AS
  5777. BEGIN
  5778.   DECLARE @suser_sid_clause NVARCHAR(200)
  5779.  
  5780.   CREATE TABLE #temp_username (user_name sysname COLLATE database_default NOT NULL, is_aliased BIT)
  5781.  
  5782.   -- Check the database name
  5783.   IF (DB_ID(@database_name) IS NULL)
  5784.   BEGIN
  5785.     RAISERROR(14262, 16, 1, 'database', @database_name)
  5786.     RETURN(1) -- Failure
  5787.   END
  5788.  
  5789.   -- Initialize return value
  5790.   SELECT @username_in_targetdb = NULL
  5791.  
  5792.   -- Make sure login name is never NULL
  5793.   IF (@login_name IS NULL)
  5794.     SELECT @login_name = SUSER_SNAME()
  5795.   IF (@login_name IS NULL)
  5796.     RETURN(1) -- Failure
  5797.  
  5798.   -- Handle an NT login name
  5799.   IF (@login_name LIKE N'%\%')
  5800.   BEGIN
  5801.     -- Special case...
  5802.     IF (UPPER(@login_name) = N'NT AUTHORITY\SYSTEM')
  5803.       SELECT @username_in_targetdb = N'dbo'
  5804.     ELSE
  5805.       SELECT @username_in_targetdb = @login_name
  5806.  
  5807.     RETURN(0) -- Success
  5808.   END
  5809.  
  5810.   -- Handle a SQL login name
  5811.   SELECT @suser_sid_clause = N'SUSER_SID(N''' + @login_name + N''')'
  5812.   IF (SUSER_SID(@login_name) IS NULL)
  5813.     RETURN(1) -- Failure
  5814.  
  5815.   -- 1) Look for the user name of the current login in the target database
  5816.   INSERT INTO #temp_username
  5817.   EXECUTE (N'SET NOCOUNT ON
  5818.              SELECT name, isaliased
  5819.              FROM '+ @database_name + N'.dbo.sysusers
  5820.              WHERE (sid = ' + @suser_sid_clause + N')
  5821.                AND (hasdbaccess = 1)')
  5822.  
  5823.   -- 2) Look for the alias user name of the current login in the target database
  5824.   IF (EXISTS (SELECT *
  5825.               FROM #temp_username
  5826.               WHERE (is_aliased = 1)))
  5827.   BEGIN
  5828.     TRUNCATE TABLE #temp_username
  5829.     INSERT INTO #temp_username
  5830.     EXECUTE (N'SET NOCOUNT ON
  5831.                SELECT name, 0
  5832.                FROM '+ @database_name + N'.dbo.sysusers
  5833.                WHERE uid = (SELECT altuid
  5834.                             FROM ' + @database_name + N'.dbo.sysusers
  5835.                             WHERE (sid = ' + @suser_sid_clause + N'))
  5836.                  AND (hasdbaccess = 1)')
  5837.   END
  5838.  
  5839.   -- 3) Look for the guest user name in the target database
  5840.   IF (NOT EXISTS (SELECT *
  5841.                   FROM #temp_username))
  5842.     INSERT INTO #temp_username
  5843.     EXECUTE (N'SET NOCOUNT ON
  5844.                SELECT name, 0
  5845.                FROM '+ @database_name + N'.dbo.sysusers
  5846.                WHERE (name = N''guest'')
  5847.                  AND (hasdbaccess = 1)')
  5848.  
  5849.   SELECT @username_in_targetdb = user_name
  5850.   FROM #temp_username
  5851.  
  5852.   RETURN(0) -- Success
  5853. END
  5854. go
  5855.  
  5856. /**************************************************************/
  5857. /* SP_VERIFY_JOBSTEP                                          */
  5858. /**************************************************************/
  5859.  
  5860. PRINT ''
  5861. PRINT 'Creating procedure sp_verify_jobstep...'
  5862. go
  5863. IF (EXISTS (SELECT *
  5864.             FROM msdb.dbo.sysobjects
  5865.             WHERE (name = N'sp_verify_jobstep')
  5866.               AND (type = 'P')))
  5867.   DROP PROCEDURE sp_verify_jobstep
  5868. go
  5869. CREATE PROCEDURE sp_verify_jobstep
  5870.   @job_id             UNIQUEIDENTIFIER,
  5871.   @step_id            INT,
  5872.   @step_name          sysname,
  5873.   @subsystem          NVARCHAR(40),
  5874.   @command            NVARCHAR(3201),
  5875.   @server             NVARCHAR(30),
  5876.   @on_success_action  TINYINT,
  5877.   @on_success_step_id INT,
  5878.   @on_fail_action     TINYINT,
  5879.   @on_fail_step_id    INT,
  5880.   @os_run_priority    INT,
  5881.   @database_name      sysname OUTPUT,
  5882.   @database_user_name sysname OUTPUT,
  5883.   @flags              INT,
  5884.   @output_file_name   NVARCHAR(200)
  5885. AS
  5886. BEGIN
  5887.   DECLARE @max_step_id             INT
  5888.   DECLARE @retval                  INT
  5889.   DECLARE @valid_values            VARCHAR(50)
  5890.   DECLARE @owner_login_name        sysname
  5891.   DECLARE @database_name_temp      sysname
  5892.   DECLARE @database_user_name_temp sysname
  5893.   DECLARE @temp_command            NVARCHAR(3200)
  5894.   DECLARE @iPos                    INT
  5895.   DECLARE @create_count            INT
  5896.   DECLARE @destroy_count           INT
  5897.  
  5898.   SET NOCOUNT ON
  5899.  
  5900.   -- Remove any leading/trailing spaces from parameters
  5901.   SELECT @subsystem        = LTRIM(RTRIM(@subsystem))
  5902.   SELECT @server           = LTRIM(RTRIM(@server))
  5903.   SELECT @output_file_name = LTRIM(RTRIM(@output_file_name))
  5904.  
  5905.   -- Get current maximum step id
  5906.   SELECT @max_step_id = ISNULL(MAX(step_id), 0)
  5907.   FROM msdb.dbo.sysjobsteps
  5908.   WHERE (job_id = @job_id)
  5909.  
  5910.   -- Check step id
  5911.   IF (@step_id < 1) OR (@step_id > @max_step_id + 1)
  5912.   BEGIN
  5913.     SELECT @valid_values = '1..' + CONVERT(VARCHAR, @max_step_id + 1)
  5914.     RAISERROR(14266, -1, -1, '@step_id', @valid_values)
  5915.     RETURN(1) -- Failure
  5916.   END
  5917.  
  5918.   -- Check subsystem
  5919.   EXECUTE @retval = sp_verify_subsystem @subsystem
  5920.   IF (@retval <> 0)
  5921.     RETURN(1) -- Failure
  5922.  
  5923.   -- Check command length
  5924.   IF ((DATALENGTH(@command) / 2) > 3200)
  5925.   BEGIN
  5926.     RAISERROR(14250, 16, 1, '@command', 3200)
  5927.     RETURN(1) -- Failure
  5928.   END
  5929.  
  5930.   -- For a VBScript command, check that object creations are paired with object destructions
  5931.   IF ((UPPER(@subsystem) = N'ACTIVESCRIPTING') AND (@database_name = N'VBScript'))
  5932.   BEGIN
  5933.     SELECT @temp_command = @command
  5934.  
  5935.     SELECT @create_count = 0
  5936.     SELECT @iPos = PATINDEX('%[Cc]reate[Oo]bject[ (]%', @temp_command)
  5937.     WHILE(@iPos > 0)
  5938.     BEGIN
  5939.       SELECT @temp_command = SUBSTRING(@temp_command, @iPos + 1, DATALENGTH(@temp_command) / 2)
  5940.       SELECT @iPos = PATINDEX('%[Cc]reate[Oo]bject[ (]%', @temp_command)
  5941.       SELECT @create_count = @create_count + 1
  5942.     END
  5943.  
  5944.     SELECT @destroy_count = 0
  5945.     SELECT @iPos = PATINDEX('%[Ss]et %=%[Nn]othing%', @temp_command)
  5946.     WHILE(@iPos > 0)
  5947.     BEGIN
  5948.       SELECT @temp_command = SUBSTRING(@temp_command, @iPos + 1, DATALENGTH(@temp_command) / 2)
  5949.       SELECT @iPos = PATINDEX('%[Ss]et %=%[Nn]othing%', @temp_command)
  5950.       SELECT @destroy_count = @destroy_count + 1
  5951.     END
  5952.  
  5953.     IF(@create_count > @destroy_count)
  5954.     BEGIN
  5955.       RAISERROR(14277, -1, -1)
  5956.       RETURN(1) -- Failure
  5957.     END
  5958.   END
  5959.  
  5960.   -- Check step name
  5961.   IF (EXISTS (SELECT *
  5962.               FROM msdb.dbo.sysjobsteps
  5963.               WHERE (job_id = @job_id)
  5964.                 AND (step_name = @step_name)))
  5965.   BEGIN
  5966.     RAISERROR(14261, -1, -1, '@step_name', @step_name)
  5967.     RETURN(1) -- Failure
  5968.   END
  5969.  
  5970.   -- Check on-success action/step
  5971.   IF (@on_success_action <> 1) AND -- Quit Qith Success
  5972.      (@on_success_action <> 2) AND -- Quit Qith Failure
  5973.      (@on_success_action <> 3) AND -- Goto Next Step
  5974.      (@on_success_action <> 4)     -- Goto Step
  5975.   BEGIN
  5976.     RAISERROR(14266, -1, -1, '@on_success_action', '1, 2, 3, 4')
  5977.     RETURN(1) -- Failure
  5978.   END
  5979.   IF (@on_success_action = 4) AND
  5980.      ((@on_success_step_id < 1) OR (@on_success_step_id = @step_id))
  5981.   BEGIN
  5982.     -- NOTE: We allow forward references to non-existant steps to prevent the user from
  5983.     --       having to make a second update pass to fix up the flow
  5984.     RAISERROR(14235, -1, -1, '@on_success_step', @step_id)
  5985.     RETURN(1) -- Failure
  5986.   END
  5987.  
  5988.   -- Check on-fail action/step
  5989.   IF (@on_fail_action <> 1) AND -- Quit Qith Success
  5990.      (@on_fail_action <> 2) AND -- Quit Qith Failure
  5991.      (@on_fail_action <> 3) AND -- Goto Next Step
  5992.      (@on_fail_action <> 4)     -- Goto Step
  5993.   BEGIN
  5994.     RAISERROR(14266, -1, -1, '@on_failure_action', '1, 2, 3, 4')
  5995.     RETURN(1) -- Failure
  5996.   END
  5997.   IF (@on_fail_action = 4) AND
  5998.      ((@on_fail_step_id < 1) OR (@on_fail_step_id = @step_id))
  5999.   BEGIN
  6000.     -- NOTE: We allow forward references to non-existant steps to prevent the user from
  6001.     --       having to make a second update pass to fix up the flow
  6002.     RAISERROR(14235, -1, -1, '@on_failure_step', @step_id)
  6003.     RETURN(1) -- Failure
  6004.   END
  6005.  
  6006.   -- Warn the user about forward references
  6007.   IF ((@on_success_action = 4) AND (@on_success_step_id > @max_step_id))
  6008.     RAISERROR(14236, 0, 1, '@on_success_step_id')
  6009.   IF ((@on_fail_action = 4) AND (@on_fail_step_id > @max_step_id))
  6010.     RAISERROR(14236, 0, 1, '@on_fail_step_id')
  6011.  
  6012.   -- Check server (this is the replication server, NOT the job-target server)
  6013.   IF (@server IS NOT NULL) AND (NOT EXISTS (SELECT *
  6014.                                             FROM master.dbo.sysservers
  6015.                                             WHERE (UPPER(srvname) = UPPER(@server))))
  6016.   BEGIN
  6017.     RAISERROR(14234, -1, -1, '@server', 'sp_helpserver')
  6018.     RETURN(1) -- Failure
  6019.   END
  6020.  
  6021.   -- Check run priority: must be a valid value to pass to SetThreadPriority:
  6022.   -- [-15 = IDLE, -1 = BELOW_NORMAL, 0 = NORMAL, 1 = ABOVE_NORMAL, 15 = TIME_CRITICAL]
  6023.   IF (@os_run_priority NOT IN (-15, -1, 0, 1, 15))
  6024.   BEGIN
  6025.     RAISERROR(14266, -1, -1, '@os_run_priority', '-15, -1, 0, 1, 15')
  6026.     RETURN(1) -- Failure
  6027.   END
  6028.  
  6029.   -- Check flags
  6030.   IF ((@flags < 0) OR (@flags > 7))
  6031.   BEGIN
  6032.     RAISERROR(14266, -1, -1, '@flags', '0..7')
  6033.     RETURN(1) -- Failure
  6034.   END
  6035.  
  6036.   -- Check output file
  6037.   IF (@output_file_name IS NOT NULL) AND (UPPER(@subsystem) NOT IN ('TSQL', 'CMDEXEC'))
  6038.   BEGIN
  6039.     RAISERROR(14545, -1, -1, '@output_file_name', @subsystem)
  6040.     RETURN(1) -- Failure
  6041.   END
  6042.  
  6043.   -- For CmdExec steps database-name and database-user-name should both be null
  6044.   IF (UPPER(@subsystem) = N'CMDEXEC')
  6045.     SELECT @database_name = NULL,
  6046.            @database_user_name = NULL
  6047.  
  6048.   -- For non-TSQL steps, database-user-name should be null
  6049.   IF (UPPER(@subsystem) <> 'TSQL')
  6050.     SELECT @database_user_name = NULL
  6051.  
  6052.   -- For a TSQL step, get (and check) the username of the caller in the target database.
  6053.   IF (UPPER(@subsystem) = 'TSQL')
  6054.   BEGIN
  6055.     SET NOCOUNT ON
  6056.  
  6057.     -- But first check if remote server name has been supplied
  6058.     IF (@server IS NOT NULL)
  6059.       SELECT @server = NULL
  6060.  
  6061.     -- Default database to 'master' if not supplied
  6062.     IF (LTRIM(RTRIM(@database_name)) IS NULL)
  6063.       SELECT @database_name = N'master'
  6064.  
  6065.     -- Check the database (although this is no guarantee that @database_user_name can access it)
  6066.     IF (DB_ID(@database_name) IS NULL)
  6067.     BEGIN
  6068.       RAISERROR(14262, -1, -1, '@database_name', @database_name)
  6069.       RETURN(1) -- Failure
  6070.     END
  6071.  
  6072.     SELECT @owner_login_name = SUSER_SNAME(owner_sid)
  6073.     FROM msdb.dbo.sysjobs
  6074.     WHERE (job_id = @job_id)
  6075.  
  6076.     SELECT @database_user_name = LTRIM(RTRIM(@database_user_name))
  6077.  
  6078.     -- Only if a SysAdmin is creating the job can the database user name be non-NULL [since only
  6079.     -- SysAdmin's can call SETUSER].
  6080.     -- NOTE: In this case we don't try to validate the user name (it's too costly to do so)
  6081.     --       so if it's bad we'll get a runtime error when the job executes.
  6082.     IF (ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) = 1)
  6083.     BEGIN
  6084.       -- Special case handling if the username is 'sa'
  6085.       IF (UPPER(@database_user_name) = N'SA')
  6086.         SELECT @database_user_name = NULL
  6087.  
  6088.       -- If this is a multi-server job then @database_user_name must be null
  6089.       IF (@database_user_name IS NOT NULL)
  6090.       BEGIN
  6091.         IF (EXISTS (SELECT *
  6092.                     FROM msdb.dbo.sysjobs       sj,
  6093.                          msdb.dbo.sysjobservers sjs
  6094.                     WHERE (sj.job_id = sjs.job_id)
  6095.                       AND (sj.job_id = @job_id)
  6096.                       AND (sjs.server_id <> 0)))
  6097.         BEGIN
  6098.           RAISERROR(14542, -1, -1, N'database_user_name')
  6099.           RETURN(1) -- Failure
  6100.         END
  6101.       END
  6102.  
  6103.       -- For a SQL-user, check if it exists
  6104.       IF (@database_user_name NOT LIKE N'%\%')
  6105.       BEGIN
  6106.         SELECT @database_user_name_temp = REPLACE(@database_user_name, N'''', N'''''')
  6107.         SELECT @database_name_temp = REPLACE(@database_name, N'''', N'''''')
  6108.  
  6109.         EXECUTE(N'DECLARE @ret INT
  6110.                   SELECT @ret = COUNT(*)
  6111.                   FROM ' + @database_name_temp + N'.dbo.sysusers
  6112.                   WHERE (name = N''' + @database_user_name_temp + N''')
  6113.                   HAVING (COUNT(*) > 0)')
  6114.         IF (@@ROWCOUNT = 0)
  6115.         BEGIN
  6116.           RAISERROR(14262, -1, -1, '@database_user_name', @database_user_name)
  6117.           RETURN(1) -- Failure
  6118.         END
  6119.       END
  6120.     END
  6121.     ELSE
  6122.       SELECT @database_user_name = NULL
  6123.  
  6124.   END  -- End of TSQL property verification
  6125.  
  6126.   RETURN(0) -- Success
  6127. END
  6128. go
  6129.  
  6130. /**************************************************************/
  6131. /* SP_ADD_JOBSTEP                                             */
  6132. /**************************************************************/
  6133.  
  6134. PRINT ''
  6135. PRINT 'Creating procedure sp_add_jobstep...'
  6136. go
  6137. IF (EXISTS (SELECT *
  6138.             FROM msdb.dbo.sysobjects
  6139.             WHERE (name = N'sp_add_jobstep')
  6140.               AND (type = 'P')))
  6141.   DROP PROCEDURE sp_add_jobstep
  6142. go
  6143. CREATE PROCEDURE sp_add_jobstep
  6144.   @job_id                UNIQUEIDENTIFIER = NULL,   -- Must provide either this or job_name
  6145.   @job_name              sysname          = NULL,   -- Must provide either this or job_id
  6146.   @step_id               INT              = NULL,   -- The proc assigns a default
  6147.   @step_name             sysname,
  6148.   @subsystem             NVARCHAR(40)     = N'TSQL',
  6149.   @command               NVARCHAR(3201)   = NULL,   -- We declare this as NVARCHAR(3201) not NVARCHAR(3200) so that we can catch 'silent truncation' of commands
  6150.   @additional_parameters NTEXT            = NULL,
  6151.   @cmdexec_success_code  INT              = 0,
  6152.   @on_success_action     TINYINT          = 1,      -- 1 = Quit With Success, 2 = Quit With Failure, 3 = Goto Next Step, 4 = Goto Step
  6153.   @on_success_step_id    INT              = 0,
  6154.   @on_fail_action        TINYINT          = 2,      -- 1 = Quit With Success, 2 = Quit With Failure, 3 = Goto Next Step, 4 = Goto Step
  6155.   @on_fail_step_id       INT              = 0,
  6156.   @server                NVARCHAR(30)     = NULL,
  6157.   @database_name         sysname          = NULL,
  6158.   @database_user_name    sysname          = NULL,
  6159.   @retry_attempts        INT              = 0,      -- No retries
  6160.   @retry_interval        INT              = 0,      -- 0 minute interval
  6161.   @os_run_priority       INT              = 0,      -- -15 = Idle, -1 = Below Normal, 0 = Normal, 1 = Above Normal, 15 = Time Critical)
  6162.   @output_file_name      NVARCHAR(200)    = NULL,
  6163.   @flags                 INT              = 0       -- 0 = Normal, 1 = Encrypted command (read only), 2 = Append output files (if any), 4 = Write TSQL step output to step history
  6164. AS
  6165. BEGIN
  6166.   DECLARE @retval      INT
  6167.   DECLARE @max_step_id INT
  6168.  
  6169.   SET NOCOUNT ON
  6170.  
  6171.   -- Remove any leading/trailing spaces from parameters
  6172.   SELECT @step_name          = LTRIM(RTRIM(@step_name))
  6173.   SELECT @subsystem          = LTRIM(RTRIM(@subsystem))
  6174.   SELECT @server             = LTRIM(RTRIM(@server))
  6175.   SELECT @database_name      = LTRIM(RTRIM(@database_name))
  6176.   SELECT @database_user_name = LTRIM(RTRIM(@database_user_name))
  6177.   SELECT @output_file_name   = LTRIM(RTRIM(@output_file_name))
  6178.  
  6179.   -- Turn [nullable] empty string parameters into NULLs
  6180.   IF (@server             = N'') SELECT @server             = NULL
  6181.   IF (@database_name      = N'') SELECT @database_name      = NULL
  6182.   IF (@database_user_name = N'') SELECT @database_user_name = NULL
  6183.   IF (@output_file_name   = N'') SELECT @output_file_name   = NULL
  6184.  
  6185.   -- Check authority (only SQLServerAgent can add a step to a non-local job)
  6186.   EXECUTE @retval = sp_verify_jobproc_caller @job_id = @job_id, @program_name = N'SQLAgent%'
  6187.   IF (@retval <> 0)
  6188.     RETURN(@retval)
  6189.  
  6190.   EXECUTE @retval = sp_verify_job_identifiers '@job_name',
  6191.                                               '@job_id',
  6192.                                                @job_name OUTPUT,
  6193.                                                @job_id   OUTPUT
  6194.   IF (@retval <> 0)
  6195.     RETURN(1) -- Failure
  6196.  
  6197.   -- Default step id (if not supplied)
  6198.   IF (@step_id IS NULL)
  6199.   BEGIN
  6200.     SELECT @step_id = ISNULL(MAX(step_id), 0) + 1
  6201.     FROM msdb.dbo.sysjobsteps
  6202.     WHERE (job_id = @job_id)
  6203.   END
  6204.  
  6205.   -- Check parameters
  6206.   EXECUTE @retval = sp_verify_jobstep @job_id,
  6207.                                       @step_id,
  6208.                                       @step_name,
  6209.                                       @subsystem,
  6210.                                       @command,
  6211.                                       @server,
  6212.                                       @on_success_action,
  6213.                                       @on_success_step_id,
  6214.                                       @on_fail_action,
  6215.                                       @on_fail_step_id,
  6216.                                       @os_run_priority,
  6217.                                       @database_name      OUTPUT,
  6218.                                       @database_user_name OUTPUT,
  6219.                                       @flags,
  6220.                                       @output_file_name
  6221.   IF (@retval <> 0)
  6222.     RETURN(1) -- Failure
  6223.  
  6224.   -- Get current maximum step id
  6225.   SELECT @max_step_id = ISNULL(MAX(step_id), 0)
  6226.   FROM msdb.dbo.sysjobsteps
  6227.   WHERE (job_id = @job_id)
  6228.  
  6229.   BEGIN TRANSACTION
  6230.  
  6231.     -- Update the job's version/last-modified information
  6232.     UPDATE msdb.dbo.sysjobs
  6233.     SET version_number = version_number + 1,
  6234.         date_modified = GETDATE()
  6235.     WHERE (job_id = @job_id)
  6236.  
  6237.     -- Adjust step id's (unless the new step is being inserted at the 'end')
  6238.     -- NOTE: We MUST do this before inserting the step.
  6239.     IF (@step_id <= @max_step_id)
  6240.     BEGIN
  6241.       UPDATE msdb.dbo.sysjobsteps
  6242.       SET step_id = step_id + 1
  6243.       WHERE (step_id >= @step_id)
  6244.         AND (job_id = @job_id)
  6245.  
  6246.       -- Clean up OnSuccess/OnFail references
  6247.       UPDATE msdb.dbo.sysjobsteps
  6248.       SET on_success_step_id = on_success_step_id + 1
  6249.       WHERE (on_success_step_id >= @step_id)
  6250.         AND (job_id = @job_id)
  6251.  
  6252.       UPDATE msdb.dbo.sysjobsteps
  6253.       SET on_fail_step_id = on_fail_step_id + 1
  6254.       WHERE (on_fail_step_id >= @step_id)
  6255.         AND (job_id = @job_id)
  6256.  
  6257.       UPDATE msdb.dbo.sysjobsteps
  6258.       SET on_success_step_id = 0,
  6259.           on_success_action = 1  -- Quit With Success
  6260.       WHERE (on_success_step_id = @step_id)
  6261.         AND (job_id = @job_id)
  6262.  
  6263.       UPDATE msdb.dbo.sysjobsteps
  6264.       SET on_fail_step_id = 0,
  6265.           on_fail_action = 2     -- Quit With Failure
  6266.       WHERE (on_fail_step_id = @step_id)
  6267.         AND (job_id = @job_id)
  6268.     END
  6269.  
  6270.     -- Insert the step
  6271.     INSERT INTO msdb.dbo.sysjobsteps
  6272.            (job_id,
  6273.             step_id,
  6274.             step_name,
  6275.             subsystem,
  6276.             command,
  6277.             flags,
  6278.             additional_parameters,
  6279.             cmdexec_success_code,
  6280.             on_success_action,
  6281.             on_success_step_id,
  6282.             on_fail_action,
  6283.             on_fail_step_id,
  6284.             server,
  6285.             database_name,
  6286.             database_user_name,
  6287.             retry_attempts,
  6288.             retry_interval,
  6289.             os_run_priority,
  6290.             output_file_name,
  6291.             last_run_outcome,
  6292.             last_run_duration,
  6293.             last_run_retries,
  6294.             last_run_date,
  6295.             last_run_time)
  6296.     VALUES (@job_id,
  6297.             @step_id,
  6298.             @step_name,
  6299.             @subsystem,
  6300.             @command,
  6301.             @flags,
  6302.             @additional_parameters,
  6303.             @cmdexec_success_code,
  6304.             @on_success_action,
  6305.             @on_success_step_id,
  6306.             @on_fail_action,
  6307.             @on_fail_step_id,
  6308.             @server,
  6309.             @database_name,
  6310.             @database_user_name,
  6311.             @retry_attempts,
  6312.             @retry_interval,
  6313.             @os_run_priority,
  6314.             @output_file_name,
  6315.             0,
  6316.             0,
  6317.             0,
  6318.             0,
  6319.             0)
  6320.  
  6321.   COMMIT TRANSACTION
  6322.  
  6323.   -- Make sure that SQLServerAgent refreshes the job if the 'Has Steps' property has changed
  6324.   IF ((SELECT COUNT(*)
  6325.        FROM msdb.dbo.sysjobsteps
  6326.        WHERE (job_id = @job_id)) = 1)
  6327.   BEGIN
  6328.     -- NOTE: We only notify SQLServerAgent if we know the job has been cached
  6329.     IF (EXISTS (SELECT *
  6330.                 FROM msdb.dbo.sysjobservers
  6331.                 WHERE (job_id = @job_id)
  6332.                   AND (server_id = 0)))
  6333.       EXECUTE msdb.dbo.sp_sqlagent_notify @op_type       = N'J',
  6334.                                             @job_id      = @job_id,
  6335.                                             @action_type = N'U'
  6336.   END
  6337.  
  6338.   -- For a multi-server job, remind the user that they need to call sp_post_msx_operation
  6339.   IF (EXISTS (SELECT *
  6340.               FROM msdb.dbo.sysjobservers
  6341.               WHERE (job_id = @job_id)
  6342.                 AND (server_id <> 0)))
  6343.     RAISERROR(14547, 0, 1, N'INSERT', N'sp_post_msx_operation')
  6344.  
  6345.   RETURN(0) -- Success
  6346. END
  6347. go
  6348.  
  6349. /**************************************************************/
  6350. /* SP_UPDATE_JOBSTEP                                          */
  6351. /**************************************************************/
  6352.  
  6353. PRINT ''
  6354. PRINT 'Creating procedure sp_update_jobstep...'
  6355. go
  6356. IF (EXISTS (SELECT *
  6357.             FROM msdb.dbo.sysobjects
  6358.             WHERE (name = N'sp_update_jobstep')
  6359.               AND (type = 'P')))
  6360.   DROP PROCEDURE sp_update_jobstep
  6361. go
  6362. CREATE PROCEDURE sp_update_jobstep
  6363.   @job_id                 UNIQUEIDENTIFIER = NULL, -- Must provide either this or job_name
  6364.   @job_name               sysname          = NULL, -- Not updatable (provided for identification purposes only)
  6365.   @step_id                INT,                     -- Not updatable (provided for identification purposes only)
  6366.   @step_name              sysname          = NULL,
  6367.   @subsystem              NVARCHAR(40)     = NULL,
  6368.   @command                NVARCHAR(3201)   = NULL, -- We declare this as NVARCHAR(3201) not NVARCHAR(3200) so that we can catch 'silent truncation' of commands
  6369.   @additional_parameters  NTEXT            = NULL,
  6370.   @cmdexec_success_code   INT              = NULL,
  6371.   @on_success_action      TINYINT          = NULL,
  6372.   @on_success_step_id     INT              = NULL,
  6373.   @on_fail_action         TINYINT          = NULL,
  6374.   @on_fail_step_id        INT              = NULL,
  6375.   @server                 NVARCHAR(30)     = NULL,
  6376.   @database_name          sysname          = NULL,
  6377.   @database_user_name     sysname          = NULL,
  6378.   @retry_attempts         INT              = NULL,
  6379.   @retry_interval         INT              = NULL,
  6380.   @os_run_priority        INT              = NULL,
  6381.   @output_file_name       NVARCHAR(200)    = NULL,
  6382.   @flags                  INT              = NULL
  6383. AS
  6384. BEGIN
  6385.   DECLARE @retval                 INT
  6386.   DECLARE @os_run_priority_code   INT
  6387.   DECLARE @step_id_as_char        VARCHAR(10)
  6388.   DECLARE @new_step_name          sysname
  6389.  
  6390.   DECLARE @x_step_name            sysname
  6391.   DECLARE @x_subsystem            NVARCHAR(40)
  6392.   DECLARE @x_command              NVARCHAR(3200)
  6393.   DECLARE @x_flags                INT
  6394.   DECLARE @x_cmdexec_success_code INT
  6395.   DECLARE @x_on_success_action    TINYINT
  6396.   DECLARE @x_on_success_step_id   INT
  6397.   DECLARE @x_on_fail_action       TINYINT
  6398.   DECLARE @x_on_fail_step_id      INT
  6399.   DECLARE @x_server               NVARCHAR(30)
  6400.   DECLARE @x_database_name        sysname
  6401.   DECLARE @x_database_user_name   sysname
  6402.   DECLARE @x_retry_attempts       INT
  6403.   DECLARE @x_retry_interval       INT
  6404.   DECLARE @x_os_run_priority      INT
  6405.   DECLARE @x_output_file_name     NVARCHAR(200)
  6406.   DECLARE @x_last_run_outcome     TINYINT      -- Not updatable (but may be in future)
  6407.   DECLARE @x_last_run_duration    INT          -- Not updatable (but may be in future)
  6408.   DECLARE @x_last_run_retries     INT          -- Not updatable (but may be in future)
  6409.   DECLARE @x_last_run_date        INT          -- Not updatable (but may be in future)
  6410.   DECLARE @x_last_run_time        INT          -- Not updatable (but may be in future)
  6411.  
  6412.   SET NOCOUNT ON
  6413.  
  6414.   -- Remove any leading/trailing spaces from parameters
  6415.   SELECT @step_name          = LTRIM(RTRIM(@step_name))
  6416.   SELECT @subsystem          = LTRIM(RTRIM(@subsystem))
  6417.   SELECT @command            = LTRIM(RTRIM(@command))
  6418.   SELECT @server             = LTRIM(RTRIM(@server))
  6419.   SELECT @database_name      = LTRIM(RTRIM(@database_name))
  6420.   SELECT @database_user_name = LTRIM(RTRIM(@database_user_name))
  6421.   SELECT @output_file_name   = LTRIM(RTRIM(@output_file_name))
  6422.  
  6423.   EXECUTE @retval = sp_verify_job_identifiers '@job_name',
  6424.                                               '@job_id',
  6425.                                                @job_name OUTPUT,
  6426.                                                @job_id   OUTPUT
  6427.   IF (@retval <> 0)
  6428.     RETURN(1) -- Failure
  6429.  
  6430.   -- Check that the step exists
  6431.   IF (NOT EXISTS (SELECT *
  6432.                   FROM msdb.dbo.sysjobsteps
  6433.                   WHERE (job_id = @job_id)
  6434.                     AND (step_id = @step_id)))
  6435.   BEGIN
  6436.     SELECT @step_id_as_char = CONVERT(VARCHAR(10), @step_id)
  6437.     RAISERROR(14262, -1, -1, '@step_id', @step_id_as_char)
  6438.     RETURN(1) -- Failure
  6439.   END
  6440.  
  6441.   -- Check authority (only SQLServerAgent can modify a step of a non-local job)
  6442.   EXECUTE @retval = sp_verify_jobproc_caller @job_id = @job_id, @program_name = N'SQLAgent%'
  6443.   IF (@retval <> 0)
  6444.     RETURN(@retval)
  6445.  
  6446.   -- Set the x_ (existing) variables
  6447.   SELECT @x_step_name            = step_name,
  6448.          @x_subsystem            = subsystem,
  6449.          @x_command              = command,
  6450.          @x_flags                = flags,
  6451.          @x_cmdexec_success_code = cmdexec_success_code,
  6452.          @x_on_success_action    = on_success_action,
  6453.          @x_on_success_step_id   = on_success_step_id,
  6454.          @x_on_fail_action       = on_fail_action,
  6455.          @x_on_fail_step_id      = on_fail_step_id,
  6456.          @x_server               = server,
  6457.          @x_database_name        = database_name,
  6458.          @x_database_user_name   = database_user_name,
  6459.          @x_retry_attempts       = retry_attempts,
  6460.          @x_retry_interval       = retry_interval,
  6461.          @x_os_run_priority      = os_run_priority,
  6462.          @x_output_file_name     = output_file_name,
  6463.          @x_last_run_outcome     = last_run_outcome,
  6464.          @x_last_run_duration    = last_run_duration,
  6465.          @x_last_run_retries     = last_run_retries,
  6466.          @x_last_run_date        = last_run_date,
  6467.          @x_last_run_time        = last_run_time
  6468.   FROM msdb.dbo.sysjobsteps
  6469.   WHERE (job_id = @job_id)
  6470.     AND (step_id = @step_id)
  6471.  
  6472.   IF ((@step_name IS NOT NULL) AND (@step_name <> @x_step_name))
  6473.     SELECT @new_step_name = @step_name
  6474.  
  6475.   -- Fill out the values for all non-supplied parameters from the existing values
  6476.   IF (@step_name            IS NULL) SELECT @step_name            = @x_step_name
  6477.   IF (@subsystem            IS NULL) SELECT @subsystem            = @x_subsystem
  6478.   IF (@command              IS NULL) SELECT @command              = @x_command
  6479.   IF (@flags                IS NULL) SELECT @flags                = @x_flags
  6480.   IF (@cmdexec_success_code IS NULL) SELECT @cmdexec_success_code = @x_cmdexec_success_code
  6481.   IF (@on_success_action    IS NULL) SELECT @on_success_action    = @x_on_success_action
  6482.   IF (@on_success_step_id   IS NULL) SELECT @on_success_step_id   = @x_on_success_step_id
  6483.   IF (@on_fail_action       IS NULL) SELECT @on_fail_action       = @x_on_fail_action
  6484.   IF (@on_fail_step_id      IS NULL) SELECT @on_fail_step_id      = @x_on_fail_step_id
  6485.   IF (@server               IS NULL) SELECT @server               = @x_server
  6486.   IF (@database_name        IS NULL) SELECT @database_name        = @x_database_name
  6487.   IF (@database_user_name   IS NULL) SELECT @database_user_name   = @x_database_user_name
  6488.   IF (@retry_attempts       IS NULL) SELECT @retry_attempts       = @x_retry_attempts
  6489.   IF (@retry_interval       IS NULL) SELECT @retry_interval       = @x_retry_interval
  6490.   IF (@os_run_priority      IS NULL) SELECT @os_run_priority      = @x_os_run_priority
  6491.   IF (@output_file_name     IS NULL) SELECT @output_file_name     = @x_output_file_name
  6492.  
  6493.   -- Turn [nullable] empty string parameters into NULLs
  6494.   IF (@command            = N'') SELECT @command            = NULL
  6495.   IF (@server             = N'') SELECT @server             = NULL
  6496.   IF (@database_name      = N'') SELECT @database_name      = NULL
  6497.   IF (@database_user_name = N'') SELECT @database_user_name = NULL
  6498.   IF (@output_file_name   = N'') SELECT @output_file_name   = NULL
  6499.  
  6500.   -- Check new values
  6501.   EXECUTE @retval = sp_verify_jobstep @job_id,
  6502.                                       @step_id,
  6503.                                       @new_step_name,
  6504.                                       @subsystem,
  6505.                                       @command,
  6506.                                       @server,
  6507.                                       @on_success_action,
  6508.                                       @on_success_step_id,
  6509.                                       @on_fail_action,
  6510.                                       @on_fail_step_id,
  6511.                                       @os_run_priority,
  6512.                                       @database_name      OUTPUT,
  6513.                                       @database_user_name OUTPUT,
  6514.                                       @flags,
  6515.                                       @output_file_name
  6516.   IF (@retval <> 0)
  6517.     RETURN(1) -- Failure
  6518.  
  6519.   BEGIN TRANSACTION
  6520.  
  6521.     -- Update the job's version/last-modified information
  6522.     UPDATE msdb.dbo.sysjobs
  6523.     SET version_number = version_number + 1,
  6524.         date_modified = GETDATE()
  6525.     WHERE (job_id = @job_id)
  6526.  
  6527.     -- Update the step
  6528.     UPDATE msdb.dbo.sysjobsteps
  6529.     SET step_name             = @step_name,
  6530.         subsystem             = @subsystem,
  6531.         command               = @command,
  6532.         flags                 = @flags,
  6533.         cmdexec_success_code  = @cmdexec_success_code,
  6534.         on_success_action     = @on_success_action,
  6535.         on_success_step_id    = @on_success_step_id,
  6536.         on_fail_action        = @on_fail_action,
  6537.         on_fail_step_id       = @on_fail_step_id,
  6538.         server                = @server,
  6539.         database_name         = @database_name,
  6540.         database_user_name    = @database_user_name,
  6541.         retry_attempts        = @retry_attempts,
  6542.         retry_interval        = @retry_interval,
  6543.         os_run_priority       = @os_run_priority,
  6544.         output_file_name      = @output_file_name,
  6545.         last_run_outcome      = @x_last_run_outcome,
  6546.         last_run_duration     = @x_last_run_duration,
  6547.         last_run_retries      = @x_last_run_retries,
  6548.         last_run_date         = @x_last_run_date,
  6549.         last_run_time         = @x_last_run_time
  6550.     WHERE (job_id = @job_id)
  6551.       AND (step_id = @step_id)
  6552.  
  6553.     -- Since we can't declare TEXT parameters (and therefore use the @x_ technique) we handle
  6554.     -- @additional_parameters as a special case...
  6555.     IF (@additional_parameters IS NOT NULL)
  6556.     BEGIN
  6557.       UPDATE msdb.dbo.sysjobsteps
  6558.       SET additional_parameters = @additional_parameters
  6559.       WHERE (job_id = @job_id)
  6560.         AND (step_id = @step_id)
  6561.     END
  6562.  
  6563.   COMMIT TRANSACTION
  6564.  
  6565.   -- For a multi-server job, remind the user that they need to call sp_post_msx_operation
  6566.   IF (EXISTS (SELECT *
  6567.               FROM msdb.dbo.sysjobservers
  6568.               WHERE (job_id = @job_id)
  6569.                 AND (server_id <> 0)))
  6570.     RAISERROR(14547, 0, 1, N'INSERT', N'sp_post_msx_operation')
  6571.  
  6572.   RETURN(0) -- Success
  6573. END
  6574. go
  6575.  
  6576. /**************************************************************/
  6577. /* SP_DELETE_JOBSTEP                                          */
  6578. /**************************************************************/
  6579.  
  6580. PRINT ''
  6581. PRINT 'Creating procedure sp_delete_jobstep...'
  6582. go
  6583. IF (EXISTS (SELECT *
  6584.             FROM msdb.dbo.sysobjects
  6585.             WHERE (name = N'sp_delete_jobstep')
  6586.               AND (type = 'P')))
  6587.   DROP PROCEDURE sp_delete_jobstep
  6588. go
  6589. CREATE PROCEDURE sp_delete_jobstep
  6590.   @job_id   UNIQUEIDENTIFIER = NULL, -- Must provide either this or job_name
  6591.   @job_name sysname          = NULL, -- Must provide either this or job_id
  6592.   @step_id  INT
  6593. AS
  6594. BEGIN
  6595.   DECLARE @retval      INT
  6596.   DECLARE @max_step_id INT
  6597.   DECLARE @valid_range VARCHAR(50)
  6598.  
  6599.   SET NOCOUNT ON
  6600.  
  6601.   EXECUTE @retval = sp_verify_job_identifiers '@job_name',
  6602.                                               '@job_id',
  6603.                                                @job_name OUTPUT,
  6604.                                                @job_id   OUTPUT
  6605.   IF (@retval <> 0)
  6606.     RETURN(1) -- Failure
  6607.  
  6608.   -- Check authority (only SQLServerAgent can delete a step of a non-local job)
  6609.   EXECUTE @retval = sp_verify_jobproc_caller @job_id = @job_id, @program_name = 'SQLAgent%'
  6610.   IF (@retval <> 0)
  6611.     RETURN(@retval)
  6612.  
  6613.   -- Get current maximum step id
  6614.   SELECT @max_step_id = ISNULL(MAX(step_id), 0)
  6615.   FROM msdb.dbo.sysjobsteps
  6616.   WHERE (job_id = @job_id)
  6617.  
  6618.   -- Check step id
  6619.   IF (@step_id < 0) OR (@step_id > @max_step_id)
  6620.   BEGIN
  6621.     SELECT @valid_range = FORMATMESSAGE(14201) + CONVERT(VARCHAR, @max_step_id)
  6622.     RAISERROR(14266, -1, -1, '@step_id', @valid_range)
  6623.     RETURN(1) -- Failure
  6624.   END
  6625.  
  6626.   BEGIN TRANSACTION
  6627.  
  6628.     -- Delete either the specified step or ALL the steps (if step id is 0)
  6629.     IF (@step_id = 0)
  6630.       DELETE FROM msdb.dbo.sysjobsteps
  6631.       WHERE (job_id = @job_id)
  6632.     ELSE
  6633.       DELETE FROM msdb.dbo.sysjobsteps
  6634.       WHERE (job_id = @job_id)
  6635.         AND (step_id = @step_id)
  6636.  
  6637.     IF (@step_id <> 0)
  6638.     BEGIN
  6639.       -- Adjust step id's
  6640.       UPDATE msdb.dbo.sysjobsteps
  6641.       SET step_id = step_id - 1
  6642.       WHERE (step_id > @step_id)
  6643.         AND (job_id = @job_id)
  6644.  
  6645.       -- Clean up OnSuccess/OnFail references
  6646.       UPDATE msdb.dbo.sysjobsteps
  6647.       SET on_success_step_id = on_success_step_id - 1
  6648.       WHERE (on_success_step_id > @step_id)
  6649.         AND (job_id = @job_id)
  6650.  
  6651.       UPDATE msdb.dbo.sysjobsteps
  6652.       SET on_fail_step_id = on_fail_step_id - 1
  6653.       WHERE (on_fail_step_id > @step_id)
  6654.         AND (job_id = @job_id)
  6655.  
  6656.       UPDATE msdb.dbo.sysjobsteps
  6657.       SET on_success_step_id = 0,
  6658.           on_success_action = 1   -- Quit With Success
  6659.       WHERE (on_success_step_id = @step_id)
  6660.         AND (job_id = @job_id)
  6661.  
  6662.       UPDATE msdb.dbo.sysjobsteps
  6663.       SET on_fail_step_id = 0,
  6664.           on_fail_action = 2   -- Quit With Failure
  6665.       WHERE (on_fail_step_id = @step_id)
  6666.         AND (job_id = @job_id)
  6667.     END
  6668.  
  6669.     -- Update the job's version/last-modified information
  6670.     UPDATE msdb.dbo.sysjobs
  6671.     SET version_number = version_number + 1,
  6672.         date_modified = GETDATE()
  6673.     WHERE (job_id = @job_id)
  6674.  
  6675.   COMMIT TRANSACTION
  6676.  
  6677.   -- Make sure that SQLServerAgent refreshes the job if the 'Has Steps' property has changed
  6678.   IF ((SELECT COUNT(*)
  6679.        FROM msdb.dbo.sysjobsteps
  6680.        WHERE (job_id = @job_id)) = 0)
  6681.   BEGIN
  6682.     -- NOTE: We only notify SQLServerAgent if we know the job has been cached
  6683.     IF (EXISTS (SELECT *
  6684.                 FROM msdb.dbo.sysjobservers
  6685.                 WHERE (job_id = @job_id)
  6686.                   AND (server_id = 0)))
  6687.       EXECUTE msdb.dbo.sp_sqlagent_notify @op_type       = N'J',
  6688.                                             @job_id      = @job_id,
  6689.                                             @action_type = N'U'
  6690.   END
  6691.  
  6692.   -- For a multi-server job, remind the user that they need to call sp_post_msx_operation
  6693.   IF (EXISTS (SELECT *
  6694.               FROM msdb.dbo.sysjobservers
  6695.               WHERE (job_id = @job_id)
  6696.                 AND (server_id <> 0)))
  6697.     RAISERROR(14547, 0, 1, N'INSERT', N'sp_post_msx_operation')
  6698.  
  6699.   RETURN(0) -- Success
  6700. END
  6701. go
  6702.  
  6703. /**************************************************************/
  6704. /* SP_HELP_JOBSTEP                                            */
  6705. /**************************************************************/
  6706.  
  6707. PRINT ''
  6708. PRINT 'Creating procedure sp_help_jobstep...'
  6709. go
  6710. IF (EXISTS (SELECT *
  6711.             FROM msdb.dbo.sysobjects
  6712.             WHERE (name = N'sp_help_jobstep')
  6713.               AND (type = 'P')))
  6714.   DROP PROCEDURE sp_help_jobstep
  6715. go
  6716. CREATE PROCEDURE sp_help_jobstep
  6717.   @job_id    UNIQUEIDENTIFIER = NULL, -- Must provide either this or job_name
  6718.   @job_name  sysname          = NULL, -- Must provide either this or job_id
  6719.   @step_id   INT              = NULL,
  6720.   @step_name sysname          = NULL,
  6721.   @suffix    BIT              = 0     -- A flag to control how the result set is formatted
  6722. AS
  6723. BEGIN
  6724.   DECLARE @retval      INT
  6725.   DECLARE @max_step_id INT
  6726.   DECLARE @valid_range VARCHAR(50)
  6727.  
  6728.   SET NOCOUNT ON
  6729.  
  6730.   EXECUTE @retval = sp_verify_job_identifiers '@job_name',
  6731.                                               '@job_id',
  6732.                                                @job_name OUTPUT,
  6733.                                                @job_id   OUTPUT,
  6734.                                               'NO_TEST'
  6735.   IF (@retval <> 0)
  6736.     RETURN(1) -- Failure
  6737.  
  6738.   -- The suffix flag must be either 0 (ie. no suffix) or 1 (ie. add suffix). 0 is the default.
  6739.   IF (@suffix <> 0)
  6740.     SELECT @suffix = 1
  6741.  
  6742.   -- Check step id (if supplied)
  6743.   IF (@step_id IS NOT NULL)
  6744.   BEGIN
  6745.     -- Get current maximum step id
  6746.     SELECT @max_step_id = ISNULL(MAX(step_id), 0)
  6747.     FROM msdb.dbo.sysjobsteps
  6748.     WHERE job_id = @job_id
  6749.  
  6750.     IF (@step_id < 1) OR (@step_id > @max_step_id)
  6751.     BEGIN
  6752.       SELECT @valid_range = '1..' + CONVERT(VARCHAR, @max_step_id)
  6753.       RAISERROR(14266, -1, -1, '@step_id', @valid_range)
  6754.       RETURN(1) -- Failure
  6755.     END
  6756.   END
  6757.  
  6758.   -- Check step name (if supplied)
  6759.   -- NOTE: A supplied step id overrides a supplied step name
  6760.   IF ((@step_id IS NULL) AND (@step_name IS NOT NULL))
  6761.   BEGIN
  6762.     SELECT @step_id = step_id
  6763.     FROM msdb.dbo.sysjobsteps
  6764.     WHERE (step_name = @step_name)
  6765.       AND (job_id = @job_id)
  6766.  
  6767.     IF (@step_id IS NULL)
  6768.     BEGIN
  6769.       RAISERROR(14262, -1, -1, '@step_name', @step_name)
  6770.       RETURN(1) -- Failure
  6771.     END
  6772.   END
  6773.  
  6774.   -- Return the job steps for this job (or just return the specific step)
  6775.   IF (@suffix = 0)
  6776.   BEGIN
  6777.     SELECT step_id,
  6778.            step_name,
  6779.            subsystem,
  6780.            command,
  6781.            flags,
  6782.            cmdexec_success_code,
  6783.            on_success_action,
  6784.            on_success_step_id,
  6785.            on_fail_action,
  6786.            on_fail_step_id,
  6787.            server,
  6788.            database_name,
  6789.            database_user_name,
  6790.            retry_attempts,
  6791.            retry_interval,
  6792.            os_run_priority,
  6793.            output_file_name,
  6794.            last_run_outcome,
  6795.            last_run_duration,
  6796.            last_run_retries,
  6797.            last_run_date,
  6798.            last_run_time
  6799.     FROM msdb.dbo.sysjobsteps
  6800.     WHERE (job_id = @job_id)
  6801.       AND ((@step_id IS NULL) OR (step_id = @step_id))
  6802.   END
  6803.   ELSE
  6804.   BEGIN
  6805.     SELECT step_id,
  6806.            step_name,
  6807.            subsystem,
  6808.            command,
  6809.           'flags' = CONVERT(NVARCHAR, flags) + N' (' +
  6810.                     ISNULL(CASE WHEN (flags = 0)     THEN FORMATMESSAGE(14561) END, '') +
  6811.                     ISNULL(CASE WHEN (flags & 1) = 1 THEN FORMATMESSAGE(14558) + ISNULL(CASE WHEN (flags > 1) THEN N', ' END, '') END, '') +
  6812.                     ISNULL(CASE WHEN (flags & 2) = 2 THEN FORMATMESSAGE(14559) + ISNULL(CASE WHEN (flags > 3) THEN N', ' END, '') END, '') +
  6813.                     ISNULL(CASE WHEN (flags & 4) = 4 THEN FORMATMESSAGE(14560) END, '') + N')',
  6814.            cmdexec_success_code,
  6815.           'on_success_action' = CASE on_success_action
  6816.                                   WHEN 1 THEN CONVERT(NVARCHAR, on_success_action) + N' ' + FORMATMESSAGE(14562)
  6817.                                   WHEN 2 THEN CONVERT(NVARCHAR, on_success_action) + N' ' + FORMATMESSAGE(14563)
  6818.                                   WHEN 3 THEN CONVERT(NVARCHAR, on_success_action) + N' ' + FORMATMESSAGE(14564)
  6819.                                   WHEN 4 THEN CONVERT(NVARCHAR, on_success_action) + N' ' + FORMATMESSAGE(14565)
  6820.                                   ELSE        CONVERT(NVARCHAR, on_success_action) + N' ' + FORMATMESSAGE(14205)
  6821.                                 END,
  6822.            on_success_step_id,
  6823.           'on_fail_action' = CASE on_fail_action
  6824.                                WHEN 1 THEN CONVERT(NVARCHAR, on_fail_action) + N' ' + FORMATMESSAGE(14562)
  6825.                                WHEN 2 THEN CONVERT(NVARCHAR, on_fail_action) + N' ' + FORMATMESSAGE(14563)
  6826.                                WHEN 3 THEN CONVERT(NVARCHAR, on_fail_action) + N' ' + FORMATMESSAGE(14564)
  6827.                                WHEN 4 THEN CONVERT(NVARCHAR, on_fail_action) + N' ' + FORMATMESSAGE(14565)
  6828.                                ELSE        CONVERT(NVARCHAR, on_fail_action) + N' ' + FORMATMESSAGE(14205)
  6829.                              END,
  6830.            on_fail_step_id,
  6831.            server,
  6832.            database_name,
  6833.            database_user_name,
  6834.            retry_attempts,
  6835.            retry_interval,
  6836.           'os_run_priority' = CASE os_run_priority
  6837.                                 WHEN -15 THEN CONVERT(NVARCHAR, os_run_priority) + N' ' + FORMATMESSAGE(14566)
  6838.                                 WHEN -1  THEN CONVERT(NVARCHAR, os_run_priority) + N' ' + FORMATMESSAGE(14567)
  6839.                                 WHEN  0  THEN CONVERT(NVARCHAR, os_run_priority) + N' ' + FORMATMESSAGE(14561)
  6840.                                 WHEN  1  THEN CONVERT(NVARCHAR, os_run_priority) + N' ' + FORMATMESSAGE(14568)
  6841.                                 WHEN  15 THEN CONVERT(NVARCHAR, os_run_priority) + N' ' + FORMATMESSAGE(14569)
  6842.                                 ELSE          CONVERT(NVARCHAR, os_run_priority) + N' ' + FORMATMESSAGE(14205)
  6843.                               END,
  6844.            output_file_name,
  6845.            last_run_outcome,
  6846.            last_run_duration,
  6847.            last_run_retries,
  6848.            last_run_date,
  6849.            last_run_time
  6850.     FROM msdb.dbo.sysjobsteps
  6851.     WHERE (job_id = @job_id)
  6852.       AND ((@step_id IS NULL) OR (step_id = @step_id))
  6853.   END
  6854.  
  6855.   RETURN(@@error) -- 0 means success
  6856.  
  6857. END
  6858. go
  6859.  
  6860. /**************************************************************/
  6861. /* SP_GET_SCHEDULE_DESCRIPTION                                */
  6862. /*                                                            */
  6863. /* NOTE: This SP only returns an English description of the   */
  6864. /*       schedule due to the piecemeal nature of the          */
  6865. /*       description's construction.                          */
  6866. /**************************************************************/
  6867.  
  6868. PRINT ''
  6869. PRINT 'Creating procedure sp_get_schedule_description...'
  6870. go
  6871. IF (EXISTS (SELECT *
  6872.             FROM msdb.dbo.sysobjects
  6873.             WHERE (name = N'sp_get_schedule_description')
  6874.               AND (type = 'P')))
  6875.   DROP PROCEDURE sp_get_schedule_description
  6876. go
  6877. CREATE PROCEDURE sp_get_schedule_description
  6878.   @freq_type              INT          = NULL,
  6879.   @freq_interval          INT          = NULL,
  6880.   @freq_subday_type       INT          = NULL,
  6881.   @freq_subday_interval   INT          = NULL,
  6882.   @freq_relative_interval INT          = NULL,
  6883.   @freq_recurrence_factor INT          = NULL,
  6884.   @active_start_date      INT          = NULL,
  6885.   @active_end_date        INT          = NULL,
  6886.   @active_start_time      INT          = NULL,
  6887.   @active_end_time        INT          = NULL,
  6888.   @schedule_description   NVARCHAR(255) OUTPUT
  6889. AS
  6890. BEGIN
  6891.   DECLARE @loop              INT
  6892.   DECLARE @idle_cpu_percent  INT
  6893.   DECLARE @idle_cpu_duration INT
  6894.  
  6895.   SET NOCOUNT ON
  6896.  
  6897.   IF (@freq_type = 0x1) -- OneTime
  6898.   BEGIN
  6899.     SELECT @schedule_description = N'Once on ' + CONVERT(NVARCHAR, @active_start_date) + N' at ' + CONVERT(NVARCHAR, @active_start_time)
  6900.     RETURN
  6901.   END
  6902.  
  6903.   IF (@freq_type = 0x4) -- Daily
  6904.   BEGIN
  6905.     SELECT @schedule_description = N'Every day '
  6906.   END
  6907.  
  6908.   IF (@freq_type = 0x8) -- Weekly
  6909.   BEGIN
  6910.     SELECT @schedule_description = N'Every ' + CONVERT(NVARCHAR, @freq_recurrence_factor) + N' week(s) on '
  6911.     SELECT @loop = 1
  6912.     WHILE (@loop <= 7)
  6913.     BEGIN
  6914.       IF (@freq_interval & POWER(2, @loop - 1) = POWER(2, @loop - 1))
  6915.         SELECT @schedule_description = @schedule_description + DATENAME(dw, N'1996120' + CONVERT(NVARCHAR, @loop)) + N', '
  6916.       SELECT @loop = @loop + 1
  6917.     END
  6918.     IF (RIGHT(@schedule_description, 2) = N', ')
  6919.       SELECT @schedule_description = SUBSTRING(@schedule_description, 1, (DATALENGTH(@schedule_description) / 2) - 2) + N' '
  6920.   END
  6921.  
  6922.   IF (@freq_type = 0x10) -- Monthly
  6923.   BEGIN
  6924.     SELECT @schedule_description = N'Every ' + CONVERT(NVARCHAR, @freq_recurrence_factor) + N' months(s) on day ' + CONVERT(NVARCHAR, @freq_interval) + N' of that month '
  6925.   END
  6926.  
  6927.   IF (@freq_type = 0x20) -- Monthly Relative
  6928.   BEGIN
  6929.     SELECT @schedule_description = N'Every ' + CONVERT(NVARCHAR, @freq_recurrence_factor) + N' months(s) on the '
  6930.     SELECT @schedule_description = @schedule_description +
  6931.       CASE @freq_relative_interval
  6932.         WHEN 0x01 THEN N'first '
  6933.         WHEN 0x02 THEN N'second '
  6934.         WHEN 0x04 THEN N'third '
  6935.         WHEN 0x08 THEN N'fourth '
  6936.         WHEN 0x10 THEN N'last '
  6937.       END +
  6938.       CASE
  6939.         WHEN (@freq_interval > 00)
  6940.          AND (@freq_interval < 08) THEN DATENAME(dw, N'1996120' + CONVERT(NVARCHAR, @freq_interval))
  6941.         WHEN (@freq_interval = 08) THEN N'day'
  6942.         WHEN (@freq_interval = 09) THEN N'week day'
  6943.         WHEN (@freq_interval = 10) THEN N'weekend day'
  6944.       END + N' of that month '
  6945.   END
  6946.  
  6947.   IF (@freq_type = 0x40) -- AutoStart
  6948.   BEGIN
  6949.     SELECT @schedule_description = FORMATMESSAGE(14579)
  6950.     RETURN
  6951.   END
  6952.  
  6953.   IF (@freq_type = 0x80) -- OnIdle
  6954.   BEGIN
  6955.     EXECUTE master.dbo.xp_instance_regread N'HKEY_LOCAL_MACHINE',
  6956.                                            N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
  6957.                                            N'IdleCPUPercent',
  6958.                                            @idle_cpu_percent OUTPUT,
  6959.                                            N'no_output'
  6960.     EXECUTE master.dbo.xp_instance_regread N'HKEY_LOCAL_MACHINE',
  6961.                                            N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
  6962.                                            N'IdleCPUDuration',
  6963.                                            @idle_cpu_duration OUTPUT,
  6964.                                            N'no_output'
  6965.     SELECT @schedule_description = FORMATMESSAGE(14578, ISNULL(@idle_cpu_percent, 10), ISNULL(@idle_cpu_duration, 600))
  6966.     RETURN
  6967.   END
  6968.  
  6969.   -- Subday stuff
  6970.   SELECT @schedule_description = @schedule_description +
  6971.     CASE @freq_subday_type
  6972.       WHEN 0x1 THEN N'at ' + CONVERT(NVARCHAR, @active_start_time)
  6973.       WHEN 0x2 THEN N'every ' + CONVERT(NVARCHAR, @freq_subday_interval) + N' second(s)'
  6974.       WHEN 0x4 THEN N'every ' + CONVERT(NVARCHAR, @freq_subday_interval) + N' minute(s)'
  6975.       WHEN 0x8 THEN N'every ' + CONVERT(NVARCHAR, @freq_subday_interval) + N' hour(s)'
  6976.     END
  6977.   IF (@freq_subday_type IN (0x2, 0x4, 0x8))
  6978.     SELECT @schedule_description = @schedule_description + N' between ' +
  6979.            CONVERT(NVARCHAR, @active_start_time) + N' and ' + CONVERT(NVARCHAR, @active_end_time)
  6980. END
  6981. go
  6982.  
  6983. DUMP TRANSACTION msdb WITH NO_LOG
  6984. go
  6985. CHECKPOINT
  6986. go
  6987.  
  6988. /**************************************************************/
  6989. /* SP_VERIFY_JOBSCHEDULE                                      */
  6990. /**************************************************************/
  6991.  
  6992. PRINT ''
  6993. PRINT 'Creating procedure sp_verify_jobschedule...'
  6994. go
  6995. IF (EXISTS (SELECT *
  6996.             FROM msdb.dbo.sysobjects
  6997.             WHERE (name = N'sp_verify_jobschedule')
  6998.               AND (type = 'P')))
  6999.   DROP PROCEDURE sp_verify_jobschedule
  7000. go
  7001. CREATE PROCEDURE sp_verify_jobschedule
  7002.   @name                   sysname,
  7003.   @enabled                TINYINT,
  7004.   @freq_type              INT,
  7005.   @freq_interval          INT OUTPUT,   -- Output because we may set it to 0 if Frequency Type is one-time or auto-start
  7006.   @freq_subday_type       INT OUTPUT,   -- As above
  7007.   @freq_subday_interval   INT OUTPUT,   -- As above
  7008.   @freq_relative_interval INT OUTPUT,   -- As above
  7009.   @freq_recurrence_factor INT OUTPUT,   -- As above
  7010.   @active_start_date      INT OUTPUT,
  7011.   @active_start_time      INT OUTPUT,
  7012.   @active_end_date        INT OUTPUT,
  7013.   @active_end_time        INT OUTPUT,
  7014.   @job_id                 UNIQUEIDENTIFIER,
  7015.   @schedule_id            INT           -- Will only be provided by sp_update_jobschedule
  7016. AS
  7017. BEGIN
  7018.   DECLARE @return_code             INT
  7019.   DECLARE @duplicate_schedule_id   INT
  7020.   DECLARE @duplicate_schedule_name sysname
  7021.   DECLARE @res_valid_range         NVARCHAR(100)
  7022.   DECLARE @reason                  NVARCHAR(200)
  7023.  
  7024.   SET NOCOUNT ON
  7025.  
  7026.   -- Remove any leading/trailing spaces from parameters
  7027.   SELECT @name = LTRIM(RTRIM(@name))
  7028.  
  7029.   -- Make sure that NULL input/output parameters - if NULL - are initialized to 0
  7030.   SELECT @freq_interval          = ISNULL(@freq_interval, 0)
  7031.   SELECT @freq_subday_type       = ISNULL(@freq_subday_type, 0)
  7032.   SELECT @freq_subday_interval   = ISNULL(@freq_subday_interval, 0)
  7033.   SELECT @freq_relative_interval = ISNULL(@freq_relative_interval, 0)
  7034.   SELECT @freq_recurrence_factor = ISNULL(@freq_recurrence_factor, 0)
  7035.   SELECT @active_start_date      = ISNULL(@active_start_date, 0)
  7036.   SELECT @active_start_time      = ISNULL(@active_start_time, 0)
  7037.   SELECT @active_end_date        = ISNULL(@active_end_date, 0)
  7038.   SELECT @active_end_time        = ISNULL(@active_end_time, 0)
  7039.  
  7040.   -- Verify name (we disallow schedules called 'ALL' since this has special meaning in sp_delete_jobschedules)
  7041.   IF (UPPER(@name) = N'ALL')
  7042.   BEGIN
  7043.     RAISERROR(14200, -1, -1, '@name')
  7044.     RETURN(1) -- Failure
  7045.   END
  7046.  
  7047.   -- Verify enabled state
  7048.   IF (@enabled <> 0) AND (@enabled <> 1)
  7049.   BEGIN
  7050.     RAISERROR(14266, -1, -1, '@enabled', '0, 1')
  7051.     RETURN(1) -- Failure
  7052.   END
  7053.  
  7054.   -- Verify frequency type
  7055.   IF (@freq_type = 0x2) -- OnDemand is no longer supported
  7056.   BEGIN
  7057.     RAISERROR(14295, -1, -1)
  7058.     RETURN(1) -- Failure
  7059.   END
  7060.   IF (@freq_type NOT IN (0x1, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80))
  7061.   BEGIN
  7062.     RAISERROR(14266, -1, -1, '@freq_type', '0x1, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80')
  7063.     RETURN(1) -- Failure
  7064.   END
  7065.  
  7066.   -- Verify frequency sub-day type
  7067.   IF (@freq_subday_type <> 0) AND (@freq_subday_type NOT IN (0x1, 0x2, 0x4, 0x8))
  7068.   BEGIN
  7069.     RAISERROR(14266, -1, -1, '@freq_subday_type', '0x1, 0x2, 0x4, 0x8')
  7070.     RETURN(1) -- Failure
  7071.   END
  7072.  
  7073.   -- Default active start/end date/times (if not supplied, or supplied as NULLs or 0)
  7074.   IF (@active_start_date = 0)
  7075.     SELECT @active_start_date = DATEPART(yy, GETDATE()) * 10000 +
  7076.                                 DATEPART(mm, GETDATE()) * 100 +
  7077.                                 DATEPART(dd, GETDATE())
  7078.   IF (@active_end_date = 0)
  7079.     SELECT @active_end_date = 99991231  -- December 31st 9999
  7080.   IF (@active_start_time = 0)
  7081.     SELECT @active_start_time = 000000  -- 12:00:00 am
  7082.   IF (@active_end_time = 0)
  7083.     SELECT @active_end_time = 235959    -- 11:59:59 pm
  7084.  
  7085.   -- Verify active start/end dates
  7086.   IF (@active_end_date = 0)
  7087.     SELECT @active_end_date = 99991231
  7088.  
  7089.   EXECUTE @return_code = sp_verify_job_date @active_end_date, '@active_end_date'
  7090.   IF (@return_code <> 0)
  7091.     RETURN(1) -- Failure
  7092.  
  7093.   EXECUTE @return_code = sp_verify_job_date @active_start_date, '@active_start_date'
  7094.   IF (@return_code <> 0)
  7095.     RETURN(1) -- Failure
  7096.  
  7097.   IF (@active_end_date < @active_start_date)
  7098.   BEGIN
  7099.     RAISERROR(14288, -1, -1, '@active_end_date', '@active_start_date')
  7100.     RETURN(1) -- Failure
  7101.   END
  7102.  
  7103.   -- Verify active start/end times
  7104.   IF (@active_end_time = 0)
  7105.     SELECT @active_end_time = 235959
  7106.  
  7107.   EXECUTE @return_code = sp_verify_job_time @active_end_time, '@active_end_time'
  7108.   IF (@return_code <> 0)
  7109.     RETURN(1) -- Failure
  7110.  
  7111.   EXECUTE @return_code = sp_verify_job_time @active_start_time, '@active_start_time'
  7112.   IF (@return_code <> 0)
  7113.     RETURN(1) -- Failure
  7114.  
  7115.   -- NOTE: It's valid for active_end_time to be less than active_start_time since in this
  7116.   --       case we assume that the user wants the active time zone to span midnight.
  7117.   --       But it's not valid for active_start_date and active_end_date to be the same...
  7118.   IF (@active_start_time = @active_end_time)
  7119.   BEGIN
  7120.     SELECT @res_valid_range = FORMATMESSAGE(14202)
  7121.     RAISERROR(14266, -1, -1, '@active_end_time', @res_valid_range)
  7122.     RETURN(1) -- Failure
  7123.   END
  7124.  
  7125.   -- NOTE: The rest of this procedure is a SQL implementation of VerifySchedule in job.c
  7126.  
  7127.   IF ((@freq_type = 0x1) OR  -- FREQTYPE_ONETIME
  7128.       (@freq_type = 0x40) OR -- FREQTYPE_AUTOSTART
  7129.       (@freq_type = 0x80))   -- FREQTYPE_ONIDLE
  7130.   BEGIN
  7131.     -- Set standard defaults for non-required parameters
  7132.     SELECT @freq_interval          = 0
  7133.     SELECT @freq_subday_type       = 0
  7134.     SELECT @freq_subday_interval   = 0
  7135.     SELECT @freq_relative_interval = 0
  7136.     SELECT @freq_recurrence_factor = 0
  7137. /*
  7138.     -- Check that a one-time schedule isn't already in the past
  7139.     IF (@freq_type = 0x1) -- FREQTYPE_ONETIME
  7140.     BEGIN
  7141.       DECLARE @current_date INT
  7142.       DECLARE @current_time INT
  7143.  
  7144.       SELECT @current_date = CONVERT(INT, CONVERT(VARCHAR, GETDATE(), 112))
  7145.       SELECT @current_time = (DATEPART(hh, GETDATE()) * 10000) + (DATEPART(mi, GETDATE()) * 100) + DATEPART(ss, GETDATE())
  7146.       IF (@active_start_date < @current_date) OR ((@active_start_date = @current_date) AND (@active_start_time <= @current_time))
  7147.       BEGIN
  7148.         SELECT @res_valid_range = '> ' + CONVERT(VARCHAR, @current_date) + ' / ' + CONVERT(VARCHAR, @current_time)
  7149.         RAISERROR(14266, -1, -1, '@active_start_date'' / ''@active_start_time', @res_valid_range)
  7150.         RETURN(1) -- Failure
  7151.       END
  7152.     END
  7153. */
  7154.     GOTO CheckForDuplicate
  7155.   END
  7156.  
  7157.   -- Safety net: If the sub-day-type is 0 (and we know that the schedule is not a one-time or
  7158.   --             auto-start) then set it to 1 (FREQSUBTYPE_ONCE).  If the user wanted something
  7159.   --             other than ONCE then they should have explicitly set @freq_subday_type.
  7160.   IF (@freq_subday_type = 0)
  7161.     SELECT @freq_subday_type = 0x1 -- FREQSUBTYPE_ONCE
  7162.  
  7163.   IF ((@freq_subday_type <> 0x1) AND  -- FREQSUBTYPE_ONCE   (see qsched.h)
  7164.       (@freq_subday_type <> 0x2) AND  -- FREQSUBTYPE_SECOND (see qsched.h)
  7165.       (@freq_subday_type <> 0x4) AND  -- FREQSUBTYPE_MINUTE (see qsched.h)
  7166.       (@freq_subday_type <> 0x8))     -- FREQSUBTYPE_HOUR   (see qsched.h)
  7167.   BEGIN
  7168.     SELECT @reason = FORMATMESSAGE(14266, '@freq_subday_type', '0x1, 0x2, 0x4, 0x8')
  7169.     RAISERROR(14278, -1, -1, @reason)
  7170.     RETURN(1) -- Failure
  7171.   END
  7172.   IF ((@freq_subday_type <> 0x1) AND (@freq_subday_interval < 1))
  7173.      OR
  7174.      ((@freq_subday_type = 0x2) AND (@freq_subday_interval < 10))
  7175.   BEGIN
  7176.     SELECT @reason = FORMATMESSAGE(14200, '@freq_subday_interval')
  7177.     RAISERROR(14278, -1, -1, @reason)
  7178.     RETURN(1) -- Failure
  7179.   END
  7180.  
  7181.   IF (@freq_type = 0x4)      -- FREQTYPE_DAILY
  7182.   BEGIN
  7183.     SELECT @freq_recurrence_factor = 0
  7184.     IF (@freq_interval < 1)
  7185.     BEGIN
  7186.       SELECT @reason = FORMATMESSAGE(14572)
  7187.       RAISERROR(14278, -1, -1, @reason)
  7188.       RETURN(1) -- Failure
  7189.     END
  7190.   END
  7191.  
  7192.   IF (@freq_type = 0x8)      -- FREQTYPE_WEEKLY
  7193.   BEGIN
  7194.     IF (@freq_interval < 1)   OR
  7195.        (@freq_interval > 127) -- (2^7)-1 [freq_interval is a bitmap (Sun=1..Sat=64)]
  7196.     BEGIN
  7197.       SELECT @reason = FORMATMESSAGE(14573)
  7198.       RAISERROR(14278, -1, -1, @reason)
  7199.       RETURN(1) -- Failure
  7200.     END
  7201.   END
  7202.  
  7203.   IF (@freq_type = 0x10)    -- FREQTYPE_MONTHLY
  7204.   BEGIN
  7205.     IF (@freq_interval < 1)  OR
  7206.        (@freq_interval > 31)
  7207.     BEGIN
  7208.       SELECT @reason = FORMATMESSAGE(14574)
  7209.       RAISERROR(14278, -1, -1, @reason)
  7210.       RETURN(1) -- Failure
  7211.     END
  7212.   END
  7213.  
  7214.   IF (@freq_type = 0x20)     -- FREQTYPE_MONTHLYRELATIVE
  7215.   BEGIN
  7216.     IF (@freq_relative_interval <> 0x01) AND  -- RELINT_1ST
  7217.        (@freq_relative_interval <> 0x02) AND  -- RELINT_2ND
  7218.        (@freq_relative_interval <> 0x04) AND  -- RELINT_3RD
  7219.        (@freq_relative_interval <> 0x08) AND  -- RELINT_4TH
  7220.        (@freq_relative_interval <> 0x10)      -- RELINT_LAST
  7221.     BEGIN
  7222.       SELECT @reason = FORMATMESSAGE(14575)
  7223.       RAISERROR(14278, -1, -1, @reason)
  7224.       RETURN(1) -- Failure
  7225.     END
  7226.   END
  7227.  
  7228.   IF (@freq_type = 0x20)     -- FREQTYPE_MONTHLYRELATIVE
  7229.   BEGIN
  7230.     IF (@freq_interval <> 01) AND -- RELATIVE_SUN
  7231.        (@freq_interval <> 02) AND -- RELATIVE_MON
  7232.        (@freq_interval <> 03) AND -- RELATIVE_TUE
  7233.        (@freq_interval <> 04) AND -- RELATIVE_WED
  7234.        (@freq_interval <> 05) AND -- RELATIVE_THU
  7235.        (@freq_interval <> 06) AND -- RELATIVE_FRI
  7236.        (@freq_interval <> 07) AND -- RELATIVE_SAT
  7237.        (@freq_interval <> 08) AND -- RELATIVE_DAY
  7238.        (@freq_interval <> 09) AND -- RELATIVE_WEEKDAY
  7239.        (@freq_interval <> 10)     -- RELATIVE_WEEKENDDAY
  7240.     BEGIN
  7241.       SELECT @reason = FORMATMESSAGE(14576)
  7242.       RAISERROR(14278, -1, -1, @reason)
  7243.       RETURN(1) -- Failure
  7244.     END
  7245.   END
  7246.  
  7247.   IF ((@freq_type = 0x08)  OR   -- FREQTYPE_WEEKLY
  7248.       (@freq_type = 0x10)  OR   -- FREQTYPE_MONTHLY
  7249.       (@freq_type = 0x20)) AND  -- FREQTYPE_MONTHLYRELATIVE
  7250.       (@freq_recurrence_factor < 1)
  7251.   BEGIN
  7252.     SELECT @reason = FORMATMESSAGE(14577)
  7253.     RAISERROR(14278, -1, -1, @reason)
  7254.     RETURN(1) -- Failure
  7255.   END
  7256.  
  7257. CheckForDuplicate:
  7258.  
  7259.   -- Check that the schedule is not a duplicate
  7260.   SELECT @duplicate_schedule_id = NULL
  7261.   SELECT @duplicate_schedule_id = schedule_id,
  7262.          @duplicate_schedule_name = name
  7263.   FROM msdb.dbo.sysjobschedules
  7264.   WHERE (job_id                 = @job_id)
  7265.     AND (freq_type              = @freq_type)
  7266.     AND (freq_interval          = @freq_interval)
  7267.     AND (freq_subday_type       = @freq_subday_type)
  7268.     AND (freq_subday_interval   = @freq_subday_interval)
  7269.     AND (freq_relative_interval = @freq_relative_interval)
  7270.     AND (freq_recurrence_factor = @freq_recurrence_factor)
  7271.     AND (active_start_date      = @active_start_date)
  7272.     AND (active_start_time      = @active_start_time)
  7273.   IF ((@duplicate_schedule_id IS NOT NULL) AND (@duplicate_schedule_id <> @schedule_id))
  7274.   BEGIN
  7275.     RAISERROR(14259, -1, -1, @duplicate_schedule_id, @duplicate_schedule_name)
  7276.     RETURN(1) -- Failure
  7277.   END
  7278.  
  7279.   -- If we made it this far the schedule is good
  7280.   RETURN(0) -- Success
  7281.  
  7282. END
  7283. go
  7284.  
  7285. /**************************************************************/
  7286. /* SP_ADD_JOBSCHEDULE                                         */
  7287. /**************************************************************/
  7288.  
  7289. PRINT ''
  7290. PRINT 'Creating procedure sp_add_jobschedule...'
  7291. go
  7292. IF (EXISTS (SELECT *
  7293.             FROM msdb.dbo.sysobjects
  7294.             WHERE (name = N'sp_add_jobschedule')
  7295.               AND (type = 'P')))
  7296.   DROP PROCEDURE sp_add_jobschedule
  7297. go
  7298. CREATE PROCEDURE sp_add_jobschedule
  7299.   @job_id                 UNIQUEIDENTIFIER = NULL,
  7300.   @job_name               sysname          = NULL,
  7301.   @name                   sysname,
  7302.   @enabled                TINYINT          = 1,
  7303.   @freq_type              INT              = 0,
  7304.   @freq_interval          INT              = 0,
  7305.   @freq_subday_type       INT              = 0,
  7306.   @freq_subday_interval   INT              = 0,
  7307.   @freq_relative_interval INT              = 0,
  7308.   @freq_recurrence_factor INT              = 0,
  7309.   @active_start_date      INT              = NULL,     -- sp_verify_jobschedule assigns a default
  7310.   @active_end_date        INT              = 99991231, -- December 31st 9999
  7311.   @active_start_time      INT              = 000000,   -- 12:00:00 am
  7312.   @active_end_time        INT              = 235959    -- 11:59:59 pm
  7313. AS
  7314. BEGIN
  7315.   DECLARE @retval      INT
  7316.   DECLARE @schedule_id INT
  7317.  
  7318.   SET NOCOUNT ON
  7319.  
  7320.   -- Remove any leading/trailing spaces from parameters
  7321.   SELECT @name = LTRIM(RTRIM(@name))
  7322.  
  7323.   SELECT @schedule_id = 0
  7324.  
  7325.   -- Check authority (only SQLServerAgent can add a schedule to a non-local job)
  7326.   EXECUTE @retval = sp_verify_jobproc_caller @job_id = @job_id, @program_name = N'SQLAgent%'
  7327.   IF (@retval <> 0)
  7328.     RETURN(@retval)
  7329.  
  7330.   -- Check that we can uniquely identify the job
  7331.   EXECUTE @retval = sp_verify_job_identifiers '@job_name',
  7332.                                               '@job_id',
  7333.                                                @job_name OUTPUT,
  7334.                                                @job_id   OUTPUT
  7335.   IF (@retval <> 0)
  7336.     RETURN(1) -- Failure
  7337.  
  7338.   -- Check that the schedule name doesn't already exist
  7339.   IF (EXISTS (SELECT *
  7340.               FROM msdb.dbo.sysjobschedules
  7341.               WHERE (job_id = @job_id)
  7342.                 AND (name = @name)))
  7343.   BEGIN
  7344.     RAISERROR(14261, -1, -1, '@name', @name)
  7345.     RETURN(1) -- Failure
  7346.   END
  7347.  
  7348.   -- Check schedule (frequency) parameters
  7349.   EXECUTE @retval = sp_verify_jobschedule @name,
  7350.                                           @enabled,
  7351.                                           @freq_type,
  7352.                                           @freq_interval          OUTPUT,
  7353.                                           @freq_subday_type       OUTPUT,
  7354.                                           @freq_subday_interval   OUTPUT,
  7355.                                           @freq_relative_interval OUTPUT,
  7356.                                           @freq_recurrence_factor OUTPUT,
  7357.                                           @active_start_date      OUTPUT,
  7358.                                           @active_start_time      OUTPUT,
  7359.                                           @active_end_date        OUTPUT,
  7360.                                           @active_end_time        OUTPUT,
  7361.                                           @job_id,
  7362.                                           NULL
  7363.   IF (@retval <> 0)
  7364.     RETURN(1) -- Failure
  7365.  
  7366.   INSERT INTO msdb.dbo.sysjobschedules
  7367.          (job_id,
  7368.           name,
  7369.           enabled,
  7370.           freq_type,
  7371.           freq_interval,
  7372.           freq_subday_type,
  7373.           freq_subday_interval,
  7374.           freq_relative_interval,
  7375.           freq_recurrence_factor,
  7376.           active_start_date,
  7377.           active_end_date,
  7378.           active_start_time,
  7379.           active_end_time,
  7380.           next_run_date,
  7381.           next_run_time)
  7382.   VALUES (@job_id,
  7383.           @name,
  7384.           @enabled,
  7385.           @freq_type,
  7386.           @freq_interval,
  7387.           @freq_subday_type,
  7388.           @freq_subday_interval,
  7389.           @freq_relative_interval,
  7390.           @freq_recurrence_factor,
  7391.           @active_start_date,
  7392.           @active_end_date,
  7393.           @active_start_time,
  7394.           @active_end_time,
  7395.           0,
  7396.           0)
  7397.  
  7398.   SELECT @retval = @@error
  7399.  
  7400.   -- Update the job's version/last-modified information
  7401.   UPDATE msdb.dbo.sysjobs
  7402.   SET version_number = version_number + 1,
  7403.       date_modified = GETDATE()
  7404.   WHERE (job_id = @job_id)
  7405.  
  7406.   SELECT @schedule_id = schedule_id
  7407.   FROM msdb.dbo.sysjobschedules
  7408.   WHERE (job_id = @job_id)
  7409.     AND (name = @name)
  7410.  
  7411.   -- Notify SQLServerAgent of the change, but only if we know the job has been cached
  7412.   IF (EXISTS (SELECT *
  7413.               FROM msdb.dbo.sysjobservers
  7414.               WHERE (job_id = @job_id)
  7415.                 AND (server_id = 0)))
  7416.   BEGIN
  7417.     EXECUTE msdb.dbo.sp_sqlagent_notify @op_type     = N'S',
  7418.                                         @job_id      = @job_id,
  7419.                                         @schedule_id = @schedule_id,
  7420.                                         @action_type = N'I'
  7421.   END
  7422.  
  7423.   -- For a multi-server job, remind the user that they need to call sp_post_msx_operation
  7424.   IF (EXISTS (SELECT *
  7425.               FROM msdb.dbo.sysjobservers
  7426.               WHERE (job_id = @job_id)
  7427.                 AND (server_id <> 0)))
  7428.     RAISERROR(14547, 0, 1, N'INSERT', N'sp_post_msx_operation')
  7429.  
  7430.   RETURN(@retval) -- 0 means success
  7431. END
  7432. go
  7433.  
  7434. /**************************************************************/
  7435. /* SP_UPDATE_REPLICATION_JOB_PARAMETER                        */
  7436. /**************************************************************/
  7437.  
  7438. PRINT ''
  7439. PRINT 'Creating procedure sp_update_replication_job_parameter...'
  7440. go
  7441. IF (EXISTS (SELECT *
  7442.             FROM msdb.dbo.sysobjects
  7443.             WHERE (name = 'sp_update_replication_job_parameter')
  7444.               AND (type = 'P')))
  7445.   DROP PROCEDURE sp_update_replication_job_parameter
  7446. go
  7447. CREATE PROCEDURE sp_update_replication_job_parameter
  7448.   @job_id        UNIQUEIDENTIFIER,
  7449.   @old_freq_type INT,
  7450.   @new_freq_type INT
  7451. AS
  7452. BEGIN
  7453.   DECLARE @category_id INT
  7454.   DECLARE @pattern     NVARCHAR(50)
  7455.   DECLARE @patternidx  INT
  7456.   DECLARE @cmdline     NVARCHAR(3200)
  7457.   DECLARE @step_id     INT
  7458.  
  7459.   SET NOCOUNT ON
  7460.   SELECT @pattern = N'%[-/][Cc][Oo][Nn][Tt][Ii][Nn][Uu][Oo][Uu][Ss]%'
  7461.  
  7462.   -- Make sure that we are dealing with relevant replication jobs
  7463.   SELECT @category_id = category_id
  7464.   FROM msdb.dbo.sysjobs
  7465.   WHERE (@job_id = job_id)
  7466.  
  7467.   -- @category_id = 10 (REPL-Distribution), 13 (REPL-LogReader), 14 (REPL-Merge),
  7468.   --  19 (REPL-QueueReader)
  7469.   IF @category_id IN (10, 13, 14, 19)
  7470.   BEGIN
  7471.     -- Adding the -Continuous parameter (non auto-start to auto-start)
  7472.     IF ((@old_freq_type <> 0x40) AND (@new_freq_type = 0x40))
  7473.     BEGIN
  7474.       -- Use a cursor to handle multiple replication agent job steps
  7475.       DECLARE step_cursor CURSOR LOCAL FOR
  7476.       SELECT command, step_id
  7477.       FROM msdb.dbo.sysjobsteps
  7478.       WHERE (@job_id = job_id)
  7479.         AND (UPPER(subsystem) IN (N'MERGE', N'LOGREADER', N'DISTRIBUTION', N'QUEUEREADER'))
  7480.       OPEN step_cursor
  7481.       FETCH step_cursor INTO @cmdline, @step_id
  7482.  
  7483.       WHILE (@@FETCH_STATUS <> -1)
  7484.       BEGIN
  7485.         SELECT @patternidx = PATINDEX(@pattern, @cmdline)
  7486.         -- Make sure that the -Continuous parameter has not been specified already
  7487.         IF (@patternidx = 0)
  7488.         BEGIN
  7489.           SELECT @cmdline = @cmdline + N' -Continuous'
  7490.           UPDATE msdb.dbo.sysjobsteps
  7491.           SET command = @cmdline
  7492.           WHERE (@job_id = job_id)
  7493.             AND (@step_id = step_id)
  7494.         END -- IF (@patternidx = 0)
  7495.         FETCH NEXT FROM step_cursor into @cmdline, @step_id
  7496.       END -- WHILE (@@FETCH_STATUS <> -1)
  7497.       CLOSE step_cursor
  7498.       DEALLOCATE step_cursor
  7499.     END -- IF ((@old_freq_type...
  7500.     -- Removing the -Continuous parameter (auto-start to non auto-start)
  7501.     ELSE
  7502.     IF ((@old_freq_type = 0x40) AND (@new_freq_type <> 0x40))
  7503.     BEGIN
  7504.       DECLARE step_cursor CURSOR LOCAL FOR
  7505.       SELECT command, step_id
  7506.       FROM msdb.dbo.sysjobsteps
  7507.       WHERE (@job_id = job_id)
  7508.         AND (UPPER(subsystem) IN (N'MERGE', N'LOGREADER', N'DISTRIBUTION', N'QUEUEREADER'))
  7509.       OPEN step_cursor
  7510.       FETCH step_cursor INTO @cmdline, @step_id
  7511.  
  7512.       WHILE (@@FETCH_STATUS <> -1)
  7513.       BEGIN
  7514.         SELECT @patternidx = PATINDEX(@pattern, @cmdline)
  7515.         IF (@patternidx <> 0)
  7516.         BEGIN
  7517.           -- Handle multiple instances of -Continuous in the commandline
  7518.           WHILE (@patternidx <> 0)
  7519.           BEGIN
  7520.             SELECT @cmdline = STUFF(@cmdline, @patternidx, 11, N'')
  7521.             IF (@patternidx > 1)
  7522.             BEGIN
  7523.               -- Remove the preceding space if -Continuous does not start at the beginning of the commandline
  7524.               SELECT @cmdline = stuff(@cmdline, @patternidx - 1, 1, N'')
  7525.             END
  7526.             SELECT @patternidx = PATINDEX(@pattern, @cmdline)
  7527.           END -- WHILE (@patternidx <> 0)
  7528.           UPDATE msdb.dbo.sysjobsteps
  7529.           SET command = @cmdline
  7530.           WHERE (@job_id = job_id)
  7531.             AND (@step_id = step_id)
  7532.         END -- IF (@patternidx <> -1)
  7533.         FETCH NEXT FROM step_cursor INTO @cmdline, @step_id
  7534.       END -- WHILE (@@FETCH_STATUS <> -1)
  7535.       CLOSE step_cursor
  7536.       DEALLOCATE step_cursor
  7537.     END -- ELSE IF ((@old_freq_type = 0x40)...
  7538.   END -- IF @category_id IN (10, 13, 14)
  7539.  
  7540.   RETURN 0
  7541. END
  7542. go
  7543.  
  7544. /**************************************************************/
  7545. /* SP_UPDATE_JOBSCHEDULE                                      */
  7546. /**************************************************************/
  7547.  
  7548. PRINT ''
  7549. PRINT 'Creating procedure sp_update_jobschedule...'
  7550. go
  7551. IF (EXISTS (SELECT *
  7552.             FROM msdb.dbo.sysobjects
  7553.             WHERE (name = N'sp_update_jobschedule')
  7554.               AND (type = 'P')))
  7555.   DROP PROCEDURE sp_update_jobschedule
  7556. go
  7557. CREATE PROCEDURE sp_update_jobschedule
  7558.   @job_id                 UNIQUEIDENTIFIER = NULL,
  7559.   @job_name               sysname          = NULL,
  7560.   @name                   sysname,
  7561.   @new_name               sysname          = NULL,
  7562.   @enabled                TINYINT          = NULL,
  7563.   @freq_type              INT              = NULL,
  7564.   @freq_interval          INT              = NULL,
  7565.   @freq_subday_type       INT              = NULL,
  7566.   @freq_subday_interval   INT              = NULL,
  7567.   @freq_relative_interval INT              = NULL,
  7568.   @freq_recurrence_factor INT              = NULL,
  7569.   @active_start_date      INT              = NULL,
  7570.   @active_end_date        INT              = NULL,
  7571.   @active_start_time      INT              = NULL,
  7572.   @active_end_time        INT              = NULL
  7573. AS
  7574. BEGIN
  7575.   DECLARE @retval                   INT
  7576.   DECLARE @schedule_id              INT
  7577.   DECLARE @x_name                   sysname
  7578.   DECLARE @x_enabled                TINYINT
  7579.   DECLARE @x_freq_type              INT
  7580.   DECLARE @x_freq_interval          INT
  7581.   DECLARE @x_freq_subday_type       INT
  7582.   DECLARE @x_freq_subday_interval   INT
  7583.   DECLARE @x_freq_relative_interval INT
  7584.   DECLARE @x_freq_recurrence_factor INT
  7585.   DECLARE @x_active_start_date      INT
  7586.   DECLARE @x_active_end_date        INT
  7587.   DECLARE @x_active_start_time      INT
  7588.   DECLARE @x_active_end_time        INT
  7589.  
  7590.   SET NOCOUNT ON
  7591.  
  7592.   -- Remove any leading/trailing spaces from parameters
  7593.   SELECT @name     = LTRIM(RTRIM(@name))
  7594.   SELECT @new_name = LTRIM(RTRIM(@new_name))
  7595.  
  7596.   -- Turn [nullable] empty string parameters into NULLs
  7597.   IF (@new_name = N'') SELECT @new_name = NULL
  7598.  
  7599.   -- Check authority (only SQLServerAgent can modify a schedule of a non-local job)
  7600.   EXECUTE @retval = sp_verify_jobproc_caller @job_id = @job_id, @program_name = 'SQLAgent%'
  7601.   IF (@retval <> 0)
  7602.     RETURN(@retval)
  7603.  
  7604.   -- Check that we can uniquely identify the job
  7605.   EXECUTE @retval = sp_verify_job_identifiers '@job_name',
  7606.                                               '@job_id',
  7607.                                                @job_name OUTPUT,
  7608.                                                @job_id   OUTPUT
  7609.   IF (@retval <> 0)
  7610.     RETURN(1) -- Failure
  7611.  
  7612.   -- Check that the schedule exists
  7613.   SELECT @schedule_id = schedule_id
  7614.   FROM msdb.dbo.sysjobschedules
  7615.   WHERE (job_id = @job_id)
  7616.     AND (name = @name)
  7617.   IF (@schedule_id IS NULL)
  7618.   BEGIN
  7619.     RAISERROR(14262, -1, -1, 'Schedule Name', @name)
  7620.     RETURN(1) -- Failure
  7621.   END
  7622.  
  7623.   -- Set the x_ (existing) variables
  7624.   SELECT @x_name                   = name,
  7625.          @x_enabled                = enabled,
  7626.          @x_freq_type              = freq_type,
  7627.          @x_freq_interval          = freq_interval,
  7628.          @x_freq_subday_type       = freq_subday_type,
  7629.          @x_freq_subday_interval   = freq_subday_interval,
  7630.          @x_freq_relative_interval = freq_relative_interval,
  7631.          @x_freq_recurrence_factor = freq_recurrence_factor,
  7632.          @x_active_start_date      = active_start_date,
  7633.          @x_active_end_date        = active_end_date,
  7634.          @x_active_start_time      = active_start_time,
  7635.          @x_active_end_time        = active_end_time
  7636.   FROM msdb.dbo.sysjobschedules
  7637.   WHERE (job_id = @job_id)
  7638.     AND (name = @name)
  7639.  
  7640.   -- Check that the new name (if any) doesn't already exist for this job
  7641.   IF (@new_name IS NOT NULL)
  7642.   BEGIN
  7643.     IF (EXISTS (SELECT *
  7644.                 FROM msdb.dbo.sysjobschedules
  7645.                 WHERE (job_id = @job_id)
  7646.                   AND (name = @new_name)
  7647.                   AND (@name <> @new_name)))
  7648.     BEGIN
  7649.       RAISERROR(14261, -1, -1, '@new_name', @new_name)
  7650.       RETURN(1) -- Failure
  7651.     END
  7652.   END
  7653.  
  7654.   -- Fill out the values for all non-supplied parameters from the existing values
  7655.   IF (@new_name               IS NULL) SELECT @new_name               = @x_name
  7656.   IF (@enabled                IS NULL) SELECT @enabled                = @x_enabled
  7657.   IF (@freq_type              IS NULL) SELECT @freq_type              = @x_freq_type
  7658.   IF (@freq_interval          IS NULL) SELECT @freq_interval          = @x_freq_interval
  7659.   IF (@freq_subday_type       IS NULL) SELECT @freq_subday_type       = @x_freq_subday_type
  7660.   IF (@freq_subday_interval   IS NULL) SELECT @freq_subday_interval   = @x_freq_subday_interval
  7661.   IF (@freq_relative_interval IS NULL) SELECT @freq_relative_interval = @x_freq_relative_interval
  7662.   IF (@freq_recurrence_factor IS NULL) SELECT @freq_recurrence_factor = @x_freq_recurrence_factor
  7663.   IF (@active_start_date      IS NULL) SELECT @active_start_date      = @x_active_start_date
  7664.   IF (@active_end_date        IS NULL) SELECT @active_end_date        = @x_active_end_date
  7665.   IF (@active_start_time      IS NULL) SELECT @active_start_time      = @x_active_start_time
  7666.   IF (@active_end_time        IS NULL) SELECT @active_end_time        = @x_active_end_time
  7667.  
  7668.   -- Check schedule (frequency) parameters
  7669.   EXECUTE @retval = sp_verify_jobschedule @new_name,
  7670.                                           @enabled,
  7671.                                           @freq_type,
  7672.                                           @freq_interval          OUTPUT,
  7673.                                           @freq_subday_type       OUTPUT,
  7674.                                           @freq_subday_interval   OUTPUT,
  7675.                                           @freq_relative_interval OUTPUT,
  7676.                                           @freq_recurrence_factor OUTPUT,
  7677.                                           @active_start_date      OUTPUT,
  7678.                                           @active_start_time      OUTPUT,
  7679.                                           @active_end_date        OUTPUT,
  7680.                                           @active_end_time        OUTPUT,
  7681.                                           @job_id,
  7682.                                           @schedule_id
  7683.   IF (@retval <> 0)
  7684.     RETURN(1) -- Failure
  7685.  
  7686.   -- Update the JobSchedule
  7687.   UPDATE msdb.dbo.sysjobschedules
  7688.   SET name                   = @new_name,
  7689.       enabled                = @enabled,
  7690.       freq_type              = @freq_type,
  7691.       freq_interval          = @freq_interval,
  7692.       freq_subday_type       = @freq_subday_type,
  7693.       freq_subday_interval   = @freq_subday_interval,
  7694.       freq_relative_interval = @freq_relative_interval,
  7695.       freq_recurrence_factor = @freq_recurrence_factor,
  7696.       active_start_date      = @active_start_date,
  7697.       active_end_date        = @active_end_date,
  7698.       active_start_time      = @active_start_time,
  7699.       active_end_time        = @active_end_time,
  7700.       next_run_date          = 0, -- Since SQLServerAgent needs to recalculate it
  7701.       next_run_time          = 0  -- Since SQLServerAgent needs to recalculate it
  7702.   WHERE (job_id = @job_id)
  7703.     AND (name = @name)
  7704.  
  7705.   SELECT @retval = @@error
  7706.  
  7707.   -- Update the job's version/last-modified information
  7708.   UPDATE msdb.dbo.sysjobs
  7709.   SET version_number = version_number + 1,
  7710.       date_modified = GETDATE()
  7711.   WHERE (job_id = @job_id)
  7712.  
  7713.   -- Notify SQLServerAgent of the change, but only if we know the job has been cached
  7714.   IF (EXISTS (SELECT *
  7715.               FROM msdb.dbo.sysjobservers
  7716.               WHERE (job_id = @job_id)
  7717.                 AND (server_id = 0)))
  7718.   BEGIN
  7719.     EXECUTE msdb.dbo.sp_sqlagent_notify @op_type     = N'S',
  7720.                                         @job_id      = @job_id,
  7721.                                         @schedule_id = @schedule_id,
  7722.                                         @action_type = N'U'
  7723.   END
  7724.  
  7725.   -- For a multi-server job, remind the user that they need to call sp_post_msx_operation
  7726.   IF (EXISTS (SELECT *
  7727.               FROM msdb.dbo.sysjobservers
  7728.               WHERE (job_id = @job_id)
  7729.                 AND (server_id <> 0)))
  7730.     RAISERROR(14547, 0, 1, N'INSERT', N'sp_post_msx_operation')
  7731.  
  7732.   -- Automatic addition and removal of -Continous parameter for replication agent
  7733.   EXECUTE sp_update_replication_job_parameter @job_id = @job_id,
  7734.                                               @old_freq_type = @x_freq_type,
  7735.                                               @new_freq_type = @freq_type
  7736.  
  7737.   RETURN(@retval) -- 0 means success
  7738. END
  7739. go
  7740.  
  7741. /**************************************************************/
  7742. /* SP_DELETE_JOBSCHEDULE                                      */
  7743. /**************************************************************/
  7744.  
  7745. PRINT ''
  7746. PRINT 'Creating procedure sp_delete_jobschedule...'
  7747. go
  7748. IF (EXISTS (SELECT *
  7749.             FROM msdb.dbo.sysobjects
  7750.             WHERE (name = 'sp_delete_jobschedule')
  7751.               AND (type = 'P')))
  7752.   DROP PROCEDURE sp_delete_jobschedule
  7753. go
  7754. CREATE PROCEDURE sp_delete_jobschedule
  7755.   @job_id   UNIQUEIDENTIFIER = NULL,
  7756.   @job_name sysname          = NULL,
  7757.   @name     sysname
  7758. AS
  7759. BEGIN
  7760.   DECLARE @retval      INT
  7761.   DECLARE @schedule_id INT
  7762.  
  7763.   SET NOCOUNT ON
  7764.  
  7765.   -- Remove any leading/trailing spaces from parameters
  7766.   SELECT @name = LTRIM(RTRIM(@name))
  7767.  
  7768.   -- Check authority (only SQLServerAgent can delete a schedule of a non-local job)
  7769.   EXECUTE @retval = sp_verify_jobproc_caller @job_id = @job_id, @program_name = N'SQLAgent%'
  7770.   IF (@retval <> 0)
  7771.     RETURN(@retval)
  7772.  
  7773.   -- Check that we can uniquely identify the job
  7774.   EXECUTE @retval = sp_verify_job_identifiers '@job_name',
  7775.                                               '@job_id',
  7776.                                                @job_name OUTPUT,
  7777.                                                @job_id   OUTPUT
  7778.   IF (@retval <> 0)
  7779.     RETURN(1) -- Failure
  7780.  
  7781.   IF (UPPER(@name) = N'ALL')
  7782.   BEGIN
  7783.     SELECT @schedule_id = -1  -- We use this in the call to sp_sqlagent_notify
  7784.  
  7785.     DELETE FROM msdb.dbo.sysjobschedules
  7786.     WHERE (job_id = @job_id)
  7787.   END
  7788.   ELSE
  7789.   BEGIN
  7790.     -- Check that the schedule exists
  7791.     SELECT @schedule_id = schedule_id
  7792.     FROM msdb.dbo.sysjobschedules
  7793.     WHERE (job_id = @job_id)
  7794.       AND (name = @name)
  7795.     IF (@schedule_id IS NULL)
  7796.     BEGIN
  7797.       RAISERROR(14262, -1, -1, '@name', @name)
  7798.       RETURN(1) -- Failure
  7799.     END
  7800.  
  7801.     DELETE FROM msdb.dbo.sysjobschedules
  7802.     WHERE (job_id = @job_id)
  7803.       AND (schedule_id = @schedule_id)
  7804.   END
  7805.  
  7806.   SELECT @retval = @@error
  7807.  
  7808.   -- Update the job's version/last-modified information
  7809.   UPDATE msdb.dbo.sysjobs
  7810.   SET version_number = version_number + 1,
  7811.       date_modified = GETDATE()
  7812.   WHERE (job_id = @job_id)
  7813.  
  7814.   -- Notify SQLServerAgent of the change, but only if we know the job has been cached
  7815.   IF (EXISTS (SELECT *
  7816.               FROM msdb.dbo.sysjobservers
  7817.               WHERE (job_id = @job_id)
  7818.                 AND (server_id = 0)))
  7819.   BEGIN
  7820.     EXECUTE msdb.dbo.sp_sqlagent_notify @op_type     = N'S',
  7821.                                         @job_id      = @job_id,
  7822.                                         @schedule_id = @schedule_id,
  7823.                                         @action_type = N'D'
  7824.   END
  7825.  
  7826.   -- For a multi-server job, remind the user that they need to call sp_post_msx_operation
  7827.   IF (EXISTS (SELECT *
  7828.               FROM msdb.dbo.sysjobservers
  7829.               WHERE (job_id = @job_id)
  7830.                 AND (server_id <> 0)))
  7831.     RAISERROR(14547, 0, 1, N'INSERT', N'sp_post_msx_operation')
  7832.  
  7833.   RETURN(@retval) -- 0 means success
  7834. END
  7835. go
  7836.  
  7837. /**************************************************************/
  7838. /* SP_HELP_JOBSCHEDULE                                        */
  7839. /**************************************************************/
  7840.  
  7841. PRINT ''
  7842. PRINT 'Creating procedure sp_help_jobschedule...'
  7843. go
  7844. IF (EXISTS (SELECT *
  7845.             FROM msdb.dbo.sysobjects
  7846.             WHERE (name = N'sp_help_jobschedule')
  7847.               AND (type = 'P')))
  7848.   DROP PROCEDURE sp_help_jobschedule
  7849. go
  7850. CREATE PROCEDURE sp_help_jobschedule
  7851.   @job_id              UNIQUEIDENTIFIER = NULL,
  7852.   @job_name            sysname          = NULL,
  7853.   @schedule_name       sysname          = NULL,
  7854.   @schedule_id         INT              = NULL,
  7855.   @include_description BIT              = 0 -- 1 if a schedule description is required (NOTE: It's expensive to generate the description)
  7856. AS
  7857. BEGIN
  7858.   DECLARE @retval                 INT
  7859.   DECLARE @schedule_description   NVARCHAR(255)
  7860.   DECLARE @name                   sysname
  7861.   DECLARE @freq_type              INT
  7862.   DECLARE @freq_interval          INT
  7863.   DECLARE @freq_subday_type       INT
  7864.   DECLARE @freq_subday_interval   INT
  7865.   DECLARE @freq_relative_interval INT
  7866.   DECLARE @freq_recurrence_factor INT
  7867.   DECLARE @active_start_date      INT
  7868.   DECLARE @active_end_date        INT
  7869.   DECLARE @active_start_time      INT
  7870.   DECLARE @active_end_time        INT
  7871.   DECLARE @schedule_id_as_char    VARCHAR(10)
  7872.  
  7873.   SET NOCOUNT ON
  7874.  
  7875.   -- Remove any leading/trailing spaces from parameters
  7876.   SELECT @schedule_name = LTRIM(RTRIM(@schedule_name))
  7877.  
  7878.   -- Turn [nullable] empty string parameters into NULLs
  7879.   IF (@schedule_name = N'') SELECT @schedule_name = NULL
  7880.  
  7881.   -- The user must provide either:
  7882.   -- 1) job_id (or job_name) and (optionally) a schedule name
  7883.   -- or...
  7884.   -- 2) just schedule_id
  7885.   IF (@schedule_id IS NULL) AND
  7886.      (@job_id      IS NULL) AND
  7887.      (@job_name    IS NULL)
  7888.   BEGIN
  7889.     RAISERROR(14273, -1, -1)
  7890.     RETURN(1) -- Failure
  7891.   END
  7892.  
  7893.   IF (@schedule_id IS NOT NULL) AND ((@job_id        IS NOT NULL) OR
  7894.                                      (@job_name      IS NOT NULL) OR
  7895.                                      (@schedule_name IS NOT NULL))
  7896.   BEGIN
  7897.     RAISERROR(14273, -1, -1)
  7898.     RETURN(1) -- Failure
  7899.   END
  7900.  
  7901.   -- Check that the schedule (by ID) exists
  7902.   IF (@schedule_id IS NOT NULL)
  7903.   BEGIN
  7904.     SELECT @job_id = job_id
  7905.     FROM msdb.dbo.sysjobschedules
  7906.     WHERE (schedule_id = @schedule_id)
  7907.     IF (@job_id IS NULL)
  7908.     BEGIN
  7909.       SELECT @schedule_id_as_char = CONVERT(VARCHAR, @schedule_id)
  7910.       RAISERROR(14262, -1, -1, '@schedule_id', @schedule_id_as_char)
  7911.       RETURN(1) -- Failure
  7912.     END
  7913.   END
  7914.  
  7915.   -- Check that we can uniquely identify the job
  7916.   IF (@job_id IS NOT NULL) OR (@job_name IS NOT NULL)
  7917.   BEGIN
  7918.     EXECUTE @retval = sp_verify_job_identifiers '@job_name',
  7919.                                                 '@job_id',
  7920.                                                  @job_name OUTPUT,
  7921.                                                  @job_id   OUTPUT,
  7922.                                                 'NO_TEST'
  7923.     IF (@retval <> 0)
  7924.       RETURN(1) -- Failure
  7925.   END
  7926.  
  7927.   -- Check that the schedule (by name) exists
  7928.   IF (@schedule_name IS NOT NULL)
  7929.   BEGIN
  7930.     IF (NOT EXISTS (SELECT *
  7931.                     FROM msdb.dbo.sysjobschedules
  7932.                     WHERE (job_id = @job_id)
  7933.                       AND (name = @schedule_name)))
  7934.     BEGIN
  7935.       RAISERROR(14262, -1, -1, '@schedule_name', @schedule_name)
  7936.       RETURN(1) -- Failure
  7937.     END
  7938.   END
  7939.  
  7940.   -- Get the schedule(s) into a temporary table
  7941.   SELECT schedule_id,
  7942.         'schedule_name' = name,
  7943.          enabled,
  7944.          freq_type,
  7945.          freq_interval,
  7946.          freq_subday_type,
  7947.          freq_subday_interval,
  7948.          freq_relative_interval,
  7949.          freq_recurrence_factor,
  7950.          active_start_date,
  7951.          active_end_date,
  7952.          active_start_time,
  7953.          active_end_time,
  7954.          date_created,
  7955.         'schedule_description' = FORMATMESSAGE(14549),
  7956.          next_run_date,
  7957.          next_run_time
  7958.   INTO #temp_jobschedule
  7959.   FROM msdb.dbo.sysjobschedules
  7960.   WHERE ((@job_id IS NULL) OR (job_id = @job_id))
  7961.     AND ((@schedule_name IS NULL) OR (name = @schedule_name))
  7962.     AND ((@schedule_id IS NULL) OR (schedule_id = @schedule_id))
  7963.  
  7964.   IF (@include_description = 1)
  7965.   BEGIN
  7966.     -- For each schedule, generate the textual schedule description and update the temporary
  7967.     -- table with it
  7968.     IF (EXISTS (SELECT *
  7969.                 FROM #temp_jobschedule))
  7970.     BEGIN
  7971.       WHILE (EXISTS (SELECT *
  7972.                      FROM #temp_jobschedule
  7973.                      WHERE schedule_description = FORMATMESSAGE(14549)))
  7974.       BEGIN
  7975.         SET ROWCOUNT 1
  7976.         SELECT @name                   = schedule_name,
  7977.                @freq_type              = freq_type,
  7978.                @freq_interval          = freq_interval,
  7979.                @freq_subday_type       = freq_subday_type,
  7980.                @freq_subday_interval   = freq_subday_interval,
  7981.                @freq_relative_interval = freq_relative_interval,
  7982.                @freq_recurrence_factor = freq_recurrence_factor,
  7983.                @active_start_date      = active_start_date,
  7984.                @active_end_date        = active_end_date,
  7985.                @active_start_time      = active_start_time,
  7986.                @active_end_time        = active_end_time
  7987.         FROM #temp_jobschedule
  7988.         WHERE (schedule_description = FORMATMESSAGE(14549))
  7989.         SET ROWCOUNT 0
  7990.  
  7991.         EXECUTE sp_get_schedule_description
  7992.           @freq_type,
  7993.           @freq_interval,
  7994.           @freq_subday_type,
  7995.           @freq_subday_interval,
  7996.           @freq_relative_interval,
  7997.           @freq_recurrence_factor,
  7998.           @active_start_date,
  7999.           @active_end_date,
  8000.           @active_start_time,
  8001.           @active_end_time,
  8002.           @schedule_description OUTPUT
  8003.  
  8004.         UPDATE #temp_jobschedule
  8005.         SET schedule_description = ISNULL(LTRIM(RTRIM(@schedule_description)), FORMATMESSAGE(14205))
  8006.         WHERE (schedule_name = @name)
  8007.       END -- While
  8008.     END
  8009.   END
  8010.  
  8011.   -- Return the result set
  8012.   SELECT *
  8013.   FROM #temp_jobschedule
  8014.   ORDER BY schedule_id
  8015.  
  8016.   RETURN(@@error) -- 0 means success
  8017. END
  8018. go
  8019.  
  8020. DUMP TRANSACTION msdb WITH NO_LOG
  8021. go
  8022. CHECKPOINT
  8023. go
  8024.  
  8025. /**************************************************************/
  8026. /* SP_VERIFY_JOB                                              */
  8027. /**************************************************************/
  8028.  
  8029. PRINT ''
  8030. PRINT 'Creating procedure sp_verify_job...'
  8031. go
  8032. IF (EXISTS (SELECT *
  8033.             FROM msdb.dbo.sysobjects
  8034.             WHERE (name = N'sp_verify_job')
  8035.               AND (type = 'P')))
  8036.   DROP PROCEDURE sp_verify_job
  8037. go
  8038. CREATE PROCEDURE sp_verify_job
  8039.   @job_id                       UNIQUEIDENTIFIER,
  8040.   @name                         sysname,
  8041.   @enabled                      TINYINT,
  8042.   @start_step_id                INT,
  8043.   @category_name                sysname,
  8044.   @owner_sid                    VARBINARY(85) OUTPUT, -- Output since we may modify it
  8045.   @notify_level_eventlog        INT,
  8046.   @notify_level_email           INT           OUTPUT, -- Output since we may reset it to 0
  8047.   @notify_level_netsend         INT           OUTPUT, -- Output since we may reset it to 0
  8048.   @notify_level_page            INT           OUTPUT, -- Output since we may reset it to 0
  8049.   @notify_email_operator_name   sysname,
  8050.   @notify_netsend_operator_name sysname,
  8051.   @notify_page_operator_name    sysname,
  8052.   @delete_level                 INT,
  8053.   @category_id                  INT           OUTPUT, -- The ID corresponding to the name
  8054.   @notify_email_operator_id     INT           OUTPUT, -- The ID corresponding to the name
  8055.   @notify_netsend_operator_id   INT           OUTPUT, -- The ID corresponding to the name
  8056.   @notify_page_operator_id      INT           OUTPUT, -- The ID corresponding to the name
  8057.   @originating_server           NVARCHAR(30)  OUTPUT  -- Output since we may modify it
  8058. AS
  8059. BEGIN
  8060.   DECLARE @job_type           INT
  8061.   DECLARE @retval             INT
  8062.   DECLARE @current_date       INT
  8063.   DECLARE @local_machine_name NVARCHAR(30)
  8064.   DECLARE @res_valid_range    NVARCHAR(200)
  8065.  
  8066.   SET NOCOUNT ON
  8067.  
  8068.   -- Remove any leading/trailing spaces from parameters
  8069.   SELECT @name                       = LTRIM(RTRIM(@name))
  8070.   SELECT @category_name              = LTRIM(RTRIM(@category_name))
  8071.   SELECT @originating_server         = LTRIM(RTRIM(@originating_server))
  8072.  
  8073.   -- Make sure that input/output strings - if NULL - are initialized to NOT null
  8074.   EXECUTE @retval = master.dbo.xp_getnetname @local_machine_name OUTPUT
  8075.   IF (@retval <> 0)
  8076.     RETURN(1) -- Failure
  8077.   SELECT @originating_server = ISNULL(@originating_server, ISNULL(@local_machine_name, UPPER(CONVERT(NVARCHAR(30), SERVERPROPERTY('ServerName')))))
  8078.  
  8079.   -- Replace the local server name with local server name
  8080.   IF (UPPER(@originating_server) = UPPER(@local_machine_name))
  8081.     SELECT @originating_server = UPPER(CONVERT(NVARCHAR(30), SERVERPROPERTY('ServerName')))
  8082.  
  8083.   -- Check originating server (only the SQLServerAgent can add jobs that originate from a remote server)
  8084.   IF (UPPER(@originating_server) <> UPPER(CONVERT(NVARCHAR(30), SERVERPROPERTY('ServerName')))) AND
  8085.      (PROGRAM_NAME() NOT LIKE N'SQLAgent%')
  8086.   BEGIN
  8087.     RAISERROR(14275, -1, -1, @local_machine_name)
  8088.     RETURN(1) -- Failure
  8089.   END
  8090.  
  8091.   -- Make sure that the local server is always referred to as local server name (ie. lower-case)
  8092.   IF (UPPER(@originating_server) = UPPER(CONVERT(NVARCHAR(30), SERVERPROPERTY('ServerName'))))
  8093.     SELECT @originating_server = LOWER(@originating_server)
  8094.  
  8095.   -- NOTE: We allow jobs with the same name (since job_id is always unique) but only if
  8096.   --       they originate from different servers.  Thus jobs can flow from an MSX to a TSX
  8097.   --       without having to worry about naming conflicts.
  8098.   IF (EXISTS (SELECT *
  8099.               FROM msdb.dbo.sysjobs
  8100.               WHERE (name = @name)
  8101.                 AND (originating_server = @originating_server)
  8102.                 AND (job_id <> ISNULL(@job_id, 0x911)))) -- When adding a new job @job_id is NULL
  8103.   BEGIN
  8104.     RAISERROR(14261, -1, -1, '@name', @name)
  8105.     RETURN(1) -- Failure
  8106.   END
  8107.  
  8108.   -- Check enabled state
  8109.   IF (@enabled <> 0) AND (@enabled <> 1)
  8110.   BEGIN
  8111.     RAISERROR(14266, -1, -1, '@enabled', '0, 1')
  8112.     RETURN(1) -- Failure
  8113.   END
  8114.  
  8115.   -- Check start step
  8116.   IF (@job_id IS NULL)
  8117.   BEGIN
  8118.     -- New job
  8119.     -- NOTE: For [new] MSX jobs we allow the start step to be other than 1 since
  8120.     --       the start step was validated when the job was created at the MSX
  8121.     IF (@start_step_id <> 1) AND (UPPER(@originating_server) = UPPER(CONVERT(NVARCHAR(30), SERVERPROPERTY('ServerName'))))
  8122.     BEGIN
  8123.       RAISERROR(14266, -1, -1, '@start_step_id', '1')
  8124.       RETURN(1) -- Failure
  8125.     END
  8126.   END
  8127.   ELSE
  8128.   BEGIN
  8129.     -- Existing job
  8130.     DECLARE @max_step_id INT
  8131.     DECLARE @valid_range VARCHAR(50)
  8132.  
  8133.     -- Get current maximum step id
  8134.     SELECT @max_step_id = ISNULL(MAX(step_id), 0)
  8135.     FROM msdb.dbo.sysjobsteps
  8136.     WHERE (job_id = @job_id)
  8137.  
  8138.     IF (@start_step_id < 1) OR (@start_step_id > @max_step_id + 1)
  8139.     BEGIN
  8140.       SELECT @valid_range = '1..' + CONVERT(VARCHAR, @max_step_id + 1)
  8141.       RAISERROR(14266, -1, -1, '@start_step_id', @valid_range)
  8142.       RETURN(1) -- Failure
  8143.     END
  8144.   END
  8145.  
  8146.   -- Check category
  8147.   SELECT @job_type = NULL
  8148.  
  8149.   IF (EXISTS (SELECT *
  8150.               FROM msdb.dbo.sysjobservers
  8151.               WHERE (job_id = @job_id)
  8152.                 AND (server_id = 0)))
  8153.     SELECT @job_type = 1 -- LOCAL
  8154.  
  8155.   IF (EXISTS (SELECT *
  8156.               FROM msdb.dbo.sysjobservers
  8157.               WHERE (job_id = @job_id)
  8158.                 AND (server_id <> 0)))
  8159.     SELECT @job_type = 2 -- MULTI-SERVER
  8160.  
  8161.   -- A local job cannot be added to a multi-server job_category
  8162.   IF (@job_type = 1) AND (EXISTS (SELECT *
  8163.                                   FROM msdb.dbo.syscategories
  8164.                                   WHERE (category_class = 1) -- Job
  8165.                                     AND (category_type = 2) -- Multi-Server
  8166.                                     AND (name = @category_name)))
  8167.   BEGIN
  8168.     RAISERROR(14285, -1, -1)
  8169.     RETURN(1) -- Failure
  8170.   END
  8171.  
  8172.   -- A multi-server job cannot be added to a local job_category
  8173.   IF (@job_type = 2) AND (EXISTS (SELECT *
  8174.                                   FROM msdb.dbo.syscategories
  8175.                                   WHERE (category_class = 1) -- Job
  8176.                                     AND (category_type = 1) -- Local
  8177.                                     AND (name = @category_name)))
  8178.   BEGIN
  8179.     RAISERROR(14286, -1, -1)
  8180.     RETURN(1) -- Failure
  8181.   END
  8182.  
  8183.   -- Get the category_id, handling any special-cases as appropriate
  8184.   SELECT @category_id = NULL
  8185.   IF (@category_name = N'[DEFAULT]') -- User wants to revert to the default job category
  8186.   BEGIN
  8187.     SELECT @category_id = CASE ISNULL(@job_type, 1)
  8188.                             WHEN 1 THEN 0 -- [Uncategorized (Local)]
  8189.                             WHEN 2 THEN 2 -- [Uncategorized (Multi-Server)]
  8190.                           END
  8191.   END
  8192.   ELSE
  8193.   IF (@category_name IS NULL) -- The sp_add_job default
  8194.   BEGIN
  8195.     SELECT @category_id = 0
  8196.   END
  8197.   ELSE
  8198.   BEGIN
  8199.     SELECT @category_id = category_id
  8200.     FROM msdb.dbo.syscategories
  8201.     WHERE (category_class = 1) -- Job
  8202.       AND (name = @category_name)
  8203.   END
  8204.  
  8205.   IF (@category_id IS NULL)
  8206.   BEGIN
  8207.     RAISERROR(14234, -1, -1, '@category_name', 'sp_help_category')
  8208.     RETURN(1) -- Failure
  8209.   END
  8210.  
  8211.   -- Only SQLServerAgent may add jobs to the 'Jobs From MSX' category
  8212.   IF (@category_id = 1) AND
  8213.      (PROGRAM_NAME() NOT LIKE N'SQLAgent%')
  8214.   BEGIN
  8215.     RAISERROR(14267, -1, -1, @category_name)
  8216.     RETURN(1) -- Failure
  8217.   END
  8218.  
  8219.   -- Check owner
  8220.   -- If a non-sa is [illegally] trying to create a job for another user then default the owner
  8221.   -- to be the calling user.
  8222.   IF ((ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) = 0) AND (@owner_sid <> SUSER_SID()))
  8223.     SELECT @owner_sid = SUSER_SID()
  8224.  
  8225.   -- Now just check that the login id is valid (ie. it exists and isn't an NT group)
  8226.   IF (@owner_sid IS NULL) OR (EXISTS (SELECT *
  8227.                                       FROM master.dbo.syslogins
  8228.                                       WHERE (sid = @owner_sid)
  8229.                                         AND (isntgroup <> 0)))
  8230.   BEGIN
  8231.     -- NOTE: In the following message we quote @owner_login_name instead of @owner_sid
  8232.     --       since this is the parameter the user passed to the calling SP (ie. either
  8233.     --       sp_add_job or sp_update_job)
  8234.     SELECT @res_valid_range = FORMATMESSAGE(14203)
  8235.     RAISERROR(14234, -1, -1, '@owner_login_name', @res_valid_range)
  8236.     RETURN(1) -- Failure
  8237.   END
  8238.  
  8239.   -- Check notification levels (must be 0, 1, 2 or 3)
  8240.   IF (@notify_level_eventlog & 0x3 <> @notify_level_eventlog)
  8241.   BEGIN
  8242.     RAISERROR(14266, -1, -1, '@notify_level_eventlog', '0, 1, 2, 3')
  8243.     RETURN(1) -- Failure
  8244.   END
  8245.   IF (@notify_level_email & 0x3 <> @notify_level_email)
  8246.   BEGIN
  8247.     RAISERROR(14266, -1, -1, '@notify_level_email', '0, 1, 2, 3')
  8248.     RETURN(1) -- Failure
  8249.   END
  8250.   IF (@notify_level_netsend & 0x3 <> @notify_level_netsend)
  8251.   BEGIN
  8252.     RAISERROR(14266, -1, -1, '@notify_level_netsend', '0, 1, 2, 3')
  8253.     RETURN(1) -- Failure
  8254.   END
  8255.   IF (@notify_level_page & 0x3 <> @notify_level_page)
  8256.   BEGIN
  8257.     RAISERROR(14266, -1, -1, '@notify_level_page', '0, 1, 2, 3')
  8258.     RETURN(1) -- Failure
  8259.   END
  8260.  
  8261.   -- If we're at a TSX, only SQLServerAgent may add jobs that notify 'MSXOperator'
  8262.   IF (NOT EXISTS (SELECT *
  8263.                   FROM msdb.dbo.systargetservers)) AND
  8264.      ((@notify_email_operator_name = N'MSXOperator') OR
  8265.       (@notify_page_operator_name = N'MSXOperator') OR
  8266.       (@notify_netsend_operator_name = N'MSXOperator')) AND
  8267.      (PROGRAM_NAME() NOT LIKE N'SQLAgent%')
  8268.   BEGIN
  8269.     RAISERROR(14251, -1, -1, 'MSXOperator')
  8270.     RETURN(1) -- Failure
  8271.   END
  8272.  
  8273.   -- Check operator to notify (via email)
  8274.   IF (@notify_email_operator_name IS NOT NULL)
  8275.   BEGIN
  8276.     SELECT @notify_email_operator_id = id
  8277.     FROM msdb.dbo.sysoperators
  8278.     WHERE (name = @notify_email_operator_name)
  8279.  
  8280.     IF (@notify_email_operator_id IS NULL)
  8281.     BEGIN
  8282.       RAISERROR(14234, -1, -1, '@notify_email_operator_name', 'sp_help_operator')
  8283.       RETURN(1) -- Failure
  8284.     END
  8285.     -- If a valid operator is specified the level must be non-zero
  8286.     IF (@notify_level_email = 0)
  8287.     BEGIN
  8288.       RAISERROR(14266, -1, -1, '@notify_level_email', '1, 2, 3')
  8289.       RETURN(1) -- Failure
  8290.     END
  8291.   END
  8292.   ELSE
  8293.   BEGIN
  8294.     SELECT @notify_email_operator_id = 0
  8295.     SELECT @notify_level_email = 0
  8296.   END
  8297.  
  8298.   -- Check operator to notify (via netsend)
  8299.   IF (@notify_netsend_operator_name IS NOT NULL)
  8300.   BEGIN
  8301.     SELECT @notify_netsend_operator_id = id
  8302.     FROM msdb.dbo.sysoperators
  8303.     WHERE (name = @notify_netsend_operator_name)
  8304.  
  8305.     IF (@notify_netsend_operator_id IS NULL)
  8306.     BEGIN
  8307.       RAISERROR(14234, -1, -1, '@notify_netsend_operator_name', 'sp_help_operator')
  8308.       RETURN(1) -- Failure
  8309.     END
  8310.     -- If a valid operator is specified the level must be non-zero
  8311.     IF (@notify_level_netsend = 0)
  8312.     BEGIN
  8313.       RAISERROR(14266, -1, -1, '@notify_level_netsend', '1, 2, 3')
  8314.       RETURN(1) -- Failure
  8315.     END
  8316.   END
  8317.   ELSE
  8318.   BEGIN
  8319.     SELECT @notify_netsend_operator_id = 0
  8320.     SELECT @notify_level_netsend = 0
  8321.   END
  8322.  
  8323.   -- Check operator to notify (via page)
  8324.   IF (@notify_page_operator_name IS NOT NULL)
  8325.   BEGIN
  8326.     SELECT @notify_page_operator_id = id
  8327.     FROM msdb.dbo.sysoperators
  8328.     WHERE (name = @notify_page_operator_name)
  8329.  
  8330.     IF (@notify_page_operator_id IS NULL)
  8331.     BEGIN
  8332.       RAISERROR(14234, -1, -1, '@notify_page_operator_name', 'sp_help_operator')
  8333.       RETURN(1) -- Failure
  8334.     END
  8335.     -- If a valid operator is specified the level must be non-zero
  8336.     IF (@notify_level_page = 0)
  8337.     BEGIN
  8338.       RAISERROR(14266, -1, -1, '@notify_level_page', '1, 2, 3')
  8339.       RETURN(1) -- Failure
  8340.     END
  8341.   END
  8342.   ELSE
  8343.   BEGIN
  8344.     SELECT @notify_page_operator_id = 0
  8345.     SELECT @notify_level_page = 0
  8346.   END
  8347.  
  8348.   -- Check delete level (must be 0, 1, 2 or 3)
  8349.   IF (@delete_level & 0x3 <> @delete_level)
  8350.   BEGIN
  8351.     RAISERROR(14266, -1, -1, '@delete_level', '0, 1, 2, 3')
  8352.     RETURN(1) -- Failure
  8353.   END
  8354.  
  8355.   RETURN(0) -- Success
  8356. END
  8357. go
  8358.  
  8359. /**************************************************************/
  8360. /* SP_ADD_JOB                                                 */
  8361. /**************************************************************/
  8362.  
  8363. PRINT ''
  8364. PRINT 'Creating procedure sp_add_job...'
  8365. go
  8366. IF (EXISTS (SELECT *
  8367.             FROM msdb.dbo.sysobjects
  8368.             WHERE (name = N'sp_add_job')
  8369.               AND (type = 'P')))
  8370.   DROP PROCEDURE sp_add_job
  8371. go
  8372. CREATE PROCEDURE sp_add_job
  8373.   @job_name                     sysname,
  8374.   @enabled                      TINYINT          = 1,        -- 0 = Disabled, 1 = Enabled
  8375.   @description                  NVARCHAR(512)    = NULL,
  8376.   @start_step_id                INT              = 1,
  8377.   @category_name                sysname          = NULL,
  8378.   @category_id                  INT              = NULL,     -- A language-independent way to specify which category to use
  8379.   @owner_login_name             sysname          = NULL,     -- The procedure assigns a default
  8380.   @notify_level_eventlog        INT              = 2,        -- 0 = Never, 1 = On Success, 2 = On Failure, 3 = Always
  8381.   @notify_level_email           INT              = 0,        -- 0 = Never, 1 = On Success, 2 = On Failure, 3 = Always
  8382.   @notify_level_netsend         INT              = 0,        -- 0 = Never, 1 = On Success, 2 = On Failure, 3 = Always
  8383.   @notify_level_page            INT              = 0,        -- 0 = Never, 1 = On Success, 2 = On Failure, 3 = Always
  8384.   @notify_email_operator_name   sysname          = NULL,
  8385.   @notify_netsend_operator_name sysname          = NULL,
  8386.   @notify_page_operator_name    sysname          = NULL,
  8387.   @delete_level                 INT              = 0,        -- 0 = Never, 1 = On Success, 2 = On Failure, 3 = Always
  8388.   @job_id                       UNIQUEIDENTIFIER = NULL OUTPUT,
  8389.   @originating_server           NVARCHAR(30)     = NULL
  8390. AS
  8391. BEGIN
  8392.   DECLARE @retval                     INT
  8393.   DECLARE @notify_email_operator_id   INT
  8394.   DECLARE @notify_netsend_operator_id INT
  8395.   DECLARE @notify_page_operator_id    INT
  8396.   DECLARE @owner_sid                  VARBINARY(85)
  8397.  
  8398.   SET NOCOUNT ON
  8399.  
  8400.   IF (@originating_server IS NULL) OR (UPPER(@originating_server) = '(LOCAL)')
  8401.     SELECT @originating_server= UPPER(CONVERT(NVARCHAR(30), SERVERPROPERTY('ServerName')))
  8402.  
  8403.   -- Remove any leading/trailing spaces from parameters (except @owner_login_name)
  8404.   SELECT @originating_server           = LTRIM(RTRIM(@originating_server))
  8405.   SELECT @job_name                     = LTRIM(RTRIM(@job_name))
  8406.   SELECT @description                  = LTRIM(RTRIM(@description))
  8407.   SELECT @category_name                = LTRIM(RTRIM(@category_name))
  8408.   SELECT @notify_email_operator_name   = LTRIM(RTRIM(@notify_email_operator_name))
  8409.   SELECT @notify_netsend_operator_name = LTRIM(RTRIM(@notify_netsend_operator_name))
  8410.   SELECT @notify_page_operator_name    = LTRIM(RTRIM(@notify_page_operator_name))
  8411.  
  8412.   -- Turn [nullable] empty string parameters into NULLs
  8413.   IF (@description                  = N'') SELECT @description                  = NULL
  8414.   IF (@category_name                = N'') SELECT @category_name                = NULL
  8415.   IF (@notify_email_operator_name   = N'') SELECT @notify_email_operator_name   = NULL
  8416.   IF (@notify_netsend_operator_name = N'') SELECT @notify_netsend_operator_name = NULL
  8417.   IF (@notify_page_operator_name    = N'') SELECT @notify_page_operator_name    = NULL
  8418.  
  8419.   -- Default the owner (if not supplied or if a non-sa is [illegally] trying to create a job for another user)
  8420.   IF (@owner_login_name IS NULL) OR ((ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) = 0) AND (@owner_login_name <> SUSER_SNAME()))
  8421.     SELECT @owner_sid = SUSER_SID()
  8422.   ELSE
  8423.     SELECT @owner_sid = SUSER_SID(@owner_login_name) -- If @owner_login_name is invalid then SUSER_SID() will return NULL
  8424.  
  8425.   -- Default the description (if not supplied)
  8426.   IF (@description IS NULL)
  8427.     SELECT @description = FORMATMESSAGE(14571)
  8428.  
  8429.   -- If a category ID is provided this overrides any supplied category name
  8430.   IF (@category_id IS NOT NULL)
  8431.   BEGIN
  8432.     SELECT @category_name = name
  8433.     FROM msdb.dbo.syscategories
  8434.     WHERE (category_id = @category_id)
  8435.     SELECT @category_name = ISNULL(@category_name, FORMATMESSAGE(14205))
  8436.   END
  8437.  
  8438.   -- Check parameters
  8439.   EXECUTE @retval = sp_verify_job NULL,  --  The job id is null since this is a new job
  8440.                                   @job_name,
  8441.                                   @enabled,
  8442.                                   @start_step_id,
  8443.                                   @category_name,
  8444.                                   @owner_sid                  OUTPUT,
  8445.                                   @notify_level_eventlog,
  8446.                                   @notify_level_email         OUTPUT,
  8447.                                   @notify_level_netsend       OUTPUT,
  8448.                                   @notify_level_page          OUTPUT,
  8449.                                   @notify_email_operator_name,
  8450.                                   @notify_netsend_operator_name,
  8451.                                   @notify_page_operator_name,
  8452.                                   @delete_level,
  8453.                                   @category_id                OUTPUT,
  8454.                                   @notify_email_operator_id   OUTPUT,
  8455.                                   @notify_netsend_operator_id OUTPUT,
  8456.                                   @notify_page_operator_id    OUTPUT,
  8457.                                   @originating_server         OUTPUT
  8458.   IF (@retval <> 0)
  8459.     RETURN(1) -- Failure
  8460.  
  8461.   IF (@job_id IS NULL)
  8462.   BEGIN
  8463.     -- Assign the GUID
  8464.     SELECT @job_id = NEWID()
  8465.   END
  8466.   ELSE
  8467.   BEGIN
  8468.     -- A job ID has been provided, so check that the caller is SQLServerAgent (inserting an MSX job)
  8469.     IF (PROGRAM_NAME() NOT LIKE N'SQLAgent%')
  8470.     BEGIN
  8471.       RAISERROR(14284, -1, -1)
  8472.       RETURN(1) -- Failure
  8473.     END
  8474.   END
  8475.  
  8476.   INSERT INTO msdb.dbo.sysjobs
  8477.          (job_id,
  8478.           originating_server,
  8479.           name,
  8480.           enabled,
  8481.           description,
  8482.           start_step_id,
  8483.           category_id,
  8484.           owner_sid,
  8485.           notify_level_eventlog,
  8486.           notify_level_email,
  8487.           notify_level_netsend,
  8488.           notify_level_page,
  8489.           notify_email_operator_id,
  8490.           notify_netsend_operator_id,
  8491.           notify_page_operator_id,
  8492.           delete_level,
  8493.           date_created,
  8494.           date_modified,
  8495.           version_number)
  8496.   VALUES (@job_id,
  8497.           @originating_server,
  8498.           @job_name,
  8499.           @enabled,
  8500.           @description,
  8501.           @start_step_id,
  8502.           @category_id,
  8503.           @owner_sid,
  8504.           @notify_level_eventlog,
  8505.           @notify_level_email,
  8506.           @notify_level_netsend,
  8507.           @notify_level_page,
  8508.           @notify_email_operator_id,
  8509.           @notify_netsend_operator_id,
  8510.           @notify_page_operator_id,
  8511.           @delete_level,
  8512.           GETDATE(),
  8513.           GETDATE(),
  8514.           1) -- Version number 1
  8515.   SELECT @retval = @@error
  8516.  
  8517.   -- If misc. replication job, then update global replication status table
  8518.   IF (@category_id IN (11, 12, 16, 17, 18))
  8519.   BEGIN
  8520.     -- Nothing can be done if this fails, so don't worry about the return code
  8521.     EXECUTE master.dbo.sp_MSupdate_replication_status
  8522.       @publisher = '',
  8523.       @publisher_db = '',
  8524.       @publication = '',
  8525.       @publication_type = -1,
  8526.       @agent_type = 5,
  8527.       @agent_name = @job_name,
  8528.       @status = NULL    -- Never run
  8529.   END
  8530.  
  8531.   -- NOTE: We don't notify SQLServerAgent to update it's cache (we'll do this in sp_add_jobserver)
  8532.  
  8533.   RETURN(@retval) -- 0 means success
  8534. END
  8535. go
  8536.  
  8537. /**************************************************************/
  8538. /* SP_UPDATE_JOB                                              */
  8539. /**************************************************************/
  8540.  
  8541. PRINT ''
  8542. PRINT 'Creating procedure sp_update_job...'
  8543. go
  8544. IF (EXISTS (SELECT *
  8545.             FROM msdb.dbo.sysobjects
  8546.             WHERE (name = N'sp_update_job')
  8547.               AND (type = 'P')))
  8548.   DROP PROCEDURE sp_update_job
  8549. go
  8550. CREATE PROCEDURE sp_update_job
  8551.   @job_id                       UNIQUEIDENTIFIER = NULL, -- Must provide this or current_name
  8552.   @job_name                     sysname          = NULL, -- Must provide this or job_id
  8553.   @new_name                     sysname          = NULL,
  8554.   @enabled                      TINYINT          = NULL,
  8555.   @description                  NVARCHAR(512)    = NULL,
  8556.   @start_step_id                INT              = NULL,
  8557.   @category_name                sysname          = NULL,
  8558.   @owner_login_name             sysname          = NULL,
  8559.   @notify_level_eventlog        INT              = NULL,
  8560.   @notify_level_email           INT              = NULL,
  8561.   @notify_level_netsend         INT              = NULL,
  8562.   @notify_level_page            INT              = NULL,
  8563.   @notify_email_operator_name   sysname          = NULL,
  8564.   @notify_netsend_operator_name sysname          = NULL,
  8565.   @notify_page_operator_name    sysname          = NULL,
  8566.   @delete_level                 INT              = NULL,
  8567.   @automatic_post               BIT              = 1     -- Flag for SEM use only
  8568. AS
  8569. BEGIN
  8570.   DECLARE @retval                        INT
  8571.   DECLARE @category_id                   INT
  8572.   DECLARE @notify_email_operator_id      INT
  8573.   DECLARE @notify_netsend_operator_id    INT
  8574.   DECLARE @notify_page_operator_id       INT
  8575.   DECLARE @owner_sid                     VARBINARY(85)
  8576.   DECLARE @alert_id                      INT
  8577.   DECLARE @cached_attribute_modified     INT
  8578.   DECLARE @is_sysadmin                   INT
  8579.   DECLARE @current_owner                 sysname
  8580.  
  8581.   DECLARE @x_new_name                    sysname
  8582.   DECLARE @x_enabled                     TINYINT
  8583.   DECLARE @x_description                 NVARCHAR(512)
  8584.   DECLARE @x_start_step_id               INT
  8585.   DECLARE @x_category_name               sysname
  8586.   DECLARE @x_category_id                 INT
  8587.   DECLARE @x_owner_sid                   VARBINARY(85)
  8588.   DECLARE @x_notify_level_eventlog       INT
  8589.   DECLARE @x_notify_level_email          INT
  8590.   DECLARE @x_notify_level_netsend        INT
  8591.   DECLARE @x_notify_level_page           INT
  8592.   DECLARE @x_notify_email_operator_name  sysname
  8593.   DECLARE @x_notify_netsnd_operator_name sysname
  8594.   DECLARE @x_notify_page_operator_name   sysname
  8595.   DECLARE @x_delete_level                INT
  8596.   DECLARE @x_originating_server          NVARCHAR(30) -- Not updatable
  8597.  
  8598.   -- Remove any leading/trailing spaces from parameters (except @owner_login_name)
  8599.   SELECT @job_name                     = LTRIM(RTRIM(@job_name))
  8600.   SELECT @new_name                     = LTRIM(RTRIM(@new_name))
  8601.   SELECT @description                  = LTRIM(RTRIM(@description))
  8602.   SELECT @category_name                = LTRIM(RTRIM(@category_name))
  8603.   SELECT @notify_email_operator_name   = LTRIM(RTRIM(@notify_email_operator_name))
  8604.   SELECT @notify_netsend_operator_name = LTRIM(RTRIM(@notify_netsend_operator_name))
  8605.   SELECT @notify_page_operator_name    = LTRIM(RTRIM(@notify_page_operator_name))
  8606.  
  8607.   SET NOCOUNT ON
  8608.  
  8609.   EXECUTE @retval = sp_verify_job_identifiers '@job_name',
  8610.                                               '@job_id',
  8611.                                                @job_name OUTPUT,
  8612.                                                @job_id   OUTPUT
  8613.   IF (@retval <> 0)
  8614.     RETURN(1) -- Failure
  8615.  
  8616.   -- Are we modifying an attribute which SQLServerAgent caches?
  8617.   IF ((@new_name                     IS NOT NULL) OR
  8618.       (@enabled                      IS NOT NULL) OR
  8619.       (@start_step_id                IS NOT NULL) OR
  8620.       (@owner_login_name             IS NOT NULL) OR
  8621.       (@notify_level_eventlog        IS NOT NULL) OR
  8622.       (@notify_level_email           IS NOT NULL) OR
  8623.       (@notify_level_netsend         IS NOT NULL) OR
  8624.       (@notify_level_page            IS NOT NULL) OR
  8625.       (@notify_email_operator_name   IS NOT NULL) OR
  8626.       (@notify_netsend_operator_name IS NOT NULL) OR
  8627.       (@notify_page_operator_name    IS NOT NULL) OR
  8628.       (@delete_level                 IS NOT NULL))
  8629.     SELECT @cached_attribute_modified = 1
  8630.   ELSE
  8631.     SELECT @cached_attribute_modified = 0
  8632.  
  8633.   -- Set the x_ (existing) variables
  8634.   SELECT @x_new_name                    = sjv.name,
  8635.          @x_enabled                     = sjv.enabled,
  8636.          @x_description                 = sjv.description,
  8637.          @x_start_step_id               = sjv.start_step_id,
  8638.          @x_category_name               = sc.name,                  -- From syscategories
  8639.          @x_category_id                 = sc.category_id,           -- From syscategories
  8640.          @x_owner_sid                   = sjv.owner_sid,
  8641.          @x_notify_level_eventlog       = sjv.notify_level_eventlog,
  8642.          @x_notify_level_email          = sjv.notify_level_email,
  8643.          @x_notify_level_netsend        = sjv.notify_level_netsend,
  8644.          @x_notify_level_page           = sjv.notify_level_page,
  8645.          @x_notify_email_operator_name  = so1.name,                   -- From sysoperators
  8646.          @x_notify_netsnd_operator_name = so2.name,                   -- From sysoperators
  8647.          @x_notify_page_operator_name   = so3.name,                   -- From sysoperators
  8648.          @x_delete_level                = sjv.delete_level,
  8649.          @x_originating_server          = sjv.originating_server
  8650.   FROM msdb.dbo.sysjobs_view                 sjv
  8651.        LEFT OUTER JOIN msdb.dbo.sysoperators so1 ON (sjv.notify_email_operator_id = so1.id)
  8652.        LEFT OUTER JOIN msdb.dbo.sysoperators so2 ON (sjv.notify_netsend_operator_id = so2.id)
  8653.        LEFT OUTER JOIN msdb.dbo.sysoperators so3 ON (sjv.notify_page_operator_id = so3.id),
  8654.        msdb.dbo.syscategories                sc
  8655.   WHERE (sjv.job_id = @job_id)
  8656.     AND (sjv.category_id = sc.category_id)
  8657.  
  8658.   -- Check authority (only SQLServerAgent can modify a non-local job)
  8659.   IF (UPPER(@x_originating_server) <> UPPER(CONVERT(NVARCHAR(30), SERVERPROPERTY('ServerName')))) AND
  8660.      (PROGRAM_NAME() NOT LIKE N'SQLAgent%')
  8661.   BEGIN
  8662.     RAISERROR(14274, -1, -1)
  8663.     RETURN(1) -- Failure
  8664.   END
  8665.  
  8666.   IF (@new_name = N'') SELECT @new_name = NULL
  8667.  
  8668.   -- Fill out the values for all non-supplied parameters from the existing values
  8669.   IF (@new_name                     IS NULL) SELECT @new_name                     = @x_new_name
  8670.   IF (@enabled                      IS NULL) SELECT @enabled                      = @x_enabled
  8671.   IF (@description                  IS NULL) SELECT @description                  = @x_description
  8672.   IF (@start_step_id                IS NULL) SELECT @start_step_id                = @x_start_step_id
  8673.   IF (@category_name                IS NULL) SELECT @category_name                = @x_category_name
  8674.   IF (@owner_sid                    IS NULL) SELECT @owner_sid                    = @x_owner_sid
  8675.   IF (@notify_level_eventlog        IS NULL) SELECT @notify_level_eventlog        = @x_notify_level_eventlog
  8676.   IF (@notify_level_email           IS NULL) SELECT @notify_level_email           = @x_notify_level_email
  8677.   IF (@notify_level_netsend         IS NULL) SELECT @notify_level_netsend         = @x_notify_level_netsend
  8678.   IF (@notify_level_page            IS NULL) SELECT @notify_level_page            = @x_notify_level_page
  8679.   IF (@notify_email_operator_name   IS NULL) SELECT @notify_email_operator_name   = @x_notify_email_operator_name
  8680.   IF (@notify_netsend_operator_name IS NULL) SELECT @notify_netsend_operator_name = @x_notify_netsnd_operator_name
  8681.   IF (@notify_page_operator_name    IS NULL) SELECT @notify_page_operator_name    = @x_notify_page_operator_name
  8682.   IF (@delete_level                 IS NULL) SELECT @delete_level                 = @x_delete_level
  8683.  
  8684.   -- If the SA is attempting to assign ownership of the job to someone else, then convert
  8685.   -- the login name to an ID
  8686.   IF ((ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) = 1) AND (@owner_login_name IS NOT NULL))
  8687.     SELECT @owner_sid = SUSER_SID(@owner_login_name) -- If @owner_login_name is invalid then SUSER_SID() will return NULL
  8688.  
  8689.   -- Only the SA can re-assign jobs
  8690.   IF ((ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) <> 1) AND (@owner_login_name IS NOT NULL))
  8691.     RAISERROR(14242, -1, -1)
  8692.  
  8693.   -- Ownership of a multi-server job cannot be assigned to a non-sysadmin
  8694.   IF (@owner_login_name IS NOT NULL) AND
  8695.      (EXISTS (SELECT *
  8696.               FROM msdb.dbo.sysjobs       sj,
  8697.                    msdb.dbo.sysjobservers sjs
  8698.               WHERE (sj.job_id = sjs.job_id)
  8699.                 AND (sj.job_id = @job_id)
  8700.                 AND (sjs.server_id <> 0)))
  8701.   BEGIN
  8702.     SELECT @is_sysadmin = 0
  8703.     EXECUTE msdb.dbo.sp_sqlagent_has_server_access @login_name = @owner_login_name, @is_sysadmin_member = @is_sysadmin OUTPUT
  8704.     IF (@is_sysadmin = 0)
  8705.     BEGIN
  8706.       SELECT @current_owner = SUSER_SNAME(@x_owner_sid)
  8707.       RAISERROR(14543, -1, -1, @current_owner, N'sysadmin')
  8708.       RETURN(1) -- Failure
  8709.     END
  8710.   END
  8711.  
  8712.   -- Turn [nullable] empty string parameters into NULLs
  8713.   IF (@description                  = N'') SELECT @description                  = NULL
  8714.   IF (@category_name                = N'') SELECT @category_name                = NULL
  8715.   IF (@notify_email_operator_name   = N'') SELECT @notify_email_operator_name   = NULL
  8716.   IF (@notify_netsend_operator_name = N'') SELECT @notify_netsend_operator_name = NULL
  8717.   IF (@notify_page_operator_name    = N'') SELECT @notify_page_operator_name    = NULL
  8718.  
  8719.   -- Check new values
  8720.   EXECUTE @retval = sp_verify_job @job_id,
  8721.                                   @new_name,
  8722.                                   @enabled,
  8723.                                   @start_step_id,
  8724.                                   @category_name,
  8725.                                   @owner_sid                  OUTPUT,
  8726.                                   @notify_level_eventlog,
  8727.                                   @notify_level_email         OUTPUT,
  8728.                                   @notify_level_netsend       OUTPUT,
  8729.                                   @notify_level_page          OUTPUT,
  8730.                                   @notify_email_operator_name,
  8731.                                   @notify_netsend_operator_name,
  8732.                                   @notify_page_operator_name,
  8733.                                   @delete_level,
  8734.                                   @category_id                OUTPUT,
  8735.                                   @notify_email_operator_id   OUTPUT,
  8736.                                   @notify_netsend_operator_id OUTPUT,
  8737.                                   @notify_page_operator_id    OUTPUT,
  8738.                                   @x_originating_server       OUTPUT -- We ignore the return value
  8739.   IF (@retval <> 0)
  8740.     RETURN(1) -- Failure
  8741.  
  8742.   BEGIN TRANSACTION
  8743.  
  8744.   -- If the job is being re-assigned, modify sysjobsteps.database_user_name as necessary
  8745.   IF (@owner_login_name IS NOT NULL)
  8746.   BEGIN
  8747.     IF (EXISTS (SELECT *
  8748.                 FROM msdb.dbo.sysjobsteps
  8749.                 WHERE (job_id = @job_id)
  8750.                   AND (subsystem = N'TSQL')))
  8751.     BEGIN
  8752.       IF (EXISTS (SELECT *
  8753.                   FROM master.dbo.syslogins
  8754.                   WHERE (sid = @owner_sid)
  8755.                     AND (sysadmin <> 1)))
  8756.       BEGIN
  8757.         -- The job is being re-assigned to an non-SA
  8758.         UPDATE msdb.dbo.sysjobsteps
  8759.         SET database_user_name = NULL
  8760.         WHERE (job_id = @job_id)
  8761.           AND (subsystem = N'TSQL')
  8762.       END
  8763.     END
  8764.   END
  8765.  
  8766.   UPDATE msdb.dbo.sysjobs
  8767.   SET name                       = @new_name,
  8768.       enabled                    = @enabled,
  8769.       description                = @description,
  8770.       start_step_id              = @start_step_id,
  8771.       category_id                = @category_id,              -- Returned from sp_verify_job
  8772.       owner_sid                  = @owner_sid,
  8773.       notify_level_eventlog      = @notify_level_eventlog,
  8774.       notify_level_email         = @notify_level_email,
  8775.       notify_level_netsend       = @notify_level_netsend,
  8776.       notify_level_page          = @notify_level_page,
  8777.       notify_email_operator_id   = @notify_email_operator_id,   -- Returned from sp_verify_job
  8778.       notify_netsend_operator_id = @notify_netsend_operator_id, -- Returned from sp_verify_job
  8779.       notify_page_operator_id    = @notify_page_operator_id,    -- Returned from sp_verify_job
  8780.       delete_level               = @delete_level,
  8781.       version_number             = version_number + 1,  -- Update the job's version
  8782.       date_modified              = GETDATE()            -- Update the job's last-modified information
  8783.   WHERE (job_id = @job_id)
  8784.   SELECT @retval = @@error
  8785.  
  8786.   COMMIT TRANSACTION
  8787.  
  8788.   -- If change to or from a misc. replication job, then update global replication status table
  8789.   IF ((@category_name != @x_category_name) AND
  8790.     (@x_category_id IN (11, 12, 16, 17, 18) OR @category_id IN (11, 12,16, 17, 18)))
  8791.   BEGIN
  8792.     -- Delete entry if change misc. replication job to other
  8793.     IF (@x_category_name IS NOT NULL)
  8794.     BEGIN
  8795.       -- Nothing can be done if this fails, so don't worry about the return code
  8796.       EXECUTE master.dbo.sp_MSupdate_replication_status
  8797.         @publisher = '',
  8798.         @publisher_db = '',
  8799.         @publication = '',
  8800.         @publication_type = -1,
  8801.         @agent_type = 5,
  8802.         @agent_name = @job_name,
  8803.         @status = -1  -- Delete
  8804.     END
  8805.  
  8806.     -- Add entry if updated to misc. replication job
  8807.     IF (@x_category_name IS NOT NULL)
  8808.     BEGIN
  8809.       -- Nothing can be done if this fails, so don't worry about the return code
  8810.       EXECUTE master.dbo.sp_MSupdate_replication_status
  8811.         @publisher = '',
  8812.         @publisher_db = '',
  8813.         @publication = '',
  8814.         @publication_type = -1,
  8815.         @agent_type = 5,
  8816.         @agent_name = @job_name,
  8817.         @status = NULL    -- Never run
  8818.     END
  8819.   END
  8820.  
  8821.   -- Always re-post the job if it's an auto-delete job (or if we're updating an auto-delete job
  8822.   -- to be non-auto-delete)
  8823.   IF (((SELECT delete_level
  8824.         FROM msdb.dbo.sysjobs
  8825.         WHERE (job_id = @job_id)) <> 0) OR
  8826.       ((@x_delete_level = 1) AND (@delete_level = 0)))
  8827.     EXECUTE msdb.dbo.sp_post_msx_operation 'INSERT', 'JOB', @job_id
  8828.   ELSE
  8829.   BEGIN
  8830.     -- Post the update to target servers
  8831.     IF (@automatic_post = 1)
  8832.       EXECUTE msdb.dbo.sp_post_msx_operation 'UPDATE', 'JOB', @job_id
  8833.   END
  8834.  
  8835.   -- Keep SQLServerAgent's cache in-sync
  8836.   -- NOTE: We only notify SQLServerAgent if we know the job has been cached and if
  8837.   --       attributes other than description or category have been changed (since
  8838.   --       SQLServerAgent doesn't cache these two)
  8839.   IF (EXISTS (SELECT *
  8840.               FROM msdb.dbo.sysjobservers
  8841.               WHERE (job_id = @job_id)
  8842.                 AND (server_id = 0)
  8843.                 AND (@cached_attribute_modified = 1)))
  8844.     EXECUTE msdb.dbo.sp_sqlagent_notify @op_type     = N'J',
  8845.                                         @job_id      = @job_id,
  8846.                                         @action_type = N'U'
  8847.  
  8848.   -- If the name was changed, make SQLServerAgent re-cache any alerts that reference the job
  8849.   -- since the alert cache contains the job name
  8850.   IF ((@job_name <> @new_name) AND (EXISTS (SELECT *
  8851.                                             FROM msdb.dbo.sysalerts
  8852.                                             WHERE (job_id = @job_id))))
  8853.   BEGIN
  8854.     DECLARE sysalerts_cache_update CURSOR LOCAL
  8855.     FOR
  8856.     SELECT id
  8857.     FROM msdb.dbo.sysalerts
  8858.     WHERE (job_id = @job_id)
  8859.  
  8860.     OPEN sysalerts_cache_update
  8861.     FETCH NEXT FROM sysalerts_cache_update INTO @alert_id
  8862.  
  8863.     WHILE (@@fetch_status = 0)
  8864.     BEGIN
  8865.       EXECUTE msdb.dbo.sp_sqlagent_notify @op_type     = N'A',
  8866.                                           @alert_id    = @alert_id,
  8867.                                           @action_type = N'U'
  8868.       FETCH NEXT FROM sysalerts_cache_update INTO @alert_id
  8869.     END
  8870.     DEALLOCATE sysalerts_cache_update
  8871.   END
  8872.  
  8873.   RETURN(@retval) -- 0 means success
  8874. END
  8875. go
  8876.  
  8877. /**************************************************************/
  8878. /* SP_DELETE_JOB                                              */
  8879. /**************************************************************/
  8880.  
  8881. PRINT ''
  8882. PRINT 'Creating procedure sp_delete_job...'
  8883. go
  8884. IF (EXISTS (SELECT *
  8885.             FROM msdb.dbo.sysobjects
  8886.             WHERE (name = N'sp_delete_job')
  8887.               AND (type = 'P')))
  8888.   DROP PROCEDURE sp_delete_job
  8889. go
  8890. CREATE PROCEDURE sp_delete_job
  8891.   @job_id             UNIQUEIDENTIFIER = NULL, -- If provided should NOT also provide job_name
  8892.   @job_name           sysname          = NULL, -- If provided should NOT also provide job_id
  8893.   @originating_server NVARCHAR(30)     = NULL, -- Reserved (used by SQLAgent)
  8894.   @delete_history     BIT              = 1     -- Reserved (used by SQLAgent)
  8895. AS
  8896. BEGIN
  8897.   DECLARE @current_msx_server NVARCHAR(30)
  8898.   DECLARE @bMSX_job           BIT
  8899.   DECLARE @retval             INT
  8900.   DECLARE @local_machine_name NVARCHAR(30)
  8901.   DECLARE @category_id        INT
  8902.  
  8903.   SET NOCOUNT ON
  8904.  
  8905.   -- Remove any leading/trailing spaces from parameters
  8906.   SELECT @originating_server = LTRIM(RTRIM(@originating_server))
  8907.  
  8908.   -- Change server name to always reflect real servername or servername\instancename
  8909.   IF (UPPER(@originating_server) = '(LOCAL)')
  8910.     SELECT @originating_server = UPPER(CONVERT(NVARCHAR(30), SERVERPROPERTY('ServerName')))
  8911.  
  8912.   -- Turn [nullable] empty string parameters into NULLs
  8913.   IF (@originating_server = N'') 
  8914.     SELECT @originating_server = NULL
  8915.  
  8916.   IF ((@job_id IS NOT NULL) OR (@job_name IS NOT NULL))
  8917.   BEGIN
  8918.     EXECUTE @retval = sp_verify_job_identifiers '@job_name',
  8919.                                                 '@job_id',
  8920.                                                  @job_name OUTPUT,
  8921.                                                  @job_id   OUTPUT
  8922.     IF (@retval <> 0)
  8923.       RETURN(1) -- Failure
  8924.   END
  8925.  
  8926.   -- We need either a job name or a server name, not both
  8927.   IF ((@job_name IS NULL)     AND (@originating_server IS NULL)) OR
  8928.      ((@job_name IS NOT NULL) AND (@originating_server IS NOT NULL))
  8929.   BEGIN
  8930.     RAISERROR(14279, -1, -1)
  8931.     RETURN(1) -- Failure
  8932.   END
  8933.  
  8934.   -- Get category to see if it is a misc. replication agent. @category_id will be
  8935.   -- NULL if there is no @job_id.
  8936.   select @category_id = category_id from msdb.dbo.sysjobs where job_id = @job_id
  8937.  
  8938.   -- If job name was given, determine if the job is from an MSX
  8939.   IF (@job_id IS NOT NULL)
  8940.   BEGIN
  8941.     SELECT @bMSX_job = CASE UPPER(originating_server)
  8942.                          WHEN UPPER(CONVERT(NVARCHAR(30), SERVERPROPERTY('ServerName'))) THEN 0
  8943.                          ELSE 1
  8944.                        END
  8945.     FROM msdb.dbo.sysjobs_view
  8946.     WHERE (job_id = @job_id)
  8947.   END
  8948.  
  8949.   -- If server name was given, warn user if different from current MSX
  8950.   IF (@originating_server IS NOT NULL)
  8951.   BEGIN
  8952.     EXECUTE @retval = master.dbo.xp_getnetname @local_machine_name OUTPUT
  8953.     IF (@retval <> 0)
  8954.       RETURN(1) -- Failure
  8955.  
  8956.     IF ((UPPER(@originating_server) = UPPER(CONVERT(NVARCHAR(30), SERVERPROPERTY('ServerName')))) OR (UPPER(@originating_server) = UPPER(@local_machine_name)))
  8957.       SELECT @originating_server = UPPER(CONVERT(NVARCHAR(30), SERVERPROPERTY('ServerName')))
  8958.  
  8959.     EXECUTE master.dbo.xp_instance_regread N'HKEY_LOCAL_MACHINE',
  8960.                                            N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
  8961.                                            N'MSXServerName',
  8962.                                            @current_msx_server OUTPUT,
  8963.                                            N'no_output'
  8964.  
  8965.     -- If server name was given but it's not the current MSX, print a warning
  8966.     SELECT @current_msx_server = LTRIM(RTRIM(@current_msx_server))
  8967.     IF ((@current_msx_server IS NOT NULL) AND (@current_msx_server <> N'') AND (@originating_server <> @current_msx_server))
  8968.       RAISERROR(14224, 0, 1, @current_msx_server)
  8969.   END
  8970.  
  8971.   -- Check authority (only SQLServerAgent can delete a non-local job)
  8972.   IF (((@originating_server IS NOT NULL) AND (@originating_server <> UPPER(CONVERT(NVARCHAR(30), SERVERPROPERTY('ServerName'))))) OR (@bMSX_job = 1)) AND
  8973.      (PROGRAM_NAME() NOT LIKE N'SQLAgent%')
  8974.   BEGIN
  8975.     RAISERROR(14274, -1, -1)
  8976.     RETURN(1) -- Failure
  8977.   END
  8978.  
  8979.   CREATE TABLE #temp_jobs_to_delete (job_id UNIQUEIDENTIFIER NOT NULL, job_is_cached INT NOT NULL)
  8980.  
  8981.   -- Do the delete (for a specific job)
  8982.   IF (@job_id IS NOT NULL)
  8983.   BEGIN
  8984.     INSERT INTO #temp_jobs_to_delete
  8985.     SELECT job_id, (SELECT COUNT(*)
  8986.                     FROM msdb.dbo.sysjobservers
  8987.                     WHERE (job_id = @job_id)
  8988.                       AND (server_id = 0))
  8989.     FROM msdb.dbo.sysjobs_view
  8990.     WHERE (job_id = @job_id)
  8991.  
  8992.     -- Check if we have any work to do
  8993.     IF (NOT EXISTS (SELECT *
  8994.                     FROM #temp_jobs_to_delete))
  8995.       RETURN(0) -- Success
  8996.  
  8997.     -- Post the delete to any target servers (need to do this BEFORE deleting the job itself,
  8998.     -- but AFTER clearing all all pending download instructions).  Note that if the job is
  8999.     -- NOT a multi-server job then sp_post_msx_operation will catch this and will do nothing.
  9000.     DELETE FROM msdb.dbo.sysdownloadlist
  9001.     WHERE (object_id = @job_id)
  9002.     EXECUTE msdb.dbo.sp_post_msx_operation 'DELETE', 'JOB', @job_id
  9003.  
  9004.     -- Must do this before deleting the job itself since sp_sqlagent_notify does a lookup on sysjobs_view
  9005.     EXECUTE msdb.dbo.sp_delete_job_references
  9006.  
  9007.     -- Delete all traces of the job
  9008.     BEGIN TRANSACTION
  9009.  
  9010.     DELETE FROM msdb.dbo.sysjobs
  9011.     WHERE job_id IN (SELECT job_id FROM #temp_jobs_to_delete)
  9012.  
  9013.     DELETE FROM msdb.dbo.sysjobservers
  9014.     WHERE job_id IN (SELECT job_id FROM #temp_jobs_to_delete)
  9015.  
  9016.     DELETE FROM msdb.dbo.sysjobsteps
  9017.     WHERE job_id IN (SELECT job_id FROM #temp_jobs_to_delete)
  9018.  
  9019.     DELETE FROM msdb.dbo.sysjobschedules
  9020.     WHERE job_id IN (SELECT job_id FROM #temp_jobs_to_delete)
  9021.  
  9022.     IF (@delete_history = 1)
  9023.       DELETE FROM msdb.dbo.sysjobhistory
  9024.       WHERE job_id IN (SELECT job_id FROM #temp_jobs_to_delete)
  9025.  
  9026.     COMMIT TRANSACTION
  9027.  
  9028.   END
  9029.   ELSE
  9030.   -- Do the delete (for all jobs originating from the specific server)
  9031.   IF (@originating_server IS NOT NULL)
  9032.   BEGIN
  9033.     EXECUTE msdb.dbo.sp_delete_all_msx_jobs @msx_server = @originating_server
  9034.  
  9035.     -- NOTE: In this case there is no need to propagate the delete via sp_post_msx_operation
  9036.     --       since this type of delete is only ever performed on a TSX.
  9037.   END
  9038.  
  9039.   DROP TABLE #temp_jobs_to_delete
  9040.  
  9041.   -- If misc. replication job, then update global replication status table.
  9042.   -- @category_id will have a value ONLY if @job_name or @job_id is provided.
  9043.   IF (@category_id IS NOT NULL AND @category_id IN (11, 12, 16, 17, 18))
  9044.   BEGIN
  9045.     -- Nothing can be done if this fails, so don't worry about the return code
  9046.     EXECUTE master.dbo.sp_MSupdate_replication_status
  9047.       @publisher = '',
  9048.       @publisher_db = '',
  9049.       @publication = '',
  9050.       @publication_type = -1,
  9051.       @agent_type = 5,
  9052.       @agent_name = @job_name,
  9053.       @status = -1 -- Delete
  9054.   END
  9055.  
  9056.   RETURN(0) -- 0 means success
  9057. END
  9058. go
  9059.  
  9060. /**************************************************************/
  9061. /* SP_GET_COMPOSITE_JOB_INFO                                  */
  9062. /**************************************************************/
  9063.  
  9064. PRINT ''
  9065. PRINT 'Creating procedure sp_get_composite_job_info...'
  9066. go
  9067. IF (EXISTS (SELECT *
  9068.             FROM msdb.dbo.sysobjects
  9069.             WHERE (name = N'sp_get_composite_job_info')
  9070.               AND (type = 'P')))
  9071.   DROP PROCEDURE sp_get_composite_job_info
  9072. go
  9073. CREATE PROCEDURE sp_get_composite_job_info
  9074.   @job_id             UNIQUEIDENTIFIER = NULL,
  9075.   @job_type           VARCHAR(12)      = NULL,  -- LOCAL or MULTI-SERVER
  9076.   @owner_login_name   sysname          = NULL,
  9077.   @subsystem          NVARCHAR(40)     = NULL,
  9078.   @category_id        INT              = NULL,
  9079.   @enabled            TINYINT          = NULL,
  9080.   @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
  9081.   @date_comparator    CHAR(1)          = NULL,  -- >, < or =
  9082.   @date_created       DATETIME         = NULL,
  9083.   @date_last_modified DATETIME         = NULL,
  9084.   @description        NVARCHAR(512)    = NULL   -- We do a LIKE on this so it can include wildcards
  9085. AS
  9086. BEGIN
  9087.   DECLARE @is_sysadmin INT
  9088.   DECLARE @job_owner   sysname
  9089.  
  9090.   SET NOCOUNT ON
  9091.  
  9092.   -- By 'composite' we mean a combination of sysjobs and xp_sqlagent_enum_jobs data.
  9093.   -- This proc should only ever be called by sp_help_job, so we don't verify the
  9094.   -- parameters (sp_help_job has already done this).
  9095.  
  9096.   -- Step 1: Create intermediate work tables
  9097.   CREATE TABLE #job_execution_state (job_id                  UNIQUEIDENTIFIER NOT NULL,
  9098.                                      date_started            INT              NOT NULL,
  9099.                                      time_started            INT              NOT NULL,
  9100.                                      execution_job_status    INT              NOT NULL,
  9101.                                      execution_step_id       INT              NULL,
  9102.                                      execution_step_name     sysname          COLLATE database_default NULL,
  9103.                                      execution_retry_attempt INT              NOT NULL,
  9104.                                      next_run_date           INT              NOT NULL,
  9105.                                      next_run_time           INT              NOT NULL,
  9106.                                      next_run_schedule_id    INT              NOT NULL)
  9107.   CREATE TABLE #filtered_jobs (job_id                   UNIQUEIDENTIFIER NOT NULL,
  9108.                                date_created             DATETIME         NOT NULL,
  9109.                                date_last_modified       DATETIME         NOT NULL,
  9110.                                current_execution_status INT              NULL,
  9111.                                current_execution_step   sysname          COLLATE database_default NULL,
  9112.                                current_retry_attempt    INT              NULL,
  9113.                                last_run_date            INT              NOT NULL,
  9114.                                last_run_time            INT              NOT NULL,
  9115.                                last_run_outcome         INT              NOT NULL,
  9116.                                next_run_date            INT              NULL,
  9117.                                next_run_time            INT              NULL,
  9118.                                next_run_schedule_id     INT              NULL,
  9119.                                type                     INT              NOT NULL)
  9120.   CREATE TABLE #xp_results (job_id                UNIQUEIDENTIFIER NOT NULL,
  9121.                             last_run_date         INT              NOT NULL,
  9122.                             last_run_time         INT              NOT NULL,
  9123.                             next_run_date         INT              NOT NULL,
  9124.                             next_run_time         INT              NOT NULL,
  9125.                             next_run_schedule_id  INT              NOT NULL,
  9126.                             requested_to_run      INT              NOT NULL, -- BOOL
  9127.                             request_source        INT              NOT NULL,
  9128.                             request_source_id     sysname          COLLATE database_default NULL,
  9129.                             running               INT              NOT NULL, -- BOOL
  9130.                             current_step          INT              NOT NULL,
  9131.                             current_retry_attempt INT              NOT NULL,
  9132.                             job_state             INT              NOT NULL)
  9133.  
  9134.   -- Step 2: Capture job execution information (for local jobs only since that's all SQLServerAgent caches)
  9135.   SELECT @is_sysadmin = ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0)
  9136.   SELECT @job_owner = SUSER_SNAME()
  9137.  
  9138.   IF ((@@microsoftversion / 0x01000000) >= 8) -- SQL Server 8.0 or greater
  9139.     INSERT INTO #xp_results
  9140.     EXECUTE master.dbo.xp_sqlagent_enum_jobs @is_sysadmin, @job_owner, @job_id
  9141.   ELSE
  9142.     INSERT INTO #xp_results
  9143.     EXECUTE master.dbo.xp_sqlagent_enum_jobs @is_sysadmin, @job_owner
  9144.  
  9145.   INSERT INTO #job_execution_state
  9146.   SELECT xpr.job_id,
  9147.          xpr.last_run_date,
  9148.          xpr.last_run_time,
  9149.          xpr.job_state,
  9150.          sjs.step_id,
  9151.          sjs.step_name,
  9152.          xpr.current_retry_attempt,
  9153.          xpr.next_run_date,
  9154.          xpr.next_run_time,
  9155.          xpr.next_run_schedule_id
  9156.   FROM #xp_results                          xpr
  9157.        LEFT OUTER JOIN msdb.dbo.sysjobsteps sjs ON ((xpr.job_id = sjs.job_id) AND (xpr.current_step = sjs.step_id)),
  9158.        msdb.dbo.sysjobs_view                sjv
  9159.   WHERE (sjv.job_id = xpr.job_id)
  9160.  
  9161.   -- Step 3: Filter on everything but dates and job_type
  9162.   IF ((@subsystem        IS NULL) AND
  9163.       (@owner_login_name IS NULL) AND
  9164.       (@enabled          IS NULL) AND
  9165.       (@category_id      IS NULL) AND
  9166.       (@execution_status IS NULL) AND
  9167.       (@description      IS NULL) AND
  9168.       (@job_id           IS NULL))
  9169.   BEGIN
  9170.     -- Optimize for the frequently used case...
  9171.     INSERT INTO #filtered_jobs
  9172.     SELECT sjv.job_id,
  9173.            sjv.date_created,
  9174.            sjv.date_modified,
  9175.            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)
  9176.            CASE ISNULL(jes.execution_step_id, 0)
  9177.              WHEN 0 THEN NULL                   -- Will be NULL if the job is non-local or is not in #job_execution_state
  9178.              ELSE CONVERT(NVARCHAR, jes.execution_step_id) + N' (' + jes.execution_step_name + N')'
  9179.            END,
  9180.            jes.execution_retry_attempt,         -- Will be NULL if the job is non-local or is not in #job_execution_state
  9181.            0,  -- last_run_date placeholder    (we'll fix it up in step 3.3)
  9182.            0,  -- last_run_time placeholder    (we'll fix it up in step 3.3)
  9183.            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)
  9184.            jes.next_run_date,                   -- Will be NULL if the job is non-local or is not in #job_execution_state
  9185.            jes.next_run_time,                   -- Will be NULL if the job is non-local or is not in #job_execution_state
  9186.            jes.next_run_schedule_id,            -- Will be NULL if the job is non-local or is not in #job_execution_state
  9187.            0   -- type placeholder             (we'll fix it up in step 3.4)
  9188.     FROM msdb.dbo.sysjobs_view                sjv
  9189.          LEFT OUTER JOIN #job_execution_state jes ON (sjv.job_id = jes.job_id)
  9190.   END
  9191.   ELSE
  9192.   BEGIN
  9193.     INSERT INTO #filtered_jobs
  9194.     SELECT DISTINCT
  9195.            sjv.job_id,
  9196.            sjv.date_created,
  9197.            sjv.date_modified,
  9198.            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)
  9199.            CASE ISNULL(jes.execution_step_id, 0)
  9200.              WHEN 0 THEN NULL                   -- Will be NULL if the job is non-local or is not in #job_execution_state
  9201.              ELSE CONVERT(NVARCHAR, jes.execution_step_id) + N' (' + jes.execution_step_name + N')'
  9202.            END,
  9203.            jes.execution_retry_attempt,         -- Will be NULL if the job is non-local or is not in #job_execution_state
  9204.            0,  -- last_run_date placeholder    (we'll fix it up in step 3.3)
  9205.            0,  -- last_run_time placeholder    (we'll fix it up in step 3.3)
  9206.            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)
  9207.            jes.next_run_date,                   -- Will be NULL if the job is non-local or is not in #job_execution_state
  9208.            jes.next_run_time,                   -- Will be NULL if the job is non-local or is not in #job_execution_state
  9209.            jes.next_run_schedule_id,            -- Will be NULL if the job is non-local or is not in #job_execution_state
  9210.            0   -- type placeholder             (we'll fix it up in step 3.4)
  9211.     FROM msdb.dbo.sysjobs_view                sjv
  9212.          LEFT OUTER JOIN #job_execution_state jes ON (sjv.job_id = jes.job_id)
  9213.          LEFT OUTER JOIN msdb.dbo.sysjobsteps sjs ON (sjv.job_id = sjs.job_id)
  9214.     WHERE ((@subsystem        IS NULL) OR (sjs.subsystem            = @subsystem))
  9215.       AND ((@owner_login_name IS NULL) OR (sjv.owner_sid            = SUSER_SID(@owner_login_name)))
  9216.       AND ((@enabled          IS NULL) OR (sjv.enabled              = @enabled))
  9217.       AND ((@category_id      IS NULL) OR (sjv.category_id          = @category_id))
  9218.       AND ((@execution_status IS NULL) OR ((@execution_status > 0) AND (jes.execution_job_status = @execution_status))
  9219.                                        OR ((@execution_status = 0) AND (jes.execution_job_status <> 4) AND (jes.execution_job_status <> 5)))
  9220.       AND ((@description      IS NULL) OR (sjv.description       LIKE @description))
  9221.       AND ((@job_id           IS NULL) OR (sjv.job_id               = @job_id))
  9222.   END
  9223.  
  9224.   -- Step 3.1: Change the execution status of non-local jobs from 'Idle' to 'Unknown'
  9225.   UPDATE #filtered_jobs
  9226.   SET current_execution_status = NULL
  9227.   WHERE (current_execution_status = 4)
  9228.     AND (job_id IN (SELECT job_id
  9229.                     FROM msdb.dbo.sysjobservers
  9230.                     WHERE (server_id <> 0)))
  9231.  
  9232.   -- Step 3.2: Check that if the user asked to see idle jobs that we still have some.
  9233.   --           If we don't have any then the query should return no rows.
  9234.   IF (@execution_status = 4) AND
  9235.      (NOT EXISTS (SELECT *
  9236.                   FROM #filtered_jobs
  9237.                   WHERE (current_execution_status = 4)))
  9238.   BEGIN
  9239.     TRUNCATE TABLE #filtered_jobs
  9240.   END
  9241.  
  9242.   -- Step 3.3: Populate the last run date/time/outcome [this is a little tricky since for
  9243.   --           multi-server jobs there are multiple last run details in sysjobservers, so
  9244.   --           we simply choose the most recent].
  9245.   IF (EXISTS (SELECT *
  9246.               FROM msdb.dbo.systargetservers))
  9247.   BEGIN
  9248.     UPDATE #filtered_jobs
  9249.     SET last_run_date = sjs.last_run_date,
  9250.         last_run_time = sjs.last_run_time,
  9251.         last_run_outcome = sjs.last_run_outcome
  9252.     FROM #filtered_jobs         fj,
  9253.          msdb.dbo.sysjobservers sjs
  9254.     WHERE (CONVERT(FLOAT, sjs.last_run_date) * 1000000) + sjs.last_run_time =
  9255.            (SELECT MAX((CONVERT(FLOAT, last_run_date) * 1000000) + last_run_time)
  9256.             FROM msdb.dbo.sysjobservers
  9257.             WHERE (job_id = sjs.job_id))
  9258.       AND (fj.job_id = sjs.job_id)
  9259.   END
  9260.   ELSE
  9261.   BEGIN
  9262.     UPDATE #filtered_jobs
  9263.     SET last_run_date = sjs.last_run_date,
  9264.         last_run_time = sjs.last_run_time,
  9265.         last_run_outcome = sjs.last_run_outcome
  9266.     FROM #filtered_jobs         fj,
  9267.          msdb.dbo.sysjobservers sjs
  9268.     WHERE (fj.job_id = sjs.job_id)
  9269.   END
  9270.  
  9271.   -- Step 3.4 : Set the type of the job to local (1) or multi-server (2)
  9272.   --            NOTE: If the job has no jobservers then it wil have a type of 0 meaning
  9273.   --                  unknown.  This is marginally inconsistent with the behaviour of
  9274.   --                  defaulting the category of a new job to [Uncategorized (Local)], but
  9275.   --                  prevents incompletely defined jobs from erroneously showing up as valid
  9276.   --                  local jobs.
  9277.   UPDATE #filtered_jobs
  9278.   SET type = 1 -- LOCAL
  9279.   FROM #filtered_jobs         fj,
  9280.        msdb.dbo.sysjobservers sjs
  9281.   WHERE (fj.job_id = sjs.job_id)
  9282.     AND (server_id = 0)
  9283.   UPDATE #filtered_jobs
  9284.   SET type = 2 -- MULTI-SERVER
  9285.   FROM #filtered_jobs         fj,
  9286.        msdb.dbo.sysjobservers sjs
  9287.   WHERE (fj.job_id = sjs.job_id)
  9288.     AND (server_id <> 0)
  9289.  
  9290.   -- Step 4: Filter on job_type
  9291.   IF (@job_type IS NOT NULL)
  9292.   BEGIN
  9293.     IF (UPPER(@job_type) = 'LOCAL')
  9294.       DELETE FROM #filtered_jobs
  9295.       WHERE (type <> 1) -- IE. Delete all the non-local jobs
  9296.     IF (UPPER(@job_type) = 'MULTI-SERVER')
  9297.       DELETE FROM #filtered_jobs
  9298.       WHERE (type <> 2) -- IE. Delete all the non-multi-server jobs
  9299.   END
  9300.  
  9301.   -- Step 5: Filter on dates
  9302.   IF (@date_comparator IS NOT NULL)
  9303.   BEGIN
  9304.     IF (@date_created IS NOT NULL)
  9305.     BEGIN
  9306.       IF (@date_comparator = '=')
  9307.         DELETE FROM #filtered_jobs WHERE (date_created <> @date_created)
  9308.       IF (@date_comparator = '>')
  9309.         DELETE FROM #filtered_jobs WHERE (date_created <= @date_created)
  9310.       IF (@date_comparator = '<')
  9311.         DELETE FROM #filtered_jobs WHERE (date_created >= @date_created)
  9312.     END
  9313.     IF (@date_last_modified IS NOT NULL)
  9314.     BEGIN
  9315.       IF (@date_comparator = '=')
  9316.         DELETE FROM #filtered_jobs WHERE (date_last_modified <> @date_last_modified)
  9317.       IF (@date_comparator = '>')
  9318.         DELETE FROM #filtered_jobs WHERE (date_last_modified <= @date_last_modified)
  9319.       IF (@date_comparator = '<')
  9320.         DELETE FROM #filtered_jobs WHERE (date_last_modified >= @date_last_modified)
  9321.     END
  9322.   END
  9323.  
  9324.   -- Return the result set (NOTE: No filtering occurs here)
  9325.   SELECT sjv.job_id,
  9326.          sjv.originating_server,
  9327.          sjv.name,
  9328.          sjv.enabled,
  9329.          sjv.description,
  9330.          sjv.start_step_id,
  9331.          category = ISNULL(sc.name, FORMATMESSAGE(14205)),
  9332.          owner = SUSER_SNAME(sjv.owner_sid),
  9333.          sjv.notify_level_eventlog,
  9334.          sjv.notify_level_email,
  9335.          sjv.notify_level_netsend,
  9336.          sjv.notify_level_page,
  9337.          notify_email_operator   = ISNULL(so1.name, FORMATMESSAGE(14205)),
  9338.          notify_netsend_operator = ISNULL(so2.name, FORMATMESSAGE(14205)),
  9339.          notify_page_operator    = ISNULL(so3.name, FORMATMESSAGE(14205)),
  9340.          sjv.delete_level,
  9341.          sjv.date_created,
  9342.          sjv.date_modified,
  9343.          sjv.version_number,
  9344.          fj.last_run_date,
  9345.          fj.last_run_time,
  9346.          fj.last_run_outcome,
  9347.          next_run_date = ISNULL(fj.next_run_date, 0),                                 -- This column will be NULL if the job is non-local
  9348.          next_run_time = ISNULL(fj.next_run_time, 0),                                 -- This column will be NULL if the job is non-local
  9349.          next_run_schedule_id = ISNULL(fj.next_run_schedule_id, 0),                   -- This column will be NULL if the job is non-local
  9350.          current_execution_status = ISNULL(fj.current_execution_status, 0),           -- This column will be NULL if the job is non-local
  9351.          current_execution_step = ISNULL(fj.current_execution_step, N'0 ' + FORMATMESSAGE(14205)), -- This column will be NULL if the job is non-local
  9352.          current_retry_attempt = ISNULL(fj.current_retry_attempt, 0),                 -- This column will be NULL if the job is non-local
  9353.          has_step = (SELECT COUNT(*)
  9354.                      FROM msdb.dbo.sysjobsteps sjst
  9355.                      WHERE (sjst.job_id = sjv.job_id)),
  9356.          has_schedule = (SELECT COUNT(*)
  9357.                          FROM msdb.dbo.sysjobschedules sjsch
  9358.                          WHERE (sjsch.job_id = sjv.job_id)),
  9359.          has_target = (SELECT COUNT(*)
  9360.                        FROM msdb.dbo.sysjobservers sjs
  9361.                        WHERE (sjs.job_id = sjv.job_id)),
  9362.          type = fj.type
  9363.   FROM #filtered_jobs                         fj
  9364.        LEFT OUTER JOIN msdb.dbo.sysjobs_view  sjv ON (fj.job_id = sjv.job_id)
  9365.        LEFT OUTER JOIN msdb.dbo.sysoperators  so1 ON (sjv.notify_email_operator_id = so1.id)
  9366.        LEFT OUTER JOIN msdb.dbo.sysoperators  so2 ON (sjv.notify_netsend_operator_id = so2.id)
  9367.        LEFT OUTER JOIN msdb.dbo.sysoperators  so3 ON (sjv.notify_page_operator_id = so3.id)
  9368.        LEFT OUTER JOIN msdb.dbo.syscategories sc  ON (sjv.category_id = sc.category_id)
  9369.   ORDER BY sjv.job_id
  9370.  
  9371.   -- Clean up
  9372.   DROP TABLE #job_execution_state
  9373.   DROP TABLE #filtered_jobs
  9374.   DROP TABLE #xp_results
  9375. END
  9376. go
  9377.  
  9378. /**************************************************************/
  9379. /* SP_HELP_JOB                                                */
  9380. /**************************************************************/
  9381.  
  9382. PRINT ''
  9383. PRINT 'Creating procedure sp_help_job...'
  9384. go
  9385. IF (EXISTS (SELECT *
  9386.             FROM msdb.dbo.sysobjects
  9387.             WHERE (name = N'sp_help_job')
  9388.               AND (type = 'P')))
  9389.   DROP PROCEDURE sp_help_job
  9390. go
  9391. CREATE PROCEDURE sp_help_job
  9392.   -- Individual job parameters
  9393.   @job_id                     UNIQUEIDENTIFIER = NULL,  -- If provided should NOT also provide job_name
  9394.   @job_name                   sysname          = NULL,  -- If provided should NOT also provide job_id
  9395.   @job_aspect                 VARCHAR(9)       = NULL,  -- JOB, STEPS, SCEDULES, TARGETS or ALL
  9396.   -- Job set parameters
  9397.   @job_type                   VARCHAR(12)      = NULL,  -- LOCAL or MULTI-SERVER
  9398.   @owner_login_name           sysname          = NULL,
  9399.   @subsystem                  NVARCHAR(40)     = NULL,
  9400.   @category_name              sysname          = NULL,
  9401.   @enabled                    TINYINT          = NULL,
  9402.   @execution_status           INT              = NULL,  -- 1 = Executing, 2 = Waiting For Thread, 3 = Between Retries, 4 = Idle, 5 = Suspended, 6 = [obsolete], 7 = PerformingCompletionActions
  9403.   @date_comparator            CHAR(1)          = NULL,  -- >, < or =
  9404.   @date_created               DATETIME         = NULL,
  9405.   @date_last_modified         DATETIME         = NULL,
  9406.   @description                NVARCHAR(512)    = NULL   -- We do a LIKE on this so it can include wildcards
  9407. AS
  9408. BEGIN
  9409.   DECLARE @retval          INT
  9410.   DECLARE @category_id     INT
  9411.   DECLARE @job_id_as_char  VARCHAR(36)
  9412.   DECLARE @res_valid_range NVARCHAR(200)
  9413.  
  9414.   SET NOCOUNT ON
  9415.  
  9416.   -- Remove any leading/trailing spaces from parameters (except @owner_login_name)
  9417.   SELECT @job_name         = LTRIM(RTRIM(@job_name))
  9418.   SELECT @job_aspect       = LTRIM(RTRIM(@job_aspect))
  9419.   SELECT @job_type         = LTRIM(RTRIM(@job_type))
  9420.   SELECT @subsystem        = LTRIM(RTRIM(@subsystem))
  9421.   SELECT @category_name    = LTRIM(RTRIM(@category_name))
  9422.   SELECT @description      = LTRIM(RTRIM(@description))
  9423.  
  9424.   -- Turn [nullable] empty string parameters into NULLs
  9425.   IF (@job_name         = N'') SELECT @job_name = NULL
  9426.   IF (@job_aspect       = '')  SELECT @job_aspect = NULL
  9427.   IF (@job_type         = '')  SELECT @job_type = NULL
  9428.   IF (@owner_login_name = N'') SELECT @owner_login_name = NULL
  9429.   IF (@subsystem        = N'') SELECT @subsystem = NULL
  9430.   IF (@category_name    = N'') SELECT @category_name = NULL
  9431.   IF (@description      = N'') SELECT @description = NULL
  9432.  
  9433.   IF ((@job_id IS NOT NULL) OR (@job_name IS NOT NULL))
  9434.   BEGIN
  9435.     EXECUTE @retval = sp_verify_job_identifiers '@job_name',
  9436.                                                 '@job_id',
  9437.                                                  @job_name OUTPUT,
  9438.                                                  @job_id   OUTPUT
  9439.     IF (@retval <> 0)
  9440.       RETURN(1) -- Failure
  9441.   END
  9442.  
  9443.   SELECT @job_id_as_char = CONVERT(VARCHAR(36), @job_id)
  9444.  
  9445.   -- If the user provided a job name or id but no aspect, default to ALL
  9446.   IF ((@job_name IS NOT NULL) OR (@job_id IS NOT NULL)) AND (@job_aspect IS NULL)
  9447.     SELECT @job_aspect = 'ALL'
  9448.  
  9449.   -- The caller must supply EITHER job name (or job id) and aspect OR one-or-more of the set
  9450.   -- parameters OR no parameters at all
  9451.   IF (((@job_name IS NOT NULL) OR (@job_id IS NOT NULL))
  9452.       AND ((@job_aspect          IS NULL)     OR
  9453.            (@job_type            IS NOT NULL) OR
  9454.            (@owner_login_name    IS NOT NULL) OR
  9455.            (@subsystem           IS NOT NULL) OR
  9456.            (@category_name       IS NOT NULL) OR
  9457.            (@enabled             IS NOT NULL) OR
  9458.            (@date_comparator     IS NOT NULL) OR
  9459.            (@date_created        IS NOT NULL) OR
  9460.            (@date_last_modified  IS NOT NULL)))
  9461.      OR
  9462.      ((@job_name IS NULL) AND (@job_id IS NULL) AND (@job_aspect IS NOT NULL))
  9463.   BEGIN
  9464.     RAISERROR(14280, -1, -1)
  9465.     RETURN(1) -- Failure
  9466.   END
  9467.  
  9468.   IF (@job_id IS NOT NULL)
  9469.   BEGIN
  9470.     -- Individual job...
  9471.  
  9472.     -- Check job aspect
  9473.     SELECT @job_aspect = UPPER(@job_aspect)
  9474.     IF (@job_aspect NOT IN ('JOB', 'STEPS', 'SCHEDULES', 'TARGETS', 'ALL'))
  9475.     BEGIN
  9476.       RAISERROR(14266, -1, -1, '@job_aspect', 'JOB, STEPS, SCHEDULES, TARGETS, ALL')
  9477.       RETURN(1) -- Failure
  9478.     END
  9479.  
  9480.     -- Generate results set...
  9481.  
  9482.     IF (@job_aspect IN ('JOB', 'ALL'))
  9483.     BEGIN
  9484.       IF (@job_aspect = 'ALL')
  9485.       BEGIN
  9486.         RAISERROR(14213, 0, 1)
  9487.         PRINT REPLICATE('=', DATALENGTH(FORMATMESSAGE(14213)) / 2)
  9488.       END
  9489.       EXECUTE sp_get_composite_job_info @job_id,
  9490.                                         @job_type,
  9491.                                         @owner_login_name,
  9492.                                         @subsystem,
  9493.                                         @category_id,
  9494.                                         @enabled,
  9495.                                         @execution_status,
  9496.                                         @date_comparator,
  9497.                                         @date_created,
  9498.                                         @date_last_modified,
  9499.                                         @description
  9500.     END
  9501.  
  9502.     IF (@job_aspect IN ('STEPS', 'ALL'))
  9503.     BEGIN
  9504.       IF (@job_aspect = 'ALL')
  9505.       BEGIN
  9506.         PRINT ''
  9507.         RAISERROR(14214, 0, 1)
  9508.         PRINT REPLICATE('=', DATALENGTH(FORMATMESSAGE(14214)) / 2)
  9509.       END
  9510.       EXECUTE ('EXECUTE sp_help_jobstep @job_id = ''' + @job_id_as_char + ''', @suffix = 1')
  9511.     END
  9512.  
  9513.     IF (@job_aspect IN ('SCHEDULES', 'ALL'))
  9514.     BEGIN
  9515.       IF (@job_aspect = 'ALL')
  9516.       BEGIN
  9517.         PRINT ''
  9518.         RAISERROR(14215, 0, 1)
  9519.         PRINT REPLICATE('=', DATALENGTH(FORMATMESSAGE(14215)) / 2)
  9520.       END
  9521.       EXECUTE ('EXECUTE sp_help_jobschedule @job_id = ''' + @job_id_as_char + '''')
  9522.     END
  9523.  
  9524.     IF (@job_aspect IN ('TARGETS', 'ALL'))
  9525.     BEGIN
  9526.       IF (@job_aspect = 'ALL')
  9527.       BEGIN
  9528.         PRINT ''
  9529.         RAISERROR(14216, 0, 1)
  9530.         PRINT REPLICATE('=', DATALENGTH(FORMATMESSAGE(14216)) / 2)
  9531.       END
  9532.       EXECUTE ('EXECUTE sp_help_jobserver @job_id = ''' + @job_id_as_char + ''', @show_last_run_details = 1')
  9533.     END
  9534.   END
  9535.   ELSE
  9536.   BEGIN
  9537.     -- Set of jobs...
  9538.  
  9539.     -- Check job type
  9540.     IF (@job_type IS NOT NULL)
  9541.     BEGIN
  9542.       SELECT @job_type = UPPER(@job_type)
  9543.       IF (@job_type NOT IN ('LOCAL', 'MULTI-SERVER'))
  9544.       BEGIN
  9545.         RAISERROR(14266, -1, -1, '@job_type', 'LOCAL, MULTI-SERVER')
  9546.         RETURN(1) -- Failure
  9547.       END
  9548.     END
  9549.  
  9550.     -- Check owner
  9551.     IF (@owner_login_name IS NOT NULL)
  9552.     BEGIN
  9553.       IF (SUSER_SID(@owner_login_name) IS NULL)
  9554.       BEGIN
  9555.         RAISERROR(14262, -1, -1, '@owner_login_name', @owner_login_name)
  9556.         RETURN(1) -- Failure
  9557.       END
  9558.     END
  9559.  
  9560.     -- Check subsystem
  9561.     IF (@subsystem IS NOT NULL)
  9562.     BEGIN
  9563.       EXECUTE @retval = sp_verify_subsystem @subsystem
  9564.       IF (@retval <> 0)
  9565.         RETURN(1) -- Failure
  9566.     END
  9567.  
  9568.     -- Check job category
  9569.     IF (@category_name IS NOT NULL)
  9570.     BEGIN
  9571.       SELECT @category_id = category_id
  9572.       FROM msdb.dbo.syscategories
  9573.       WHERE (category_class = 1) -- Job
  9574.         AND (name = @category_name)
  9575.       IF (@category_id IS NULL)
  9576.       BEGIN
  9577.         RAISERROR(14262, -1, -1, '@category_name', @category_name)
  9578.         RETURN(1) -- Failure
  9579.       END
  9580.     END
  9581.  
  9582.     -- Check enabled state
  9583.     IF (@enabled IS NOT NULL) AND (@enabled NOT IN (0, 1))
  9584.     BEGIN
  9585.       RAISERROR(14266, -1, -1, '@enabled', '0, 1')
  9586.       RETURN(1) -- Failure
  9587.     END
  9588.  
  9589.     -- Check current execution status
  9590.     IF (@execution_status IS NOT NULL)
  9591.     BEGIN
  9592.       IF (@execution_status NOT IN (0, 1, 2, 3, 4, 5, 7))
  9593.       BEGIN
  9594.         SELECT @res_valid_range = FORMATMESSAGE(14204)
  9595.         RAISERROR(14266, -1, -1, '@execution_status', @res_valid_range)
  9596.         RETURN(1) -- Failure
  9597.       END
  9598.     END
  9599.  
  9600.     -- If a date comparator is supplied, we must have either a date-created or date-last-modified
  9601.     IF ((@date_comparator IS NOT NULL) AND (@date_created IS NOT NULL) AND (@date_last_modified IS NOT NULL)) OR
  9602.        ((@date_comparator IS NULL)     AND ((@date_created IS NOT NULL) OR (@date_last_modified IS NOT NULL)))
  9603.     BEGIN
  9604.       RAISERROR(14282, -1, -1)
  9605.       RETURN(1) -- Failure
  9606.     END
  9607.  
  9608.     -- Check dates / comparator
  9609.     IF (@date_comparator IS NOT NULL) AND (@date_comparator NOT IN ('=', '<', '>'))
  9610.     BEGIN
  9611.       RAISERROR(14266, -1, -1, '@date_comparator', '=, >, <')
  9612.       RETURN(1) -- Failure
  9613.     END
  9614.     IF (@date_created IS NOT NULL) AND
  9615.        ((@date_created < '1 Jan 1990 12:00:00am') OR (@date_created > '31 Dec 9999 11:59:59pm'))
  9616.     BEGIN
  9617.       RAISERROR(14266, -1, -1, '@date_created', '1/1/1990 12:00am .. 12/31/9999 11:59pm')
  9618.       RETURN(1) -- Failure
  9619.     END
  9620.     IF (@date_last_modified IS NOT NULL) AND
  9621.        ((@date_last_modified < '1 Jan 1990 12:00am') OR (@date_last_modified > 'Dec 31 9999 11:59:59pm'))
  9622.     BEGIN
  9623.       RAISERROR(14266, -1, -1, '@date_last_modified', '1/1/1990 12:00am .. 12/31/9999 11:59pm')
  9624.       RETURN(1) -- Failure
  9625.     END
  9626.  
  9627.     -- Generate results set...
  9628.     EXECUTE sp_get_composite_job_info @job_id,
  9629.                                       @job_type,
  9630.                                       @owner_login_name,
  9631.                                       @subsystem,
  9632.                                       @category_id,
  9633.                                       @enabled,
  9634.                                       @execution_status,
  9635.                                       @date_comparator,
  9636.                                       @date_created,
  9637.                                       @date_last_modified,
  9638.                                       @description
  9639.   END
  9640.  
  9641.   RETURN(0) -- Success
  9642. END
  9643. go
  9644.  
  9645. DUMP TRANSACTION msdb WITH NO_LOG
  9646. go
  9647. CHECKPOINT
  9648. go
  9649.  
  9650. /**************************************************************/
  9651. /* SP_MANAGE_JOBS_BY_LOGIN                                    */
  9652. /**************************************************************/
  9653.  
  9654. PRINT ''
  9655. PRINT 'Creating procedure sp_manage_jobs_by_login...'
  9656. go
  9657. IF (EXISTS (SELECT *
  9658.             FROM msdb.dbo.sysobjects
  9659.             WHERE (name = N'sp_manage_jobs_by_login')
  9660.               AND (type = 'P')))
  9661.   DROP PROCEDURE sp_manage_jobs_by_login
  9662. go
  9663. CREATE PROCEDURE sp_manage_jobs_by_login
  9664.   @action                   VARCHAR(10), -- DELETE or REASSIGN
  9665.   @current_owner_login_name sysname,
  9666.   @new_owner_login_name     sysname = NULL
  9667. AS
  9668. BEGIN
  9669.   DECLARE @current_sid   VARBINARY(85)
  9670.   DECLARE @new_sid       VARBINARY(85)
  9671.   DECLARE @job_id        UNIQUEIDENTIFIER
  9672.   DECLARE @rows_affected INT
  9673.   DECLARE @is_sysadmin   INT
  9674.  
  9675.   SET NOCOUNT ON
  9676.  
  9677.   -- Remove any leading/trailing spaces from parameters
  9678.   SELECT @action                   = LTRIM(RTRIM(@action))
  9679.   SELECT @current_owner_login_name = LTRIM(RTRIM(@current_owner_login_name))
  9680.   SELECT @new_owner_login_name     = LTRIM(RTRIM(@new_owner_login_name))
  9681.  
  9682.   -- Turn [nullable] empty string parameters into NULLs
  9683.   IF (@new_owner_login_name = N'') SELECT @new_owner_login_name = NULL
  9684.  
  9685.   -- Only a sysadmin can do this
  9686.   IF (ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) <> 1)
  9687.   BEGIN
  9688.     RAISERROR(15003, 16, 1, N'sysadmin')
  9689.     RETURN(1) -- Failure
  9690.   END
  9691.  
  9692.   -- Check action
  9693.   IF (@action NOT IN ('DELETE', 'REASSIGN'))
  9694.   BEGIN
  9695.     RAISERROR(14266, -1, -1, '@action', 'DELETE, REASSIGN')
  9696.     RETURN(1) -- Failure
  9697.   END
  9698.  
  9699.   -- Check parameter combinations
  9700.   IF ((@action = 'DELETE') AND (@new_owner_login_name IS NOT NULL))
  9701.     RAISERROR(14281, 0, 1)
  9702.  
  9703.   IF ((@action = 'REASSIGN') AND (@new_owner_login_name IS NULL))
  9704.   BEGIN
  9705.     RAISERROR(14237, -1, -1)
  9706.     RETURN(1) -- Failure
  9707.   END
  9708.  
  9709.   -- Check current login
  9710.   SELECT @current_sid = SUSER_SID(@current_owner_login_name)
  9711.   IF (@current_sid IS NULL)
  9712.   BEGIN
  9713.     RAISERROR(14262, -1, -1, '@current_owner_login_name', @current_owner_login_name)
  9714.     RETURN(1) -- Failure
  9715.   END
  9716.  
  9717.   -- Check new login (if supplied)
  9718.   IF (@new_owner_login_name IS NOT NULL)
  9719.   BEGIN
  9720.     SELECT @new_sid = SUSER_SID(@new_owner_login_name)
  9721.     IF (@new_sid IS NULL)
  9722.     BEGIN
  9723.       RAISERROR(14262, -1, -1, '@new_owner_login_name', @new_owner_login_name)
  9724.       RETURN(1) -- Failure
  9725.     END
  9726.   END
  9727.  
  9728.   IF (@action = 'DELETE')
  9729.   BEGIN
  9730.     DECLARE jobs_to_delete CURSOR LOCAL
  9731.     FOR
  9732.     SELECT job_id
  9733.     FROM msdb.dbo.sysjobs
  9734.     WHERE (owner_sid = @current_sid)
  9735.  
  9736.     OPEN jobs_to_delete
  9737.     FETCH NEXT FROM jobs_to_delete INTO @job_id
  9738.  
  9739.     SELECT @rows_affected = 0
  9740.     WHILE (@@fetch_status = 0)
  9741.     BEGIN
  9742.       EXECUTE sp_delete_job @job_id = @job_id
  9743.       SELECT @rows_affected = @rows_affected + 1
  9744.       FETCH NEXT FROM jobs_to_delete INTO @job_id
  9745.     END
  9746.     DEALLOCATE jobs_to_delete
  9747.     RAISERROR(14238, 0, 1, @rows_affected)
  9748.   END
  9749.   ELSE
  9750.   IF (@action = 'REASSIGN')
  9751.   BEGIN
  9752.     -- Check if the current owner owns any multi-server jobs.
  9753.     -- If they do, then the new owner must be member of the sysadmin role.
  9754.     IF (EXISTS (SELECT *
  9755.                 FROM msdb.dbo.sysjobs       sj,
  9756.                      msdb.dbo.sysjobservers sjs
  9757.                 WHERE (sj.job_id = sjs.job_id)
  9758.                   AND (sj.owner_sid = @current_sid)
  9759.                   AND (sjs.server_id <> 0)))
  9760.     BEGIN
  9761.       SELECT @is_sysadmin = 0
  9762.       EXECUTE msdb.dbo.sp_sqlagent_has_server_access @login_name = @new_owner_login_name, @is_sysadmin_member = @is_sysadmin OUTPUT
  9763.       IF (@is_sysadmin = 0)
  9764.       BEGIN
  9765.         RAISERROR(14543, -1, -1, @current_owner_login_name, N'sysadmin')
  9766.         RETURN(1) -- Failure
  9767.       END
  9768.     END
  9769.  
  9770.     UPDATE msdb.dbo.sysjobs
  9771.     SET owner_sid = @new_sid
  9772.     WHERE (owner_sid = @current_sid)
  9773.     RAISERROR(14239, 0, 1, @@rowcount, @new_owner_login_name)
  9774.   END
  9775.  
  9776.   RETURN(0) -- Success
  9777. END
  9778. go
  9779.  
  9780. /**************************************************************/
  9781. /* SP_APPLY_JOB_TO_TARGETS                                    */
  9782. /**************************************************************/
  9783.  
  9784. PRINT ''
  9785. PRINT 'Creating procedure sp_apply_job_to_targets...'
  9786. go
  9787. IF (EXISTS (SELECT *
  9788.             FROM msdb.dbo.sysobjects
  9789.             WHERE (name = N'sp_apply_job_to_targets')
  9790.               AND (type = 'P')))
  9791.   DROP PROCEDURE sp_apply_job_to_targets
  9792. go
  9793. CREATE PROCEDURE sp_apply_job_to_targets
  9794.   @job_id               UNIQUEIDENTIFIER = NULL,   -- Must provide either this or job_name
  9795.   @job_name             sysname          = NULL,   -- Must provide either this or job_id
  9796.   @target_server_groups NVARCHAR(2048)   = NULL,   -- A comma-separated list of target server groups
  9797.   @target_servers       NVARCHAR(2048)   = NULL,   -- An comma-separated list of target servers
  9798.   @operation            VARCHAR(7)       = 'APPLY' -- Or 'REMOVE'
  9799. AS
  9800. BEGIN
  9801.   DECLARE @retval        INT
  9802.   DECLARE @rows_affected INT
  9803.   DECLARE @server_name   NVARCHAR(30)
  9804.   DECLARE @groups        NVARCHAR(2048)
  9805.   DECLARE @group         sysname
  9806.   DECLARE @servers       NVARCHAR(2048)
  9807.   DECLARE @server        NVARCHAR(30)
  9808.   DECLARE @pos_of_comma  INT
  9809.  
  9810.   SET NOCOUNT ON
  9811.  
  9812.   -- Only a sysadmin can do this
  9813.   IF (ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) <> 1)
  9814.   BEGIN
  9815.     RAISERROR(15003, 16, 1, N'sysadmin')
  9816.     RETURN(1) -- Failure
  9817.   END
  9818.  
  9819.   -- Remove any leading/trailing spaces from parameters
  9820.   SELECT @target_server_groups = LTRIM(RTRIM(@target_server_groups))
  9821.   SELECT @target_servers       = LTRIM(RTRIM(@target_servers))
  9822.   SELECT @operation            = LTRIM(RTRIM(@operation))
  9823.  
  9824.   -- Turn [nullable] empty string parameters into NULLs
  9825.   IF (@target_server_groups = NULL) SELECT @target_server_groups = NULL
  9826.   IF (@target_servers       = NULL) SELECT @target_servers = NULL
  9827.   IF (@operation            = NULL) SELECT @operation = NULL
  9828.  
  9829.   EXECUTE @retval = sp_verify_job_identifiers '@job_name',
  9830.                                               '@job_id',
  9831.                                                @job_name OUTPUT,
  9832.                                                @job_id   OUTPUT
  9833.   IF (@retval <> 0)
  9834.     RETURN(1) -- Failure
  9835.  
  9836.   -- Check operation type
  9837.   IF ((@operation <> 'APPLY') AND (@operation <> 'REMOVE'))
  9838.   BEGIN
  9839.     RAISERROR(14266, -1, -1, '@operation', 'APPLY, REMOVE')
  9840.     RETURN(1) -- Failure
  9841.   END
  9842.  
  9843.   CREATE TABLE #temp_groups (group_name sysname COLLATE database_default NOT NULL)
  9844.   CREATE TABLE #temp_server_name (server_name NVARCHAR(30) COLLATE database_default NOT NULL)
  9845.  
  9846.   -- Check that we have a target server group list and/or a target server list
  9847.   IF ((@target_server_groups IS NULL) AND (@target_servers IS NULL))
  9848.   BEGIN
  9849.     RAISERROR(14283, -1, -1)
  9850.     RETURN(1) -- Failure
  9851.   END
  9852.  
  9853.   -- Parse the Target Server comma-separated list (if supplied)
  9854.   IF (@target_servers IS NOT NULL)
  9855.   BEGIN
  9856.     SELECT @servers = @target_servers
  9857.     SELECT @pos_of_comma = CHARINDEX(N',', @servers)
  9858.     WHILE (@pos_of_comma <> 0)
  9859.     BEGIN
  9860.       SELECT @server = SUBSTRING(@servers, 1, @pos_of_comma - 1)
  9861.       INSERT INTO #temp_server_name (server_name) VALUES (LTRIM(RTRIM(@server)))
  9862.       SELECT @servers = RIGHT(@servers, (DATALENGTH(@servers) / 2) - @pos_of_comma)
  9863.       SELECT @pos_of_comma = CHARINDEX(N',', @servers)
  9864.     END
  9865.     INSERT INTO #temp_server_name (server_name) VALUES (LTRIM(RTRIM(@servers)))
  9866.   END
  9867.  
  9868.   -- Parse the Target Server Groups comma-separated list
  9869.   IF (@target_server_groups IS NOT NULL)
  9870.   BEGIN
  9871.     SELECT @groups = @target_server_groups
  9872.     SELECT @pos_of_comma = CHARINDEX(N',', @groups)
  9873.     WHILE (@pos_of_comma <> 0)
  9874.     BEGIN
  9875.       SELECT @group = SUBSTRING(@groups, 1, @pos_of_comma - 1)
  9876.       INSERT INTO #temp_groups (group_name) VALUES (LTRIM(RTRIM(@group)))
  9877.       SELECT @groups = RIGHT(@groups, (DATALENGTH(@groups) / 2) - @pos_of_comma)
  9878.       SELECT @pos_of_comma = CHARINDEX(N',', @groups)
  9879.     END
  9880.     INSERT INTO #temp_groups (group_name) VALUES (LTRIM(RTRIM(@groups)))
  9881.   END
  9882.  
  9883.   -- Check server groups
  9884.   SET ROWCOUNT 1 -- We do this so that we catch the FIRST invalid group
  9885.   SELECT @group = NULL
  9886.   SELECT @group = group_name
  9887.   FROM #temp_groups
  9888.   WHERE group_name NOT IN (SELECT name
  9889.                            FROM msdb.dbo.systargetservergroups)
  9890.   IF (@group IS NOT NULL)
  9891.   BEGIN
  9892.     RAISERROR(14262, -1, -1, '@target_server_groups', @group)
  9893.     RETURN(1) -- Failure
  9894.   END
  9895.   SET ROWCOUNT 0
  9896.  
  9897.   -- Find the distinct list of servers being targeted
  9898.   INSERT INTO #temp_server_name (server_name)
  9899.   SELECT DISTINCT sts.server_name
  9900.   FROM msdb.dbo.systargetservergroups       stsg,
  9901.        msdb.dbo.systargetservergroupmembers stsgm,
  9902.        msdb.dbo.systargetservers            sts
  9903.   WHERE (stsg.name IN (SELECT group_name FROM #temp_groups))
  9904.     AND (stsg.servergroup_id = stsgm.servergroup_id)
  9905.     AND (stsgm.server_id = sts.server_id)
  9906.     AND (sts.server_name NOT IN (SELECT server_name
  9907.                                  FROM #temp_server_name))
  9908.  
  9909.   IF (@operation = 'APPLY')
  9910.   BEGIN
  9911.     -- Remove those servers to which the job has already been applied
  9912.     DELETE FROM #temp_server_name
  9913.     WHERE server_name IN (SELECT sts.server_name
  9914.                           FROM msdb.dbo.sysjobservers    sjs,
  9915.                                msdb.dbo.systargetservers sts
  9916.                           WHERE (sjs.job_id = @job_id)
  9917.                             AND (sjs.server_id = sts.server_id))
  9918.   END
  9919.  
  9920.   IF (@operation = 'REMOVE')
  9921.   BEGIN
  9922.     -- Remove those servers to which the job is not currently applied
  9923.     DELETE FROM #temp_server_name
  9924.     WHERE server_name NOT IN (SELECT sts.server_name
  9925.                               FROM msdb.dbo.sysjobservers    sjs,
  9926.                                    msdb.dbo.systargetservers sts
  9927.                               WHERE (sjs.job_id = @job_id)
  9928.                                 AND (sjs.server_id = sts.server_id))
  9929.   END
  9930.  
  9931.   SELECT @rows_affected = COUNT(*)
  9932.   FROM #temp_server_name
  9933.  
  9934.   SET ROWCOUNT 1
  9935.   WHILE (EXISTS (SELECT *
  9936.                  FROM #temp_server_name))
  9937.   BEGIN
  9938.     SELECT @server_name = server_name
  9939.     FROM #temp_server_name
  9940.     IF (@operation = 'APPLY')
  9941.       EXECUTE sp_add_jobserver @job_id = @job_id, @server_name = @server_name
  9942.     ELSE
  9943.     IF (@operation = 'REMOVE')
  9944.       EXECUTE sp_delete_jobserver @job_id = @job_id, @server_name = @server_name
  9945.     DELETE FROM #temp_server_name
  9946.     WHERE (server_name = @server_name)
  9947.   END
  9948.   SET ROWCOUNT 0
  9949.  
  9950.   IF (@operation = 'APPLY')
  9951.     RAISERROR(14240, 0, 1, @rows_affected)
  9952.   IF (@operation = 'REMOVE')
  9953.     RAISERROR(14241, 0, 1, @rows_affected)
  9954.  
  9955.   RETURN(0) -- Success
  9956. END
  9957. go
  9958.  
  9959. /**************************************************************/
  9960. /* SP_REMOVE_JOB_FROM_TARGETS                                 */
  9961. /**************************************************************/
  9962.  
  9963. PRINT ''
  9964. PRINT 'Creating procedure sp_remove_job_from_targets...'
  9965. go
  9966. IF (EXISTS (SELECT *
  9967.             FROM msdb.dbo.sysobjects
  9968.             WHERE (name = N'sp_remove_job_from_targets')
  9969.               AND (type = 'P')))
  9970.   DROP PROCEDURE sp_remove_job_from_targets
  9971. go
  9972. CREATE PROCEDURE sp_remove_job_from_targets
  9973.   @job_id               UNIQUEIDENTIFIER = NULL,   -- Must provide either this or job_name
  9974.   @job_name             sysname          = NULL,   -- Must provide either this or job_id
  9975.   @target_server_groups NVARCHAR(1024)   = NULL,   -- A comma-separated list of target server groups
  9976.   @target_servers       NVARCHAR(1024)   = NULL    -- A comma-separated list of target servers
  9977. AS
  9978. BEGIN
  9979.   DECLARE @retval INT
  9980.  
  9981.   SET NOCOUNT ON
  9982.  
  9983.   EXECUTE @retval = sp_apply_job_to_targets @job_id,
  9984.                                             @job_name,
  9985.                                             @target_server_groups,
  9986.                                             @target_servers,
  9987.                                            'REMOVE'
  9988.   RETURN(@retval) -- 0 means success
  9989. END
  9990. go
  9991.  
  9992. /**************************************************************/
  9993. /* SP_GET_JOB_ALERTS                                          */
  9994. /**************************************************************/
  9995.  
  9996. PRINT ''
  9997. PRINT 'Creating procedure sp_get_job_alerts...'
  9998. go
  9999. IF (EXISTS (SELECT *
  10000.             FROM msdb.dbo.sysobjects
  10001.             WHERE (name = N'sp_get_job_alerts')
  10002.               AND (type = 'P')))
  10003.   DROP PROCEDURE sp_get_job_alerts
  10004. go
  10005. CREATE PROCEDURE sp_get_job_alerts
  10006.   @job_id   UNIQUEIDENTIFIER = NULL,
  10007.   @job_name sysname          = NULL
  10008. AS
  10009. BEGIN
  10010.   DECLARE @retval INT
  10011.  
  10012.   EXECUTE @retval = sp_verify_job_identifiers '@job_name',
  10013.                                               '@job_id',
  10014.                                                @job_name OUTPUT,
  10015.                                                @job_id   OUTPUT
  10016.   IF (@retval <> 0)
  10017.     RETURN(1) -- Failure
  10018.  
  10019.   SELECT id,
  10020.          name,
  10021.          enabled,
  10022.          type = CASE ISNULL(performance_condition, N'!')
  10023.                   WHEN N'!' THEN
  10024.                     CASE event_source
  10025.                       WHEN N'MSSQLSERVER' THEN 1 -- SQL Server event alert
  10026.                       ELSE 3                     -- Non SQL Server event alert
  10027.                     END
  10028.                   ELSE 2                         -- SQL Server performance condition alert
  10029.                 END
  10030.   FROM msdb.dbo.sysalerts
  10031.   WHERE (job_id = @job_id)
  10032.  
  10033.   RETURN(0) -- Success
  10034. END
  10035. go
  10036.  
  10037. /**************************************************************/
  10038. /*                                                            */
  10039. /*   S  U  P  P  O  R  T     P  R  O  C  E  D  U  R  E  S     */
  10040. /*                                                            */
  10041. /**************************************************************/
  10042.  
  10043. /**************************************************************/
  10044. /* SP_CONVERT_JOBID_TO_CHAR [used by SEM only]                */
  10045. /**************************************************************/
  10046.  
  10047. PRINT ''
  10048. PRINT 'Creating procedure sp_convert_jobid_to_char...'
  10049. go
  10050. IF (EXISTS (SELECT *
  10051.             FROM msdb.dbo.sysobjects
  10052.             WHERE (name = N'sp_convert_jobid_to_char')
  10053.               AND (type = 'P')))
  10054.   DROP PROCEDURE sp_convert_jobid_to_char
  10055. go
  10056. CREATE PROCEDURE sp_convert_jobid_to_char
  10057.   @job_id         UNIQUEIDENTIFIER,
  10058.   @job_id_as_char NVARCHAR(34) OUTPUT -- 34 because of the leading '0x'
  10059. AS
  10060. BEGIN
  10061.   DECLARE @job_id_as_binary BINARY(16)
  10062.   DECLARE @temp             NCHAR(8)
  10063.   DECLARE @counter          INT
  10064.   DECLARE @byte_value       INT
  10065.   DECLARE @high_word        INT
  10066.   DECLARE @low_word         INT
  10067.   DECLARE @high_high_nybble INT
  10068.   DECLARE @high_low_nybble  INT
  10069.   DECLARE @low_high_nybble  INT
  10070.   DECLARE @low_low_nybble   INT
  10071.  
  10072.   SET NOCOUNT ON
  10073.  
  10074.   SELECT @job_id_as_binary = CONVERT(BINARY(16), @job_id)
  10075.   SELECT @temp = CONVERT(NCHAR(8), @job_id_as_binary)
  10076.  
  10077.   SELECT @job_id_as_char = N''
  10078.   SELECT @counter = 1
  10079.  
  10080.   WHILE (@counter <= (DATALENGTH(@temp) / 2))
  10081.   BEGIN
  10082.     SELECT @byte_value       = CONVERT(INT, CONVERT(BINARY(2), SUBSTRING(@temp, @counter, 1)))
  10083.     SELECT @high_word        = (@byte_value & 0xff00) / 0x100
  10084.     SELECT @low_word         = (@byte_value & 0x00ff)
  10085.     SELECT @high_high_nybble = (@high_word & 0xff) / 16
  10086.     SELECT @high_low_nybble  = (@high_word & 0xff) % 16
  10087.     SELECT @low_high_nybble  = (@low_word & 0xff) / 16
  10088.     SELECT @low_low_nybble   = (@low_word & 0xff) % 16
  10089.  
  10090.     IF (@high_high_nybble < 10)
  10091.       SELECT @job_id_as_char = @job_id_as_char + NCHAR(ASCII('0') + @high_high_nybble)
  10092.     ELSE
  10093.       SELECT @job_id_as_char = @job_id_as_char + NCHAR(ASCII('A') + (@high_high_nybble - 10))
  10094.  
  10095.     IF (@high_low_nybble < 10)
  10096.       SELECT @job_id_as_char = @job_id_as_char + NCHAR(ASCII('0') + @high_low_nybble)
  10097.     ELSE
  10098.       SELECT @job_id_as_char = @job_id_as_char + NCHAR(ASCII('A') + (@high_low_nybble - 10))
  10099.  
  10100.     IF (@low_high_nybble < 10)
  10101.       SELECT @job_id_as_char = @job_id_as_char + NCHAR(ASCII('0') + @low_high_nybble)
  10102.     ELSE
  10103.       SELECT @job_id_as_char = @job_id_as_char + NCHAR(ASCII('A') + (@low_high_nybble - 10))
  10104.  
  10105.     IF (@low_low_nybble < 10)
  10106.       SELECT @job_id_as_char = @job_id_as_char + NCHAR(ASCII('0') + @low_low_nybble)
  10107.     ELSE
  10108.       SELECT @job_id_as_char = @job_id_as_char + NCHAR(ASCII('A') + (@low_low_nybble - 10))
  10109.  
  10110.     SELECT @counter = @counter + 1
  10111.   END
  10112.  
  10113.   SELECT @job_id_as_char = N'0x' + LOWER(@job_id_as_char)
  10114. END
  10115. go
  10116.  
  10117. /**************************************************************/
  10118. /* SP_START_JOB                                               */
  10119. /**************************************************************/
  10120.  
  10121. PRINT ''
  10122. PRINT 'Creating procedure sp_start_job...'
  10123. go
  10124. IF (EXISTS (SELECT *
  10125.             FROM msdb.dbo.sysobjects
  10126.             WHERE (name = N'sp_start_job')
  10127.               AND (type = 'P')))
  10128.   DROP PROCEDURE sp_start_job
  10129. go
  10130. CREATE PROCEDURE sp_start_job
  10131.   @job_name    sysname          = NULL,
  10132.   @job_id      UNIQUEIDENTIFIER = NULL,
  10133.   @error_flag  INT              = 1,    -- Set to 0 to suppress the error from sp_sqlagent_notify if SQLServerAgent is not running
  10134.   @server_name NVARCHAR(30)     = NULL, -- The specific target server to start the [multi-server] job on
  10135.   @step_name   sysname          = NULL, -- The name of the job step to start execution with [for use with a local job only]
  10136.   @output_flag INT              = 1     -- Set to 0 to suppress the success message
  10137. AS
  10138. BEGIN
  10139.   DECLARE @job_id_as_char VARCHAR(36)
  10140.   DECLARE @retval         INT
  10141.   DECLARE @step_id        INT
  10142.  
  10143.   SET NOCOUNT ON
  10144.  
  10145.   -- Remove any leading/trailing spaces from parameters
  10146.   SELECT @job_name    = LTRIM(RTRIM(@job_name))
  10147.   SELECT @server_name = LTRIM(RTRIM(@server_name))
  10148.   SELECT @step_name   = LTRIM(RTRIM(@step_name))
  10149.  
  10150.   -- Turn [nullable] empty string parameters into NULLs
  10151.   IF (@job_name = N'')    SELECT @job_name = NULL
  10152.   IF (@server_name = N'') SELECT @server_name = NULL
  10153.   IF (@step_name = N'')   SELECT @step_name = NULL
  10154.  
  10155.   EXECUTE @retval = sp_verify_job_identifiers '@job_name',
  10156.                                               '@job_id',
  10157.                                                @job_name OUTPUT,
  10158.                                                @job_id   OUTPUT
  10159.   IF (@retval <> 0)
  10160.     RETURN(1) -- Failure
  10161.  
  10162.   IF (NOT EXISTS (SELECT *
  10163.                   FROM msdb.dbo.sysjobservers
  10164.                   WHERE (job_id = @job_id)))
  10165.   BEGIN
  10166.     SELECT @job_id_as_char = CONVERT(VARCHAR(36), @job_id)
  10167.     RAISERROR(14256, -1, -1, @job_name, @job_id_as_char)
  10168.     RETURN(1) -- Failure
  10169.   END
  10170.  
  10171.   IF (EXISTS (SELECT *
  10172.               FROM msdb.dbo.sysjobservers
  10173.               WHERE (job_id = @job_id)
  10174.                 AND (server_id = 0)))
  10175.   BEGIN
  10176.     -- The job is local, so start (run) the job locally
  10177.  
  10178.     -- Check the step name (if supplied)
  10179.     IF (@step_name IS NOT NULL)
  10180.     BEGIN
  10181.       SELECT @step_id = step_id
  10182.       FROM msdb.dbo.sysjobsteps
  10183.       WHERE (step_name = @step_name)
  10184.         AND (job_id = @job_id)
  10185.  
  10186.       IF (@step_id IS NULL)
  10187.       BEGIN
  10188.         RAISERROR(14262, -1, -1, '@step_name', @step_name)
  10189.         RETURN(1) -- Failure
  10190.       END
  10191.     END
  10192.  
  10193.     EXECUTE @retval = msdb.dbo.sp_sqlagent_notify @op_type     = N'J',
  10194.                                                   @job_id      = @job_id,
  10195.                                                   @schedule_id = @step_id, -- This is the start step
  10196.                                                   @action_type = N'S',
  10197.                                                   @error_flag  = @error_flag
  10198.     IF ((@retval = 0) AND (@output_flag = 1))
  10199.       RAISERROR(14243, 0, 1, @job_name)
  10200.   END
  10201.   ELSE
  10202.   BEGIN
  10203.     -- The job is a multi-server job
  10204.  
  10205.     -- Check target server name (if any)
  10206.     IF (@server_name IS NOT NULL)
  10207.     BEGIN
  10208.       IF (NOT EXISTS (SELECT *
  10209.                       FROM msdb.dbo.systargetservers
  10210.                       WHERE (server_name = @server_name)))
  10211.       BEGIN
  10212.         RAISERROR(14262, -1, -1, '@server_name', @server_name)
  10213.         RETURN(1) -- Failure
  10214.       END
  10215.     END
  10216.  
  10217.     -- Re-post the job if it's an auto-delete job
  10218.     IF ((SELECT delete_level
  10219.          FROM msdb.dbo.sysjobs
  10220.          WHERE (job_id = @job_id)) <> 0)
  10221.       EXECUTE @retval = msdb.dbo.sp_post_msx_operation 'INSERT', 'JOB', @job_id, @server_name
  10222.  
  10223.     -- Post start instruction(s)
  10224.     EXECUTE @retval = msdb.dbo.sp_post_msx_operation 'START', 'JOB', @job_id, @server_name
  10225.   END
  10226.  
  10227.   RETURN(@retval) -- 0 means success
  10228. END
  10229. go
  10230.  
  10231. /**************************************************************/
  10232. /* SP_STOP_JOB                                                */
  10233. /**************************************************************/
  10234.  
  10235. PRINT ''
  10236. PRINT 'Creating procedure sp_stop_job...'
  10237. go
  10238. IF (EXISTS (SELECT *
  10239.             FROM msdb.dbo.sysobjects
  10240.             WHERE (name = N'sp_stop_job')
  10241.               AND (type = 'P')))
  10242.   DROP PROCEDURE sp_stop_job
  10243. go
  10244. CREATE PROCEDURE sp_stop_job
  10245.   @job_name           sysname          = NULL,
  10246.   @job_id             UNIQUEIDENTIFIER = NULL,
  10247.   @originating_server NVARCHAR(30)     = NULL, -- So that we can stop ALL jobs that came from the given server
  10248.   @server_name        NVARCHAR(30)     = NULL  -- The specific target server to stop the [multi-server] job on
  10249. AS
  10250. BEGIN
  10251.   DECLARE @job_id_as_char VARCHAR(36)
  10252.   DECLARE @retval         INT
  10253.   DECLARE @num_parameters INT
  10254.  
  10255.   SET NOCOUNT ON
  10256.  
  10257.   -- Remove any leading/trailing spaces from parameters
  10258.   SELECT @job_name           = LTRIM(RTRIM(@job_name))
  10259.   SELECT @originating_server = LTRIM(RTRIM(@originating_server))
  10260.   SELECT @server_name        = LTRIM(RTRIM(@server_name))
  10261.  
  10262.   -- Turn [nullable] empty string parameters into NULLs
  10263.   IF (@job_name           = N'') SELECT @job_name = NULL
  10264.   IF (@originating_server = N'') SELECT @originating_server = NULL
  10265.   IF (@server_name        = N'') SELECT @server_name = NULL
  10266.  
  10267.   -- We must have EITHER a job id OR a job name OR an originating server
  10268.   SELECT @num_parameters = 0
  10269.   IF (@job_id IS NOT NULL)
  10270.     SELECT @num_parameters = @num_parameters + 1
  10271.   IF (@job_name IS NOT NULL)
  10272.     SELECT @num_parameters = @num_parameters + 1
  10273.   IF (@originating_server IS NOT NULL)
  10274.     SELECT @num_parameters = @num_parameters + 1
  10275.   IF (@num_parameters <> 1)
  10276.   BEGIN
  10277.     RAISERROR(14232, -1, -1)
  10278.     RETURN(1) -- Failure
  10279.   END
  10280.  
  10281.   IF (@originating_server IS NOT NULL)
  10282.   BEGIN
  10283.     -- Stop (cancel) ALL local jobs that originated from the specified server
  10284.     IF (NOT EXISTS (SELECT *
  10285.                     FROM msdb.dbo.sysjobs_view
  10286.                     WHERE (originating_server = @originating_server)))
  10287.     BEGIN
  10288.       RAISERROR(14268, -1, -1, @originating_server)
  10289.       RETURN(1) -- Failure
  10290.     END
  10291.  
  10292.     DECLARE @total_counter   INT
  10293.     DECLARE @success_counter INT
  10294.  
  10295.     DECLARE stop_jobs CURSOR LOCAL
  10296.     FOR
  10297.     SELECT job_id
  10298.     FROM msdb.dbo.sysjobs_view
  10299.     WHERE (originating_server = @originating_server)
  10300.  
  10301.     SELECT @total_counter = 0, @success_counter = 0
  10302.     OPEN stop_jobs
  10303.     FETCH NEXT FROM stop_jobs INTO @job_id
  10304.     WHILE (@@fetch_status = 0)
  10305.     BEGIN
  10306.       SELECT @total_counter + @total_counter + 1
  10307.       EXECUTE @retval = msdb.dbo.sp_sqlagent_notify @op_type     = N'J',
  10308.                                                     @job_id      = @job_id,
  10309.                                                     @action_type = N'C'
  10310.       IF (@retval = 0)
  10311.         SELECT @success_counter = @success_counter + 1
  10312.       FETCH NEXT FROM stop_jobs INTO @job_id
  10313.     END
  10314.     RAISERROR(14253, 0, 1, @success_counter, @total_counter)
  10315.     DEALLOCATE stop_jobs
  10316.  
  10317.     RETURN(0) -- 0 means success
  10318.   END
  10319.   ELSE
  10320.   BEGIN
  10321.     -- Stop ONLY the specified job
  10322.     EXECUTE @retval = sp_verify_job_identifiers '@job_name',
  10323.                                                 '@job_id',
  10324.                                                  @job_name OUTPUT,
  10325.                                                  @job_id   OUTPUT
  10326.     IF (@retval <> 0)
  10327.       RETURN(1) -- Failure
  10328.  
  10329.     IF (NOT EXISTS (SELECT *
  10330.                     FROM msdb.dbo.sysjobservers
  10331.                     WHERE (job_id = @job_id)))
  10332.     BEGIN
  10333.       SELECT @job_id_as_char = CONVERT(VARCHAR(36), @job_id)
  10334.       RAISERROR(14257, -1, -1, @job_name, @job_id_as_char)
  10335.       RETURN(1) -- Failure
  10336.     END
  10337.  
  10338.     IF (EXISTS (SELECT *
  10339.                 FROM msdb.dbo.sysjobservers
  10340.                 WHERE (job_id = @job_id)
  10341.                   AND (server_id = 0)))
  10342.     BEGIN
  10343.       -- The job is local, so stop (cancel) the job locally
  10344.       EXECUTE @retval = msdb.dbo.sp_sqlagent_notify @op_type     = N'J',
  10345.                                                     @job_id      = @job_id,
  10346.                                                     @action_type = N'C'
  10347.       IF (@retval = 0)
  10348.         RAISERROR(14254, 0, 1, @job_name)
  10349.     END
  10350.     ELSE
  10351.     BEGIN
  10352.       -- The job is a multi-server job
  10353.  
  10354.       -- Check target server name (if any)
  10355.       IF (@server_name IS NOT NULL)
  10356.       BEGIN
  10357.         IF (NOT EXISTS (SELECT *
  10358.                         FROM msdb.dbo.systargetservers
  10359.                         WHERE (server_name = @server_name)))
  10360.         BEGIN
  10361.           RAISERROR(14262, -1, -1, '@server_name', @server_name)
  10362.           RETURN(1) -- Failure
  10363.         END
  10364.       END
  10365.  
  10366.       -- Post the stop instruction(s)
  10367.       EXECUTE @retval = sp_post_msx_operation 'STOP', 'JOB', @job_id, @server_name
  10368.     END
  10369.  
  10370.     RETURN(@retval) -- 0 means success
  10371.   END
  10372.  
  10373. END
  10374. go
  10375.  
  10376. /**************************************************************/
  10377. /* SP_GET_CHUNKED_JOBSTEP_PARAMS                              */
  10378. /**************************************************************/
  10379.  
  10380. PRINT ''
  10381. PRINT 'Creating procedure sp_get_chunked_jobstep_params...'
  10382. go
  10383. IF (EXISTS (SELECT *
  10384.             FROM msdb.dbo.sysobjects
  10385.             WHERE (name = N'sp_get_chunked_jobstep_params')
  10386.               AND (type = 'P')))
  10387.   DROP PROCEDURE sp_get_chunked_jobstep_params
  10388. go
  10389. CREATE PROCEDURE sp_get_chunked_jobstep_params
  10390.   @job_name sysname,
  10391.   @step_id  INT = 1
  10392. AS
  10393. BEGIN
  10394.   DECLARE @job_id           UNIQUEIDENTIFIER
  10395.   DECLARE @step_id_as_char  VARCHAR(10)
  10396.   DECLARE @text_pointer     VARBINARY(16)
  10397.   DECLARE @remaining_length INT
  10398.   DECLARE @offset           INT
  10399.   DECLARE @chunk            INT
  10400.   DECLARE @retval           INT
  10401.  
  10402.   SET NOCOUNT ON
  10403.  
  10404.   -- Check that the job exists
  10405.   EXECUTE @retval = sp_verify_job_identifiers '@job_name',
  10406.                                               '@job_id',
  10407.                                                @job_name OUTPUT,
  10408.                                                @job_id   OUTPUT
  10409.   IF (@retval <> 0)
  10410.     RETURN(1) -- Failure
  10411.  
  10412.   -- Check that the step exists
  10413.   IF (NOT EXISTS (SELECT *
  10414.                   FROM msdb.dbo.sysjobsteps
  10415.                   WHERE (job_id = @job_id)
  10416.                     AND (step_id = @step_id)))
  10417.   BEGIN
  10418.     SELECT @step_id_as_char = CONVERT(VARCHAR(10), @step_id)
  10419.     RAISERROR(14262, -1, -1, '@step_id', @step_id_as_char)
  10420.     RETURN(1) -- Failure
  10421.   END
  10422.  
  10423.   -- Return the sysjobsteps.additional_parameters TEXT column as multiple readtexts of
  10424.   -- length 2048
  10425.  
  10426.   SELECT @text_pointer = TEXTPTR(additional_parameters),
  10427.          @remaining_length = (DATALENGTH(additional_parameters) / 2)
  10428.   FROM msdb.dbo.sysjobsteps
  10429.   WHERE (job_id = @job_id)
  10430.     AND (step_id = @step_id)
  10431.  
  10432.   SELECT @offset = 0, @chunk = 100
  10433.  
  10434.   -- Get all the chunks of @chunk size
  10435.   WHILE (@remaining_length > @chunk)
  10436.   BEGIN
  10437.     READTEXT msdb.dbo.sysjobsteps.additional_parameters @text_pointer @offset @chunk
  10438.     SELECT @offset = @offset + @chunk
  10439.     SELECT @remaining_length = @remaining_length - @chunk
  10440.   END
  10441.  
  10442.   -- Get the last chunk
  10443.   IF (@remaining_length > 0)
  10444.     READTEXT msdb.dbo.sysjobsteps.additional_parameters @text_pointer @offset @remaining_length
  10445.  
  10446.   RETURN(@@error) -- 0 means success
  10447. END
  10448. go
  10449.  
  10450. /**************************************************************/
  10451. /* SP_CHECK_FOR_OWNED_JOBS                                    */
  10452. /**************************************************************/
  10453.  
  10454. PRINT ''
  10455. PRINT 'Creating procedure sp_check_for_owned_jobs...'
  10456. go
  10457. IF (EXISTS (SELECT *
  10458.             FROM msdb.dbo.sysobjects
  10459.             WHERE (name = N'sp_check_for_owned_jobs')
  10460.               AND (type = 'P')))
  10461.   DROP PROCEDURE sp_check_for_owned_jobs
  10462. go
  10463. CREATE PROCEDURE sp_check_for_owned_jobs
  10464.   @login_name sysname,
  10465.   @table_name sysname
  10466. AS
  10467. BEGIN
  10468.   SET NOCOUNT ON
  10469.  
  10470.   -- This procedure is called by sp_droplogin to check if the login being dropped
  10471.   -- still owns jobs.  The return value (the number of jobs owned) is passed back
  10472.   -- via the supplied table name [this cumbersome approach is necessary because
  10473.   -- sp_check_for_owned_jobs is invoked via an EXEC() and because we always want
  10474.   -- sp_droplogin to work, even if msdb and/or sysjobs does not exist].
  10475.  
  10476.   IF (EXISTS (SELECT *
  10477.               FROM msdb.dbo.sysobjects
  10478.               WHERE (name = N'sysjobs')
  10479.                 AND (type = 'U')))
  10480.   BEGIN
  10481.     SELECT @login_name = REPLACE(@login_name, N'''', N'''''')
  10482.     EXECUTE(N'INSERT INTO ' + @table_name + N' SELECT COUNT(*) FROM msdb.dbo.sysjobs_view WHERE (owner_sid = SUSER_SID(N''' + @login_name + '''))')
  10483.   END
  10484. END
  10485. go
  10486.  
  10487. /**************************************************************/
  10488. /* SP_CHECK_FOR_OWNED_JOBSTEPS                                */
  10489. /**************************************************************/
  10490.  
  10491. PRINT ''
  10492. PRINT 'Creating procedure sp_check_for_owned_jobsteps...'
  10493. go
  10494. IF (EXISTS (SELECT *
  10495.             FROM msdb.dbo.sysobjects
  10496.             WHERE (name = N'sp_check_for_owned_jobsteps')
  10497.               AND (type = 'P')))
  10498.   DROP PROCEDURE sp_check_for_owned_jobsteps
  10499. go
  10500. CREATE PROCEDURE sp_check_for_owned_jobsteps
  10501.   @login_name         sysname = NULL,  -- Supply this OR the database_X parameters, but not both
  10502.   @database_name      sysname = NULL,
  10503.   @database_user_name sysname = NULL
  10504. AS
  10505. BEGIN
  10506.   DECLARE @db_name         NVARCHAR(255)
  10507.   DECLARE @escaped_db_name NVARCHAR(255)
  10508.  
  10509.   SET NOCOUNT ON
  10510.  
  10511.   CREATE TABLE #work_table
  10512.   (
  10513.   database_name      sysname COLLATE database_default,
  10514.   database_user_name sysname COLLATE database_default
  10515.   )
  10516.  
  10517.   IF ((@login_name IS NOT NULL) AND (@database_name IS NULL) AND (@database_user_name IS NULL))
  10518.   BEGIN
  10519.     IF (SUSER_SID(@login_name) IS NULL)
  10520.     BEGIN
  10521.       RAISERROR(14262, -1, -1, '@login_name', @login_name)
  10522.       RETURN(1) -- Failure
  10523.     END
  10524.  
  10525.     DECLARE all_databases CURSOR LOCAL
  10526.     FOR
  10527.     SELECT name
  10528.     FROM master.dbo.sysdatabases
  10529.  
  10530.     OPEN all_databases
  10531.     FETCH NEXT FROM all_databases INTO @db_name
  10532.  
  10533.     -- Double up any single quotes in @login_name
  10534.     SELECT @login_name = REPLACE(@login_name, N'''', N'''''')
  10535.  
  10536.     WHILE (@@fetch_status = 0)
  10537.     BEGIN
  10538.       SELECT @escaped_db_name = QUOTENAME(@db_name, N'[')
  10539.       SELECT @db_name = REPLACE(@db_name, '''', '''''')
  10540.       EXECUTE(N'INSERT INTO #work_table
  10541.                 SELECT N''' + @db_name + N''', name
  10542.                 FROM ' + @escaped_db_name + N'.dbo.sysusers
  10543.                 WHERE (sid = SUSER_SID(N''' + @login_name + N'''))')
  10544.       FETCH NEXT FROM all_databases INTO @db_name
  10545.     END
  10546.  
  10547.     DEALLOCATE all_databases
  10548.  
  10549.     -- If the login is an NT login, check for steps run as the login directly (as is the case with transient NT logins)
  10550.     IF (@login_name LIKE '%\%')
  10551.     BEGIN
  10552.       INSERT INTO #work_table
  10553.       SELECT database_name, database_user_name
  10554.       FROM msdb.dbo.sysjobsteps
  10555.       WHERE (database_user_name = @login_name)
  10556.     END
  10557.   END
  10558.  
  10559.   IF ((@login_name IS NULL) AND (@database_name IS NOT NULL) AND (@database_user_name IS NOT NULL))
  10560.   BEGIN
  10561.     INSERT INTO #work_table
  10562.     SELECT @database_name, @database_user_name
  10563.   END
  10564.  
  10565.   IF (EXISTS (SELECT *
  10566.               FROM #work_table wt,
  10567.                    msdb.dbo.sysjobsteps sjs
  10568.               WHERE (wt.database_name = sjs.database_name)
  10569.                 AND (wt.database_user_name = sjs.database_user_name)))
  10570.   BEGIN
  10571.     SELECT sjv.job_id,
  10572.            sjv.name,
  10573.            sjs.step_id,
  10574.            sjs.step_name
  10575.     FROM #work_table           wt,
  10576.          msdb.dbo.sysjobsteps  sjs,
  10577.          msdb.dbo.sysjobs_view sjv
  10578.     WHERE (wt.database_name = sjs.database_name)
  10579.       AND (wt.database_user_name = sjs.database_user_name)
  10580.       AND (sjv.job_id = sjs.job_id)
  10581.     ORDER BY sjs.job_id
  10582.   END
  10583.  
  10584.   RETURN(0) -- 0 means success
  10585. END
  10586. go
  10587.  
  10588. /**************************************************************/
  10589. /* SP_SQLAGENT_REFRESH_JOB                                    */
  10590. /**************************************************************/
  10591.  
  10592. PRINT ''
  10593. PRINT 'Creating procedure sp_sqlagent_refresh_job...'
  10594. go
  10595. IF (EXISTS (SELECT *
  10596.             FROM msdb.dbo.sysobjects
  10597.             WHERE (name = N'sp_sqlagent_refresh_job')
  10598.               AND (type = 'P')))
  10599.   DROP PROCEDURE sp_sqlagent_refresh_job
  10600. go
  10601. CREATE PROCEDURE sp_sqlagent_refresh_job
  10602.   @job_id      UNIQUEIDENTIFIER = NULL,
  10603.   @server_name NVARCHAR(30)     = NULL -- This parameter allows a TSX to use this SP when updating a job
  10604. AS
  10605. BEGIN
  10606.   DECLARE @server_id INT
  10607.  
  10608.   SET NOCOUNT ON
  10609.  
  10610.   IF (@server_name IS NULL) OR (UPPER(@server_name) = '(LOCAL)')
  10611.     SELECT @server_name = UPPER(CONVERT(NVARCHAR(30), SERVERPROPERTY('ServerName')))
  10612.  
  10613.   SELECT @server_id = server_id
  10614.   FROM msdb.dbo.systargetservers_view
  10615.   WHERE (server_name = ISNULL(@server_name, UPPER(CONVERT(NVARCHAR(30), SERVERPROPERTY('ServerName')))))
  10616.  
  10617.   SELECT @server_id = ISNULL(@server_id, 0)
  10618.  
  10619.   SELECT sjv.job_id,
  10620.          sjv.name,
  10621.          sjv.enabled,
  10622.          sjv.start_step_id,
  10623.          owner = SUSER_SNAME(sjv.owner_sid),
  10624.          sjv.notify_level_eventlog,
  10625.          sjv.notify_level_email,
  10626.          sjv.notify_level_netsend,
  10627.          sjv.notify_level_page,
  10628.          sjv.notify_email_operator_id,
  10629.          sjv.notify_netsend_operator_id,
  10630.          sjv.notify_page_operator_id,
  10631.          sjv.delete_level,
  10632.          has_step = (SELECT COUNT(*)
  10633.                      FROM msdb.dbo.sysjobsteps sjst
  10634.                      WHERE (sjst.job_id = sjv.job_id)),
  10635.          sjv.version_number,
  10636.          last_run_date = ISNULL(sjs.last_run_date, 0),
  10637.          last_run_time = ISNULL(sjs.last_run_time, 0),
  10638.          sjv.originating_server,
  10639.          sjv.description
  10640.   FROM msdb.dbo.sysjobs_view  sjv,
  10641.        msdb.dbo.sysjobservers sjs
  10642.   WHERE ((@job_id IS NULL) OR (@job_id = sjv.job_id))
  10643.     AND (sjv.job_id = sjs.job_id)
  10644.     AND (sjs.server_id = @server_id)
  10645.   ORDER BY sjv.job_id
  10646.  
  10647.   RETURN(@@error) -- 0 means success
  10648. END
  10649. go
  10650.  
  10651. /**************************************************************/
  10652. /* SP_JOBHISTORY_ROW_LIMITER                                  */
  10653. /**************************************************************/
  10654.  
  10655. PRINT ''
  10656. PRINT 'Creating procedure sp_jobhistory_row_limiter...'
  10657. go
  10658. IF (EXISTS (SELECT *
  10659.             FROM msdb.dbo.sysobjects
  10660.             WHERE (name = N'sp_jobhistory_row_limiter')
  10661.               AND (type = 'P')))
  10662.   DROP PROCEDURE dbo.sp_jobhistory_row_limiter
  10663. go
  10664. CREATE PROCEDURE sp_jobhistory_row_limiter
  10665.   @job_id UNIQUEIDENTIFIER
  10666. AS
  10667. BEGIN
  10668.   DECLARE @max_total_rows         INT -- This value comes from the registry (MaxJobHistoryTableRows)
  10669.   DECLARE @max_rows_per_job       INT -- This value comes from the registry (MaxJobHistoryRows)
  10670.   DECLARE @rows_to_delete         INT
  10671.   DECLARE @rows_to_delete_as_char VARCHAR(10)
  10672.   DECLARE @current_rows           INT
  10673.   DECLARE @current_rows_per_job   INT
  10674.   DECLARE @job_id_as_char         VARCHAR(36)
  10675.  
  10676.   SET NOCOUNT ON
  10677.  
  10678.   SELECT @job_id_as_char = CONVERT(VARCHAR(36), @job_id)
  10679.  
  10680.   -- Get max-job-history-rows from the registry
  10681.   EXECUTE master.dbo.xp_instance_regread N'HKEY_LOCAL_MACHINE',
  10682.                                          N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
  10683.                                          N'JobHistoryMaxRows',
  10684.                                          @max_total_rows OUTPUT,
  10685.                                          N'no_output'
  10686.  
  10687.   -- Check if we are limiting sysjobhistory rows
  10688.   IF (ISNULL(@max_total_rows, -1) = -1)
  10689.     RETURN(0)
  10690.  
  10691.   -- Check that max_total_rows is more than 1
  10692.   IF (ISNULL(@max_total_rows, 0) < 2)
  10693.   BEGIN
  10694.     -- It isn't, so set the default to 1000 rows
  10695.     SELECT @max_total_rows = 1000
  10696.     EXECUTE master.dbo.xp_instance_regwrite N'HKEY_LOCAL_MACHINE',
  10697.                                             N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
  10698.                                             N'JobHistoryMaxRows',
  10699.                                             N'REG_DWORD',
  10700.                                             @max_total_rows
  10701.   END
  10702.  
  10703.   -- Get the per-job maximum number of rows to keep
  10704.   SELECT @max_rows_per_job = 0
  10705.   EXECUTE master.dbo.xp_instance_regread N'HKEY_LOCAL_MACHINE',
  10706.                                          N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
  10707.                                          N'JobHistoryMaxRowsPerJob',
  10708.                                          @max_rows_per_job OUTPUT,
  10709.                                          N'no_output'
  10710.  
  10711.   -- Check that max_rows_per_job is <= max_total_rows
  10712.   IF ((@max_rows_per_job > @max_total_rows) OR (@max_rows_per_job < 1))
  10713.   BEGIN
  10714.     -- It isn't, so default the rows_per_job to max_total_rows
  10715.     SELECT @max_rows_per_job = @max_total_rows
  10716.     EXECUTE master.dbo.xp_instance_regwrite N'HKEY_LOCAL_MACHINE',
  10717.                                             N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
  10718.                                             N'JobHistoryMaxRowsPerJob',
  10719.                                             N'REG_DWORD',
  10720.                                             @max_rows_per_job
  10721.   END
  10722.  
  10723.   BEGIN TRANSACTION
  10724.  
  10725.   SELECT @current_rows_per_job = COUNT(*)
  10726.   FROM msdb.dbo.sysjobhistory (TABLOCKX)
  10727.   WHERE (job_id = @job_id)
  10728.  
  10729.   -- Delete the oldest history row(s) for the job being inserted if the new row has
  10730.   -- pushed us over the per-job row limit (MaxJobHistoryRows)
  10731.   SELECT @rows_to_delete = @current_rows_per_job - @max_rows_per_job
  10732.   SELECT @rows_to_delete_as_char = CONVERT(VARCHAR, @rows_to_delete)
  10733.  
  10734.   IF (@rows_to_delete > 0)
  10735.   BEGIN
  10736.     EXECUTE ('DECLARE @new_oldest_id INT
  10737.               SET NOCOUNT ON
  10738.               SET ROWCOUNT ' + @rows_to_delete_as_char +
  10739.              'SELECT @new_oldest_id = instance_id
  10740.               FROM msdb.dbo.sysjobhistory
  10741.               WHERE (job_id = ''' + @job_id_as_char + ''') ' +
  10742.              'ORDER BY instance_id
  10743.               SET ROWCOUNT 0
  10744.               DELETE FROM msdb.dbo.sysjobhistory
  10745.               WHERE (job_id = ''' + @job_id_as_char + ''')' +
  10746.              '  AND (instance_id <= @new_oldest_id)')
  10747.   END
  10748.  
  10749.   -- Delete the oldest history row(s) if inserting the new row has pushed us over the
  10750.   -- global MaxJobHistoryTableRows limit.
  10751.   SELECT @current_rows = COUNT(*)
  10752.   FROM msdb.dbo.sysjobhistory
  10753.  
  10754.   SELECT @rows_to_delete = @current_rows - @max_total_rows
  10755.   SELECT @rows_to_delete_as_char = CONVERT(VARCHAR, @rows_to_delete)
  10756.  
  10757.   IF (@rows_to_delete > 0)
  10758.   BEGIN
  10759.     EXECUTE ('DECLARE @new_oldest_id INT
  10760.               SET NOCOUNT ON
  10761.               SET ROWCOUNT ' + @rows_to_delete_as_char +
  10762.              'SELECT @new_oldest_id = instance_id
  10763.               FROM msdb.dbo.sysjobhistory
  10764.               ORDER BY instance_id
  10765.               SET ROWCOUNT 0
  10766.               DELETE FROM msdb.dbo.sysjobhistory
  10767.               WHERE (instance_id <= @new_oldest_id)')
  10768.   END
  10769.  
  10770.   IF (@@trancount > 0)
  10771.     COMMIT TRANSACTION
  10772.  
  10773.   RETURN(0) -- Success
  10774. END
  10775. go
  10776.  
  10777.  
  10778. /**************************************************************/
  10779. /* SP_SQLAGENT_LOG_JOBHISTORY                                 */
  10780. /**************************************************************/
  10781.  
  10782. PRINT ''
  10783. PRINT 'Creating procedure sp_sqlagent_log_jobhistory...'
  10784. go
  10785. IF (EXISTS (SELECT *
  10786.             FROM msdb.dbo.sysobjects
  10787.             WHERE (name = N'sp_sqlagent_log_jobhistory')
  10788.               AND (type = 'P')))
  10789.   DROP PROCEDURE sp_sqlagent_log_jobhistory
  10790. go
  10791. CREATE PROCEDURE sp_sqlagent_log_jobhistory
  10792.   @job_id               UNIQUEIDENTIFIER,
  10793.   @step_id              INT,
  10794.   @sql_message_id       INT = 0,
  10795.   @sql_severity         INT = 0,
  10796.   @message              NVARCHAR(1024) = NULL,
  10797.   @run_status           INT, -- SQLAGENT_EXEC_X code
  10798.   @run_date             INT,
  10799.   @run_time             INT,
  10800.   @run_duration         INT,
  10801.   @operator_id_emailed  INT = 0,
  10802.   @operator_id_netsent  INT = 0,
  10803.   @operator_id_paged    INT = 0,
  10804.   @retries_attempted    INT,
  10805.   @server               NVARCHAR(30) = NULL
  10806. AS
  10807. BEGIN
  10808.   DECLARE @retval              INT
  10809.   DECLARE @job_id_as_char      VARCHAR(36)
  10810.   DECLARE @step_id_as_char     VARCHAR(10)
  10811.   DECLARE @operator_id_as_char VARCHAR(10)
  10812.   DECLARE @step_name           sysname
  10813.   DECLARE @error_severity      INT
  10814.  
  10815.   SET NOCOUNT ON
  10816.  
  10817.   IF (@server IS NULL) OR (UPPER(@server) = '(LOCAL)')
  10818.     SELECT @server = UPPER(CONVERT(NVARCHAR(30), SERVERPROPERTY('ServerName')))
  10819.  
  10820.   -- Check authority (only SQLServerAgent can add a history entry for a job)
  10821.   EXECUTE @retval = sp_verify_jobproc_caller @job_id = @job_id, @program_name = N'SQLAgent%'
  10822.   IF (@retval <> 0)
  10823.     RETURN(@retval)
  10824.  
  10825.   -- NOTE: We raise all errors as informational (sev 0) to prevent SQLServerAgent from caching
  10826.   --       the operation (if it fails) since if the operation will never run successfully we
  10827.   --       don't want it to hang around in the operation cache.
  10828.   SELECT @error_severity = 0
  10829.  
  10830.   -- Check job_id
  10831.   IF (NOT EXISTS (SELECT *
  10832.                   FROM msdb.dbo.sysjobs_view
  10833.                   WHERE (job_id = @job_id)))
  10834.   BEGIN
  10835.     SELECT @job_id_as_char = CONVERT(VARCHAR(36), @job_id)
  10836.     RAISERROR(14262, @error_severity, -1, 'Job', @job_id_as_char)
  10837.     RETURN(1) -- Failure
  10838.   END
  10839.  
  10840.   -- Check step id
  10841.   IF (@step_id <> 0) -- 0 means 'for the whole job'
  10842.   BEGIN
  10843.     SELECT @step_name = step_name
  10844.     FROM msdb.dbo.sysjobsteps
  10845.     WHERE (job_id = @job_id)
  10846.       AND (step_id = @step_id)
  10847.     IF (@step_name IS NULL)
  10848.     BEGIN
  10849.       SELECT @step_id_as_char = CONVERT(VARCHAR, @step_id)
  10850.       RAISERROR(14262, @error_severity, -1, '@step_id', @step_id_as_char)
  10851.       RETURN(1) -- Failure
  10852.     END
  10853.   END
  10854.   ELSE
  10855.     SELECT @step_name = FORMATMESSAGE(14570)
  10856.  
  10857.   -- Check run_status
  10858.   IF (@run_status NOT IN (0, 1, 2, 3, 4, 5)) -- SQLAGENT_EXEC_X code
  10859.   BEGIN
  10860.     RAISERROR(14266, @error_severity, -1, '@run_status', '0, 1, 2, 3, 4, 5')
  10861.     RETURN(1) -- Failure
  10862.   END
  10863.  
  10864.   -- Check run_date
  10865.   EXECUTE @retval = sp_verify_job_date @run_date, '@run_date', 10
  10866.   IF (@retval <> 0)
  10867.     RETURN(1) -- Failure
  10868.  
  10869.   -- Check run_time
  10870.   EXECUTE @retval = sp_verify_job_time @run_time, '@run_time', 10
  10871.   IF (@retval <> 0)
  10872.     RETURN(1) -- Failure
  10873.  
  10874.   -- Check operator_id_emailed
  10875.   IF (@operator_id_emailed <> 0)
  10876.   BEGIN
  10877.     IF (NOT EXISTS (SELECT *
  10878.                     FROM msdb.dbo.sysoperators
  10879.                     WHERE (id = @operator_id_emailed)))
  10880.     BEGIN
  10881.       SELECT @operator_id_as_char = CONVERT(VARCHAR, @operator_id_emailed)
  10882.       RAISERROR(14262, @error_severity, -1, '@operator_id_emailed', @operator_id_as_char)
  10883.       RETURN(1) -- Failure
  10884.     END
  10885.   END
  10886.  
  10887.   -- Check operator_id_netsent
  10888.   IF (@operator_id_netsent <> 0)
  10889.   BEGIN
  10890.     IF (NOT EXISTS (SELECT *
  10891.                     FROM msdb.dbo.sysoperators
  10892.                     WHERE (id = @operator_id_netsent)))
  10893.     BEGIN
  10894.       SELECT @operator_id_as_char = CONVERT(VARCHAR, @operator_id_netsent)
  10895.       RAISERROR(14262, @error_severity, -1, '@operator_id_netsent', @operator_id_as_char)
  10896.       RETURN(1) -- Failure
  10897.     END
  10898.   END
  10899.  
  10900.   -- Check operator_id_paged
  10901.   IF (@operator_id_paged <> 0)
  10902.   BEGIN
  10903.     IF (NOT EXISTS (SELECT *
  10904.                     FROM msdb.dbo.sysoperators
  10905.                     WHERE (id = @operator_id_paged)))
  10906.     BEGIN
  10907.       SELECT @operator_id_as_char = CONVERT(VARCHAR, @operator_id_paged)
  10908.       RAISERROR(14262, @error_severity, -1, '@operator_id_paged', @operator_id_as_char)
  10909.       RETURN(1) -- Failure
  10910.     END
  10911.   END
  10912.  
  10913.   -- Insert the history row
  10914.   INSERT INTO msdb.dbo.sysjobhistory
  10915.          (job_id,
  10916.           step_id,
  10917.           step_name,
  10918.           sql_message_id,
  10919.           sql_severity,
  10920.           message,
  10921.           run_status,
  10922.           run_date,
  10923.           run_time,
  10924.           run_duration,
  10925.           operator_id_emailed,
  10926.           operator_id_netsent,
  10927.           operator_id_paged,
  10928.           retries_attempted,
  10929.           server)
  10930.   VALUES (@job_id,
  10931.           @step_id,
  10932.           @step_name,
  10933.           @sql_message_id,
  10934.           @sql_severity,
  10935.           @message,
  10936.           @run_status,
  10937.           @run_date,
  10938.           @run_time,
  10939.           @run_duration,
  10940.           @operator_id_emailed,
  10941.           @operator_id_netsent,
  10942.           @operator_id_paged,
  10943.           @retries_attempted,
  10944.           @server)
  10945.  
  10946.   -- Special handling of replication jobs 
  10947.   DECLARE @job_name sysname
  10948.   DECLARE @category_id int
  10949.   SELECT  @job_name = name, @category_id = category_id from msdb.dbo.sysjobs 
  10950.     where job_id = @job_id 
  10951.   -- If misc. replication job, then update global replication status table
  10952.   IF @category_id IN (11, 12, 16, 17, 18)
  10953.   BEGIN
  10954.     -- Nothing can be done if this fails, so don't worry about the return code
  10955.     EXECUTE master.dbo.sp_MSupdate_replication_status
  10956.       @publisher = '',
  10957.       @publisher_db = '',
  10958.       @publication = '',
  10959.       @publication_type = -1,
  10960.       @agent_type = 5,
  10961.       @agent_name = @job_name,
  10962.       @status = @run_status
  10963.   END
  10964.   -- If replicatio agents (snapshot, logreader, distribution, merge, and queuereader
  10965.   -- and the step has been canceled and if we are at the distributor.
  10966.   IF @category_id in (10,13,14,15,19) and @run_status = 3 and 
  10967.     object_id('MSdistributiondbs') is not null
  10968.   BEGIN
  10969.     -- Get the database
  10970.     DECLARE @database sysname
  10971.     SELECT @database = database_name from sysjobsteps where job_id = @job_id and 
  10972.     lower(subsystem) in (N'distribution', N'logreader','snapshot',N'merge',
  10973.         N'queuereader')
  10974.     -- If the database is a distribution database
  10975.     IF EXISTS (select * from MSdistributiondbs where name = @database)
  10976.     BEGIN
  10977.     DECLARE @proc nvarchar(500)
  10978.     SELECT @proc = quotename(@database) + N'.dbo.sp_MSlog_agent_cancel'
  10979.     EXEC @proc @job_id = @job_id, @category_id = @category_id, 
  10980.         @message = @message
  10981.     END     
  10982.   END
  10983.  
  10984.   -- Delete any history rows that are over the registry-defined limits
  10985.   EXECUTE msdb.dbo.sp_jobhistory_row_limiter @job_id
  10986.  
  10987.   RETURN(@@error) -- 0 means success
  10988. END
  10989. go
  10990.  
  10991. /**************************************************************/
  10992. /* SP_SQLAGENT_CHECK_MSX_VERSION                              */
  10993. /**************************************************************/
  10994.  
  10995. PRINT ''
  10996. PRINT 'Creating procedure sp_sqlagent_check_msx_version...'
  10997. go
  10998. IF (EXISTS (SELECT *
  10999.             FROM msdb.dbo.sysobjects
  11000.             WHERE (name = N'sp_sqlagent_check_msx_version')
  11001.               AND (type = 'P')))
  11002.   DROP PROCEDURE sp_sqlagent_check_msx_version
  11003. go
  11004. CREATE PROCEDURE sp_sqlagent_check_msx_version
  11005.   @required_microsoft_version INT = NULL
  11006. AS
  11007. BEGIN
  11008.   SET NOCOUNT ON
  11009.  
  11010.   DECLARE @msx_version          NVARCHAR(16)
  11011.   DECLARE @required_msx_version NVARCHAR(16)
  11012.  
  11013.   IF (@required_microsoft_version IS NULL)
  11014.     SELECT @required_microsoft_version = 0x07000252 -- 7.0.594
  11015.  
  11016.   IF (@@microsoftversion < @required_microsoft_version)
  11017.   BEGIN
  11018.     SELECT @msx_version = CONVERT( NVARCHAR(2), CONVERT( INT, CONVERT( BINARY(1), @@microsoftversion / 0x1000000 ) ) )
  11019.     + N'.' 
  11020.     + CONVERT( NVARCHAR(2), CONVERT( INT, CONVERT( BINARY(1), CONVERT( BINARY(2), ((@@microsoftversion / 0x10000) % 0x100) ) ) ) )
  11021.     + N'.'
  11022.     + CONVERT( NVARCHAR(4), @@microsoftversion % 0x10000 )
  11023.  
  11024.     SELECT @required_msx_version = CONVERT( NVARCHAR(2), CONVERT( INT, CONVERT( BINARY(1), @required_microsoft_version / 0x1000000 ) ) )
  11025.     + N'.'
  11026.     + CONVERT( NVARCHAR(2), CONVERT( INT, CONVERT( BINARY(1), CONVERT( BINARY(2), ((@required_microsoft_version / 0x10000) % 0x100) ) ) ) )
  11027.     + N'.' 
  11028.     + CONVERT( NVARCHAR(4), @required_microsoft_version % 0x10000 )    
  11029.  
  11030.     RAISERROR(14541, -1, -1, @msx_version, @required_msx_version)
  11031.     RETURN(1) -- Failure
  11032.   END
  11033.   RETURN(0) -- Success
  11034. END
  11035. go
  11036.  
  11037. /**************************************************************/
  11038. /* SP_SQLAGENT_PROBE_MSX                                      */
  11039. /**************************************************************/
  11040.  
  11041. PRINT ''
  11042. PRINT 'Creating procedure sp_sqlagent_probe_msx...'
  11043. go
  11044. IF (EXISTS (SELECT *
  11045.             FROM msdb.dbo.sysobjects
  11046.             WHERE (name = N'sp_sqlagent_probe_msx')
  11047.               AND (type = 'P')))
  11048.   DROP PROCEDURE sp_sqlagent_probe_msx
  11049. go
  11050. CREATE PROCEDURE sp_sqlagent_probe_msx
  11051.   @server_name          NVARCHAR(30),  -- The name of the target server probing the MSX
  11052.   @local_time           NVARCHAR(100), -- The local time at the target server in the format YYYY/MM/DD HH:MM:SS
  11053.   @poll_interval        INT,           -- The frequency (in seconds) with which the target polls the MSX
  11054.   @time_zone_adjustment INT = NULL     -- The offset from GMT in minutes (may be NULL if unknown)
  11055. AS
  11056. BEGIN
  11057.   DECLARE @bad_enlistment        BIT
  11058.   DECLARE @blocking_instructions INT
  11059.   DECLARE @pending_instructions  INT
  11060.  
  11061.   SET NOCOUNT ON
  11062.  
  11063.   SELECT @bad_enlistment = 0, @blocking_instructions = 0, @pending_instructions = 0
  11064.  
  11065.   UPDATE msdb.dbo.systargetservers
  11066.   SET last_poll_date = GETDATE(),
  11067.       local_time_at_last_poll = CONVERT(DATETIME, @local_time, 111),
  11068.       poll_interval = @poll_interval,
  11069.       time_zone_adjustment = ISNULL(@time_zone_adjustment, time_zone_adjustment)
  11070.   WHERE (server_name = @server_name)
  11071.  
  11072.   -- If the systargetservers entry is missing (and no DEFECT instruction has been posted)
  11073.   -- then the enlistment is bad
  11074.   IF (NOT EXISTS (SELECT 1
  11075.                   FROM msdb.dbo.systargetservers
  11076.                   WHERE (server_name = @server_name))) AND
  11077.      (NOT EXISTS (SELECT 1
  11078.                   FROM msdb.dbo.sysdownloadlist
  11079.                   WHERE (target_server = @server_name)
  11080.                     AND (operation_code = 7)
  11081.                     AND (object_type = 2)))
  11082.     SELECT @bad_enlistment = 1
  11083.  
  11084.   SELECT @blocking_instructions = COUNT(*)
  11085.   FROM msdb.dbo.sysdownloadlist
  11086.   WHERE (target_server = @server_name)
  11087.     AND (error_message IS NOT NULL)
  11088.  
  11089.   SELECT @pending_instructions = COUNT(*)
  11090.   FROM msdb.dbo.sysdownloadlist
  11091.   WHERE (target_server = @server_name)
  11092.     AND (error_message IS NULL)
  11093.     AND (status = 0)
  11094.  
  11095.   SELECT @bad_enlistment, @blocking_instructions, @pending_instructions
  11096. END
  11097. go
  11098.  
  11099. /**************************************************************/
  11100. /* SP_SET_LOCAL_TIME                                          */
  11101. /**************************************************************/
  11102.  
  11103. PRINT ''
  11104. PRINT 'Creating procedure sp_set_local_time...'
  11105. go
  11106. IF (EXISTS (SELECT *
  11107.             FROM msdb.dbo.sysobjects
  11108.             WHERE (name = N'sp_set_local_time')
  11109.               AND (type = 'P')))
  11110.   DROP PROCEDURE sp_set_local_time
  11111. go
  11112. CREATE PROCEDURE sp_set_local_time
  11113.   @server_name           NVARCHAR(30) = NULL,
  11114.   @adjustment_in_minutes INT          = 0 -- Only needed for Win9x
  11115. AS
  11116. BEGIN
  11117.   DECLARE @ret              INT
  11118.   DECLARE @local_time       INT
  11119.   DECLARE @local_date       INT
  11120.   DECLARE @current_datetime DATETIME
  11121.   DECLARE @local_time_sz    VARCHAR(30)
  11122.   DECLARE @cmd              NVARCHAR(200)
  11123.   DECLARE @date_format      NVARCHAR(64)
  11124.   DECLARE @year_sz          NVARCHAR(16)
  11125.   DECLARE @month_sz         NVARCHAR(16)
  11126.   DECLARE @day_sz           NVARCHAR(16)
  11127.  
  11128.   -- Synchronize the clock with the remote server (if supplied)
  11129.   -- NOTE: NT takes timezones into account, whereas Win9x does not
  11130.   IF (@server_name IS NOT NULL)
  11131.   BEGIN
  11132.     SELECT @cmd = N'net time \\' + @server_name + N' /set /y'
  11133.     EXECUTE @ret = master.dbo.xp_cmdshell @cmd, no_output
  11134.     IF (@ret <> 0)
  11135.       RETURN(1) -- Failure
  11136.   END
  11137.  
  11138.   -- Since NET TIME on Win9x does not take time zones into account we need to manually adjust
  11139.   -- for this using @adjustment_in_minutes which will be the difference between the MSX GMT
  11140.   -- offset and the target server GMT offset
  11141.   IF ((PLATFORM() & 0x2) = 0x2) -- Win9x
  11142.   BEGIN
  11143.     -- Get the date format from the registry (so that we can construct our DATE command-line command)
  11144.     EXECUTE master.dbo.xp_regread N'HKEY_CURRENT_USER',
  11145.                                   N'Control Panel\International',
  11146.                                   N'sShortDate',
  11147.                                   @date_format OUTPUT,
  11148.                                   N'no_output'
  11149.     SELECT @date_format = LOWER(@date_format)
  11150.  
  11151.     IF (@adjustment_in_minutes <> 0)
  11152.     BEGIN
  11153.       -- Wait for SQLServer to re-cache the OS time
  11154.       WAITFOR DELAY '00:01:00'
  11155.  
  11156.       SELECT @current_datetime = DATEADD(mi, @adjustment_in_minutes, GETDATE())
  11157.       SELECT @local_time_sz = SUBSTRING(CONVERT(VARCHAR, @current_datetime, 8), 1, 5)
  11158.       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)))
  11159.       SELECT @local_date = CONVERT(INT, CONVERT(VARCHAR, @current_datetime, 112))
  11160.  
  11161.       -- Set the date
  11162.       SELECT @year_sz = CONVERT(NVARCHAR, @local_date / 10000)
  11163.       SELECT @month_sz = CONVERT(NVARCHAR, (@local_date % 10000) / 100)
  11164.       SELECT @day_sz = CONVERT(NVARCHAR, @local_date % 100)
  11165.  
  11166.       IF (@date_format LIKE N'y%m%d')
  11167.         SELECT @cmd = N'DATE ' + @year_sz + N'-' + @month_sz + N'-' + @day_sz
  11168.       IF (@date_format LIKE N'y%d%m')
  11169.         SELECT @cmd = N'DATE ' + @year_sz + N'-' + @day_sz + N'-' + @month_sz
  11170.       IF (@date_format LIKE N'm%d%y')
  11171.         SELECT @cmd = N'DATE ' + @month_sz + N'-' + @day_sz + N'-' + @year_sz
  11172.       IF (@date_format LIKE N'd%m%y')
  11173.         SELECT @cmd = N'DATE ' + @day_sz + N'-' + @month_sz + N'-' + @year_sz
  11174.  
  11175.       EXECUTE @ret = master.dbo.xp_cmdshell @cmd, no_output
  11176.       IF (@ret <> 0)
  11177.         RETURN 1 -- Failure
  11178.  
  11179.       -- Set the time (NOTE: We can't set the millisecond part of the time, so we may be up to .999 sec off)
  11180.       SELECT @cmd = N'TIME ' + CONVERT(NVARCHAR, @local_time / 100) + N':' + CONVERT(NVARCHAR, @local_time % 100) + ':' + CONVERT(NVARCHAR(2), DATEPART(SS, GETDATE()))
  11181.       EXECUTE @ret = master.dbo.xp_cmdshell @cmd, no_output
  11182.       IF (@ret <> 0)
  11183.         RETURN 1 -- Failure
  11184.     END
  11185.  
  11186.   END
  11187.  
  11188.   RETURN(0) -- Success
  11189. END
  11190. go
  11191.  
  11192. /**************************************************************/
  11193. /* SP_MULTI_SERVER_JOB_SUMMARY [used by SEM only]             */
  11194. /**************************************************************/
  11195.  
  11196. PRINT ''
  11197. PRINT 'Creating procedure sp_multi_server_job_summary...'
  11198. go
  11199. IF (EXISTS (SELECT *
  11200.             FROM msdb.dbo.sysobjects
  11201.             WHERE (name = N'sp_multi_server_job_summary')
  11202.               AND (type = 'P')))
  11203.   DROP PROCEDURE sp_multi_server_job_summary
  11204. go
  11205. CREATE PROCEDURE sp_multi_server_job_summary
  11206.   @job_id   UNIQUEIDENTIFIER = NULL,
  11207.   @job_name sysname          = NULL
  11208. AS
  11209. BEGIN
  11210.   DECLARE @retval INT
  11211.  
  11212.   SET NOCOUNT ON
  11213.  
  11214.   IF ((@job_id IS NOT NULL) OR (@job_name IS NOT NULL))
  11215.   BEGIN
  11216.     EXECUTE @retval = sp_verify_job_identifiers '@job_name',
  11217.                                                 '@job_id',
  11218.                                                  @job_name OUTPUT,
  11219.                                                  @job_id   OUTPUT
  11220.     IF (@retval <> 0)
  11221.       RETURN(1) -- Failure
  11222.   END
  11223.  
  11224.   -- NOTE: We join with syscategories - not sysjobservers - since we want to include jobs
  11225.   --       which are of type multi-server but which don't currently have any servers
  11226.   SELECT 'job_id'   = sj.job_id,
  11227.          'job_name' = sj.name,
  11228.          'enabled'  = sj.enabled,
  11229.          'category_name'  = sc.name,
  11230.          'target_servers' = (SELECT COUNT(*)
  11231.                              FROM msdb.dbo.sysjobservers sjs
  11232.                              WHERE (sjs.job_id = sj.job_id)),
  11233.          'pending_download_instructions' = (SELECT COUNT(*)
  11234.                                             FROM msdb.dbo.sysdownloadlist sdl
  11235.                                             WHERE (sdl.object_id = sj.job_id)
  11236.                                               AND (status = 0)),
  11237.          'download_errors' = (SELECT COUNT(*)
  11238.                               FROM msdb.dbo.sysdownloadlist sdl
  11239.                               WHERE (sdl.object_id = sj.job_id)
  11240.                                 AND (sdl.error_message IS NOT NULL)),
  11241.          'execution_failures' = (SELECT COUNT(*)
  11242.                                  FROM msdb.dbo.sysjobservers sjs
  11243.                                  WHERE (sjs.job_id = sj.job_id)
  11244.                                    AND (sjs.last_run_date <> 0)
  11245.                                    AND (sjs.last_run_outcome <> 1)) -- 1 is success
  11246.   FROM msdb.dbo.sysjobs sj,
  11247.        msdb.dbo.syscategories sc
  11248.   WHERE (sj.category_id = sc.category_id)
  11249.     AND (sc.category_class = 1) -- JOB
  11250.     AND (sc.category_type  = 2) -- Multi-Server
  11251.     AND ((@job_id IS NULL)   OR (sj.job_id = @job_id))
  11252.     AND ((@job_name IS NULL) OR (sj.name = @job_name))
  11253.  
  11254.   RETURN(0) -- Success
  11255. END
  11256. go
  11257.  
  11258. /**************************************************************/
  11259. /* SP_TARGET_SERVER_SUMMARY [used by SEM only]                */
  11260. /**************************************************************/
  11261.  
  11262. PRINT ''
  11263. PRINT 'Creating procedure sp_target_server_summary...'
  11264. go
  11265. IF (EXISTS (SELECT *
  11266.             FROM msdb.dbo.sysobjects
  11267.             WHERE (name = N'sp_target_server_summary')
  11268.               AND (type = 'P')))
  11269.   DROP PROCEDURE sp_target_server_summary
  11270. go
  11271. CREATE PROCEDURE sp_target_server_summary
  11272.   @target_server NVARCHAR(30) = NULL
  11273. AS
  11274. BEGIN
  11275.   SET NOCOUNT ON
  11276.  
  11277.   SELECT server_id,
  11278.          server_name,
  11279.         'local_time' = DATEADD(SS, DATEDIFF(SS, last_poll_date, GETDATE()), local_time_at_last_poll),
  11280.          last_poll_date,
  11281.         'unread_instructions' = (SELECT COUNT(*)
  11282.                                  FROM msdb.dbo.sysdownloadlist sdl
  11283.                                  WHERE (sdl.target_server = sts.server_name)
  11284.                                    AND (sdl.status = 0)),
  11285.         'blocked' = (SELECT COUNT(*)
  11286.                      FROM msdb.dbo.sysdownloadlist sdl
  11287.                      WHERE (sdl.target_server = sts.server_name)
  11288.                        AND (sdl.error_message IS NOT NULL)),
  11289.          poll_interval
  11290.   FROM msdb.dbo.systargetservers sts
  11291.   WHERE ((@target_server IS NULL) OR (@target_server = sts.server_name))
  11292. END
  11293. go
  11294.  
  11295. DUMP TRANSACTION msdb WITH NO_LOG
  11296. go
  11297. CHECKPOINT
  11298. go
  11299.  
  11300.  
  11301. /**************************************************************/
  11302. /*                                                            */
  11303. /*         6  .  X     P  R  O  C  E  D  U  R  E  S           */
  11304. /*                                                            */
  11305. /* These procedures are provided for backwards compatability  */
  11306. /* with 6.x scripts and 6.x replication.  The re-implemented  */
  11307. /* procedures are as follows:                                 */
  11308. /*                                                            */
  11309. /* - sp_uniquetaskname  (SQLDMO)                              */
  11310. /* - systasks_view      (INSTDIST.SQL)                        */
  11311. /* - sp_addtask         (INSTREPL.SQL, INSTDIST.SQL, SQLDMO)  */
  11312. /* - sp_updatetask      (INSTDIST.SQL)                        */
  11313. /* - sp_droptask        (INSTREPL.SQL, INSTDIST.SQL, SQLDMO)  */
  11314. /* - sp_helptask        (INSTREPL.SQL, SQLDMO)                */
  11315. /* - sp_verifytaskid    (INSTREPL.SQL)                        */
  11316. /* - sp_reassigntask    (INSTDIST.SQL)                        */
  11317. /* - sp_helphistory     (For completeness only)               */
  11318. /* - sp_purgehistory    (For completeness only)               */
  11319. /* - systasks           (For completeness only)               */
  11320. /**************************************************************/
  11321.  
  11322. /**************************************************************/
  11323. /* SYSTASKS (a view to simulate the 6.x systasks table)       */
  11324. /**************************************************************/
  11325.  
  11326. PRINT ''
  11327. PRINT 'Creating [legacy] table systasks [as a view]...'
  11328. go
  11329. IF (EXISTS (SELECT *
  11330.             FROM msdb.dbo.sysobjects
  11331.             WHERE (name = N'systasks')
  11332.               AND (type = 'U')))
  11333.   DROP TABLE systasks -- Just a precaution in case the systasks table is somehow still lingering around
  11334. IF (EXISTS (SELECT *
  11335.             FROM msdb.dbo.sysobjects
  11336.             WHERE (name = N'systasks')
  11337.               AND (type = 'V')))
  11338.   DROP VIEW systasks
  11339. go
  11340. CREATE VIEW systasks
  11341. AS
  11342.   SELECT 'id'                     = sti.task_id,
  11343.          'name'                   = sj.name,
  11344.          'subsystem'              = sjst.subsystem,
  11345.          'server'                 = sjst.server,
  11346.          'username'               = sjst.database_user_name,
  11347.          'ownerloginid'           = 1, -- Always default to SA since suid is no longer available
  11348.          'databasename'           = sjst.database_name,
  11349.          'enabled'                = sj.enabled,
  11350.          'freqtype'               = ISNULL(sjsch.freq_type, 2), -- On Demand
  11351.          'freqinterval'           = ISNULL(sjsch.freq_interval, 0),
  11352.          'freqsubtype'            = ISNULL(sjsch.freq_subday_type, 0),
  11353.          'freqsubinterval'        = ISNULL(sjsch.freq_subday_interval, 0),
  11354.          'freqrelativeinterval'   = ISNULL(sjsch.freq_relative_interval, 0),
  11355.          'freqrecurrencefactor'   = ISNULL(sjsch.freq_recurrence_factor, 0),
  11356.          'activestartdate'        = ISNULL(sjsch.active_start_date, 19900101),
  11357.          'activeenddate'          = ISNULL(sjsch.active_end_date, 99991231),
  11358.          'activestarttimeofday'   = ISNULL(sjsch.active_start_time, 0),
  11359.          'activeendtimeofday'     = ISNULL(sjsch.active_end_time, 235959),
  11360.          'lastrundate'            = sjs.last_run_date,
  11361.          'lastruntime'            = sjs.last_run_time,
  11362.          'nextrundate'            = ISNULL(sjsch.next_run_date, 0),
  11363.          'nextruntime'            = ISNULL(sjsch.next_run_time, 0),
  11364.          'runpriority'            = sjst.os_run_priority,
  11365.          'emailoperatorid'        = sj.notify_email_operator_id,
  11366.          'retryattempts'          = sjst.retry_attempts,
  11367.          'retrydelay'             = sjst.retry_interval,
  11368.          'datecreated'            = sj.date_created,
  11369.          'datemodified'           = sj.date_modified,
  11370.          'command'                = sjst.command,
  11371.          'lastruncompletionlevel' = sjs.last_run_outcome,
  11372.          'lastrunduration'        = sjst.last_run_duration,
  11373.          'lastrunretries'         = sjst.last_run_retries,
  11374.          'loghistcompletionlevel' = sj.notify_level_eventlog,
  11375.          'emailcompletionlevel'   = sj.notify_level_email,
  11376.          'description'            = sj.description,
  11377.          'tagadditionalinfo'      = 0,
  11378.          'tagobjectid'            = 0,
  11379.          'tagobjecttype'          = 0,
  11380.          'parameters'             = CONVERT(TEXT, sjst.additional_parameters),
  11381.          'cmdexecsuccesscode'     = sjst.cmdexec_success_code
  11382.     FROM msdb.dbo.sysjobs                         sj
  11383.          LEFT OUTER JOIN msdb.dbo.sysjobschedules sjsch ON (sj.job_id = sjsch.job_id),
  11384.          msdb.dbo.systaskids                      sti,
  11385.          msdb.dbo.sysjobsteps                     sjst,
  11386.          msdb.dbo.sysjobservers                   sjs
  11387.     WHERE (sj.job_id = sti.job_id)
  11388.       AND (sj.job_id = sjst.job_id)
  11389.       AND (sjst.step_id = 1)
  11390.       AND (sj.job_id = sjs.job_id)
  11391.       AND (sjs.server_id = 0)
  11392.       AND ((sjsch.name = N'6.x schedule') OR (sjsch.name IS NULL)) -- NULL handles the case of the job not having a schedule
  11393.   UNION ALL -- NOTE: We do this just to make the view non-updatable
  11394.   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
  11395.   WHERE (1 = 2)
  11396. go
  11397.  
  11398. /**************************************************************/
  11399. /* SYSTASKS_VIEW                                              */
  11400. /**************************************************************/
  11401.  
  11402. PRINT ''
  11403. PRINT 'Creating [legacy] view systasks_view...'
  11404. go
  11405. IF (EXISTS (SELECT *
  11406.             FROM msdb.dbo.sysobjects
  11407.             WHERE (name = N'systasks_view')
  11408.               AND (type = 'V')))
  11409.   DROP VIEW systasks_view
  11410. go
  11411. CREATE VIEW systasks_view
  11412. AS
  11413.   SELECT 'id'                     = sti.task_id,
  11414.          'name'                   = sjv.name,
  11415.          'subsystem'              = sjst.subsystem,
  11416.          'server'                 = sjst.server,
  11417.          'username'               = sjst.database_user_name,
  11418.          'ownerloginid'           = 1, -- Always default to SA since suid is no longer available
  11419.          'databasename'           = sjst.database_name,
  11420.          'enabled'                = sjv.enabled,
  11421.          'freqtype'               = ISNULL(sjsch.freq_type, 2), -- On Demand
  11422.          'freqinterval'           = ISNULL(sjsch.freq_interval, 0),
  11423.          'freqsubtype'            = ISNULL(sjsch.freq_subday_type, 0),
  11424.          'freqsubinterval'        = ISNULL(sjsch.freq_subday_interval, 0),
  11425.          'freqrelativeinterval'   = ISNULL(sjsch.freq_relative_interval, 0),
  11426.          'freqrecurrencefactor'   = ISNULL(sjsch.freq_recurrence_factor, 0),
  11427.          'activestartdate'        = ISNULL(sjsch.active_start_date, 19900101),
  11428.          'activeenddate'          = ISNULL(sjsch.active_end_date, 99991231),
  11429.          'activestarttimeofday'   = ISNULL(sjsch.active_start_time, 0),
  11430.          'activeendtimeofday'     = ISNULL(sjsch.active_end_time, 235959),
  11431.          'lastrundate'            = sjs.last_run_date,
  11432.          'lastruntime'            = sjs.last_run_time,
  11433.          'nextrundate'            = ISNULL(sjsch.next_run_date, 0),
  11434.          'nextruntime'            = ISNULL(sjsch.next_run_time, 0),
  11435.          'runpriority'            = sjst.os_run_priority,
  11436.          'emailoperatorid'        = sjv.notify_email_operator_id,
  11437.          'retryattempts'          = sjst.retry_attempts,
  11438.          'retrydelay'             = sjst.retry_interval,
  11439.          'datecreated'            = sjv.date_created,
  11440.          'datemodified'           = sjv.date_modified,
  11441.          'command'                = sjst.command,
  11442.          'lastruncompletionlevel' = sjs.last_run_outcome,
  11443.          'lastrunduration'        = sjst.last_run_duration,
  11444.          'lastrunretries'         = sjst.last_run_retries,
  11445.          'loghistcompletionlevel' = sjv.notify_level_eventlog,
  11446.          'emailcompletionlevel'   = sjv.notify_level_email,
  11447.          'description'            = sjv.description,
  11448.          'tagadditionalinfo'      = 0,
  11449.          'tagobjectid'            = 0,
  11450.          'tagobjecttype'          = 0,
  11451.          'parameters'             = CONVERT(TEXT, sjst.additional_parameters),
  11452.          'cmdexecsuccesscode'     = sjst.cmdexec_success_code
  11453.     FROM msdb.dbo.sysjobs_view                    sjv
  11454.          LEFT OUTER JOIN msdb.dbo.sysjobschedules sjsch ON (sjv.job_id = sjsch.job_id),
  11455.          msdb.dbo.systaskids                      sti,
  11456.          msdb.dbo.sysjobsteps                     sjst,
  11457.          msdb.dbo.sysjobservers                   sjs
  11458.     WHERE (sjv.job_id = sti.job_id)
  11459.       AND (sjv.job_id = sjst.job_id)
  11460.       AND (sjst.step_id = 1)
  11461.       AND (sjv.job_id = sjs.job_id)
  11462.       AND (sjs.server_id = 0)
  11463.       AND ((sjsch.name = N'6.x schedule') OR (sjsch.name IS NULL)) -- NULL handles the case of the job not having a schedule
  11464.   UNION ALL -- NOTE: We do this just to make the view non-updatable
  11465.   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
  11466.   WHERE (1 = 2)
  11467. go
  11468.  
  11469. /**************************************************************/
  11470. /* SP_UNIQUETASKNAME                                          */
  11471. /**************************************************************/
  11472.  
  11473. PRINT ''
  11474. PRINT 'Creating [legacy] procedure sp_uniquetaskname...'
  11475. go
  11476. IF (EXISTS (SELECT *
  11477.             FROM msdb.dbo.sysobjects
  11478.             WHERE (name = N'sp_uniquetaskname')
  11479.               AND (type = 'P')))
  11480.   DROP PROCEDURE sp_uniquetaskname
  11481. go
  11482. CREATE PROCEDURE sp_uniquetaskname
  11483.   @seed NVARCHAR(92)
  11484. AS
  11485. BEGIN
  11486.   DECLARE @newest_suffix INT
  11487.  
  11488.   SET NOCOUNT ON
  11489.  
  11490.   -- We're going to add a suffix of 8 characters so make sure the seed is at most 84 characters
  11491.   SELECT @seed = LTRIM(RTRIM(@seed))
  11492.   IF (DATALENGTH(@seed) > 0)
  11493.     SELECT @seed = SUBSTRING(@seed, 1, 84)
  11494.  
  11495.   -- Find the newest (highest) suffix so far
  11496.   SELECT @newest_suffix = MAX(CONVERT(INT, RIGHT(name, 8)))
  11497.   FROM msdb.dbo.sysjobs -- DON'T use sysjobs_view here!
  11498.   WHERE (name LIKE N'%[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]')
  11499.  
  11500.   -- Generate the task name by appending the 'newest suffix' value (plus one) to the seed
  11501.   IF (@newest_suffix IS NOT NULL)
  11502.   BEGIN
  11503.     SELECT @newest_suffix = @newest_suffix + 1
  11504.     SELECT 'TaskName' = CONVERT(NVARCHAR(92), @seed + REPLICATE(N'0', 8 - (DATALENGTH(CONVERT(NVARCHAR, @newest_suffix)) / 2)) + CONVERT(NVARCHAR, @newest_suffix))
  11505.   END
  11506.   ELSE
  11507.     SELECT 'TaskName' = CONVERT(NVARCHAR(92), @seed + N'00000001')
  11508. END
  11509. go
  11510.  
  11511. /**************************************************************/
  11512. /* SP_ADDTASK                                                 */
  11513. /**************************************************************/
  11514.  
  11515. PRINT ''
  11516. PRINT 'Creating [legacy] procedure sp_addtask...'
  11517. go
  11518. IF (EXISTS (SELECT *
  11519.             FROM msdb.dbo.sysobjects
  11520.             WHERE (name = N'sp_addtask')
  11521.               AND (type = 'P')))
  11522.   DROP PROCEDURE sp_addtask
  11523. go
  11524. CREATE PROCEDURE sp_addtask
  11525.   @name                   sysname,               -- Was VARCHAR(100) in 6.x
  11526.   @subsystem              NVARCHAR(40)   = N'TSQL', -- Was VARCHAR(30) in 6.x
  11527.   @server                 NVARCHAR(30)   = NULL,
  11528.   @username               sysname        = NULL, -- Was VARCHAR(30) in 6.x
  11529.   @databasename           sysname        = NULL, -- Was VARCHAR(30) in 6.x
  11530.   @enabled                TINYINT        = 0,
  11531.   @freqtype               INT            = 2,    -- 2 means OnDemand
  11532.   @freqinterval           INT            = 1,
  11533.   @freqsubtype            INT            = 1,
  11534.   @freqsubinterval        INT            = 1,
  11535.   @freqrelativeinterval   INT            = 1,
  11536.   @freqrecurrencefactor   INT            = 1,
  11537.   @activestartdate        INT            = 0,
  11538.   @activeenddate          INT            = 0,
  11539.   @activestarttimeofday   INT            = 0,
  11540.   @activeendtimeofday     INT            = 0,
  11541.   @nextrundate            INT            = 0,
  11542.   @nextruntime            INT            = 0,
  11543.   @runpriority            INT            = 0,
  11544.   @emailoperatorname      sysname        = NULL, -- Was VARCHAR(50) in 6.x
  11545.   @retryattempts          INT            = 0,
  11546.   @retrydelay             INT            = 10,
  11547.   @command                NVARCHAR(3200) = NULL, -- Was VARCHAR(255) in 6.x
  11548.   @loghistcompletionlevel INT            = 2,
  11549.   @emailcompletionlevel   INT            = 0,
  11550.   @description            NVARCHAR(512)  = NULL, -- Was VARCHAR(255) in 6.x
  11551.   @tagadditionalinfo      VARCHAR(96)    = NULL, -- Obsolete in 7.0
  11552.   @tagobjectid            INT            = NULL, -- Obsolete in 7.0
  11553.   @tagobjecttype          INT            = NULL, -- Obsolete in 7.0
  11554.   @newid                  INT            = NULL OUTPUT,
  11555.   @parameters             NTEXT          = NULL, -- Was TEXT in 6.x
  11556.   @cmdexecsuccesscode     INT            = 0,
  11557.   @category_name          sysname        = NULL, -- New for 7.0
  11558.   @category_id            INT            = NULL  -- New for 7.0
  11559. AS
  11560. BEGIN
  11561.   DECLARE @retval INT
  11562.   DECLARE @job_id UNIQUEIDENTIFIER
  11563.   DECLARE @id     INT
  11564.   DECLARE @distdb sysname
  11565.   DECLARE @proc nvarchar(255)
  11566.  
  11567.   SET NOCOUNT ON
  11568.  
  11569.   SELECT @retval = 1 -- 0 means success, 1 means failure
  11570.  
  11571.   -- Set 7.0 category names for 6.5 replication tasks
  11572.   IF (LOWER(@subsystem) = N'sync')
  11573.     SELECT @category_id = 15
  11574.   ELSE IF (LOWER(@subsystem) = N'logreader')
  11575.     SELECT @category_id = 13
  11576.   ELSE IF (LOWER(@subsystem) = N'distribution')
  11577.     SELECT @category_id = 10
  11578.  
  11579.   -- Convert old replication synchronization subsystem name to the 7.0 name
  11580.   IF (LOWER(@subsystem) = N'sync')
  11581.     SELECT @subsystem = N'Snapshot'
  11582.  
  11583.   -- If a category ID is provided this overrides any supplied category name
  11584.   IF (@category_id IS NOT NULL)
  11585.   BEGIN
  11586.     SELECT @category_name = name
  11587.     FROM msdb.dbo.syscategories
  11588.     WHERE (category_id = @category_id)
  11589.     SELECT @category_name = ISNULL(@category_name, FORMATMESSAGE(14205))
  11590.   END
  11591.  
  11592.   -- In 6.x active start date was not restricted, but it is in 7.0; so to avoid a "noisey"
  11593.   -- failure in sp_add_jobschedule we modify the value accordingly
  11594.   IF ((@activestartdate <> 0) AND (@activestartdate < 19900101))
  11595.     SELECT @activestartdate = 19900101
  11596.  
  11597.   BEGIN TRANSACTION
  11598.  
  11599.     -- Add the job
  11600.     EXECUTE @retval = sp_add_job
  11601.       @job_name                   = @name,
  11602.       @enabled                    = @enabled,
  11603.       @start_step_id              = 1,
  11604.       @description                = @description,
  11605.       @category_name              = @category_name,
  11606.       @notify_level_eventlog      = @loghistcompletionlevel,
  11607.       @notify_level_email         = @emailcompletionlevel,
  11608.       @notify_email_operator_name = @emailoperatorname,
  11609.       @job_id                     = @job_id OUTPUT
  11610.  
  11611.     IF (@retval <> 0)
  11612.     BEGIN
  11613.       ROLLBACK TRANSACTION
  11614.       GOTO Quit
  11615.     END
  11616.  
  11617.     -- Add an entry to systaskids for the new job (created by a 6.x client)
  11618.     INSERT INTO msdb.dbo.systaskids (job_id) VALUES (@job_id)
  11619.  
  11620.     -- Get the assigned task id
  11621.     SELECT @id = task_id, @newid = task_id
  11622.     FROM msdb.dbo.systaskids
  11623.     WHERE (job_id = @job_id)
  11624.  
  11625.     -- Add the job step
  11626.     EXECUTE @retval = sp_add_jobstep
  11627.       @job_id                = @job_id,
  11628.       @step_id               = 1,
  11629.       @step_name             = N'Step 1',
  11630.       @subsystem             = @subsystem,
  11631.       @command               = @command,
  11632.       @additional_parameters = @parameters,
  11633.       @cmdexec_success_code  = @cmdexecsuccesscode,
  11634.       @server                = @server,
  11635.       @database_name         = @databasename,
  11636.       @database_user_name    = @username,
  11637.       @retry_attempts        = @retryattempts,
  11638.       @retry_interval        = @retrydelay,
  11639.       @os_run_priority       = @runpriority
  11640.  
  11641.     IF (@retval <> 0)
  11642.     BEGIN
  11643.       ROLLBACK TRANSACTION
  11644.       GOTO Quit
  11645.     END
  11646.  
  11647.     -- Add the job schedule
  11648.     IF (@activestartdate = 0)
  11649.       SELECT @activestartdate = NULL
  11650.     IF (@activeenddate = 0)
  11651.       SELECT @activeenddate = NULL
  11652.     IF (@activestarttimeofday = 0)
  11653.       SELECT @activestarttimeofday = NULL
  11654.     IF (@activeendtimeofday = 0)
  11655.       SELECT @activeendtimeofday = NULL
  11656.     IF (@freqtype <> 0x2) -- OnDemand tasks simply have no schedule in 7.0
  11657.     BEGIN
  11658.       EXECUTE @retval = sp_add_jobschedule
  11659.         @job_id                 = @job_id,
  11660.         @name                   = N'6.x schedule',
  11661.         @enabled                = 1,
  11662.         @freq_type              = @freqtype,
  11663.         @freq_interval          = @freqinterval,
  11664.         @freq_subday_type       = @freqsubtype,
  11665.         @freq_subday_interval   = @freqsubinterval,
  11666.         @freq_relative_interval = @freqrelativeinterval,
  11667.         @freq_recurrence_factor = @freqrecurrencefactor,
  11668.         @active_start_date      = @activestartdate,
  11669.         @active_end_date        = @activeenddate,
  11670.         @active_start_time      = @activestarttimeofday,
  11671.         @active_end_time        = @activeendtimeofday
  11672.  
  11673.       IF (@retval <> 0)
  11674.       BEGIN
  11675.         ROLLBACK TRANSACTION
  11676.         GOTO Quit
  11677.       END
  11678.     END
  11679.  
  11680.     -- And finally, add the job server
  11681.     EXECUTE @retval = sp_add_jobserver @job_id = @job_id, @server_name = NULL
  11682.  
  11683.     IF (@retval <> 0)
  11684.     BEGIN
  11685.       ROLLBACK TRANSACTION
  11686.       GOTO Quit
  11687.     END
  11688.  
  11689.     -- Add the replication agent for monitoring
  11690.     IF (@category_id = 13) -- Logreader
  11691.     BEGIN
  11692.       SELECT @distdb = distribution_db from MSdistpublishers where name = @server
  11693.       SELECT @proc = @distdb + '.dbo.sp_MSadd_logreader_agent'
  11694.  
  11695.       EXECUTE @retval = @proc
  11696.         @name = @name,
  11697.         @publisher = @server,
  11698.         @publisher_db = @databasename,
  11699.         @publication = '',
  11700.         @local_job = 1,
  11701.         @job_existing = 1,
  11702.         @job_id = @job_id
  11703.  
  11704.       IF (@retval <> 0)
  11705.       BEGIN
  11706.         ROLLBACK TRANSACTION
  11707.         GOTO Quit
  11708.       END
  11709.     END
  11710.     ELSE
  11711.     IF (@category_id = 15) -- Snapshot
  11712.     BEGIN
  11713.       DECLARE @publication sysname
  11714.  
  11715.       EXECUTE @retval = master.dbo.sp_MSget_publication_from_taskname
  11716.                             @taskname = @name,
  11717.                             @publisher = @server,
  11718.                             @publisherdb = @databasename,
  11719.                             @publication = @publication OUTPUT
  11720.  
  11721.       IF (@publication IS NOT NULL)
  11722.       BEGIN
  11723.  
  11724.         SELECT @distdb = distribution_db from MSdistpublishers where name = @server
  11725.         SELECT @proc = @distdb + '.dbo.sp_MSadd_snapshot_agent'
  11726.  
  11727.         EXECUTE @retval = @proc
  11728.                 @name = @name,
  11729.                 @publisher = @server,
  11730.                 @publisher_db = @databasename,
  11731.                 @publication = @publication,
  11732.                 @local_job = 1,
  11733.                 @job_existing = 1,
  11734.                 @snapshot_jobid = @job_id
  11735.  
  11736.         IF (@retval <> 0)
  11737.         BEGIN
  11738.           ROLLBACK TRANSACTION
  11739.           GOTO Quit
  11740.         END
  11741.  
  11742.         SELECT @proc = @distdb + '.dbo.sp_MSadd_publication'
  11743.         EXECUTE @retval = @proc
  11744.                 @publisher = @server,
  11745.                 @publisher_db = @databasename,
  11746.                 @publication = @publication,
  11747.                 @publication_type = 0 -- Transactional
  11748.         IF (@retval <> 0)
  11749.         BEGIN
  11750.           ROLLBACK TRANSACTION
  11751.           GOTO Quit
  11752.         END
  11753.       END
  11754.     END
  11755.  
  11756.   COMMIT TRANSACTION
  11757.  
  11758.   -- If this is an autostart LogReader or Distribution job, add the [new] '-Continuous' paramter to the command
  11759.   IF (@freqtype = 0x40) AND ((UPPER(@subsystem) = N'LOGREADER') OR (UPPER(@subsystem) = N'DISTRIBUTION'))
  11760.   BEGIN
  11761.     UPDATE msdb.dbo.sysjobsteps
  11762.     SET command = command + N' -Continuous'
  11763.     WHERE (job_id = @job_id)
  11764.       AND (step_id = 1)
  11765.   END
  11766.  
  11767.   -- If this is an autostart job, start it now (for backwards compatibility with 6.x SQLExecutive behaviour)
  11768.   IF (@freqtype = 0x40)
  11769.     EXECUTE msdb.dbo.sp_start_job @job_id = @job_id, @error_flag = 0, @output_flag = 0
  11770.  
  11771. Quit:
  11772.   RETURN(@retval) -- 0 means success
  11773.  
  11774. END
  11775. go
  11776.  
  11777. /**************************************************************/
  11778. /* SP_UPDATETASK                                              */
  11779. /**************************************************************/
  11780.  
  11781. PRINT ''
  11782. PRINT 'Creating [legacy] procedure sp_updatetask...'
  11783. go
  11784. IF (EXISTS (SELECT *
  11785.             FROM msdb.dbo.sysobjects
  11786.             WHERE (name = N'sp_updatetask')
  11787.               AND (type = 'P')))
  11788.   DROP PROCEDURE sp_updatetask
  11789. go
  11790. CREATE PROCEDURE sp_updatetask
  11791.   @currentname            sysname        = NULL, -- Was VARCHAR(100) in 6.x
  11792.   @id                     INT            = NULL,
  11793.   @name                   sysname        = NULL, -- Was VARCHAR(100) in 6.x
  11794.   @subsystem              NVARCHAR(40)   = NULL, -- Was VARCHAR(30) in 6.x
  11795.   @server                 NVARCHAR(30)   = NULL, -- Was VARCHAR(30) in 6.x
  11796.   @username               sysname        = NULL, -- Was VARCHAR(30) in 6.x
  11797.   @databasename           sysname        = NULL, -- Was VARCHAR(30) in 6.x
  11798.   @enabled                TINYINT        = NULL,
  11799.   @freqtype               INT            = NULL,
  11800.   @freqinterval           INT            = NULL,
  11801.   @freqsubtype            INT            = NULL,
  11802.   @freqsubinterval        INT            = NULL,
  11803.   @freqrelativeinterval   INT            = NULL,
  11804.   @freqrecurrencefactor   INT            = NULL,
  11805.   @activestartdate        INT            = NULL,
  11806.   @activeenddate          INT            = NULL,
  11807.   @activestarttimeofday   INT            = NULL,
  11808.   @activeendtimeofday     INT            = NULL,
  11809.   @nextrundate            INT            = NULL,
  11810.   @nextruntime            INT            = NULL,
  11811.   @runpriority            INT            = NULL,
  11812.   @emailoperatorname      sysname        = NULL, -- Was VARCHAR(50) in 6.x
  11813.   @retryattempts          INT            = NULL,
  11814.   @retrydelay             INT            = NULL,
  11815.   @command                NVARCHAR(3200) = NULL,
  11816.   @loghistcompletionlevel INT            = NULL,
  11817.   @emailcompletionlevel   INT            = NULL,
  11818.   @description            VARCHAR(512)   = NULL,
  11819.   @tagadditionalinfo      VARCHAR(96)    = NULL, -- Obsolete in 7.0
  11820.   @tagobjectid            INT            = NULL, -- Obsolete in 7.0
  11821.   @tagobjecttype          INT            = NULL, -- Obsolete in 7.0
  11822.   @parameters             TEXT           = NULL,
  11823.   @cmdexecsuccesscode     INT            = NULL
  11824. AS
  11825. BEGIN
  11826.   DECLARE @retval INT
  11827.   DECLARE @job_id UNIQUEIDENTIFIER
  11828.  
  11829.   SET NOCOUNT ON
  11830.  
  11831.   SELECT @retval = 1 -- 0 means success, 1 means failure
  11832.  
  11833.   -- Convert old replication synchronization subsystem name to the 7.0 name
  11834.   IF (LOWER(@subsystem) = N'sync')
  11835.     SELECT @subsystem = N'Snapshot'
  11836.  
  11837.   IF ((@id IS NULL) AND (@currentname IS NULL)) OR
  11838.      ((@id IS NOT NULL) AND (@currentname IS NOT NULL))
  11839.   BEGIN
  11840.     RAISERROR(14246, -1, -1)
  11841.     RETURN(1) -- Failure
  11842.   END
  11843.  
  11844.   -- In 6.x active start date was not restricted, but it is in 7.0; so to avoid a "noisey"
  11845.   -- failure in sp_update_jobschedule we modify the value accordingly
  11846.   IF ((@activestartdate IS NOT NULL) AND (@activestartdate < 19900101))
  11847.     SELECT @activestartdate = 19900101
  11848.  
  11849.   -- If the name is supplied, get the job_id directly from sysjobs
  11850.   IF (@currentname IS NOT NULL)
  11851.   BEGIN
  11852.     -- Check if the name is ambiguous
  11853.     IF ((SELECT COUNT(*)
  11854.          FROM msdb.dbo.sysjobs_view
  11855.          WHERE (name = @currentname)) > 1)
  11856.     BEGIN
  11857.       RAISERROR(14292, -1, -1, @currentname, '@id', '@currentname')
  11858.       RETURN(1) -- Failure
  11859.     END
  11860.  
  11861.     SELECT @job_id = job_id
  11862.     FROM msdb.dbo.sysjobs_view
  11863.     WHERE (name = @currentname)
  11864.  
  11865.     SELECT @id = task_id
  11866.     FROM msdb.dbo.systaskids
  11867.     WHERE (job_id = @job_id)
  11868.  
  11869.     IF (@job_id IS NULL)
  11870.     BEGIN
  11871.       RAISERROR(14262, -1, -1, '@currentname', @currentname)
  11872.       RETURN(1) -- Failure
  11873.     END
  11874.   END
  11875.  
  11876.   -- If the id is supplied lookup the corresponding job_id from systaskids
  11877.   IF (@id IS NOT NULL)
  11878.   BEGIN
  11879.     SELECT @job_id = job_id
  11880.     FROM msdb.dbo.systaskids
  11881.     WHERE (task_id = @id)
  11882.  
  11883.     -- Check that the job still exists
  11884.     IF (NOT EXISTS (SELECT *
  11885.                     FROM msdb.dbo.sysjobs_view
  11886.                     WHERE (job_id = @job_id)))
  11887.     BEGIN
  11888.       SELECT @currentname = CONVERT(NVARCHAR, @id)
  11889.       RAISERROR(14262, -1, -1, '@id', @currentname)
  11890.       RETURN(1) -- Failure
  11891.     END
  11892.   END
  11893.  
  11894.   -- Do the update
  11895.   BEGIN TRANSACTION
  11896.  
  11897.     -- Update the Job Step
  11898.     IF (@subsystem          IS NOT NULL) OR
  11899.        (@command            IS NOT NULL) OR
  11900.        (@cmdexecsuccesscode IS NOT NULL) OR
  11901.        (@server             IS NOT NULL) OR
  11902.        (@databasename       IS NOT NULL) OR
  11903.        (@username           IS NOT NULL) OR
  11904.        (@retryattempts      IS NOT NULL) OR
  11905.        (@retrydelay         IS NOT NULL) OR
  11906.        (@runpriority        IS NOT NULL)
  11907.     BEGIN
  11908.       EXECUTE @retval = sp_update_jobstep
  11909.         @job_id               = @job_id,
  11910.         @step_id              = 1,
  11911.         @subsystem            = @subsystem,
  11912.         @command              = @command,
  11913.         @cmdexec_success_code = @cmdexecsuccesscode,
  11914.         @server               = @server,
  11915.         @database_name        = @databasename,
  11916.         @database_user_name   = @username,
  11917.         @retry_attempts       = @retryattempts,
  11918.         @retry_interval       = @retrydelay,
  11919.         @os_run_priority      = @runpriority
  11920.  
  11921.       IF (@retval <> 0)
  11922.       BEGIN
  11923.         ROLLBACK TRANSACTION
  11924.         GOTO Quit
  11925.       END
  11926.     END
  11927.  
  11928.     -- Now update the job itself
  11929.     IF (@name                   IS NOT NULL) OR
  11930.        (@enabled                IS NOT NULL) OR
  11931.        (@description            IS NOT NULL) OR
  11932.        (@loghistcompletionlevel IS NOT NULL) OR
  11933.        (@emailcompletionlevel   IS NOT NULL) OR
  11934.        (@emailoperatorname      IS NOT NULL)
  11935.     BEGIN
  11936.       EXECUTE @retval = sp_update_job
  11937.         @job_id                     = @job_id,
  11938.         @new_name                   = @name,
  11939.         @enabled                    = @enabled,
  11940.         @description                = @description,
  11941.         @notify_level_eventlog      = @loghistcompletionlevel,
  11942.         @notify_level_email         = @emailcompletionlevel,
  11943.         @notify_email_operator_name = @emailoperatorname
  11944.  
  11945.     IF (@retval <> 0)
  11946.       BEGIN
  11947.         ROLLBACK TRANSACTION
  11948.         GOTO Quit
  11949.       END
  11950.     END
  11951.  
  11952.     -- Finally, update the job schedule
  11953.     IF (@freqtype             IS NOT NULL) OR
  11954.        (@freqinterval         IS NOT NULL) OR
  11955.        (@freqsubtype          IS NOT NULL) OR
  11956.        (@freqsubinterval      IS NOT NULL) OR
  11957.        (@freqrelativeinterval IS NOT NULL) OR
  11958.        (@freqrecurrencefactor IS NOT NULL) OR
  11959.        (@activestartdate      IS NOT NULL) OR
  11960.        (@activeenddate        IS NOT NULL) OR
  11961.        (@activestarttimeofday IS NOT NULL) OR
  11962.        (@activeendtimeofday   IS NOT NULL)
  11963.     BEGIN
  11964.       IF (@freqtype = 0x2)
  11965.       BEGIN
  11966.         -- OnDemand tasks simply have no schedule in 7.0, so delete the job schedule
  11967.         EXECUTE @retval = sp_delete_jobschedule
  11968.           @job_id = @job_id,
  11969.           @name   = N'6.x schedule'
  11970.       END
  11971.       ELSE
  11972.       BEGIN
  11973.         IF (NOT EXISTS (SELECT *
  11974.                         FROM msdb.dbo.sysjobschedules
  11975.                         WHERE (job_id = @job_id)
  11976.                           AND (name = N'6.x schedule')))
  11977.           EXECUTE @retval = sp_add_jobschedule
  11978.             @job_id                 = @job_id,
  11979.             @name                   = N'6.x schedule',
  11980.             @enabled                = 1,
  11981.             @freq_type              = @freqtype,
  11982.             @freq_interval          = @freqinterval,
  11983.             @freq_subday_type       = @freqsubtype,
  11984.             @freq_subday_interval   = @freqsubinterval,
  11985.             @freq_relative_interval = @freqrelativeinterval,
  11986.             @freq_recurrence_factor = @freqrecurrencefactor,
  11987.             @active_start_date      = @activestartdate,
  11988.             @active_end_date        = @activeenddate,
  11989.             @active_start_time      = @activestarttimeofday,
  11990.             @active_end_time        = @activeendtimeofday
  11991.         ELSE
  11992.           EXECUTE @retval = sp_update_jobschedule
  11993.             @job_id                 = @job_id,
  11994.             @name                   = N'6.x schedule',
  11995.             @enabled                = 1,
  11996.             @freq_type              = @freqtype,
  11997.             @freq_interval          = @freqinterval,
  11998.             @freq_subday_type       = @freqsubtype,
  11999.             @freq_subday_interval   = @freqsubinterval,
  12000.             @freq_relative_interval = @freqrelativeinterval,
  12001.             @freq_recurrence_factor = @freqrecurrencefactor,
  12002.             @active_start_date      = @activestartdate,
  12003.             @active_end_date        = @activeenddate,
  12004.             @active_start_time      = @activestarttimeofday,
  12005.             @active_end_time        = @activeendtimeofday
  12006.       END
  12007.  
  12008.       IF (@retval <> 0)
  12009.       BEGIN
  12010.         ROLLBACK TRANSACTION
  12011.         GOTO Quit
  12012.       END
  12013.     END
  12014.  
  12015.   COMMIT TRANSACTION
  12016.  
  12017. Quit:
  12018.   RETURN(@retval) -- 0 means success
  12019.  
  12020. END
  12021. go
  12022.  
  12023. /**************************************************************/
  12024. /* SP_DROPTASK                                                */
  12025. /**************************************************************/
  12026.  
  12027. PRINT ''
  12028. PRINT 'Creating [legacy] procedure sp_droptask...'
  12029. go
  12030. IF (EXISTS (SELECT *
  12031.             FROM msdb.dbo.sysobjects
  12032.             WHERE (name = N'sp_droptask')
  12033.               AND (type = 'P')))
  12034.   DROP PROCEDURE sp_droptask
  12035. go
  12036. CREATE PROCEDURE sp_droptask
  12037.   @name      sysname = NULL, -- Was VARCHAR(100) in 6.x
  12038.   @loginname sysname = NULL, -- Was VARCHAR(30) in 6.x
  12039.   @id        INT     = NULL
  12040. AS
  12041. BEGIN
  12042.   DECLARE @retval INT
  12043.   DECLARE @job_id UNIQUEIDENTIFIER
  12044.   DECLARE @category_id int
  12045.  
  12046.   SET NOCOUNT ON
  12047.  
  12048.   IF ((@name      IS NULL)     AND (@id    IS NULL)     AND (@loginname IS NULL)) OR
  12049.      ((@name      IS NOT NULL) AND ((@id   IS NOT NULL) OR  (@loginname IS NOT NULL))) OR
  12050.      ((@id        IS NOT NULL) AND ((@name IS NOT NULL) OR  (@loginname IS NOT NULL))) OR
  12051.      ((@loginname IS NOT NULL) AND ((@name IS NOT NULL) OR  (@id        IS NOT NULL)))
  12052.   BEGIN
  12053.     RAISERROR(14245, -1, -1)
  12054.     RETURN(1) -- Failure
  12055.   END
  12056.  
  12057.   -- If the name is supplied, get the job_id directly from sysjobs
  12058.   IF (@name IS NOT NULL)
  12059.   BEGIN
  12060.     -- Check if the name is ambiguous
  12061.     IF ((SELECT COUNT(*)
  12062.          FROM msdb.dbo.sysjobs_view
  12063.          WHERE (name = @name)) > 1)
  12064.     BEGIN
  12065.       RAISERROR(14292, -1, -1, @name, '@id', '@name')
  12066.       RETURN(1) -- Failure
  12067.     END
  12068.  
  12069.     SELECT @job_id = job_id, @category_id = category_id
  12070.     FROM msdb.dbo.sysjobs_view
  12071.     WHERE (name = @name)
  12072.  
  12073.     SELECT @id = task_id
  12074.     FROM msdb.dbo.systaskids
  12075.     WHERE (job_id = @job_id)
  12076.  
  12077.     IF (@job_id IS NULL)
  12078.     BEGIN
  12079.       RAISERROR(14262, -1, -1, '@name', @name)
  12080.       RETURN(1) -- Failure
  12081.     END
  12082.   END
  12083.  
  12084.   -- If the id is supplied lookup the corresponding job_id from systaskids
  12085.   IF (@id IS NOT NULL)
  12086.   BEGIN
  12087.     SELECT @job_id = job_id
  12088.     FROM msdb.dbo.systaskids
  12089.     WHERE (task_id = @id)
  12090.  
  12091.     -- Check that the job still exists
  12092.     IF (NOT EXISTS (SELECT *
  12093.                     FROM msdb.dbo.sysjobs_view
  12094.                     WHERE (job_id = @job_id)))
  12095.     BEGIN
  12096.       SELECT @name = CONVERT(NVARCHAR, @id)
  12097.       RAISERROR(14262, -1, -1, '@id', @name)
  12098.       RETURN(1) -- Failure
  12099.     END
  12100.  
  12101.     -- Get the name of this job
  12102.     SELECT @name = name, @category_id = category_id
  12103.     FROM msdb.dbo.sysjobs_view
  12104.     WHERE (job_id = @job_id)
  12105.   END
  12106.  
  12107.   -- Delete the specific job
  12108.   IF (@name IS NOT NULL)
  12109.   BEGIN
  12110.     BEGIN TRANSACTION
  12111.  
  12112.     DELETE FROM msdb.dbo.systaskids
  12113.     WHERE (job_id = @job_id)
  12114.     EXECUTE @retval = sp_delete_job @job_id = @job_id
  12115.     IF (@retval <> 0)
  12116.     BEGIN
  12117.       ROLLBACK TRANSACTION
  12118.       GOTO Quit
  12119.     END
  12120.  
  12121.     -- If a Logreader or Snapshot task, delete corresponding replication agent information
  12122.     IF @category_id = 13 or @category_id = 15
  12123.     BEGIN
  12124.          EXECUTE @retval = sp_MSdrop_6x_replication_agent @job_id, @category_id
  12125.       IF (@retval <> 0)
  12126.       BEGIN
  12127.           ROLLBACK TRANSACTION
  12128.           GOTO Quit
  12129.       END
  12130.     END
  12131.  
  12132.  
  12133.     COMMIT TRANSACTION
  12134.   END
  12135.  
  12136.   -- Delete all jobs belonging to the specified login
  12137.   IF (@loginname IS NOT NULL)
  12138.   BEGIN
  12139.     BEGIN TRANSACTION
  12140.  
  12141.     DELETE FROM msdb.dbo.systaskids
  12142.     WHERE job_id IN (SELECT job_id
  12143.                      FROM msdb.dbo.sysjobs_view
  12144.                      WHERE (owner_sid = SUSER_SID(@loginname)))
  12145.     EXECUTE @retval = sp_manage_jobs_by_login @action = 'DELETE',
  12146.                                               @current_owner_login_name = @loginname
  12147.     IF (@retval <> 0)
  12148.     BEGIN
  12149.       ROLLBACK TRANSACTION
  12150.       GOTO Quit
  12151.     END        
  12152.  
  12153.     COMMIT TRANSACTION
  12154.   END
  12155.  
  12156. Quit:
  12157.   RETURN(@retval) -- 0 means success
  12158.  
  12159. END
  12160. go
  12161.  
  12162.  
  12163. /**************************************************************/
  12164. /* SP_HELPTASK                                                */
  12165. /**************************************************************/
  12166.  
  12167. PRINT ''
  12168. PRINT 'Creating [legacy] procedure procedure sp_helptask...'
  12169. go
  12170. IF (EXISTS (SELECT *
  12171.             FROM msdb.dbo.sysobjects
  12172.             WHERE (name = N'sp_helptask')
  12173.               AND (type = 'P')))
  12174.   DROP PROCEDURE sp_helptask
  12175. go
  12176. CREATE PROCEDURE sp_helptask
  12177.   @taskname     sysname      = NULL, -- Was VARCHAR(100) in 6.x
  12178.   @taskid       INT          = NULL,
  12179.   @loginname    sysname      = NULL, -- Was VARCHAR(20) in 6.x
  12180.   @operatorname sysname      = NULL, -- Was VARCHAR(50) in 6.x
  12181.   @subsystem    NVARCHAR(40) = NULL, -- Was VARCHAR(30) in 6.x
  12182.   @mode         VARCHAR(10)  = 'QUICK'  -- Or 'FULL'
  12183. AS
  12184. BEGIN
  12185.   DECLARE @operator_id INT
  12186.   DECLARE @owner_sid   VARBINARY(85)
  12187.  
  12188.   SET NOCOUNT ON
  12189.  
  12190.   -- Convert old replication synchronization subsystem name to the 7.0 name
  12191.   IF (LOWER(@subsystem) = N'sync')
  12192.     SELECT @subsystem = N'Snapshot'
  12193.  
  12194.   -- Get the login id for the login name (if supplied)
  12195.   IF (@loginname IS NOT NULL)
  12196.   BEGIN
  12197.     IF (ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) = 0) AND (SUSER_SNAME() <> @loginname)
  12198.     BEGIN
  12199.       RAISERROR(14247, -1, -1)
  12200.       RETURN(1) -- Failure
  12201.     END
  12202.  
  12203.     SELECT @owner_sid = SUSER_ID(@loginname)
  12204.     IF (@owner_sid IS NULL)
  12205.     BEGIN
  12206.       RAISERROR(14234, -1, -1, '@loginname', 'sp_helplogins')
  12207.       RETURN(1) -- Failure
  12208.     END
  12209.   END
  12210.  
  12211.   -- Get the operator id for the operator name (if supplied)
  12212.   IF (@operatorname IS NOT NULL)
  12213.   BEGIN
  12214.     SELECT @operator_id = id
  12215.     FROM msdb.dbo.sysoperators
  12216.     WHERE (name = @operatorname)
  12217.  
  12218.     IF (@operator_id IS NULL)
  12219.     BEGIN
  12220.       RAISERROR(14262, -1, -1, '@operatorname', @operatorname)
  12221.       RETURN(1) -- Failure
  12222.     END
  12223.   END
  12224.  
  12225.   -- Check the mode
  12226.   SELECT @mode = UPPER(@mode)
  12227.   IF (@mode NOT IN ('FULL', 'QUICK'))
  12228.   BEGIN
  12229.     RAISERROR(14266, -1, -1, '@mode', 'FULL, QUICK')
  12230.     RETURN(1) -- Failure
  12231.   END
  12232.  
  12233.   -- Return task details...
  12234.   -- NOTE: SQLOLE and Starfighter rely on the 'FULL' mode format - do not change it!
  12235.   IF (@mode = 'FULL')
  12236.   BEGIN
  12237.     SELECT name                   = sjv.name,
  12238.            id                     = sti.task_id,
  12239.            subsystem              = sjst.subsystem,
  12240.            server                 = sjst.server,
  12241.            username               = sjst.database_user_name,
  12242.            ownerloginname         = SUSER_SNAME(sjv.owner_sid),
  12243.            databasename           = sjst.database_name,
  12244.            enabled                = sjv.enabled,
  12245.            freqtype               = ISNULL(sjsch.freq_type, 2), -- On Demand
  12246.            freqinterval           = ISNULL(sjsch.freq_interval, 0),
  12247.            freqsubtype            = ISNULL(sjsch.freq_subday_type, 0),
  12248.            freqsubinterval        = ISNULL(sjsch.freq_subday_interval, 0),
  12249.            freqrelativeinterval   = ISNULL(sjsch.freq_relative_interval, 0),
  12250.            freqrecurrencefactor   = ISNULL(sjsch.freq_recurrence_factor, 0),
  12251.            activestartdate        = ISNULL(sjsch.active_start_date, 19900101),
  12252.            activeenddate          = ISNULL(sjsch.active_end_date, 99991231),
  12253.            activestarttimeofday   = ISNULL(sjsch.active_start_time, 0),
  12254.            activeendtimeofday     = ISNULL(sjsch.active_end_time, 235959),
  12255.            lastrundate            = sjs.last_run_date,
  12256.            lastruntime            = sjs.last_run_time,
  12257.            nextrundate            = ISNULL(sjsch.next_run_date, 0),
  12258.            nextruntime            = ISNULL(sjsch.next_run_time, 0),
  12259.            runpriority            = sjst.os_run_priority,
  12260.            emailoperatorname      = so.name,
  12261.            retryattempts          = sjst.retry_attempts,
  12262.            retrydelay             = sjst.retry_interval,
  12263.            datecreated            = sjv.date_created,
  12264.            datemodified           = sjv.date_modified,
  12265.            command                = sjst.command,
  12266.            lastruncompletionlevel = sjs.last_run_outcome,
  12267.            lastrunduration        = sjst.last_run_duration,
  12268.            lastrunretries         = sjst.last_run_retries,
  12269.            loghistcompletionlevel = sjv.notify_level_eventlog,
  12270.            emailcompletionlevel   = sjv.notify_level_email,
  12271.            description            = sjv.description,
  12272.            tagadditionalinfo      = 0,
  12273.            tagobjectid            = 0,
  12274.            tagobjecttype          = 0,
  12275.            cmdexecsuccesscode     = sjst.cmdexec_success_code
  12276.     FROM msdb.dbo.sysjobs_view                    sjv
  12277.          LEFT OUTER JOIN msdb.dbo.sysoperators    so    ON (sjv.notify_email_operator_id = so.id)
  12278.          LEFT OUTER JOIN msdb.dbo.systaskids      sti   ON (sjv.job_id = sti.job_id)
  12279.          LEFT OUTER JOIN msdb.dbo.sysjobschedules sjsch ON (sjv.job_id = sjsch.job_id),
  12280.          msdb.dbo.sysjobsteps                     sjst,
  12281.          msdb.dbo.sysjobservers                   sjs
  12282.     WHERE (sjv.job_id = sjst.job_id)
  12283.       AND (sjst.step_id = 1)
  12284.       AND (sjv.job_id = sjs.job_id)
  12285.       AND (sjs.server_id = 0)
  12286.       AND ((sjsch.name = N'6.x schedule') OR (sjsch.name IS NULL)) -- NULL handles the case of the job not having a schedule
  12287.       AND ((@owner_sid      IS NULL) OR (sjv.owner_sid                = @owner_sid))
  12288.       AND ((@subsystem      IS NULL) OR (sjst.subsystem               = @subsystem))
  12289.       AND ((@operator_id    IS NULL) OR (sjv.notify_email_operator_id = @operator_id))
  12290.       AND ((@taskname       IS NULL) OR (sjv.name                     = @taskname))
  12291.       AND ((@taskid         IS NULL) OR (sti.task_id                  = @taskid))
  12292.     ORDER BY sj.name
  12293.   END
  12294.   ELSE
  12295.   BEGIN
  12296.     SELECT name      = SUBSTRING(sjv.name, 1, 20),
  12297.            id        = sti.task_id,
  12298.            subsystem = SUBSTRING(sjst.subsystem, 1, 15),
  12299.            server    = SUBSTRING(sjst.server, 1, 20),
  12300.            username  = SUBSTRING(sjst.database_user_name, 1, 20),
  12301.            dbname    = SUBSTRING(sjst.database_name, 1, 20),
  12302.            enabled   = sjv.enabled
  12303.     FROM msdb.dbo.sysjobs_view               sjv
  12304.          LEFT OUTER JOIN msdb.dbo.systaskids sti ON (sjv.job_id = sti.job_id),
  12305.          msdb.dbo.sysjobsteps                sjst
  12306.     WHERE (sjv.job_id = sjst.job_id)
  12307.       AND (sjst.step_id = 1)
  12308.       AND ((@owner_sid      IS NULL) OR (sjv.owner_sid                = @owner_sid))
  12309.       AND ((@subsystem      IS NULL) OR (sjst.subsystem               = @subsystem))
  12310.       AND ((@operator_id    IS NULL) OR (sjv.notify_email_operator_id = @operator_id))
  12311.       AND ((@taskname       IS NULL) OR (sjv.name                     = @taskname))
  12312.       AND ((@taskid         IS NULL) OR (sti.task_id                  = @taskid))
  12313.     ORDER BY sjv.name
  12314.   END
  12315. END
  12316. go
  12317.  
  12318. DUMP TRANSACTION msdb WITH NO_LOG
  12319. go
  12320. CHECKPOINT
  12321. go
  12322.  
  12323. /**************************************************************/
  12324. /* SP_VERIFYTASKID                                            */
  12325. /**************************************************************/
  12326.  
  12327. PRINT ''
  12328. PRINT 'Creating [legacy] procedure procedure sp_verifytaskid...'
  12329. go
  12330. IF (EXISTS (SELECT *
  12331.             FROM msdb.dbo.sysobjects
  12332.             WHERE (name = N'sp_verifytaskid')
  12333.               AND (type = 'P')))
  12334.   DROP PROCEDURE sp_verifytaskid
  12335. go
  12336. CREATE PROCEDURE sp_verifytaskid
  12337.   @taskid    INT,
  12338.   @subsystem NVARCHAR(40) = N'%'
  12339. AS
  12340. BEGIN
  12341.   SET NOCOUNT ON
  12342.  
  12343.   -- Convert old replication synchronization subsystem name to the 7.0 name
  12344.   IF (LOWER(@subsystem) = N'sync')
  12345.     SELECT @subsystem = N'Snapshot'
  12346.  
  12347.   -- Check if the task [job] exists
  12348.   IF (EXISTS (SELECT *
  12349.               FROM msdb.dbo.sysjobs_view sjv,
  12350.                    msdb.dbo.sysjobsteps  sjst,
  12351.                    msdb.dbo.systaskids   sti
  12352.               WHERE (sjv.job_id = sjst.job_id)
  12353.                 AND (sjv.job_id = sti.job_id)
  12354.                 AND (sti.task_id = @taskid)
  12355.                 AND (LOWER(sjst.subsystem) LIKE LOWER(@subsystem))))
  12356.     RETURN(0) -- Success
  12357.   ELSE
  12358.     RETURN(1) -- Failure
  12359. END
  12360. go
  12361.  
  12362. /**************************************************************/
  12363. /* SP_REASSIGNTASK                                            */
  12364. /**************************************************************/
  12365.  
  12366. PRINT ''
  12367. PRINT 'Creating [legacy] procedure sp_reassigntask...'
  12368. go
  12369. IF (EXISTS (SELECT *
  12370.             FROM msdb.dbo.sysobjects
  12371.             WHERE (name = N'sp_reassigntask')
  12372.               AND (type = 'P')))
  12373.   DROP PROCEDURE sp_reassigntask
  12374. go
  12375. CREATE PROCEDURE sp_reassigntask
  12376.   @taskname     sysname = NULL, -- Was VARCHAR(100) in 6.x
  12377.   @newloginname sysname,        -- Was VARCHAR(30) in 6.x
  12378.   @oldloginname sysname = NULL  -- Was VARCHAR(30) in 6.x
  12379. AS
  12380. BEGIN
  12381.   DECLARE @retval INT
  12382.  
  12383.   SET NOCOUNT ON
  12384.  
  12385.   IF (ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) <> 1)
  12386.   BEGIN
  12387.     RAISERROR(14244, -1, -1)
  12388.     RETURN(1) -- Failure
  12389.   END
  12390.  
  12391.   -- Check that we have either task or old login name (or both, though it's redundant)
  12392.   IF ((@taskname IS NULL) AND (@oldloginname IS NULL))
  12393.   BEGIN
  12394.     RAISERROR(14249, -1, -1)
  12395.     RETURN(1) -- Failure
  12396.   END
  12397.  
  12398.   -- Case [1]: Reassign a specific task [job]...
  12399.   IF (@taskname IS NOT NULL)
  12400.   BEGIN
  12401.     -- Check new login id
  12402.     IF (SUSER_ID(@newloginname) IS NULL)
  12403.     BEGIN
  12404.       RAISERROR(14262, -1, -1, '@newloginname', @newloginname)
  12405.       RETURN(1) -- Failure
  12406.     END
  12407.  
  12408.     -- NOTE: Normally we'd invoke sp_update_job by supplying the job_id, but since this is
  12409.     --       a legacy procedure we cannot change the parameter list to have the job_id
  12410.     --       supplied to us.  Hence we use name and we run the risk of a [handled] error
  12411.     --       if the task [job] name is not unique.
  12412.     EXECUTE @retval = sp_update_job @job_name = @taskname, @owner_login_name = @newloginname
  12413.     RETURN(@retval) -- 0 means success
  12414.   END
  12415.  
  12416.   -- Case [2]: Reassign all jobs belonging to the specified old login name...
  12417.   IF (@oldloginname IS NOT NULL)
  12418.   BEGIN
  12419.     EXECUTE @retval = sp_manage_jobs_by_login @action = 'REASSIGN',
  12420.                                               @current_owner_login_name = @oldloginname,
  12421.                                               @new_owner_login_name = @newloginname
  12422.     RETURN(@retval) -- 0 means success
  12423.   END
  12424. END
  12425. go
  12426.  
  12427. /**************************************************************/
  12428. /* SP_HELPHISTORY (Replication doesn't need this - It is here */
  12429. /* for completeness only)                                     */
  12430. /**************************************************************/
  12431.  
  12432. PRINT ''
  12433. PRINT 'Creating [legacy] procedure sp_helphistory...'
  12434. go
  12435. IF (EXISTS (SELECT *
  12436.             FROM msdb.dbo.sysobjects
  12437.             WHERE (name = N'sp_helphistory')
  12438.               AND (type = 'P')))
  12439.   DROP PROCEDURE sp_helphistory
  12440. go
  12441. CREATE PROCEDURE sp_helphistory
  12442.   @taskname            sysname     = NULL,   -- Was VARCHAR(100) in 6.x
  12443.   @taskid              INT         = NULL,
  12444.   @eventid             INT         = NULL,
  12445.   @messageid           INT         = NULL,
  12446.   @severity            INT         = NULL,
  12447.   @source              VARCHAR(30) = NULL,   -- Obsolete in 7.0
  12448.   @category            VARCHAR(30) = NULL,   -- Obsolete in 7.0
  12449.   @startdate           INT         = NULL,   -- YYYYMMDD format
  12450.   @enddate             INT         = NULL,   -- YYYYMMDD format
  12451.   @starttime           INT         = NULL,   -- HHMMSS format
  12452.   @endtime             INT         = NULL,   -- HHMMSS format
  12453.   @minimumtimesskipped INT         = NULL,
  12454.   @minimumrunduration  INT         = NULL,   -- HHMMSS format
  12455.   @runstatusmask       INT         = NULL,   -- SQLOLE_COMPLETION_STATUS
  12456.   @minimumretries      INT         = NULL,
  12457.   @oldestfirst         INT         = NULL,
  12458.   @mode                VARCHAR(10) = 'QUICK' -- Or FULL
  12459. AS
  12460. BEGIN
  12461.   DECLARE @job_id   UNIQUEIDENTIFIER
  12462.   DECLARE @order_by INT
  12463.  
  12464.   SET NOCOUNT ON
  12465.  
  12466.   -- If the name is supplied, get the job_id directly from sysjobs
  12467.   IF (@taskname IS NOT NULL)
  12468.   BEGIN
  12469.     SELECT @job_id = job_id
  12470.     FROM msdb.dbo.sysjobs_view
  12471.     WHERE (name = @taskname)
  12472.  
  12473.     -- Check if the name is ambiguous
  12474.     IF (@@rowcount > 1)
  12475.     BEGIN
  12476.       RAISERROR(14292, -1, -1, @taskname, '@taskid', '@taskname')
  12477.       RETURN(1) -- Failure
  12478.     END
  12479.  
  12480.     IF (@job_id IS NULL)
  12481.     BEGIN
  12482.       RAISERROR(14262, -1, -1, '@taskname', @taskname)
  12483.       RETURN(1) -- Failure
  12484.     END
  12485.   END
  12486.  
  12487.   -- If the id is supplied lookup the corresponding job_id from systaskids
  12488.   IF (@taskid IS NOT NULL)
  12489.   BEGIN
  12490.     SELECT @job_id = job_id
  12491.     FROM msdb.dbo.systaskids
  12492.     WHERE (task_id = @taskid)
  12493.  
  12494.     -- Check that the job still exists
  12495.     IF (NOT EXISTS (SELECT *
  12496.                     FROM msdb.dbo.sysjobs_view
  12497.                     WHERE (job_id = @job_id)))
  12498.     BEGIN
  12499.       SELECT @taskname = CONVERT(NVARCHAR, @taskid)
  12500.       RAISERROR(14262, -1, -1, '@taskid', @taskname)
  12501.       RETURN(1) -- Failure
  12502.     END
  12503.   END
  12504.  
  12505.   SELECT @mode = UPPER(@mode)
  12506.   IF (@mode = 'QUICK')
  12507.     SELECT @mode = 'SUMMARY'
  12508.  
  12509.   CREATE TABLE #task_history_full
  12510.   (
  12511.   instance_id       INT              NOT NULL,
  12512.   job_id            UNIQUEIDENTIFIER NOT NULL,
  12513.   job_name          sysname          COLLATE database_default NOT NULL,
  12514.   step_id           INT              NOT NULL,
  12515.   step_name         sysname          COLLATE database_default NOT NULL,
  12516.   sql_message_id    INT              NOT NULL,
  12517.   sql_severity      INT              NOT NULL,
  12518.   message           NVARCHAR(1024)   COLLATE database_default NULL,
  12519.   run_status        INT              NOT NULL,
  12520.   run_date          INT              NOT NULL,
  12521.   run_time          INT              NOT NULL,
  12522.   run_duration      INT              NOT NULL,
  12523.   operator_emailed  sysname          COLLATE database_default NULL,
  12524.   operator_netsent  sysname          COLLATE database_default NULL,
  12525.   operator_paged    sysname          COLLATE database_default NULL,
  12526.   retries_attempted INT              NOT NULL,
  12527.   server            NVARCHAR(30)     COLLATE database_default NOT NULL
  12528.   )
  12529.  
  12530.   CREATE TABLE #task_history_quick
  12531.   (
  12532.   job_id            UNIQUEIDENTIFIER NOT NULL,
  12533.   job_name          sysname          COLLATE database_default NOT NULL,
  12534.   run_status        INT              NOT NULL,
  12535.   run_date          INT              NOT NULL,
  12536.   run_time          INT              NOT NULL,
  12537.   run_duration      INT              NOT NULL,
  12538.   operator_emailed  sysname          COLLATE database_default NULL,
  12539.   operator_netsent  sysname          COLLATE database_default NULL,
  12540.   operator_paged    sysname          COLLATE database_default NULL,
  12541.   retries_attempted INT              NOT NULL,
  12542.   server            NVARCHAR(30)     COLLATE database_default NOT NULL
  12543.   )
  12544.  
  12545.   IF (@mode = 'FULL')
  12546.   BEGIN
  12547.     INSERT INTO #task_history_full
  12548.     EXECUTE msdb.dbo.sp_help_jobhistory  @job_id               = @job_id,
  12549.                                          @sql_message_id       = @messageid,
  12550.                                          @sql_severity         = @severity,
  12551.                                          @start_run_date       = @startdate,
  12552.                                          @end_run_date         = @enddate,
  12553.                                          @start_run_time       = @starttime,
  12554.                                          @end_run_time         = @endtime,
  12555.                                          @minimum_run_duration = @minimumrunduration,
  12556.                                          @run_status           = @runstatusmask,
  12557.                                          @minimum_retries      = @minimumretries,
  12558.                                          @oldest_first         = @oldestfirst,
  12559.                                          @mode                 = @mode
  12560.   END
  12561.   ELSE
  12562.   BEGIN
  12563.     INSERT INTO #task_history_quick
  12564.     EXECUTE msdb.dbo.sp_help_jobhistory  @job_id               = @job_id,
  12565.                                          @sql_message_id       = @messageid,
  12566.                                          @sql_severity         = @severity,
  12567.                                          @start_run_date       = @startdate,
  12568.                                          @end_run_date         = @enddate,
  12569.                                          @start_run_time       = @starttime,
  12570.                                          @end_run_time         = @endtime,
  12571.                                          @minimum_run_duration = @minimumrunduration,
  12572.                                          @run_status           = @runstatusmask,
  12573.                                          @minimum_retries      = @minimumretries,
  12574.                                          @oldest_first         = @oldestfirst,
  12575.                                          @mode                 = @mode
  12576.   END
  12577.  
  12578.   IF (@mode = 'FULL')
  12579.   BEGIN
  12580.     SELECT id                = sti.task_id,
  12581.            eventid           = 0,
  12582.            messageid         = sql_message_id,
  12583.            severity          = sql_severity,
  12584.            taskname          = job_name,
  12585.            source            = '',
  12586.            category          = '',
  12587.            runstatus         = run_status,
  12588.            rundate           = run_date,
  12589.            runtime           = run_time,
  12590.            runduration       = run_duration,
  12591.            reviewstatus      = 0,
  12592.            emailoperatorname = operator_emailed,
  12593.            retries           = retries_attempted,
  12594.            comments          = message,
  12595.            timesskipped      = 0
  12596.     FROM #task_history_full thf,
  12597.          systaskids         sti
  12598.     WHERE (thf.job_id = sti.job_id)
  12599.   END
  12600.   ELSE
  12601.   BEGIN
  12602.     SELECT taskname          = job_name,
  12603.            source            = '',
  12604.            runstatus         = run_status,
  12605.            rundate           = run_date,
  12606.            runtime           = run_time,
  12607.            runduration       = run_duration,
  12608.            emailoperatorname = operator_emailed,
  12609.            retries           = retries_attempted
  12610.     FROM #task_history_quick
  12611.   END
  12612. END
  12613. go
  12614.  
  12615. /**************************************************************/
  12616. /* SP_PURGEHISTORY (Replication doesn't need this - It is     */
  12617. /* here for completeness only)                                */
  12618. /**************************************************************/
  12619.  
  12620. PRINT ''
  12621. PRINT 'Creating [legacy] procedure sp_purgehistory...'
  12622. go
  12623. IF (EXISTS (SELECT *
  12624.             FROM msdb.dbo.sysobjects
  12625.             WHERE (name = N'sp_purgehistory')
  12626.               AND (type = 'P')))
  12627.   DROP PROCEDURE sp_purgehistory
  12628. go
  12629. CREATE PROCEDURE sp_purgehistory
  12630.   @taskname sysname = NULL, -- Was VARCHAR(100) in 6.x
  12631.   @taskid   INT     = NULL
  12632. AS
  12633. BEGIN
  12634.   DECLARE @job_id UNIQUEIDENTIFIER
  12635.  
  12636.   SET NOCOUNT ON
  12637.  
  12638.   -- If the name is supplied, get the job_id directly from sysjobs
  12639.   IF (@taskname IS NOT NULL)
  12640.   BEGIN
  12641.     SELECT @job_id = job_id
  12642.     FROM msdb.dbo.sysjobs_view
  12643.     WHERE (name = @taskname)
  12644.  
  12645.     -- Check if the name is ambiguous
  12646.     IF (@@rowcount > 1)
  12647.     BEGIN
  12648.       RAISERROR(14292, -1, -1, @taskname, '@taskid', '@taskname')
  12649.       RETURN(1) -- Failure
  12650.     END
  12651.  
  12652.     IF (@job_id IS NULL)
  12653.     BEGIN
  12654.       RAISERROR(14262, -1, -1, '@taskname', @taskname)
  12655.       RETURN(1) -- Failure
  12656.     END
  12657.   END
  12658.  
  12659.   -- If the id is supplied lookup the corresponding job_id from systaskids
  12660.   IF (@taskid IS NOT NULL)
  12661.   BEGIN
  12662.     SELECT @job_id = job_id
  12663.     FROM msdb.dbo.systaskids
  12664.     WHERE (task_id = @taskid)
  12665.  
  12666.     -- Check that the job still exists
  12667.     IF (NOT EXISTS (SELECT *
  12668.                     FROM msdb.dbo.sysjobs_view
  12669.                     WHERE (job_id = @job_id)))
  12670.     BEGIN
  12671.       SELECT @taskname = CONVERT(NVARCHAR, @taskid)
  12672.       RAISERROR(14262, -1, -1, '@taskid', @taskname)
  12673.       RETURN(1) -- Failure
  12674.     END
  12675.   END
  12676.  
  12677.   EXECUTE sp_purge_jobhistory @job_id = @job_id
  12678. END
  12679. go
  12680.  
  12681.  
  12682. /**************************************************************/
  12683. /*                                                            */
  12684. /*         E  R  R  O  R    M  E  S  S  A  G  E  S            */
  12685. /*                                                            */
  12686. /*  These are now created by MESSAGES.SQL.                    */
  12687. /*                                                            */
  12688. /*  NOTE: 14255 and 14265 are called by dynamic SQL generated */
  12689. /*        by SQLServerAgent.                                  */
  12690. /**************************************************************/
  12691.  
  12692.  
  12693. /**************************************************************/
  12694. /*                                                            */
  12695. /*                   T  R  I  G  G  E  R  S                   */
  12696. /*                                                            */
  12697. /**************************************************************/
  12698.  
  12699. /**************************************************************/
  12700. /* TRIG_TARGETSERVER_INSERT                                   */
  12701. /**************************************************************/
  12702.  
  12703. PRINT ''
  12704. PRINT 'Creating trigger trig_targetserver_insert...'
  12705. go
  12706. IF (EXISTS (SELECT *
  12707.             FROM msdb.dbo.sysobjects
  12708.             WHERE (name = N'trig_targetserver_insert')
  12709.               AND (type = 'TR')))
  12710.   DROP TRIGGER dbo.trig_targetserver_insert
  12711. go
  12712. CREATE TRIGGER trig_targetserver_insert
  12713. ON msdb.dbo.systargetservers
  12714. FOR INSERT, DELETE
  12715. AS
  12716. BEGIN
  12717.   SET NOCOUNT ON
  12718.  
  12719.   -- Disallow the insert if the server is called 'ALL'
  12720.   -- NOTE: We have to do this check here in the trigger since there is no sp_add_targetserver
  12721.   --       (target servers insert a row for themselves when they 'enlist' in an MSX)
  12722.   IF (EXISTS (SELECT *
  12723.               FROM inserted
  12724.               WHERE (server_name = N'ALL')))
  12725.   BEGIN
  12726.     DELETE FROM msdb.dbo.systargetservers
  12727.     WHERE (server_name = N'ALL')
  12728.     RAISERROR(14271, -1, -1, 'ALL')
  12729.     RETURN
  12730.   END
  12731.  
  12732.   -- Set (or delete) the registy flag (so that SETUP can detect if we're an MSX)
  12733.   IF ((SELECT COUNT(*)
  12734.        FROM msdb.dbo.systargetservers) = 0)
  12735.   BEGIN
  12736.     DECLARE @val INT
  12737.  
  12738.     EXECUTE master.dbo.xp_instance_regread N'HKEY_LOCAL_MACHINE',
  12739.                                            N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
  12740.                                            N'MSXServer',
  12741.                                            @val OUTPUT,
  12742.                                            N'no_output'
  12743.     IF (@val IS NOT NULL)
  12744.       EXECUTE master.dbo.xp_instance_regdeletevalue N'HKEY_LOCAL_MACHINE',
  12745.                                                     N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
  12746.                                                     N'MSXServer'
  12747.   END
  12748.   ELSE
  12749.     EXECUTE master.dbo.xp_instance_regwrite N'HKEY_LOCAL_MACHINE',
  12750.                                             N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
  12751.                                             N'MSXServer',
  12752.                                             N'REG_DWORD',
  12753.                                             1
  12754. END
  12755. go
  12756.  
  12757. DUMP TRANSACTION msdb WITH NO_LOG
  12758. go
  12759. CHECKPOINT
  12760. go
  12761.  
  12762.  
  12763.  
  12764. /**************************************************************/
  12765. /**                                                          **/
  12766. /**          A L E R T S  A N D  O P E R A T O R S           **/
  12767. /**                                                          **/
  12768. /**************************************************************/
  12769.  
  12770. /**************************************************************/
  12771. /*                                                            */
  12772. /*        C  O  R  E     P  R  O  C  E  D  U  R  E  S         */
  12773. /*                                                            */
  12774. /**************************************************************/
  12775.  
  12776. DUMP TRANSACTION msdb WITH NO_LOG
  12777. go
  12778.  
  12779. /**************************************************************/
  12780. /* SP_VERIFY_PERFORMANCE_CONDITION                            */
  12781. /**************************************************************/
  12782.  
  12783. PRINT ''
  12784. PRINT 'Creating procedure sp_verify_performance_condition...'
  12785. go
  12786. IF (EXISTS (SELECT *
  12787.             FROM msdb.dbo.sysobjects
  12788.             WHERE (name = N'sp_verify_performance_condition')
  12789.               AND (type = 'P')))
  12790.   DROP PROCEDURE sp_verify_performance_condition
  12791. go
  12792. CREATE PROCEDURE sp_verify_performance_condition
  12793.   @performance_condition NVARCHAR(512)
  12794. AS
  12795. BEGIN
  12796.   DECLARE @delimiter_count INT
  12797.   DECLARE @temp_str        NVARCHAR(512)
  12798.   DECLARE @object_name     sysname
  12799.   DECLARE @counter_name    sysname
  12800.   DECLARE @instance_name   sysname
  12801.   DECLARE @pos             INT
  12802.  
  12803.   SET NOCOUNT ON
  12804.  
  12805.   -- The performance condition must have the format 'object|counter|instance|comparator|value'
  12806.   -- NOTE: 'instance' may be empty.
  12807.   IF (PATINDEX(N'%_|%_|%|[><=]|[0-9]%', @performance_condition) = 0)
  12808.   BEGIN
  12809.     RAISERROR(14507, 16, 1)
  12810.     RETURN(1) -- Failure
  12811.   END
  12812.  
  12813.   -- Parse the performance_condition
  12814.   SELECT @delimiter_count = 0
  12815.   SELECT @temp_str = @performance_condition
  12816.   SELECT @pos = CHARINDEX(N'|', @temp_str)
  12817.   WHILE (@pos <> 0)
  12818.   BEGIN
  12819.     SELECT @delimiter_count = @delimiter_count + 1
  12820.     IF (@delimiter_count = 1) SELECT @object_name = SUBSTRING(@temp_str, 1, @pos - 1)
  12821.     IF (@delimiter_count = 2) SELECT @counter_name = SUBSTRING(@temp_str, 1, @pos - 1)
  12822.     IF (@delimiter_count = 3) SELECT @instance_name = SUBSTRING(@temp_str, 1, @pos - 1)
  12823.     SELECT @temp_str = SUBSTRING(@temp_str, @pos + 1, (DATALENGTH(@temp_str) / 2) - @pos)
  12824.     SELECT @pos = CHARINDEX(N'|', @temp_str)
  12825.   END
  12826.   IF (@delimiter_count <> 4)
  12827.   BEGIN
  12828.     RAISERROR(14507, 16, 1)
  12829.     RETURN(1) -- Failure
  12830.   END
  12831.  
  12832.   -- Check the object_name
  12833.   IF (NOT EXISTS (SELECT *
  12834.                   FROM master.dbo.sysperfinfo
  12835.                   WHERE (object_name = @object_name)))
  12836.   BEGIN
  12837.     RAISERROR(14262, 16, 1, 'object_name', @object_name)
  12838.     RETURN(1) -- Failure
  12839.   END
  12840.  
  12841.   -- Check the counter_name
  12842.   IF (NOT EXISTS (SELECT *
  12843.                   FROM master.dbo.sysperfinfo
  12844.                   WHERE (object_name = @object_name)
  12845.                     AND (counter_name = @counter_name)))
  12846.   BEGIN
  12847.     RAISERROR(14262, 16, 1, 'counter_name', @counter_name)
  12848.     RETURN(1) -- Failure
  12849.   END
  12850.  
  12851.   -- Check the instance_name
  12852.   IF (@instance_name IS NOT NULL)
  12853.   BEGIN
  12854.     IF (NOT EXISTS (SELECT *
  12855.                     FROM master.dbo.sysperfinfo
  12856.                     WHERE (object_name = @object_name)
  12857.                       AND (counter_name = @counter_name)
  12858.                       AND (instance_name = @instance_name)))
  12859.     BEGIN
  12860.       RAISERROR(14262, 16, 1, 'instance_name', @instance_name)
  12861.       RETURN(1) -- Failure
  12862.     END
  12863.   END
  12864.  
  12865.   RETURN(0) -- Success
  12866. END
  12867. go
  12868.  
  12869. /**************************************************************/
  12870. /* SP_VERIFY_ALERT                                            */
  12871. /**************************************************************/
  12872.  
  12873. PRINT ''
  12874. PRINT 'Creating procedure sp_verify_alert...'
  12875. go
  12876. IF (EXISTS (SELECT *
  12877.             FROM msdb.dbo.sysobjects
  12878.             WHERE (name = N'sp_verify_alert')
  12879.               AND (type = 'P')))
  12880.   DROP PROCEDURE sp_verify_alert
  12881. go
  12882. CREATE PROCEDURE sp_verify_alert
  12883.   @name                          sysname,
  12884.   @message_id                    INT,
  12885.   @severity                      INT,
  12886.   @enabled                       TINYINT,
  12887.   @delay_between_responses       INT,
  12888.   @notification_message          NVARCHAR(512),
  12889.   @include_event_description_in  TINYINT,
  12890.   @database_name                 sysname,
  12891.   @event_description_keyword     NVARCHAR(100),
  12892.   @job_id                        UNIQUEIDENTIFIER OUTPUT,
  12893.   @job_name                      sysname          OUTPUT,
  12894.   @occurrence_count              INT,
  12895.   @raise_snmp_trap               TINYINT,
  12896.   @performance_condition         NVARCHAR(512),
  12897.   @category_name                 sysname,
  12898.   @category_id                   INT              OUTPUT,
  12899.   @count_reset_date              INT,
  12900.   @count_reset_time              INT
  12901. AS
  12902. BEGIN
  12903.   DECLARE @retval               INT
  12904.   DECLARE @non_alertable_errors VARCHAR(512)
  12905.   DECLARE @message_id_as_string VARCHAR(10)
  12906.   DECLARE @res_valid_range      NVARCHAR(100)
  12907.  
  12908.   SET NOCOUNT ON
  12909.  
  12910.   -- Remove any leading/trailing spaces from parameters
  12911.   SELECT @name                      = LTRIM(RTRIM(@name))
  12912.   SELECT @notification_message      = LTRIM(RTRIM(@notification_message))
  12913.   SELECT @database_name             = LTRIM(RTRIM(@database_name))
  12914.   SELECT @event_description_keyword = LTRIM(RTRIM(@event_description_keyword))
  12915.   SELECT @job_name                  = LTRIM(RTRIM(@job_name))
  12916.   SELECT @performance_condition     = LTRIM(RTRIM(@performance_condition))
  12917.   SELECT @category_name             = LTRIM(RTRIM(@category_name))
  12918.  
  12919.   -- Only a sysadmin can do this
  12920.   IF (ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) <> 1)
  12921.   BEGIN
  12922.     RAISERROR(15003, 16, 1, N'sysadmin')
  12923.     RETURN(1) -- Failure
  12924.   END
  12925.  
  12926.   -- Check if the NewName is unique
  12927.   IF (EXISTS (SELECT *
  12928.               FROM msdb.dbo.sysalerts
  12929.               WHERE (name = @name)))
  12930.   BEGIN
  12931.     RAISERROR(14261, 16, 1, '@name', @name)
  12932.     RETURN(1) -- Failure
  12933.   END
  12934.  
  12935.   -- Check if the user has supplied MessageID OR Severity OR Performance-Condition
  12936.   IF ((@performance_condition IS NULL)     AND ((@message_id = 0) AND (@severity = 0)) OR ((@message_id <> 0) AND (@severity <> 0))) OR
  12937.      ((@performance_condition IS NOT NULL) AND ((@message_id <> 0) OR (@severity <> 0)))
  12938.   BEGIN
  12939.     RAISERROR(14500, 16, 1)
  12940.     RETURN(1) -- Failure
  12941.   END
  12942.  
  12943.   -- Check the Severity
  12944.   IF ((@severity < 0) OR (@severity > 25))
  12945.   BEGIN
  12946.     RAISERROR(14266, 16, 1, '@severity', '0..25')
  12947.     RETURN(1) -- Failure
  12948.   END
  12949.  
  12950.   -- Check the MessageID
  12951.   IF (@message_id <> 0) AND
  12952.      (NOT EXISTS (SELECT error
  12953.                   FROM master.dbo.sysmessages
  12954.                   WHERE (error = @message_id)))
  12955.   BEGIN
  12956.     SELECT @message_id_as_string = CONVERT(VARCHAR, @message_id)
  12957.     RAISERROR(14262, 16, 1, '@message_id', @message_id_as_string)
  12958.     RETURN(1) -- Failure
  12959.   END
  12960.  
  12961.   -- Check if it is legal to set an alert on this MessageID
  12962.   CREATE TABLE #TempRetVal (RetVal INT)
  12963.   EXECUTE master.dbo.xp_instance_regread N'HKEY_LOCAL_MACHINE',
  12964.                                          N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
  12965.                                          N'NonAlertableErrors',
  12966.                                          @non_alertable_errors OUTPUT,
  12967.                                          N'no_output'
  12968.   IF (ISNULL(@non_alertable_errors, N'NULL') <> N'NULL')
  12969.   BEGIN
  12970.     DECLARE @message_id_as_char VARCHAR(10)
  12971.  
  12972.     SELECT @message_id_as_char = CONVERT(VARCHAR(10), @message_id)
  12973.     INSERT INTO #TempRetVal
  12974.     EXECUTE ('IF (' + @message_id_as_char + ' IN (' + @non_alertable_errors + ')) SELECT 1')
  12975.   END
  12976.  
  12977.   IF (EXISTS (SELECT *
  12978.               FROM #TempRetVal))
  12979.   BEGIN
  12980.     RAISERROR(14506, 16, 1, @message_id)
  12981.     RETURN(1) -- Failure
  12982.   END
  12983.  
  12984.   DROP TABLE #TempRetVal
  12985.  
  12986.   -- Enabled must be 0 or 1
  12987.   IF (@enabled NOT IN (0, 1))
  12988.   BEGIN
  12989.     RAISERROR(14266, 16, 1, '@enabled', '0, 1')
  12990.     RETURN(1) -- Failure
  12991.   END
  12992.  
  12993.   -- DelayBetweenResponses must be > 0
  12994.   IF (@delay_between_responses < 0)
  12995.   BEGIN
  12996.     SELECT @res_valid_range = FORMATMESSAGE(14206)
  12997.     RAISERROR(14266, 16, 1, '@delay_between_responses', @res_valid_range)
  12998.     RETURN(1) -- Failure
  12999.   END
  13000.  
  13001.   -- NOTE: We don't check the notification message
  13002.  
  13003.   -- Check IncludeEventDescriptionIn
  13004.   IF ((@include_event_description_in < 0) OR (@include_event_description_in > 7))
  13005.   BEGIN
  13006.     SELECT @res_valid_range = FORMATMESSAGE(14208)
  13007.     RAISERROR(14266, 16, 1, '@include_event_description_in', @res_valid_range)
  13008.     RETURN(1) -- Failure
  13009.   END
  13010.  
  13011.   -- Check the database name
  13012.   IF (@database_name IS NOT NULL) AND (DB_ID(@database_name) IS NULL)
  13013.   BEGIN
  13014.     RAISERROR(15010, 16, 1, @database_name)
  13015.     RETURN(1) -- Failure
  13016.   END
  13017.  
  13018.   -- NOTE: We don't check the event description keyword
  13019.  
  13020.   -- Check JobName/ID
  13021.   IF ((@job_id IS NOT NULL) OR (@job_name IS NOT NULL))
  13022.   BEGIN
  13023.     -- We use '' as a special value which means 'no job' (we cannot use NULL since this forces
  13024.     -- sp_update_alert to use the existing value)
  13025.     IF (@job_name = N'')
  13026.       SELECT @job_id = 0x00
  13027.     ELSE
  13028.     BEGIN
  13029.       EXECUTE @retval = sp_verify_job_identifiers '@job_name',
  13030.                                                   '@job_id',
  13031.                                                    @job_name OUTPUT,
  13032.                                                    @job_id   OUTPUT
  13033.       IF (@retval <> 0)
  13034.         RETURN(1) -- Failure
  13035.       -- Check that the job is a local job
  13036.       IF (NOT EXISTS (SELECT *
  13037.                       FROM msdb.dbo.sysjobservers
  13038.                       WHERE (job_id = @job_id)
  13039.                         AND (server_id = 0)))
  13040.       BEGIN
  13041.         RAISERROR(14234, -1, -1, '@job_id', 'sp_help_job @job_type = ''LOCAL''')
  13042.         RETURN(1) -- Failure
  13043.       END
  13044.     END
  13045.   END
  13046.  
  13047.   -- OccurrenceCount must be > 0
  13048.   IF (@occurrence_count < 0)
  13049.   BEGIN
  13050.     RAISERROR(14266, 16, 1, '@occurrence_count', '0..n')
  13051.     RETURN(1) -- Failure
  13052.   END
  13053.  
  13054.   -- RaiseSNMPTrap must be 0 or 1
  13055.   IF (@raise_snmp_trap NOT IN (0, 1))
  13056.   BEGIN
  13057.     RAISERROR(14266, 16, 1, '@raise_snmp_trap', '0, 1')
  13058.     RETURN(1) -- Failure
  13059.   END
  13060.  
  13061.   -- Check the performance condition (including invalid parameter combinations)
  13062.   IF (@performance_condition IS NOT NULL)
  13063.   BEGIN
  13064.     IF (@database_name IS NOT NULL)
  13065.     BEGIN
  13066.       RAISERROR(14505, 16, 1, 'database_name')
  13067.       RETURN(1) -- Failure
  13068.     END
  13069.  
  13070.     IF (@event_description_keyword IS NOT NULL)
  13071.     BEGIN
  13072.       RAISERROR(14505, 16, 1, 'event_description_keyword')
  13073.       RETURN(1) -- Failure
  13074.     END
  13075.  
  13076.     -- Verify the performance condition
  13077.     EXECUTE @retval = msdb.dbo.sp_verify_performance_condition @performance_condition
  13078.     IF (@retval <> 0)
  13079.       RETURN(1) -- Failure
  13080.   END
  13081.  
  13082.   -- Check category name
  13083.   IF (@category_name = N'[DEFAULT]')
  13084.     SELECT @category_id = 98
  13085.   ELSE
  13086.   BEGIN
  13087.     SELECT @category_id = category_id
  13088.     FROM msdb.dbo.syscategories
  13089.     WHERE (category_class = 2) -- Alerts
  13090.       AND (category_type = 3) -- None
  13091.       AND (name = @category_name)
  13092.   END
  13093.   IF (@category_id IS NULL)
  13094.   BEGIN
  13095.     RAISERROR(14262, -1, -1, '@category_name', @category_name)
  13096.     RETURN(1) -- Failure
  13097.   END
  13098.  
  13099.   -- Check count reset date
  13100.   IF (@count_reset_date <> 0)
  13101.   BEGIN
  13102.     EXECUTE @retval = msdb.dbo.sp_verify_job_date @count_reset_date, '@count_reset_date'
  13103.     IF (@retval <> 0)
  13104.       RETURN(1) -- Failure
  13105.   END
  13106.  
  13107.   -- Check count reset time
  13108.   IF (@count_reset_time <> 0)
  13109.   BEGIN
  13110.     EXECUTE @retval = msdb.dbo.sp_verify_job_time @count_reset_time, '@count_reset_time'
  13111.     IF (@retval <> 0)
  13112.       RETURN(1) -- Failure
  13113.   END
  13114.  
  13115.   RETURN(0) -- Success
  13116. END
  13117. go
  13118.  
  13119. /**************************************************************/
  13120. /* SP_ADD_ALERT                                               */
  13121. /**************************************************************/
  13122.  
  13123. PRINT ''
  13124. PRINT 'Creating procedure sp_add_alert...'
  13125. go
  13126. IF (EXISTS (SELECT *
  13127.             FROM msdb.dbo.sysobjects
  13128.             WHERE (name = N'sp_add_alert')
  13129.               AND (type = 'P')))
  13130.   DROP PROCEDURE sp_add_alert
  13131. go
  13132. CREATE PROCEDURE sp_add_alert
  13133.   @name                         sysname,
  13134.   @message_id                   INT              = 0,
  13135.   @severity                     INT              = 0,
  13136.   @enabled                      TINYINT          = 1,
  13137.   @delay_between_responses      INT              = 0,
  13138.   @notification_message         NVARCHAR(512)    = NULL,
  13139.   @include_event_description_in TINYINT          = 5,    -- 0 = None, 1 = Email, 2 = Pager, 4 = NetSend, 7 = All
  13140.   @database_name                sysname          = NULL,
  13141.   @event_description_keyword    NVARCHAR(100)    = NULL,
  13142.   @job_id                       UNIQUEIDENTIFIER = NULL, -- If provided must NOT also provide job_name
  13143.   @job_name                     sysname          = NULL, -- If provided must NOT also provide job_id
  13144.   @raise_snmp_trap              TINYINT          = 0,
  13145.   @performance_condition        NVARCHAR(512)    = NULL, -- New for 7.0
  13146.   @category_name                sysname          = NULL  -- New for 7.0
  13147. AS
  13148. BEGIN
  13149.   DECLARE @event_source           NVARCHAR(100)
  13150.   DECLARE @event_category_id      INT
  13151.   DECLARE @event_id               INT
  13152.   DECLARE @last_occurrence_date   INT
  13153.   DECLARE @last_occurrence_time   INT
  13154.   DECLARE @last_notification_date INT
  13155.   DECLARE @last_notification_time INT
  13156.   DECLARE @occurrence_count       INT
  13157.   DECLARE @count_reset_date       INT
  13158.   DECLARE @count_reset_time       INT
  13159.   DECLARE @has_notification       INT
  13160.   DECLARE @return_code            INT
  13161.   DECLARE @duplicate_name         sysname
  13162.   DECLARE @category_id            INT
  13163.   DECLARE @alert_id               INT
  13164.  
  13165.   SET NOCOUNT ON
  13166.  
  13167.   -- Remove any leading/trailing spaces from parameters
  13168.   SELECT @name                      = LTRIM(RTRIM(@name))
  13169.   SELECT @notification_message      = LTRIM(RTRIM(@notification_message))
  13170.   SELECT @database_name             = LTRIM(RTRIM(@database_name))
  13171.   SELECT @event_description_keyword = LTRIM(RTRIM(@event_description_keyword))
  13172.   SELECT @job_name                  = LTRIM(RTRIM(@job_name))
  13173.   SELECT @performance_condition     = LTRIM(RTRIM(@performance_condition))
  13174.   SELECT @category_name             = LTRIM(RTRIM(@category_name))
  13175.  
  13176.   -- Turn [nullable] empty string parameters into NULLs
  13177.   IF (@notification_message      = N'') SELECT @notification_message = NULL
  13178.   IF (@database_name             = N'') SELECT @database_name = NULL
  13179.   IF (@event_description_keyword = N'') SELECT @event_description_keyword = NULL
  13180.   IF (@job_name                  = N'') SELECT @job_name = NULL
  13181.   IF (@performance_condition     = N'') SELECT @performance_condition = NULL
  13182.   IF (@category_name             = N'') SELECT @category_name = NULL
  13183.  
  13184.   SELECT @message_id = ISNULL(@message_id, 0)
  13185.   SELECT @severity = ISNULL(@severity, 0)
  13186.  
  13187.   -- Only a sysadmin can do this
  13188.   IF (ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) <> 1)
  13189.   BEGIN
  13190.     RAISERROR(15003, 16, 1, N'sysadmin')
  13191.     RETURN(1) -- Failure
  13192.   END
  13193.  
  13194.   -- Check if SQLServerAgent is in the process of starting
  13195.   EXECUTE @return_code = msdb.dbo.sp_is_sqlagent_starting
  13196.   IF (@return_code <> 0)
  13197.     RETURN(1) -- Failure
  13198.  
  13199.   -- Hard-code the new Alert defaults
  13200.   -- event source needs to be instance aware
  13201.   DECLARE @instance_name sysname
  13202.   SELECT @instance_name = CONVERT (sysname, SERVERPROPERTY ('InstanceName'))
  13203.   IF (@instance_name IS NULL OR @instance_name = N'MSSQLSERVER')
  13204.     SELECT @event_source  = N'MSSQLSERVER'
  13205.   ELSE
  13206.     SELECT @event_source  = N'MSSQL$' + @instance_name
  13207.  
  13208.   SELECT @event_category_id = NULL
  13209.   SELECT @event_id = NULL
  13210.   SELECT @last_occurrence_date = 0
  13211.   SELECT @last_occurrence_time = 0
  13212.   SELECT @last_notification_date = 0
  13213.   SELECT @last_notification_time = 0
  13214.   SELECT @occurrence_count = 0
  13215.   SELECT @count_reset_date = 0
  13216.   SELECT @count_reset_time = 0
  13217.   SELECT @has_notification = 0
  13218.  
  13219.   IF (@category_name IS NULL)
  13220.   BEGIN
  13221.     SELECT @category_name = name
  13222.     FROM msdb.dbo.syscategories
  13223.     WHERE (category_id = 98)
  13224.   END
  13225.  
  13226.   -- Map a job_id of 0 to the real value we use to mean 'no job'
  13227.   IF (@job_id = CONVERT(UNIQUEIDENTIFIER, 0x00)) AND (@job_name IS NULL)
  13228.     SELECT @job_name = N''
  13229.  
  13230.   -- Verify the Alert
  13231.   IF (@job_id = CONVERT(UNIQUEIDENTIFIER, 0x00))
  13232.     SELECT @job_id = NULL
  13233.   EXECUTE @return_code = sp_verify_alert @name,
  13234.                                          @message_id,
  13235.                                          @severity,
  13236.                                          @enabled,
  13237.                                          @delay_between_responses,
  13238.                                          @notification_message,
  13239.                                          @include_event_description_in,
  13240.                                          @database_name,
  13241.                                          @event_description_keyword,
  13242.                                          @job_id OUTPUT,
  13243.                                          @job_name OUTPUT,
  13244.                                          @occurrence_count,
  13245.                                          @raise_snmp_trap,
  13246.                                          @performance_condition,
  13247.                                          @category_name,
  13248.                                          @category_id OUTPUT,
  13249.                                          @count_reset_date,
  13250.                                          @count_reset_time
  13251.   IF (@return_code <> 0)
  13252.     RETURN(1) -- Failure
  13253.  
  13254.   -- Check if this Alert already exists
  13255.   SELECT @duplicate_name = FORMATMESSAGE(14205)
  13256.   SELECT @duplicate_name = name
  13257.   FROM msdb.dbo.sysalerts
  13258.   WHERE (ISNULL(performance_condition, N'apples') = ISNULL(@performance_condition, N'oranges'))
  13259.      OR ((performance_condition IS NULL) AND
  13260.          (message_id = @message_id) AND
  13261.          (severity = @severity) AND
  13262.          (ISNULL(database_name, N'') = ISNULL(@database_name, N'')) AND
  13263.          (ISNULL(event_description_keyword, N'') = ISNULL(@event_description_keyword, N'')))
  13264.   IF (@duplicate_name <> FORMATMESSAGE(14205))
  13265.   BEGIN
  13266.     RAISERROR(14501, 16, 1, @duplicate_name)
  13267.     RETURN(1) -- Failure
  13268.   END
  13269.  
  13270.   -- Finally, do the actual INSERT
  13271.   INSERT INTO msdb.dbo.sysalerts
  13272.          (name,
  13273.           event_source,
  13274.           event_category_id,
  13275.           event_id,
  13276.           message_id,
  13277.           severity,
  13278.           enabled,
  13279.           delay_between_responses,
  13280.           last_occurrence_date,
  13281.           last_occurrence_time,
  13282.           last_response_date,
  13283.           last_response_time,
  13284.           notification_message,
  13285.           include_event_description,
  13286.           database_name,
  13287.           event_description_keyword,
  13288.           occurrence_count,
  13289.           count_reset_date,
  13290.           count_reset_time,
  13291.           job_id,
  13292.           has_notification,
  13293.           flags,
  13294.           performance_condition,
  13295.           category_id)
  13296.   VALUES (@name,
  13297.           @event_source,
  13298.           @event_category_id,
  13299.           @event_id,
  13300.           @message_id,
  13301.           @severity,
  13302.           @enabled,
  13303.           @delay_between_responses,
  13304.           @last_occurrence_date,
  13305.           @last_occurrence_time,
  13306.           @last_notification_date,
  13307.           @last_notification_time,
  13308.           @notification_message,
  13309.           @include_event_description_in,
  13310.           @database_name,
  13311.           @event_description_keyword,
  13312.           @occurrence_count,
  13313.           @count_reset_date,
  13314.           @count_reset_time,
  13315.           ISNULL(@job_id, CONVERT(UNIQUEIDENTIFIER, 0x00)),
  13316.           @has_notification,
  13317.           @raise_snmp_trap,
  13318.           @performance_condition,
  13319.           @category_id)
  13320.  
  13321.   -- Notify SQLServerAgent of the change
  13322.   SELECT @alert_id = id
  13323.   FROM msdb.dbo.sysalerts
  13324.   WHERE (name = @name)
  13325.   EXECUTE msdb.dbo.sp_sqlagent_notify @op_type     = N'A',
  13326.                                       @alert_id    = @alert_id,
  13327.                                       @action_type = N'I'
  13328.   RETURN(0) -- Success
  13329. END
  13330. go
  13331.  
  13332. /**************************************************************/
  13333. /* SP_UPDATE_ALERT                                            */
  13334. /**************************************************************/
  13335.  
  13336. PRINT ''
  13337. PRINT 'Creating procedure sp_update_alert...'
  13338. go
  13339. IF (EXISTS (SELECT *
  13340.             FROM msdb.dbo.sysobjects
  13341.             WHERE (name = N'sp_update_alert')
  13342.               AND (type = 'P')))
  13343.   DROP PROCEDURE sp_update_alert
  13344. go
  13345. CREATE PROCEDURE sp_update_alert
  13346.   @name                         sysname,
  13347.   @new_name                     sysname          = NULL,
  13348.   @enabled                      TINYINT          = NULL,
  13349.   @message_id                   INT              = NULL,
  13350.   @severity                     INT              = NULL,
  13351.   @delay_between_responses      INT              = NULL,
  13352.   @notification_message         NVARCHAR(512)    = NULL,
  13353.   @include_event_description_in TINYINT          = NULL, -- 0 = None, 1 = Email, 2 = Pager. 4 = NetSend, 7 = All
  13354.   @database_name                sysname          = NULL,
  13355.   @event_description_keyword    NVARCHAR(100)    = NULL,
  13356.   @job_id                       UNIQUEIDENTIFIER = NULL, -- If provided must NOT also provide job_name
  13357.   @job_name                     sysname          = NULL, -- If provided must NOT also provide job_id
  13358.   @occurrence_count             INT              = NULL, -- Can only be set to 0
  13359.   @count_reset_date             INT              = NULL,
  13360.   @count_reset_time             INT              = NULL,
  13361.   @last_occurrence_date         INT              = NULL, -- Can only be set to 0
  13362.   @last_occurrence_time         INT              = NULL, -- Can only be set to 0
  13363.   @last_response_date           INT              = NULL, -- Can only be set to 0
  13364.   @last_response_time           INT              = NULL, -- Can only be set to 0
  13365.   @raise_snmp_trap              TINYINT          = NULL,
  13366.   @performance_condition        NVARCHAR(512)    = NULL, -- New for 7.0
  13367.   @category_name                sysname          = NULL  -- New for 7.0
  13368. AS
  13369. BEGIN
  13370.   DECLARE @x_enabled                   TINYINT
  13371.   DECLARE @x_message_id                INT
  13372.   DECLARE @x_severity                  INT
  13373.   DECLARE @x_delay_between_responses   INT
  13374.   DECLARE @x_notification_message      NVARCHAR(512)
  13375.   DECLARE @x_include_event_description TINYINT
  13376.   DECLARE @x_database_name             sysname
  13377.   DECLARE @x_event_description_keyword NVARCHAR(100)
  13378.   DECLARE @x_occurrence_count          INT
  13379.   DECLARE @x_count_reset_date          INT
  13380.   DECLARE @x_count_reset_time          INT
  13381.   DECLARE @x_last_occurrence_date      INT
  13382.   DECLARE @x_last_occurrence_time      INT
  13383.   DECLARE @x_last_response_date        INT
  13384.   DECLARE @x_last_response_time        INT
  13385.   DECLARE @x_flags                     INT
  13386.   DECLARE @x_performance_condition     NVARCHAR(512)
  13387.   DECLARE @x_job_id                    UNIQUEIDENTIFIER
  13388.   DECLARE @x_category_id               INT
  13389.  
  13390.   DECLARE @include_event_desc_code     TINYINT
  13391.   DECLARE @return_code                 INT
  13392.   DECLARE @duplicate_name              sysname
  13393.   DECLARE @category_id                 INT
  13394.   DECLARE @alert_id                    INT
  13395.   DECLARE @cached_attribute_modified   INT
  13396.  
  13397.   SET NOCOUNT ON
  13398.  
  13399.   -- Remove any leading/trailing spaces from parameters
  13400.   SELECT @new_name                  = LTRIM(RTRIM(@new_name))
  13401.   SELECT @job_name                  = LTRIM(RTRIM(@job_name))
  13402.   SELECT @notification_message      = LTRIM(RTRIM(@notification_message))
  13403.   SELECT @database_name             = LTRIM(RTRIM(@database_name))
  13404.   SELECT @event_description_keyword = LTRIM(RTRIM(@event_description_keyword))
  13405.   SELECT @performance_condition     = LTRIM(RTRIM(@performance_condition))
  13406.   SELECT @category_name             = LTRIM(RTRIM(@category_name))
  13407.  
  13408.   -- Are we modifying an attribute which SQLServerAgent caches?
  13409.   IF ((@new_name                     IS NOT NULL) OR
  13410.       (@enabled                      IS NOT NULL) OR
  13411.       (@message_id                   IS NOT NULL) OR
  13412.       (@severity                     IS NOT NULL) OR
  13413.       (@delay_between_responses      IS NOT NULL) OR
  13414.       (@notification_message         IS NOT NULL) OR
  13415.       (@include_event_description_in IS NOT NULL) OR
  13416.       (@database_name                IS NOT NULL) OR
  13417.       (@event_description_keyword    IS NOT NULL) OR
  13418.       (@job_id                       IS NOT NULL) OR
  13419.       (@job_name                     IS NOT NULL) OR
  13420.       (@last_response_date           IS NOT NULL) OR
  13421.       (@last_response_time           IS NOT NULL) OR
  13422.       (@raise_snmp_trap              IS NOT NULL) OR
  13423.       (@performance_condition        IS NOT NULL))
  13424.     SELECT @cached_attribute_modified = 1
  13425.   ELSE
  13426.     SELECT @cached_attribute_modified = 0
  13427.  
  13428.   -- Map a job_id of 0 to the real value we use to mean 'no job'
  13429.   IF (@job_id = CONVERT(UNIQUEIDENTIFIER, 0x00)) AND (@job_name IS NULL)
  13430.     SELECT @job_name = N''
  13431.  
  13432.   -- Only a sysadmin can do this
  13433.   IF (ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) <> 1)
  13434.   BEGIN
  13435.     RAISERROR(15003, 16, 1, N'sysadmin')
  13436.     RETURN(1)
  13437.   END
  13438.  
  13439.   -- Check if SQLServerAgent is in the process of starting
  13440.   EXECUTE @return_code = msdb.dbo.sp_is_sqlagent_starting
  13441.   IF (@return_code <> 0)
  13442.     RETURN(1) -- Failure
  13443.  
  13444.   -- Check if this Alert exists
  13445.   IF (NOT EXISTS (SELECT *
  13446.                   FROM msdb.dbo.sysalerts
  13447.                   WHERE (name = @name)))
  13448.   BEGIN
  13449.     RAISERROR(14262, 16, 1, '@name', @name)
  13450.     RETURN(1)
  13451.   END
  13452.  
  13453.   -- Certain values (if supplied) may only be updated to 0
  13454.   IF (@occurrence_count <> 0)
  13455.   BEGIN
  13456.     RAISERROR(14266, -1, -1, '@occurrence_count', '0')
  13457.     RETURN(1) -- Failure
  13458.   END
  13459.   IF (@last_occurrence_date <> 0)
  13460.   BEGIN
  13461.     RAISERROR(14266, -1, -1, '@last_occurrence_date', '0')
  13462.     RETURN(1) -- Failure
  13463.   END
  13464.   IF (@last_occurrence_time <> 0)
  13465.   BEGIN
  13466.     RAISERROR(14266, -1, -1, '@last_occurrence_time', '0')
  13467.     RETURN(1) -- Failure
  13468.   END
  13469.   IF (@last_response_date <> 0)
  13470.   BEGIN
  13471.     RAISERROR(14266, -1, -1, '@last_response_date', '0')
  13472.     RETURN(1) -- Failure
  13473.   END
  13474.   IF (@last_response_time <> 0)
  13475.   BEGIN
  13476.     RAISERROR(14266, -1, -1, '@last_response_time', '0')
  13477.     RETURN(1) -- Failure
  13478.   END
  13479.  
  13480.   -- Get existing (@x_) values
  13481.   SELECT @alert_id                    = id,
  13482.          @x_enabled                   = enabled,
  13483.          @x_message_id                = message_id,
  13484.          @x_severity                  = severity,
  13485.          @x_delay_between_responses   = delay_between_responses,
  13486.          @x_notification_message      = notification_message,
  13487.          @x_include_event_description = include_event_description,
  13488.          @x_database_name             = database_name,
  13489.          @x_event_description_keyword = event_description_keyword,
  13490.          @x_occurrence_count          = occurrence_count,
  13491.          @x_count_reset_date          = count_reset_date,
  13492.          @x_count_reset_time          = count_reset_time,
  13493.          @x_job_id                    = job_id,
  13494.          @x_last_occurrence_date      = last_occurrence_date,
  13495.          @x_last_occurrence_time      = last_occurrence_time,
  13496.          @x_last_response_date        = last_response_date,
  13497.          @x_last_response_time        = last_response_time,
  13498.          @x_flags                     = flags,
  13499.          @x_performance_condition     = performance_condition,
  13500.          @x_category_id               = category_id
  13501.   FROM msdb.dbo.sysalerts
  13502.   WHERE (name = @name)
  13503.  
  13504.   SELECT @x_job_id = sjv.job_id
  13505.   FROM msdb.dbo.sysalerts    sa,
  13506.        msdb.dbo.sysjobs_view sjv
  13507.   WHERE (sa.job_id = sjv.job_id)
  13508.     AND (sa.name = @name)
  13509.  
  13510.   -- Fill out the values for all non-supplied parameters from the existsing values
  13511.   IF (@enabled                      IS NULL) SELECT @enabled                      = @x_enabled
  13512.   IF (@message_id                   IS NULL) SELECT @message_id                   = @x_message_id
  13513.   IF (@severity                     IS NULL) SELECT @severity                     = @x_severity
  13514.   IF (@delay_between_responses      IS NULL) SELECT @delay_between_responses      = @x_delay_between_responses
  13515.   IF (@notification_message         IS NULL) SELECT @notification_message         = @x_notification_message
  13516.   IF (@include_event_description_in IS NULL) SELECT @include_event_description_in = @x_include_event_description
  13517.   IF (@database_name                IS NULL) SELECT @database_name                = @x_database_name
  13518.   IF (@event_description_keyword    IS NULL) SELECT @event_description_keyword    = @x_event_description_keyword
  13519.   IF (@job_id IS NULL) AND (@job_name IS NULL) SELECT @job_id                     = @x_job_id
  13520.   IF (@occurrence_count             IS NULL) SELECT @occurrence_count             = @x_occurrence_count
  13521.   IF (@count_reset_date             IS NULL) SELECT @count_reset_date             = @x_count_reset_date
  13522.   IF (@count_reset_time             IS NULL) SELECT @count_reset_time             = @x_count_reset_time
  13523.   IF (@last_occurrence_date         IS NULL) SELECT @last_occurrence_date         = @x_last_occurrence_date
  13524.   IF (@last_occurrence_time         IS NULL) SELECT @last_occurrence_time         = @x_last_occurrence_time
  13525.   IF (@last_response_date           IS NULL) SELECT @last_response_date           = @x_last_response_date
  13526.   IF (@last_response_time           IS NULL) SELECT @last_response_time           = @x_last_response_time
  13527.   IF (@raise_snmp_trap              IS NULL) SELECT @raise_snmp_trap              = @x_flags & 0x1
  13528.   IF (@performance_condition        IS NULL) SELECT @performance_condition        = @x_performance_condition
  13529.   IF (@category_name                IS NULL) SELECT @category_name = name FROM msdb.dbo.syscategories WHERE (category_id = @x_category_id)
  13530.  
  13531.   IF (@category_name IS NULL)
  13532.   BEGIN
  13533.     SELECT @category_name = name
  13534.     FROM msdb.dbo.syscategories
  13535.     WHERE (category_id = 98)
  13536.   END
  13537.  
  13538.   -- Turn [nullable] empty string parameters into NULLs
  13539.   IF (@new_name                  = N'') SELECT @new_name                  = NULL
  13540.   IF (@notification_message      = N'') SELECT @notification_message      = NULL
  13541.   IF (@database_name             = N'') SELECT @database_name             = NULL
  13542.   IF (@event_description_keyword = N'') SELECT @event_description_keyword = NULL
  13543.   IF (@performance_condition     = N'') SELECT @performance_condition     = NULL
  13544.  
  13545.   -- Check if this alert would match an already existing alert
  13546.   SELECT @duplicate_name = FORMATMESSAGE(14205)
  13547.   SELECT @duplicate_name = name
  13548.   FROM msdb.dbo.sysalerts
  13549.   WHERE (ISNULL(performance_condition, N'') = ISNULL(@performance_condition, N''))
  13550.     AND (message_id = @message_id)
  13551.     AND (severity = @severity)
  13552.     AND (ISNULL(database_name, N'') = ISNULL(@database_name, N''))
  13553.     AND (ISNULL(event_description_keyword, N'') = ISNULL(@event_description_keyword, N''))
  13554.     AND (name <> @name)
  13555.   IF (@duplicate_name <> FORMATMESSAGE(14205))
  13556.   BEGIN
  13557.     RAISERROR(14501, 16, 1, @duplicate_name)
  13558.     RETURN(1) -- Failure
  13559.   END
  13560.  
  13561.   -- Verify the Alert
  13562.   IF (@job_id = CONVERT(UNIQUEIDENTIFIER, 0x00))
  13563.     SELECT @job_id = NULL
  13564.   EXECUTE @return_code = sp_verify_alert @new_name,
  13565.                                          @message_id,
  13566.                                          @severity,
  13567.                                          @enabled,
  13568.                                          @delay_between_responses,
  13569.                                          @notification_message,
  13570.                                          @include_event_description_in,
  13571.                                          @database_name,
  13572.                                          @event_description_keyword,
  13573.                                          @job_id OUTPUT,
  13574.                                          @job_name OUTPUT,
  13575.                                          @occurrence_count,
  13576.                                          @raise_snmp_trap,
  13577.                                          @performance_condition,
  13578.                                          @category_name,
  13579.                                          @category_id OUTPUT,
  13580.                                          @count_reset_date,
  13581.                                          @count_reset_time
  13582.   IF (@return_code <> 0)
  13583.     RETURN(1) -- Failure
  13584.  
  13585.   -- If the user didn't supply a NewName, use the old one.
  13586.   -- NOTE: This must be done AFTER sp_verify_alert.
  13587.   IF (@new_name IS NULL)
  13588.     SELECT @new_name = @name
  13589.  
  13590.   -- Turn the 1st 'flags' bit on or off accordingly
  13591.   IF (@raise_snmp_trap = 0)
  13592.     SELECT @x_flags = @x_flags & 0xFFFE
  13593.   ELSE
  13594.     SELECT @x_flags = @x_flags | 0x0001
  13595.  
  13596.   -- Finally, do the actual UPDATE
  13597.   UPDATE msdb.dbo.sysalerts
  13598.   SET name                        = @new_name,
  13599.       message_id                  = @message_id,
  13600.       severity                    = @severity,
  13601.       enabled                     = @enabled,
  13602.       delay_between_responses     = @delay_between_responses,
  13603.       notification_message        = @notification_message,
  13604.       include_event_description   = @include_event_description_in,
  13605.       database_name               = @database_name,
  13606.       event_description_keyword   = @event_description_keyword,
  13607.       job_id                      = ISNULL(@job_id, CONVERT(UNIQUEIDENTIFIER, 0x00)),
  13608.       occurrence_count            = @occurrence_count,
  13609.       count_reset_date            = @count_reset_date,
  13610.       count_reset_time            = @count_reset_time,
  13611.       last_occurrence_date        = @last_occurrence_date,
  13612.       last_occurrence_time        = @last_occurrence_time,
  13613.       last_response_date          = @last_response_date,
  13614.       last_response_time          = @last_response_time,
  13615.       flags                       = @x_flags,
  13616.       performance_condition       = @performance_condition,
  13617.       category_id                 = @category_id
  13618.   WHERE (name = @name)
  13619.  
  13620.   -- Notify SQLServerAgent of the change
  13621.   IF (@cached_attribute_modified = 1)
  13622.     EXECUTE msdb.dbo.sp_sqlagent_notify @op_type     = N'A',
  13623.                                         @alert_id    = @alert_id,
  13624.                                         @action_type = N'U'
  13625.   RETURN(0) -- Success
  13626. END
  13627. go
  13628.  
  13629. /**************************************************************/
  13630. /* SP_DELETE_ALERT                                            */
  13631. /**************************************************************/
  13632.  
  13633. PRINT ''
  13634. PRINT 'Creating procedure sp_delete_alert...'
  13635. go
  13636. IF (EXISTS (SELECT *
  13637.             FROM msdb.dbo.sysobjects
  13638.             WHERE (name = N'sp_delete_alert')
  13639.               AND (type = 'P')))
  13640.   DROP PROCEDURE sp_delete_alert
  13641. go
  13642. CREATE PROCEDURE sp_delete_alert
  13643.   @name sysname
  13644. AS
  13645. BEGIN
  13646.   DECLARE @alert_id    INT
  13647.   DECLARE @return_code INT
  13648.  
  13649.   SET NOCOUNT ON
  13650.  
  13651.   -- Remove any leading/trailing spaces from parameters
  13652.   SELECT @name = LTRIM(RTRIM(@name))
  13653.  
  13654.   -- Only a sysadmin can do this
  13655.   IF (ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) <> 1)
  13656.   BEGIN
  13657.     RAISERROR(15003, 16, 1, N'sysadmin')
  13658.     RETURN(1) -- Failure
  13659.   END
  13660.  
  13661.   -- Check if SQLServerAgent is in the process of starting
  13662.   EXECUTE @return_code = msdb.dbo.sp_is_sqlagent_starting
  13663.   IF (@return_code <> 0)
  13664.     RETURN(1) -- Failure
  13665.  
  13666.   -- Check if this Alert exists
  13667.   IF (NOT EXISTS (SELECT *
  13668.                   FROM msdb.dbo.sysalerts
  13669.                   WHERE (name = @name)))
  13670.   BEGIN
  13671.     RAISERROR(14262, 16, 1, '@name', @name)
  13672.     RETURN(1) -- Failure
  13673.   END
  13674.  
  13675.   -- Convert the Name to it's ID
  13676.   SELECT @alert_id = id
  13677.   FROM msdb.dbo.sysalerts
  13678.   WHERE (name = @name)
  13679.  
  13680.   BEGIN TRANSACTION
  13681.  
  13682.     -- Delete sysnotifications entries
  13683.     DELETE FROM msdb.dbo.sysnotifications
  13684.     WHERE (alert_id = @alert_id)
  13685.  
  13686.     -- Finally, do the actual DELETE
  13687.     DELETE FROM msdb.dbo.sysalerts
  13688.     WHERE (id = @alert_id)
  13689.  
  13690.   COMMIT TRANSACTION
  13691.  
  13692.   -- Notify SQLServerAgent of the change
  13693.   EXECUTE msdb.dbo.sp_sqlagent_notify @op_type     = N'A',
  13694.                                       @alert_id    = @alert_id,
  13695.                                       @action_type = N'D'
  13696.   RETURN(0) -- Success
  13697. END
  13698. go
  13699.  
  13700. /**************************************************************/
  13701. /* SP_HELP_ALERT                                              */
  13702. /**************************************************************/
  13703.  
  13704. PRINT ''
  13705. PRINT 'Creating procedure sp_help_alert...'
  13706. go
  13707. IF (EXISTS (SELECT *
  13708.             FROM msdb.dbo.sysobjects
  13709.             WHERE (name = N'sp_help_alert')
  13710.               AND (type = 'P')))
  13711.   DROP PROCEDURE sp_help_alert
  13712. go
  13713. CREATE PROCEDURE sp_help_alert
  13714.   @alert_name    sysname = NULL,
  13715.   @order_by      sysname = N'name',
  13716.   @alert_id      INT     = NULL,
  13717.   @category_name sysname = NULL
  13718. AS
  13719. BEGIN
  13720.   DECLARE @alert_id_as_char NVARCHAR(10)
  13721.  
  13722.   SET NOCOUNT ON
  13723.  
  13724.   -- Remove any leading/trailing spaces from parameters
  13725.   SELECT @alert_name    = LTRIM(RTRIM(@alert_name))
  13726.   SELECT @order_by      = LTRIM(RTRIM(@order_by))
  13727.   SELECT @category_name = LTRIM(RTRIM(@category_name))
  13728.  
  13729.   -- Turn [nullable] empty string parameters into NULLs
  13730.   IF (@category_name = N'') SELECT @category_name = NULL
  13731.   IF (@alert_name = N'')    SELECT @alert_name = NULL
  13732.  
  13733.   -- Check alert name
  13734.   IF (@alert_name IS NOT NULL)
  13735.   BEGIN
  13736.     IF (NOT EXISTS (SELECT *
  13737.                     FROM msdb.dbo.sysalerts
  13738.                     WHERE (name = @alert_name)))
  13739.     BEGIN
  13740.       RAISERROR(14262, -1, -1, '@alert_name', @alert_name)
  13741.       RETURN(1) -- Failure
  13742.     END
  13743.   END
  13744.  
  13745.   -- Check alert id
  13746.   IF (@alert_id IS NOT NULL)
  13747.   BEGIN
  13748.     IF (NOT EXISTS (SELECT *
  13749.                     FROM msdb.dbo.sysalerts
  13750.                     WHERE (id = @alert_id)))
  13751.     BEGIN
  13752.       SELECT @alert_id_as_char = CONVERT(VARCHAR, @alert_id)
  13753.       RAISERROR(14262, -1, -1, '@alert_id', @alert_id_as_char)
  13754.       RETURN(1) -- Failure
  13755.     END
  13756.   END
  13757.  
  13758.   IF (@order_by NOT LIKE N'job_name%')
  13759.     SELECT @order_by = N'sa.' + @order_by
  13760.  
  13761.   IF (@alert_id IS NOT NULL)
  13762.     SELECT @alert_id_as_char = CONVERT(VARCHAR, @alert_id)
  13763.   ELSE
  13764.     SELECT @alert_id_as_char = N'NULL'
  13765.  
  13766.   -- Double up any single quotes in @alert_name
  13767.   IF (@alert_name IS NOT NULL)
  13768.     SELECT @alert_name = REPLACE(@alert_name, N'''', N'''''')
  13769.  
  13770.   -- Double up any single quotes in @category_name
  13771.   IF (@category_name IS NOT NULL)
  13772.     SELECT @category_name = REPLACE(@category_name, N'''', N'''''')
  13773.  
  13774.   EXECUTE (N'SELECT sa.id,
  13775.                     sa.name,
  13776.                     sa.event_source,
  13777.                     sa.event_category_id,
  13778.                     sa.event_id,
  13779.                     sa.message_id,
  13780.                     sa.severity,
  13781.                     sa.enabled,
  13782.                     sa.delay_between_responses,
  13783.                     sa.last_occurrence_date,
  13784.                     sa.last_occurrence_time,
  13785.                     sa.last_response_date,
  13786.                     sa.last_response_time,
  13787.                     sa.notification_message,
  13788.                     sa.include_event_description,
  13789.                     sa.database_name,
  13790.                     sa.event_description_keyword,
  13791.                     sa.occurrence_count,
  13792.                     sa.count_reset_date,
  13793.                     sa.count_reset_time,
  13794.                     sjv.job_id,
  13795.                     job_name = sjv.name,
  13796.                     sa.has_notification,
  13797.                     sa.flags,
  13798.                     sa.performance_condition,
  13799.                     category_name = sc.name,
  13800.                     type = CASE ISNULL(performance_condition, ''!'')
  13801.                              WHEN ''!'' THEN
  13802.                                CASE event_source
  13803.                                  WHEN ''MSSQLSERVER'' THEN 1 -- SQL Server event alert
  13804.                                  ELSE 3                      -- Non SQL Server event alert
  13805.                                END
  13806.                              ELSE 2                          -- SQL Server performance condition alert
  13807.                            END
  13808.              FROM msdb.dbo.sysalerts                     sa
  13809.                   LEFT OUTER JOIN msdb.dbo.sysjobs_view  sjv ON (sa.job_id = sjv.job_id)
  13810.                   LEFT OUTER JOIN msdb.dbo.syscategories sc  ON (sa.category_id = sc.category_id)
  13811.              WHERE ((N''' + @alert_name + N''' = N'''') OR (sa.name = N''' + @alert_name + N'''))
  13812.                AND ((' + @alert_id_as_char + N' IS NULL) OR (sa.id = ' + @alert_id_as_char + N'))
  13813.                AND ((N''' + @category_name + N''' = N'''') OR (sc.name = N''' + @category_name + N'''))
  13814.              ORDER BY ' + @order_by)
  13815.  
  13816.   RETURN(@@error) -- 0 means success
  13817. END
  13818. go
  13819.  
  13820. /**************************************************************/
  13821. /* SP_VERIFY_OPERATOR                                         */
  13822. /**************************************************************/
  13823.  
  13824. PRINT ''
  13825. PRINT 'Creating procedure sp_verify_operator...'
  13826. go
  13827. IF (EXISTS (SELECT *
  13828.             FROM msdb.dbo.sysobjects
  13829.             WHERE (name = N'sp_verify_operator')
  13830.               AND (type = 'P')))
  13831.   DROP PROCEDURE sp_verify_operator
  13832. go
  13833. CREATE PROCEDURE sp_verify_operator
  13834.   @name                      sysname,
  13835.   @enabled                   TINYINT,
  13836.   @pager_days                TINYINT,
  13837.   @weekday_pager_start_time  INT,
  13838.   @weekday_pager_end_time    INT,
  13839.   @saturday_pager_start_time INT,
  13840.   @saturday_pager_end_time   INT,
  13841.   @sunday_pager_start_time   INT,
  13842.   @sunday_pager_end_time     INT,
  13843.   @category_name             sysname,
  13844.   @category_id               INT OUTPUT
  13845. AS
  13846. BEGIN
  13847.   DECLARE @return_code     TINYINT
  13848.   DECLARE @res_valid_range NVARCHAR(100)
  13849.  
  13850.   SET NOCOUNT ON
  13851.  
  13852.   SELECT @res_valid_range = FORMATMESSAGE(14209)
  13853.  
  13854.   -- Remove any leading/trailing spaces from parameters
  13855.   SELECT @name          = LTRIM(RTRIM(@name))
  13856.   SELECT @category_name = LTRIM(RTRIM(@category_name))
  13857.  
  13858.   -- The name must be unique
  13859.   IF (EXISTS (SELECT *
  13860.               FROM msdb.dbo.sysoperators
  13861.               WHERE (name = @name)))
  13862.   BEGIN
  13863.     RAISERROR(14261, 16, 1, '@name', @name)
  13864.     RETURN(1) -- Failure
  13865.   END
  13866.  
  13867.   -- Enabled must be 0 or 1
  13868.   IF (@enabled NOT IN (0, 1))
  13869.   BEGIN
  13870.     RAISERROR(14266, 16, 1, '@enabled', '0, 1')
  13871.     RETURN(1) -- Failure
  13872.   END
  13873.  
  13874.   -- Check PagerDays
  13875.   IF (@pager_days < 0) OR (@pager_days > 127)
  13876.   BEGIN
  13877.     RAISERROR(14266, 16, 1, '@pager_days', @res_valid_range)
  13878.     RETURN(1) -- Failure
  13879.   END
  13880.  
  13881.   -- Check Start/End Times
  13882.   EXECUTE @return_code = sp_verify_job_time @weekday_pager_start_time, '@weekday_pager_start_time'
  13883.   IF (@return_code <> 0)
  13884.     RETURN(1)
  13885.  
  13886.   EXECUTE @return_code = sp_verify_job_time @weekday_pager_end_time, '@weekday_pager_end_time'
  13887.   IF (@return_code <> 0)
  13888.     RETURN(1)
  13889.  
  13890.   EXECUTE @return_code = sp_verify_job_time @saturday_pager_start_time, '@saturday_pager_start_time'
  13891.   IF (@return_code <> 0)
  13892.     RETURN(1)
  13893.  
  13894.   EXECUTE @return_code = sp_verify_job_time @saturday_pager_end_time, '@saturday_pager_end_time'
  13895.   IF (@return_code <> 0)
  13896.     RETURN(1)
  13897.  
  13898.   EXECUTE @return_code = sp_verify_job_time @sunday_pager_start_time, '@sunday_pager_start_time'
  13899.   IF (@return_code <> 0)
  13900.     RETURN(1)
  13901.  
  13902.   EXECUTE @return_code = sp_verify_job_time @sunday_pager_end_time, '@sunday_pager_end_time'
  13903.   IF (@return_code <> 0)
  13904.     RETURN(1)
  13905.  
  13906.   -- Check category name
  13907.   IF (@category_name = N'[DEFAULT]')
  13908.     SELECT @category_id = 99
  13909.   ELSE
  13910.   BEGIN
  13911.     SELECT @category_id = category_id
  13912.     FROM msdb.dbo.syscategories
  13913.     WHERE (category_class = 3) -- Operators
  13914.       AND (category_type = 3) -- None
  13915.       AND (name = @category_name)
  13916.   END
  13917.   IF (@category_id IS NULL)
  13918.   BEGIN
  13919.     RAISERROR(14262, -1, -1, '@category_name', @category_name)
  13920.     RETURN(1) -- Failure
  13921.   END
  13922.  
  13923.   RETURN(0)
  13924. END
  13925. go
  13926.  
  13927. /**************************************************************/
  13928. /* SP_ADD_OPERATOR                                            */
  13929. /**************************************************************/
  13930.  
  13931. PRINT ''
  13932. PRINT 'Creating procedure sp_add_operator...'
  13933. go
  13934. IF (EXISTS (SELECT *
  13935.             FROM msdb.dbo.sysobjects
  13936.             WHERE (name = N'sp_add_operator')
  13937.               AND (type = 'P')))
  13938.   DROP PROCEDURE sp_add_operator
  13939. go
  13940. CREATE PROCEDURE sp_add_operator
  13941.   @name                      sysname,
  13942.   @enabled                   TINYINT       = 1,
  13943.   @email_address             NVARCHAR(100) = NULL,
  13944.   @pager_address             NVARCHAR(100) = NULL,
  13945.   @weekday_pager_start_time  INT           = 090000, -- HHMMSS using 24 hour clock
  13946.   @weekday_pager_end_time    INT           = 180000, -- As above
  13947.   @saturday_pager_start_time INT           = 090000, -- As above
  13948.   @saturday_pager_end_time   INT           = 180000, -- As above
  13949.   @sunday_pager_start_time   INT           = 090000, -- As above
  13950.   @sunday_pager_end_time     INT           = 180000, -- As above
  13951.   @pager_days                TINYINT       = 0,      -- 1 = Sunday .. 64 = Saturday
  13952.   @netsend_address           NVARCHAR(100) = NULL,   -- New for 7.0
  13953.   @category_name             sysname       = NULL    -- New for 7.0
  13954. AS
  13955. BEGIN
  13956.   DECLARE @return_code TINYINT
  13957.   DECLARE @category_id INT
  13958.  
  13959.   SET NOCOUNT ON
  13960.  
  13961.   -- Remove any leading/trailing spaces from parameters
  13962.   SELECT @name            = LTRIM(RTRIM(@name))
  13963.   SELECT @email_address   = LTRIM(RTRIM(@email_address))
  13964.   SELECT @pager_address   = LTRIM(RTRIM(@pager_address))
  13965.   SELECT @netsend_address = LTRIM(RTRIM(@netsend_address))
  13966.   SELECT @category_name   = LTRIM(RTRIM(@category_name))
  13967.  
  13968.   -- Turn [nullable] empty string parameters into NULLs
  13969.   IF (@email_address   = N'') SELECT @email_address   = NULL
  13970.   IF (@pager_address   = N'') SELECT @pager_address   = NULL
  13971.   IF (@netsend_address = N'') SELECT @netsend_address = NULL
  13972.   IF (@category_name   = N'') SELECT @category_name   = NULL
  13973.  
  13974.   -- Only a sysadmin can do this
  13975.   IF (ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) <> 1)
  13976.   BEGIN
  13977.     RAISERROR(15003, 16, 1, N'sysadmin')
  13978.     RETURN(1) -- Failure
  13979.   END
  13980.  
  13981.   IF (@category_name IS NULL)
  13982.   BEGIN
  13983.     SELECT @category_name = name
  13984.     FROM msdb.dbo.syscategories
  13985.     WHERE (category_id = 99)
  13986.   END
  13987.  
  13988.   -- Verify the operator
  13989.   EXECUTE @return_code = sp_verify_operator @name,
  13990.                                             @enabled,
  13991.                                             @pager_days,
  13992.                                             @weekday_pager_start_time,
  13993.                                             @weekday_pager_end_time,
  13994.                                             @saturday_pager_start_time,
  13995.                                             @saturday_pager_end_time,
  13996.                                             @sunday_pager_start_time,
  13997.                                             @sunday_pager_end_time,
  13998.                                             @category_name,
  13999.                                             @category_id OUTPUT
  14000.   IF (@return_code <> 0)
  14001.     RETURN(1) -- Failure
  14002.  
  14003.   -- Finally, do the INSERT
  14004.   INSERT INTO msdb.dbo.sysoperators
  14005.          (name,
  14006.           enabled,
  14007.           email_address,
  14008.           last_email_date,
  14009.           last_email_time,
  14010.           pager_address,
  14011.           last_pager_date,
  14012.           last_pager_time,
  14013.           weekday_pager_start_time,
  14014.           weekday_pager_end_time,
  14015.           saturday_pager_start_time,
  14016.           saturday_pager_end_time,
  14017.           sunday_pager_start_time,
  14018.           sunday_pager_end_time,
  14019.           pager_days,
  14020.           netsend_address,
  14021.           last_netsend_date,
  14022.           last_netsend_time,
  14023.           category_id)
  14024.   VALUES (@name,
  14025.           @enabled,
  14026.           @email_address,
  14027.           0,
  14028.           0,
  14029.           @pager_address,
  14030.           0,
  14031.           0,
  14032.           @weekday_pager_start_time,
  14033.           @weekday_pager_end_time,
  14034.           @saturday_pager_start_time,
  14035.           @saturday_pager_end_time,
  14036.           @sunday_pager_start_time,
  14037.           @sunday_pager_end_time,
  14038.           @pager_days,
  14039.           @netsend_address,
  14040.           0,
  14041.           0,
  14042.           @category_id)
  14043.  
  14044.   RETURN(@@error) -- 0 means success
  14045. END
  14046. go
  14047.  
  14048. /**************************************************************/
  14049. /* SP_UPDATE_OPERATOR                                         */
  14050. /**************************************************************/
  14051.  
  14052. PRINT ''
  14053. PRINT 'Creating procedure sp_update_operator...'
  14054. go
  14055. IF (EXISTS (SELECT *
  14056.             FROM msdb.dbo.sysobjects
  14057.             WHERE (name = N'sp_update_operator')
  14058.               AND (type = 'P')))
  14059.   DROP PROCEDURE sp_update_operator
  14060. go
  14061. CREATE PROCEDURE sp_update_operator
  14062.   @name                      sysname,
  14063.   @new_name                  sysname       = NULL,
  14064.   @enabled                   TINYINT       = NULL,
  14065.   @email_address             NVARCHAR(100) = NULL,
  14066.   @pager_address             NVARCHAR(100) = NULL,
  14067.   @weekday_pager_start_time  INT           = NULL, -- HHMMSS using 24 hour clock
  14068.   @weekday_pager_end_time    INT           = NULL, -- As above
  14069.   @saturday_pager_start_time INT           = NULL, -- As above
  14070.   @saturday_pager_end_time   INT           = NULL, -- As above
  14071.   @sunday_pager_start_time   INT           = NULL, -- As above
  14072.   @sunday_pager_end_time     INT           = NULL, -- As above
  14073.   @pager_days                TINYINT       = NULL,
  14074.   @netsend_address           NVARCHAR(100) = NULL, -- New for 7.0
  14075.   @category_name             sysname       = NULL  -- New for 7.0
  14076. AS
  14077. BEGIN
  14078.   DECLARE @x_enabled                   TINYINT
  14079.   DECLARE @x_email_address             NVARCHAR(100)
  14080.   DECLARE @x_pager_address             NVARCHAR(100)
  14081.   DECLARE @x_weekday_pager_start_time  INT
  14082.   DECLARE @x_weekday_pager_end_time    INT
  14083.   DECLARE @x_saturday_pager_start_time INT
  14084.   DECLARE @x_saturday_pager_end_time   INT
  14085.   DECLARE @x_sunday_pager_start_time   INT
  14086.   DECLARE @x_sunday_pager_end_time     INT
  14087.   DECLARE @x_pager_days                TINYINT
  14088.   DECLARE @x_netsend_address           NVARCHAR(100)
  14089.   DECLARE @x_category_id               INT
  14090.  
  14091.   DECLARE @return_code                 INT
  14092.   DECLARE @notification_method         INT
  14093.   DECLARE @alert_fail_safe_operator    sysname
  14094.   DECLARE @current_msx_server          NVARCHAR(30)
  14095.   DECLARE @category_id                 INT
  14096.  
  14097.   SET NOCOUNT ON
  14098.  
  14099.   -- Remove any leading/trailing spaces from parameters
  14100.   SELECT @name            = LTRIM(RTRIM(@name))
  14101.   SELECT @new_name        = LTRIM(RTRIM(@new_name))
  14102.   SELECT @email_address   = LTRIM(RTRIM(@email_address))
  14103.   SELECT @pager_address   = LTRIM(RTRIM(@pager_address))
  14104.   SELECT @netsend_address = LTRIM(RTRIM(@netsend_address))
  14105.   SELECT @category_name   = LTRIM(RTRIM(@category_name))
  14106.  
  14107.   -- Only a sysadmin can do this
  14108.   IF (ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) <> 1)
  14109.   BEGIN
  14110.     RAISERROR(15003, 16, 1, N'sysadmin')
  14111.     RETURN(1) -- Failure
  14112.   END
  14113.  
  14114.   -- Check if this Operator exists
  14115.   IF (NOT EXISTS (SELECT *
  14116.                   FROM msdb.dbo.sysoperators
  14117.                   WHERE (name = @name)))
  14118.   BEGIN
  14119.     RAISERROR(14262, 16, 1, '@name', @name)
  14120.     RETURN(1) -- Failure
  14121.   END
  14122.  
  14123.   -- Check if this operator is 'MSXOperator'
  14124.   IF (@name = N'MSXOperator')
  14125.   BEGIN
  14126.     -- Disallow the update operation if we're at a TSX for all callers other than xp_msx_enlist
  14127.     EXECUTE master.dbo.xp_instance_regread N'HKEY_LOCAL_MACHINE',
  14128.                                            N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
  14129.                                            N'MSXServerName',
  14130.                                            @current_msx_server OUTPUT,
  14131.                                            N'no_output'
  14132.     IF ((@current_msx_server IS NOT NULL) AND (PROGRAM_NAME() <> N'xp_msx_enlist'))
  14133.     BEGIN
  14134.       RAISERROR(14223, 16, 1, 'MSXOperator', 'TSX')
  14135.       RETURN(1) -- Failure
  14136.     END
  14137.   END
  14138.  
  14139.   -- Get existing (@x_) operator property values
  14140.   SELECT @x_enabled                   = enabled,
  14141.          @x_email_address             = email_address,
  14142.          @x_pager_address             = pager_address,
  14143.          @x_weekday_pager_start_time  = weekday_pager_start_time,
  14144.          @x_weekday_pager_end_time    = weekday_pager_end_time,
  14145.          @x_saturday_pager_start_time = saturday_pager_start_time,
  14146.          @x_saturday_pager_end_time   = saturday_pager_end_time,
  14147.          @x_sunday_pager_start_time   = sunday_pager_start_time,
  14148.          @x_sunday_pager_end_time     = sunday_pager_end_time,
  14149.          @x_pager_days                = pager_days,
  14150.          @x_netsend_address           = netsend_address,
  14151.          @x_category_id               = category_id
  14152.   FROM msdb.dbo.sysoperators
  14153.   WHERE (name = @name)
  14154.  
  14155.   -- Fill out the values for all non-supplied parameters from the existsing values
  14156.   IF (@enabled                   IS NULL) SELECT @enabled                   = @x_enabled
  14157.   IF (@email_address             IS NULL) SELECT @email_address             = @x_email_address
  14158.   IF (@pager_address             IS NULL) SELECT @pager_address             = @x_pager_address
  14159.   IF (@weekday_pager_start_time  IS NULL) SELECT @weekday_pager_start_time  = @x_weekday_pager_start_time
  14160.   IF (@weekday_pager_end_time    IS NULL) SELECT @weekday_pager_end_time    = @x_weekday_pager_end_time
  14161.   IF (@saturday_pager_start_time IS NULL) SELECT @saturday_pager_start_time = @x_saturday_pager_start_time
  14162.   IF (@saturday_pager_end_time   IS NULL) SELECT @saturday_pager_end_time   = @x_saturday_pager_end_time
  14163.   IF (@sunday_pager_start_time   IS NULL) SELECT @sunday_pager_start_time   = @x_sunday_pager_start_time
  14164.   IF (@sunday_pager_end_time     IS NULL) SELECT @sunday_pager_end_time     = @x_sunday_pager_end_time
  14165.   IF (@pager_days                IS NULL) SELECT @pager_days                = @x_pager_days
  14166.   IF (@netsend_address           IS NULL) SELECT @netsend_address           = @x_netsend_address
  14167.   IF (@category_name             IS NULL) SELECT @category_name = name FROM msdb.dbo.syscategories WHERE (category_id = @x_category_id)
  14168.  
  14169.   IF (@category_name IS NULL)
  14170.   BEGIN
  14171.     SELECT @category_name = name
  14172.     FROM msdb.dbo.syscategories
  14173.     WHERE (category_id = 99)
  14174.   END
  14175.  
  14176.   -- Turn [nullable] empty string parameters into NULLs
  14177.   IF (@email_address   = N'') SELECT @email_address   = NULL
  14178.   IF (@pager_address   = N'') SELECT @pager_address   = NULL
  14179.   IF (@netsend_address = N'') SELECT @netsend_address = NULL
  14180.   IF (@category_name   = N'') SELECT @category_name   = NULL
  14181.  
  14182.   -- Verify the operator
  14183.   EXECUTE @return_code = sp_verify_operator @new_name,
  14184.                                             @enabled,
  14185.                                             @pager_days,
  14186.                                             @weekday_pager_start_time,
  14187.                                             @weekday_pager_end_time,
  14188.                                             @saturday_pager_start_time,
  14189.                                             @saturday_pager_end_time,
  14190.                                             @sunday_pager_start_time,
  14191.                                             @sunday_pager_end_time,
  14192.                                             @category_name,
  14193.                                             @category_id OUTPUT
  14194.   IF (@return_code <> 0)
  14195.     RETURN(1) -- Failure
  14196.  
  14197.   -- If no new name is supplied, use the old one
  14198.   -- NOTE: We must do this AFTER calling sp_verify_operator.
  14199.   IF (@new_name IS NULL)
  14200.     SELECT @new_name = @name
  14201.   ELSE
  14202.   BEGIN
  14203.     -- You can't rename the MSXOperator
  14204.     IF (@name = N'MSXOperator')
  14205.     BEGIN
  14206.       RAISERROR(14222, 16, 1, 'MSXOperator')
  14207.       RETURN(1) -- Failure
  14208.     END
  14209.   END
  14210.  
  14211.   -- Do the UPDATE
  14212.   UPDATE msdb.dbo.sysoperators
  14213.   SET name                      = @new_name,
  14214.       enabled                   = @enabled,
  14215.       email_address             = @email_address,
  14216.       pager_address             = @pager_address,
  14217.       weekday_pager_start_time  = @weekday_pager_start_time,
  14218.       weekday_pager_end_time    = @weekday_pager_end_time,
  14219.       saturday_pager_start_time = @saturday_pager_start_time,
  14220.       saturday_pager_end_time   = @saturday_pager_end_time,
  14221.       sunday_pager_start_time   = @sunday_pager_start_time,
  14222.       sunday_pager_end_time     = @sunday_pager_end_time,
  14223.       pager_days                = @pager_days,
  14224.       netsend_address           = @netsend_address,
  14225.       category_id               = @category_id
  14226.   WHERE (name = @name)
  14227.  
  14228.   -- Check if the operator is 'MSXOperator', in which case we need to re-enlist all the targets
  14229.   -- so that they will download the new MSXOperator details
  14230.   IF ((@name = N'MSXOperator') AND ((SELECT COUNT(*) FROM msdb.dbo.systargetservers) > 0))
  14231.     EXECUTE msdb.dbo.sp_post_msx_operation 'RE-ENLIST', 'SERVER', 0x00
  14232.  
  14233.   -- Check if this operator is the FailSafe Operator
  14234.   EXECUTE master.dbo.xp_instance_regread N'HKEY_LOCAL_MACHINE',
  14235.                                          N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
  14236.                                          N'AlertFailSafeOperator',
  14237.                                          @alert_fail_safe_operator OUTPUT,
  14238.                                          N'no_output'
  14239.  
  14240.   -- If it is, we update the 4 'AlertFailSafe...' registry entries and AlertNotificationMethod
  14241.   IF (LTRIM(RTRIM(@alert_fail_safe_operator)) = @name)
  14242.   BEGIN
  14243.     -- Update AlertFailSafeX values
  14244.     EXECUTE master.dbo.xp_instance_regwrite N'HKEY_LOCAL_MACHINE',
  14245.                                             N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
  14246.                                             N'AlertFailSafeOperator',
  14247.                                             N'REG_SZ',
  14248.                                             @new_name
  14249.     EXECUTE master.dbo.xp_instance_regwrite N'HKEY_LOCAL_MACHINE',
  14250.                                             N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
  14251.                                             N'AlertFailSafeEmailAddress',
  14252.                                             N'REG_SZ',
  14253.                                             @email_address
  14254.     EXECUTE master.dbo.xp_instance_regwrite N'HKEY_LOCAL_MACHINE',
  14255.                                             N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
  14256.                                             N'AlertFailSafePagerAddress',
  14257.                                             N'REG_SZ',
  14258.                                             @pager_address
  14259.     EXECUTE master.dbo.xp_instance_regwrite N'HKEY_LOCAL_MACHINE',
  14260.                                             N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
  14261.                                             N'AlertFailSafeNetSendAddress',
  14262.                                             N'REG_SZ',
  14263.                                             @netsend_address
  14264.  
  14265.     -- Update AlertNotificationMethod values
  14266.     EXECUTE master.dbo.xp_instance_regread N'HKEY_LOCAL_MACHINE',
  14267.                                            N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
  14268.                                            N'AlertNotificationMethod',
  14269.                                            @notification_method OUTPUT,
  14270.                                            N'no_output'
  14271.     IF (LTRIM(RTRIM(@email_address)) IS NULL)
  14272.       SELECT @notification_method = @notification_method & ~1
  14273.     IF (LTRIM(RTRIM(@pager_address)) IS NULL)
  14274.       SELECT @notification_method = @notification_method & ~2
  14275.     IF (LTRIM(RTRIM(@netsend_address)) IS NULL)
  14276.       SELECT @notification_method = @notification_method & ~4
  14277.     EXECUTE master.dbo.xp_instance_regwrite N'HKEY_LOCAL_MACHINE',
  14278.                                             N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
  14279.                                             N'AlertNotificationMethod',
  14280.                                             N'REG_DWORD',
  14281.                                             @notification_method
  14282.  
  14283.     -- And finally, let SQLServerAgent know of the changes
  14284.     EXECUTE msdb.dbo.sp_sqlagent_notify @op_type = N'G'
  14285.   END
  14286.  
  14287.   RETURN(0) -- Success
  14288. END
  14289. go
  14290.  
  14291. /**************************************************************/
  14292. /* SP_DELETE_OPERATOR                                         */
  14293. /**************************************************************/
  14294.  
  14295. PRINT ''
  14296. PRINT 'Creating procedure sp_delete_operator...'
  14297. go
  14298. IF (EXISTS (SELECT *
  14299.             FROM msdb.dbo.sysobjects
  14300.             WHERE (name = N'sp_delete_operator')
  14301.               AND (type = 'P')))
  14302.   DROP PROCEDURE sp_delete_operator
  14303. go
  14304. CREATE PROCEDURE sp_delete_operator
  14305.   @name                 sysname,
  14306.   @reassign_to_operator sysname = NULL
  14307. AS
  14308. BEGIN
  14309.   DECLARE @id                         INT
  14310.   DECLARE @alert_fail_safe_operator   sysname
  14311.   DECLARE @job_id                     UNIQUEIDENTIFIER
  14312.   DECLARE @job_id_as_char             VARCHAR(36)
  14313.   DECLARE @notify_email_operator_id   INT
  14314.   DECLARE @notify_netsend_operator_id INT
  14315.   DECLARE @notify_page_operator_id    INT
  14316.   DECLARE @reassign_to_id             INT
  14317.   DECLARE @cmd                        NVARCHAR(512)
  14318.   DECLARE @current_msx_server         NVARCHAR(30)
  14319.  
  14320.   SET NOCOUNT ON
  14321.  
  14322.   -- Remove any leading/trailing spaces from parameters
  14323.   SELECT @name                 = LTRIM(RTRIM(@name))
  14324.   SELECT @reassign_to_operator = LTRIM(RTRIM(@reassign_to_operator))
  14325.  
  14326.   -- Turn [nullable] empty string parameters into NULLs
  14327.   IF (@reassign_to_operator = N'') SELECT @reassign_to_operator = NULL
  14328.  
  14329.   -- Only a sysadmin can do this
  14330.   IF (ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) <> 1)
  14331.   BEGIN
  14332.     RAISERROR(15003, 16, 1, N'sysadmin')
  14333.     RETURN(1) -- Failure
  14334.   END
  14335.  
  14336.   -- Check if this Operator exists
  14337.   IF (NOT EXISTS (SELECT *
  14338.                   FROM msdb.dbo.sysoperators
  14339.                   WHERE (name = @name)))
  14340.   BEGIN
  14341.     RAISERROR(14262, 16, 1, '@name', @name)
  14342.     RETURN(1) -- Failure
  14343.   END
  14344.  
  14345.   -- Check if this operator the FailSafe Operator
  14346.   EXECUTE master.dbo.xp_instance_regread N'HKEY_LOCAL_MACHINE',
  14347.                                          N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
  14348.                                          N'AlertFailSafeOperator',
  14349.                                          @alert_fail_safe_operator OUTPUT,
  14350.                                          N'no_output'
  14351.  
  14352.   -- If it is, we disallow the delete operation
  14353.   IF (LTRIM(RTRIM(@alert_fail_safe_operator)) = @name)
  14354.   BEGIN
  14355.     RAISERROR(14504, 16, 1, @name, @name)
  14356.     RETURN(1) -- Failure
  14357.   END
  14358.  
  14359.   -- Check if this operator is 'MSXOperator'
  14360.   IF (@name = N'MSXOperator')
  14361.   BEGIN
  14362.     DECLARE @server_type VARCHAR(3)
  14363.  
  14364.     -- Disallow the delete operation if we're an MSX or a TSX
  14365.     EXECUTE master.dbo.xp_instance_regread N'HKEY_LOCAL_MACHINE',
  14366.                                            N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
  14367.                                            N'MSXServerName',
  14368.                                            @current_msx_server OUTPUT,
  14369.                                            N'no_output'
  14370.     IF (@current_msx_server IS NOT NULL)
  14371.       SELECT @server_type = 'TSX'
  14372.  
  14373.     IF ((SELECT COUNT(*)
  14374.          FROM msdb.dbo.systargetservers) > 0)
  14375.       SELECT @server_type = 'MSX'
  14376.  
  14377.     IF (@server_type IS NOT NULL)
  14378.     BEGIN
  14379.       RAISERROR(14223, 16, 1, 'MSXOperator', @server_type)
  14380.       RETURN(1) -- Failure
  14381.     END
  14382.   END
  14383.  
  14384.   -- Convert the Name to it's ID
  14385.   SELECT @id = id
  14386.   FROM msdb.dbo.sysoperators
  14387.   WHERE (name = @name)
  14388.  
  14389.   IF (@reassign_to_operator IS NOT NULL)
  14390.   BEGIN
  14391.     -- On a TSX or standalone server, disallow re-assigning to the MSXOperator
  14392.     IF (@reassign_to_operator = N'MSXOperator') AND
  14393.        (NOT EXISTS (SELECT *
  14394.                     FROM msdb.dbo.systargetservers))
  14395.     BEGIN
  14396.       RAISERROR(14251, -1, -1, @reassign_to_operator)
  14397.       RETURN(1) -- Failure
  14398.     END
  14399.  
  14400.     SELECT @reassign_to_id = id
  14401.     FROM msdb.dbo.sysoperators
  14402.     WHERE (name = @reassign_to_operator)
  14403.  
  14404.     IF (@reassign_to_id IS NULL)
  14405.     BEGIN
  14406.       RAISERROR(14262, -1, -1, '@reassign_to_operator', @reassign_to_operator)
  14407.       RETURN(1) -- Failure
  14408.     END
  14409.   END
  14410.  
  14411.   -- Double up any single quotes in @reassign_to_operator
  14412.   IF (@reassign_to_operator IS NOT NULL)
  14413.     SELECT @reassign_to_operator = REPLACE(@reassign_to_operator, N'''', N'''''')
  14414.  
  14415.   BEGIN TRANSACTION
  14416.  
  14417.     -- Reassign (or delete) any sysnotifications rows that reference this operator
  14418.     IF (@reassign_to_operator IS NOT NULL)
  14419.     BEGIN
  14420.       UPDATE msdb.dbo.sysnotifications
  14421.       SET operator_id = @reassign_to_id
  14422.       WHERE (operator_id = @id)
  14423.         AND (NOT EXISTS (SELECT *
  14424.                          FROM msdb.dbo.sysnotifications sn2
  14425.                          WHERE (sn2.alert_id = msdb.dbo.sysnotifications.alert_id)
  14426.                            AND (sn2.operator_id = @reassign_to_id)))
  14427.     END
  14428.  
  14429.     DELETE FROM msdb.dbo.sysnotifications
  14430.     WHERE (operator_id = @id)
  14431.  
  14432.     -- Update any jobs that reference this operator
  14433.     DECLARE jobs_referencing_this_operator CURSOR LOCAL
  14434.     FOR
  14435.     SELECT job_id,
  14436.            notify_email_operator_id,
  14437.            notify_netsend_operator_id,
  14438.            notify_page_operator_id
  14439.     FROM msdb.dbo.sysjobs
  14440.     WHERE (notify_email_operator_id = @id)
  14441.        OR (notify_netsend_operator_id = @id)
  14442.        OR (notify_page_operator_id = @id)
  14443.  
  14444.     OPEN jobs_referencing_this_operator
  14445.     FETCH NEXT FROM jobs_referencing_this_operator INTO @job_id,
  14446.                                                         @notify_email_operator_id,
  14447.                                                         @notify_netsend_operator_id,
  14448.                                                         @notify_page_operator_id
  14449.     WHILE (@@fetch_status = 0)
  14450.     BEGIN
  14451.       SELECT @job_id_as_char = CONVERT(VARCHAR(36), @job_id)
  14452.       SELECT @cmd = N'msdb.dbo.sp_update_job @job_id = ''' + @job_id_as_char + N''', '
  14453.  
  14454.       IF (@notify_email_operator_id = @id)
  14455.         IF (@reassign_to_operator IS NOT NULL)
  14456.           SELECT @cmd = @cmd + N'@notify_email_operator_name = N''' + @reassign_to_operator + N''', '
  14457.         ELSE
  14458.           SELECT @cmd = @cmd + N'@notify_email_operator_name = N'''', @notify_level_email = 0, '
  14459.  
  14460.       IF (@notify_netsend_operator_id = @id)
  14461.         IF (@reassign_to_operator IS NOT NULL)
  14462.           SELECT @cmd = @cmd + N'@notify_netsend_operator_name = N''' + @reassign_to_operator + N''', '
  14463.         ELSE
  14464.           SELECT @cmd = @cmd + N'@notify_netsend_operator_name = N'''', @notify_level_netsend = 0, '
  14465.  
  14466.       IF (@notify_page_operator_id = @id)
  14467.         IF (@reassign_to_operator IS NOT NULL)
  14468.           SELECT @cmd = @cmd + N'@notify_page_operator_name = N''' + @reassign_to_operator + N''', '
  14469.         ELSE
  14470.           SELECT @cmd = @cmd + N'@notify_page_operator_name = N'''', @notify_level_page = 0, '
  14471.  
  14472.       SELECT @cmd = SUBSTRING(@cmd, 1, (DATALENGTH(@cmd) / 2) - 2)
  14473.       EXECUTE (N'EXECUTE ' + @cmd)
  14474.  
  14475.       FETCH NEXT FROM jobs_referencing_this_operator INTO @job_id,
  14476.                                                           @notify_email_operator_id,
  14477.                                                           @notify_netsend_operator_id,
  14478.                                                           @notify_page_operator_id
  14479.     END
  14480.     DEALLOCATE jobs_referencing_this_operator
  14481.  
  14482.     -- Finally, do the actual DELETE
  14483.     DELETE FROM msdb.dbo.sysoperators
  14484.     WHERE (id = @id)
  14485.  
  14486.   COMMIT TRANSACTION
  14487.  
  14488.   RETURN(@@error) -- 0 means success
  14489. END
  14490. go
  14491.  
  14492. /**************************************************************/
  14493. /* SP_HELP_OPERATOR                                           */
  14494. /**************************************************************/
  14495.  
  14496. PRINT ''
  14497. PRINT 'Creating procedure sp_help_operator...'
  14498. go
  14499. IF (EXISTS (SELECT *
  14500.             FROM msdb.dbo.sysobjects
  14501.             WHERE (name = N'sp_help_operator')
  14502.               AND (type = 'P')))
  14503.   DROP PROCEDURE sp_help_operator
  14504. go
  14505. CREATE PROCEDURE sp_help_operator
  14506.   @operator_name sysname = NULL,
  14507.   @operator_id   INT     = NULL
  14508. AS
  14509. BEGIN
  14510.   DECLARE @operator_id_as_char VARCHAR(10)
  14511.  
  14512.   SET NOCOUNT ON
  14513.  
  14514.   -- Remove any leading/trailing spaces from parameters
  14515.   SELECT @operator_name = LTRIM(RTRIM(@operator_name))
  14516.   IF (@operator_name = '') SELECT @operator_name = NULL
  14517.  
  14518.   -- Check operator name
  14519.   IF (@operator_name IS NOT NULL)
  14520.   BEGIN
  14521.     IF (NOT EXISTS (SELECT *
  14522.                     FROM msdb.dbo.sysoperators
  14523.                     WHERE (name = @operator_name)))
  14524.     BEGIN
  14525.       RAISERROR(14262, -1, -1, '@operator_name', @operator_name)
  14526.       RETURN(1) -- Failure
  14527.     END
  14528.   END
  14529.  
  14530.   -- Check operator id
  14531.   IF (@operator_id IS NOT NULL)
  14532.   BEGIN
  14533.     IF (NOT EXISTS (SELECT *
  14534.                     FROM msdb.dbo.sysoperators
  14535.                     WHERE (id = @operator_id)))
  14536.     BEGIN
  14537.       SELECT @operator_id_as_char = CONVERT(VARCHAR, @operator_id)
  14538.       RAISERROR(14262, -1, -1, '@operator_id', @operator_id_as_char)
  14539.       RETURN(1) -- Failure
  14540.     END
  14541.   END
  14542.  
  14543.   SELECT so.id,
  14544.          so.name,
  14545.          so.enabled,
  14546.          so.email_address,
  14547.          so.last_email_date,
  14548.          so.last_email_time,
  14549.          so.pager_address,
  14550.          so.last_pager_date,
  14551.          so.last_pager_time,
  14552.          so.weekday_pager_start_time,
  14553.          so.weekday_pager_end_time,
  14554.          so.saturday_pager_start_time,
  14555.          so.saturday_pager_end_time,
  14556.          so.sunday_pager_start_time,
  14557.          so.sunday_pager_end_time,
  14558.          so.pager_days,
  14559.          so.netsend_address,
  14560.          so.last_netsend_date,
  14561.          so.last_netsend_time,
  14562.          category_name = sc.name
  14563.   FROM msdb.dbo.sysoperators                  so
  14564.        LEFT OUTER JOIN msdb.dbo.syscategories sc ON (so.category_id = sc.category_id)
  14565.   WHERE ((@operator_name IS NULL) OR (so.name = @operator_name))
  14566.     AND ((@operator_id IS NULL) OR (so.id = @operator_id))
  14567.   ORDER BY so.name
  14568.  
  14569.   RETURN(@@error) -- 0 means success
  14570. END
  14571. go
  14572.  
  14573. /**************************************************************/
  14574. /* SP_HELP_OPERATOR_JOBS                                      */
  14575. /**************************************************************/
  14576.  
  14577. PRINT ''
  14578. PRINT 'Creating procedure sp_help_operator_jobs...'
  14579. go
  14580. IF (EXISTS (SELECT *
  14581.             FROM msdb.dbo.sysobjects
  14582.             WHERE (name = 'sp_help_operator_jobs')
  14583.               AND (type = 'P')))
  14584.   DROP PROCEDURE sp_help_operator_jobs
  14585. go
  14586. CREATE PROCEDURE sp_help_operator_jobs
  14587.   @operator_name sysname = NULL
  14588. AS
  14589. BEGIN
  14590.   DECLARE @operator_id INT
  14591.  
  14592.   SET NOCOUNT ON
  14593.  
  14594.   -- Check operator name
  14595.   SELECT @operator_id = id
  14596.   FROM msdb.dbo.sysoperators
  14597.   WHERE (name = @operator_name)
  14598.   IF (@operator_id IS NULL)
  14599.   BEGIN
  14600.     RAISERROR(14262, -1, -1, '@operator_name', @operator_name)
  14601.     RETURN(1) -- Failure
  14602.   END
  14603.  
  14604.   -- Get the job info
  14605.   SELECT job_id, name, notify_level_email, notify_level_netsend, notify_level_page
  14606.   FROM msdb.dbo.sysjobs_view
  14607.   WHERE ((notify_email_operator_id = @operator_id)   AND (notify_level_email <> 0))
  14608.      OR ((notify_netsend_operator_id = @operator_id) AND (notify_level_netsend <> 0))
  14609.      OR ((notify_page_operator_id = @operator_id)    AND (notify_level_page <> 0))
  14610.  
  14611.   RETURN(0) -- Success
  14612. END
  14613. go
  14614.  
  14615. /**************************************************************/
  14616. /* SP_VERIFY_NOTIFICATION                                     */
  14617. /**************************************************************/
  14618.  
  14619. PRINT ''
  14620. PRINT 'Creating procedure sp_verify_notification...'
  14621. go
  14622. IF (EXISTS (SELECT *
  14623.             FROM msdb.dbo.sysobjects
  14624.             WHERE (name = N'sp_verify_notification')
  14625.               AND (type = 'P')))
  14626.   DROP PROCEDURE sp_verify_notification
  14627. go
  14628. CREATE PROCEDURE sp_verify_notification
  14629.   @alert_name          sysname,
  14630.   @operator_name       sysname,
  14631.   @notification_method TINYINT,
  14632.   @alert_id            INT OUTPUT,
  14633.   @operator_id         INT OUTPUT
  14634. AS
  14635. BEGIN
  14636.   DECLARE @res_valid_range NVARCHAR(100)
  14637.  
  14638.   SET NOCOUNT ON
  14639.  
  14640.   SELECT @res_valid_range = FORMATMESSAGE(14208)
  14641.  
  14642.   -- Remove any leading/trailing spaces from parameters
  14643.   SELECT @alert_name    = LTRIM(RTRIM(@alert_name))
  14644.   SELECT @operator_name = LTRIM(RTRIM(@operator_name))
  14645.  
  14646.   -- Check if the AlertName is valid
  14647.   SELECT @alert_id = id
  14648.   FROM msdb.dbo.sysalerts
  14649.   WHERE (name = @alert_name)
  14650.  
  14651.   IF (@alert_id IS NULL)
  14652.   BEGIN
  14653.     RAISERROR(14262, 16, 1, '@alert_name', @alert_name)
  14654.     RETURN(1) -- Failure
  14655.   END
  14656.  
  14657.   -- Check if the OperatorName is valid
  14658.   SELECT @operator_id = id
  14659.   FROM msdb.dbo.sysoperators
  14660.   WHERE (name = @operator_name)
  14661.  
  14662.   IF (@operator_id IS NULL)
  14663.   BEGIN
  14664.     RAISERROR(14262, 16, 1, '@operator_name', @operator_name)
  14665.     RETURN(1) -- Failure
  14666.   END
  14667.  
  14668.   -- If we're at a TSX, we disallow using operator 'MSXOperator'
  14669.   IF (NOT EXISTS (SELECT *
  14670.                   FROM msdb.dbo.systargetservers)) AND
  14671.      (@operator_name = N'MSXOperator')
  14672.   BEGIN
  14673.     RAISERROR(14251, -1, -1, @operator_name)
  14674.     RETURN(1) -- Failure
  14675.   END
  14676.  
  14677.   -- Check if the NotificationMethod is valid
  14678.   IF ((@notification_method < 1) OR (@notification_method > 7))
  14679.   BEGIN
  14680.     RAISERROR(14266, 16, 1, '@notification_method', @res_valid_range)
  14681.     RETURN(1) -- Failure
  14682.   END
  14683.  
  14684.   RETURN(0) -- Success
  14685. END
  14686. go
  14687.  
  14688. /**************************************************************/
  14689. /* SP_ADD_NOTIFICATION                                        */
  14690. /**************************************************************/
  14691.  
  14692. PRINT ''
  14693. PRINT 'Creating procedure sp_add_notification...'
  14694. go
  14695. IF (EXISTS (SELECT *
  14696.             FROM msdb.dbo.sysobjects
  14697.             WHERE (name = N'sp_add_notification')
  14698.               AND (type = 'P')))
  14699.   DROP PROCEDURE sp_add_notification
  14700. go
  14701. CREATE PROCEDURE sp_add_notification
  14702.   @alert_name          sysname,
  14703.   @operator_name       sysname,
  14704.   @notification_method TINYINT -- 1 = Email, 2 = Pager, 4 = NetSend, 7 = All
  14705. AS
  14706. BEGIN
  14707.   DECLARE @alert_id             INT
  14708.   DECLARE @operator_id          INT
  14709.   DECLARE @notification         NVARCHAR(512)
  14710.   DECLARE @retval               INT
  14711.   DECLARE @old_has_notification INT
  14712.   DECLARE @new_has_notification INT
  14713.   DECLARE @res_notification     NVARCHAR(100)
  14714.  
  14715.   SET NOCOUNT ON
  14716.  
  14717.   SELECT @res_notification = FORMATMESSAGE(14210)
  14718.  
  14719.   -- Remove any leading/trailing spaces from parameters
  14720.   SELECT @alert_name    = LTRIM(RTRIM(@alert_name))
  14721.   SELECT @operator_name = LTRIM(RTRIM(@operator_name))
  14722.  
  14723.   -- Only a sysadmin can do this
  14724.   IF (ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) <> 1)
  14725.   BEGIN
  14726.     RAISERROR(15003, 16, 1, N'sysadmin')
  14727.     RETURN(1) -- Failure
  14728.   END
  14729.  
  14730.   -- Check if the Notification is valid
  14731.   EXECUTE @retval = msdb.dbo.sp_verify_notification @alert_name,
  14732.                                                     @operator_name,
  14733.                                                     @notification_method,
  14734.                                                     @alert_id     OUTPUT,
  14735.                                                     @operator_id  OUTPUT
  14736.   IF (@retval <> 0)
  14737.     RETURN(1) -- Failure
  14738.  
  14739.   -- Check if this notification already exists
  14740.   -- NOTE: The unique index would catch this, but testing for the problem here lets us
  14741.   --       control the message.
  14742.   IF (EXISTS (SELECT *
  14743.               FROM msdb.dbo.sysnotifications
  14744.               WHERE (alert_id = @alert_id)
  14745.                 AND (operator_id = @operator_id)))
  14746.   BEGIN
  14747.     SELECT @notification = @alert_name + N' / ' + @operator_name + N' / ' + CONVERT(NVARCHAR, @notification_method)
  14748.     RAISERROR(14261, 16, 1, @res_notification, @notification)
  14749.     RETURN(1) -- Failure
  14750.   END
  14751.  
  14752.   SELECT @old_has_notification = has_notification
  14753.   FROM msdb.dbo.sysalerts
  14754.   WHERE (id = @alert_id)
  14755.  
  14756.   -- Do the INSERT
  14757.   INSERT INTO msdb.dbo.sysnotifications
  14758.          (alert_id,
  14759.           operator_id,
  14760.           notification_method)
  14761.   VALUES (@alert_id,
  14762.           @operator_id,
  14763.           @notification_method)
  14764.  
  14765.   SELECT @retval = @@error
  14766.  
  14767.   SELECT @new_has_notification = has_notification
  14768.   FROM msdb.dbo.sysalerts
  14769.   WHERE (id = @alert_id)
  14770.  
  14771.   -- Notify SQLServerAgent of the change - if any - to has_notifications
  14772.   IF (@old_has_notification <> @new_has_notification)
  14773.     EXECUTE msdb.dbo.sp_sqlagent_notify @op_type     = N'A',
  14774.                                         @alert_id    = @alert_id,
  14775.                                         @action_type = N'U'
  14776.  
  14777.   RETURN(@retval) -- 0 means success
  14778. END
  14779. go
  14780.  
  14781. /**************************************************************/
  14782. /* SP_UPDATE_NOTIFICATION                                     */
  14783. /**************************************************************/
  14784.  
  14785. PRINT ''
  14786. PRINT 'Creating procedure sp_update_notification...'
  14787. go
  14788. IF (EXISTS (SELECT *
  14789.             FROM msdb.dbo.sysobjects
  14790.             WHERE (name = N'sp_update_notification')
  14791.               AND (type = 'P')))
  14792.   DROP PROCEDURE sp_update_notification
  14793. go
  14794. CREATE PROCEDURE sp_update_notification
  14795.   @alert_name          sysname,
  14796.   @operator_name       sysname,
  14797.   @notification_method TINYINT -- 1 = Email, 2 = Pager, 4 = NetSend, 7 = All
  14798. AS
  14799. BEGIN
  14800.   DECLARE @alert_id             INT
  14801.   DECLARE @operator_id          INT
  14802.   DECLARE @notification         NVARCHAR(512)
  14803.   DECLARE @retval               INT
  14804.   DECLARE @old_has_notification INT
  14805.   DECLARE @new_has_notification INT
  14806.   DECLARE @res_notification     NVARCHAR(100)
  14807.  
  14808.   SET NOCOUNT ON
  14809.  
  14810.   SELECT @res_notification = FORMATMESSAGE(14210)
  14811.  
  14812.   -- Remove any leading/trailing spaces from parameters
  14813.   SELECT @alert_name    = LTRIM(RTRIM(@alert_name))
  14814.   SELECT @operator_name = LTRIM(RTRIM(@operator_name))
  14815.  
  14816.   -- Only a sysadmin can do this
  14817.   IF (ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) <> 1)
  14818.   BEGIN
  14819.     RAISERROR(15003, 16, 1, N'sysadmin')
  14820.     RETURN(1) -- Failure
  14821.   END
  14822.  
  14823.   -- Check if the Notification is valid
  14824.   EXECUTE sp_verify_notification @alert_name,
  14825.                                  @operator_name,
  14826.                                  @notification_method,
  14827.                                  @alert_id     OUTPUT,
  14828.                                  @operator_id  OUTPUT
  14829.  
  14830.   -- Check if this notification exists
  14831.   IF (NOT EXISTS (SELECT *
  14832.                   FROM msdb.dbo.sysnotifications
  14833.                   WHERE (alert_id = @alert_id)
  14834.                     AND (operator_id = @operator_id)))
  14835.   BEGIN
  14836.     SELECT @notification = @alert_name + N' / ' + @operator_name
  14837.     RAISERROR(14262, 16, 1, @res_notification, @notification)
  14838.     RETURN(1) -- Failure
  14839.   END
  14840.  
  14841.   SELECT @old_has_notification = has_notification
  14842.   FROM msdb.dbo.sysalerts
  14843.   WHERE (id = @alert_id)
  14844.  
  14845.   -- Do the UPDATE
  14846.   UPDATE msdb.dbo.sysnotifications
  14847.   SET notification_method = @notification_method
  14848.   WHERE (alert_id = @alert_id)
  14849.     AND (operator_id = @operator_id)
  14850.  
  14851.   SELECT @retval = @@error
  14852.  
  14853.   SELECT @new_has_notification = has_notification
  14854.   FROM msdb.dbo.sysalerts
  14855.   WHERE (id = @alert_id)
  14856.  
  14857.   -- Notify SQLServerAgent of the change - if any - to has_notifications
  14858.   IF (@old_has_notification <> @new_has_notification)
  14859.     EXECUTE msdb.dbo.sp_sqlagent_notify @op_type       = N'A',
  14860.                                           @alert_id    = @alert_id,
  14861.                                           @action_type = N'U'
  14862.  
  14863.   RETURN(@retval) -- 0 means success
  14864. END
  14865. go
  14866.  
  14867. /**************************************************************/
  14868. /* SP_DELETE_NOTIFICATION                                     */
  14869. /**************************************************************/
  14870.  
  14871. PRINT ''
  14872. PRINT 'Creating procedure sp_delete_notification...'
  14873. go
  14874. IF (EXISTS (SELECT *
  14875.             FROM msdb.dbo.sysobjects
  14876.             WHERE (name = N'sp_delete_notification')
  14877.               AND (type = 'P')))
  14878.   DROP PROCEDURE sp_delete_notification
  14879. go
  14880. CREATE PROCEDURE sp_delete_notification
  14881.   @alert_name    sysname,
  14882.   @operator_name sysname
  14883. AS
  14884. BEGIN
  14885.   DECLARE @alert_id             INT
  14886.   DECLARE @operator_id          INT
  14887.   DECLARE @ignored              TINYINT
  14888.   DECLARE @notification         NVARCHAR(512)
  14889.   DECLARE @retval               INT
  14890.   DECLARE @old_has_notification INT
  14891.   DECLARE @new_has_notification INT
  14892.   DECLARE @res_notification     NVARCHAR(100)
  14893.  
  14894.   SET NOCOUNT ON
  14895.  
  14896.   SELECT @res_notification = FORMATMESSAGE(14210)
  14897.  
  14898.   -- Remove any leading/trailing spaces from parameters
  14899.   SELECT @alert_name    = LTRIM(RTRIM(@alert_name))
  14900.   SELECT @operator_name = LTRIM(RTRIM(@operator_name))
  14901.  
  14902.   -- Only a sysadmin can do this
  14903.   IF (ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) <> 1)
  14904.   BEGIN
  14905.     RAISERROR(15003, 16, 1, N'sysadmin')
  14906.     RETURN(1) -- Failure
  14907.   END
  14908.  
  14909.   -- Get the alert and operator ID's
  14910.   EXECUTE sp_verify_notification @alert_name,
  14911.                                  @operator_name,
  14912.                                  7,           -- A dummy (but valid) value
  14913.                                  @alert_id    OUTPUT,
  14914.                                  @operator_id OUTPUT
  14915.  
  14916.   -- Check if this notification exists
  14917.   IF (NOT EXISTS (SELECT *
  14918.                   FROM msdb.dbo.sysnotifications
  14919.                   WHERE (alert_id = @alert_id)
  14920.                     AND (operator_id = @operator_id)))
  14921.   BEGIN
  14922.     SELECT @notification = @alert_name + N' / ' + @operator_name
  14923.     RAISERROR(14262, 16, 1, @res_notification, @notification)
  14924.     RETURN(1) -- Failure
  14925.   END
  14926.  
  14927.   SELECT @old_has_notification = has_notification
  14928.   FROM msdb.dbo.sysalerts
  14929.   WHERE (id = @alert_id)
  14930.  
  14931.   -- Do the Delete
  14932.   DELETE FROM msdb.dbo.sysnotifications
  14933.   WHERE (alert_id = @alert_id)
  14934.     AND (operator_id = @operator_id)
  14935.  
  14936.   SELECT @retval = @@error
  14937.  
  14938.   SELECT @new_has_notification = has_notification
  14939.   FROM msdb.dbo.sysalerts
  14940.   WHERE (id = @alert_id)
  14941.  
  14942.   -- Notify SQLServerAgent of the change - if any - to has_notifications
  14943.   IF (@old_has_notification <> @new_has_notification)
  14944.     EXECUTE msdb.dbo.sp_sqlagent_notify @op_type       = N'A',
  14945.                                           @alert_id    = @alert_id,
  14946.                                           @action_type = N'U'
  14947.  
  14948.   RETURN(@retval) -- 0 means success
  14949. END
  14950. go
  14951.  
  14952. /**************************************************************/
  14953. /* SP_HELP_NOTIFICATION                                       */
  14954. /**************************************************************/
  14955.  
  14956. PRINT ''
  14957. PRINT 'Creating procedure sp_help_notification...'
  14958. go
  14959. IF (EXISTS (SELECT *
  14960.             FROM msdb.dbo.sysobjects
  14961.             WHERE (name = N'sp_help_notification')
  14962.               AND (type = 'P')))
  14963.   DROP PROCEDURE sp_help_notification
  14964. go
  14965. CREATE PROCEDURE sp_help_notification
  14966.   @object_type          CHAR(9),   -- Either 'ALERTS'    (enumerates Alerts for given Operator)
  14967.                                    --     or 'OPERATORS' (enumerates Operators for given Alert)
  14968.   @name                 sysname,   -- Either an Operator Name (if @object_type is 'ALERTS')
  14969.                                    --     or an Alert Name    (if @object_type is 'OPERATORS')
  14970.   @enum_type            CHAR(10),  -- Either 'ALL'    (enumerate all objects [eg. all alerts irrespective of whether 'Fred' receives a notification for them])
  14971.                                    --     or 'ACTUAL' (enumerate only the associated objects [eg. only the alerts which 'Fred' receives a notification for])
  14972.                                    --     or 'TARGET' (enumerate only the objects matching @target_name [eg. a single row showing how 'Fred' is notfied for alert 'Test'])
  14973.   @notification_method  TINYINT,   -- Either 1 (Email)   - Modifies the result set to only show use_email column
  14974.                                    --     or 2 (Pager)   - Modifies the result set to only show use_pager column
  14975.                                    --     or 4 (NetSend) - Modifies the result set to only show use_netsend column
  14976.                                    --     or 7 (All)     - Modifies the result set to show all the use_xxx columns
  14977.   @target_name   sysname = NULL    -- Either an Alert Name    (if @object_type is 'ALERTS')
  14978.                                    --     or an Operator Name (if @object_type is 'OPERATORS')
  14979.                                    -- NOTE: This parameter is only required if @enum_type is 'TARGET')
  14980. AS
  14981. BEGIN
  14982.   DECLARE @id              INT    -- We use this to store the decode of @name
  14983.   DECLARE @target_id       INT    -- We use this to store the decode of @target_name
  14984.   DECLARE @select_clause   NVARCHAR(1024)
  14985.   DECLARE @from_clause     NVARCHAR(512)
  14986.   DECLARE @where_clause    NVARCHAR(512)
  14987.   DECLARE @res_valid_range NVARCHAR(100)
  14988.  
  14989.   SET NOCOUNT ON
  14990.  
  14991.   SELECT @res_valid_range = FORMATMESSAGE(14208)
  14992.  
  14993.   -- Remove any leading/trailing spaces from parameters
  14994.   SELECT @object_type = UPPER(LTRIM(RTRIM(@object_type)))
  14995.   SELECT @name        = LTRIM(RTRIM(@name))
  14996.   SELECT @enum_type   = UPPER(LTRIM(RTRIM(@enum_type)))
  14997.   SELECT @target_name = LTRIM(RTRIM(@target_name))
  14998.  
  14999.   -- Turn [nullable] empty string parameters into NULLs
  15000.   IF (@target_name = N'') SELECT @target_name = NULL
  15001.  
  15002.   -- Check ObjectType
  15003.   IF (@object_type NOT IN ('ALERTS', 'OPERATORS'))
  15004.   BEGIN
  15005.     RAISERROR(14266, 16, 1, '@object_type', 'ALERTS, OPERATORS')
  15006.     RETURN(1) -- Failure
  15007.   END
  15008.  
  15009.   -- Check AlertName
  15010.   IF (@object_type = 'OPERATORS') AND
  15011.      (NOT EXISTS (SELECT *
  15012.                   FROM msdb.dbo.sysalerts
  15013.                   WHERE (name = @name)))
  15014.   BEGIN
  15015.     RAISERROR(14262, 16, 1, '@name', @name)
  15016.     RETURN(1) -- Failure
  15017.   END
  15018.  
  15019.   -- Check OperatorName
  15020.   IF (@object_type = 'ALERTS') AND
  15021.      (NOT EXISTS (SELECT *
  15022.                   FROM msdb.dbo.sysoperators
  15023.                   WHERE (name = @name)))
  15024.   BEGIN
  15025.     RAISERROR(14262, 16, 1, '@name', @name)
  15026.     RETURN(1) -- Failure
  15027.   END
  15028.  
  15029.   -- Check EnumType
  15030.   IF (@enum_type NOT IN ('ALL', 'ACTUAL', 'TARGET'))
  15031.   BEGIN
  15032.     RAISERROR(14266, 16, 1, '@enum_type', 'ALL, ACTUAL, TARGET')
  15033.     RETURN(1) -- Failure
  15034.   END
  15035.  
  15036.   -- Check Notification Method
  15037.   IF ((@notification_method < 1) OR (@notification_method > 7))
  15038.   BEGIN
  15039.     RAISERROR(14266, 16, 1, '@notification_method', @res_valid_range)
  15040.     RETURN(1) -- Failure
  15041.   END
  15042.  
  15043.   -- If EnumType is 'TARGET', check if we have a @TargetName parameter
  15044.   IF (@enum_type = 'TARGET') AND (@target_name IS NULL)
  15045.   BEGIN
  15046.     RAISERROR(14502, 16, 1)
  15047.     RETURN(1) -- Failure
  15048.   END
  15049.  
  15050.   -- If EnumType isn't 'TARGET', we shouldn't have an @target_name parameter
  15051.   IF (@enum_type <> 'TARGET') AND (@target_name IS NOT NULL)
  15052.   BEGIN
  15053.     RAISERROR(14503, 16, 1)
  15054.     RETURN(1) -- Failure
  15055.   END
  15056.  
  15057.   -- Translate the Name into an ID
  15058.   IF (@object_type = 'ALERTS')
  15059.   BEGIN
  15060.     SELECT @id = id
  15061.     FROM msdb.dbo.sysoperators
  15062.     WHERE (name = @name)
  15063.   END
  15064.   IF (@object_type = 'OPERATORS')
  15065.   BEGIN
  15066.     SELECT @id = id
  15067.     FROM msdb.dbo.sysalerts
  15068.     WHERE (name = @name)
  15069.   END
  15070.  
  15071.   -- Translate the TargetName into a TargetID
  15072.   IF (@target_name IS NOT NULL)
  15073.   BEGIN
  15074.     IF (@object_type = 'OPERATORS')
  15075.     BEGIN
  15076.       SELECT @target_id = id
  15077.       FROM msdb.dbo.sysoperators
  15078.       WHERE (name = @target_name )
  15079.     END
  15080.     IF (@object_type = 'ALERTS')
  15081.     BEGIN
  15082.       SELECT @target_id = id
  15083.       FROM msdb.dbo.sysalerts
  15084.       WHERE (name = @target_name)
  15085.     END
  15086.     IF (@target_id IS NULL) -- IE. the Target Name is invalid
  15087.     BEGIN
  15088.       RAISERROR(14262, 16, 1, @object_type, @target_name)
  15089.       RETURN(1) -- Failure
  15090.     END
  15091.   END
  15092.  
  15093.   -- Ok, the parameters look good so generate the SQL then EXECUTE() it...
  15094.  
  15095.   -- Generate the 'stub' SELECT clause and the FROM clause
  15096.   IF (@object_type = 'OPERATORS') -- So we want a list of Operators for the supplied AlertID
  15097.   BEGIN
  15098.     SELECT @select_clause = N'SELECT operator_id = o.id, operator_name = o.name, '
  15099.     IF (@enum_type = 'ALL')
  15100.       SELECT @from_clause = N'FROM msdb.dbo.sysoperators o LEFT OUTER JOIN msdb.dbo.sysnotifications sn ON (o.id = sn.operator_id) '
  15101.     ELSE
  15102.       SELECT @from_clause = N'FROM msdb.dbo.sysoperators o, msdb.dbo.sysnotifications sn '
  15103.   END
  15104.   IF (@object_type = 'ALERTS') -- So we want a list of Alerts for the supplied OperatorID
  15105.   BEGIN
  15106.     SELECT @select_clause = N'SELECT alert_id = a.id, alert_name = a.name, '
  15107.     IF (@enum_type = 'ALL')
  15108.       SELECT @from_clause = N'FROM msdb.dbo.sysalerts a LEFT OUTER JOIN msdb.dbo.sysnotifications sn ON (a.id = sn.alert_id) '
  15109.     ELSE
  15110.       SELECT @from_clause = N'FROM msdb.dbo.sysalerts a, msdb.dbo.sysnotifications sn '
  15111.   END
  15112.  
  15113.   -- Add the required use_xxx columns to the SELECT clause
  15114.   IF (@notification_method & 1 = 1)
  15115.     SELECT @select_clause = @select_clause + N'use_email = ISNULL((sn.notification_method & 1) / POWER(2, 0), 0), '
  15116.   IF (@notification_method & 2 = 2)
  15117.     SELECT @select_clause = @select_clause + N'use_pager = ISNULL((sn.notification_method & 2) / POWER(2, 1), 0), '
  15118.   IF (@notification_method & 4 = 4)
  15119.     SELECT @select_clause = @select_clause + N'use_netsend = ISNULL((sn.notification_method & 4) / POWER(2, 2), 0), '
  15120.  
  15121.   -- Remove the trailing comma
  15122.   SELECT @select_clause = SUBSTRING(@select_clause, 1, (DATALENGTH(@select_clause) / 2) - 2) + N' '
  15123.  
  15124.   -- Generate the WHERE clause
  15125.   IF (@object_type = 'OPERATORS')
  15126.   BEGIN
  15127.     IF (@enum_type = 'ALL')
  15128.       SELECT @from_clause = @from_clause + N' AND (sn.alert_id = ' + CONVERT(VARCHAR(10), @id) + N')'
  15129.  
  15130.     IF (@enum_type = 'ACTUAL')
  15131.       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)'
  15132.  
  15133.     IF (@enum_type = 'TARGET')
  15134.       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')'
  15135.   END
  15136.   IF (@object_type = 'ALERTS')
  15137.   BEGIN
  15138.     IF (@enum_type = 'ALL')
  15139.       SELECT @from_clause = @from_clause + N' AND (sn.operator_id = ' + CONVERT(VARCHAR(10), @id) + N')'
  15140.  
  15141.     IF (@enum_type = 'ACTUAL')
  15142.       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)'
  15143.  
  15144.     IF (@enum_type = 'TARGET')
  15145.       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')'
  15146.   END
  15147.  
  15148.   -- Add the has_email and has_pager columns to the SELECT clause
  15149.   IF (@object_type = 'OPERATORS')
  15150.   BEGIN
  15151.     SELECT @select_clause = @select_clause + N', has_email = PATINDEX(N''%[^ ]%'', ISNULL(o.email_address, N''''))'
  15152.     SELECT @select_clause = @select_clause + N', has_pager = PATINDEX(N''%[^ ]%'', ISNULL(o.pager_address, N''''))'
  15153.     SELECT @select_clause = @select_clause + N', has_netsend = PATINDEX(N''%[^ ]%'', ISNULL(o.netsend_address, N''''))'
  15154.   END
  15155.   IF (@object_type = 'ALERTS')
  15156.   BEGIN
  15157.     -- NOTE: We return counts so that the UI can detect 'unchecking' the last notification
  15158.     SELECT @select_clause = @select_clause + N', has_email = (SELECT COUNT(*) FROM sysnotifications WHERE (alert_id = a.id) AND ((notification_method & 1) = 1)) '
  15159.     SELECT @select_clause = @select_clause + N', has_pager = (SELECT COUNT(*) FROM sysnotifications WHERE (alert_id = a.id) AND ((notification_method & 2) = 2)) '
  15160.     SELECT @select_clause = @select_clause + N', has_netsend = (SELECT COUNT(*) FROM sysnotifications WHERE (alert_id = a.id) AND ((notification_method & 4) = 4)) '
  15161.   END
  15162.  
  15163.   EXECUTE (@select_clause + @from_clause + @where_clause)
  15164.  
  15165.   RETURN(@@error) -- 0 means success
  15166. END
  15167. go
  15168.  
  15169. DUMP TRANSACTION msdb WITH NO_LOG
  15170. go
  15171.  
  15172. /**************************************************************/
  15173. /*                                                            */
  15174. /*                    T  R  I G  G  E  R  S                   */
  15175. /*                                                            */
  15176. /**************************************************************/
  15177.  
  15178. /**************************************************************/
  15179. /* DROP THE OLD 6.x TRIGGERS                                  */
  15180. /* [multiple triggers of the same type are allowed in 7.0]    */
  15181. /**************************************************************/
  15182.  
  15183. IF (EXISTS (SELECT *
  15184.             FROM msdb.dbo.sysobjects
  15185.             WHERE (name = N'NewOrChangedNotification')
  15186.               AND (type = 'TR')))
  15187.   DROP TRIGGER NewOrChangedNotification
  15188.  
  15189. IF (EXISTS (SELECT *
  15190.             FROM msdb.dbo.sysobjects
  15191.             WHERE (name = N'RemovedNotification')
  15192.               AND (type = 'TR')))
  15193.   DROP TRIGGER RemovedNotification
  15194. go
  15195.  
  15196. /**************************************************************/
  15197. /* TRIG_NOTIFICATION_INS_OR_UPD                               */
  15198. /**************************************************************/
  15199.  
  15200. PRINT ''
  15201. PRINT 'Creating trigger trig_notification_ins_or_upd...'
  15202. go
  15203. IF (EXISTS (SELECT *
  15204.             FROM msdb.dbo.sysobjects
  15205.             WHERE (name = N'trig_notification_ins_or_upd')
  15206.               AND (type = 'TR')))
  15207.   DROP TRIGGER trig_notification_ins_or_upd
  15208. go
  15209. CREATE TRIGGER trig_notification_ins_or_upd
  15210. ON msdb.dbo.sysnotifications
  15211. FOR INSERT,
  15212.     UPDATE
  15213. AS
  15214. BEGIN
  15215.   SET NOCOUNT ON
  15216.  
  15217.   -- First, throw out 'non-notification' rows
  15218.   DELETE FROM msdb.dbo.sysnotifications
  15219.   WHERE (notification_method = 0)
  15220.  
  15221.   -- Reset the has_notification flag for the affected alerts
  15222.   UPDATE msdb.dbo.sysalerts
  15223.   SET has_notification = 0
  15224.   FROM inserted           i,
  15225.        msdb.dbo.sysalerts sa
  15226.   WHERE (i.alert_id = sa.id)
  15227.  
  15228.   -- Update sysalerts.has_notification (for email)
  15229.   UPDATE msdb.dbo.sysalerts
  15230.   SET has_notification = has_notification | 1
  15231.   FROM msdb.dbo.sysalerts        sa,
  15232.        msdb.dbo.sysnotifications sn,
  15233.        inserted                  i
  15234.   WHERE (sa.id = sn.alert_id)
  15235.     AND (sa.id = i.alert_id)
  15236.     AND ((sn.notification_method & 1) = 1)
  15237.  
  15238.   -- Update sysalerts.has_notification (for pager)
  15239.   UPDATE msdb.dbo.sysalerts
  15240.   SET has_notification = has_notification | 2
  15241.   FROM msdb.dbo.sysalerts        sa,
  15242.        msdb.dbo.sysnotifications sn,
  15243.        inserted                  i
  15244.   WHERE (sa.id = sn.alert_id)
  15245.     AND (sa.id = i.alert_id)
  15246.     AND ((sn.notification_method & 2) = 2)
  15247.  
  15248.   -- Update sysalerts.has_notification (for netsend)
  15249.   UPDATE msdb.dbo.sysalerts
  15250.   SET has_notification = has_notification | 4
  15251.   FROM msdb.dbo.sysalerts        sa,
  15252.        msdb.dbo.sysnotifications sn,
  15253.        inserted                  i
  15254.   WHERE (sa.id = sn.alert_id)
  15255.     AND (sa.id = i.alert_id)
  15256.     AND ((sn.notification_method & 4) = 4)
  15257. END
  15258. go
  15259.  
  15260. /**************************************************************/
  15261. /* TRIG_NOTIFICATION_DELETE                                   */
  15262. /**************************************************************/
  15263.  
  15264. PRINT ''
  15265. PRINT 'Creating trigger trig_notification_delete...'
  15266. go
  15267. IF (EXISTS (SELECT *
  15268.             FROM msdb.dbo.sysobjects
  15269.             WHERE (name = N'trig_notification_delete')
  15270.               AND (type = 'TR')))
  15271.   DROP TRIGGER trig_notification_delete
  15272. go
  15273. CREATE TRIGGER trig_notification_delete
  15274. ON msdb.dbo.sysnotifications
  15275. FOR DELETE
  15276. AS
  15277. BEGIN
  15278.   SET NOCOUNT ON
  15279.  
  15280.   -- Reset the has_notification flag for the affected alerts
  15281.   UPDATE msdb.dbo.sysalerts
  15282.   SET has_notification = 0
  15283.   FROM deleted            d,
  15284.        msdb.dbo.sysalerts sa
  15285.   WHERE (d.alert_id = sa.id)
  15286.  
  15287.   -- Update sysalerts.has_notification (for email)
  15288.   UPDATE msdb.dbo.sysalerts
  15289.   SET has_notification = has_notification | 1
  15290.   FROM msdb.dbo.sysalerts        sa,
  15291.        msdb.dbo.sysnotifications sn,
  15292.        deleted                   d
  15293.   WHERE (sa.id = sn.alert_id)
  15294.     AND (sa.id = d.alert_id)
  15295.     AND ((sn.notification_method & 1) = 1)
  15296.  
  15297.   -- Update sysalerts.has_notification (for pager)
  15298.   UPDATE msdb.dbo.sysalerts
  15299.   SET has_notification = has_notification | 2
  15300.   FROM msdb.dbo.sysalerts        sa,
  15301.        msdb.dbo.sysnotifications sn,
  15302.        deleted                   d
  15303.   WHERE (sa.id = sn.alert_id)
  15304.     AND (sa.id = d.alert_id)
  15305.     AND ((sn.notification_method & 2) = 2)
  15306.  
  15307.   -- Update sysalerts.has_notification (for netsend)
  15308.   UPDATE msdb.dbo.sysalerts
  15309.   SET has_notification = has_notification | 4
  15310.   FROM msdb.dbo.sysalerts        sa,
  15311.        msdb.dbo.sysnotifications sn,
  15312.        deleted                   d
  15313.   WHERE (sa.id = sn.alert_id)
  15314.     AND (sa.id = d.alert_id)
  15315.     AND ((sn.notification_method & 4) = 4)
  15316. END
  15317. go
  15318.  
  15319. DUMP TRANSACTION msdb WITH NO_LOG
  15320. go
  15321.  
  15322. /**************************************************************/
  15323. /*                                                            */
  15324. /*          D  E  F  A  U  L  T    A  L  E  R  T  S           */
  15325. /*                                                            */
  15326. /**************************************************************/
  15327.  
  15328. PRINT ''
  15329. PRINT 'Installing default alerts...'
  15330. go
  15331.  
  15332. EXECUTE master.dbo.sp_altermessage 9002, 'WITH_LOG', TRUE
  15333. go
  15334.  
  15335. IF (NOT EXISTS (SELECT *
  15336.                 FROM msdb.dbo.sysalerts
  15337.                 WHERE (name = N'Demo: Full msdb log')
  15338.                    OR ((severity = 0) AND
  15339.                        (message_id = 9002) AND
  15340.                        (database_name = N'msdb') AND
  15341.                        (event_description_keyword IS NULL) AND
  15342.                        (performance_condition IS NULL))))
  15343.   EXECUTE msdb.dbo.sp_add_alert @name = N'Demo: Full msdb log',
  15344.                                 @message_id = 9002,
  15345.                                 @severity = 0,
  15346.                                 @enabled = 1,
  15347.                                 @delay_between_responses = 10,
  15348.                                 @database_name = N'msdb',
  15349.                                 @notification_message = NULL,
  15350.                                 @job_name = NULL,
  15351.                                 @event_description_keyword = NULL,
  15352.                                 @include_event_description_in = 5 -- Email and NetSend
  15353. go
  15354.  
  15355. IF (NOT EXISTS (SELECT *
  15356.                 FROM msdb.dbo.sysalerts
  15357.                 WHERE (name = N'Demo: Full tempdb')
  15358.                    OR ((severity = 0) AND
  15359.                        (message_id = 9002) AND
  15360.                        (database_name = N'tempdb') AND
  15361.                        (event_description_keyword IS NULL) AND
  15362.                        (performance_condition IS NULL))))
  15363.   EXECUTE msdb.dbo.sp_add_alert @name = N'Demo: Full tempdb',
  15364.                                 @message_id = 9002,
  15365.                                 @severity = 0,
  15366.                                 @enabled = 1,
  15367.                                 @delay_between_responses = 10,
  15368.                                 @database_name = N'tempdb',
  15369.                                 @notification_message = NULL,
  15370.                                 @job_name = NULL,
  15371.                                 @event_description_keyword = NULL,
  15372.                                 @include_event_description_in = 5 -- Email and NetSend
  15373. go
  15374.  
  15375. IF (NOT EXISTS (SELECT *
  15376.                 FROM msdb.dbo.sysalerts
  15377.                 WHERE (name = N'Demo: Sev. 19 Errors')
  15378.                    OR ((severity = 19) AND
  15379.                        (message_id = 0) AND
  15380.                        (database_name IS NULL) AND
  15381.                        (event_description_keyword IS NULL) AND
  15382.                        (performance_condition IS NULL))))
  15383.   EXECUTE msdb.dbo.sp_add_alert @name = N'Demo: Sev. 19 Errors',
  15384.                                 @message_id = 0,
  15385.                                 @severity = 19,
  15386.                                 @enabled = 1,
  15387.                                 @delay_between_responses = 10,
  15388.                                 @database_name = NULL,
  15389.                                 @notification_message = NULL,
  15390.                                 @job_name = NULL,
  15391.                                 @event_description_keyword = NULL,
  15392.                                 @include_event_description_in = 5 -- Email and NetSend
  15393. go
  15394.  
  15395. IF (NOT EXISTS (SELECT *
  15396.                 FROM msdb.dbo.sysalerts
  15397.                 WHERE (name = N'Demo: Sev. 20 Errors')
  15398.                    OR ((severity = 20) AND
  15399.                        (message_id = 0) AND
  15400.                        (database_name IS NULL) AND
  15401.                        (event_description_keyword IS NULL) AND
  15402.                        (performance_condition IS NULL))))
  15403.   EXECUTE msdb.dbo.sp_add_alert @name = N'Demo: Sev. 20 Errors',
  15404.                                 @message_id = 0,
  15405.                                 @severity = 20,
  15406.                                 @enabled = 1,
  15407.                                 @delay_between_responses = 10,
  15408.                                 @database_name = NULL,
  15409.                                 @notification_message = NULL,
  15410.                                 @job_name = NULL,
  15411.                                 @event_description_keyword = NULL,
  15412.                                 @include_event_description_in = 5 -- Email and NetSend
  15413. go
  15414.  
  15415. IF (NOT EXISTS (SELECT *
  15416.                 FROM msdb.dbo.sysalerts
  15417.                 WHERE (name = N'Demo: Sev. 21 Errors')
  15418.                    OR ((severity = 21) AND
  15419.                        (message_id = 0) AND
  15420.                        (database_name IS NULL) AND
  15421.                        (event_description_keyword IS NULL) AND
  15422.                        (performance_condition IS NULL))))
  15423.   EXECUTE msdb.dbo.sp_add_alert @name = N'Demo: Sev. 21 Errors',
  15424.                                 @message_id = 0,
  15425.                                 @severity = 21,
  15426.                                 @enabled = 1,
  15427.                                 @delay_between_responses = 10,
  15428.                                 @database_name = NULL,
  15429.                                 @notification_message = NULL,
  15430.                                 @job_name = NULL,
  15431.                                 @event_description_keyword = NULL,
  15432.                                 @include_event_description_in = 5 -- Email and NetSend
  15433. go
  15434.  
  15435. IF (NOT EXISTS (SELECT *
  15436.                 FROM msdb.dbo.sysalerts
  15437.                 WHERE (name = N'Demo: Sev. 22 Errors')
  15438.                    OR ((severity = 22) AND
  15439.                        (message_id = 0) AND
  15440.                        (database_name IS NULL) AND
  15441.                        (event_description_keyword IS NULL) AND
  15442.                        (performance_condition IS NULL))))
  15443.   EXECUTE msdb.dbo.sp_add_alert @name = N'Demo: Sev. 22 Errors',
  15444.                                 @message_id = 0,
  15445.                                 @severity = 22,
  15446.                                 @enabled = 1,
  15447.                                 @delay_between_responses = 10,
  15448.                                 @database_name = NULL,
  15449.                                 @notification_message = NULL,
  15450.                                 @job_name = NULL,
  15451.                                 @event_description_keyword = NULL,
  15452.                                 @include_event_description_in = 5 -- Email and NetSend
  15453. go
  15454.  
  15455. IF (NOT EXISTS (SELECT *
  15456.                 FROM msdb.dbo.sysalerts
  15457.                 WHERE name = N'Demo: Sev. 23 Errors'
  15458.                    OR ((severity = 23) AND
  15459.                        (message_id = 0) AND
  15460.                        (database_name IS NULL) AND
  15461.                        (event_description_keyword IS NULL) AND
  15462.                        (performance_condition IS NULL))))
  15463.   EXECUTE msdb.dbo.sp_add_alert @name = N'Demo: Sev. 23 Errors',
  15464.                                 @message_id = 0,
  15465.                                 @severity = 23,
  15466.                                 @enabled = 1,
  15467.                                 @delay_between_responses = 10,
  15468.                                 @database_name = NULL,
  15469.                                 @notification_message = NULL,
  15470.                                 @job_name = NULL,
  15471.                                 @event_description_keyword = NULL,
  15472.                                 @include_event_description_in = 5 -- Email and NetSend
  15473. go
  15474.  
  15475. IF (NOT EXISTS (SELECT *
  15476.                 FROM msdb.dbo.sysalerts
  15477.                 WHERE (name = N'Demo: Sev. 24 Errors')
  15478.                    OR ((severity = 24) AND
  15479.                        (message_id = 0) AND
  15480.                        (database_name IS NULL) AND
  15481.                        (event_description_keyword IS NULL) AND
  15482.                        (performance_condition IS NULL))))
  15483.   EXECUTE msdb.dbo.sp_add_alert @name = N'Demo: Sev. 24 Errors',
  15484.                                 @message_id = 0,
  15485.                                 @severity = 24,
  15486.                                 @enabled = 1,
  15487.                                 @delay_between_responses = 10,
  15488.                                 @database_name = NULL,
  15489.                                 @notification_message = NULL,
  15490.                                 @job_name = NULL,
  15491.                                 @event_description_keyword = NULL,
  15492.                                 @include_event_description_in = 5 -- Email and NetSend
  15493. go
  15494.  
  15495. IF (NOT EXISTS (SELECT *
  15496.                 FROM msdb.dbo.sysalerts
  15497.                 WHERE (name = N'Demo: Sev. 25 Errors')
  15498.                    OR ((severity = 25) AND
  15499.                        (message_id = 0) AND
  15500.                        (database_name IS NULL) AND
  15501.                        (event_description_keyword IS NULL) AND
  15502.                        (performance_condition IS NULL))))
  15503.   EXECUTE msdb.dbo.sp_add_alert @name = N'Demo: Sev. 25 Errors',
  15504.                                 @message_id = 0,
  15505.                                 @severity = 25,
  15506.                                 @enabled = 1,
  15507.                                 @delay_between_responses = 10,
  15508.                                 @database_name = NULL,
  15509.                                 @notification_message = NULL,
  15510.                                 @job_name = NULL,
  15511.                                 @event_description_keyword = NULL,
  15512.                                 @include_event_description_in = 5 -- Email and NetSend
  15513. go
  15514.  
  15515.  
  15516. /**************************************************************/
  15517. /**                                                          **/
  15518. /**       B A C K U P   H I S T O R Y   S U P P O R T        **/
  15519. /**                                                          **/
  15520. /**************************************************************/
  15521.  
  15522. /**************************************************************/
  15523. /* T A B L E S                                                */
  15524. /**************************************************************/
  15525.  
  15526. /**************************************************************/
  15527. /* BACKUPMEDIASET                                             */
  15528. /**************************************************************/
  15529.  
  15530. IF (NOT EXISTS (SELECT *
  15531.                 FROM msdb.dbo.sysobjects
  15532.                 WHERE (name = 'backupmediaset')))
  15533. BEGIN
  15534.   PRINT ''
  15535.   PRINT 'Creating table backupmediaset...'
  15536.  
  15537.   CREATE TABLE backupmediaset
  15538.   (
  15539.   media_set_id       INT IDENTITY     NOT NULL PRIMARY KEY,
  15540.   media_uuid         UNIQUEIDENTIFIER NULL,  -- Null if this media set only one media family
  15541.   media_family_count TINYINT          NULL,  -- Number of media families in the media set
  15542.   name               NVARCHAR(128)    NULL,
  15543.   description        NVARCHAR(255)    NULL,
  15544.   software_name      NVARCHAR(128)    NULL,
  15545.   software_vendor_id INT              NULL,
  15546.   MTF_major_version  TINYINT          NULL
  15547.   )
  15548.  
  15549.   CREATE INDEX backupmediasetuuid ON backupmediaset (media_uuid)
  15550. END
  15551. go
  15552.  
  15553. /**************************************************************/
  15554. /* BACKUPMEDIAFAMILY                                          */
  15555. /**************************************************************/
  15556.  
  15557. IF (NOT EXISTS (SELECT *
  15558.                 FROM msdb.dbo.sysobjects
  15559.                 WHERE (name = 'backupmediafamily')))
  15560. BEGIN
  15561.   PRINT ''
  15562.   PRINT 'Creating table backupmediafamily...'
  15563.  
  15564.   CREATE TABLE backupmediafamily
  15565.   (
  15566.   media_set_id           INT              NOT NULL REFERENCES backupmediaset(media_set_id),
  15567.   family_sequence_number TINYINT          NOT NULL, -- Raid sequence number
  15568.   media_family_id        UNIQUEIDENTIFIER NULL,     -- This will be a uuid in MTF 2.0, allow space
  15569.   media_count            INT              NULL,     -- Number of media in the family
  15570.   logical_device_name    NVARCHAR(128)    NULL,     -- Name from sysdevices, if any
  15571.   physical_device_name   NVARCHAR(260)    NULL,     -- To facilitate restores from online media (disk)
  15572.   device_type            TINYINT          NULL,  -- Disk, tape, pipe, ...
  15573.   physical_block_size    INT              NULL
  15574.   PRIMARY KEY (media_set_id, family_sequence_number)
  15575.   )
  15576.  
  15577.   CREATE INDEX backupmediafamilyuuid ON backupmediafamily (media_family_id)
  15578. END
  15579. go
  15580.  
  15581. /**************************************************************/
  15582. /* BACKUPSET - One row per backup operation.                  */
  15583. /**************************************************************/
  15584.  
  15585. IF (NOT EXISTS (SELECT *
  15586.                 FROM msdb.dbo.sysobjects
  15587.                 WHERE (name = 'backupset')))
  15588. BEGIN
  15589.   PRINT ''
  15590.   PRINT 'Creating table backupset...'
  15591.  
  15592.   CREATE TABLE backupset
  15593.   (
  15594.   backup_set_id          INT IDENTITY     NOT NULL PRIMARY KEY,
  15595.   backup_set_uuid        UNIQUEIDENTIFIER NOT NULL,
  15596.   media_set_id           INT              NOT NULL REFERENCES backupmediaset(media_set_id),
  15597.   first_family_number    TINYINT          NULL,  -- family number & media number of the media
  15598.   first_media_number     SMALLINT         NULL,  -- containing the start of this backup (first SSET)
  15599.   last_family_number     TINYINT          NULL,  -- family number & media number of the media
  15600.   last_media_number      SMALLINT         NULL,  -- containing the end of this backup (ESET after MBC)
  15601.   catalog_family_number  TINYINT          NULL,  -- family number & media number of the media
  15602.   catalog_media_number   SMALLINT         NULL,  -- containing the start of the 'directory' data stream
  15603.  
  15604.   position               INT              NULL,  -- For FILE=
  15605.   expiration_date        DATETIME         NULL,
  15606.  
  15607.   -- From SSET...
  15608.   software_vendor_id     INT              NULL,  -- Might want table for sw vendors
  15609.   name                   NVARCHAR(128)    NULL,
  15610.   description            NVARCHAR(255)    NULL,
  15611.   user_name              NVARCHAR(128)    NULL,
  15612.   software_major_version TINYINT          NULL,    
  15613.   software_minor_version TINYINT          NULL,    
  15614.   software_build_version SMALLINT         NULL,
  15615.   time_zone              SMALLINT         NULL,        
  15616.   mtf_minor_version      TINYINT          NULL,
  15617.  
  15618.   -- From CONFIG_INFO...
  15619.   first_lsn              NUMERIC(25,0)    NULL,
  15620.   last_lsn               NUMERIC(25,0)    NULL,
  15621.   checkpoint_lsn         NUMERIC(25,0)    NULL,
  15622.   database_backup_lsn    NUMERIC(25,0)    NULL,
  15623.   database_creation_date DATETIME         NULL,
  15624.   backup_start_date      DATETIME         NULL,
  15625.   backup_finish_date     DATETIME         NULL,
  15626.   type                   CHAR(1)          NULL,
  15627.   sort_order             SMALLINT         NULL,
  15628.   code_page              SMALLINT         NULL,
  15629.   compatibility_level    TINYINT          NULL,
  15630.   database_version       INT              NULL,
  15631.   backup_size            NUMERIC(20,0)    NULL,
  15632.   database_name          NVARCHAR(128)    NULL,
  15633.   server_name            NVARCHAR(128)    NULL,
  15634.   machine_name           NVARCHAR(128)    NULL,
  15635.   flags                  INT              NULL,
  15636.   unicode_locale         INT              NULL,
  15637.   unicode_compare_style  INT              NULL,
  15638.   collation_name         NVARCHAR(128)    NULL
  15639.   )
  15640.  
  15641.   CREATE INDEX backupsetuuid ON backupset (backup_set_uuid)
  15642. END
  15643. ELSE
  15644. BEGIN
  15645.   IF NOT EXISTS (
  15646.     select * from msdb.dbo.syscolumns where name='flags' and id =
  15647.         (select id from msdb.dbo.sysobjects where name='backupset'))
  15648.  
  15649.     ALTER TABLE backupset ADD flags INT NULL
  15650.  
  15651.   IF NOT EXISTS (
  15652.     select * from msdb.dbo.syscolumns where name='collation_name' and id =
  15653.         (select id from msdb.dbo.sysobjects where name='backupset'))
  15654.  
  15655.     ALTER TABLE backupset ADD
  15656.       unicode_locale         INT              NULL,
  15657.       unicode_compare_style  INT              NULL,
  15658.       collation_name         NVARCHAR(128)    NULL
  15659. END
  15660. go
  15661.  
  15662. /**************************************************************/
  15663. /* BACKUPFILE - One row per file backed up (data file, log    */
  15664. /*              file)                                         */
  15665. /**************************************************************/
  15666.  
  15667. IF (NOT EXISTS (SELECT *
  15668.                 FROM msdb.dbo.sysobjects
  15669.                 WHERE (name = 'backupfile')))
  15670. BEGIN
  15671.   PRINT ''
  15672.   PRINT 'Creating table backupfile...'
  15673.  
  15674.   CREATE TABLE backupfile
  15675.   (
  15676.   backup_set_id          INT           NOT NULL REFERENCES backupset(backup_set_id),
  15677.   first_family_number    TINYINT       NULL,     -- Family number & media number of he first media
  15678.   first_media_number     SMALLINT      NULL,     -- containing this file
  15679.   filegroup_name         NVARCHAR(128) NULL,
  15680.   page_size              INT           NULL,
  15681.   file_number            NUMERIC(10,0) NOT NULL,
  15682.   backed_up_page_count   NUMERIC(10,0) NULL,
  15683.   file_type              CHAR(1)       NULL,     -- database or log
  15684.   source_file_block_size NUMERIC(10,0) NULL,
  15685.   file_size              NUMERIC(20,0) NULL,
  15686.   logical_name           NVARCHAR(128) NULL,
  15687.   physical_drive         VARCHAR(260)  NULL,     -- Drive or partition name
  15688.   physical_name          VARCHAR(260)  NULL      -- Remainder of physical (OS) filename
  15689.   PRIMARY KEY (backup_set_id, file_number)
  15690.   )
  15691. END
  15692. go
  15693.  
  15694. /**************************************************************/
  15695. /* RESTOREHISTORY - One row per restore operation.            */
  15696. /**************************************************************/
  15697.  
  15698. IF (NOT EXISTS (SELECT *
  15699.                 FROM msdb.dbo.sysobjects
  15700.                 WHERE (name = 'restorehistory')))
  15701. BEGIN
  15702.   PRINT ''
  15703.   PRINT 'Creating table restorehistory...'
  15704.  
  15705.   CREATE TABLE restorehistory
  15706.   (
  15707.   restore_history_id        INT           NOT NULL IDENTITY PRIMARY KEY,
  15708.   restore_date              DATETIME      NULL,
  15709.   destination_database_name NVARCHAR(128) NULL,
  15710.   user_name                 NVARCHAR(128) NULL,
  15711.   backup_set_id             INT           NOT NULL REFERENCES backupset(backup_set_id), -- The backup set restored
  15712.   restore_type              CHAR(1)       NULL,      -- Database, file, filegroup, log, verifyonly, ...
  15713.  
  15714.   -- Various options...
  15715.   replace                   BIT           NULL,      -- Replace(1), Noreplace(0)
  15716.   recovery                  BIT           NULL,      -- Recovery(1), Norecovery(0)
  15717.   restart                   BIT           NULL,      -- Restart(1), Norestart(0)
  15718.   stop_at                   DATETIME      NULL,
  15719.   device_count              TINYINT       NULL,      -- Can be less than number of media families
  15720.   stop_at_mark_name         NVARCHAR(128) NULL,
  15721.   stop_before               BIT           NULL
  15722.   )
  15723.  
  15724.   CREATE INDEX restorehistorybackupset ON restorehistory (backup_set_id)
  15725. END
  15726.  
  15727. IF (NOT EXISTS (SELECT *
  15728.                 FROM msdb.dbo.syscolumns
  15729.                 WHERE (name in ('stop_at_mark_name', 'stop_before'))
  15730.                 AND (id = (SELECT id
  15731.                           FROM msdb.dbo.sysobjects
  15732.                           WHERE (name = 'restorehistory')))))
  15733. BEGIN
  15734.   IF NOT EXISTS (
  15735.     select * from msdb.dbo.syscolumns where name='stop_before' and id =
  15736.         (select id from msdb.dbo.sysobjects where name='restorehistory'))
  15737.   BEGIN
  15738.     PRINT ''
  15739.     PRINT 'Adding columns to table restorehistory...'
  15740.  
  15741.     ALTER TABLE restorehistory
  15742.       ADD
  15743.       stop_at_mark_name       NVARCHAR(128) NULL,
  15744.       stop_before             BIT           NULL
  15745.   END
  15746. END
  15747. go
  15748.  
  15749. /**************************************************************/
  15750. /* RESTOREFILE - One row per file restored.                   */
  15751. /**************************************************************/
  15752.  
  15753. IF (NOT EXISTS (SELECT *
  15754.                 FROM msdb.dbo.sysobjects
  15755.                 WHERE (name = 'restorefile')))
  15756. BEGIN
  15757.   PRINT ''
  15758.   PRINT 'Creating table restorefile...'
  15759.  
  15760.   CREATE TABLE restorefile
  15761.   (
  15762.   restore_history_id     INT           NOT NULL REFERENCES restorehistory(restore_history_id),
  15763.   file_number            NUMERIC(10,0) NULL,      -- Note: requires database to make unique
  15764.   destination_phys_drive VARCHAR(260)  NULL,
  15765.   destination_phys_name  VARCHAR(260)  NULL
  15766.   )
  15767. END
  15768. go
  15769.  
  15770. /**************************************************************/
  15771. /* RESTOREFILEGROUP - One row per filegroup restored.         */
  15772. /**************************************************************/
  15773.  
  15774. IF (NOT EXISTS (SELECT *
  15775.                 FROM msdb.dbo.sysobjects
  15776.                 WHERE (name = 'restorefilegroup')))
  15777. BEGIN
  15778.   PRINT ''
  15779.   PRINT 'Creating table restorefilegroup...'
  15780.  
  15781.   CREATE TABLE restorefilegroup
  15782.   (
  15783.   restore_history_id INT           NOT NULL REFERENCES restorehistory(restore_history_id),
  15784.   filegroup_name     NVARCHAR(128) NULL
  15785.   )
  15786. END
  15787. go
  15788.  
  15789. /**************************************************************/
  15790. /* LOGMARKHISTORY - One row per log mark generated            */
  15791. /**************************************************************/
  15792.  
  15793. IF (NOT EXISTS (SELECT *
  15794.                 FROM msdb.dbo.sysobjects
  15795.                 WHERE (name = 'logmarkhistory')))
  15796. BEGIN
  15797.   PRINT ''
  15798.   PRINT 'Creating table logmarkhistory...'
  15799.  
  15800.   CREATE TABLE logmarkhistory
  15801.   (
  15802.   database_name     NVARCHAR(128)   NOT NULL,
  15803.   mark_name         NVARCHAR(128)   NOT NULL,
  15804.   description       NVARCHAR(255)   NULL,
  15805.   user_name         NVARCHAR(128)   NOT NULL,
  15806.   lsn               NUMERIC(25,0)   NOT NULL,
  15807.   mark_time         DATETIME        NOT NULL
  15808.   )
  15809.  
  15810.   CREATE INDEX logmarkhistory1 ON logmarkhistory (database_name, mark_name)
  15811.  
  15812.   CREATE INDEX logmarkhistory2 ON logmarkhistory (database_name, lsn)
  15813. END
  15814. go
  15815.  
  15816. IF (EXISTS (SELECT *
  15817.                 FROM msdb.dbo.sysobjects
  15818.                 WHERE (name = 'trig_backupset_delete')
  15819.                   AND (OBJECTPROPERTY(id, 'IsTrigger') != 0)))
  15820. BEGIN
  15821.   DROP TRIGGER trig_backupset_delete
  15822. END
  15823. go
  15824.  
  15825. CREATE TRIGGER trig_backupset_delete ON msdb.dbo.backupset FOR DELETE AS
  15826. BEGIN
  15827.   DELETE FROM msdb.dbo.logmarkhistory from deleted
  15828.   WHERE (msdb.dbo.logmarkhistory.database_name = deleted.database_name)
  15829.     AND (msdb.dbo.logmarkhistory.lsn >= deleted.first_lsn)
  15830.     AND (msdb.dbo.logmarkhistory.lsn < deleted.last_lsn)
  15831. END
  15832. go
  15833.  
  15834. /**************************************************************/
  15835. /**                                                          **/
  15836. /**           O B J E C T    P E R M I S S I O N S           **/
  15837. /**                                                          **/
  15838. /**************************************************************/
  15839.  
  15840. PRINT ''
  15841. PRINT 'Setting object permissions...'
  15842. go
  15843.  
  15844. -- Permissions a non-SA needs to create/update/delete a job
  15845. GRANT EXECUTE ON sp_get_sqlagent_properties  TO PUBLIC
  15846. GRANT EXECUTE ON sp_help_category            TO PUBLIC
  15847. GRANT EXECUTE ON sp_enum_sqlagent_subsystems TO PUBLIC
  15848. GRANT EXECUTE ON sp_add_jobserver            TO PUBLIC
  15849. GRANT EXECUTE ON sp_delete_jobserver         TO PUBLIC
  15850. GRANT SELECT  ON syscategories               TO PUBLIC
  15851.  
  15852. GRANT EXECUTE ON sp_purge_jobhistory TO PUBLIC
  15853. GRANT EXECUTE ON sp_help_jobhistory  TO PUBLIC
  15854.  
  15855. GRANT EXECUTE ON sp_add_jobstep    TO PUBLIC
  15856. GRANT EXECUTE ON sp_update_jobstep TO PUBLIC
  15857. GRANT EXECUTE ON sp_delete_jobstep TO PUBLIC
  15858. GRANT EXECUTE ON sp_help_jobstep   TO PUBLIC
  15859.  
  15860. GRANT EXECUTE ON sp_add_jobschedule    TO PUBLIC
  15861. GRANT EXECUTE ON sp_update_jobschedule TO PUBLIC
  15862. GRANT EXECUTE ON sp_delete_jobschedule TO PUBLIC
  15863. GRANT EXECUTE ON sp_help_jobschedule   TO PUBLIC
  15864.  
  15865. GRANT EXECUTE ON sp_add_job    TO PUBLIC
  15866. GRANT EXECUTE ON sp_update_job TO PUBLIC
  15867. GRANT EXECUTE ON sp_delete_job TO PUBLIC
  15868. GRANT EXECUTE ON sp_help_job   TO PUBLIC
  15869. GRANT EXECUTE ON sp_start_job  TO PUBLIC
  15870. GRANT EXECUTE ON sp_stop_job   TO PUBLIC
  15871.  
  15872. GRANT EXECUTE ON sp_help_jobserver TO PUBLIC
  15873.  
  15874. GRANT EXECUTE ON sp_check_for_owned_jobs     TO PUBLIC
  15875. GRANT EXECUTE ON sp_check_for_owned_jobsteps TO PUBLIC
  15876. GRANT EXECUTE ON sp_get_jobstep_db_username  TO PUBLIC
  15877. GRANT EXECUTE ON sp_post_msx_operation       TO PUBLIC
  15878. GRANT EXECUTE ON sp_get_job_alerts           TO PUBLIC
  15879.  
  15880. GRANT EXECUTE ON sp_uniquetaskname TO PUBLIC
  15881. GRANT EXECUTE ON sp_addtask        TO PUBLIC
  15882. GRANT EXECUTE ON sp_updatetask     TO PUBLIC
  15883. GRANT EXECUTE ON sp_droptask       TO PUBLIC
  15884. GRANT EXECUTE ON sp_helptask       TO PUBLIC
  15885. GRANT EXECUTE ON sp_verifytaskid   TO PUBLIC
  15886. GRANT EXECUTE ON sp_reassigntask   TO PUBLIC
  15887. GRANT EXECUTE ON sp_helphistory    TO PUBLIC
  15888. GRANT EXECUTE ON sp_purgehistory   TO PUBLIC
  15889.  
  15890. GRANT SELECT ON sysjobs_view  TO PUBLIC
  15891. GRANT SELECT ON systasks_view TO PUBLIC
  15892. REVOKE ALL ON systargetservers                 FROM PUBLIC
  15893. REVOKE ALL ON systargetservers_view            FROM PUBLIC
  15894. REVOKE ALL ON systargetservergroups            FROM PUBLIC
  15895. REVOKE ALL ON systargetservergroupmembers      FROM PUBLIC
  15896. REVOKE INSERT, UPDATE, DELETE ON syscategories FROM PUBLIC
  15897. REVOKE ALL ON sysalerts                        FROM PUBLIC
  15898. REVOKE ALL ON sysoperators                     FROM PUBLIC
  15899. REVOKE ALL ON sysnotifications                 FROM PUBLIC
  15900.  
  15901. GRANT SELECT ON backupfile        TO PUBLIC
  15902. GRANT SELECT ON backupmediafamily TO PUBLIC
  15903. GRANT SELECT ON backupmediaset    TO PUBLIC
  15904. GRANT SELECT ON backupset         TO PUBLIC
  15905. GRANT SELECT ON restorehistory    TO PUBLIC
  15906. GRANT SELECT ON restorefile       TO PUBLIC
  15907. GRANT SELECT ON restorefilegroup  TO PUBLIC
  15908. GRANT SELECT ON logmarkhistory    TO PUBLIC
  15909. go
  15910.  
  15911. -- Create the TargetServers role (for use by target servers when downloading jobs / uploading status)
  15912. IF (EXISTS (SELECT *
  15913.             FROM msdb.dbo.sysusers
  15914.             WHERE (name = N'TargetServersRole')
  15915.               AND (issqlrole = 1)))
  15916. BEGIN
  15917.   -- If there are no members in the role, then drop and re-create it
  15918.   IF ((SELECT COUNT(*)
  15919.        FROM msdb.dbo.sysusers   su,
  15920.             msdb.dbo.sysmembers sm
  15921.        WHERE (su.uid = sm.groupuid)
  15922.          AND (su.name = N'TargetServersRole')
  15923.          AND (su.issqlrole = 1)) = 0)
  15924.   BEGIN
  15925.     EXECUTE msdb.dbo.sp_droprole @rolename = N'TargetServersRole'
  15926.     EXECUTE msdb.dbo.sp_addrole @rolename = N'TargetServersRole'
  15927.   END
  15928. END
  15929. ELSE
  15930.   EXECUTE msdb.dbo.sp_addrole @rolename = N'TargetServersRole'
  15931.  
  15932. GRANT SELECT, UPDATE, DELETE ON sysdownloadlist               TO TargetServersRole
  15933. GRANT SELECT, UPDATE         ON sysjobservers                 TO TargetServersRole
  15934. GRANT SELECT, UPDATE         ON systargetservers              TO TargetServersRole
  15935. GRANT EXECUTE                ON sp_downloaded_row_limiter     TO TargetServersRole
  15936. GRANT SELECT                 ON sysjobs                       TO TargetServersRole
  15937. GRANT EXECUTE                ON sp_help_jobstep               TO TargetServersRole
  15938. GRANT EXECUTE                ON sp_help_jobschedule           TO TargetServersRole
  15939. GRANT EXECUTE                ON sp_sqlagent_refresh_job       TO TargetServersRole
  15940. GRANT EXECUTE                ON sp_sqlagent_probe_msx         TO TargetServersRole
  15941. GRANT EXECUTE                ON sp_sqlagent_check_msx_version TO TargetServersRole
  15942. go
  15943.  
  15944. USE msdb
  15945. go
  15946.  
  15947. /**************************************************************/
  15948. /**************************************************************/
  15949. /* BEGIN DTS                                                  */
  15950. /**************************************************************/
  15951. /**************************************************************/
  15952.  
  15953. /**************************************************************/
  15954. /* DTS TABLES                                                 */
  15955. /* These are never dropped since we dropped MSDB itself if    */
  15956. /* this was an upgrade from pre-beta3, and we preserve beta3  */
  15957. /* packages.  However, we need to add the owner_sid column    */
  15958. /* if it's not there already, defaulting to sa ownership.     */
  15959. /**************************************************************/
  15960.  
  15961. /**************************************************************/
  15962. /* SYSDTSCATEGORIES                                           */
  15963. /**************************************************************/
  15964. IF (NOT EXISTS (SELECT *
  15965.                 FROM msdb.dbo.sysobjects
  15966.                 WHERE (name = N'sysdtscategories')))
  15967. BEGIN
  15968.   PRINT ''
  15969.   PRINT 'Creating table sysdtscategories...'
  15970.   CREATE TABLE sysdtscategories
  15971.   (
  15972.     name                   sysname             NOT NULL,
  15973.     description            NVARCHAR(1024)      NULL,
  15974.     id                     UNIQUEIDENTIFIER    NOT NULL,
  15975.     parentid               UNIQUEIDENTIFIER    NOT NULL,         --// IID_NULL if a predefined root category
  15976.     CONSTRAINT pk_dtscategories PRIMARY KEY (id),
  15977.     CONSTRAINT uq_dtscategories_name_parent UNIQUE (name, parentid)
  15978.   )
  15979.  
  15980.   /**************************************************************/
  15981.   /* PREDEFINED DTS CATEGORIES                                  */
  15982.   /**************************************************************/
  15983.   PRINT ''
  15984.   PRINT 'Adding predefined dts categories...'
  15985.   --// MUST BE IN SYNC with DTSPkg.h!
  15986.   --// These must be INSERTed explicitly as the IID_NULL parent does not exist.
  15987.   INSERT sysdtscategories VALUES (N'Local', 'DTS Packages stored on local SQL Server', 'B8C30000-A282-11D1-B7D9-00C04FB6EFD5', '00000000-0000-0000-0000-000000000000')
  15988.   INSERT sysdtscategories VALUES (N'Repository', 'DTS Packages stored on Repository', 'B8C30001-A282-11D1-B7D9-00C04FB6EFD5', '00000000-0000-0000-0000-000000000000')
  15989.  
  15990.   --// Default location for DTSPackage.SaveToSQLServer
  15991.   INSERT sysdtscategories VALUES (N'LocalDefault', 'Default local subcategory for DTS Packages', 'B8C30002-A282-11D1-B7D9-00C04FB6EFD5', 'B8C30000-A282-11D1-B7D9-00C04FB6EFD5')
  15992. END
  15993. GO
  15994.  
  15995. /**************************************************************/
  15996. /* SYSDTSPACKAGES                                             */
  15997. /**************************************************************/
  15998. IF (NOT EXISTS (SELECT *
  15999.                 FROM msdb.dbo.sysobjects
  16000.                 WHERE (name = N'sysdtspackages')))
  16001. BEGIN
  16002.   PRINT ''
  16003.   PRINT 'Creating table sysdtspackages...'
  16004.   CREATE TABLE sysdtspackages
  16005.   (
  16006.     name                   sysname             NOT NULL,                   --// May have multiple ids
  16007.     id                     UNIQUEIDENTIFIER    NOT NULL,                   --// May have multiple versionids
  16008.     versionid              UNIQUEIDENTIFIER    NOT NULL UNIQUE,
  16009.     description            NVARCHAR(1024)      NULL,
  16010.     categoryid             UNIQUEIDENTIFIER    NOT NULL REFERENCES sysdtscategories (id),
  16011.     createdate             DATETIME,
  16012.     owner                  sysname,
  16013.     packagedata            IMAGE,
  16014.     owner_sid              VARBINARY(85)       NOT NULL DEFAULT SUSER_SID(N'sa'),
  16015.     packagetype            int                 NOT NULL DEFAULT 0          --// DTSPkgType_Default
  16016.     CONSTRAINT pk_dtspackages PRIMARY KEY (id, versionid)
  16017.   )
  16018. END ELSE BEGIN
  16019.   IF (NOT EXISTS (SELECT *
  16020.                   FROM msdb.dbo.syscolumns
  16021.                   WHERE name = N'owner_sid' AND id = OBJECT_ID(N'sysdtspackages')))
  16022.   BEGIN
  16023.     PRINT ''
  16024.     PRINT 'Altering table sysdtspackages for owner_sid and packagetype...'
  16025.     ALTER TABLE sysdtspackages ADD owner_sid VARBINARY(85) NOT NULL DEFAULT SUSER_SID(N'sa'),
  16026.                                    packagetype int NOT NULL DEFAULT 0      --// DTSPkgType_Default
  16027.   END
  16028.   IF (NOT EXISTS (SELECT *
  16029.                   FROM msdb.dbo.syscolumns
  16030.                   WHERE name = N'packagetype' AND id = OBJECT_ID(N'sysdtspackages')))
  16031.   BEGIN
  16032.     PRINT ''
  16033.     PRINT 'Altering table sysdtspackages for packagetype...'
  16034.     ALTER TABLE sysdtspackages ADD packagetype int NOT NULL DEFAULT 0      --// DTSPkgType_Default
  16035.   END
  16036. END
  16037. GO
  16038.  
  16039. /**************************************************************/
  16040. /* SP_MAKE_DTSPACKAGENAME                                     */
  16041. /**************************************************************/
  16042. PRINT ''
  16043. PRINT 'Creating procedure sp_get_dtsversion...'
  16044. go
  16045. IF OBJECT_ID(N'sp_get_dtsversion') IS NOT NULL
  16046.   DROP PROCEDURE sp_get_dtsversion
  16047. go
  16048. CREATE PROCEDURE sp_get_dtsversion
  16049. AS
  16050.   /* Values for this are same as @@microsoftversion */
  16051.   /* @@microsoftversion format is 0xaaiibbbb (aa = major, ii = minor, bb[bb] = build #) */
  16052.   DECLARE @i INT
  16053.   select @i = 0x08000000    /* Must be in hex! */
  16054.  
  16055.   /* Select the numeric value, and a conversion to make it readable */
  16056.   select N'Microsoft SQLDTS Scripts' = @i, N'Version' = convert(binary(4), @i)
  16057. GO
  16058. GRANT EXECUTE ON sp_get_dtsversion TO PUBLIC
  16059. GO
  16060.  
  16061. /**************************************************************/
  16062. /* SP_MAKE_DTSPACKAGENAME                                     */
  16063. /**************************************************************/
  16064. PRINT ''
  16065. PRINT 'Creating procedure sp_make_dtspackagename...'
  16066. go
  16067. IF OBJECT_ID(N'sp_make_dtspackagename') IS NOT NULL
  16068.   DROP PROCEDURE sp_make_dtspackagename
  16069. go
  16070. CREATE PROCEDURE sp_make_dtspackagename
  16071.   @categoryid UNIQUEIDENTIFIER,
  16072.   @name sysname OUTPUT,
  16073.   @flags int = 0
  16074. AS
  16075.   SET NOCOUNT ON
  16076.  
  16077.   --// If NULL catid, default to the LocalDefault category.
  16078.   IF (@categoryid IS NULL)
  16079.     SELECT @categoryid = 'B8C30002-A282-11d1-B7D9-00C04FB6EFD5'
  16080.  
  16081.   --// Validate category.  We'll generate a unique name within category.
  16082.   DECLARE @stringfromclsid NVARCHAR(200)
  16083.   IF NOT EXISTS (SELECT * FROM sysdtscategories WHERE id = @categoryid)
  16084.   BEGIN
  16085.     SELECT @stringfromclsid = CONVERT(NVARCHAR(50), @categoryid)
  16086.     RAISERROR(14262, 16, 1, '@categoryid', @stringfromclsid)
  16087.     RETURN(1) -- Failure
  16088.   END
  16089.  
  16090.   --// Autogenerate the next name in our format.
  16091.   DECLARE @max sysname, @i INT, @spidchar NVARCHAR(20)
  16092.  
  16093.   --// Any logic we use may have collisions so let's get the max and wrap if we have to.
  16094.   --// @@spid is necessary for guaranteed uniqueness but makes it ugly so for now, don't use it.
  16095.   --// Note:  use only 9 characters as it makes the pattern match easier without overflowing.
  16096.   SELECT @i = 0, @spidchar = '_'               -- + LTRIM(STR(@@spid)) + '_'
  16097.   SELECT @max = MAX(name)
  16098.     FROM sysdtspackages
  16099.     WHERE name like 'DTS_' + @spidchar + '[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]'
  16100.   IF @max IS NOT NULL
  16101.     SELECT @i = CONVERT(INT, SUBSTRING(@max, (DATALENGTH(N'DTS_' + @spidchar) / 2) + 1, 9))
  16102.  
  16103.   --// Wrap if needed.  Find a gap in the names.
  16104.   IF @i < 999999999
  16105.   BEGIN
  16106.     SELECT @i = @i + 1
  16107.   END ELSE BEGIN
  16108.     SELECT @i = 1
  16109.     DECLARE @existingname sysname
  16110.     DECLARE hC CURSOR LOCAL FOR SELECT name FROM sysdtspackages WHERE categoryid = @categoryid ORDER BY name FOR READ ONLY
  16111.     OPEN hC
  16112.     FETCH NEXT FROM hC INTO @existingname
  16113.     WHILE @@FETCH_STATUS = 0 AND @i < 999999999
  16114.     BEGIN
  16115.       SELECT @name = 'DTS_' + @spidchar + REPLICATE('0', 9 - DATALENGTH(LTRIM(STR(@i)))) + LTRIM(STR(@i))
  16116.       IF @existingname > @name
  16117.         BREAK
  16118.       SELECT @i = @i + 1
  16119.       FETCH NEXT FROM hC INTO @existingname
  16120.     END
  16121.     CLOSE hC
  16122.     DEALLOCATE hC
  16123.   END
  16124.  
  16125.   --// Set the name.
  16126.   SELECT @name = 'DTS_' + @spidchar + REPLICATE('0', 9 - DATALENGTH(LTRIM(STR(@i)))) + LTRIM(STR(@i))
  16127.   IF (@flags & 1) <> 0
  16128.     SELECT @name
  16129. GO
  16130. GRANT EXECUTE ON sp_make_dtspackagename TO PUBLIC
  16131. GO
  16132.  
  16133. /**************************************************************/
  16134. /* SP_ADD_DTSPACKAGE                                          */
  16135. /**************************************************************/
  16136. PRINT ''
  16137. PRINT 'Creating procedure sp_add_dtspackage...'
  16138. GO
  16139. IF OBJECT_ID(N'sp_add_dtspackage') IS NOT NULL
  16140.   DROP PROCEDURE sp_add_dtspackage
  16141. GO
  16142. CREATE PROCEDURE sp_add_dtspackage
  16143.   @name sysname,
  16144.   @id UNIQUEIDENTIFIER,
  16145.   @versionid UNIQUEIDENTIFIER,
  16146.   @description NVARCHAR(255),
  16147.   @categoryid UNIQUEIDENTIFIER,
  16148.   @owner sysname,
  16149.   @packagedata IMAGE,
  16150.   @packagetype int = 0        --// DTSPkgType_Default
  16151. AS
  16152.   SET NOCOUNT ON
  16153.  
  16154.   --// If NULL catid, default to the LocalDefault category.
  16155.   IF (@categoryid IS NULL)
  16156.     SELECT @categoryid = 'B8C30002-A282-11d1-B7D9-00C04FB6EFD5'
  16157.  
  16158.   --// Autogenerate name if it came in NULL.  If it didn't, the below will validate uniqueness.
  16159.   IF DATALENGTH(@name) = 0
  16160.     SELECT @name = NULL
  16161.   IF @name IS NULL
  16162.   BEGIN
  16163.     --// First see if they specified a new version based on id instead of name.
  16164.     if @id IS NOT NULL
  16165.     BEGIN
  16166.       SELECT @name = name
  16167.         FROM sysdtspackages WHERE @id = id
  16168.       IF @name IS NOT NULL
  16169.         GOTO AddPackage          -- OK, add with the existing name
  16170.     END
  16171.  
  16172.     --// Name not available, autogenerate one.
  16173.     exec sp_make_dtspackagename @categoryid, @name OUTPUT
  16174.     GOTO AddPackage
  16175.   END
  16176.  
  16177.   --// Verify name unique within category.  Allow a new versionid of the same name though.
  16178.   IF EXISTS (SELECT * FROM sysdtspackages WHERE name = @name AND categoryid = @categoryid AND id <> @id)
  16179.   BEGIN
  16180.     RAISERROR (14590, -1, -1, @name)
  16181.     RETURN(1) -- Failure
  16182.   END
  16183.  
  16184.   --// Verify that the same id is not getting a different name.
  16185.   IF EXISTS (SELECT * FROM sysdtspackages WHERE id = @id AND name <> @name)
  16186.   BEGIN
  16187.     DECLARE @stringfromclsid NVARCHAR(200)
  16188.     SELECT @stringfromclsid = CONVERT(NVARCHAR(50), @id)
  16189.     RAISERROR (14597, -1, -1, @stringfromclsid)
  16190.     RETURN(1) -- Failure
  16191.   END
  16192.  
  16193.   --// Verify all versions of a package go in the same category.
  16194.   IF EXISTS (SELECT * FROM sysdtspackages WHERE id = @id AND categoryid <> @categoryid)
  16195.   BEGIN
  16196.     RAISERROR (14596, -1, -1, @name)
  16197.     RETURN(1) -- Failure
  16198.   END
  16199.  
  16200.   --// The real information is in the IMAGE; the rest is "documentary".
  16201.   --// Therefore, there is no need to verify anything.
  16202.   --// The REFERENCE in sysdtspackages will validate @categoryid.
  16203. AddPackage:
  16204.  
  16205.   --// We will use the original owner_sid for all new versions - all must have the same owner.
  16206.   --// New packages will get the current login's SID as owner_sid.
  16207.   DECLARE @owner_sid VARBINARY(85)
  16208.   SELECT @owner_sid = MIN(owner_sid) FROM sysdtspackages WHERE id = @id
  16209.   IF @@rowcount = 0 OR @owner_sid IS NULL
  16210.   BEGIN
  16211.     SELECT @owner_sid = SUSER_SID()
  16212.   END ELSE BEGIN
  16213.     --// Only the owner of DTS Package ''%s'' or a member of the sysadmin role may create new versions of it.
  16214.     IF (@owner_sid <> SUSER_SID() AND (ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) <> 1))
  16215.     BEGIN
  16216.       RAISERROR (14586, -1, -1, @name)
  16217.       RETURN(1) -- Failure
  16218.     END
  16219.   END
  16220.  
  16221.   --// Everything checks out, add the package or its new version.
  16222.   INSERT sysdtspackages (
  16223.     name,
  16224.     id,
  16225.     versionid,
  16226.     description,
  16227.     categoryid,
  16228.     createdate,
  16229.     owner,
  16230.     packagedata,
  16231.     owner_sid,
  16232.     packagetype
  16233.   ) VALUES (
  16234.     @name,
  16235.     @id,
  16236.     @versionid,
  16237.     @description,
  16238.     @categoryid,
  16239.     GETDATE(),
  16240.     @owner,
  16241.     @packagedata,
  16242.     @owner_sid,
  16243.     @packagetype
  16244.   )
  16245.   RETURN 0    -- SUCCESS
  16246. GO
  16247. GRANT EXECUTE ON sp_add_dtspackage TO PUBLIC
  16248. GO
  16249.  
  16250. /**************************************************************/
  16251. /* SP_DROP_DTSPACKAGE                                         */
  16252. /**************************************************************/
  16253. PRINT ''
  16254. PRINT 'Creating procedure sp_drop_dtspackage...'
  16255. go
  16256. IF OBJECT_ID(N'sp_drop_dtspackage') IS NOT NULL
  16257.   DROP PROCEDURE sp_drop_dtspackage
  16258. go
  16259. CREATE PROCEDURE sp_drop_dtspackage
  16260.   @name sysname,
  16261.   @id UNIQUEIDENTIFIER,
  16262.   @versionid UNIQUEIDENTIFIER
  16263. AS
  16264.   SET NOCOUNT ON
  16265.  
  16266.   --// Does the specified package (uniquely) exist?  Referencing by name only may not be unique.
  16267.   --// We do a bit of a hack here as SQL can't handle a DISTINCT clause with UNIQUEIDENTIFIER.
  16268.   --// @id will get the first id returned; if only name specified, see if there are more.
  16269.   DECLARE @findid UNIQUEIDENTIFIER
  16270.   SELECT @findid = id FROM sysdtspackages
  16271.     WHERE (@name IS NOT NULL OR @id IS NOT NULL OR @versionid IS NOT NULL)
  16272.       AND (@name IS NULL OR @name = name)
  16273.       AND (@id IS NULL OR @id = id)
  16274.       AND (@versionid IS NULL or @versionid = versionid)
  16275.   IF @@rowcount = 0
  16276.   BEGIN
  16277.     DECLARE @pkgnotfound NVARCHAR(200)
  16278.     DECLARE @dts_package_res NVARCHAR(100)
  16279.     SELECT @pkgnotfound = FORMATMESSAGE(14599) + ' = ''' + ISNULL(@name, FORMATMESSAGE(14589)) + '''; ' + FORMATMESSAGE(14588) + ' {'
  16280.     SELECT @pkgnotfound = @pkgnotfound + CASE WHEN @id IS NULL THEN FORMATMESSAGE(14589) ELSE CONVERT(NVARCHAR(50), @id) END + '}.{'
  16281.     SELECT @pkgnotfound = @pkgnotfound + CASE WHEN @versionid IS NULL THEN FORMATMESSAGE(14589) ELSE CONVERT(NVARCHAR(50), @versionid) END + '}'
  16282.     SELECT @dts_package_res = FORMATMESSAGE(14594)
  16283.     RAISERROR(14262, 16, 1, @dts_package_res, @pkgnotfound)
  16284.     RETURN(1) -- Failure
  16285.   END ELSE IF @name IS NOT NULL AND @id IS NULL AND @versionid IS NULL AND
  16286.       EXISTS (SELECT * FROM sysdtspackages WHERE name = @name AND id <> @findid)
  16287.   BEGIN
  16288.     RAISERROR(14595, -1, -1, @name)
  16289.     RETURN(1) -- Failure
  16290.   END
  16291.   SELECT @id = @findid
  16292.  
  16293.   --// Only the owner of DTS Package ''%s'' or a member of the sysadmin role may drop it or any of its versions.
  16294.   --// sp_add_dtspackage ensures that all versions have the same owner_sid.
  16295.   IF (ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) <> 1)
  16296.   BEGIN
  16297.     IF (NOT EXISTS (SELECT * FROM sysdtspackages WHERE id = @id AND owner_sid = SUSER_SID()))
  16298.     BEGIN
  16299.       SELECT @name = name FROM sysdtspackages WHERE id = @id
  16300.       RAISERROR (14587, -1, -1, @name)
  16301.       RETURN(1) -- Failure
  16302.     END
  16303.   END
  16304.  
  16305.   --// If @versionid is NULL, drop all versions of name, else only the @versionid version.
  16306.   DELETE sysdtspackages
  16307.   WHERE id = @id
  16308.     AND (@versionid IS NULL OR @versionid = versionid)
  16309.   RETURN 0    -- SUCCESS
  16310. go
  16311. GRANT EXECUTE ON sp_drop_dtspackage TO PUBLIC
  16312. go
  16313.  
  16314. /**************************************************************/
  16315. /* SP_REASSIGN_DTSPACKAGEOWNER                                */
  16316. /**************************************************************/
  16317. PRINT ''
  16318. PRINT 'Creating procedure sp_reassign_dtspackageowner...'
  16319. go
  16320. IF OBJECT_ID(N'sp_reassign_dtspackageowner') IS NOT NULL
  16321.   DROP PROCEDURE sp_reassign_dtspackageowner
  16322. go
  16323. CREATE PROCEDURE sp_reassign_dtspackageowner
  16324.   @name sysname,
  16325.   @id UNIQUEIDENTIFIER,
  16326.   @newloginname sysname
  16327. AS
  16328.   SET NOCOUNT ON
  16329.  
  16330.   --// First, is this a valid login?
  16331.   IF SUSER_SID(@newloginname) IS NULL
  16332.   BEGIN
  16333.     RAISERROR(14262, -1, -1, '@newloginname', @newloginname)
  16334.     RETURN(1) -- Failure
  16335.   END
  16336.  
  16337.   --// Does the specified package (uniquely) exist?  Referencing by name only may not be unique.
  16338.   --// We do a bit of a hack here as SQL can't handle a DISTINCT clause with UNIQUEIDENTIFIER.
  16339.   --// @id will get the first id returned; if only name specified, see if there are more.
  16340.   DECLARE @findid UNIQUEIDENTIFIER
  16341.   SELECT @findid = id FROM sysdtspackages
  16342.     WHERE (@name IS NOT NULL OR @id IS NOT NULL)
  16343.       AND (@name IS NULL OR @name = name)
  16344.       AND (@id IS NULL OR @id = id)
  16345.   IF @@rowcount = 0
  16346.   BEGIN
  16347.     DECLARE @pkgnotfound NVARCHAR(200)
  16348.     DECLARE @dts_package_res NVARCHAR(100)
  16349.     SELECT @pkgnotfound = FORMATMESSAGE(14599) + ' = ''' + ISNULL(@name, FORMATMESSAGE(14589)) + '''; ' + FORMATMESSAGE(14588) + ' {'
  16350.     SELECT @pkgnotfound = @pkgnotfound + CASE WHEN @id IS NULL THEN FORMATMESSAGE(14589) ELSE CONVERT(NVARCHAR(50), @id) END + '}.{'
  16351.     SELECT @pkgnotfound = @pkgnotfound + FORMATMESSAGE(14589) + '}'
  16352.     SELECT @dts_package_res = FORMATMESSAGE(14594)
  16353.     RAISERROR(14262, 16, 1, @dts_package_res, @pkgnotfound)
  16354.     RETURN(1) -- Failure
  16355.   END ELSE IF @name IS NOT NULL AND @id IS NULL AND
  16356.       EXISTS (SELECT * FROM sysdtspackages WHERE name = @name AND id <> @findid)
  16357.   BEGIN
  16358.     RAISERROR(14595, -1, -1, @name)
  16359.     RETURN(1) -- Failure
  16360.   END
  16361.   SELECT @id = @findid
  16362.  
  16363.   --// Only the owner of DTS Package ''%s'' or a member of the sysadmin role may reassign its ownership.
  16364.   --// sp_add_dtspackage ensures that all versions have the same owner_sid.
  16365.   IF (ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) <> 1)
  16366.   BEGIN
  16367.     IF (NOT EXISTS (SELECT * FROM sysdtspackages WHERE id = @id AND owner_sid = SUSER_SID()))
  16368.     BEGIN
  16369.       SELECT @name = name FROM sysdtspackages WHERE id = @id
  16370.       RAISERROR (14585, -1, -1, @name)
  16371.       RETURN(1) -- Failure
  16372.     END
  16373.   END
  16374.  
  16375.   --// Everything checks out, so reassign the owner.
  16376.   --// Note that @newloginname may be a sql server login rather than a network user,
  16377.   --// which is not quite the same as when a package is created.
  16378.   UPDATE sysdtspackages
  16379.     SET owner_sid = SUSER_SID(@newloginname),
  16380.         owner = @newloginname
  16381.     WHERE id = @id
  16382.  
  16383.   RETURN 0    -- SUCCESS
  16384. GO
  16385. GRANT EXECUTE ON sp_reassign_dtspackageowner TO PUBLIC
  16386. GO
  16387.  
  16388. /**************************************************************/
  16389. /* SP_GET_DTSPACKAGE                                          */
  16390. /**************************************************************/
  16391. PRINT ''
  16392. PRINT 'Creating procedure sp_get_dtspackage...'
  16393. go
  16394. IF OBJECT_ID(N'sp_get_dtspackage') IS NOT NULL
  16395.   DROP PROCEDURE sp_get_dtspackage
  16396. go
  16397. CREATE PROCEDURE sp_get_dtspackage
  16398.   @name sysname,
  16399.   @id UNIQUEIDENTIFIER,
  16400.   @versionid UNIQUEIDENTIFIER
  16401. AS
  16402.   SET NOCOUNT ON
  16403.  
  16404.   --// Does the specified package (uniquely) exist?  Dropping by name only may not be unique.
  16405.   --// We do a bit of a hack here as SQL can't handle a DISTINCT clause with UNIQUEIDENTIFIER.
  16406.   --// @id will get the first id returned; if only name specified, see if there are more.
  16407.   DECLARE @findid UNIQUEIDENTIFIER
  16408.   SELECT @findid = id FROM sysdtspackages
  16409.     WHERE (@name IS NOT NULL OR @id IS NOT NULL OR @versionid IS NOT NULL)
  16410.       AND (@name IS NULL OR @name = name)
  16411.       AND (@id IS NULL OR @id = id)
  16412.       AND (@versionid IS NULL or @versionid = versionid)
  16413.   IF @@rowcount = 0
  16414.   BEGIN
  16415.     DECLARE @pkgnotfound NVARCHAR(200)
  16416.     DECLARE @dts_package_res NVARCHAR(100)
  16417.     SELECT @pkgnotfound = FORMATMESSAGE(14599) + ' = ''' + ISNULL(@name, FORMATMESSAGE(14589)) + '''; ' + FORMATMESSAGE(14588) + ' {'
  16418.     SELECT @pkgnotfound = @pkgnotfound + CASE WHEN @id IS NULL THEN FORMATMESSAGE(14589) ELSE CONVERT(NVARCHAR(50), @id) END + '}.{'
  16419.     SELECT @pkgnotfound = @pkgnotfound + CASE WHEN @versionid IS NULL THEN FORMATMESSAGE(14589) ELSE CONVERT(NVARCHAR(50), @versionid) END + '}'
  16420.     SELECT @dts_package_res = FORMATMESSAGE(14594)
  16421.     RAISERROR(14262, 16, 1, @dts_package_res, @pkgnotfound)
  16422.     RETURN(1) -- Failure
  16423.   END ELSE IF @name IS NOT NULL AND @id IS NULL AND @versionid IS NULL AND
  16424.       EXISTS (SELECT * FROM sysdtspackages WHERE name = @name AND id <> @findid)
  16425.   BEGIN
  16426.     RAISERROR(14595, -1, -1, @name)
  16427.     RETURN(1) -- Failure
  16428.   END
  16429.   SELECT @id = @findid
  16430.  
  16431.   --// If @versionid is NULL, select all versions of name, else only the @versionid version.
  16432.   --// This must return the IMAGE as the rightmost column.
  16433.   SELECT
  16434.     name,
  16435.     id,
  16436.     versionid,
  16437.     description,
  16438.     createdate,
  16439.     owner,
  16440.     pkgsize = datalength(packagedata),
  16441.     packagedata,
  16442.     isowner = CASE WHEN (ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) = 1 OR owner_sid = SUSER_SID()) THEN 1 ELSE 0 END,
  16443.     packagetype
  16444.   FROM sysdtspackages
  16445.   WHERE id = @id
  16446.     AND (@versionid IS NULL OR @versionid = versionid)
  16447.   ORDER BY name, createdate DESC
  16448.  
  16449.   RETURN 0    -- SUCCESS
  16450. go
  16451. GRANT EXECUTE ON sp_get_dtspackage TO PUBLIC
  16452. go
  16453.  
  16454. /**************************************************************/
  16455. /* SP_REASSIGN_DTSPACKAGECATEGORY                             */
  16456. /**************************************************************/
  16457. PRINT ''
  16458. PRINT 'Creating procedure sp_reassign_dtspackagecategory...'
  16459. go
  16460. IF OBJECT_ID(N'sp_reassign_dtspackagecategory') IS NOT NULL
  16461.   DROP PROCEDURE sp_reassign_dtspackagecategory
  16462. go
  16463. CREATE PROCEDURE sp_reassign_dtspackagecategory
  16464.   @packageid UNIQUEIDENTIFIER,
  16465.   @categoryid UNIQUEIDENTIFIER
  16466. AS
  16467.   SET NOCOUNT ON
  16468.  
  16469.   --// Does the package exist?
  16470.   DECLARE @stringfromclsid NVARCHAR(200)
  16471.   IF NOT EXISTS (SELECT * from sysdtspackages WHERE id = @packageid)
  16472.   BEGIN
  16473.     SELECT @stringfromclsid = CONVERT(NVARCHAR(50), @packageid)
  16474.     RAISERROR(14262, 16, 1, '@packageid', @stringfromclsid)
  16475.     RETURN(1) -- Failure
  16476.   END
  16477.  
  16478.   --// Does the category exist?
  16479.   IF NOT EXISTS (SELECT * FROM sysdtscategories WHERE id = @categoryid)
  16480.   BEGIN
  16481.     SELECT @stringfromclsid = CONVERT(NVARCHAR(50), @categoryid)
  16482.     RAISERROR(14262, 16, 1, '@categoryid', @stringfromclsid)
  16483.     RETURN(1) -- Failure
  16484.   END
  16485.  
  16486.   UPDATE sysdtspackages SET categoryid = @categoryid WHERE id = @packageid
  16487. go
  16488.  
  16489. /**************************************************************/
  16490. /* SP_ENUM_DTSPACKAGES                                        */
  16491. /**************************************************************/
  16492. PRINT ''
  16493. PRINT 'Creating procedure sp_enum_dtspackages...'
  16494. go
  16495. IF OBJECT_ID(N'sp_enum_dtspackages') IS NOT NULL
  16496.   DROP PROCEDURE sp_enum_dtspackages
  16497. go
  16498. CREATE PROCEDURE sp_enum_dtspackages
  16499.   @name_like sysname = '%',
  16500.   @description_like NVARCHAR(255) = '%',
  16501.   @categoryid UNIQUEIDENTIFIER = NULL,
  16502.   @flags INT = 0,          --// Bitmask:  0x01 == return image data
  16503.                            --//           0x02 == recursive (packagenames and categorynames only)
  16504.                            --//           0x04 == all versions (default == only most-recent-versions)
  16505.                            --//           0x08 == all prior versions versions (not most-recent; requires @id)
  16506.   @id UNIQUEIDENTIFIER = NULL,    --// If non-NULL, enum versions of this package.
  16507.   @wanttype int = NULL            --// If non-NULL, enum only packages of the given type
  16508. AS
  16509.   IF (@flags & 0x02) <> 0
  16510.     GOTO DO_RECURSE
  16511.  
  16512.   --// Just return the non-IMAGE stuff - sp_get_dtspackage will return the
  16513.   --// actual dtspackage info.
  16514.   DECLARE @latestversiondate datetime
  16515.   SELECT @latestversiondate = NULL
  16516.   IF (@flags & 0x08 = 0x08)
  16517.   BEGIN
  16518.     SELECT @latestversiondate = MAX(t.createdate) FROM sysdtspackages t WHERE t.id = @id
  16519.     IF @latestversiondate IS NULL
  16520.     BEGIN
  16521.       DECLARE @pkgnotfound NVARCHAR(200)
  16522.       DECLARE @dts_package_res NVARCHAR(100)
  16523.       SELECT @pkgnotfound = FORMATMESSAGE(14599) + ' = ' + FORMATMESSAGE(14589) + '; ' + FORMATMESSAGE(14588) + ' {'
  16524.       SELECT @pkgnotfound = @pkgnotfound + CASE WHEN @id IS NULL THEN FORMATMESSAGE(14589) ELSE CONVERT(NVARCHAR(50), @id) END + '}.{'
  16525.       SELECT @pkgnotfound = @pkgnotfound + FORMATMESSAGE(14589) + '}'
  16526.       SELECT @dts_package_res = FORMATMESSAGE(14594)
  16527.       RAISERROR(14262, 16, 1, @dts_package_res, @pkgnotfound)
  16528.       RETURN(1) -- Failure
  16529.     END
  16530.   END
  16531.   SELECT
  16532.     p.name,
  16533.     p.id,
  16534.     p.versionid,
  16535.     p.description,
  16536.     p.createdate,
  16537.     p.owner,
  16538.     size = datalength(p.packagedata),
  16539.     packagedata = CASE (@flags & 0x01) WHEN 0 THEN NULL ELSE p.packagedata END,
  16540.     isowner = CASE WHEN (ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) = 1 OR p.owner_sid = SUSER_SID()) THEN 1 ELSE 0 END,
  16541.     p.packagetype
  16542.   FROM sysdtspackages p
  16543.   WHERE (@name_like IS NULL OR p.name LIKE @name_like)
  16544.     AND (@description_like IS NULL OR p.description LIKE @description_like)
  16545.     AND (@categoryid IS NULL OR p.categoryid = @categoryid)
  16546.     AND (@id is NULL OR p.id = @id)
  16547.     -- These filter by version
  16548.     AND ( (@flags & 0x08 = 0x08 AND p.createdate < @latestversiondate)
  16549.           OR ( (@flags & 0x04 = 0x04)
  16550.                OR (@flags & 0x08 = 0 AND p.createdate = (SELECT MAX(t.createdate) FROM sysdtspackages t WHERE t.id = p.id))
  16551.              )
  16552.         )
  16553.     AND (@wanttype is NULL or p.packagetype = @wanttype)
  16554.   ORDER BY id, createdate DESC
  16555.   RETURN 0    -- SUCCESS
  16556.  
  16557.   DO_RECURSE:
  16558.   DECLARE @packagesfound INT
  16559.   SELECT @packagesfound = 0
  16560.  
  16561.   --// Starting parent category.  If null, start at root.
  16562.   if (@categoryid IS NULL)
  16563.     SELECT @categoryid = '00000000-0000-0000-0000-000000000000'
  16564.  
  16565.   IF EXISTS (SELECT *
  16566.       FROM sysdtspackages p INNER JOIN sysdtscategories c ON p.categoryid = c.id
  16567.       WHERE p.categoryid = @categoryid
  16568.       AND (@name_like IS NULL OR p.name LIKE @name_like)
  16569.       AND (@description_like IS NULL OR p.description LIKE @description_like)
  16570.     )
  16571.     SELECT @packagesfound = 1
  16572.  
  16573.   IF (@packagesfound <> 0)
  16574.   BEGIN
  16575.     --// Identify the category and list its Packages.
  16576.     SELECT 'Level' = @@nestlevel, 'PackageName' = p.name, 'CategoryName' = c.name
  16577.         FROM sysdtspackages p INNER JOIN sysdtscategories c ON p.categoryid = c.id
  16578.         WHERE p.categoryid = @categoryid
  16579.         AND (@name_like IS NULL OR p.name LIKE @name_like)
  16580.         AND (@description_like IS NULL OR p.description LIKE @description_like)
  16581.   END
  16582.  
  16583.   --// List its subcategories' packages
  16584.   DECLARE @childid UNIQUEIDENTIFIER
  16585.   DECLARE hC CURSOR LOCAL FOR SELECT id FROM sysdtscategories c WHERE parentid = @categoryid ORDER BY c.name FOR READ ONLY
  16586.   OPEN hC
  16587.   FETCH NEXT FROM hC INTO @childid
  16588.   WHILE @@FETCH_STATUS = 0
  16589.   BEGIN
  16590.     EXECUTE sp_enum_dtspackages @name_like, @description_like, @childid, @flags
  16591.     FETCH NEXT FROM hC INTO @childid
  16592.   END
  16593.   CLOSE hC
  16594.   DEALLOCATE hC
  16595.   RETURN 0
  16596. go
  16597.  
  16598. GRANT EXECUTE ON sp_enum_dtspackages TO PUBLIC
  16599. go
  16600.  
  16601. /**************************************************************/
  16602. /* SP_ADD_DTSCATEGORY                                         */
  16603. /**************************************************************/
  16604. PRINT ''
  16605. PRINT 'Creating procedure sp_add_dtscategory...'
  16606. go
  16607. IF OBJECT_ID(N'sp_add_dtscategory') IS NOT NULL
  16608.   DROP PROCEDURE sp_add_dtscategory
  16609. go
  16610. CREATE PROCEDURE sp_add_dtscategory
  16611.   @name sysname,
  16612.   @description NVARCHAR(1024),
  16613.   @id UNIQUEIDENTIFIER,
  16614.   @parentid UNIQUEIDENTIFIER
  16615. AS
  16616.   SET NOCOUNT ON
  16617.  
  16618.   --// If parentid is NULL, use 'Local'
  16619.   IF @parentid IS NULL
  16620.     SELECT @parentid = 'B8C30000-A282-11d1-B7D9-00C04FB6EFD5'
  16621.  
  16622.   --// First do some simple validation of "non-assert" cases.  UI should validate others and the table
  16623.   --// definitions will act as an "assert", but we check here (with a nice message) for user-error stuff
  16624.   --// it would be hard for UI to validate.
  16625.   IF NOT EXISTS (SELECT * FROM sysdtscategories WHERE id = @parentid)
  16626.   BEGIN
  16627.     DECLARE @stringfromclsid NVARCHAR(200)
  16628.     SELECT @stringfromclsid = CONVERT(NVARCHAR(50), @parentid)
  16629.     RAISERROR(14262, 16, 1, '@parentid', @stringfromclsid)
  16630.     RETURN(1) -- Failure
  16631.   END
  16632.  
  16633.   IF EXISTS (SELECT * FROM sysdtscategories WHERE name = @name AND parentid = @parentid)
  16634.   BEGIN
  16635.     RAISERROR(14591, 16, -1, @name)
  16636.     RETURN(1) -- Failure
  16637.   END
  16638.  
  16639.   --// id uniqueness is ensured by the primary key.
  16640.   INSERT sysdtscategories (
  16641.     name,
  16642.     description,
  16643.     id,
  16644.     parentid
  16645.   ) VALUES (
  16646.     @name,
  16647.     @description,
  16648.     @id,
  16649.     @parentid
  16650.   )
  16651.   RETURN 0    -- SUCCESS
  16652. go
  16653.  
  16654. /**************************************************************/
  16655. /* SP_DROP_DTSCATEGORY                                        */
  16656. /**************************************************************/
  16657. PRINT ''
  16658. PRINT 'Creating procedure sp_drop_dtscategory...'
  16659. go
  16660. IF OBJECT_ID(N'sp_drop_dtscategory') IS NOT NULL
  16661.   DROP PROCEDURE sp_drop_dtscategory
  16662. go
  16663. CREATE PROCEDURE sp_drop_dtscategory
  16664.   @name_like sysname,
  16665.   @id UNIQUEIDENTIFIER = NULL,
  16666.   @flags INT = 0           --// Bitmask:  0x01 == recursive (drop all subcategories and packages)
  16667. AS
  16668.   SET NOCOUNT ON
  16669.  
  16670.   --// Temp table in case recursion is needed.
  16671.   CREATE TABLE #recurse(id UNIQUEIDENTIFIER, passcount INT DEFAULT(0))
  16672.  
  16673.   IF (@name_like IS NOT NULL)
  16674.   BEGIN
  16675.     INSERT #recurse (id) SELECT id FROM sysdtscategories WHERE name LIKE @name_like
  16676.     IF @@rowcount = 0
  16677.     BEGIN
  16678.       RAISERROR(14262, 16, 1, '@name_like', @name_like)
  16679.       RETURN(1) -- Failure
  16680.     END
  16681.     IF @@rowcount > 1
  16682.     BEGIN
  16683.       RAISERROR(14592, 16, -1, @name_like)
  16684.       RETURN(1) -- Failure
  16685.     END
  16686.     SELECT @name_like = name, @id = id FROM sysdtscategories WHERE name LIKE @name_like
  16687.   END ELSE BEGIN
  16688.     --// Verify the id.  @name_like will be NULL if we're here so no need to initialize.
  16689.     SELECT @name_like = name FROM sysdtscategories WHERE id = @id
  16690.     IF @name_like IS NULL
  16691.     BEGIN
  16692.       DECLARE @stringfromclsid NVARCHAR(200)
  16693.       SELECT @stringfromclsid = CONVERT(NVARCHAR(50), @id)
  16694.       RAISERROR(14262, 16, 1, '@id', @stringfromclsid)
  16695.       RETURN(1) -- Failure
  16696.     END
  16697.     INSERT #recurse (id) VALUES (@id)
  16698.   END
  16699.  
  16700.   --// We now have a unique category.
  16701.  
  16702.   --// Cannot drop the predefined categories (or the root, which already failed above as IID_NULL
  16703.   --// is not an id in sysdtscategories).  These will be at top level.
  16704.   IF @id IN (
  16705.     'B8C30000-A282-11d1-B7D9-00C04FB6EFD5'
  16706.     , 'B8C30001-A282-11d1-B7D9-00C04FB6EFD5'
  16707.     , 'B8C30002-A282-11d1-B7D9-00C04FB6EFD5'
  16708.   ) BEGIN
  16709.       RAISERROR(14598, 16, 1)
  16710.       RETURN(1) -- Failure
  16711.   END
  16712.  
  16713.   --// Check for subcategories or packages.
  16714.   IF EXISTS (SELECT * FROM sysdtspackages WHERE categoryid = @id)
  16715.              OR EXISTS (SELECT * FROM sysdtscategories WHERE parentid = @id)
  16716.   BEGIN
  16717.     --// It does.  Make sure recursion was requested.
  16718.     IF (@flags & 0x01 = 0)
  16719.     BEGIN
  16720.       RAISERROR(14593, 16, -1, @name_like)
  16721.       RETURN(1) -- Failure
  16722.     END
  16723.  
  16724.     --// Fill up #recurse.
  16725.     UPDATE #recurse SET passcount = 0
  16726.     WHILE (1 = 1)
  16727.     BEGIN
  16728.       UPDATE #recurse SET passcount = passcount + 1
  16729.       INSERT #recurse (id, passcount)
  16730.         SELECT c.id, 0 FROM sysdtscategories c INNER JOIN #recurse r ON c.parentid = r.id
  16731.         WHERE passcount = 1
  16732.       IF @@rowcount = 0
  16733.         BREAK
  16734.     END
  16735.   END
  16736.  
  16737.   DELETE sysdtspackages FROM sysdtspackages INNER JOIN #recurse ON sysdtspackages.categoryid = #recurse.id
  16738.   DELETE sysdtscategories FROM sysdtscategories INNER JOIN #recurse ON sysdtscategories.id = #recurse.id
  16739.   RETURN(0) -- SUCCESS
  16740. go
  16741.  
  16742. /**************************************************************/
  16743. /* SP_MODIFY_DTSCATEGORY                                      */
  16744. /**************************************************************/
  16745. PRINT ''
  16746. PRINT 'Creating procedure sp_modify_dtscategory...'
  16747. go
  16748. IF OBJECT_ID(N'sp_modify_dtscategory') IS NOT NULL
  16749.   DROP PROCEDURE sp_modify_dtscategory
  16750. go
  16751. CREATE PROCEDURE sp_modify_dtscategory
  16752.   @id UNIQUEIDENTIFIER,
  16753.   @name sysname,
  16754.   @description NVARCHAR(1024),
  16755.   @parentid UNIQUEIDENTIFIER
  16756. AS
  16757.   SET NOCOUNT ON
  16758.  
  16759.   --// Validate.
  16760.   DECLARE @stringfromclsid NVARCHAR(200)
  16761.   IF NOT EXISTS (SELECT * FROM sysdtscategories WHERE id = @id)
  16762.   BEGIN
  16763.     SELECT @stringfromclsid = CONVERT(NVARCHAR(50), @id)
  16764.     RAISERROR(14262, 16, 1, '@id', @stringfromclsid)
  16765.     RETURN(1) -- Failure
  16766.   END
  16767.  
  16768.   IF NOT EXISTS (SELECT * FROM sysdtscategories WHERE id = @parentid)
  16769.   BEGIN
  16770.     SELECT @stringfromclsid = CONVERT(NVARCHAR(50), @parentid)
  16771.     RAISERROR(14262, 16, 1, '@parentid', @stringfromclsid)
  16772.     RETURN(1) -- Failure
  16773.   END
  16774.  
  16775.   --// Check the name uniqueness within parent, but make sure the id is different (we may just be renaming
  16776.   --// without reassigning parentage).
  16777.   IF EXISTS (SELECT * FROM sysdtscategories WHERE name = @name AND parentid = @parentid and id <> @id)
  16778.   BEGIN
  16779.     RAISERROR(14591, 16, -1, @name)
  16780.     RETURN(1) -- Failure
  16781.   END
  16782.  
  16783.   UPDATE sysdtscategories SET name = @name, description = @description, parentid = @parentid
  16784.     WHERE id = @id
  16785.   RETURN(0) -- SUCCESS
  16786. go
  16787.  
  16788. /**************************************************************/
  16789. /* SP_ENUM_DTSCATEGORIES                                      */
  16790. /**************************************************************/
  16791. PRINT ''
  16792. PRINT 'Creating procedure sp_enum_dtscategories...'
  16793. go
  16794. IF OBJECT_ID(N'sp_enum_dtscategories') IS NOT NULL
  16795.   DROP PROCEDURE sp_enum_dtscategories
  16796. go
  16797. CREATE PROCEDURE sp_enum_dtscategories
  16798.   @parentid UNIQUEIDENTIFIER = NULL,
  16799.   @flags INT = 0           --// Bitmask:  0x01 == recursive (enum all subcategories; names only)
  16800. AS
  16801.   IF (@flags & 0x01) <> 0
  16802.     GOTO DO_RECURSE
  16803.  
  16804.   --// Go to the root if no parentid specified
  16805.   IF @parentid IS NULL
  16806.     SELECT @parentid = '00000000-0000-0000-0000-000000000000'
  16807.  
  16808.   --// 'No results' is valid here.
  16809.   SELECT name, description, id FROM sysdtscategories WHERE parentid = @parentid
  16810.     ORDER BY name
  16811.   RETURN 0
  16812.  
  16813.   DO_RECURSE:
  16814.  
  16815.   --// Identify the category.
  16816.   IF @@nestlevel <> 0
  16817.     SELECT 'Level' = @@nestlevel, name FROM sysdtscategories WHERE id = @parentid
  16818.  
  16819.   --// List its subcategories
  16820.   DECLARE @childid UNIQUEIDENTIFIER
  16821.   DECLARE hC CURSOR LOCAL FOR SELECT id FROM sysdtscategories c WHERE parentid = @parentid ORDER BY c.name FOR READ ONLY
  16822.   OPEN hC
  16823.   FETCH NEXT FROM hC INTO @childid
  16824.   WHILE @@FETCH_STATUS = 0
  16825.   BEGIN
  16826.     EXECUTE sp_enum_dtscategories @childid, @flags
  16827.     FETCH NEXT FROM hC INTO @childid
  16828.   END
  16829.   CLOSE hC
  16830.   DEALLOCATE hC
  16831.   RETURN 0
  16832. go
  16833.  
  16834. /**************************************************************/
  16835. /* Drop Beta1 DTS Logging objects                             */
  16836. /**************************************************************/
  16837.  
  16838. if OBJECT_ID('sysdtspackagestepslog') IS NOT NULL
  16839. BEGIN
  16840.     PRINT ''
  16841.     PRINT 'Dropping Beta1 logging tables and stored procedures...'
  16842.     DROP TABLE sysdtspackagestepslog
  16843.     IF OBJECT_ID('sysdtspackagelog') IS NOT NULL
  16844.         DROP TABLE sysdtspackagelog
  16845.     IF OBJECT_ID('sp_log_dtspackage') IS NOT NULL
  16846.         DROP PROCEDURE sp_log_dtspackage
  16847.     IF OBJECT_ID('sp_log_dtspackagesteps') IS NOT NULL
  16848.         DROP PROCEDURE sp_log_dtspackagesteps
  16849. END
  16850.  
  16851. /**************************************************************/
  16852. /* SYSDTSPACKAGELOG                                           */
  16853. /**************************************************************/
  16854. if OBJECT_ID('sysdtspackagelog') IS NULL
  16855. BEGIN
  16856.   PRINT ''
  16857.   PRINT 'Creating table sysdtspackagelog...'
  16858.   CREATE TABLE sysdtspackagelog
  16859.   (
  16860.     name                sysname            NOT NULL,
  16861.     description                NVARCHAR(1000)        NULL,
  16862.     id                    UNIQUEIDENTIFIER    NOT NULL,
  16863.     versionid                UNIQUEIDENTIFIER    NOT NULL,
  16864.     lineagefull                UNIQUEIDENTIFIER    NOT NULL PRIMARY KEY,
  16865.     lineageshort            INT            NOT NULL,
  16866.     starttime                DATETIME        NOT NULL,
  16867.     endtime                DATETIME        NULL,
  16868.     elapsedtime                double precision    NULL,
  16869.     computer                sysname            NOT NULL,
  16870.     operator                sysname            NOT NULL,
  16871.     logdate                datetime        NOT NULL DEFAULT GETDATE(),
  16872.     errorcode                INT            NULL,
  16873.     errordescription            NVARCHAR(2000)        NULL
  16874.   )
  16875. END
  16876.  
  16877. /**************************************************************/
  16878. /* SYSDTSSTEPLOG                                              */
  16879. /**************************************************************/
  16880. if OBJECT_ID('sysdtssteplog') IS NULL
  16881. BEGIN
  16882.   PRINT ''
  16883.   PRINT 'Creating table sysdtssteplog...'
  16884.   CREATE TABLE sysdtssteplog
  16885.   (
  16886.     stepexecutionid            BIGINT IDENTITY (1, 1)    NOT NULL PRIMARY KEY,
  16887.     lineagefull                UNIQUEIDENTIFIER    NOT NULL 
  16888.                     REFERENCES sysdtspackagelog(lineagefull)
  16889.                     ON DELETE CASCADE,
  16890.     stepname                sysname            NOT NULL,
  16891.     stepexecstatus            int                NULL,
  16892.     stepexecresult            int                NULL,
  16893.     starttime                DATETIME        NOT NULL,
  16894.     endtime                DATETIME        NULL,
  16895.     elapsedtime                double precision    NULL,
  16896.     errorcode                INT            NULL,
  16897.     errordescription            NVARCHAR(2000)        NULL,
  16898.     progresscount            BIGINT            NULL
  16899.   )
  16900. END ELSE BEGIN
  16901.   IF (NOT EXISTS (SELECT *
  16902.                   FROM msdb.dbo.syscolumns
  16903.                   WHERE name = N'stepexecresult' AND id = OBJECT_ID(N'sysdtssteplog')))
  16904.   BEGIN
  16905.     PRINT ''
  16906.     PRINT 'Altering table sysdtssteplog...'
  16907.     ALTER TABLE sysdtssteplog ADD stepexecresult INT NULL DEFAULT 0
  16908.   END
  16909. END
  16910.  
  16911. /**************************************************************/
  16912. /* SYSDTSTASKLOG                                              */
  16913. /**************************************************************/
  16914. if OBJECT_ID('sysdtstasklog') IS NULL
  16915. BEGIN
  16916.   PRINT ''
  16917.   PRINT 'Creating table sysdtstasklog...'
  16918.   CREATE TABLE sysdtstasklog
  16919.   (
  16920.     stepexecutionid            BIGINT            NOT NULL
  16921.                     REFERENCES sysdtssteplog (stepexecutionid)
  16922.                     ON DELETE CASCADE,
  16923.     sequenceid                INT            NOT NULL,
  16924.     errorcode                INT            NOT NULL,
  16925.     description                NVARCHAR(2000)        NULL,
  16926.     PRIMARY KEY                (stepexecutionid, sequenceid)
  16927.   )
  16928. END
  16929.  
  16930. /**************************************************************/
  16931. /* SP_LOG_DTSPACKAGE_BEGIN                                    */
  16932. /**************************************************************/
  16933. PRINT ''
  16934. PRINT 'Creating procedure sp_log_dtspackage_begin...'
  16935. GO
  16936. IF OBJECT_ID(N'sp_log_dtspackage_begin') IS NOT NULL
  16937.   DROP PROCEDURE sp_log_dtspackage_begin
  16938. GO
  16939. CREATE PROCEDURE sp_log_dtspackage_begin
  16940.   @name            sysname,
  16941.   @description        NVARCHAR(1000),
  16942.   @id            UNIQUEIDENTIFIER,
  16943.   @versionid        UNIQUEIDENTIFIER,
  16944.   @lineagefull        UNIQUEIDENTIFIER,
  16945.   @lineageshort        INT,
  16946.   @starttime        DATETIME,
  16947.   @computer        sysname,
  16948.   @operator        sysname
  16949. AS
  16950.   SET NOCOUNT ON
  16951.  
  16952.   INSERT sysdtspackagelog (
  16953.     name,
  16954.     description,
  16955.     id,
  16956.     versionid,
  16957.     lineagefull,
  16958.     lineageshort,
  16959.     starttime,
  16960.     computer,
  16961.     operator
  16962.   ) VALUES (
  16963.     @name,
  16964.     @description,
  16965.     @id,
  16966.     @versionid,
  16967.     @lineagefull,
  16968.     @lineageshort,
  16969.     @starttime,
  16970.     @computer,
  16971.     @operator
  16972.   )
  16973.   RETURN 0    -- SUCCESS
  16974. GO
  16975. GRANT EXECUTE ON sp_log_dtspackage_begin TO PUBLIC
  16976. GO
  16977.  
  16978. /**************************************************************/
  16979. /* SP_LOG_DTSPACKAGE_END                                      */
  16980. /**************************************************************/
  16981. PRINT ''
  16982. PRINT 'Creating procedure sp_log_dtspackage_end...'
  16983. GO
  16984. IF OBJECT_ID(N'sp_log_dtspackage_end') IS NOT NULL
  16985.   DROP PROCEDURE sp_log_dtspackage_end
  16986. GO
  16987. CREATE PROCEDURE sp_log_dtspackage_end
  16988.   @lineagefull        UNIQUEIDENTIFIER,
  16989.   @endtime        DATETIME,
  16990.   @elapsedtime        double precision,
  16991.   @errorcode        INT,
  16992.   @errordescription    NVARCHAR(2000)
  16993. AS
  16994.   SET NOCOUNT ON
  16995.  
  16996.   --// Validate lineage.
  16997.   DECLARE @stringfromclsid NVARCHAR(200)
  16998.   IF NOT EXISTS (SELECT * FROM sysdtspackagelog WHERE lineagefull = @lineagefull)
  16999.   BEGIN
  17000.     SELECT @stringfromclsid = CONVERT(NVARCHAR(50), @lineagefull)
  17001.     RAISERROR(14262, 16, 1, '@lineagefull', @stringfromclsid)
  17002.     RETURN(1) -- Failure
  17003.   END
  17004.  
  17005.   UPDATE sysdtspackagelog
  17006.     SET 
  17007.         endtime = @endtime,
  17008.         elapsedtime = @elapsedtime,
  17009.         errorcode = @errorcode,
  17010.         errordescription = @errordescription
  17011.     WHERE lineagefull = @lineagefull
  17012.  
  17013.   RETURN 0    -- SUCCESS
  17014. GO
  17015. GRANT EXECUTE ON sp_log_dtspackage_end TO PUBLIC
  17016. GO
  17017.  
  17018. /**************************************************************/
  17019. /* SP_LOG_DTSSTEP_BEGIN                                       */
  17020. /**************************************************************/
  17021. PRINT ''
  17022. PRINT 'Creating procedure sp_log_dtsstep_begin...'
  17023. GO
  17024. IF OBJECT_ID(N'sp_log_dtsstep_begin') IS NOT NULL
  17025.   DROP PROCEDURE sp_log_dtsstep_begin
  17026. GO
  17027. CREATE PROCEDURE sp_log_dtsstep_begin
  17028.   @lineagefull        UNIQUEIDENTIFIER,
  17029.   @stepname        sysname,
  17030.   @starttime        DATETIME
  17031. AS
  17032.   SET NOCOUNT ON
  17033.  
  17034.   --// Validate lineage.
  17035.   DECLARE @stringfromclsid NVARCHAR(200)
  17036.   IF NOT EXISTS (SELECT * FROM sysdtspackagelog WHERE lineagefull = @lineagefull)
  17037.   BEGIN
  17038.     SELECT @stringfromclsid = CONVERT(NVARCHAR(50), @lineagefull)
  17039.     RAISERROR(14262, 16, 1, '@lineagefull', @stringfromclsid)
  17040.     RETURN(1) -- Failure
  17041.   END
  17042.  
  17043.   INSERT sysdtssteplog (
  17044.     lineagefull,
  17045.     stepname,
  17046.     starttime
  17047.   ) VALUES (
  17048.     @lineagefull,
  17049.     @stepname,
  17050.     @starttime
  17051.   )
  17052.  
  17053.   --// Return the @@identity for sp_log_dtstask and sp_logdtsstep_end
  17054.   SELECT @@IDENTITY
  17055.  
  17056.   RETURN 0    -- SUCCESS
  17057. GO
  17058. GRANT EXECUTE ON sp_log_dtsstep_begin TO PUBLIC
  17059. GO
  17060.  
  17061. /**************************************************************/
  17062. /* SP_LOG_DTSSTEP_END                                         */
  17063. /**************************************************************/
  17064. PRINT ''
  17065. PRINT 'Creating procedure sp_log_dtsstep_end...'
  17066. GO
  17067. IF OBJECT_ID(N'sp_log_dtsstep_end') IS NOT NULL
  17068.   DROP PROCEDURE sp_log_dtsstep_end
  17069. GO
  17070. CREATE PROCEDURE sp_log_dtsstep_end
  17071.   @stepexecutionid    BIGINT,
  17072.   @stepexecstatus    int,
  17073.   @stepexecresult    int,
  17074.   @endtime        DATETIME,
  17075.   @elapsedtime        double precision,
  17076.   @errorcode        INT,
  17077.   @errordescription    NVARCHAR(2000),
  17078.   @progresscount    BIGINT
  17079. AS
  17080.   SET NOCOUNT ON
  17081.  
  17082.   --// Validate @stepexecutionid.
  17083.   DECLARE @stringfromclsid NVARCHAR(200)
  17084.   IF NOT EXISTS (SELECT * FROM sysdtssteplog WHERE stepexecutionid = @stepexecutionid)
  17085.   BEGIN
  17086.     SELECT @stringfromclsid = CONVERT(NVARCHAR(50), @stepexecutionid)
  17087.     RAISERROR(14262, 16, 1, '@stepexecutionid', @stringfromclsid)
  17088.     RETURN(1) -- Failure
  17089.   END
  17090.  
  17091.   UPDATE sysdtssteplog
  17092.     SET 
  17093.         stepexecstatus = @stepexecstatus,
  17094.         stepexecresult = @stepexecresult,
  17095.         endtime = @endtime,
  17096.         elapsedtime = @elapsedtime,
  17097.         errorcode = @errorcode,
  17098.         errordescription = @errordescription,
  17099.         progresscount = @progresscount
  17100.     WHERE stepexecutionid = @stepexecutionid
  17101.  
  17102.   RETURN 0    -- SUCCESS
  17103. GO
  17104. GRANT EXECUTE ON sp_log_dtsstep_end TO PUBLIC
  17105. GO
  17106.  
  17107. /**************************************************************/
  17108. /* SP_LOG_DTSTASK                                             */
  17109. /**************************************************************/
  17110. PRINT ''
  17111. PRINT 'Creating procedure sp_log_dtstask...'
  17112. GO
  17113. IF OBJECT_ID(N'sp_log_dtstask') IS NOT NULL
  17114.   DROP PROCEDURE sp_log_dtstask
  17115. GO
  17116. CREATE PROCEDURE sp_log_dtstask
  17117.   @stepexecutionid    BIGINT,
  17118.   @sequenceid        INT,
  17119.   @errorcode        INT,
  17120.   @description        NVARCHAR(2000)
  17121. AS
  17122.   SET NOCOUNT ON
  17123.  
  17124.   --// Validate @stepexecutionid.
  17125.   DECLARE @stringfromclsid NVARCHAR(200)
  17126.   IF NOT EXISTS (SELECT * FROM sysdtssteplog WHERE stepexecutionid = @stepexecutionid)
  17127.   BEGIN
  17128.     SELECT @stringfromclsid = CONVERT(NVARCHAR(50), @stepexecutionid)
  17129.     RAISERROR(14262, 16, 1, '@stepexecutionid', @stringfromclsid)
  17130.     RETURN(1) -- Failure
  17131.   END
  17132.  
  17133.   INSERT sysdtstasklog (
  17134.     stepexecutionid,
  17135.     sequenceid,
  17136.     errorcode,
  17137.     description
  17138.   ) VALUES (
  17139.     @stepexecutionid,
  17140.     @sequenceid,
  17141.     @errorcode,
  17142.     @description
  17143.   )
  17144.  
  17145.   RETURN 0    -- SUCCESS
  17146. GO
  17147. GRANT EXECUTE ON sp_log_dtstask TO PUBLIC
  17148. GO
  17149.  
  17150. /**************************************************************/
  17151. /* SP_ENUM_DTSPACKAGELOG                                      */
  17152. /**************************************************************/
  17153. PRINT ''
  17154. PRINT 'Creating procedure sp_enum_dtspackagelog...'
  17155. GO
  17156. IF OBJECT_ID(N'sp_enum_dtspackagelog') IS NOT NULL
  17157.   DROP PROCEDURE sp_enum_dtspackagelog
  17158. GO
  17159. CREATE PROCEDURE sp_enum_dtspackagelog
  17160.   @name sysname,
  17161.   @flags INT = 0,                  --// Bitmask:  0x01 == return only latest
  17162.   @id UNIQUEIDENTIFIER = NULL,        --// If non-NULL, use instead of @name.
  17163.   @versionid UNIQUEIDENTIFIER = NULL,    --// If non-NULL, use instead of @id or @name
  17164.   @lineagefull UNIQUEIDENTIFIER = NULL    --// If non-NULL, use instead of @versionid or @id or @name
  17165. AS
  17166.   SET NOCOUNT ON
  17167.  
  17168.   --// This is used for realtime viewing of package logs, so don't error if no entries
  17169.   --// found, simply return an empty result set.
  17170.   SELECT
  17171.     p.name,
  17172.     p.description,
  17173.     p.id,
  17174.     p.versionid,
  17175.     p.lineagefull,
  17176.     p.lineageshort,
  17177.     p.starttime,
  17178.     p.endtime,
  17179.     p.elapsedtime,
  17180.     p.computer,
  17181.     p.operator,
  17182.     p.logdate,
  17183.     p.errorcode,
  17184.     p.errordescription
  17185.   FROM sysdtspackagelog p
  17186.   WHERE ((@lineagefull IS NULL OR p.lineagefull = @lineagefull)
  17187.       AND  (@versionid IS NULL OR p.versionid = @versionid)
  17188.       AND (@id IS NULL OR p.id = @id)
  17189.       AND (@name IS NULL OR p.name = @name))
  17190.     AND ((@flags & 0x01) = 0
  17191.       OR p.logdate = 
  17192.       (
  17193.         SELECT MAX(logdate) 
  17194.         FROM sysdtspackagelog d
  17195.         WHERE (d.id = p.id)
  17196.       )
  17197.      )
  17198.   ORDER BY logdate 
  17199.  
  17200.   RETURN 0    -- SUCCESS
  17201. GO
  17202. GRANT EXECUTE ON sp_enum_dtspackagelog TO PUBLIC
  17203. GO
  17204.  
  17205. /**************************************************************/
  17206. /* SP_ENUM_DTSSTEPLOG                                         */
  17207. /**************************************************************/
  17208. PRINT ''
  17209. PRINT 'Creating procedure sp_enum_dtssteplog...'
  17210. GO
  17211. IF OBJECT_ID(N'sp_enum_dtssteplog') IS NOT NULL
  17212.   DROP PROCEDURE sp_enum_dtssteplog
  17213. GO
  17214. CREATE PROCEDURE sp_enum_dtssteplog
  17215.   @lineagefull        UNIQUEIDENTIFIER = NULL,    -- all steps in this package execution
  17216.   @stepexecutionid    BIGINT = NULL
  17217. AS
  17218.   SET NOCOUNT ON
  17219.  
  17220.   --// This is used for realtime viewing of package logs, so don't error if no entries
  17221.   --// found, simply return an empty result set.
  17222.   --// This query must be restricted within a single package execution (lineage); it may
  17223.   --// be further restricted by stepexecutionid to a single step within that package execution.
  17224.   SELECT
  17225.     stepexecutionid,
  17226.     lineagefull,
  17227.     stepname,
  17228.     stepexecstatus,
  17229.     stepexecresult,
  17230.     starttime,
  17231.     endtime,
  17232.     elapsedtime,
  17233.     errorcode,
  17234.     errordescription,
  17235.     progresscount
  17236.   FROM sysdtssteplog
  17237.   WHERE (@lineagefull IS NULL OR lineagefull = @lineagefull)
  17238.     AND (@stepexecutionid IS NULL OR stepexecutionid = @stepexecutionid)
  17239.   ORDER BY stepexecutionid
  17240.  
  17241.   RETURN 0    -- SUCCESS
  17242. GO
  17243. GRANT EXECUTE ON sp_enum_dtssteplog TO PUBLIC
  17244. GO
  17245.  
  17246. /**************************************************************/
  17247. /* SP_ENUM_DTSTASKLOG                                         */
  17248. /**************************************************************/
  17249. PRINT ''
  17250. PRINT 'Creating procedure sp_enum_dtstasklog...'
  17251. GO
  17252. IF OBJECT_ID(N'sp_enum_dtstasklog') IS NOT NULL
  17253.   DROP PROCEDURE sp_enum_dtstasklog
  17254. GO
  17255. CREATE PROCEDURE sp_enum_dtstasklog
  17256.   @stepexecutionid    BIGINT,
  17257.   @sequenceid        INT = NULL
  17258. AS
  17259.   SET NOCOUNT ON
  17260.  
  17261.   --// This is used for realtime viewing of package logs, so don't error if no entries
  17262.   --// found, simply return an empty result set.
  17263.   --// This query must be restricted within a single step execution; it may
  17264.   --// be further restricted by stepexecutionid to a single record within that step execution.
  17265.   SELECT
  17266.     -- stepexecutionid,  -- this is always passed in so we don't need to return it.
  17267.     sequenceid,
  17268.     errorcode,
  17269.     description
  17270.   FROM sysdtstasklog
  17271.   WHERE (stepexecutionid IS NULL or stepexecutionid = @stepexecutionid)
  17272.     AND (@sequenceid IS NULL OR sequenceid = @sequenceid)
  17273.   ORDER BY sequenceid
  17274.  
  17275.   RETURN 0    -- SUCCESS
  17276. GO
  17277. GRANT EXECUTE ON sp_enum_dtstasklog TO PUBLIC
  17278. GO
  17279.  
  17280. /**************************************************************/
  17281. /* SP_DUMP_DTSLOG_ALL                                         */
  17282. /**************************************************************/
  17283. PRINT ''
  17284. PRINT 'Creating procedure sp_dump_dtslog_all...'
  17285. GO
  17286. IF OBJECT_ID(N'sp_dump_dtslog_all') IS NOT NULL
  17287.   DROP PROCEDURE sp_dump_dtslog_all
  17288. GO
  17289. CREATE PROCEDURE sp_dump_dtslog_all
  17290. AS
  17291.   SET NOCOUNT ON
  17292.  
  17293.   --// sysadmin only.
  17294.   IF (ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) <> 1)
  17295.   BEGIN
  17296.     RAISERROR(15003, 16, 1, N'sysadmin')
  17297.     RETURN(1) -- Failure
  17298.   END
  17299.  
  17300.   DELETE sysdtspackagelog
  17301.   RETURN 0    -- SUCCESS
  17302. GO
  17303. GRANT EXECUTE ON sp_dump_dtslog_all TO PUBLIC
  17304. GO
  17305.  
  17306. /**************************************************************/
  17307. /* SP_DUMP_DTSPACKAGELOG                                      */
  17308. /**************************************************************/
  17309. PRINT ''
  17310. PRINT 'Creating procedure sp_dump_dtspackagelog...'
  17311. GO
  17312. IF OBJECT_ID(N'sp_dump_dtspackagelog') IS NOT NULL
  17313.   DROP PROCEDURE sp_dump_dtspackagelog
  17314. GO
  17315. CREATE PROCEDURE sp_dump_dtspackagelog
  17316.   @name sysname,
  17317.   @flags INT = 0,                  --// Bitmask:  0x01 == preserve latest
  17318.   @id UNIQUEIDENTIFIER = NULL,        --// If non-NULL, use instead of @name.
  17319.   @versionid UNIQUEIDENTIFIER = NULL,    --// If non-NULL, use instead of @id or @name
  17320.   @lineagefull UNIQUEIDENTIFIER = NULL    --// If non-NULL, use instead of @versionid or @id or @name
  17321. AS
  17322.   SET NOCOUNT ON
  17323.  
  17324.   --// sysadmin only.
  17325.   IF (ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) <> 1)
  17326.   BEGIN
  17327.     RAISERROR(15003, 16, 1, N'sysadmin')
  17328.     RETURN(1) -- Failure
  17329.   END
  17330.  
  17331.   --// Don't error if no entries found, as the desired result will be met.
  17332.   --// DELETE will CASCADE
  17333.   DELETE sysdtspackagelog
  17334.   FROM sysdtspackagelog p
  17335.   WHERE ((@lineagefull IS NULL OR p.lineagefull = @lineagefull)
  17336.       AND  (@versionid IS NULL OR p.versionid = @versionid)
  17337.       AND (@id IS NULL OR p.id = @id)
  17338.       AND (@name IS NULL OR p.name = @name))
  17339.     AND ((@flags & 0x01) = 0
  17340.       OR p.logdate < 
  17341.       (
  17342.         SELECT MAX(logdate) 
  17343.         FROM sysdtspackagelog d
  17344.         WHERE (d.id = p.id)
  17345.       )
  17346.      )
  17347.  
  17348.   RETURN 0    -- SUCCESS
  17349. GO
  17350. GRANT EXECUTE ON sp_dump_dtspackagelog TO PUBLIC
  17351. GO
  17352.  
  17353. /**************************************************************/
  17354. /* SP_DUMP_DTSSTEPLOG                                         */
  17355. /**************************************************************/
  17356. PRINT ''
  17357. PRINT 'Creating procedure sp_dump_dtssteplog...'
  17358. GO
  17359. IF OBJECT_ID(N'sp_dump_dtssteplog') IS NOT NULL
  17360.   DROP PROCEDURE sp_dump_dtssteplog
  17361. GO
  17362. CREATE PROCEDURE sp_dump_dtssteplog
  17363.   @lineagefull        UNIQUEIDENTIFIER = NULL,    -- all steps in this package execution
  17364.   @stepexecutionid    BIGINT = NULL
  17365. AS
  17366.   SET NOCOUNT ON
  17367.  
  17368.   --// sysadmin only.
  17369.   IF (ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) <> 1)
  17370.   BEGIN
  17371.     RAISERROR(15003, 16, 1, N'sysadmin')
  17372.     RETURN(1) -- Failure
  17373.   END
  17374.  
  17375.   --// Don't error if no entries found, as the desired result will be met.
  17376.   --// DELETE will CASCADE
  17377.   DELETE sysdtssteplog
  17378.   WHERE (@lineagefull IS NULL OR lineagefull = @lineagefull)
  17379.     AND (@stepexecutionid IS NULL OR stepexecutionid = @stepexecutionid)
  17380.  
  17381.   RETURN 0    -- SUCCESS
  17382. GO
  17383. GRANT EXECUTE ON sp_dump_dtssteplog TO PUBLIC
  17384. GO
  17385.  
  17386. /**************************************************************/
  17387. /* SP_DUMP_DTSTASKLOG                                         */
  17388. /**************************************************************/
  17389. PRINT ''
  17390. PRINT 'Creating procedure sp_dump_dtstasklog...'
  17391. GO
  17392. IF OBJECT_ID(N'sp_dump_dtstasklog') IS NOT NULL
  17393.   DROP PROCEDURE sp_dump_dtstasklog
  17394. GO
  17395. CREATE PROCEDURE sp_dump_dtstasklog
  17396.   @stepexecutionid    BIGINT,
  17397.   @sequenceid        INT = NULL
  17398. AS
  17399.   SET NOCOUNT ON
  17400.  
  17401.   --// sysadmin only.
  17402.   IF (ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) <> 1)
  17403.   BEGIN
  17404.     RAISERROR(15003, 16, 1, N'sysadmin')
  17405.     RETURN(1) -- Failure
  17406.   END
  17407.  
  17408.   --// Don't error if no entries found, as the desired result will be met.
  17409.   DELETE sysdtstasklog
  17410.   WHERE (stepexecutionid IS NULL or stepexecutionid = @stepexecutionid)
  17411.     AND (@sequenceid IS NULL OR sequenceid = @sequenceid)
  17412.  
  17413.   RETURN 0    -- SUCCESS
  17414. GO
  17415. GRANT EXECUTE ON sp_dump_dtstasklog TO PUBLIC
  17416. GO
  17417.  
  17418. /**************************************************************/
  17419. /*                                                            */
  17420. /*  D  B    M  A  I  N  T  E  N  A  N  C  E    P  L  A  N  S  */
  17421. /*                                                            */
  17422. /**************************************************************/
  17423.  
  17424. /**************************************************************/
  17425. /* SYSDBMAINTPLANS                                            */
  17426. /**************************************************************/
  17427.  
  17428. IF (NOT EXISTS (SELECT *
  17429.                 FROM msdb.dbo.sysobjects
  17430.                 WHERE (name = N'sysdbmaintplans')
  17431.                   AND (type = 'U')))
  17432. BEGIN
  17433.   PRINT ''
  17434.   PRINT 'Creating table sysdbmaintplans...'
  17435.  
  17436.   CREATE TABLE sysdbmaintplans
  17437.   (
  17438.   plan_id                    UNIQUEIDENTIFIER NOT NULL PRIMARY KEY CLUSTERED,
  17439.   plan_name                  sysname          NOT NULL,
  17440.   date_created               DATETIME         NOT NULL DEFAULT (GETDATE()),
  17441.   owner                      sysname          NOT NULL DEFAULT (ISNULL(NT_CLIENT(), SUSER_SNAME())),
  17442.   max_history_rows           INT              NOT NULL DEFAULT (0),
  17443.   remote_history_server      sysname          NOT NULL DEFAULT (''),
  17444.   max_remote_history_rows    INT              NOT NULL DEFAULT (0),
  17445.   user_defined_1             INT              NULL,
  17446.   user_defined_2             NVARCHAR(100)    NULL,
  17447.   user_defined_3             DATETIME         NULL,
  17448.   user_defined_4             UNIQUEIDENTIFIER NULL
  17449.   )
  17450. END
  17451. go
  17452.  
  17453. -- Add row for "plan 0"
  17454. IF (NOT EXISTS (SELECT *
  17455.                 FROM msdb.dbo.sysdbmaintplans
  17456.                 WHERE (plan_id = CONVERT(UNIQUEIDENTIFIER, 0x00))))
  17457.   INSERT INTO sysdbmaintplans(plan_id, plan_name, owner) VALUES (0x00, N'All ad-hoc plans', N'sa')
  17458. go
  17459.  
  17460. /**************************************************************/
  17461. /* SYSDBMAINTPLAN_JOBS                                        */
  17462. /**************************************************************/
  17463.  
  17464. IF (NOT EXISTS (SELECT *
  17465.                 FROM msdb.dbo.sysobjects
  17466.                 WHERE (name = N'sysdbmaintplan_jobs')
  17467.                   AND (type = 'U')))
  17468. BEGIN
  17469.   PRINT ''
  17470.   PRINT 'Creating table sysdbmaintplan_jobs...'
  17471.  
  17472.   CREATE TABLE sysdbmaintplan_jobs
  17473.   (
  17474.   plan_id UNIQUEIDENTIFIER NOT NULL UNIQUE CLUSTERED (plan_id, job_id)
  17475.                                     FOREIGN KEY REFERENCES msdb.dbo.sysdbmaintplans (plan_id),
  17476.   job_id  UNIQUEIDENTIFIER NOT NULL
  17477.   )
  17478. END
  17479. go
  17480.  
  17481. /**************************************************************/
  17482. /* SYSDBMAINTPLAN_DATABASES                                   */
  17483. /**************************************************************/
  17484.  
  17485. IF (NOT EXISTS (SELECT *
  17486.                 FROM msdb.dbo.sysobjects
  17487.                 WHERE (name = N'sysdbmaintplan_databases')
  17488.                   AND (type = 'U')))
  17489. BEGIN
  17490.   PRINT ''
  17491.   PRINT 'Creating table sysdbmaintplan_databases...'
  17492.  
  17493.   CREATE TABLE sysdbmaintplan_databases
  17494.   (
  17495.   plan_id       UNIQUEIDENTIFIER NOT NULL UNIQUE CLUSTERED (plan_id, database_name)
  17496.                                           FOREIGN KEY REFERENCES msdb.dbo.sysdbmaintplans (plan_id),
  17497.   database_name sysname          NOT NULL
  17498.   )
  17499. END
  17500. go
  17501.  
  17502. /**************************************************************/
  17503. /* SYSDBMAINTPLAN_HISTORY                                     */
  17504. /**************************************************************/
  17505.  
  17506. IF (NOT EXISTS (SELECT *
  17507.                 FROM msdb.dbo.sysobjects
  17508.                 WHERE (name = N'sysdbmaintplan_history')
  17509.                   AND (type = 'U')))
  17510. BEGIN
  17511.   PRINT ''
  17512.   PRINT 'Creating table sysdbmaintplan_history...'
  17513.  
  17514.   CREATE TABLE sysdbmaintplan_history
  17515.   (
  17516.   sequence_id    INT               NOT NULL IDENTITY UNIQUE NONCLUSTERED,
  17517.   plan_id        UNIQUEIDENTIFIER  NOT NULL DEFAULT('00000000-0000-0000-0000-000000000000'),
  17518.   plan_name      sysname           NOT NULL DEFAULT('All ad-hoc plans'),
  17519.   database_name  sysname           NULL,
  17520.   server_name    sysname           NOT NULL DEFAULT (CONVERT(sysname, ServerProperty('ServerName'))),
  17521.   activity       NVARCHAR(128)     NULL,
  17522.   succeeded      BIT               NOT NULL DEFAULT (1),
  17523.   end_time       DATETIME          NOT NULL DEFAULT (GETDATE()),
  17524.   duration       INT               NULL     DEFAULT (0),
  17525.   start_time     AS                DATEADD (ss, -duration, end_time),
  17526.   error_number   INT               NOT NULL DEFAULT (0),
  17527.   message        NVARCHAR(512)     NULL
  17528.   )
  17529.  
  17530.   CREATE CLUSTERED INDEX clust ON sysdbmaintplan_history(plan_id)
  17531. END
  17532. -- ALTER TABLE to correct default constraint 
  17533. ELSE
  17534. BEGIN
  17535.   CREATE TABLE #t
  17536.   (
  17537.   constraint_type         NVARCHAR(146)  COLLATE database_default NULL,
  17538.   constraint_name         sysname        COLLATE database_default NULL,
  17539.   delete_action           NVARCHAR(20)   COLLATE database_default NULL,
  17540.   update_action           NVARCHAR(20)   COLLATE database_default NULL,
  17541.   status_enabled          NVARCHAR(20)   COLLATE database_default NULL,
  17542.   status_for_replication  NVARCHAR(20)   COLLATE database_default NULL,
  17543.   constraint_keys         NVARCHAR(2126) COLLATE database_default NULL
  17544.   )
  17545.  
  17546.   INSERT INTO #t EXEC sp_helpconstraint N'sysdbmaintplan_history', 'nomsg'
  17547.  
  17548.   DECLARE @constraint_name sysname
  17549.   DECLARE @sql NVARCHAR(4000)
  17550.  
  17551.   SELECT @constraint_name = constraint_name 
  17552.   FROM   #t 
  17553.   WHERE  constraint_type = N'DEFAULT on column server_name' 
  17554.   AND    constraint_keys = N'(@@servername)'
  17555.  
  17556.   DROP TABLE #t
  17557.  
  17558.   -- default found
  17559.   IF (@constraint_name IS NOT NULL)
  17560.   BEGIN
  17561.     PRINT ''
  17562.     PRINT 'Alter sysdbmaintplan_history ...'
  17563.     SELECT @sql = N'ALTER TABLE sysdbmaintplan_history DROP CONSTRAINT ' + @constraint_name
  17564.     EXEC (@sql)
  17565.  
  17566.     ALTER TABLE sysdbmaintplan_history 
  17567.       ADD CONSTRAINT servername_default DEFAULT (CONVERT(sysname, ServerProperty('ServerName')))
  17568.       FOR server_name
  17569.   END
  17570. END
  17571. go
  17572.  
  17573. /**************************************************************/
  17574. /* SPs for the maintenance plans                              */
  17575. /**************************************************************/
  17576. /**************************************************************/
  17577. /* sp_clear_dbmaintplan_by_db                                 */
  17578. /**************************************************************/
  17579.  
  17580. PRINT ''
  17581. PRINT 'Creating procedure sp_clear_dbmaintplan_by_db...'
  17582. GO
  17583. IF (EXISTS (SELECT *
  17584.                 FROM msdb.dbo.sysobjects
  17585.                 WHERE (name = N'sp_clear_dbmaintplan_by_db') AND (type = 'P')))
  17586.   DROP PROCEDURE sp_clear_dbmaintplan_by_db
  17587. GO
  17588. CREATE PROCEDURE sp_clear_dbmaintplan_by_db
  17589.   @db_name sysname
  17590. AS
  17591. BEGIN
  17592.   DECLARE planid_cursor CURSOR
  17593.   FOR
  17594.   select plan_id from msdb.dbo.sysdbmaintplan_databases where database_name=@db_name
  17595.   OPEN planid_cursor
  17596.   declare @planid uniqueidentifier
  17597.   FETCH NEXT FROM planid_cursor INTO @planid
  17598.   WHILE (@@FETCH_STATUS <> -1)
  17599.   BEGIN
  17600.     IF (@@FETCH_STATUS <> -2)
  17601.     BEGIN
  17602.       delete from msdb.dbo.sysdbmaintplan_databases where plan_id=@planid AND database_name=@db_name
  17603.       if (NOT EXISTS(select * from msdb.dbo.sysdbmaintplan_databases where plan_id=@planid))
  17604.       BEGIN
  17605.         --delete the job
  17606.         DECLARE jobid_cursor CURSOR
  17607.         FOR
  17608.         select job_id from msdb.dbo.sysdbmaintplan_jobs where plan_id=@planid
  17609.         OPEN jobid_cursor
  17610.         DECLARE @jobid uniqueidentifier
  17611.         FETCH NEXT FROM jobid_cursor INTO @jobid
  17612.         WHILE (@@FETCH_STATUS <> -1)
  17613.         BEGIN
  17614.           if (@@FETCH_STATUS <> -2)
  17615.           BEGIN
  17616.             execute msdb.dbo.sp_delete_job @jobid
  17617.           END
  17618.           FETCH NEXT FROM jobid_cursor into @jobid
  17619.         END
  17620.         CLOSE jobid_cursor
  17621.         DEALLOCATE jobid_cursor
  17622.         --delete the history
  17623.         delete from msdb.dbo.sysdbmaintplan_history where plan_id=@planid
  17624.         --delete the plan
  17625.         delete from msdb.dbo.sysdbmaintplans where plan_id=@planid
  17626.       END
  17627.     END
  17628.     FETCH NEXT FROM planid_cursor INTO @planid
  17629.   END
  17630.   CLOSE planid_cursor
  17631.   DEALLOCATE planid_cursor
  17632. END
  17633. GO
  17634.  
  17635. /**************************************************************/
  17636. /* sp_add_maintenance_plan                                    */
  17637. /**************************************************************/
  17638.  
  17639. PRINT ''
  17640. PRINT 'Creating procedure sp_add_maintenance_plan...'
  17641. GO
  17642. IF (EXISTS (SELECT *
  17643.                 FROM msdb.dbo.sysobjects
  17644.                 WHERE (name = N'sp_add_maintenance_plan') AND (type = 'P')))
  17645.   DROP PROCEDURE sp_add_maintenance_plan
  17646. GO
  17647. CREATE PROCEDURE sp_add_maintenance_plan
  17648.   @plan_name varchar(128),
  17649.   @plan_id   UNIQUEIDENTIFIER OUTPUT
  17650. AS
  17651. BEGIN
  17652.   IF (NOT EXISTS (SELECT *
  17653.                 FROM msdb.dbo.sysdbmaintplans
  17654.                 WHERE plan_name=@plan_name))
  17655.     BEGIN
  17656.       SELECT @plan_id=NEWID()
  17657.       INSERT INTO msdb.dbo.sysdbmaintplans (plan_id, plan_name) VALUES (@plan_id, @plan_name)
  17658.     END
  17659.   ELSE
  17660.     BEGIN
  17661.       RAISERROR(14261,-1,-1,'@plan_name',@plan_name)
  17662.       RETURN(1) -- failure
  17663.     END
  17664. END
  17665. GO
  17666.  
  17667. /**************************************************************/
  17668. /* sp_delete_maintenance_plan                                 */
  17669. /**************************************************************/
  17670.  
  17671. PRINT ''
  17672. PRINT 'Creating procedure sp_delete_maintenance_plan...'
  17673. GO
  17674. IF (EXISTS (SELECT *
  17675.             FROM msdb.dbo.sysobjects
  17676.             WHERE (name = N'sp_delete_maintenance_plan')
  17677.               AND (type = 'P')))
  17678.   DROP PROCEDURE sp_delete_maintenance_plan
  17679. GO
  17680. CREATE PROCEDURE sp_delete_maintenance_plan
  17681.   @plan_id UNIQUEIDENTIFIER
  17682. AS
  17683. BEGIN
  17684.   /*check if the plan_id is valid*/
  17685.   IF (NOT EXISTS(SELECT *
  17686.                  FROM sysdbmaintplans
  17687.                  WHERE plan_id=@plan_id))
  17688.   BEGIN
  17689.     DECLARE @syserr VARCHAR(100)
  17690.     SELECT @syserr=CONVERT(VARCHAR(100),@plan_id)
  17691.     RAISERROR(14262,-1,-1,'@plan_id',@syserr)
  17692.     RETURN(1)
  17693.   END
  17694.   /* clean the related records in sysdbmaintplan_database */
  17695.   DELETE FROM msdb.dbo.sysdbmaintplan_databases
  17696.   WHERE plan_id=@plan_id
  17697.   /* clean the related records in sysdbmaintplan_jobs*/
  17698.   DELETE FROM msdb.dbo.sysdbmaintplan_jobs
  17699.   WHERE plan_id=@plan_id
  17700.   /* clean sysdbmaintplans */
  17701.   DELETE FROM msdb.dbo.sysdbmaintplans
  17702.   WHERE  plan_id= @plan_id
  17703. END
  17704. GO
  17705.  
  17706. /**************************************************************/
  17707. /* sp_add_maintenance_plan_db                                 */
  17708. /**************************************************************/
  17709. PRINT ''
  17710. PRINT 'Creating procedure sp_add_maintenance_plan_db...'
  17711. GO
  17712. IF (EXISTS (SELECT *
  17713.             FROM msdb.dbo.sysobjects
  17714.             WHERE (name = N'sp_add_maintenance_plan_db')
  17715.               AND (type = 'P')))
  17716.   DROP PROCEDURE sp_add_maintenance_plan_db
  17717. GO
  17718. CREATE PROCEDURE sp_add_maintenance_plan_db
  17719.   @plan_id UNIQUEIDENTIFIER,
  17720.   @db_name sysname
  17721. AS
  17722. BEGIN
  17723.   DECLARE @syserr VARCHAR(100)
  17724.   /*check if the plan_id is valid */
  17725.   IF (NOT EXISTS (SELECT plan_id
  17726.               FROM  msdb.dbo.sysdbmaintplans
  17727.               WHERE plan_id=@plan_id))
  17728.   BEGIN
  17729.     SELECT @syserr=CONVERT(VARCHAR(100),@plan_id)
  17730.     RAISERROR(14262,-1,-1,'@plan_id',@syserr)
  17731.     RETURN(1)
  17732.   END
  17733.   /*check if the database name is valid */
  17734.   IF (NOT EXISTS (SELECT name
  17735.               FROM master.dbo.sysdatabases
  17736.               WHERE name=@db_name))
  17737.     BEGIN
  17738.     RAISERROR(14262,-1,-1,'@db_name',@db_name)
  17739.     RETURN(1)
  17740.   END
  17741.   /*check if the (plan_id, database) pair already exists*/
  17742.   IF (EXISTS (SELECT *
  17743.               FROM sysdbmaintplan_databases
  17744.               WHERE plan_id=@plan_id AND database_name=@db_name))
  17745.   BEGIN
  17746.     SELECT @syserr=CONVERT(VARCHAR(100),@plan_id)+' + '+@db_name
  17747.     RAISERROR(14261,-1,-1,'@plan_id+@db_name',@syserr)
  17748.     RETURN(1)
  17749.   END
  17750.   INSERT INTO msdb.dbo.sysdbmaintplan_databases (plan_id,database_name) VALUES (@plan_id, @db_name)
  17751. END
  17752. GO
  17753.  
  17754. /**************************************************************/
  17755. /* sp_delete_maintenance_plan_db                              */
  17756. /**************************************************************/
  17757. PRINT ''
  17758. PRINT 'Creating procedure sp_delete_maintenance_plan_db...'
  17759. go
  17760. IF (EXISTS (SELECT *
  17761.             FROM msdb.dbo.sysobjects
  17762.             WHERE (name = N'sp_delete_maintenance_plan_db')
  17763.               AND (type = 'P')))
  17764.   DROP PROCEDURE sp_delete_maintenance_plan_db
  17765. go
  17766. CREATE PROCEDURE sp_delete_maintenance_plan_db
  17767.   @plan_id uniqueidentifier,
  17768.   @db_name sysname
  17769. AS
  17770. BEGIN
  17771.   /*check if the (plan_id, db_name) exists in the table*/
  17772.   IF (NOT EXISTS(SELECT *
  17773.                  FROM msdb.dbo.sysdbmaintplan_databases
  17774.                  WHERE @plan_id=plan_id AND @db_name=database_name))
  17775.   BEGIN
  17776.     DECLARE @syserr VARCHAR(300)
  17777.     SELECT @syserr=CONVERT(VARCHAR(100),@plan_id)+' + '+@db_name
  17778.     RAISERROR(14262,-1,-1,'@plan_id+@db_name',@syserr)
  17779.     RETURN(1)
  17780.   END
  17781.   /*delete the pair*/
  17782.   DELETE FROM msdb.dbo.sysdbmaintplan_databases
  17783.   WHERE plan_id=@plan_id AND database_name=@db_name
  17784. END
  17785. GO
  17786.  
  17787. /**************************************************************/
  17788. /* sp_add_maintenance_plan_job                                */
  17789. /**************************************************************/
  17790. PRINT ''
  17791. PRINT 'Creating procedure sp_add_maintenance_plan_job...'
  17792. GO
  17793. IF (EXISTS (SELECT *
  17794.             FROM msdb.dbo.sysobjects
  17795.             WHERE (name = N'sp_add_maintenance_plan_job')
  17796.               AND (type = 'P')))
  17797.   DROP PROCEDURE sp_add_maintenance_plan_job
  17798. GO
  17799. CREATE PROCEDURE sp_add_maintenance_plan_job
  17800.   @plan_id UNIQUEIDENTIFIER,
  17801.   @job_id  UNIQUEIDENTIFIER
  17802. AS
  17803. BEGIN
  17804.   DECLARE @syserr varchar(100)
  17805.   /*check if the @plan_id is valid*/
  17806.   IF (NOT EXISTS(SELECT plan_id
  17807.                  FROM msdb.dbo.sysdbmaintplans
  17808.                  WHERE plan_id=@plan_id))
  17809.   BEGIN
  17810.     SELECT @syserr=CONVERT(VARCHAR(100),@plan_id)
  17811.     RAISERROR(14262,-1,-1,'@plan_id',@syserr)
  17812.     RETURN(1)
  17813.   END
  17814.   /*check if the @job_id is valid*/
  17815.   IF (NOT EXISTS(SELECT job_id
  17816.                  FROM msdb.dbo.sysjobs
  17817.                  WHERE job_id=@job_id))
  17818.   BEGIN
  17819.     SELECT @syserr=CONVERT(VARCHAR(100),@job_id)
  17820.     RAISERROR(14262,-1,-1,'@job_id',@syserr)
  17821.     RETURN(1)
  17822.   END
  17823.   /*check if the job has at least one step calling xp_sqlmaint*/
  17824.   DECLARE @maxind INT
  17825.   SELECT @maxind=(SELECT MAX(CHARINDEX('xp_sqlmaint', command))
  17826.                 FROM  msdb.dbo.sysjobsteps
  17827.                 WHERE @job_id=job_id)
  17828.   IF (@maxind<=0)
  17829.   BEGIN
  17830.     /*print N'Warning: The job is not for maitenance plan.' -- will add the new sysmessage here*/
  17831.     SELECT @syserr=CONVERT(VARCHAR(100),@job_id)
  17832.     RAISERROR(14199,-1,-1,'@job_id',@syserr)
  17833.     RETURN(1)
  17834.   END
  17835.   INSERT INTO msdb.dbo.sysdbmaintplan_jobs(plan_id,job_id) VALUES (@plan_id, @job_id) --don't have to check duplicate here
  17836. END
  17837. GO
  17838.  
  17839. /**************************************************************/
  17840. /* sp_delete_maintenance_plan_job                             */
  17841. /**************************************************************/
  17842. PRINT ''
  17843. PRINT 'Creating procedure sp_delete_maintenance_plan_job...'
  17844. GO
  17845. IF (EXISTS (SELECT *
  17846.             FROM msdb.dbo.sysobjects
  17847.             WHERE (name = N'sp_delete_maintenance_plan_job')
  17848.               AND (type = 'P')))
  17849.   DROP PROCEDURE sp_delete_maintenance_plan_job
  17850. GO
  17851. CREATE PROCEDURE sp_delete_maintenance_plan_job
  17852.   @plan_id uniqueidentifier,
  17853.   @job_id  uniqueidentifier
  17854. AS
  17855. BEGIN
  17856.   /*check if the (plan_id, job_id) exists*/
  17857.   IF (NOT EXISTS(SELECT *
  17858.                  FROM sysdbmaintplan_jobs
  17859.                  WHERE @plan_id=plan_id AND @job_id=job_id))
  17860.   BEGIN
  17861.     DECLARE @syserr VARCHAR(300)
  17862.     SELECT @syserr=CONVERT(VARCHAR(100),@plan_id)+' + '+CONVERT(VARCHAR(100),@job_id)
  17863.     RAISERROR(14262,-1,-1,'@plan_id+@job_id',@syserr)
  17864.     RETURN(1)
  17865.   END
  17866.   DELETE FROM msdb.dbo.sysdbmaintplan_jobs
  17867.   WHERE plan_id=@plan_id AND job_id=@job_id
  17868. END
  17869. GO
  17870.  
  17871. /**************************************************************/
  17872. /* sp_help_maintenance_plan                                   */
  17873. /**************************************************************/
  17874. PRINT ''
  17875. PRINT 'Creating procedure sp_help_maintenance_plan...'
  17876. GO
  17877. IF (EXISTS (SELECT *
  17878.             FROM msdb.dbo.sysobjects
  17879.             WHERE (name = N'sp_help_maintenance_plan')
  17880.               AND (type = 'P')))
  17881.   DROP PROCEDURE sp_help_maintenance_plan
  17882. GO
  17883. CREATE PROCEDURE sp_help_maintenance_plan
  17884.   @plan_id UNIQUEIDENTIFIER = NULL
  17885. AS
  17886. BEGIN
  17887.   IF (@plan_id IS NOT NULL)
  17888.     BEGIN
  17889.       /*return the information about the plan itself*/
  17890.       SELECT *
  17891.       FROM msdb.dbo.sysdbmaintplans
  17892.       WHERE plan_id=@plan_id
  17893.       /*return the information about databases this plan defined on*/
  17894.       SELECT database_name
  17895.       FROM msdb.dbo.sysdbmaintplan_databases
  17896.       WHERE plan_id=@plan_id
  17897.       /*return the information about the jobs that relating to the plan*/
  17898.       SELECT job_id
  17899.       FROM msdb.dbo.sysdbmaintplan_jobs
  17900.       WHERE plan_id=@plan_id
  17901.     END
  17902.   ELSE
  17903.     BEGIN
  17904.       SELECT *
  17905.       FROM msdb.dbo.sysdbmaintplans
  17906.     END
  17907. END
  17908. GO
  17909.  
  17910. /**************************************************************/
  17911. /*                                                            */
  17912. /* B A C K U P  H I S T O R Y                                 */
  17913. /*                                                            */
  17914. /**************************************************************/
  17915. /**************************************************************/
  17916. /* sp_delete_database_backuphistory                           */
  17917. /**************************************************************/
  17918.  
  17919. PRINT ''
  17920. PRINT 'Creating procedure sp_delete_database_backuphistory...'
  17921. go
  17922. IF (EXISTS (SELECT *
  17923.             FROM msdb.dbo.sysobjects
  17924.             WHERE (name = N'sp_delete_database_backuphistory')
  17925.               AND (type = 'P')))
  17926.   DROP PROCEDURE sp_delete_database_backuphistory
  17927. go
  17928. CREATE   PROCEDURE sp_delete_database_backuphistory
  17929.   @db_nm nvarchar(256)
  17930. AS
  17931. BEGIN
  17932.   declare @bsid int
  17933.   declare @msid int
  17934.   declare @rows int
  17935.   declare @errorflag int
  17936.   declare @str nvarchar(64)
  17937.  
  17938.   set nocount on
  17939.   set @errorflag = 0
  17940.   declare oldbackups insensitive cursor for
  17941.     select backup_set_id from backupset where database_name=@db_nm
  17942.     for read only
  17943.   open oldbackups
  17944.   fetch next from oldbackups into @bsid
  17945.   while(@@fetch_status = 0)
  17946.   begin
  17947.     begin transaction
  17948.     set rowcount 1
  17949.     set @rows = (select count(*) from restorehistory where backup_set_id = @bsid)
  17950.     set rowcount 0
  17951.     if (@rows > 0)
  17952.     begin
  17953.       delete from restorefile where restore_history_id in (select restore_history_id from restorehistory where backup_set_id = @bsid)
  17954.       if (@@error <> 0)
  17955.       begin
  17956.          rollback transaction
  17957.          set @errorflag = 1
  17958.          break
  17959.       end
  17960.       delete from restorefilegroup where restore_history_id in (select restore_history_id from restorehistory where backup_set_id = @bsid)
  17961.       if (@@error <> 0)
  17962.       begin
  17963.          rollback transaction
  17964.          set @errorflag = 1
  17965.          break
  17966.       end
  17967.       delete from restorehistory where backup_set_id = @bsid
  17968.       if (@@error <> 0)
  17969.       begin
  17970.          rollback transaction
  17971.          set @errorflag = 1
  17972.          break
  17973.       end
  17974.     end
  17975.     delete from backupfile where backup_set_id = @bsid
  17976.     if (@@error <> 0)
  17977.     begin
  17978.        rollback transaction
  17979.        set @errorflag = 1
  17980.        break
  17981.     end
  17982.     set @msid = (select media_set_id from backupset where backup_set_id = @bsid)
  17983.     delete from backupset where backup_set_id = @bsid
  17984.     if (@@error <> 0)
  17985.     begin
  17986.        rollback transaction
  17987.        set @errorflag = 1
  17988.        break
  17989.     end
  17990.     set rowcount 1
  17991.     set @rows = (select count(*) from backupset where media_set_id = @msid)
  17992.     set rowcount 0
  17993.     if (@rows = 0)
  17994.     begin
  17995.       delete from backupmediafamily where media_set_id = @msid
  17996.       if (@@error <> 0)
  17997.       begin
  17998.          rollback transaction
  17999.          set @errorflag = 1
  18000.          break
  18001.       end
  18002.       delete from backupmediaset where media_set_id = @msid
  18003.       if (@@error <> 0)
  18004.       begin
  18005.          rollback transaction
  18006.          set @errorflag = 1
  18007.          break
  18008.       end
  18009.     end
  18010.     commit transaction
  18011.     fetch next from oldbackups into @bsid
  18012.   end
  18013.   deallocate oldbackups
  18014.   set nocount off
  18015.  
  18016.   if (@errorflag <> 0)
  18017.   begin
  18018.     set @str = (select convert( nvarchar(64), @bsid))
  18019.     raiserror( 4325, -1, -1, @str )
  18020.     return(1)
  18021.   end
  18022.  
  18023. END
  18024. go
  18025.  
  18026. /**************************************************************/
  18027. /* SP_DELETE_BACKUPHISTORY                                    */
  18028. /**************************************************************/
  18029.  
  18030. PRINT ''
  18031. PRINT 'Creating procedure sp_delete_backuphistory...'
  18032. go
  18033. IF (EXISTS (SELECT *
  18034.             FROM msdb.dbo.sysobjects
  18035.             WHERE (name = N'sp_delete_backuphistory')
  18036.               AND (type = 'P')))
  18037.   DROP PROCEDURE sp_delete_backuphistory
  18038. go
  18039. CREATE   PROCEDURE sp_delete_backuphistory
  18040.   @oldest_date datetime
  18041. AS
  18042. BEGIN
  18043.   declare @bsid int
  18044.   declare @msid int
  18045.   declare @rows int
  18046.   declare @errorflag int
  18047.   declare @str nvarchar(64)
  18048.  
  18049.   set nocount on
  18050.   set @errorflag = 0
  18051.   declare oldbackups insensitive cursor for
  18052.     select backup_set_id from backupset where backup_finish_date < @oldest_date
  18053.     for read only
  18054.   open oldbackups
  18055.   fetch next from oldbackups into @bsid
  18056.   while(@@fetch_status = 0)
  18057.   begin
  18058.     begin transaction
  18059.     set rowcount 1
  18060.     set @rows = (select count(*) from restorehistory where backup_set_id = @bsid)
  18061.     set rowcount 0
  18062.     if (@rows > 0)
  18063.     begin
  18064.       delete from restorefile where restore_history_id in (select restore_history_id from restorehistory where backup_set_id = @bsid)
  18065.       if (@@error <> 0)
  18066.       begin
  18067.          rollback transaction
  18068.          set @errorflag = 1
  18069.          break
  18070.       end
  18071.       delete from restorefilegroup where restore_history_id in (select restore_history_id from restorehistory where backup_set_id = @bsid)
  18072.       if (@@error <> 0)
  18073.       begin
  18074.          rollback transaction
  18075.          set @errorflag = 1
  18076.          break
  18077.       end
  18078.       delete from restorehistory where backup_set_id = @bsid
  18079.       if (@@error <> 0)
  18080.       begin
  18081.          rollback transaction
  18082.          set @errorflag = 1
  18083.          break
  18084.       end
  18085.     end
  18086.     delete from backupfile where backup_set_id = @bsid
  18087.     if (@@error <> 0)
  18088.     begin
  18089.        rollback transaction
  18090.        set @errorflag = 1
  18091.        break
  18092.     end
  18093.     set @msid = (select media_set_id from backupset where backup_set_id = @bsid)
  18094.     delete from backupset where backup_set_id = @bsid
  18095.     if (@@error <> 0)
  18096.     begin
  18097.        rollback transaction
  18098.        set @errorflag = 1
  18099.        break
  18100.     end
  18101.     set rowcount 1
  18102.     set @rows = (select count(*) from backupset where media_set_id = @msid)
  18103.     set rowcount 0
  18104.     if (@rows = 0)
  18105.     begin
  18106.       delete from backupmediafamily where media_set_id = @msid
  18107.       if (@@error <> 0)
  18108.       begin
  18109.          rollback transaction
  18110.          set @errorflag = 1
  18111.          break
  18112.       end
  18113.       delete from backupmediaset where media_set_id = @msid
  18114.       if (@@error <> 0)
  18115.       begin
  18116.          rollback transaction
  18117.          set @errorflag = 1
  18118.          break
  18119.       end
  18120.     end
  18121.     commit transaction
  18122.     fetch next from oldbackups into @bsid
  18123.   end
  18124.   deallocate oldbackups
  18125.   set nocount off
  18126.  
  18127.   if (@errorflag <> 0)
  18128.   begin
  18129.     set @str = (select convert( nvarchar(64), @bsid))
  18130.     raiserror( 4325, -1, -1, @str )
  18131.     return(1)
  18132.   end
  18133.  
  18134.   set @str = (select convert( nvarchar(64), @oldest_date))
  18135.   raiserror( 4324, -1, -1, @str  )
  18136.   return(0)
  18137.  
  18138. END
  18139. go
  18140.  
  18141. /**************************************************************/
  18142. /* SP_DELETE_BACKUP_AND_RESTORE_HISTORY                       */
  18143. /**************************************************************/
  18144.  
  18145. PRINT ''
  18146. PRINT 'Creating procedure sp_delete_backup_and_restore_history...'
  18147. go
  18148. IF (EXISTS (SELECT *
  18149.             FROM msdb.dbo.sysobjects
  18150.             WHERE (name = 'sp_delete_backup_and_restore_history')
  18151.               AND (type = 'P')))
  18152.   DROP PROCEDURE sp_delete_backup_and_restore_history
  18153. go
  18154. CREATE PROCEDURE sp_delete_backup_and_restore_history
  18155.   @database_name sysname
  18156. AS
  18157. BEGIN
  18158.   SET NOCOUNT ON
  18159.  
  18160.   CREATE TABLE #backup_set_id      (backup_set_id INT)
  18161.   CREATE TABLE #media_set_id       (media_set_id INT)
  18162.   CREATE TABLE #restore_history_id (restore_history_id INT)
  18163.  
  18164.   INSERT INTO #backup_set_id (backup_set_id)
  18165.   SELECT DISTINCT backup_set_id
  18166.   FROM msdb.dbo.backupset
  18167.   WHERE database_name = @database_name
  18168.  
  18169.   INSERT INTO #media_set_id (media_set_id)
  18170.   SELECT DISTINCT media_set_id
  18171.   FROM msdb.dbo.backupset
  18172.   WHERE database_name = @database_name
  18173.  
  18174.   INSERT INTO #restore_history_id (restore_history_id)
  18175.   SELECT DISTINCT restore_history_id
  18176.   FROM msdb.dbo.restorehistory
  18177.   WHERE backup_set_id IN (SELECT backup_set_id
  18178.                           FROM #backup_set_id)
  18179.  
  18180.   BEGIN TRANSACTION
  18181.  
  18182.   DELETE FROM msdb.dbo.backupfile
  18183.   WHERE backup_set_id IN (SELECT backup_set_id
  18184.                           FROM #backup_set_id)
  18185.   IF (@@error > 0)
  18186.     GOTO Quit
  18187.  
  18188.   DELETE FROM msdb.dbo.restorefile
  18189.   WHERE restore_history_id IN (SELECT restore_history_id
  18190.                                FROM #restore_history_id)
  18191.   IF (@@error > 0)
  18192.     GOTO Quit
  18193.  
  18194.   DELETE FROM msdb.dbo.restorefilegroup
  18195.   WHERE restore_history_id IN (SELECT restore_history_id
  18196.                                FROM #restore_history_id)
  18197.   IF (@@error > 0)
  18198.     GOTO Quit
  18199.  
  18200.   DELETE FROM msdb.dbo.restorehistory
  18201.   WHERE restore_history_id IN (SELECT restore_history_id
  18202.                                FROM #restore_history_id)
  18203.   IF (@@error > 0)
  18204.     GOTO Quit
  18205.  
  18206.   DELETE FROM msdb.dbo.backupset
  18207.   WHERE backup_set_id IN (SELECT backup_set_id
  18208.                           FROM #backup_set_id)
  18209.   IF (@@error > 0)
  18210.     GOTO Quit
  18211.  
  18212.   DELETE msdb.dbo.backupmediafamily
  18213.   FROM msdb.dbo.backupmediafamily bmf
  18214.   WHERE bmf.media_set_id IN (SELECT media_set_id
  18215.                              FROM #media_set_id)
  18216.     AND ((SELECT COUNT(*)
  18217.           FROM msdb.dbo.backupset
  18218.           WHERE media_set_id = bmf.media_set_id) = 0)
  18219.   IF (@@error > 0)
  18220.     GOTO Quit
  18221.  
  18222.   DELETE msdb.dbo.backupmediaset
  18223.   FROM msdb.dbo.backupmediaset bms
  18224.   WHERE bms.media_set_id IN (SELECT media_set_id
  18225.                              FROM #media_set_id)
  18226.     AND ((SELECT COUNT(*)
  18227.           FROM msdb.dbo.backupset
  18228.           WHERE media_set_id = bms.media_set_id) = 0)
  18229.   IF (@@error > 0)
  18230.     GOTO Quit
  18231.  
  18232.   COMMIT TRANSACTION
  18233.   RETURN
  18234.  
  18235. Quit:
  18236.   ROLLBACK TRANSACTION
  18237.  
  18238. END
  18239. go
  18240.  
  18241.  
  18242. /**********************************************************************/
  18243. /* TABLE : log_shipping_primaries                                     */
  18244. /* Populated on the monitor server                                    */
  18245. /*                                                                    */
  18246. /**********************************************************************/
  18247.  
  18248. IF (NOT EXISTS (SELECT *
  18249.             FROM INFORMATION_SCHEMA.TABLES
  18250.             WHERE (TABLE_NAME = N'log_shipping_primaries')))
  18251. BEGIN
  18252.  PRINT ''
  18253.  PRINT 'Creating table log_shipping_primaries...'
  18254.  CREATE TABLE log_shipping_primaries
  18255.  (
  18256.   primary_id                   INT IDENTITY     NOT NULL PRIMARY KEY,
  18257.   primary_server_name          sysname          NOT NULL,
  18258.   primary_database_name        sysname          NOT NULL,
  18259.   maintenance_plan_id          UNIQUEIDENTIFIER NULL,
  18260.   backup_threshold             INT              NOT NULL,
  18261.   threshold_alert              INT              NOT NULL,
  18262.   threshold_alert_enabled      BIT              NOT NULL, /* 1 = enabled, 0 = disabled */
  18263.   last_backup_filename         NVARCHAR(500)    NULL,
  18264.   last_updated                 DATETIME         NULL,
  18265.   planned_outage_start_time    INT              NOT NULL,
  18266.   planned_outage_end_time      INT              NOT NULL,
  18267.   planned_outage_weekday_mask  INT              NOT NULL,
  18268.   source_directory             NVARCHAR(500)    NULL
  18269.  )
  18270. END
  18271. ELSE 
  18272. BEGIN
  18273.   IF (NOT EXISTS (SELECT * 
  18274.     FROM INFORMATION_SCHEMA.COLUMNS
  18275.     WHERE (TABLE_NAME = N'log_shipping_primaries')
  18276.       AND (COLUMN_NAME = N'source_directory')))
  18277.  
  18278.   BEGIN
  18279.     PRINT ''
  18280.     PRINT 'Adding columns to table log_shipping_primaries...'
  18281.  
  18282.     ALTER TABLE log_shipping_primaries
  18283.      ADD source_directory NVARCHAR(500) NULL
  18284.  
  18285.   END
  18286. END 
  18287. go
  18288.  
  18289. /**********************************************************************/
  18290. /* TABLE : log_shipping_secondaries                                   */
  18291. /* Populated on the monitor server                                    */
  18292. /*                                                                    */
  18293. /**********************************************************************/
  18294.  
  18295. IF (NOT EXISTS (SELECT *
  18296.             FROM INFORMATION_SCHEMA.TABLES
  18297.             WHERE (TABLE_NAME = N'log_shipping_secondaries')))
  18298. BEGIN
  18299.  PRINT ''
  18300.  PRINT 'Creating table log_shipping_secondaries...'
  18301.  CREATE TABLE log_shipping_secondaries
  18302.  (
  18303.   primary_id                   INT                FOREIGN KEY REFERENCES log_shipping_primaries (primary_id),
  18304.   secondary_server_name        sysname,
  18305.   secondary_database_name      sysname,
  18306.   last_copied_filename         NVARCHAR(500),
  18307.   last_loaded_filename         NVARCHAR(500),
  18308.   last_copied_last_updated     DATETIME,
  18309.   last_loaded_last_updated     DATETIME,
  18310.   secondary_plan_id            UNIQUEIDENTIFIER,
  18311.   copy_enabled                 BIT,
  18312.   load_enabled                 BIT,              /* 1 = load enabled, 0 = load disabled */
  18313.   out_of_sync_threshold        INT,
  18314.   threshold_alert              INT,
  18315.   threshold_alert_enabled      BIT,              /*1 = enabled, 0 = disabled */
  18316.   planned_outage_start_time    INT,
  18317.   planned_outage_end_time      INT,
  18318.   planned_outage_weekday_mask  INT,
  18319.   allow_role_change            BIT DEFAULT (0)
  18320.  )
  18321. END
  18322. ELSE 
  18323. BEGIN
  18324.   IF (NOT EXISTS (SELECT * 
  18325.     FROM INFORMATION_SCHEMA.COLUMNS
  18326.     WHERE (TABLE_NAME = N'log_shipping_secondaries')
  18327.       AND (COLUMN_NAME = N'allow_role_change')))
  18328.  
  18329.   BEGIN
  18330.     PRINT ''
  18331.     PRINT 'Adding columns to table log_shipping_secondaries...'
  18332.  
  18333.     ALTER TABLE log_shipping_secondaries
  18334.      ADD allow_role_change BIT DEFAULT (0)
  18335.  
  18336.   END
  18337. END 
  18338. go
  18339.  
  18340. /**************************************************************/
  18341. /* sp_add_log_shipping_monitor_jobs                           */
  18342. /**************************************************************/
  18343. PRINT ''
  18344. PRINT 'Creating procedure sp_add_log_shipping_monitor_jobs...'
  18345. go
  18346. IF (EXISTS (SELECT * from msdb.dbo.sysobjects WHERE name = N'sp_add_log_shipping_monitor_jobs' AND type = N'P')  )
  18347.   drop procedure sp_add_log_shipping_monitor_jobs
  18348. go
  18349. CREATE PROCEDURE sp_add_log_shipping_monitor_jobs AS 
  18350. BEGIN
  18351.   SET NOCOUNT ON
  18352.   BEGIN TRANSACTION
  18353.   DECLARE @rv INT
  18354.   DECLARE @backup_job_name sysname
  18355.   SET @backup_job_name = N'Log Shipping Alert Job - Backup'
  18356.   IF (NOT EXISTS (SELECT * FROM msdb.dbo.sysjobs WHERE name = @backup_job_name))
  18357.   BEGIN
  18358.     EXECUTE @rv = msdb.dbo.sp_add_job @job_name = N'Log Shipping Alert Job - Backup'
  18359.  
  18360.     IF (@@error <> 0 OR @rv <> 0) GOTO rollback_quit -- error 
  18361.  
  18362.     EXECUTE @rv = msdb.dbo.sp_add_jobstep 
  18363.       @job_name = N'Log Shipping Alert Job - Backup', 
  18364.       @step_id = 1, 
  18365.       @step_name = N'Log Shipping Alert - Backup', 
  18366.       @command = N'EXECUTE msdb.dbo.sp_log_shipping_monitor_backup',
  18367.       @on_fail_action = 2, 
  18368.       @flags = 4, 
  18369.       @subsystem = N'TSQL', 
  18370.       @on_success_step_id = 0, 
  18371.       @on_success_action = 1, 
  18372.       @on_fail_step_id = 0
  18373.     IF (@@error <> 0 OR @rv <> 0) GOTO rollback_quit -- error 
  18374.  
  18375.    EXECUTE @rv = msdb.dbo.sp_add_jobschedule 
  18376.       @job_name = @backup_job_name, 
  18377.       @freq_type = 4, 
  18378.       @freq_interval = 1, 
  18379.       @freq_subday_type = 0x4, 
  18380.       @freq_subday_interval = 1, -- run every minute
  18381.       @freq_relative_interval = 0, 
  18382.       @name = @backup_job_name
  18383.     IF (@@error <> 0 OR @rv <> 0) GOTO rollback_quit -- error
  18384.  
  18385.    EXECUTE @rv = msdb.dbo.sp_add_jobserver @job_name = @backup_job_name, @server_name = NULL
  18386.     IF (@@error <> 0 OR @rv <> 0) GOTO rollback_quit -- error
  18387.   END
  18388.  
  18389.   DECLARE @restore_job_name sysname
  18390.   SET @restore_job_name = 'Log Shipping Alert Job - Restore'
  18391.   IF (NOT EXISTS (SELECT * FROM msdb.dbo.sysjobs WHERE name = @restore_job_name))
  18392.   BEGIN
  18393.     EXECUTE @rv = msdb.dbo.sp_add_job @job_name = @restore_job_name
  18394.  
  18395.     IF (@@error <> 0 OR @rv <> 0) GOTO rollback_quit -- error 
  18396.  
  18397.     EXECUTE @rv = msdb.dbo.sp_add_jobstep 
  18398.       @job_name = @restore_job_name, 
  18399.       @step_id = 1, 
  18400.       @step_name = @restore_job_name, 
  18401.       @command = N'EXECUTE msdb.dbo.sp_log_shipping_monitor_restore',
  18402.       @on_fail_action = 2, 
  18403.       @flags = 4, 
  18404.       @subsystem = N'TSQL', 
  18405.       @on_success_step_id = 0, 
  18406.       @on_success_action = 1, 
  18407.       @on_fail_step_id = 0
  18408.     IF (@@error <> 0 OR @rv <> 0) GOTO rollback_quit -- error 
  18409.  
  18410.     EXECUTE @rv = msdb.dbo.sp_add_jobschedule 
  18411.       @job_name = @restore_job_name, 
  18412.       @freq_type = 4, 
  18413.       @freq_interval = 1, 
  18414.       @freq_subday_type = 0x4, 
  18415.       @freq_subday_interval = 1, -- run every minute
  18416.       @freq_relative_interval = 0, 
  18417.       @name = @restore_job_name
  18418.     IF (@@error <> 0 OR @rv <> 0) GOTO rollback_quit -- error
  18419.  
  18420.     EXECUTE @rv = msdb.dbo.sp_add_jobserver @job_name = @restore_job_name, @server_name = NULL
  18421.     IF (@@error <> 0 OR @rv <> 0) GOTO rollback_quit -- error
  18422.   END
  18423.   COMMIT TRANSACTION
  18424.   RETURN
  18425.  
  18426. rollback_quit:
  18427.   ROLLBACK TRANSACTION
  18428. END
  18429. go
  18430.  
  18431. /**************************************************************/
  18432. /* sp_add_log_shipping_primary                                */
  18433. /**************************************************************/
  18434. PRINT ''
  18435. PRINT 'Creating procedure sp_add_log_shipping_primary...'
  18436. go
  18437. IF (EXISTS (SELECT * from msdb.dbo.sysobjects WHERE name = N'sp_add_log_shipping_primary' AND type = N'P'))
  18438.   drop procedure sp_add_log_shipping_primary
  18439. go
  18440. CREATE PROCEDURE sp_add_log_shipping_primary
  18441.   @primary_server_name         sysname,
  18442.   @primary_database_name       sysname,
  18443.   @maintenance_plan_id         UNIQUEIDENTIFIER = NULL,
  18444.   @backup_threshold            INT              = 60,
  18445.   @threshold_alert             INT              = 14420,
  18446.   @threshold_alert_enabled     BIT              = 1,
  18447.   @planned_outage_start_time   INT              = 0,
  18448.   @planned_outage_end_time     INT              = 0,
  18449.   @planned_outage_weekday_mask INT              = 0,
  18450.   @primary_id                   INT = NULL OUTPUT       
  18451. AS
  18452. BEGIN
  18453.   SET NOCOUNT ON
  18454.   IF EXISTS (SELECT * FROM msdb.dbo.log_shipping_primaries WHERE primary_server_name = @primary_server_name AND primary_database_name = @primary_database_name)
  18455.   BEGIN  
  18456.     DECLARE @pair_name NVARCHAR 
  18457.     SELECT @pair_name = @primary_server_name + N'.' + @primary_database_name
  18458.     RAISERROR (14261,16,1, N'primary_server_name.primary_database_name', @pair_name)
  18459.     RETURN (1) -- error
  18460.   END
  18461.   INSERT INTO msdb.dbo.log_shipping_primaries (
  18462.     primary_server_name,
  18463.     primary_database_name,
  18464.     maintenance_plan_id,
  18465.     backup_threshold,
  18466.     threshold_alert,
  18467.     threshold_alert_enabled,
  18468.     last_backup_filename,
  18469.     last_updated,
  18470.     planned_outage_start_time,
  18471.     planned_outage_end_time,
  18472.     planned_outage_weekday_mask,
  18473.     source_directory)  
  18474.   VALUES (@primary_server_name,  
  18475.     @primary_database_name, 
  18476.     @maintenance_plan_id, 
  18477.     @backup_threshold,
  18478.     @threshold_alert,
  18479.     @threshold_alert_enabled,
  18480.     N'first_file_000000000000.trn',
  18481.     GETDATE (),
  18482.     @planned_outage_start_time,
  18483.     @planned_outage_end_time,
  18484.     @planned_outage_weekday_mask,
  18485.     NULL)
  18486.  
  18487.   SELECT @primary_id = @@IDENTITY
  18488.  
  18489.   EXECUTE msdb.dbo.sp_add_log_shipping_monitor_jobs
  18490. END
  18491. go
  18492.  
  18493. /**************************************************************/
  18494. /* sp_add_log_shipping_secondary                              */
  18495. /**************************************************************/
  18496. PRINT ''
  18497. PRINT 'Creating procedure sp_add_log_shipping_secondary...'
  18498. go
  18499. IF (EXISTS (SELECT * from msdb.dbo.sysobjects WHERE name = N'sp_add_log_shipping_secondary' AND type = N'P'))
  18500.   drop procedure sp_add_log_shipping_secondary
  18501. go
  18502. CREATE PROCEDURE sp_add_log_shipping_secondary
  18503.   @primary_id                  INT,
  18504.   @secondary_server_name       sysname,
  18505.   @secondary_database_name     sysname,
  18506.   @secondary_plan_id           UNIQUEIDENTIFIER,
  18507.   @copy_enabled                BIT              = 1,
  18508.   @load_enabled                BIT              = 1,
  18509.   @out_of_sync_threshold       INT              = 60,
  18510.   @threshold_alert             INT              = 14421,
  18511.   @threshold_alert_enabled     BIT              = 1,
  18512.   @planned_outage_start_time   INT              = 0,
  18513.   @planned_outage_end_time     INT              = 0,
  18514.   @planned_outage_weekday_mask INT              = 0,
  18515.   @allow_role_change           BIT              = 0 
  18516. AS
  18517. BEGIN
  18518.   SET NOCOUNT ON
  18519.   IF NOT EXISTS (SELECT * FROM msdb.dbo.log_shipping_primaries where primary_id = @primary_id)
  18520.   BEGIN
  18521.     RAISERROR (14262, 16, 1, N'primary_id', N'msdb.dbo.log_shipping_primaries')
  18522.     RETURN(1)
  18523.   END
  18524.  
  18525.   INSERT INTO msdb.dbo.log_shipping_secondaries (
  18526.     primary_id,
  18527.     secondary_server_name,
  18528.     secondary_database_name,
  18529.     last_copied_filename,
  18530.     last_loaded_filename,
  18531.     last_copied_last_updated,
  18532.     last_loaded_last_updated,
  18533.     secondary_plan_id,
  18534.     copy_enabled,
  18535.     load_enabled,
  18536.     out_of_sync_threshold,
  18537.     threshold_alert,
  18538.     threshold_alert_enabled,
  18539.     planned_outage_start_time,
  18540.     planned_outage_end_time,
  18541.     planned_outage_weekday_mask,
  18542.     allow_role_change)
  18543.    VALUES (@primary_id,
  18544.     @secondary_server_name,
  18545.     @secondary_database_name,
  18546.     N'first_file_000000000000.trn',
  18547.     N'first_file_000000000000.trn',
  18548.     GETDATE (),
  18549.     GETDATE (),
  18550.     @secondary_plan_id,
  18551.     @copy_enabled,
  18552.     @load_enabled,
  18553.     @out_of_sync_threshold,
  18554.     @threshold_alert,
  18555.     @threshold_alert_enabled,
  18556.     @planned_outage_start_time,
  18557.     @planned_outage_end_time,
  18558.     @planned_outage_weekday_mask,
  18559.     @allow_role_change)
  18560. END
  18561. go
  18562.  
  18563. /**************************************************************/
  18564. /* sp_delete_log_shipping_monitor_jobs                        */
  18565. /**************************************************************/
  18566. PRINT ''
  18567. PRINT 'Creating procedure sp_delete_log_shipping_monitor_jobs...'
  18568. go
  18569. IF (EXISTS (SELECT * from msdb.dbo.sysobjects WHERE name = N'sp_delete_log_shipping_monitor_jobs' AND type = N'P')  )
  18570.   drop procedure sp_delete_log_shipping_monitor_jobs
  18571. go
  18572. CREATE PROCEDURE sp_delete_log_shipping_monitor_jobs AS
  18573. BEGIN
  18574.   DECLARE @backup_job_name sysname
  18575.   SET NOCOUNT ON
  18576.   SET @backup_job_name = N'Log Shipping Alert Job - Backup'
  18577.   IF (EXISTS (SELECT * FROM msdb.dbo.sysjobs WHERE name = @backup_job_name))
  18578.     EXECUTE msdb.dbo.sp_delete_job @job_name = N'Log Shipping Alert Job - Backup'
  18579.  
  18580.   DECLARE @restore_job_name sysname
  18581.   SET @restore_job_name = 'Log Shipping Alert Job - Restore'
  18582.   IF (EXISTS (SELECT * FROM msdb.dbo.sysjobs WHERE name = @restore_job_name))
  18583.     EXECUTE msdb.dbo.sp_delete_job @job_name = N'Log Shipping Alert Job - Restore'
  18584. END
  18585. go
  18586.  
  18587. /**************************************************************/
  18588. /* sp_delete_log_shipping_primary                             */
  18589. /**************************************************************/
  18590. PRINT ''
  18591. PRINT 'Creating procedure sp_delete_log_shipping_primary...'
  18592. go
  18593. IF (EXISTS (SELECT * from msdb.dbo.sysobjects WHERE name = N'sp_delete_log_shipping_primary' AND type = N'P')  )
  18594.   drop procedure sp_delete_log_shipping_primary
  18595. go
  18596. CREATE PROCEDURE sp_delete_log_shipping_primary 
  18597.   @primary_server_name sysname,
  18598.   @primary_database_name sysname,
  18599.   @delete_secondaries BIT = 0
  18600. AS BEGIN
  18601.   DECLARE @primary_id INT
  18602.  
  18603.   SET NOCOUNT ON
  18604.  
  18605.   SELECT @primary_id = primary_id 
  18606.     FROM msdb.dbo.log_shipping_primaries 
  18607.     WHERE primary_server_name = @primary_server_name AND primary_database_name = @primary_database_name
  18608.   IF (@primary_id IS NULL)
  18609.     RETURN (0)
  18610.  
  18611.   BEGIN TRANSACTION
  18612.   IF (EXISTS (SELECT * FROM msdb.dbo.log_shipping_secondaries WHERE primary_id = @primary_id))
  18613.   BEGIN
  18614.     IF (@delete_secondaries = 0)
  18615.     BEGIN
  18616.       RAISERROR (14429,-1,-1)
  18617.       goto rollback_quit
  18618.     END
  18619.     DELETE FROM msdb.dbo.log_shipping_secondaries WHERE primary_id = @primary_id
  18620.     IF (@@ERROR <> 0)
  18621.       GOTO rollback_quit
  18622.   END
  18623.   DELETE FROM msdb.dbo.log_shipping_primaries WHERE primary_id = @primary_id
  18624.   IF (@@ERROR <> 0)
  18625.     GOTO rollback_quit
  18626.  
  18627.   COMMIT TRANSACTION
  18628.   DECLARE @i INT
  18629.   SELECT @i = COUNT(*) FROM msdb.dbo.log_shipping_primaries
  18630.   IF (@i=0)
  18631.     EXECUTE msdb.dbo.sp_delete_log_shipping_monitor_jobs
  18632.   RETURN (0)
  18633.  
  18634. rollback_quit:
  18635.   ROLLBACK TRANSACTION
  18636.   RETURN(1) -- error
  18637. END
  18638. go
  18639.  
  18640. /**************************************************************/
  18641. /* sp_delete_log_shipping_secondary                           */
  18642. /**************************************************************/
  18643. PRINT ''
  18644. PRINT 'Creating sp_delete_log_shipping_secondary...'
  18645. go
  18646. IF (EXISTS (SELECT * from msdb.dbo.sysobjects WHERE name = N'sp_delete_log_shipping_secondary' AND type = N'P')  )
  18647.   drop procedure sp_delete_log_shipping_secondary
  18648. go
  18649. CREATE PROCEDURE sp_delete_log_shipping_secondary 
  18650.   @secondary_server_name   sysname,
  18651.   @secondary_database_name sysname
  18652. AS BEGIN
  18653.   SET NOCOUNT ON
  18654.   DELETE FROM msdb.dbo.log_shipping_secondaries WHERE 
  18655.     secondary_server_name   = @secondary_server_name AND
  18656.     secondary_database_name = @secondary_database_name
  18657. END
  18658. go
  18659.  
  18660. /**************************************************************/
  18661. /* sp_log_shipping_in_sync                                    */
  18662. /**************************************************************/
  18663. PRINT ''
  18664. PRINT 'Creating procedure sp_log_shipping_in_sync...'
  18665. go
  18666. IF (EXISTS (SELECT * from msdb.dbo.sysobjects WHERE name = N'sp_log_shipping_in_sync' AND type = N'P')  )
  18667.   drop procedure sp_log_shipping_in_sync
  18668. go
  18669. CREATE PROCEDURE sp_log_shipping_in_sync
  18670.   @last_updated        DATETIME,
  18671.   @compare_with        DATETIME,
  18672.   @threshold           INT,
  18673.   @outage_start_time   INT,
  18674.   @outage_end_time     INT,
  18675.   @outage_weekday_mask INT,
  18676.   @enabled             BIT = 1,
  18677.   @delta               INT = NULL OUTPUT
  18678. AS BEGIN
  18679.   SET NOCOUNT ON
  18680.   DECLARE @cur_time INT
  18681.  
  18682.   SELECT @delta = DATEDIFF (mi, @last_updated, @compare_with)
  18683.   -- in sync
  18684.   IF (@delta <= @threshold)
  18685.     RETURN (0) -- in sync
  18686.  
  18687.   IF (@enabled = 0) 
  18688.     RETURN(0) -- in sync
  18689.  
  18690.   IF (@outage_weekday_mask & DATEPART(dw, GETDATE ()) > 0) -- potentially in outage window
  18691.   BEGIN
  18692.     SELECT @cur_time = DATEPART (hh, GETDATE()) * 10000 +
  18693.                        DATEPART (mi, GETDATE()) * 100 + 
  18694.                        DATEPART (ss, GETDATE())
  18695.       -- outage doesn't span midnight
  18696.     IF (@outage_start_time < @outage_end_time)
  18697.     BEGIN
  18698.       IF (@cur_time >= @outage_start_time AND @cur_time < @outage_end_time)
  18699.         RETURN(1) -- in outage
  18700.     END
  18701.       -- outage does span midnight
  18702.     ELSE IF (@outage_start_time > @outage_end_time)
  18703.     BEGIN
  18704.       IF (@cur_time >= @outage_start_time OR @cur_time < @outage_end_time)
  18705.         RETURN(1) -- in outage
  18706.     END
  18707.   END
  18708.   RETURN(-1 ) -- not in outage, not in sync
  18709. END
  18710. go
  18711.  
  18712. /**************************************************************/
  18713. /* sp_log_shipping_get_date_from_file                         */
  18714. /**************************************************************/
  18715. PRINT ''
  18716. PRINT 'Creating procedure sp_log_shipping_get_date_from_file...'
  18717. go
  18718. IF (EXISTS (SELECT * from msdb.dbo.sysobjects WHERE name = N'sp_log_shipping_get_date_from_file' AND type = N'P')  )
  18719.   drop procedure sp_log_shipping_get_date_from_file
  18720. go
  18721. CREATE PROCEDURE sp_log_shipping_get_date_from_file 
  18722.   @db_name sysname,
  18723.   @filename NVARCHAR (500),
  18724.   @file_date DATETIME OUTPUT
  18725. AS
  18726. BEGIN
  18727.   SET NOCOUNT ON
  18728.  
  18729.   DECLARE @tempname NVARCHAR (500)
  18730.   IF (LEN (@filename) - (LEN(@db_name) + LEN ('_tlog_')) <= 0)
  18731.     RETURN(1) -- filename string isn't long enough
  18732.   SELECT @tempname = RIGHT (@filename, LEN (@filename) - (LEN(@db_name) + LEN ('_tlog_')))
  18733.   IF (CHARINDEX ('.',@tempname,0) > 0)
  18734.     SELECT @tempname = LEFT (@tempname, CHARINDEX ('.',@tempname,0) - 1)
  18735.   IF (LEN (@tempname) <>  8 AND LEN (@tempname) <> 12)
  18736.     RETURN (1) -- error must be yyyymmddhhmm or yyyymmdd
  18737.   IF (ISNUMERIC (@tempname) = 0 OR CHARINDEX ('.',@tempname,0) <> 0 OR CONVERT (FLOAT,SUBSTRING (@tempname, 1,8)) < 1 )
  18738.     RETURN (1) -- must be numeric, can't contain any '.' etc
  18739.   SELECT @file_date = CONVERT (DATETIME,SUBSTRING (@tempname, 1,8),112)
  18740.   IF (LEN (@tempname) = 12)
  18741.   BEGIN
  18742.     SELECT @file_date = DATEADD (hh, CONVERT (INT, SUBSTRING (@tempname,9,2)),@file_date)
  18743.     SELECT @file_date = DATEADD (mi, CONVERT (INT, SUBSTRING (@tempname,11,2)),@file_date)
  18744.   END
  18745.   RETURN (0) -- success
  18746. END
  18747. go
  18748.  
  18749. /**************************************************************/
  18750. /* sp_get_log_shipping_monitor_info                           */
  18751. /**************************************************************/
  18752. PRINT ''
  18753. PRINT 'Creating procedure sp_get_log_shipping_monitor_info...'
  18754. go
  18755. IF (EXISTS (SELECT * from msdb.dbo.sysobjects WHERE name = N'sp_get_log_shipping_monitor_info' AND type = N'P')  )
  18756.   drop procedure sp_get_log_shipping_monitor_info
  18757. go
  18758. CREATE PROCEDURE sp_get_log_shipping_monitor_info
  18759.   @primary_server_name     sysname = N'%',
  18760.   @primary_database_name   sysname = N'%',
  18761.   @secondary_server_name   sysname = N'%',
  18762.   @secondary_database_name sysname = N'%'
  18763. AS BEGIN
  18764.   SET NOCOUNT ON
  18765.   CREATE TABLE #lsp (
  18766.     primary_server_name            sysname       COLLATE database_default NOT NULL,
  18767.     primary_database_name          sysname       COLLATE database_default NOT NULL,
  18768.     secondary_server_name          sysname       COLLATE database_default NOT NULL,
  18769.     secondary_database_name        sysname       COLLATE database_default NOT NULL,
  18770.     backup_threshold               INT           NOT NULL,
  18771.     backup_threshold_alert         INT           NOT NULL,
  18772.     backup_threshold_alert_enabled BIT           NOT NULL,
  18773.     last_backup_filename           NVARCHAR(500) COLLATE database_default NOT NULL,
  18774.     last_backup_last_updated       DATETIME      NOT NULL,
  18775.     backup_outage_start_time       INT           NOT NULL,
  18776.     backup_outage_end_time         INT           NOT NULL,
  18777.     backup_outage_weekday_mask     INT           NOT NULL,
  18778.     backup_in_sync                 INT           NULL, -- 0 = in sync, -1 = out of sync, 1 = in outage window
  18779.     backup_delta                   INT           NULL,
  18780.     last_copied_filename           NVARCHAR(500) COLLATE database_default NOT NULL,
  18781.     last_copied_last_updated       DATETIME      NOT NULL,
  18782.     last_loaded_filename           NVARCHAR(500) COLLATE database_default NOT NULL,
  18783.     last_loaded_last_updated       DATETIME      NOT NULL,
  18784.     copy_delta                     INT           NULL,
  18785.     copy_enabled                   BIT           NOT NULL,
  18786.     load_enabled                   BIT           NOT NULL,
  18787.     out_of_sync_threshold          INT           NOT NULL,
  18788.     load_threshold_alert           INT           NOT NULL,
  18789.     load_threshold_alert_enabled   BIT           NOT NULL,
  18790.     load_outage_start_time         INT           NOT NULL,
  18791.     load_outage_end_time           INT           NOT NULL,
  18792.     load_outage_weekday_mask       INT           NOT NULL,
  18793.     load_in_sync                   INT           NULL, -- 0 = in sync, -1 = out of sync, 1 = in outage window
  18794.     load_delta                     INT           NULL,
  18795.     maintenance_plan_id                 UNIQUEIDENTIFIER NULL,
  18796.     secondary_plan_id              UNIQUEIDENTIFIER NOT NULL)
  18797.  
  18798.   INSERT INTO #lsp
  18799.  
  18800.  SELECT
  18801.     primary_server_name,
  18802.     primary_database_name,
  18803.     secondary_server_name,
  18804.     secondary_database_name,
  18805.     backup_threshold,
  18806.     p.threshold_alert,
  18807.     p.threshold_alert_enabled,
  18808.     last_backup_filename,
  18809.     p.last_updated,
  18810.     p.planned_outage_start_time,
  18811.     p.planned_outage_end_time,
  18812.     p.planned_outage_weekday_mask,
  18813.     NULL,
  18814.     NULL,
  18815.     last_copied_filename,
  18816.     last_copied_last_updated,
  18817.     last_loaded_filename,
  18818.     last_loaded_last_updated,
  18819.     NULL,
  18820.     copy_enabled,
  18821.     load_enabled,
  18822.     out_of_sync_threshold,
  18823.     s.threshold_alert,
  18824.     s.threshold_alert_enabled,
  18825.     s.planned_outage_start_time,
  18826.     s.planned_outage_weekday_mask,
  18827.     s.planned_outage_end_time,
  18828.     NULL,
  18829.     NULL,
  18830.     maintenance_plan_id,
  18831.     secondary_plan_id
  18832.   FROM msdb.dbo.log_shipping_primaries p, msdb.dbo.log_shipping_secondaries s
  18833.   WHERE 
  18834.     p.primary_id = s.primary_id AND
  18835.     primary_server_name LIKE @primary_server_name AND
  18836.     primary_database_name LIKE @primary_database_name AND
  18837.     secondary_server_name LIKE @secondary_server_name AND
  18838.     secondary_database_name LIKE @secondary_database_name
  18839.  
  18840.   DECLARE @load_in_sync                   INT
  18841.   DECLARE @backup_in_sync                 INT
  18842.   DECLARE @_primary_server_name           sysname 
  18843.   DECLARE @_primary_database_name         sysname 
  18844.   DECLARE @_secondary_server_name         sysname
  18845.   DECLARE @_secondary_database_name       sysname
  18846.   DECLARE @last_loaded_last_updated       DATETIME
  18847.   DECLARE @last_loaded_filename           NVARCHAR (500)
  18848.   DECLARE @last_copied_filename           NVARCHAR (500)
  18849.   DECLARE @last_backup_last_updated       DATETIME
  18850.   DECLARE @last_backup_filename           NVARCHAR (500)
  18851.   DECLARE @backup_outage_start_time       INT
  18852.   DECLARE @backup_outage_end_time         INT
  18853.   DECLARE @backup_outage_weekday_mask     INT
  18854.   DECLARE @backup_threshold               INT
  18855.   DECLARE @backup_threshold_alert_enabled BIT
  18856.   DECLARE @load_outage_start_time         INT
  18857.   DECLARE @load_outage_end_time           INT
  18858.   DECLARE @load_outage_weekday_mask       INT
  18859.   DECLARE @load_threshold                 INT
  18860.   DECLARE @load_threshold_alert_enabled   BIT
  18861.   DECLARE @backupdt                       DATETIME
  18862.   DECLARE @restoredt                      DATETIME
  18863.   DECLARE @copydt                         DATETIME
  18864.   DECLARE @rv                             INT
  18865.   DECLARE @dt                             DATETIME
  18866.   DECLARE @copy_delta                     INT
  18867.   DECLARE @load_delta                     INT
  18868.   DECLARE @backup_delta                   INT
  18869.   DECLARE @last_copied_last_updated       DATETIME
  18870.  
  18871.   SELECT @dt = GETDATE ()
  18872.  
  18873.   DECLARE sync_update CURSOR FOR
  18874.     SELECT 
  18875.       primary_server_name, 
  18876.       primary_database_name, 
  18877.       secondary_server_name, 
  18878.       secondary_database_name,
  18879.       last_backup_filename,
  18880.       last_backup_last_updated,
  18881.       last_loaded_filename,
  18882.       last_loaded_last_updated,
  18883.       backup_outage_start_time,
  18884.       backup_outage_end_time,
  18885.       backup_outage_weekday_mask,
  18886.       backup_threshold,
  18887.       backup_threshold_alert_enabled,
  18888.       load_outage_start_time,
  18889.       load_outage_end_time,
  18890.       out_of_sync_threshold,
  18891.       load_outage_weekday_mask,
  18892.       load_threshold_alert_enabled,
  18893.       last_copied_filename,
  18894.       last_copied_last_updated
  18895.     FROM #lsp
  18896.     FOR READ ONLY
  18897.  
  18898.   OPEN sync_update
  18899.  
  18900. loop:
  18901.   FETCH NEXT FROM sync_update INTO
  18902.     @_primary_server_name, 
  18903.     @_primary_database_name, 
  18904.     @_secondary_server_name, 
  18905.     @_secondary_database_name,
  18906.     @last_backup_filename,
  18907.     @last_backup_last_updated,
  18908.     @last_loaded_filename,
  18909.     @last_loaded_last_updated,
  18910.     @backup_outage_start_time,
  18911.     @backup_outage_end_time,
  18912.     @backup_outage_weekday_mask,
  18913.     @backup_threshold,
  18914.     @backup_threshold_alert_enabled,
  18915.     @load_outage_start_time,
  18916.     @load_outage_end_time,
  18917.     @load_threshold,
  18918.     @load_outage_weekday_mask,
  18919.     @load_threshold_alert_enabled,
  18920.     @last_copied_filename,
  18921.     @last_copied_last_updated
  18922.  
  18923.   IF @@fetch_status <> 0
  18924.     GOTO _loop
  18925.  
  18926.   EXECUTE @rv = sp_log_shipping_get_date_from_file @_primary_database_name, @last_backup_filename, @backupdt OUTPUT
  18927.   IF (@rv <> 0)
  18928.     SElECT @backupdt = @last_backup_last_updated
  18929.   EXECUTE @rv = sp_log_shipping_get_date_from_file @_primary_database_name, @last_loaded_filename, @restoredt OUTPUT
  18930.   IF  (@rv <> 0)
  18931.     SElECT @restoredt = @last_loaded_last_updated
  18932.   EXECUTE @rv = sp_log_shipping_get_date_from_file @_primary_database_name, @last_copied_filename, @copydt OUTPUT
  18933.   IF  (@rv <> 0)
  18934.     SElECT @copydt = @last_copied_last_updated
  18935.   
  18936.   EXECUTE @load_in_sync = msdb.dbo.sp_log_shipping_in_sync
  18937.     @restoredt,
  18938.     @backupdt,
  18939.     @load_threshold,
  18940.     @load_outage_start_time,
  18941.     @load_outage_end_time,
  18942.     @load_outage_weekday_mask,
  18943.     @load_threshold_alert_enabled,
  18944.     @load_delta OUTPUT
  18945.  
  18946.   EXECUTE @backup_in_sync = msdb.dbo.sp_log_shipping_in_sync
  18947.     @last_backup_last_updated,
  18948.     @dt,
  18949.     @backup_threshold,
  18950.     @backup_outage_start_time,
  18951.     @backup_outage_end_time,
  18952.     @backup_outage_weekday_mask,
  18953.     @backup_threshold_alert_enabled,
  18954.     @backup_delta OUTPUT
  18955.  
  18956.   EXECUTE msdb.dbo.sp_log_shipping_in_sync
  18957.     @copydt,
  18958.     @backupdt,
  18959.     1,0,0,0,0,
  18960.     @copy_delta OUTPUT
  18961.  
  18962.   UPDATE #lsp 
  18963.   SET backup_in_sync = @backup_in_sync, load_in_sync  = @load_in_sync, 
  18964.     copy_delta = @copy_delta, load_delta = @load_delta, backup_delta = @backup_delta
  18965.   WHERE primary_server_name = @_primary_server_name AND
  18966.     secondary_server_name = @_secondary_server_name AND
  18967.     primary_database_name = @_primary_database_name AND
  18968.     secondary_database_name = @_secondary_database_name 
  18969.   GOTO loop
  18970. _loop:
  18971.   CLOSE sync_update
  18972.   DEALLOCATE sync_update
  18973.   SELECT * FROM #lsp
  18974. END
  18975. go
  18976.  
  18977. /**************************************************************/
  18978. /* sp_update_log_shipping_monitor_info                        */
  18979. /**************************************************************/
  18980. PRINT ''
  18981. PRINT 'Creating procedure sp_update_log_shipping_monitor_info...'
  18982. go
  18983. IF (EXISTS (SELECT * from msdb.dbo.sysobjects WHERE name = N'sp_update_log_shipping_monitor_info' AND type = N'P')  )
  18984.   DROP PROCEDURE sp_update_log_shipping_monitor_info
  18985. go
  18986. CREATE PROCEDURE sp_update_log_shipping_monitor_info
  18987.   @primary_server_name                 sysname,
  18988.   @primary_database_name               sysname,
  18989.   @secondary_server_name               sysname,
  18990.   @secondary_database_name             sysname,
  18991.   @backup_threshold                    INT = NULL,
  18992.   @backup_threshold_alert              INT = NULL,
  18993.   @backup_threshold_alert_enabled      BIT = NULL,
  18994.   @backup_outage_start_time            INT = NULL,
  18995.   @backup_outage_end_time              INT = NULL,
  18996.   @backup_outage_weekday_mask          INT = NULL,
  18997.   @copy_enabled                        BIT = NULL,
  18998.   @load_enabled                        BIT = NULL,
  18999.   @out_of_sync_threshold               INT = NULL,
  19000.   @out_of_sync_threshold_alert         INT = NULL,
  19001.   @out_of_sync_threshold_alert_enabled BIT = NULL,
  19002.   @out_of_sync_outage_start_time       INT = NULL,
  19003.   @out_of_sync_outage_end_time         INT = NULL,
  19004.   @out_of_sync_outage_weekday_mask     INT = NULL
  19005. AS BEGIN
  19006.   SET NOCOUNT ON
  19007.   DECLARE @_backup_threshold                    INT
  19008.   DECLARE @_backup_threshold_alert              INT
  19009.   DECLARE @_backup_threshold_alert_enabled      BIT
  19010.   DECLARE @_backup_outage_start_time            INT
  19011.   DECLARE @_backup_outage_end_time              INT
  19012.   DECLARE @_backup_outage_weekday_mask          INT
  19013.   DECLARE @_copy_enabled                        BIT
  19014.   DECLARE @_load_enabled                        BIT
  19015.   DECLARE @_out_of_sync_threshold               INT
  19016.   DECLARE @_out_of_sync_threshold_alert         INT
  19017.   DECLARE @_out_of_sync_threshold_alert_enabled BIT
  19018.   DECLARE @_out_of_sync_outage_start_time       INT
  19019.   DECLARE @_out_of_sync_outage_end_time         INT
  19020.   DECLARE @_out_of_sync_outage_weekday_mask     INT
  19021.  
  19022.   -- check that the primary exists
  19023.   IF (NOT EXISTS (SELECT * FROM msdb.dbo.log_shipping_primaries WHERE primary_server_name = @primary_server_name AND primary_database_name = @primary_database_name))
  19024.   BEGIN
  19025.     DECLARE @pp sysname
  19026.     SELECT @pp = @primary_server_name + N'.' + @primary_database_name
  19027.     RAISERROR (14262, 16, 1, N'primary_server_name.primary_database_name', @pp)
  19028.     RETURN (1) -- error
  19029.   END
  19030.  
  19031.   -- check that the secondary exists
  19032.   IF (NOT EXISTS (SELECT * FROM msdb.dbo.log_shipping_secondaries WHERE secondary_server_name = @secondary_server_name AND secondary_database_name = @secondary_database_name))
  19033.   BEGIN
  19034.     DECLARE @sp sysname
  19035.     SELECT @sp = @secondary_server_name + N'.' + @secondary_database_name
  19036.     RAISERROR (14262, 16, 1, N'secondary_server_name.secondary_database_name', @sp)
  19037.     RETURN (1) -- error
  19038.   END
  19039.  
  19040.   -- load the original variables
  19041.  
  19042.  SELECT
  19043.     @_backup_threshold                    = backup_threshold,
  19044.     @_backup_threshold_alert              = p.threshold_alert,
  19045.     @_backup_threshold_alert_enabled      = p.threshold_alert_enabled,
  19046.     @_backup_outage_start_time            = p.planned_outage_start_time,
  19047.     @_backup_outage_end_time              = p.planned_outage_end_time,
  19048.     @_backup_outage_weekday_mask          = p.planned_outage_weekday_mask,
  19049.     @_copy_enabled                        = copy_enabled,
  19050.     @_load_enabled                        = load_enabled,
  19051.     @_out_of_sync_threshold               = out_of_sync_threshold,
  19052.     @_out_of_sync_threshold_alert         = s.threshold_alert,
  19053.     @_out_of_sync_threshold_alert_enabled = s.threshold_alert_enabled,
  19054.     @_out_of_sync_outage_start_time       = s.planned_outage_start_time,
  19055.     @_out_of_sync_outage_weekday_mask     = s.planned_outage_weekday_mask,
  19056.     @_out_of_sync_outage_end_time         = s.planned_outage_end_time
  19057.   FROM msdb.dbo.log_shipping_primaries p, msdb.dbo.log_shipping_secondaries s
  19058.   WHERE 
  19059.     p.primary_id            = s.primary_id           AND
  19060.     primary_server_name     = @primary_server_name   AND
  19061.     primary_database_name   = @primary_database_name AND
  19062.     secondary_server_name   = @secondary_server_name AND
  19063.     secondary_database_name = @secondary_database_name
  19064.  
  19065.   SELECT @_backup_threshold                    = ISNULL (@backup_threshold,                    @_backup_threshold)
  19066.   SELECT @_backup_threshold_alert              = ISNULL (@backup_threshold_alert,              @_backup_threshold_alert)
  19067.   SELECT @_backup_threshold_alert_enabled      = ISNULL (@backup_threshold_alert_enabled,      @_backup_threshold_alert_enabled)
  19068.   SELECT @_backup_outage_start_time            = ISNULL (@backup_outage_start_time,            @_backup_outage_start_time)
  19069.   SELECT @_backup_outage_end_time              = ISNULL (@backup_outage_end_time,              @_backup_outage_end_time)
  19070.   SELECT @_backup_outage_weekday_mask          = ISNULL (@backup_outage_weekday_mask,          @_backup_outage_weekday_mask)
  19071.   SELECT @_copy_enabled                        = ISNULL (@copy_enabled,                        @_copy_enabled)
  19072.   SELECT @_load_enabled                        = ISNULL (@load_enabled,                        @_load_enabled)
  19073.   SELECT @_out_of_sync_threshold               = ISNULL (@out_of_sync_threshold,               @_out_of_sync_threshold)
  19074.   SELECT @_out_of_sync_threshold_alert         = ISNULL (@out_of_sync_threshold_alert,         @_out_of_sync_threshold_alert)
  19075.   SELECT @_out_of_sync_threshold_alert_enabled = ISNULL (@out_of_sync_threshold_alert_enabled, @_out_of_sync_threshold_alert_enabled)
  19076.   SELECT @_out_of_sync_outage_start_time       = ISNULL (@out_of_sync_outage_start_time,       @_out_of_sync_outage_start_time)
  19077.   SELECT @_out_of_sync_outage_end_time         = ISNULL (@out_of_sync_outage_end_time,         @_out_of_sync_outage_end_time)
  19078.   SELECT @_out_of_sync_outage_weekday_mask     = ISNULL (@out_of_sync_outage_weekday_mask,     @_out_of_sync_outage_weekday_mask)
  19079.  
  19080.   -- updates
  19081.   UPDATE msdb.dbo.log_shipping_primaries SET
  19082.     backup_threshold            = @_backup_threshold,
  19083.     threshold_alert             = @_backup_threshold_alert,
  19084.     threshold_alert_enabled     = @_backup_threshold_alert_enabled,
  19085.     planned_outage_start_time   = @_backup_outage_start_time,
  19086.     planned_outage_end_time     = @_backup_outage_end_time,
  19087.     planned_outage_weekday_mask = @_backup_outage_weekday_mask
  19088.   WHERE primary_server_name = @primary_server_name AND primary_database_name = @primary_database_name
  19089.  
  19090.   UPDATE msdb.dbo.log_shipping_secondaries SET
  19091.     copy_enabled                = @_copy_enabled,
  19092.     load_enabled                = @_load_enabled,
  19093.     out_of_sync_threshold       = @_out_of_sync_threshold,
  19094.     threshold_alert             = @_out_of_sync_threshold_alert,
  19095.     threshold_alert_enabled     = @_out_of_sync_threshold_alert_enabled,
  19096.     planned_outage_start_time   = @_out_of_sync_outage_start_time,
  19097.     planned_outage_end_time     = @_out_of_sync_outage_weekday_mask,
  19098.     planned_outage_weekday_mask = @_out_of_sync_outage_end_time
  19099.   WHERE secondary_server_name = @secondary_server_name AND secondary_database_name = @secondary_database_name
  19100. RETURN(0)
  19101. END
  19102. go
  19103.  
  19104. /**************************************************************/
  19105. /* sp_delete_log_shipping_monitor_info                        */
  19106. /**************************************************************/
  19107. PRINT ''
  19108. PRINT 'Creating procedure sp_delete_log_shipping_monitor_info...'
  19109. go
  19110. IF (EXISTS (SELECT * from msdb.dbo.sysobjects WHERE name = N'sp_delete_log_shipping_monitor_info' AND type = N'P')  )
  19111.   DROP PROCEDURE sp_delete_log_shipping_monitor_info
  19112. go
  19113. CREATE PROCEDURE sp_delete_log_shipping_monitor_info
  19114.   @primary_server_name                 sysname,
  19115.   @primary_database_name               sysname,
  19116.   @secondary_server_name               sysname,
  19117.   @secondary_database_name             sysname
  19118. AS BEGIN
  19119.   -- check that the primary exists
  19120.   IF (NOT EXISTS (SELECT * FROM msdb.dbo.log_shipping_primaries WHERE primary_server_name = @primary_server_name AND primary_database_name = @primary_database_name))
  19121.   BEGIN
  19122.     DECLARE @pp sysname
  19123.     SELECT @pp = @primary_server_name + N'.' + @primary_database_name
  19124.     RAISERROR (14262, 16, 1, N'primary_server_name.primary_database_name', @pp)
  19125.     RETURN (1) -- error
  19126.   END
  19127.  
  19128.   -- check that the secondary exists
  19129.   IF (NOT EXISTS (SELECT * FROM msdb.dbo.log_shipping_secondaries WHERE secondary_server_name = @secondary_server_name AND secondary_database_name = @secondary_database_name))
  19130.   BEGIN
  19131.     DECLARE @sp sysname
  19132.     SELECT @sp = @secondary_server_name + N'.' + @secondary_database_name
  19133.     RAISERROR (14262, 16, 1, N'secondary_server_name.secondary_database_name', @sp)
  19134.     RETURN (1) -- error
  19135.   END
  19136.  
  19137.   BEGIN TRANSACTION
  19138.  
  19139.   -- delete the secondary
  19140.   DELETE FROM msdb.dbo.log_shipping_secondaries WHERE secondary_server_name = @secondary_server_name AND secondary_database_name = @secondary_database_name
  19141.   IF (@@error <> 0)
  19142.     goto rollback_quit
  19143.  
  19144.   -- if there are no more secondaries for this primary then delete it
  19145.   IF (NOT EXISTS (SELECT * FROM msdb.dbo.log_shipping_primaries p, msdb.dbo.log_shipping_secondaries s WHERE p.primary_id = s.primary_id AND primary_server_name = @primary_server_name AND primary_database_name = @primary_database_name))
  19146.   BEGIN
  19147.     DELETE FROM msdb.dbo.log_shipping_primaries WHERE primary_server_name = @primary_server_name AND primary_database_name = @primary_database_name
  19148.     IF (@@error <> 0)
  19149.       goto rollback_quit
  19150.   END
  19151.  COMMIT TRANSACTION
  19152.  RETURN (0)
  19153.  
  19154. rollback_quit:
  19155.   ROLLBACK TRANSACTION
  19156.   RETURN(1) -- Failure
  19157. END
  19158. go 
  19159.  
  19160. /**************************************************************/
  19161. /* sp_remove_log_shipping_monitor_account                     */
  19162. /**************************************************************/
  19163. PRINT ''
  19164. PRINT 'Creating procedure sp_remove_log_shipping_monitor_account...'
  19165. go
  19166. IF (EXISTS (SELECT * from msdb.dbo.sysobjects WHERE name = N'sp_remove_log_shipping_monitor_account' AND type = N'P')  )
  19167.   DROP PROCEDURE sp_remove_log_shipping_monitor_account
  19168. go
  19169.  
  19170. CREATE PROCEDURE sp_remove_log_shipping_monitor_account
  19171. AS
  19172. BEGIN
  19173.   SET NOCOUNT ON
  19174.   EXECUTE sp_dropuser N'log_shipping_monitor_probe'
  19175.   EXECUTE sp_droplogin N'log_shipping_monitor_probe'
  19176. END
  19177. go
  19178.  
  19179. /**************************************************************/
  19180. /* sp_log_shipping_monitor_backup                             */
  19181. /**************************************************************/
  19182. PRINT ''
  19183. PRINT 'Creating procedure sp_log_shipping_monitor_backup...'
  19184. go
  19185. IF (EXISTS (SELECT * from msdb.dbo.sysobjects WHERE name = N'sp_log_shipping_monitor_backup' AND type = N'P')  )
  19186.   drop procedure sp_log_shipping_monitor_backup
  19187. go
  19188.  
  19189. CREATE PROCEDURE sp_log_shipping_monitor_backup AS
  19190. BEGIN
  19191.   DECLARE @primary_id                  sysname
  19192.   DECLARE @primary_server_name         sysname 
  19193.   DECLARE @primary_database_name       sysname 
  19194.   DECLARE @maintenance_plan_id         UNIQUEIDENTIFIER
  19195.   DECLARE @backup_threshold            INT
  19196.   DECLARE @threshold_alert             INT 
  19197.   DECLARE @threshold_alert_enabled     BIT 
  19198.   DECLARE @last_backup_filename        sysname 
  19199.   DECLARE @last_updated                DATETIME
  19200.   DECLARE @planned_outage_start_time   INT
  19201.   DECLARE @planned_outage_end_time     INT 
  19202.   DECLARE @planned_outage_weekday_mask INT
  19203.   DECLARE @sync_status                 INT
  19204.   DECLARE @backup_delta                INT
  19205.   DECLARE @delta_string                NVARCHAR (10)
  19206.   DECLARE @dt                             DATETIME
  19207.  
  19208.   SELECT @dt = GETDATE ()
  19209.  
  19210.   SET NOCOUNT ON
  19211.  
  19212.   DECLARE bmlsp_cur CURSOR FOR
  19213.     SELECT primary_id, 
  19214.            primary_server_name, 
  19215.            primary_database_name, 
  19216.            maintenance_plan_id, 
  19217.            backup_threshold, 
  19218.            threshold_alert, 
  19219.            threshold_alert_enabled, 
  19220.            last_backup_filename, 
  19221.            last_updated,
  19222.            planned_outage_start_time, 
  19223.            planned_outage_end_time, 
  19224.            planned_outage_weekday_mask 
  19225.     FROM msdb.dbo.log_shipping_primaries
  19226.     FOR READ ONLY
  19227.  
  19228.   OPEN bmlsp_cur
  19229. loop:
  19230.   FETCH NEXT FROM bmlsp_cur 
  19231.   INTO @primary_id, 
  19232.        @primary_server_name, 
  19233.        @primary_database_name, 
  19234.        @maintenance_plan_id,
  19235.        @backup_threshold, 
  19236.        @threshold_alert, 
  19237.        @threshold_alert_enabled, 
  19238.        @last_backup_filename, 
  19239.        @last_updated, 
  19240.          @planned_outage_start_time,
  19241.        @planned_outage_end_time, 
  19242.        @planned_outage_weekday_mask
  19243.  
  19244.   IF @@FETCH_STATUS <> 0 -- nothing more to fetch, finish the loop
  19245.     GOTO _loop
  19246.  
  19247.   EXECUTE @sync_status = sp_log_shipping_in_sync
  19248.     @last_updated,
  19249.     @dt,
  19250.       @backup_threshold,
  19251.       @planned_outage_start_time,
  19252.       @planned_outage_end_time,
  19253.     @planned_outage_weekday_mask,
  19254.       @threshold_alert_enabled,
  19255.       @backup_delta OUTPUT
  19256.  
  19257.    IF (@sync_status < 0)
  19258.    BEGIN
  19259.      SELECT @delta_string = CONVERT (NVARCHAR(10), @backup_delta)
  19260.      RAISERROR (@threshold_alert, 16, 1, @primary_server_name, @primary_database_name, @delta_string)
  19261.    END
  19262.  
  19263.   GOTO loop
  19264. _loop:
  19265.   CLOSE bmlsp_cur
  19266.   DEALLOCATE bmlsp_cur
  19267. END
  19268. go
  19269.  
  19270. /**************************************************************/
  19271. /* sp_log_shipping_monitor_restore                            */
  19272. /**************************************************************/
  19273. PRINT ''
  19274. PRINT 'Creating procedure sp_log_shipping_monitor_restore...'
  19275. go
  19276. IF (EXISTS (SELECT * from msdb.dbo.sysobjects WHERE name = N'sp_log_shipping_monitor_restore' AND type = N'P')  )
  19277.   drop procedure sp_log_shipping_monitor_restore
  19278. go
  19279. CREATE PROCEDURE sp_log_shipping_monitor_restore AS
  19280. BEGIN
  19281.   SET NOCOUNT ON
  19282.   DECLARE @primary_id                  INT
  19283.   DECLARE @secondary_server_name       sysname
  19284.   DECLARE @secondary_database_name     sysname
  19285.   DECLARE @secondary_plan_id           UNIQUEIDENTIFIER
  19286.   DECLARE @out_of_sync_threshold       INT 
  19287.   DECLARE @threshold_alert             INT 
  19288.   DECLARE @threshold_alert_enabled     BIT 
  19289.   DECLARE @last_loaded_filename        NVARCHAR (500)
  19290.   DECLARE @last_backup_filename        NVARCHAR (500) 
  19291.   DECLARE @primary_database_name       sysname
  19292.   DECLARE @last_loaded_last_updated    DATETIME
  19293.   DECLARE @last_backup_last_updated    DATETIME
  19294.   DECLARE @planned_outage_start_time   INT 
  19295.   DECLARE @planned_outage_end_time     INT 
  19296.   DECLARE @planned_outage_weekday_mask INT
  19297.   DECLARE @sync_status                 INT
  19298.   DECLARE @sync_delta                  INT
  19299.   DECLARE @delta_string                NVARCHAR(10)
  19300.  
  19301.   SET NOCOUNT ON
  19302.   DECLARE @backupdt  DATETIME
  19303.   DECLARE @restoredt DATETIME
  19304.   DECLARE @rv        INT
  19305.   DECLARE rmlsp_cur CURSOR FOR
  19306.     SELECT s.primary_id, 
  19307.       s.secondary_server_name, 
  19308.       s.secondary_database_name, 
  19309.       s.secondary_plan_id, 
  19310.       s.out_of_sync_threshold, 
  19311.       s.threshold_alert, 
  19312.       s.threshold_alert_enabled, 
  19313.       s.last_loaded_filename, 
  19314.       s.last_loaded_last_updated,
  19315.       p.last_backup_filename,
  19316.       p.last_updated,
  19317.       p.primary_database_name,
  19318.       s.planned_outage_start_time, 
  19319.       s.planned_outage_end_time, 
  19320.       s.planned_outage_weekday_mask 
  19321.     FROM msdb.dbo.log_shipping_secondaries s 
  19322.     INNER JOIN msdb.dbo.log_shipping_primaries p 
  19323.     ON s.primary_id = p.primary_id
  19324.     FOR READ ONLY
  19325.  
  19326.   OPEN rmlsp_cur
  19327. loop:
  19328.   FETCH NEXT FROM rmlsp_cur 
  19329.   INTO @primary_id, 
  19330.          @secondary_server_name, 
  19331.           @secondary_database_name, 
  19332.            @secondary_plan_id, 
  19333.        @out_of_sync_threshold, 
  19334.            @threshold_alert, 
  19335.            @threshold_alert_enabled, 
  19336.            @last_loaded_filename, 
  19337.            @last_loaded_last_updated,
  19338.        @last_backup_filename,
  19339.        @last_backup_last_updated,
  19340.        @primary_database_name,
  19341.        @planned_outage_start_time, 
  19342.            @planned_outage_end_time, 
  19343.            @planned_outage_weekday_mask 
  19344.  
  19345.   IF @@FETCH_STATUS <> 0 -- nothing more to fetch, finish the loop
  19346.     GOTO _loop
  19347.  
  19348.   EXECUTE @rv = sp_log_shipping_get_date_from_file @primary_database_name, @last_backup_filename, @backupdt OUTPUT
  19349.   IF (@rv <> 0)
  19350.     SELECT @backupdt = @last_backup_last_updated
  19351.   
  19352.   EXECUTE @rv = sp_log_shipping_get_date_from_file @primary_database_name, @last_loaded_filename, @restoredt OUTPUT
  19353.   IF  (@rv <> 0)
  19354.     SELECT @restoredt = @last_loaded_last_updated
  19355.  
  19356.   EXECUTE @sync_status = sp_log_shipping_in_sync
  19357.     @restoredt,
  19358.     @backupdt,
  19359.       @out_of_sync_threshold,
  19360.       @planned_outage_start_time,
  19361.       @planned_outage_end_time,
  19362.     @planned_outage_weekday_mask,
  19363.     @threshold_alert_enabled,
  19364.     @sync_delta OUTPUT
  19365.  
  19366.    IF (@sync_status < 0)
  19367.    BEGIN
  19368.      SELECT @delta_string = CONVERT (NVARCHAR(10), @sync_delta)
  19369.      RAISERROR (@threshold_alert, 16, 1, @secondary_server_name, @secondary_database_name, @delta_string)
  19370.    END
  19371.  
  19372.   GOTO loop
  19373. _loop:
  19374.   CLOSE rmlsp_cur
  19375.   DEALLOCATE rmlsp_cur
  19376. END
  19377. go
  19378.  
  19379. /**************************************************************/
  19380. /* sp_change_monitor_role                                     */
  19381. /**************************************************************/
  19382. PRINT ''
  19383. PRINT 'Creating procedure sp_change_monitor_role...'
  19384. go
  19385. IF (EXISTS (SELECT * from msdb.dbo.sysobjects WHERE name = N'sp_change_monitor_role' AND type = N'P')  )
  19386.   DROP PROCEDURE sp_change_monitor_role
  19387. go
  19388. CREATE PROCEDURE sp_change_monitor_role
  19389.   @primary_server     sysname,
  19390.   @secondary_server   sysname,
  19391.   @database           sysname,
  19392.   @new_source         NVARCHAR (128)
  19393. AS BEGIN
  19394.   SET NOCOUNT ON
  19395.  
  19396.   BEGIN TRANSACTION
  19397.  
  19398.   -- drop the secondary
  19399.   DELETE FROM msdb.dbo.log_shipping_secondaries 
  19400.     WHERE secondary_server_name = @secondary_server AND secondary_database_name = @database
  19401.  
  19402.   IF (@@ROWCOUNT <> 1)
  19403.   BEGIN
  19404.       ROLLBACK TRANSACTION
  19405.       RAISERROR (14442,-1,-1)
  19406.       return(1)
  19407.   END
  19408.  
  19409.   -- let everyone know that we are the new primary
  19410.   UPDATE msdb.dbo.log_shipping_primaries 
  19411.     SET primary_server_name = @secondary_server, primary_database_name = @database, source_directory = @new_source
  19412.     WHERE primary_server_name = @primary_server AND primary_database_name = @database
  19413.  
  19414.   IF (@@ROWCOUNT <> 1)
  19415.   BEGIN
  19416.       ROLLBACK TRANSACTION
  19417.       RAISERROR (14442,-1,-1)
  19418.       return(1)
  19419.   END
  19420.   COMMIT TRANSACTION
  19421.  
  19422. END
  19423. go
  19424.  
  19425. /**************************************************************/
  19426. /* sp_create_log_shipping_monitor_account                     */
  19427. /**************************************************************/
  19428. PRINT ''
  19429. PRINT 'Creating procedure sp_create_log_shipping_monitor_account...'
  19430. go
  19431. IF (EXISTS (SELECT * from msdb.dbo.sysobjects WHERE name = N'sp_create_log_shipping_monitor_account' AND type = N'P')  )
  19432.   drop procedure sp_create_log_shipping_monitor_account
  19433. go
  19434. CREATE PROCEDURE sp_create_log_shipping_monitor_account @password sysname
  19435. AS
  19436. BEGIN
  19437.   DECLARE @rv INT
  19438.   SET NOCOUNT ON
  19439. -- raise an error if the password already exists
  19440.   if exists(select * from master.dbo.syslogins where loginname = N'log_shipping_monitor_probe')
  19441.   begin
  19442.     raiserror(15025,-1,-1,N'log_shipping_monitor_probe')
  19443.     RETURN (1) -- error
  19444.   end
  19445.  
  19446.   IF (@password = N'')
  19447.   BEGIN
  19448.     EXECUTE @rv = sp_addlogin N'log_shipping_monitor_probe', @defdb = N'msdb'
  19449.     IF @@error <>0 or @rv <> 0
  19450.       RETURN (1) -- error
  19451.   END
  19452.   ELSE
  19453.   BEGIN
  19454.     EXECUTE @rv = sp_addlogin N'log_shipping_monitor_probe', @password, N'msdb'
  19455.     IF @@error <>0 or @rv <> 0
  19456.       RETURN (1) -- error
  19457.   END
  19458.  
  19459.   EXECUTE @rv = sp_grantdbaccess N'log_shipping_monitor_probe', N'log_shipping_monitor_probe'
  19460.   IF @@error <>0 or @rv <> 0
  19461.     RETURN (1) -- error
  19462.  
  19463.   GRANT UPDATE ON log_shipping_primaries   TO log_shipping_monitor_probe
  19464.   GRANT UPDATE ON log_shipping_secondaries TO log_shipping_monitor_probe
  19465.   GRANT SELECT ON log_shipping_primaries   TO log_shipping_monitor_probe
  19466.   GRANT SELECT ON log_shipping_secondaries TO log_shipping_monitor_probe
  19467.  
  19468.   RETURN (0)
  19469. END
  19470. go
  19471.  
  19472. GRANT EXECUTE ON sp_get_log_shipping_monitor_info TO PUBLIC
  19473.  
  19474. /**************************************************************/
  19475. /* Turn 'System Object' marking OFF                           */
  19476. /**************************************************************/
  19477. PRINT ''
  19478. EXECUTE master.dbo.sp_MS_upd_sysobj_category 2
  19479. go
  19480.  
  19481. EXECUTE master.dbo.sp_configure N'allow updates', 0
  19482. go
  19483. RECONFIGURE WITH OVERRIDE
  19484. go
  19485.  
  19486. PRINT ''
  19487. PRINT '----------------------------------'
  19488. PRINT 'Execution of INSTMSDB.SQL complete'
  19489. PRINT '----------------------------------'
  19490. go
  19491.  
  19492. DUMP TRANSACTION msdb WITH NO_LOG
  19493. go
  19494. CHECKPOINT
  19495. go
  19496.